diff options
280 files changed, 10307 insertions, 4259 deletions
diff --git a/api/current.txt b/api/current.txt index 7a348ea7d846..612d16de8332 100644 --- a/api/current.txt +++ b/api/current.txt @@ -4464,10 +4464,10 @@ package android.app { method public void setInTouchMode(boolean); method public void start(); method public android.app.Activity startActivitySync(android.content.Intent); - method public void startAllocCounting(); + method public deprecated void startAllocCounting(); method public void startPerformanceSnapshot(); method public void startProfiling(); - method public void stopAllocCounting(); + method public deprecated void stopAllocCounting(); method public void stopProfiling(); method public void waitForIdle(java.lang.Runnable); method public void waitForIdleSync(); @@ -5369,6 +5369,7 @@ package android.app { method public static android.app.WallpaperManager getInstance(android.content.Context); method public android.app.WallpaperInfo getWallpaperInfo(); method public boolean hasResourceWallpaper(int); + method public boolean isWallpaperSupported(); method public android.graphics.drawable.Drawable peekDrawable(); method public android.graphics.drawable.Drawable peekFastDrawable(); method public void sendWallpaperCommand(android.os.IBinder, java.lang.String, int, int, int, android.os.Bundle); @@ -5495,6 +5496,7 @@ package android.app.admin { method public boolean getScreenCaptureDisabled(android.content.ComponentName); method public boolean getStorageEncryption(android.content.ComponentName); method public int getStorageEncryptionStatus(); + method public java.util.List<android.os.PersistableBundle> getTrustAgentConfiguration(android.content.ComponentName, android.content.ComponentName); method public boolean hasCaCertInstalled(android.content.ComponentName, byte[]); method public boolean hasGrantedPolicy(android.content.ComponentName, int); method public boolean installCaCert(android.content.ComponentName, byte[]); @@ -5545,8 +5547,10 @@ package android.app.admin { method public void setScreenCaptureDisabled(android.content.ComponentName, boolean); method public void setSecureSetting(android.content.ComponentName, java.lang.String, java.lang.String); method public int setStorageEncryption(android.content.ComponentName, boolean); + method public void setTrustAgentConfiguration(android.content.ComponentName, android.content.ComponentName, android.os.PersistableBundle); method public void setUninstallBlocked(android.content.ComponentName, java.lang.String, boolean); method public boolean setUserEnabled(android.content.ComponentName); + method public void setUserIcon(android.content.ComponentName, android.graphics.Bitmap); method public boolean switchUser(android.content.ComponentName, android.os.UserHandle); method public void uninstallAllUserCaCerts(android.content.ComponentName); method public void uninstallCaCert(android.content.ComponentName, byte[]); @@ -5564,10 +5568,11 @@ package android.app.admin { field public static final java.lang.String EXTRA_DEVICE_ADMIN = "android.app.extra.DEVICE_ADMIN"; field public static final java.lang.String EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE = "android.app.extra.PROVISIONING_ACCOUNT_TO_MIGRATE"; field public static final java.lang.String EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE = "android.app.extra.PROVISIONING_ADMIN_EXTRAS_BUNDLE"; + field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME = "android.app.extra.PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME"; field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM"; field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_COOKIE_HEADER = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_COOKIE_HEADER"; field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION"; - field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME"; + field public static final deprecated java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME"; field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_INITIALIZER_COMPONENT_NAME = "android.app.extra.PROVISIONING_DEVICE_INITIALIZER_COMPONENT_NAME"; field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_CHECKSUM = "android.app.extra.PROVISIONING_DEVICE_INITIALIZER_PACKAGE_CHECKSUM"; field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_COOKIE_HEADER = "android.app.extra.PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_COOKIE_HEADER"; @@ -10968,6 +10973,8 @@ package android.graphics { public class ImageFormat { ctor public ImageFormat(); method public static int getBitsPerPixel(int); + field public static final int DEPTH16 = 1144402265; // 0x44363159 + field public static final int DEPTH_POINT_CLOUD = 257; // 0x101 field public static final int JPEG = 256; // 0x100 field public static final int NV16 = 16; // 0x10 field public static final int NV21 = 17; // 0x11 @@ -22040,47 +22047,47 @@ package android.os { method public static final int getBinderProxyObjectCount(); method public static int getBinderReceivedTransactions(); method public static int getBinderSentTransactions(); - method public static int getGlobalAllocCount(); - method public static int getGlobalAllocSize(); - method public static int getGlobalClassInitCount(); - method public static int getGlobalClassInitTime(); + method public static deprecated int getGlobalAllocCount(); + method public static deprecated int getGlobalAllocSize(); + method public static deprecated int getGlobalClassInitCount(); + method public static deprecated int getGlobalClassInitTime(); method public static deprecated int getGlobalExternalAllocCount(); method public static deprecated int getGlobalExternalAllocSize(); method public static deprecated int getGlobalExternalFreedCount(); method public static deprecated int getGlobalExternalFreedSize(); - method public static int getGlobalFreedCount(); - method public static int getGlobalFreedSize(); - method public static int getGlobalGcInvocationCount(); + method public static deprecated int getGlobalFreedCount(); + method public static deprecated int getGlobalFreedSize(); + method public static deprecated int getGlobalGcInvocationCount(); method public static int getLoadedClassCount(); method public static void getMemoryInfo(android.os.Debug.MemoryInfo); method public static long getNativeHeapAllocatedSize(); method public static long getNativeHeapFreeSize(); method public static long getNativeHeapSize(); method public static long getPss(); - method public static int getThreadAllocCount(); - method public static int getThreadAllocSize(); + method public static deprecated int getThreadAllocCount(); + method public static deprecated int getThreadAllocSize(); method public static deprecated int getThreadExternalAllocCount(); method public static deprecated int getThreadExternalAllocSize(); - method public static int getThreadGcInvocationCount(); + method public static deprecated int getThreadGcInvocationCount(); method public static boolean isDebuggerConnected(); method public static void printLoadedClasses(int); - method public static void resetAllCounts(); - method public static void resetGlobalAllocCount(); - method public static void resetGlobalAllocSize(); - method public static void resetGlobalClassInitCount(); - method public static void resetGlobalClassInitTime(); + method public static deprecated void resetAllCounts(); + method public static deprecated void resetGlobalAllocCount(); + method public static deprecated void resetGlobalAllocSize(); + method public static deprecated void resetGlobalClassInitCount(); + method public static deprecated void resetGlobalClassInitTime(); method public static deprecated void resetGlobalExternalAllocCount(); method public static deprecated void resetGlobalExternalAllocSize(); method public static deprecated void resetGlobalExternalFreedCount(); method public static deprecated void resetGlobalExternalFreedSize(); - method public static void resetGlobalFreedCount(); - method public static void resetGlobalFreedSize(); - method public static void resetGlobalGcInvocationCount(); - method public static void resetThreadAllocCount(); - method public static void resetThreadAllocSize(); + method public static deprecated void resetGlobalFreedCount(); + method public static deprecated void resetGlobalFreedSize(); + method public static deprecated void resetGlobalGcInvocationCount(); + method public static deprecated void resetThreadAllocCount(); + method public static deprecated void resetThreadAllocSize(); method public static deprecated void resetThreadExternalAllocCount(); method public static deprecated void resetThreadExternalAllocSize(); - method public static void resetThreadGcInvocationCount(); + method public static deprecated void resetThreadGcInvocationCount(); method public static deprecated int setAllocationLimit(int); method public static deprecated int setGlobalAllocationLimit(int); method public static deprecated void startAllocCounting(); @@ -22099,7 +22106,7 @@ package android.os { field public static final int SHOW_CLASSLOADER = 2; // 0x2 field public static final int SHOW_FULL_DETAIL = 1; // 0x1 field public static final int SHOW_INITIALIZED = 4; // 0x4 - field public static final int TRACE_COUNT_ALLOCS = 1; // 0x1 + field public static final deprecated int TRACE_COUNT_ALLOCS = 1; // 0x1 } public static deprecated class Debug.InstructionCount { @@ -24914,6 +24921,7 @@ package android.provider { field public static final int ORGANIZATION = 30; // 0x1e field public static final int PHONE = 20; // 0x14 field public static final int STRUCTURED_NAME = 40; // 0x28 + field public static final int STRUCTURED_PHONETIC_NAME = 37; // 0x25 field public static final int UNDEFINED = 0; // 0x0 } @@ -29329,6 +29337,7 @@ package android.telephony { } public class TelephonyManager { + method public boolean canChangeDtmfToneLength(); method public java.util.List<android.telephony.CellInfo> getAllCellInfo(); method public int getCallState(); method public android.telephony.CellLocation getCellLocation(); @@ -29364,6 +29373,7 @@ package android.telephony { method public boolean isNetworkRoaming(); method public boolean isSmsCapable(); method public boolean isVoiceCapable(); + method public boolean isWorldPhone(); method public void listen(android.telephony.PhoneStateListener, int); method public java.lang.String sendEnvelopeWithStatus(java.lang.String); method public boolean setLine1NumberForDisplay(java.lang.String, java.lang.String); @@ -36923,6 +36933,12 @@ package android.webkit { method public abstract void onReceivedIcon(java.lang.String, android.graphics.Bitmap); } + public abstract class WebResourceError { + ctor public WebResourceError(); + method public abstract java.lang.String getDescription(); + method public abstract int getErrorCode(); + } + public abstract interface WebResourceRequest { method public abstract java.lang.String getMethod(); method public abstract java.util.Map<java.lang.String, java.lang.String> getRequestHeaders(); @@ -36931,7 +36947,7 @@ package android.webkit { method public abstract boolean isForMainFrame(); } - public class WebResourceResponse { + public class WebResourceResponse extends android.webkit.WebResourceResponseBase { ctor public WebResourceResponse(java.lang.String, java.lang.String, java.io.InputStream); ctor public WebResourceResponse(java.lang.String, java.lang.String, int, java.lang.String, java.util.Map<java.lang.String, java.lang.String>, java.io.InputStream); method public java.io.InputStream getData(); @@ -36947,6 +36963,16 @@ package android.webkit { method public void setStatusCodeAndReasonPhrase(int, java.lang.String); } + public abstract class WebResourceResponseBase { + ctor public WebResourceResponseBase(); + method public abstract java.io.InputStream getData(); + method public abstract java.lang.String getEncoding(); + method public abstract java.lang.String getMimeType(); + method public abstract java.lang.String getReasonPhrase(); + method public abstract java.util.Map<java.lang.String, java.lang.String> getResponseHeaders(); + method public abstract int getStatusCode(); + } + public abstract class WebSettings { ctor public WebSettings(); method public abstract deprecated boolean enableSmoothTransition(); @@ -37261,8 +37287,10 @@ package android.webkit { method public void onPageFinished(android.webkit.WebView, java.lang.String); method public void onPageStarted(android.webkit.WebView, java.lang.String, android.graphics.Bitmap); method public void onReceivedClientCertRequest(android.webkit.WebView, android.webkit.ClientCertRequest); - method public void onReceivedError(android.webkit.WebView, int, java.lang.String, java.lang.String); + method public deprecated void onReceivedError(android.webkit.WebView, int, java.lang.String, java.lang.String); + method public void onReceivedError(android.webkit.WebView, android.webkit.WebResourceRequest, android.webkit.WebResourceError); method public void onReceivedHttpAuthRequest(android.webkit.WebView, android.webkit.HttpAuthHandler, java.lang.String, java.lang.String); + method public void onReceivedHttpError(android.webkit.WebView, android.webkit.WebResourceRequest, android.webkit.WebResourceResponseBase); method public void onReceivedLoginRequest(android.webkit.WebView, java.lang.String, java.lang.String, java.lang.String); method public void onReceivedSslError(android.webkit.WebView, android.webkit.SslErrorHandler, android.net.http.SslError); method public void onScaleChanged(android.webkit.WebView, float, float); @@ -37275,6 +37303,7 @@ package android.webkit { method public boolean shouldOverrideUrlLoading(android.webkit.WebView, java.lang.String); field public static final int ERROR_AUTHENTICATION = -4; // 0xfffffffc field public static final int ERROR_BAD_URL = -12; // 0xfffffff4 + field public static final int ERROR_BLOCKED = -16; // 0xfffffff0 field public static final int ERROR_CONNECT = -6; // 0xfffffffa field public static final int ERROR_FAILED_SSL_HANDSHAKE = -11; // 0xfffffff5 field public static final int ERROR_FILE = -13; // 0xfffffff3 diff --git a/api/system-current.txt b/api/system-current.txt index 4755fe748c27..ff9809ffb14b 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -4554,10 +4554,10 @@ package android.app { method public void setInTouchMode(boolean); method public void start(); method public android.app.Activity startActivitySync(android.content.Intent); - method public void startAllocCounting(); + method public deprecated void startAllocCounting(); method public void startPerformanceSnapshot(); method public void startProfiling(); - method public void stopAllocCounting(); + method public deprecated void stopAllocCounting(); method public void stopProfiling(); method public void waitForIdle(java.lang.Runnable); method public void waitForIdleSync(); @@ -5460,6 +5460,7 @@ package android.app { method public static android.app.WallpaperManager getInstance(android.content.Context); method public android.app.WallpaperInfo getWallpaperInfo(); method public boolean hasResourceWallpaper(int); + method public boolean isWallpaperSupported(); method public android.graphics.drawable.Drawable peekDrawable(); method public android.graphics.drawable.Drawable peekFastDrawable(); method public void sendWallpaperCommand(android.os.IBinder, java.lang.String, int, int, int, android.os.Bundle); @@ -5596,6 +5597,7 @@ package android.app.admin { method public boolean getScreenCaptureDisabled(android.content.ComponentName); method public boolean getStorageEncryption(android.content.ComponentName); method public int getStorageEncryptionStatus(); + method public java.util.List<android.os.PersistableBundle> getTrustAgentConfiguration(android.content.ComponentName, android.content.ComponentName); method public boolean hasCaCertInstalled(android.content.ComponentName, byte[]); method public boolean hasGrantedPolicy(android.content.ComponentName, int); method public boolean installCaCert(android.content.ComponentName, byte[]); @@ -5647,8 +5649,10 @@ package android.app.admin { method public void setScreenCaptureDisabled(android.content.ComponentName, boolean); method public void setSecureSetting(android.content.ComponentName, java.lang.String, java.lang.String); method public int setStorageEncryption(android.content.ComponentName, boolean); + method public void setTrustAgentConfiguration(android.content.ComponentName, android.content.ComponentName, android.os.PersistableBundle); method public void setUninstallBlocked(android.content.ComponentName, java.lang.String, boolean); method public boolean setUserEnabled(android.content.ComponentName); + method public void setUserIcon(android.content.ComponentName, android.graphics.Bitmap); method public boolean switchUser(android.content.ComponentName, android.os.UserHandle); method public void uninstallAllUserCaCerts(android.content.ComponentName); method public void uninstallCaCert(android.content.ComponentName, byte[]); @@ -5668,10 +5672,11 @@ package android.app.admin { field public static final java.lang.String EXTRA_PROFILE_OWNER_NAME = "android.app.extra.PROFILE_OWNER_NAME"; field public static final java.lang.String EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE = "android.app.extra.PROVISIONING_ACCOUNT_TO_MIGRATE"; field public static final java.lang.String EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE = "android.app.extra.PROVISIONING_ADMIN_EXTRAS_BUNDLE"; + field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME = "android.app.extra.PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME"; field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM"; field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_COOKIE_HEADER = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_COOKIE_HEADER"; field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION"; - field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME"; + field public static final deprecated java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME"; field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_INITIALIZER_COMPONENT_NAME = "android.app.extra.PROVISIONING_DEVICE_INITIALIZER_COMPONENT_NAME"; field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_CHECKSUM = "android.app.extra.PROVISIONING_DEVICE_INITIALIZER_PACKAGE_CHECKSUM"; field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_COOKIE_HEADER = "android.app.extra.PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_COOKIE_HEADER"; @@ -11243,6 +11248,8 @@ package android.graphics { public class ImageFormat { ctor public ImageFormat(); method public static int getBitsPerPixel(int); + field public static final int DEPTH16 = 1144402265; // 0x44363159 + field public static final int DEPTH_POINT_CLOUD = 257; // 0x101 field public static final int JPEG = 256; // 0x100 field public static final int NV16 = 16; // 0x10 field public static final int NV21 = 17; // 0x11 @@ -15134,6 +15141,7 @@ package android.media { public final class AudioAttributes implements android.os.Parcelable { method public int describeContents(); + method public int getAllFlags(); method public int getCapturePreset(); method public int getContentType(); method public int getFlags(); @@ -15175,6 +15183,7 @@ package android.media { method public android.media.AudioAttributes.Builder setCapturePreset(int); method public android.media.AudioAttributes.Builder setContentType(int); method public android.media.AudioAttributes.Builder setFlags(int); + method public android.media.AudioAttributes.Builder setInternalCapturePreset(int); method public android.media.AudioAttributes.Builder setLegacyStreamType(int); method public android.media.AudioAttributes.Builder setUsage(int); } @@ -15407,6 +15416,7 @@ package android.media { public class AudioRecord { ctor public AudioRecord(int, int, int, int, int) throws java.lang.IllegalArgumentException; + ctor public AudioRecord(android.media.AudioAttributes, android.media.AudioFormat, int, int) throws java.lang.IllegalArgumentException; method public int getAudioFormat(); method public int getAudioSessionId(); method public int getAudioSource(); @@ -16545,7 +16555,9 @@ package android.media { public final class MediaRecorder.AudioSource { field public static final int CAMCORDER = 5; // 0x5 field public static final int DEFAULT = 0; // 0x0 + field public static final int HOTWORD = 1999; // 0x7cf field public static final int MIC = 1; // 0x1 + field public static final int RADIO_TUNER = 1998; // 0x7ce field public static final int REMOTE_SUBMIX = 8; // 0x8 field public static final int VOICE_CALL = 4; // 0x4 field public static final int VOICE_COMMUNICATION = 7; // 0x7 @@ -23630,47 +23642,47 @@ package android.os { method public static final int getBinderProxyObjectCount(); method public static int getBinderReceivedTransactions(); method public static int getBinderSentTransactions(); - method public static int getGlobalAllocCount(); - method public static int getGlobalAllocSize(); - method public static int getGlobalClassInitCount(); - method public static int getGlobalClassInitTime(); + method public static deprecated int getGlobalAllocCount(); + method public static deprecated int getGlobalAllocSize(); + method public static deprecated int getGlobalClassInitCount(); + method public static deprecated int getGlobalClassInitTime(); method public static deprecated int getGlobalExternalAllocCount(); method public static deprecated int getGlobalExternalAllocSize(); method public static deprecated int getGlobalExternalFreedCount(); method public static deprecated int getGlobalExternalFreedSize(); - method public static int getGlobalFreedCount(); - method public static int getGlobalFreedSize(); - method public static int getGlobalGcInvocationCount(); + method public static deprecated int getGlobalFreedCount(); + method public static deprecated int getGlobalFreedSize(); + method public static deprecated int getGlobalGcInvocationCount(); method public static int getLoadedClassCount(); method public static void getMemoryInfo(android.os.Debug.MemoryInfo); method public static long getNativeHeapAllocatedSize(); method public static long getNativeHeapFreeSize(); method public static long getNativeHeapSize(); method public static long getPss(); - method public static int getThreadAllocCount(); - method public static int getThreadAllocSize(); + method public static deprecated int getThreadAllocCount(); + method public static deprecated int getThreadAllocSize(); method public static deprecated int getThreadExternalAllocCount(); method public static deprecated int getThreadExternalAllocSize(); - method public static int getThreadGcInvocationCount(); + method public static deprecated int getThreadGcInvocationCount(); method public static boolean isDebuggerConnected(); method public static void printLoadedClasses(int); - method public static void resetAllCounts(); - method public static void resetGlobalAllocCount(); - method public static void resetGlobalAllocSize(); - method public static void resetGlobalClassInitCount(); - method public static void resetGlobalClassInitTime(); + method public static deprecated void resetAllCounts(); + method public static deprecated void resetGlobalAllocCount(); + method public static deprecated void resetGlobalAllocSize(); + method public static deprecated void resetGlobalClassInitCount(); + method public static deprecated void resetGlobalClassInitTime(); method public static deprecated void resetGlobalExternalAllocCount(); method public static deprecated void resetGlobalExternalAllocSize(); method public static deprecated void resetGlobalExternalFreedCount(); method public static deprecated void resetGlobalExternalFreedSize(); - method public static void resetGlobalFreedCount(); - method public static void resetGlobalFreedSize(); - method public static void resetGlobalGcInvocationCount(); - method public static void resetThreadAllocCount(); - method public static void resetThreadAllocSize(); + method public static deprecated void resetGlobalFreedCount(); + method public static deprecated void resetGlobalFreedSize(); + method public static deprecated void resetGlobalGcInvocationCount(); + method public static deprecated void resetThreadAllocCount(); + method public static deprecated void resetThreadAllocSize(); method public static deprecated void resetThreadExternalAllocCount(); method public static deprecated void resetThreadExternalAllocSize(); - method public static void resetThreadGcInvocationCount(); + method public static deprecated void resetThreadGcInvocationCount(); method public static deprecated int setAllocationLimit(int); method public static deprecated int setGlobalAllocationLimit(int); method public static deprecated void startAllocCounting(); @@ -23689,7 +23701,7 @@ package android.os { field public static final int SHOW_CLASSLOADER = 2; // 0x2 field public static final int SHOW_FULL_DETAIL = 1; // 0x1 field public static final int SHOW_INITIALIZED = 4; // 0x4 - field public static final int TRACE_COUNT_ALLOCS = 1; // 0x1 + field public static final deprecated int TRACE_COUNT_ALLOCS = 1; // 0x1 } public static deprecated class Debug.InstructionCount { @@ -26514,6 +26526,7 @@ package android.provider { field public static final int ORGANIZATION = 30; // 0x1e field public static final int PHONE = 20; // 0x14 field public static final int STRUCTURED_NAME = 40; // 0x28 + field public static final int STRUCTURED_PHONETIC_NAME = 37; // 0x25 field public static final int UNDEFINED = 0; // 0x0 } @@ -31456,6 +31469,7 @@ package android.telephony { public class TelephonyManager { method public void answerRingingCall(); method public void call(java.lang.String, java.lang.String); + method public boolean canChangeDtmfToneLength(); method public int checkCarrierPrivilegesForPackage(java.lang.String); method public void dial(java.lang.String); method public boolean disableDataConnectivity(); @@ -31515,6 +31529,7 @@ package android.telephony { method public boolean isSmsCapable(); method public boolean isVideoCallingEnabled(); method public boolean isVoiceCapable(); + method public boolean isWorldPhone(); method public void listen(android.telephony.PhoneStateListener, int); method public boolean needsOtaServiceProvisioning(); method public java.lang.String sendEnvelopeWithStatus(java.lang.String); @@ -39147,6 +39162,12 @@ package android.webkit { method public abstract void onReceivedIcon(java.lang.String, android.graphics.Bitmap); } + public abstract class WebResourceError { + ctor public WebResourceError(); + method public abstract java.lang.String getDescription(); + method public abstract int getErrorCode(); + } + public abstract interface WebResourceRequest { method public abstract java.lang.String getMethod(); method public abstract java.util.Map<java.lang.String, java.lang.String> getRequestHeaders(); @@ -39155,7 +39176,7 @@ package android.webkit { method public abstract boolean isForMainFrame(); } - public class WebResourceResponse { + public class WebResourceResponse extends android.webkit.WebResourceResponseBase { ctor public WebResourceResponse(java.lang.String, java.lang.String, java.io.InputStream); ctor public WebResourceResponse(java.lang.String, java.lang.String, int, java.lang.String, java.util.Map<java.lang.String, java.lang.String>, java.io.InputStream); method public java.io.InputStream getData(); @@ -39171,6 +39192,16 @@ package android.webkit { method public void setStatusCodeAndReasonPhrase(int, java.lang.String); } + public abstract class WebResourceResponseBase { + ctor public WebResourceResponseBase(); + method public abstract java.io.InputStream getData(); + method public abstract java.lang.String getEncoding(); + method public abstract java.lang.String getMimeType(); + method public abstract java.lang.String getReasonPhrase(); + method public abstract java.util.Map<java.lang.String, java.lang.String> getResponseHeaders(); + method public abstract int getStatusCode(); + } + public abstract class WebSettings { ctor public WebSettings(); method public abstract deprecated boolean enableSmoothTransition(); @@ -39530,8 +39561,10 @@ package android.webkit { method public void onPageFinished(android.webkit.WebView, java.lang.String); method public void onPageStarted(android.webkit.WebView, java.lang.String, android.graphics.Bitmap); method public void onReceivedClientCertRequest(android.webkit.WebView, android.webkit.ClientCertRequest); - method public void onReceivedError(android.webkit.WebView, int, java.lang.String, java.lang.String); + method public deprecated void onReceivedError(android.webkit.WebView, int, java.lang.String, java.lang.String); + method public void onReceivedError(android.webkit.WebView, android.webkit.WebResourceRequest, android.webkit.WebResourceError); method public void onReceivedHttpAuthRequest(android.webkit.WebView, android.webkit.HttpAuthHandler, java.lang.String, java.lang.String); + method public void onReceivedHttpError(android.webkit.WebView, android.webkit.WebResourceRequest, android.webkit.WebResourceResponseBase); method public void onReceivedLoginRequest(android.webkit.WebView, java.lang.String, java.lang.String, java.lang.String); method public void onReceivedSslError(android.webkit.WebView, android.webkit.SslErrorHandler, android.net.http.SslError); method public void onScaleChanged(android.webkit.WebView, float, float); @@ -39544,6 +39577,7 @@ package android.webkit { method public boolean shouldOverrideUrlLoading(android.webkit.WebView, java.lang.String); field public static final int ERROR_AUTHENTICATION = -4; // 0xfffffffc field public static final int ERROR_BAD_URL = -12; // 0xfffffff4 + field public static final int ERROR_BLOCKED = -16; // 0xfffffff0 field public static final int ERROR_CONNECT = -6; // 0xfffffffa field public static final int ERROR_FAILED_SSL_HANDSHAKE = -11; // 0xfffffff5 field public static final int ERROR_FILE = -13; // 0xfffffff3 diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java index bc0c451a0e16..29ba1d7a146f 100644 --- a/cmds/am/src/com/android/commands/am/Am.java +++ b/cmds/am/src/com/android/commands/am/Am.java @@ -117,6 +117,8 @@ public class Am extends BaseCommand { " am dumpheap [--user <USER_ID> current] [-n] <PROCESS> <FILE>\n" + " am set-debug-app [-w] [--persistent] <PACKAGE>\n" + " am clear-debug-app\n" + + " am set-watch-heap <PROCESS> <MEM-LIMIT>\n" + + " am clear-watch-heap\n" + " am monitor [--gdb <port>]\n" + " am hang [--allow-restart]\n" + " am restart\n" + @@ -211,6 +213,11 @@ public class Am extends BaseCommand { "\n" + "am clear-debug-app: clear the previously set-debug-app.\n" + "\n" + + "am set-watch-heap: start monitoring pss size of <PROCESS>, if it is at or\n" + + " above <HEAP-LIMIT> then a heap dump is collected for the user to report\n" + + "\n" + + "am clear-watch-heap: clear the previously set-watch-heap.\n" + + "\n" + "am bug-report: request bug report generation; will launch UI\n" + " when done to select where it should be delivered.\n" + "\n" + @@ -342,6 +349,10 @@ public class Am extends BaseCommand { runSetDebugApp(); } else if (op.equals("clear-debug-app")) { runClearDebugApp(); + } else if (op.equals("set-watch-heap")) { + runSetWatchHeap(); + } else if (op.equals("clear-watch-heap")) { + runClearWatchHeap(); } else if (op.equals("bug-report")) { runBugReport(); } else if (op.equals("monitor")) { @@ -1172,6 +1183,17 @@ public class Am extends BaseCommand { mAm.setDebugApp(null, false, true); } + private void runSetWatchHeap() throws Exception { + String proc = nextArgRequired(); + String limit = nextArgRequired(); + mAm.setDumpHeapDebugLimit(proc, Long.parseLong(limit)); + } + + private void runClearWatchHeap() throws Exception { + String proc = nextArgRequired(); + mAm.setDumpHeapDebugLimit(proc, -1); + } + private void runBugReport() throws Exception { mAm.requestBugReport(); System.out.println("Your lovely bug report is being created; please be patient."); diff --git a/core/java/android/animation/ObjectAnimator.java b/core/java/android/animation/ObjectAnimator.java index 87ad49b0a096..3f71d51bd8ab 100644 --- a/core/java/android/animation/ObjectAnimator.java +++ b/core/java/android/animation/ObjectAnimator.java @@ -16,6 +16,7 @@ package android.animation; +import android.annotation.CallSuper; import android.annotation.NonNull; import android.annotation.Nullable; import android.graphics.Path; @@ -861,6 +862,7 @@ public final class ObjectAnimator extends ValueAnimator { * <p>Overriders of this method should call the superclass method to cause * internal mechanisms to be set up correctly.</p> */ + @CallSuper @Override void initAnimation() { if (!mInitialized) { @@ -961,6 +963,7 @@ public final class ObjectAnimator extends ValueAnimator { * * @param fraction The elapsed fraction of the animation. */ + @CallSuper @Override void animateValue(float fraction) { final Object target = getTarget(); diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java index 118af6491d85..85dc8320803f 100644 --- a/core/java/android/animation/ValueAnimator.java +++ b/core/java/android/animation/ValueAnimator.java @@ -16,6 +16,7 @@ package android.animation; +import android.annotation.CallSuper; import android.os.Looper; import android.os.Trace; import android.util.AndroidRuntimeException; @@ -506,6 +507,7 @@ public class ValueAnimator extends Animator { * <p>Overrides of this method should call the superclass method to ensure * that internal mechanisms for the animation are set up correctly.</p> */ + @CallSuper void initAnimation() { if (!mInitialized) { int numValues = mValues.length; @@ -1375,6 +1377,7 @@ public class ValueAnimator extends Animator { * * @param fraction The elapsed fraction of the animation. */ + @CallSuper void animateValue(float fraction) { fraction = mInterpolator.getInterpolation(fraction); mCurrentFraction = fraction; diff --git a/core/java/android/annotation/CallSuper.java b/core/java/android/annotation/CallSuper.java new file mode 100644 index 000000000000..82e27232abb6 --- /dev/null +++ b/core/java/android/annotation/CallSuper.java @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.annotation; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.RetentionPolicy.SOURCE; + +/** + * Denotes that any overriding methods should invoke this method as well. + * <p> + * Example: + * <pre>{@code + * @CallSuper + * public abstract void onFocusLost(); + * }</pre> + * + * @hide + */ +@Retention(SOURCE) +@Target({METHOD}) +public @interface CallSuper { +}
\ No newline at end of file diff --git a/core/java/android/annotation/CheckResult.java b/core/java/android/annotation/CheckResult.java new file mode 100644 index 000000000000..787514e9f8c3 --- /dev/null +++ b/core/java/android/annotation/CheckResult.java @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.annotation; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.RetentionPolicy.SOURCE; + +/** + * Denotes that the annotated method returns a result that it typically is + * an error to ignore. This is usually used for methods that have no side effect, + * so calling it without actually looking at the result usually means the developer + * has misunderstood what the method does. + * <p> + * Example: + * <pre>{@code + * public @CheckResult String trim(String s) { return s.trim(); } + * ... + * s.trim(); // this is probably an error + * s = s.trim(); // ok + * }</pre> + * + * @hide + */ +@Retention(SOURCE) +@Target({METHOD}) +public @interface CheckResult { + /** Defines the name of the suggested method to use instead, if applicable (using + * the same signature format as javadoc.) If there is more than one possibility, + * list them all separated by commas. + * <p> + * For example, ProcessBuilder has a method named {@code redirectErrorStream()} + * which sounds like it might redirect the error stream. It does not. It's just + * a getter which returns whether the process builder will redirect the error stream, + * and to actually set it, you must call {@code redirectErrorStream(boolean)}. + * In that case, the method should be defined like this: + * <pre> + * @CheckResult(suggest="#redirectErrorStream(boolean)") + * public boolean redirectErrorStream() { ... } + * </pre> + */ + String suggest() default ""; +}
\ No newline at end of file diff --git a/core/java/android/annotation/ColorInt.java b/core/java/android/annotation/ColorInt.java new file mode 100644 index 000000000000..c4c93eee3cee --- /dev/null +++ b/core/java/android/annotation/ColorInt.java @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.annotation; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.ElementType.LOCAL_VARIABLE; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.PARAMETER; +import static java.lang.annotation.RetentionPolicy.SOURCE; + +/** + * Denotes that the annotated element represents a packed color + * int, {@code AARRGGBB}. If applied to an int array, every element + * in the array represents a color integer. + * <p> + * public abstract void setTextColor(@ColorInt int color); + * }</pre> + * + * @hide + */ +@Retention(SOURCE) +@Target({PARAMETER,METHOD,LOCAL_VARIABLE,FIELD}) +public @interface ColorInt { +}
\ No newline at end of file diff --git a/core/java/android/annotation/FloatRange.java b/core/java/android/annotation/FloatRange.java new file mode 100644 index 000000000000..3a7c15015b49 --- /dev/null +++ b/core/java/android/annotation/FloatRange.java @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.annotation; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.ElementType.LOCAL_VARIABLE; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.PARAMETER; +import static java.lang.annotation.RetentionPolicy.SOURCE; + +/** + * Denotes that the annotated element should be a float or double in the given range + * <p> + * Example: + * <pre>{@code + * @FloatRange(from=0.0,to=1.0) + * public float getAlpha() { + * ... + * } + * }</pre> + * + * @hide + */ +@Retention(SOURCE) +@Target({METHOD,PARAMETER,FIELD,LOCAL_VARIABLE}) +public @interface FloatRange { + /** Smallest value. Whether it is inclusive or not is determined + * by {@link #fromInclusive} */ + double from() default Double.NEGATIVE_INFINITY; + /** Largest value. Whether it is inclusive or not is determined + * by {@link #toInclusive} */ + double to() default Double.POSITIVE_INFINITY; + + /** Whether the from value is included in the range */ + boolean fromInclusive() default true; + + /** Whether the to value is included in the range */ + boolean toInclusive() default true; +}
\ No newline at end of file diff --git a/core/java/android/annotation/IntRange.java b/core/java/android/annotation/IntRange.java new file mode 100644 index 000000000000..1e3c072267d7 --- /dev/null +++ b/core/java/android/annotation/IntRange.java @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.annotation; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.ElementType.LOCAL_VARIABLE; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.PARAMETER; +import static java.lang.annotation.RetentionPolicy.SOURCE; + +/** + * Denotes that the annotated element should be an int or long in the given range + * <p> + * Example: + * <pre>{@code + * @IntRange(from=0,to=255) + * public int getAlpha() { + * ... + * } + * }</pre> + * + * @hide + */ +@Retention(SOURCE) +@Target({METHOD,PARAMETER,FIELD,LOCAL_VARIABLE}) +public @interface IntRange { + /** Smallest value, inclusive */ + long from() default Long.MIN_VALUE; + /** Largest value, inclusive */ + long to() default Long.MAX_VALUE; +}
\ No newline at end of file diff --git a/core/java/android/annotation/Size.java b/core/java/android/annotation/Size.java new file mode 100644 index 000000000000..389b819bb41a --- /dev/null +++ b/core/java/android/annotation/Size.java @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.annotation; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.ElementType.LOCAL_VARIABLE; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.PARAMETER; +import static java.lang.annotation.RetentionPolicy.SOURCE; + +/** + * Denotes that the annotated element should have a given size or length. + * Note that "-1" means "unset". Typically used with a parameter or + * return value of type array or collection. + * <p> + * Example: + * <pre>{@code + * public void getLocationInWindow(@Size(2) int[] location) { + * ... + * } + * }</pre> + * + * @hide + */ +@Retention(SOURCE) +@Target({PARAMETER,LOCAL_VARIABLE,METHOD,FIELD}) +public @interface Size { + /** An exact size (or -1 if not specified) */ + long value() default -1; + /** A minimum size, inclusive */ + long min() default Long.MIN_VALUE; + /** A maximum size, inclusive */ + long max() default Long.MAX_VALUE; + /** The size must be a multiple of this factor */ + long multiple() default 1; +}
\ No newline at end of file diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index a36d34add03f..9f8befec9902 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -16,6 +16,7 @@ package android.app; +import android.annotation.CallSuper; import android.annotation.DrawableRes; import android.annotation.IdRes; import android.annotation.IntDef; @@ -921,6 +922,7 @@ public class Activity extends ContextThemeWrapper * @see #onRestoreInstanceState * @see #onPostCreate */ + @CallSuper protected void onCreate(@Nullable Bundle savedInstanceState) { if (DEBUG_LIFECYCLE) Slog.v(TAG, "onCreate " + this + ": " + savedInstanceState); if (mLastNonConfigurationInstances != null) { @@ -1122,6 +1124,7 @@ public class Activity extends ContextThemeWrapper * recently supplied in {@link #onSaveInstanceState}. <b><i>Note: Otherwise it is null.</i></b> * @see #onCreate */ + @CallSuper protected void onPostCreate(@Nullable Bundle savedInstanceState) { if (!isChild()) { mTitleReady = true; @@ -1159,6 +1162,7 @@ public class Activity extends ContextThemeWrapper * @see #onStop * @see #onResume */ + @CallSuper protected void onStart() { if (DEBUG_LIFECYCLE) Slog.v(TAG, "onStart " + this); mCalled = true; @@ -1196,6 +1200,7 @@ public class Activity extends ContextThemeWrapper * @see #onStart * @see #onResume */ + @CallSuper protected void onRestart() { mCalled = true; } @@ -1220,6 +1225,7 @@ public class Activity extends ContextThemeWrapper * @see #onPostResume * @see #onPause */ + @CallSuper protected void onResume() { if (DEBUG_LIFECYCLE) Slog.v(TAG, "onResume " + this); getApplication().dispatchActivityResumed(this); @@ -1239,6 +1245,7 @@ public class Activity extends ContextThemeWrapper * * @see #onResume */ + @CallSuper protected void onPostResume() { final Window win = getWindow(); if (win != null) win.makeActive(); @@ -1464,6 +1471,7 @@ public class Activity extends ContextThemeWrapper * @see #onSaveInstanceState * @see #onStop */ + @CallSuper protected void onPause() { if (DEBUG_LIFECYCLE) Slog.v(TAG, "onPause " + this); getApplication().dispatchActivityPaused(this); @@ -1570,6 +1578,7 @@ public class Activity extends ContextThemeWrapper * @see #onSaveInstanceState * @see #onDestroy */ + @CallSuper protected void onStop() { if (DEBUG_LIFECYCLE) Slog.v(TAG, "onStop " + this); if (mActionBar != null) mActionBar.setShowHideAnimationEnabled(false); @@ -1607,6 +1616,7 @@ public class Activity extends ContextThemeWrapper * @see #finish * @see #isFinishing */ + @CallSuper protected void onDestroy() { if (DEBUG_LIFECYCLE) Slog.v(TAG, "onDestroy " + this); mCalled = true; @@ -5587,6 +5597,7 @@ public class Activity extends ContextThemeWrapper * @see #requestVisibleBehind(boolean) * @see #onBackgroundVisibleBehindChanged(boolean) */ + @CallSuper public void onVisibleBehindCanceled() { mCalled = true; } @@ -5709,6 +5720,7 @@ public class Activity extends ContextThemeWrapper * * @param mode The new action mode. */ + @CallSuper @Override public void onActionModeStarted(ActionMode mode) { } @@ -5719,6 +5731,7 @@ public class Activity extends ContextThemeWrapper * * @param mode The action mode that just finished. */ + @CallSuper @Override public void onActionModeFinished(ActionMode mode) { } diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java index 3197461e5c64..997f69dc0f81 100644 --- a/core/java/android/app/ActivityManagerNative.java +++ b/core/java/android/app/ActivityManagerNative.java @@ -2423,6 +2423,23 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM reply.writeNoException(); return true; } + + case SET_DUMP_HEAP_DEBUG_LIMIT_TRANSACTION: { + data.enforceInterface(IActivityManager.descriptor); + String procName = data.readString(); + long maxMemSize = data.readLong(); + setDumpHeapDebugLimit(procName, maxMemSize); + reply.writeNoException(); + return true; + } + + case DUMP_HEAP_FINISHED_TRANSACTION: { + data.enforceInterface(IActivityManager.descriptor); + String path = data.readString(); + dumpHeapFinished(path); + reply.writeNoException(); + return true; + } } return super.onTransact(code, data, reply, flags); @@ -5616,5 +5633,30 @@ class ActivityManagerProxy implements IActivityManager reply.recycle(); } + @Override + public void setDumpHeapDebugLimit(String processName, long maxMemSize) throws RemoteException { + Parcel data = Parcel.obtain(); + Parcel reply = Parcel.obtain(); + data.writeInterfaceToken(IActivityManager.descriptor); + data.writeString(processName); + data.writeLong(maxMemSize); + mRemote.transact(SET_DUMP_HEAP_DEBUG_LIMIT_TRANSACTION, data, reply, 0); + reply.readException(); + data.recycle(); + reply.recycle(); + } + + @Override + public void dumpHeapFinished(String path) throws RemoteException { + Parcel data = Parcel.obtain(); + Parcel reply = Parcel.obtain(); + data.writeInterfaceToken(IActivityManager.descriptor); + data.writeString(path); + mRemote.transact(DUMP_HEAP_FINISHED_TRANSACTION, data, reply, 0); + reply.readException(); + data.recycle(); + reply.recycle(); + } + private IBinder mRemote; } diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 653b951e5513..97793c515c8e 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -121,7 +121,6 @@ import java.util.Locale; import java.util.Map; import java.util.Objects; import java.util.TimeZone; -import java.util.regex.Pattern; import libcore.io.DropBox; import libcore.io.EventLogger; @@ -160,7 +159,6 @@ public final class ActivityThread { private static final boolean DEBUG_MEMORY_TRIM = false; private static final boolean DEBUG_PROVIDER = false; private static final long MIN_TIME_BETWEEN_GCS = 5*1000; - private static final Pattern PATTERN_SEMICOLON = Pattern.compile(";"); private static final int SQLITE_MEM_RELEASED_EVENT_LOG_TAG = 75003; private static final int LOG_AM_ON_PAUSE_CALLED = 30021; private static final int LOG_AM_ON_RESUME_CALLED = 30022; @@ -4247,6 +4245,10 @@ public final class ActivityThread { } else { Debug.dumpNativeHeap(dhd.fd.getFileDescriptor()); } + try { + ActivityManagerNative.getDefault().dumpHeapFinished(dhd.path); + } catch (RemoteException e) { + } } final void handleDispatchPackageBroadcast(int cmd, String[] packages) { @@ -4986,7 +4988,7 @@ public final class ActivityThread { private ProviderClientRecord installProviderAuthoritiesLocked(IContentProvider provider, ContentProvider localProvider, IActivityManager.ContentProviderHolder holder) { - final String auths[] = PATTERN_SEMICOLON.split(holder.info.authority); + final String auths[] = holder.info.authority.split(";"); final int userId = UserHandle.getUserId(holder.info.applicationInfo.uid); final ProviderClientRecord pcr = new ProviderClientRecord( diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index 95870cf9675a..4bd23320b516 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -206,8 +206,10 @@ public class AppOpsManager { public static final int OP_PROJECT_MEDIA = 46; /** @hide Activate a VPN connection without user intervention. */ public static final int OP_ACTIVATE_VPN = 47; + /** @hide Access the WallpaperManagerAPI to write wallpapers. */ + public static final int OP_WRITE_WALLPAPER = 48; /** @hide */ - public static final int _NUM_OP = 48; + public static final int _NUM_OP = 49; /** Access to coarse location information. */ public static final String OPSTR_COARSE_LOCATION = @@ -285,6 +287,7 @@ public class AppOpsManager { OP_TOAST_WINDOW, OP_PROJECT_MEDIA, OP_ACTIVATE_VPN, + OP_WRITE_WALLPAPER, }; /** @@ -340,6 +343,7 @@ public class AppOpsManager { null, null, OPSTR_ACTIVATE_VPN, + null, }; /** @@ -395,6 +399,7 @@ public class AppOpsManager { "TOAST_WINDOW", "PROJECT_MEDIA", "ACTIVATE_VPN", + "WRITE_WALLPAPER", }; /** @@ -450,6 +455,7 @@ public class AppOpsManager { null, // no permission for displaying toasts null, // no permission for projecting media null, // no permission for activating vpn + null, // no permission for supporting wallpaper }; /** @@ -506,6 +512,7 @@ public class AppOpsManager { UserManager.DISALLOW_CREATE_WINDOWS, // TOAST_WINDOW null, //PROJECT_MEDIA UserManager.DISALLOW_CONFIG_VPN, // ACTIVATE_VPN + UserManager.DISALLOW_WALLPAPER, // WRITE_WALLPAPER }; /** @@ -561,6 +568,7 @@ public class AppOpsManager { true, //TOAST_WINDOW false, //PROJECT_MEDIA false, //ACTIVATE_VPN + false, //WALLPAPER }; /** @@ -615,6 +623,7 @@ public class AppOpsManager { AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_IGNORED, // OP_PROJECT_MEDIA AppOpsManager.MODE_IGNORED, // OP_ACTIVATE_VPN + AppOpsManager.MODE_ALLOWED, }; /** @@ -673,6 +682,7 @@ public class AppOpsManager { false, false, false, + false, }; private static HashMap<String, Integer> sOpStrToOp = new HashMap<String, Integer>(); diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java index e465d577924e..8e64b345d317 100644 --- a/core/java/android/app/Dialog.java +++ b/core/java/android/app/Dialog.java @@ -16,6 +16,7 @@ package android.app; +import android.annotation.CallSuper; import android.annotation.DrawableRes; import android.annotation.IdRes; import android.annotation.LayoutRes; @@ -1010,6 +1011,7 @@ public class Dialog implements DialogInterface, Window.Callback, * Note that if you override this method you should always call through * to the superclass implementation by calling super.onActionModeStarted(mode). */ + @CallSuper public void onActionModeStarted(ActionMode mode) { mActionMode = mode; } @@ -1020,6 +1022,7 @@ public class Dialog implements DialogInterface, Window.Callback, * Note that if you override this method you should always call through * to the superclass implementation by calling super.onActionModeFinished(mode). */ + @CallSuper public void onActionModeFinished(ActionMode mode) { if (mode == mActionMode) { mActionMode = null; diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java index 1277cfa22422..3dcbdd229288 100644 --- a/core/java/android/app/IActivityManager.java +++ b/core/java/android/app/IActivityManager.java @@ -482,6 +482,9 @@ public interface IActivityManager extends IInterface { public void systemBackupRestored() throws RemoteException; public void notifyCleartextNetwork(int uid, byte[] firstPacket) throws RemoteException; + public void setDumpHeapDebugLimit(String processName, long maxMemSize) throws RemoteException; + public void dumpHeapFinished(String path) throws RemoteException; + /* * Private non-Binder interfaces */ @@ -512,7 +515,7 @@ public interface IActivityManager extends IInterface { dest.writeStrongBinder(null); } dest.writeStrongBinder(connection); - dest.writeInt(noReleaseNeeded ? 1:0); + dest.writeInt(noReleaseNeeded ? 1 : 0); } public static final Parcelable.Creator<ContentProviderHolder> CREATOR @@ -531,7 +534,7 @@ public interface IActivityManager extends IInterface { private ContentProviderHolder(Parcel source) { info = ProviderInfo.CREATOR.createFromParcel(source); provider = ContentProviderNative.asInterface( - source.readStrongBinder()); + source.readStrongBinder()); connection = source.readStrongBinder(); noReleaseNeeded = source.readInt() != 0; } @@ -813,4 +816,6 @@ public interface IActivityManager extends IInterface { int REQUEST_ASSIST_CONTEXT_EXTRAS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+284; int RESIZE_TASK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+285; int GET_LOCK_TASK_MODE_STATE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+286; + int SET_DUMP_HEAP_DEBUG_LIMIT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+287; + int DUMP_HEAP_FINISHED_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+288; } diff --git a/core/java/android/app/IWallpaperManager.aidl b/core/java/android/app/IWallpaperManager.aidl index 3b5900b4a5d7..ccba250001b6 100644 --- a/core/java/android/app/IWallpaperManager.aidl +++ b/core/java/android/app/IWallpaperManager.aidl @@ -29,13 +29,18 @@ interface IWallpaperManager { /** * Set the wallpaper. */ - ParcelFileDescriptor setWallpaper(String name); + ParcelFileDescriptor setWallpaper(String name, in String callingPackage); /** * Set the live wallpaper. */ + void setWallpaperComponentChecked(in ComponentName name, in String callingPackage); + + /** + * Set the live wallpaper. + */ void setWallpaperComponent(in ComponentName name); - + /** * Get the wallpaper. */ @@ -50,7 +55,7 @@ interface IWallpaperManager { /** * Clear the wallpaper. */ - void clearWallpaper(); + void clearWallpaper(in String callingPackage); /** * Return whether there is a wallpaper set with the given name. @@ -61,7 +66,7 @@ interface IWallpaperManager { * Sets the dimension hint for the wallpaper. These hints indicate the desired * minimum width and height for the wallpaper. */ - void setDimensionHints(in int width, in int height); + void setDimensionHints(in int width, in int height, in String callingPackage); /** * Returns the desired minimum width for the wallpaper. @@ -76,7 +81,7 @@ interface IWallpaperManager { /** * Sets extra padding that we would like the wallpaper to have outside of the display. */ - void setDisplayPadding(in Rect padding); + void setDisplayPadding(in Rect padding, in String callingPackage); /** * Returns the name of the wallpaper. Private API. @@ -87,4 +92,9 @@ interface IWallpaperManager { * Informs the service that wallpaper settings have been restored. Private API. */ void settingsRestored(); + + /** + * Check whether wallpapers are supported for the calling user. + */ + boolean isWallpaperSupported(in String callingPackage); } diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java index ad2b61f2446b..5572d30284ba 100644 --- a/core/java/android/app/Instrumentation.java +++ b/core/java/android/app/Instrumentation.java @@ -1322,7 +1322,10 @@ public class Instrumentation { /* * Starts allocation counting. This triggers a gc and resets the counts. + * + * @deprecated Accurate counting is a burden on the runtime and may be removed. */ + @Deprecated public void startAllocCounting() { // Before we start trigger a GC and reset the debug counts. Run the // finalizers and another GC before starting and stopping the alloc @@ -1340,7 +1343,10 @@ public class Instrumentation { /* * Stops allocation counting. + * + * @deprecated Accurate counting is a burden on the runtime and may be removed. */ + @Deprecated public void stopAllocCounting() { Runtime.getRuntime().gc(); Runtime.getRuntime().runFinalization(); diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index 9c00e1cff607..85a6aff07c13 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -16,6 +16,7 @@ package android.app; +import android.annotation.ColorInt; import android.annotation.DrawableRes; import android.annotation.IntDef; import android.annotation.SdkConstant; @@ -338,6 +339,7 @@ public class Notification implements Parcelable * @see #FLAG_SHOW_LIGHTS * @see #flags */ + @ColorInt public int ledARGB; /** @@ -415,7 +417,6 @@ public class Notification implements Parcelable * Bit to be bitwise-ored into the {@link #flags} field that should be * set if the notification should be canceled when it is clicked by the * user. - */ public static final int FLAG_AUTO_CANCEL = 0x00000010; @@ -520,12 +521,14 @@ public class Notification implements Parcelable * {@link #icon} image (stenciled in white) atop a field of this color. Alpha components are * ignored. */ + @ColorInt public int color = COLOR_DEFAULT; /** * Special value of {@link #color} telling the system not to decorate this notification with * any special color but instead use default colors when presenting this notification. */ + @ColorInt public static final int COLOR_DEFAULT = 0; // AKA Color.TRANSPARENT /** @@ -2388,7 +2391,7 @@ public class Notification implements Parcelable * @see Notification#ledOnMS * @see Notification#ledOffMS */ - public Builder setLights(int argb, int onMs, int offMs) { + public Builder setLights(@ColorInt int argb, int onMs, int offMs) { mLedArgb = argb; mLedOnMs = onMs; mLedOffMs = offMs; @@ -2712,7 +2715,7 @@ public class Notification implements Parcelable * * @return The same Builder. */ - public Builder setColor(int argb) { + public Builder setColor(@ColorInt int argb) { mColor = argb; return this; } @@ -5160,7 +5163,7 @@ public class Notification implements Parcelable * automotive setting. This method can be used to override the color provided in the * notification in such a situation. */ - public CarExtender setColor(int color) { + public CarExtender setColor(@ColorInt int color) { mColor = color; return this; } @@ -5170,6 +5173,7 @@ public class Notification implements Parcelable * * @see setColor */ + @ColorInt public int getColor() { return mColor; } diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java index badb6064d962..22e79b6da220 100644 --- a/core/java/android/app/WallpaperManager.java +++ b/core/java/android/app/WallpaperManager.java @@ -64,7 +64,10 @@ import java.util.List; * Provides access to the system wallpaper. With WallpaperManager, you can * get the current wallpaper, get the desired dimensions for the wallpaper, set * the wallpaper, and more. Get an instance of WallpaperManager with - * {@link #getInstance(android.content.Context) getInstance()}. + * {@link #getInstance(android.content.Context) getInstance()}. + * + * <p> An app can check whether wallpapers are supported for the current user, by calling + * {@link #isWallpaperSupported()}. */ public class WallpaperManager { private static String TAG = "WallpaperManager"; @@ -249,6 +252,15 @@ public class WallpaperManager { public Bitmap peekWallpaperBitmap(Context context, boolean returnDefault) { synchronized (this) { + if (mService != null) { + try { + if (!mService.isWallpaperSupported(context.getOpPackageName())) { + return null; + } + } catch (RemoteException e) { + // Ignore + } + } if (mWallpaper != null) { return mWallpaper; } @@ -618,7 +630,9 @@ public class WallpaperManager { * wallpaper will require reloading it again from disk. */ public void forgetLoadedWallpaper() { - sGlobals.forgetLoadedWallpaper(); + if (isWallpaperSupported()) { + sGlobals.forgetLoadedWallpaper(); + } } /** @@ -717,7 +731,7 @@ public class WallpaperManager { Resources resources = mContext.getResources(); /* Set the wallpaper to the default values */ ParcelFileDescriptor fd = sGlobals.mService.setWallpaper( - "res:" + resources.getResourceName(resid)); + "res:" + resources.getResourceName(resid), mContext.getOpPackageName()); if (fd != null) { FileOutputStream fos = null; try { @@ -753,7 +767,8 @@ public class WallpaperManager { return; } try { - ParcelFileDescriptor fd = sGlobals.mService.setWallpaper(null); + ParcelFileDescriptor fd = sGlobals.mService.setWallpaper(null, + mContext.getOpPackageName()); if (fd == null) { return; } @@ -792,7 +807,8 @@ public class WallpaperManager { return; } try { - ParcelFileDescriptor fd = sGlobals.mService.setWallpaper(null); + ParcelFileDescriptor fd = sGlobals.mService.setWallpaper(null, + mContext.getOpPackageName()); if (fd == null) { return; } @@ -945,7 +961,8 @@ public class WallpaperManager { if (sGlobals.mService == null) { Log.w(TAG, "WallpaperService not running"); } else { - sGlobals.mService.setDimensionHints(minimumWidth, minimumHeight); + sGlobals.mService.setDimensionHints(minimumWidth, minimumHeight, + mContext.getOpPackageName()); } } catch (RemoteException e) { // Ignore @@ -966,7 +983,7 @@ public class WallpaperManager { if (sGlobals.mService == null) { Log.w(TAG, "WallpaperService not running"); } else { - sGlobals.mService.setDisplayPadding(padding); + sGlobals.mService.setDisplayPadding(padding, mContext.getOpPackageName()); } } catch (RemoteException e) { // Ignore @@ -1006,7 +1023,7 @@ public class WallpaperManager { return; } try { - sGlobals.mService.clearWallpaper(); + sGlobals.mService.clearWallpaper(mContext.getOpPackageName()); } catch (RemoteException e) { // Ignore } @@ -1027,7 +1044,7 @@ public class WallpaperManager { return false; } try { - sGlobals.mService.setWallpaperComponent(name); + sGlobals.mService.setWallpaperComponentChecked(name, mContext.getOpPackageName()); return true; } catch (RemoteException e) { // Ignore @@ -1096,7 +1113,24 @@ public class WallpaperManager { // Ignore. } } - + + /** + * Returns whether wallpapers are supported for the calling user. If this function returns + * false, any attempts to changing the wallpaper will have no effect. + */ + public boolean isWallpaperSupported() { + if (sGlobals.mService == null) { + Log.w(TAG, "WallpaperService not running"); + } else { + try { + return sGlobals.mService.isWallpaperSupported(mContext.getOpPackageName()); + } catch (RemoteException e) { + // Ignore + } + } + return false; + } + /** * Clear the offsets previously associated with this window through * {@link #setWallpaperOffsets(IBinder, float, float)}. This reverts diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 3d587b608d57..e23ffe412d4a 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -28,6 +28,7 @@ import android.content.IntentFilter; import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; +import android.graphics.Bitmap; import android.net.ProxyInfo; import android.os.Bundle; import android.os.Handler; @@ -108,7 +109,11 @@ public class DevicePolicyManager { * Provisioning adds a managed profile and sets the MDM as the profile owner who has full * control over the profile. * - * <p>This intent must contain the extra {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME}. + * In version {@link android.os.Build.VERSION_CODES#LOLLIPOP}, this intent must contain the + * extra {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME}. + * As of {@link android.os.Build.VERSION_CODES#MNC}, it should contain the extra + * {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME} instead, although specifying only + * {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME} is still supported. * * <p> When managed provisioning has completed, broadcasts are sent to the application specified * in the provisioning intent. The @@ -149,11 +154,36 @@ public class DevicePolicyManager { * * <p>This package is set as device owner when device owner provisioning is started by an NFC * message containing an NFC record with MIME type {@link #MIME_TYPE_PROVISIONING_NFC}. + * + * <p> When this extra is set, the application must have exactly one device admin receiver. + * This receiver will be set as the profile or device owner and active admin.</p> + + * @see DeviceAdminReceiver + * @deprecated Use {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME}. This extra is still + * supported. */ + @Deprecated public static final String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME"; /** + * A ComponentName extra indicating the device admin receiver of the mobile device management + * application that will be set as the profile owner or device owner and active admin. + * + * <p>If an application starts provisioning directly via an intent with action + * {@link #ACTION_PROVISION_MANAGED_PROFILE} the package name of this component has to match the + * package name of the application that started provisioning. + * + * <p>This component is set as device owner and active admin when device owner provisioning is + * started by an NFC message containing an NFC record with MIME type + * {@link #MIME_TYPE_PROVISIONING_NFC}. + * + * @see DeviceAdminReceiver + */ + public static final String EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME + = "android.app.extra.PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME"; + + /** * An {@link android.accounts.Account} extra holding the account to migrate during managed * profile provisioning. If the account supplied is present in the primary user, it will be * copied, along with its credentials to the managed profile and removed from the primary user. @@ -418,7 +448,6 @@ public class DevicePolicyManager { * <p>The NFC record must contain a serialized {@link java.util.Properties} object which * contains the following properties: * <ul> - * <li>{@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME}</li> * <li>{@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION}</li> * <li>{@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_COOKIE_HEADER}, optional</li> * <li>{@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM}</li> @@ -435,6 +464,15 @@ public class DevicePolicyManager { * <li>{@link #EXTRA_PROVISIONING_WIFI_PAC_URL}, optional</li> * <li>{@link #EXTRA_PROVISIONING_SKIP_ENCRYPTION}, optional</li></ul> * + * <p> + * In version {@link android.os.Build.VERSION_CODES#LOLLIPOP}, it should also contain + * {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME}. + * As of {@link android.os.Build.VERSION_CODES#MNC}, it should contain + * {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME} instead, (although + * specifying only {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME} is still supported). + * This componentName must have been converted to a String via + * {@link android.content.ComponentName#flattenToString()} + * * <p> When device owner provisioning has completed, an intent of the type * {@link DeviceAdminReceiver#ACTION_PROFILE_PROVISIONING_COMPLETE} is broadcasted to the * device owner. @@ -2862,7 +2900,6 @@ public class DevicePolicyManager { * <p>If {@link #KEYGUARD_DISABLE_TRUST_AGENTS} is set and options is not null for all admins, * then it's up to the TrustAgent itself to aggregate the values from all device admins. * <p>Consult documentation for the specific TrustAgent to determine legal options parameters. - * @hide */ public void setTrustAgentConfiguration(ComponentName admin, ComponentName target, PersistableBundle configuration) { @@ -2888,7 +2925,6 @@ public class DevicePolicyManager { * for this {@param agent} or calls it with a null configuration, null is returned. * @param agent Which component to get enabled features for. * @return configuration for the given trust agent. - * @hide */ public List<PersistableBundle> getTrustAgentConfiguration(ComponentName admin, ComponentName agent) { @@ -3645,9 +3681,14 @@ public class DevicePolicyManager { /** * Check whether the current user has been blocked by device policy from uninstalling a package. * Requires the caller to be the profile owner if checking a specific admin's policy. + * <p> + * <strong>Note:</strong> Starting from {@link android.os.Build.VERSION_CODES#LOLLIPOP_MR1}, the + * behavior of this API is changed such that passing <code>null</code> as the <code>admin</code> + * parameter will return if any admin has blocked the uninstallation. Before L MR1, passing + * <code>null</code> will cause a NullPointerException to be raised. * * @param admin The name of the admin component whose blocking policy will be checked, or null - * to check if any admin has blocked the uninstallation. + * to check if any admin has blocked the uninstallation. * @param packageName package to check. * @return true if uninstallation is blocked. */ @@ -3742,4 +3783,18 @@ public class DevicePolicyManager { } return Collections.emptyList(); } + + /** + * Called by profile or device owners to set the current user's photo. + * + * @param admin Which {@link DeviceAdminReceiver} this request is associated with. + * @param icon the bitmap to set as the photo. + */ + public void setUserIcon(ComponentName admin, Bitmap icon) { + try { + mService.setUserIcon(admin, icon); + } catch (RemoteException re) { + Log.w(TAG, "Could not set the user icon ", re); + } + } } diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl index 5cbab4b48a44..f69cf36020c4 100644 --- a/core/java/android/app/admin/IDevicePolicyManager.aidl +++ b/core/java/android/app/admin/IDevicePolicyManager.aidl @@ -20,6 +20,7 @@ package android.app.admin; import android.content.ComponentName; import android.content.Intent; import android.content.IntentFilter; +import android.graphics.Bitmap; import android.net.ProxyInfo; import android.os.Bundle; import android.os.PersistableBundle; @@ -205,4 +206,6 @@ interface IDevicePolicyManager { void clearDeviceInitializer(in ComponentName who); boolean setDeviceInitializer(in ComponentName who, in ComponentName initializer, String initializerName); String getDeviceInitializer(); + + void setUserIcon(in ComponentName admin, in Bitmap icon); } diff --git a/core/java/android/app/backup/BackupAgent.java b/core/java/android/app/backup/BackupAgent.java index 1b1e6007b4aa..7f891003ca53 100644 --- a/core/java/android/app/backup/BackupAgent.java +++ b/core/java/android/app/backup/BackupAgent.java @@ -258,6 +258,7 @@ public abstract class BackupAgent extends ContextWrapper { * * <ul> * <li>The contents of the {@link #getCacheDir()} directory</li> + * <li>The contents of the {@link #getCodeCacheDir()} directory</li> * <li>The contents of the {@link #getNoBackupFilesDir()} directory</li> * <li>The contents of the app's shared library directory</li> * </ul> @@ -285,6 +286,7 @@ public abstract class BackupAgent extends ContextWrapper { String databaseDir = getDatabasePath("foo").getParentFile().getCanonicalPath(); String sharedPrefsDir = getSharedPrefsFile("foo").getParentFile().getCanonicalPath(); String cacheDir = getCacheDir().getCanonicalPath(); + String codeCacheDir = getCodeCacheDir().getCanonicalPath(); String libDir = (appInfo.nativeLibraryDir != null) ? new File(appInfo.nativeLibraryDir).getCanonicalPath() : null; @@ -298,6 +300,7 @@ public abstract class BackupAgent extends ContextWrapper { filterSet.add(libDir); } filterSet.add(cacheDir); + filterSet.add(codeCacheDir); filterSet.add(databaseDir); filterSet.add(sharedPrefsDir); filterSet.add(filesDir); @@ -354,6 +357,7 @@ public abstract class BackupAgent extends ContextWrapper { String dbDir; String spDir; String cacheDir; + String codeCacheDir; String libDir; String efDir = null; String filePath; @@ -367,6 +371,7 @@ public abstract class BackupAgent extends ContextWrapper { dbDir = getDatabasePath("foo").getParentFile().getCanonicalPath(); spDir = getSharedPrefsFile("foo").getParentFile().getCanonicalPath(); cacheDir = getCacheDir().getCanonicalPath(); + codeCacheDir = getCodeCacheDir().getCanonicalPath(); libDir = (appInfo.nativeLibraryDir == null) ? null : new File(appInfo.nativeLibraryDir).getCanonicalPath(); @@ -380,7 +385,8 @@ public abstract class BackupAgent extends ContextWrapper { } // Now figure out which well-defined tree the file is placed in, working from - // most to least specific. We also specifically exclude the lib and cache dirs. + // most to least specific. We also specifically exclude the lib, cache, + // and code_cache dirs. filePath = file.getCanonicalPath(); } catch (IOException e) { Log.w(TAG, "Unable to obtain canonical paths"); @@ -388,9 +394,10 @@ public abstract class BackupAgent extends ContextWrapper { } if (filePath.startsWith(cacheDir) + || filePath.startsWith(codeCacheDir) || filePath.startsWith(libDir) || filePath.startsWith(nbFilesDir)) { - Log.w(TAG, "lib, cache, and no_backup files are not backed up"); + Log.w(TAG, "lib, cache, code_cache, and no_backup files are not backed up"); return; } diff --git a/core/java/android/bluetooth/BluetoothActivityEnergyInfo.java b/core/java/android/bluetooth/BluetoothActivityEnergyInfo.java index ce87329ee43d..161c339e78a8 100644 --- a/core/java/android/bluetooth/BluetoothActivityEnergyInfo.java +++ b/core/java/android/bluetooth/BluetoothActivityEnergyInfo.java @@ -26,32 +26,32 @@ import android.os.Parcelable; * @hide */ public final class BluetoothActivityEnergyInfo implements Parcelable { + private final long mTimestamp; private final int mBluetoothStackState; private final int mControllerTxTimeMs; private final int mControllerRxTimeMs; private final int mControllerIdleTimeMs; private final int mControllerEnergyUsed; - private final long timestamp; public static final int BT_STACK_STATE_INVALID = 0; public static final int BT_STACK_STATE_STATE_ACTIVE = 1; public static final int BT_STACK_STATE_STATE_SCANNING = 2; public static final int BT_STACK_STATE_STATE_IDLE = 3; - public BluetoothActivityEnergyInfo(int stackState, int txTime, int rxTime, - int idleTime, int energyUsed) { + public BluetoothActivityEnergyInfo(long timestamp, int stackState, + int txTime, int rxTime, int idleTime, int energyUsed) { + mTimestamp = timestamp; mBluetoothStackState = stackState; mControllerTxTimeMs = txTime; mControllerRxTimeMs = rxTime; mControllerIdleTimeMs = idleTime; mControllerEnergyUsed = energyUsed; - timestamp = System.currentTimeMillis(); } @Override public String toString() { return "BluetoothActivityEnergyInfo{" - + " timestamp=" + timestamp + + " mTimestamp=" + mTimestamp + " mBluetoothStackState=" + mBluetoothStackState + " mControllerTxTimeMs=" + mControllerTxTimeMs + " mControllerRxTimeMs=" + mControllerRxTimeMs @@ -63,13 +63,14 @@ public final class BluetoothActivityEnergyInfo implements Parcelable { public static final Parcelable.Creator<BluetoothActivityEnergyInfo> CREATOR = new Parcelable.Creator<BluetoothActivityEnergyInfo>() { public BluetoothActivityEnergyInfo createFromParcel(Parcel in) { + long timestamp = in.readLong(); int stackState = in.readInt(); int txTime = in.readInt(); int rxTime = in.readInt(); int idleTime = in.readInt(); int energyUsed = in.readInt(); - return new BluetoothActivityEnergyInfo(stackState, txTime, rxTime, - idleTime, energyUsed); + return new BluetoothActivityEnergyInfo(timestamp, stackState, + txTime, rxTime, idleTime, energyUsed); } public BluetoothActivityEnergyInfo[] newArray(int size) { return new BluetoothActivityEnergyInfo[size]; @@ -77,6 +78,7 @@ public final class BluetoothActivityEnergyInfo implements Parcelable { }; public void writeToParcel(Parcel out, int flags) { + out.writeLong(mTimestamp); out.writeInt(mBluetoothStackState); out.writeInt(mControllerTxTimeMs); out.writeInt(mControllerRxTimeMs); @@ -123,11 +125,12 @@ public final class BluetoothActivityEnergyInfo implements Parcelable { public int getControllerEnergyUsed() { return mControllerEnergyUsed; } + /** - * @return timestamp(wall clock) of record creation + * @return timestamp(real time elapsed in milliseconds since boot) of record creation. */ public long getTimeStamp() { - return timestamp; + return mTimestamp; } /** diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 010c860b0df4..61cdec3d9e9a 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -16,6 +16,7 @@ package android.content; +import android.annotation.CheckResult; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; @@ -3041,6 +3042,7 @@ public abstract class Context { * @see PackageManager#checkPermission(String, String) * @see #checkCallingPermission */ + @CheckResult(suggest="#enforcePermission(String,int,int,String)") @PackageManager.PermissionResult public abstract int checkPermission(@NonNull String permission, int pid, int uid); @@ -3070,6 +3072,7 @@ public abstract class Context { * @see #checkPermission * @see #checkCallingOrSelfPermission */ + @CheckResult(suggest="#enforceCallingPermission(String,String)") @PackageManager.PermissionResult public abstract int checkCallingPermission(@NonNull String permission); @@ -3089,6 +3092,7 @@ public abstract class Context { * @see #checkPermission * @see #checkCallingPermission */ + @CheckResult(suggest="#enforceCallingOrSelfPermission(String,String)") @PackageManager.PermissionResult public abstract int checkCallingOrSelfPermission(@NonNull String permission); @@ -3233,6 +3237,7 @@ public abstract class Context { * * @see #checkCallingUriPermission */ + @CheckResult(suggest="#enforceUriPermission(Uri,int,int,String)") public abstract int checkUriPermission(Uri uri, int pid, int uid, @Intent.AccessUriMode int modeFlags); @@ -3261,6 +3266,7 @@ public abstract class Context { * * @see #checkUriPermission(Uri, int, int, int) */ + @CheckResult(suggest="#enforceCallingUriPermission(Uri,int,String)") public abstract int checkCallingUriPermission(Uri uri, @Intent.AccessUriMode int modeFlags); /** @@ -3280,6 +3286,7 @@ public abstract class Context { * * @see #checkCallingUriPermission */ + @CheckResult(suggest="#enforceCallingOrSelfUriPermission(Uri,int,String)") public abstract int checkCallingOrSelfUriPermission(Uri uri, @Intent.AccessUriMode int modeFlags); @@ -3305,6 +3312,7 @@ public abstract class Context { * is allowed to access that uri or holds one of the given permissions, or * {@link PackageManager#PERMISSION_DENIED} if it is not. */ + @CheckResult(suggest="#enforceUriPermission(Uri,String,String,int,int,int,String)") public abstract int checkUriPermission(@Nullable Uri uri, @Nullable String readPermission, @Nullable String writePermission, int pid, int uid, @Intent.AccessUriMode int modeFlags); diff --git a/core/java/android/content/UriMatcher.java b/core/java/android/content/UriMatcher.java index 8487dae4f7bf..71a035e47f19 100644 --- a/core/java/android/content/UriMatcher.java +++ b/core/java/android/content/UriMatcher.java @@ -20,7 +20,6 @@ import android.net.Uri; import java.util.ArrayList; import java.util.List; -import java.util.regex.Pattern; /** Utility class to aid in matching URIs in content providers. @@ -171,7 +170,7 @@ public class UriMatcher if (path.length() > 0 && path.charAt(0) == '/') { newPath = path.substring(1); } - tokens = PATH_SPLIT_PATTERN.split(newPath); + tokens = newPath.split("/"); } int numTokens = tokens != null ? tokens.length : 0; @@ -207,8 +206,6 @@ public class UriMatcher node.mCode = code; } - static final Pattern PATH_SPLIT_PATTERN = Pattern.compile("/"); - /** * Try to match against the path in a url. * diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index ebc8e1efdf01..036568952e3e 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -16,6 +16,7 @@ package android.content.pm; +import android.annotation.CheckResult; import android.annotation.DrawableRes; import android.annotation.IntDef; import android.annotation.NonNull; @@ -2121,6 +2122,7 @@ public abstract class PackageManager { * @see #PERMISSION_GRANTED * @see #PERMISSION_DENIED */ + @CheckResult public abstract int checkPermission(String permName, String pkgName); /** @@ -2248,6 +2250,7 @@ public abstract class PackageManager { * @see #SIGNATURE_NO_MATCH * @see #SIGNATURE_UNKNOWN_PACKAGE */ + @CheckResult public abstract int checkSignatures(String pkg1, String pkg2); /** @@ -2270,6 +2273,7 @@ public abstract class PackageManager { * @see #SIGNATURE_NO_MATCH * @see #SIGNATURE_UNKNOWN_PACKAGE */ + @CheckResult public abstract int checkSignatures(int uid1, int uid2); /** diff --git a/core/java/android/content/res/ColorStateList.java b/core/java/android/content/res/ColorStateList.java index ace402a2b1f7..841b09d0ddb6 100644 --- a/core/java/android/content/res/ColorStateList.java +++ b/core/java/android/content/res/ColorStateList.java @@ -16,6 +16,7 @@ package android.content.res; +import android.annotation.ColorInt; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.res.Resources.Theme; @@ -91,7 +92,7 @@ public class ColorStateList implements Parcelable { * Creates a ColorStateList that returns the specified mapping from * states to colors. */ - public ColorStateList(int[][] states, int[] colors) { + public ColorStateList(int[][] states, @ColorInt int[] colors) { mStateSpecs = states; mColors = colors; @@ -102,7 +103,7 @@ public class ColorStateList implements Parcelable { * @return A ColorStateList containing a single color. */ @NonNull - public static ColorStateList valueOf(int color) { + public static ColorStateList valueOf(@ColorInt int color) { synchronized (sCache) { final int index = sCache.indexOfKey(color); if (index >= 0) { @@ -436,6 +437,7 @@ public class ColorStateList implements Parcelable { * * @return the default color in this {@link ColorStateList}. */ + @ColorInt public int getDefaultColor() { return mDefaultColor; } diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java index 584f3f65abd6..5dc9ef933c3f 100644 --- a/core/java/android/content/res/Resources.java +++ b/core/java/android/content/res/Resources.java @@ -16,6 +16,7 @@ package android.content.res; +import android.annotation.ColorInt; import com.android.internal.util.XmlUtils; import org.xmlpull.v1.XmlPullParser; @@ -925,6 +926,7 @@ public class Resources { * @return A single color value in the form 0xAARRGGBB. * @deprecated Use {@link #getColor(int, Theme)} instead. */ + @ColorInt public int getColor(@ColorRes int id) throws NotFoundException { return getColor(id, null); } @@ -945,6 +947,7 @@ public class Resources { * * @return A single color value in the form 0xAARRGGBB. */ + @ColorInt public int getColor(@ColorRes int id, @Nullable Theme theme) throws NotFoundException { TypedValue value; synchronized (mAccessLock) { diff --git a/core/java/android/content/res/TypedArray.java b/core/java/android/content/res/TypedArray.java index 3e07f0c5183c..1fca9204fe42 100644 --- a/core/java/android/content/res/TypedArray.java +++ b/core/java/android/content/res/TypedArray.java @@ -17,6 +17,7 @@ package android.content.res; import android.annotation.AnyRes; +import android.annotation.ColorInt; import android.annotation.Nullable; import android.graphics.drawable.Drawable; import android.os.StrictMode; @@ -420,7 +421,8 @@ public class TypedArray { * @throws UnsupportedOperationException if the attribute is defined but is * not an integer color or color state list. */ - public int getColor(int index, int defValue) { + @ColorInt + public int getColor(int index, @ColorInt int defValue) { if (mRecycled) { throw new RuntimeException("Cannot make calls to a recycled instance!"); } @@ -442,8 +444,10 @@ public class TypedArray { } return defValue; } else if (type == TypedValue.TYPE_ATTRIBUTE) { + final TypedValue value = mValue; + getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value); throw new UnsupportedOperationException( - "Failed to resolve attribute at index " + index); + "Failed to resolve attribute at index " + index + ": " + value); } throw new UnsupportedOperationException("Can't convert to color: type=0x" @@ -478,7 +482,7 @@ public class TypedArray { if (getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value)) { if (value.type == TypedValue.TYPE_ATTRIBUTE) { throw new UnsupportedOperationException( - "Failed to resolve attribute at index " + index); + "Failed to resolve attribute at index " + index + ": " + value); } return mResources.loadColorStateList(value, value.resourceId, mTheme); } @@ -514,8 +518,10 @@ public class TypedArray { && type <= TypedValue.TYPE_LAST_INT) { return data[index+AssetManager.STYLE_DATA]; } else if (type == TypedValue.TYPE_ATTRIBUTE) { + final TypedValue value = mValue; + getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value); throw new UnsupportedOperationException( - "Failed to resolve attribute at index " + index); + "Failed to resolve attribute at index " + index + ": " + value); } throw new UnsupportedOperationException("Can't convert to integer: type=0x" @@ -558,8 +564,10 @@ public class TypedArray { return TypedValue.complexToDimension( data[index + AssetManager.STYLE_DATA], mMetrics); } else if (type == TypedValue.TYPE_ATTRIBUTE) { + final TypedValue value = mValue; + getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value); throw new UnsupportedOperationException( - "Failed to resolve attribute at index " + index); + "Failed to resolve attribute at index " + index + ": " + value); } throw new UnsupportedOperationException("Can't convert to dimension: type=0x" @@ -603,8 +611,10 @@ public class TypedArray { return TypedValue.complexToDimensionPixelOffset( data[index + AssetManager.STYLE_DATA], mMetrics); } else if (type == TypedValue.TYPE_ATTRIBUTE) { + final TypedValue value = mValue; + getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value); throw new UnsupportedOperationException( - "Failed to resolve attribute at index " + index); + "Failed to resolve attribute at index " + index + ": " + value); } throw new UnsupportedOperationException("Can't convert to dimension: type=0x" @@ -649,8 +659,10 @@ public class TypedArray { return TypedValue.complexToDimensionPixelSize( data[index+AssetManager.STYLE_DATA], mMetrics); } else if (type == TypedValue.TYPE_ATTRIBUTE) { + final TypedValue value = mValue; + getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value); throw new UnsupportedOperationException( - "Failed to resolve attribute at index " + index); + "Failed to resolve attribute at index " + index + ": " + value); } throw new UnsupportedOperationException("Can't convert to dimension: type=0x" @@ -690,8 +702,10 @@ public class TypedArray { return TypedValue.complexToDimensionPixelSize( data[index+AssetManager.STYLE_DATA], mMetrics); } else if (type == TypedValue.TYPE_ATTRIBUTE) { + final TypedValue value = mValue; + getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value); throw new UnsupportedOperationException( - "Failed to resolve attribute at index " + index); + "Failed to resolve attribute at index " + index + ": " + value); } throw new UnsupportedOperationException(getPositionDescription() @@ -763,8 +777,10 @@ public class TypedArray { return TypedValue.complexToFraction( data[index+AssetManager.STYLE_DATA], base, pbase); } else if (type == TypedValue.TYPE_ATTRIBUTE) { + final TypedValue value = mValue; + getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value); throw new UnsupportedOperationException( - "Failed to resolve attribute at index " + index); + "Failed to resolve attribute at index " + index + ": " + value); } throw new UnsupportedOperationException("Can't convert to fraction: type=0x" @@ -851,7 +867,7 @@ public class TypedArray { if (getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value)) { if (value.type == TypedValue.TYPE_ATTRIBUTE) { throw new UnsupportedOperationException( - "Failed to resolve attribute at index " + index); + "Failed to resolve attribute at index " + index + ": " + value); } return mResources.loadDrawable(value, value.resourceId, mTheme); } diff --git a/core/java/android/gesture/GestureOverlayView.java b/core/java/android/gesture/GestureOverlayView.java index e1a2a25feb1b..e0d454cb44d0 100644 --- a/core/java/android/gesture/GestureOverlayView.java +++ b/core/java/android/gesture/GestureOverlayView.java @@ -16,6 +16,7 @@ package android.gesture; +import android.annotation.ColorInt; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; @@ -204,18 +205,20 @@ public class GestureOverlayView extends FrameLayout { mOrientation = orientation; } - public void setGestureColor(int color) { + public void setGestureColor(@ColorInt int color) { mCertainGestureColor = color; } - public void setUncertainGestureColor(int color) { + public void setUncertainGestureColor(@ColorInt int color) { mUncertainGestureColor = color; } + @ColorInt public int getUncertainGestureColor() { return mUncertainGestureColor; } + @ColorInt public int getGestureColor() { return mCertainGestureColor; } diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java index 87ec06a5b237..a0217c2171b4 100644 --- a/core/java/android/hardware/camera2/CameraCharacteristics.java +++ b/core/java/android/hardware/camera2/CameraCharacteristics.java @@ -2493,6 +2493,83 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri public static final Key<Integer> SYNC_MAX_LATENCY = new Key<Integer>("android.sync.maxLatency", int.class); + /** + * <p>The available depth dataspace stream + * configurations that this camera device supports + * (i.e. format, width, height, output/input stream).</p> + * <p>These are output stream configurations for use with + * dataSpace HAL_DATASPACE_DEPTH. The configurations are + * listed as <code>(format, width, height, input?)</code> tuples.</p> + * <p>Only devices that support depth output for at least + * the HAL_PIXEL_FORMAT_Y16 dense depth map may include + * this entry.</p> + * <p>A device that also supports the HAL_PIXEL_FORMAT_BLOB + * sparse depth point cloud must report a single entry for + * the format in this list as <code>(HAL_PIXEL_FORMAT_BLOB, + * android.depth.maxDepthSamples, 1, OUTPUT)</code> in addition to + * the entries for HAL_PIXEL_FORMAT_Y16.</p> + * <p><b>Optional</b> - This value may be {@code null} on some devices.</p> + * <p><b>Limited capability</b> - + * Present on all camera devices that report being at least {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED HARDWARE_LEVEL_LIMITED} devices in the + * {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel} key</p> + * + * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL + * @hide + */ + public static final Key<android.hardware.camera2.params.StreamConfiguration[]> DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS = + new Key<android.hardware.camera2.params.StreamConfiguration[]>("android.depth.availableDepthStreamConfigurations", android.hardware.camera2.params.StreamConfiguration[].class); + + /** + * <p>This lists the minimum frame duration for each + * format/size combination for depth output formats.</p> + * <p>This should correspond to the frame duration when only that + * stream is active, with all processing (typically in android.*.mode) + * set to either OFF or FAST.</p> + * <p>When multiple streams are used in a request, the minimum frame + * duration will be max(individual stream min durations).</p> + * <p>The minimum frame duration of a stream (of a particular format, size) + * is the same regardless of whether the stream is input or output.</p> + * <p>See {@link CaptureRequest#SENSOR_FRAME_DURATION android.sensor.frameDuration} and + * android.scaler.availableStallDurations for more details about + * calculating the max frame rate.</p> + * <p>(Keep in sync with + * StreamConfigurationMap#getOutputMinFrameDuration)</p> + * <p><b>Units</b>: (format, width, height, ns) x n</p> + * <p><b>Optional</b> - This value may be {@code null} on some devices.</p> + * <p><b>Limited capability</b> - + * Present on all camera devices that report being at least {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED HARDWARE_LEVEL_LIMITED} devices in the + * {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel} key</p> + * + * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL + * @see CaptureRequest#SENSOR_FRAME_DURATION + * @hide + */ + public static final Key<android.hardware.camera2.params.StreamConfigurationDuration[]> DEPTH_AVAILABLE_DEPTH_MIN_FRAME_DURATIONS = + new Key<android.hardware.camera2.params.StreamConfigurationDuration[]>("android.depth.availableDepthMinFrameDurations", android.hardware.camera2.params.StreamConfigurationDuration[].class); + + /** + * <p>This lists the maximum stall duration for each + * format/size combination for depth streams.</p> + * <p>A stall duration is how much extra time would get added + * to the normal minimum frame duration for a repeating request + * that has streams with non-zero stall.</p> + * <p>This functions similarly to + * android.scaler.availableStallDurations for depth + * streams.</p> + * <p>All depth output stream formats may have a nonzero stall + * duration.</p> + * <p><b>Units</b>: (format, width, height, ns) x n</p> + * <p><b>Optional</b> - This value may be {@code null} on some devices.</p> + * <p><b>Limited capability</b> - + * Present on all camera devices that report being at least {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED HARDWARE_LEVEL_LIMITED} devices in the + * {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel} key</p> + * + * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL + * @hide + */ + public static final Key<android.hardware.camera2.params.StreamConfigurationDuration[]> DEPTH_AVAILABLE_DEPTH_STALL_DURATIONS = + new Key<android.hardware.camera2.params.StreamConfigurationDuration[]>("android.depth.availableDepthStallDurations", android.hardware.camera2.params.StreamConfigurationDuration[].class); + /*~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~ * End generated code *~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~O@*/ diff --git a/core/java/android/hardware/camera2/ICameraDeviceUser.aidl b/core/java/android/hardware/camera2/ICameraDeviceUser.aidl index 50a58edda35b..d286d381f6e8 100644 --- a/core/java/android/hardware/camera2/ICameraDeviceUser.aidl +++ b/core/java/android/hardware/camera2/ICameraDeviceUser.aidl @@ -66,7 +66,7 @@ interface ICameraDeviceUser int deleteStream(int streamId); // non-negative value is the stream ID. negative value is status_t - int createStream(int width, int height, int format, in Surface surface); + int createStream(in Surface surface); int createDefaultRequest(int templateId, out CameraMetadataNative request); diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java index ec450bd14cc8..78aefa5675f3 100644 --- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java +++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java @@ -373,9 +373,7 @@ public class CameraDeviceImpl extends CameraDevice { // Add all new streams for (Surface s : addSet) { - // TODO: remove width,height,format since we are ignoring - // it. - int streamId = mRemoteDevice.createStream(0, 0, 0, s); + int streamId = mRemoteDevice.createStream(s); mConfiguredOutputs.put(streamId, s); } diff --git a/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java b/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java index fcf172c47ec4..26cd498751d0 100644 --- a/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java +++ b/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java @@ -504,7 +504,7 @@ public class CameraDeviceUserShim implements ICameraDeviceUser { } @Override - public int createStream(int width, int height, int format, Surface surface) { + public int createStream(Surface surface) { if (DEBUG) { Log.d(TAG, "createStream called."); } diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java index 0fee4b341475..d96a0e955068 100644 --- a/core/java/android/os/BatteryStats.java +++ b/core/java/android/os/BatteryStats.java @@ -86,10 +86,10 @@ public abstract class BatteryStats implements Parcelable { */ public static final int WIFI_SCAN = 6; - /** - * A constant indicating a wifi multicast timer - */ - public static final int WIFI_MULTICAST_ENABLED = 7; + /** + * A constant indicating a wifi multicast timer + */ + public static final int WIFI_MULTICAST_ENABLED = 7; /** * A constant indicating a video turn on timer @@ -353,7 +353,9 @@ public abstract class BatteryStats implements Parcelable { public abstract long getWifiRunningTime(long elapsedRealtimeUs, int which); public abstract long getFullWifiLockTime(long elapsedRealtimeUs, int which); public abstract long getWifiScanTime(long elapsedRealtimeUs, int which); + public abstract int getWifiScanCount(int which); public abstract long getWifiBatchedScanTime(int csphBin, long elapsedRealtimeUs, int which); + public abstract int getWifiBatchedScanCount(int csphBin, int which); public abstract long getWifiMulticastTime(long elapsedRealtimeUs, int which); public abstract long getAudioTurnedOnTime(long elapsedRealtimeUs, int which); public abstract long getVideoTurnedOnTime(long elapsedRealtimeUs, int which); @@ -439,14 +441,14 @@ public abstract class BatteryStats implements Parcelable { public abstract boolean isActive(); /** - * Returns the total time (in 1/100 sec) spent executing in user code. + * Returns the total time (in milliseconds) spent executing in user code. * * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT. */ public abstract long getUserTime(int which); /** - * Returns the total time (in 1/100 sec) spent executing in system code. + * Returns the total time (in milliseconds) spent executing in system code. * * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT. */ @@ -474,14 +476,14 @@ public abstract class BatteryStats implements Parcelable { public abstract int getNumAnrs(int which); /** - * Returns the cpu time spent in microseconds while the process was in the foreground. + * Returns the cpu time (milliseconds) spent while the process was in the foreground. * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT. * @return foreground cpu time in microseconds */ public abstract long getForegroundTime(int which); /** - * Returns the approximate cpu time spent in microseconds, at a certain CPU speed. + * Returns the approximate cpu time (in milliseconds) spent at a certain CPU speed. * @param speedStep the index of the CPU speed. This is not the actual speed of the * CPU. * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT. @@ -1856,6 +1858,15 @@ public abstract class BatteryStats implements Parcelable { public abstract long getNetworkActivityBytes(int type, int which); public abstract long getNetworkActivityPackets(int type, int which); + public static final int CONTROLLER_IDLE_TIME = 0; + public static final int CONTROLLER_RX_TIME = 1; + public static final int CONTROLLER_TX_TIME = 2; + public static final int CONTROLLER_ENERGY = 3; + public static final int NUM_CONTROLLER_ACTIVITY_TYPES = CONTROLLER_ENERGY + 1; + + public abstract long getBluetoothControllerActivity(int type, int which); + public abstract long getWifiControllerActivity(int type, int which); + /** * Return the wall clock time when battery stats data collection started. */ @@ -2140,13 +2151,6 @@ public abstract class BatteryStats implements Parcelable { } } - public final static void formatTime(StringBuilder sb, long time) { - long sec = time / 100; - formatTimeRaw(sb, sec); - sb.append((time - (sec * 100)) * 10); - sb.append("ms "); - } - public final static void formatTimeMs(StringBuilder sb, long time) { long sec = time / 1000; formatTimeRaw(sb, sec); @@ -2572,6 +2576,7 @@ public abstract class BatteryStats implements Parcelable { long wifiPacketsTx = u.getNetworkActivityPackets(NETWORK_WIFI_TX_DATA, which); long fullWifiLockOnTime = u.getFullWifiLockTime(rawRealtime, which); long wifiScanTime = u.getWifiScanTime(rawRealtime, which); + int wifiScanCount = u.getWifiScanCount(which); long uidWifiRunningTime = u.getWifiRunningTime(rawRealtime, which); if (mobileBytesRx > 0 || mobileBytesTx > 0 || wifiBytesRx > 0 || wifiBytesTx > 0 @@ -2584,10 +2589,10 @@ public abstract class BatteryStats implements Parcelable { mobileActiveTime, mobileActiveCount); } - if (fullWifiLockOnTime != 0 || wifiScanTime != 0 + if (fullWifiLockOnTime != 0 || wifiScanTime != 0 || wifiScanCount != 0 || uidWifiRunningTime != 0) { dumpLine(pw, uid, category, WIFI_DATA, - fullWifiLockOnTime, wifiScanTime, uidWifiRunningTime); + fullWifiLockOnTime, wifiScanTime, uidWifiRunningTime, wifiScanCount); } if (u.hasUserActivity()) { @@ -2705,9 +2710,9 @@ public abstract class BatteryStats implements Parcelable { : processStats.entrySet()) { Uid.Proc ps = ent.getValue(); - final long userMillis = ps.getUserTime(which) * 10; - final long systemMillis = ps.getSystemTime(which) * 10; - final long foregroundMillis = ps.getForegroundTime(which) * 10; + final long userMillis = ps.getUserTime(which); + final long systemMillis = ps.getSystemTime(which); + final long foregroundMillis = ps.getForegroundTime(which); final int starts = ps.getStarts(which); final int numCrashes = ps.getNumCrashes(which); final int numAnrs = ps.getNumAnrs(which); @@ -3146,6 +3151,35 @@ public abstract class BatteryStats implements Parcelable { if (!didOne) sb.append(" (no activity)"); pw.println(sb.toString()); + final long wifiIdleTimeMs = getBluetoothControllerActivity(CONTROLLER_IDLE_TIME, which); + final long wifiRxTimeMs = getBluetoothControllerActivity(CONTROLLER_RX_TIME, which); + final long wifiTxTimeMs = getBluetoothControllerActivity(CONTROLLER_TX_TIME, which); + final long wifiTotalTimeMs = wifiIdleTimeMs + wifiRxTimeMs + wifiTxTimeMs; + + sb.setLength(0); + sb.append(prefix); + sb.append(" WiFi Idle time: "); formatTimeMs(sb, wifiIdleTimeMs); + sb.append(" ("); + sb.append(formatRatioLocked(wifiIdleTimeMs, wifiTotalTimeMs)); + sb.append(")"); + pw.println(sb.toString()); + + sb.setLength(0); + sb.append(prefix); + sb.append(" WiFi Rx time: "); formatTimeMs(sb, wifiRxTimeMs); + sb.append(" ("); + sb.append(formatRatioLocked(wifiRxTimeMs, wifiTotalTimeMs)); + sb.append(")"); + pw.println(sb.toString()); + + sb.setLength(0); + sb.append(prefix); + sb.append(" WiFi Tx time: "); formatTimeMs(sb, wifiTxTimeMs); + sb.append(" ("); + sb.append(formatRatioLocked(wifiTxTimeMs, wifiTotalTimeMs)); + sb.append(")"); + pw.println(sb.toString()); + sb.setLength(0); sb.append(prefix); sb.append(" Bluetooth on: "); formatTimeMs(sb, bluetoothOnTime / 1000); @@ -3173,9 +3207,41 @@ public abstract class BatteryStats implements Parcelable { sb.append(getPhoneDataConnectionCount(i, which)); sb.append("x"); } + if (!didOne) sb.append(" (no activity)"); pw.println(sb.toString()); + final long bluetoothIdleTimeMs = + getBluetoothControllerActivity(CONTROLLER_IDLE_TIME, which); + final long bluetoothRxTimeMs = getBluetoothControllerActivity(CONTROLLER_RX_TIME, which); + final long bluetoothTxTimeMs = getBluetoothControllerActivity(CONTROLLER_TX_TIME, which); + final long bluetoothTotalTimeMs = bluetoothIdleTimeMs + bluetoothRxTimeMs + + bluetoothTxTimeMs; + + sb.setLength(0); + sb.append(prefix); + sb.append(" Bluetooth Idle time: "); formatTimeMs(sb, bluetoothIdleTimeMs); + sb.append(" ("); + sb.append(formatRatioLocked(bluetoothIdleTimeMs, bluetoothTotalTimeMs)); + sb.append(")"); + pw.println(sb.toString()); + + sb.setLength(0); + sb.append(prefix); + sb.append(" Bluetooth Rx time: "); formatTimeMs(sb, bluetoothRxTimeMs); + sb.append(" ("); + sb.append(formatRatioLocked(bluetoothRxTimeMs, bluetoothTotalTimeMs)); + sb.append(")"); + pw.println(sb.toString()); + + sb.setLength(0); + sb.append(prefix); + sb.append(" Bluetooth Tx time: "); formatTimeMs(sb, bluetoothTxTimeMs); + sb.append(" ("); + sb.append(formatRatioLocked(bluetoothTxTimeMs, bluetoothTotalTimeMs)); + sb.append(")"); + pw.println(sb.toString()); + pw.println(); if (which == STATS_SINCE_UNPLUGGED) { @@ -3420,6 +3486,7 @@ public abstract class BatteryStats implements Parcelable { long wifiTxPackets = u.getNetworkActivityPackets(NETWORK_WIFI_TX_DATA, which); long fullWifiLockOnTime = u.getFullWifiLockTime(rawRealtime, which); long wifiScanTime = u.getWifiScanTime(rawRealtime, which); + int wifiScanCount = u.getWifiScanCount(which); long uidWifiRunningTime = u.getWifiRunningTime(rawRealtime, which); if (mobileRxBytes > 0 || mobileTxBytes > 0 @@ -3455,7 +3522,7 @@ public abstract class BatteryStats implements Parcelable { pw.print(" received, "); pw.print(wifiTxPackets); pw.println(" sent)"); } - if (fullWifiLockOnTime != 0 || wifiScanTime != 0 + if (fullWifiLockOnTime != 0 || wifiScanTime != 0 || wifiScanCount != 0 || uidWifiRunningTime != 0) { sb.setLength(0); sb.append(prefix); sb.append(" Wifi Running: "); @@ -3469,7 +3536,9 @@ public abstract class BatteryStats implements Parcelable { sb.append(prefix); sb.append(" Wifi Scan: "); formatTimeMs(sb, wifiScanTime / 1000); sb.append("("); sb.append(formatRatioLocked(wifiScanTime, - whichBatteryRealtime)); sb.append(")"); + whichBatteryRealtime)); sb.append(") "); + sb.append(wifiScanCount); + sb.append("x"); pw.println(sb.toString()); } @@ -3728,9 +3797,9 @@ public abstract class BatteryStats implements Parcelable { sb.append(prefix); sb.append(" Proc "); sb.append(ent.getKey()); sb.append(":\n"); sb.append(prefix); sb.append(" CPU: "); - formatTime(sb, userTime); sb.append("usr + "); - formatTime(sb, systemTime); sb.append("krn ; "); - formatTime(sb, foregroundTime); sb.append("fg"); + formatTimeMs(sb, userTime); sb.append("usr + "); + formatTimeMs(sb, systemTime); sb.append("krn ; "); + formatTimeMs(sb, foregroundTime); sb.append("fg"); if (starts != 0 || numCrashes != 0 || numAnrs != 0) { sb.append("\n"); sb.append(prefix); sb.append(" "); boolean hasOne = false; diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java index d03365b657a9..512e2127e6b0 100644 --- a/core/java/android/os/Debug.java +++ b/core/java/android/os/Debug.java @@ -63,7 +63,10 @@ public final class Debug * * TRACE_COUNT_ALLOCS adds the results from startAllocCounting to the * trace key file. + * + * @deprecated Accurate counting is a burden on the runtime and may be removed. */ + @Deprecated public static final int TRACE_COUNT_ALLOCS = VMDebug.TRACE_COUNT_ALLOCS; /** @@ -760,7 +763,7 @@ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Lo /** * Stop counting the number and aggregate size of memory allocations. * - * @see #startAllocCounting() + * @deprecated Accurate counting is a burden on the runtime and may be removed. */ @Deprecated public static void stopAllocCounting() { @@ -770,7 +773,10 @@ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Lo /** * Returns the global count of objects allocated by the runtime between a * {@link #startAllocCounting() start} and {@link #stopAllocCounting() stop}. + * + * @deprecated Accurate counting is a burden on the runtime and may be removed. */ + @Deprecated public static int getGlobalAllocCount() { return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_ALLOCATED_OBJECTS); } @@ -778,7 +784,10 @@ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Lo /** * Clears the global count of objects allocated. * @see #getGlobalAllocCount() + * + * @deprecated Accurate counting is a burden on the runtime and may be removed. */ + @Deprecated public static void resetGlobalAllocCount() { VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_ALLOCATED_OBJECTS); } @@ -786,7 +795,10 @@ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Lo /** * Returns the global size, in bytes, of objects allocated by the runtime between a * {@link #startAllocCounting() start} and {@link #stopAllocCounting() stop}. + * + * @deprecated Accurate counting is a burden on the runtime and may be removed. */ + @Deprecated public static int getGlobalAllocSize() { return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_ALLOCATED_BYTES); } @@ -794,7 +806,10 @@ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Lo /** * Clears the global size of objects allocated. * @see #getGlobalAllocSize() + * + * @deprecated Accurate counting is a burden on the runtime and may be removed. */ + @Deprecated public static void resetGlobalAllocSize() { VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_ALLOCATED_BYTES); } @@ -802,7 +817,10 @@ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Lo /** * Returns the global count of objects freed by the runtime between a * {@link #startAllocCounting() start} and {@link #stopAllocCounting() stop}. + * + * @deprecated Accurate counting is a burden on the runtime and may be removed. */ + @Deprecated public static int getGlobalFreedCount() { return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_FREED_OBJECTS); } @@ -810,7 +828,10 @@ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Lo /** * Clears the global count of objects freed. * @see #getGlobalFreedCount() + * + * @deprecated Accurate counting is a burden on the runtime and may be removed. */ + @Deprecated public static void resetGlobalFreedCount() { VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_FREED_OBJECTS); } @@ -818,7 +839,10 @@ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Lo /** * Returns the global size, in bytes, of objects freed by the runtime between a * {@link #startAllocCounting() start} and {@link #stopAllocCounting() stop}. + * + * @deprecated Accurate counting is a burden on the runtime and may be removed. */ + @Deprecated public static int getGlobalFreedSize() { return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_FREED_BYTES); } @@ -826,7 +850,10 @@ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Lo /** * Clears the global size of objects freed. * @see #getGlobalFreedSize() + * + * @deprecated Accurate counting is a burden on the runtime and may be removed. */ + @Deprecated public static void resetGlobalFreedSize() { VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_FREED_BYTES); } @@ -834,7 +861,10 @@ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Lo /** * Returns the number of non-concurrent GC invocations between a * {@link #startAllocCounting() start} and {@link #stopAllocCounting() stop}. + * + * @deprecated Accurate counting is a burden on the runtime and may be removed. */ + @Deprecated public static int getGlobalGcInvocationCount() { return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_GC_INVOCATIONS); } @@ -842,7 +872,10 @@ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Lo /** * Clears the count of non-concurrent GC invocations. * @see #getGlobalGcInvocationCount() + * + * @deprecated Accurate counting is a burden on the runtime and may be removed. */ + @Deprecated public static void resetGlobalGcInvocationCount() { VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_GC_INVOCATIONS); } @@ -851,7 +884,10 @@ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Lo * Returns the number of classes successfully initialized (ie those that executed without * throwing an exception) between a {@link #startAllocCounting() start} and * {@link #stopAllocCounting() stop}. + * + * @deprecated Accurate counting is a burden on the runtime and may be removed. */ + @Deprecated public static int getGlobalClassInitCount() { return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_CLASS_INIT_COUNT); } @@ -859,7 +895,10 @@ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Lo /** * Clears the count of classes initialized. * @see #getGlobalClassInitCount() + * + * @deprecated Accurate counting is a burden on the runtime and may be removed. */ + @Deprecated public static void resetGlobalClassInitCount() { VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_CLASS_INIT_COUNT); } @@ -867,7 +906,10 @@ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Lo /** * Returns the time spent successfully initializing classes between a * {@link #startAllocCounting() start} and {@link #stopAllocCounting() stop}. + * + * @deprecated Accurate counting is a burden on the runtime and may be removed. */ + @Deprecated public static int getGlobalClassInitTime() { /* cumulative elapsed time for class initialization, in usec */ return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_CLASS_INIT_TIME); @@ -876,7 +918,10 @@ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Lo /** * Clears the count of time spent initializing classes. * @see #getGlobalClassInitTime() + * + * @deprecated Accurate counting is a burden on the runtime and may be removed. */ + @Deprecated public static void resetGlobalClassInitTime() { VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_CLASS_INIT_TIME); } @@ -948,7 +993,10 @@ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Lo /** * Returns the thread-local count of objects allocated by the runtime between a * {@link #startAllocCounting() start} and {@link #stopAllocCounting() stop}. + * + * @deprecated Accurate counting is a burden on the runtime and may be removed. */ + @Deprecated public static int getThreadAllocCount() { return VMDebug.getAllocCount(VMDebug.KIND_THREAD_ALLOCATED_OBJECTS); } @@ -956,7 +1004,10 @@ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Lo /** * Clears the thread-local count of objects allocated. * @see #getThreadAllocCount() + * + * @deprecated Accurate counting is a burden on the runtime and may be removed. */ + @Deprecated public static void resetThreadAllocCount() { VMDebug.resetAllocCount(VMDebug.KIND_THREAD_ALLOCATED_OBJECTS); } @@ -965,7 +1016,10 @@ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Lo * Returns the thread-local size of objects allocated by the runtime between a * {@link #startAllocCounting() start} and {@link #stopAllocCounting() stop}. * @return The allocated size in bytes. + * + * @deprecated Accurate counting is a burden on the runtime and may be removed. */ + @Deprecated public static int getThreadAllocSize() { return VMDebug.getAllocCount(VMDebug.KIND_THREAD_ALLOCATED_BYTES); } @@ -973,7 +1027,10 @@ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Lo /** * Clears the thread-local count of objects allocated. * @see #getThreadAllocSize() + * + * @deprecated Accurate counting is a burden on the runtime and may be removed. */ + @Deprecated public static void resetThreadAllocSize() { VMDebug.resetAllocCount(VMDebug.KIND_THREAD_ALLOCATED_BYTES); } @@ -1013,7 +1070,10 @@ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Lo /** * Returns the number of thread-local non-concurrent GC invocations between a * {@link #startAllocCounting() start} and {@link #stopAllocCounting() stop}. + * + * @deprecated Accurate counting is a burden on the runtime and may be removed. */ + @Deprecated public static int getThreadGcInvocationCount() { return VMDebug.getAllocCount(VMDebug.KIND_THREAD_GC_INVOCATIONS); } @@ -1021,7 +1081,10 @@ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Lo /** * Clears the thread-local count of non-concurrent GC invocations. * @see #getThreadGcInvocationCount() + * + * @deprecated Accurate counting is a burden on the runtime and may be removed. */ + @Deprecated public static void resetThreadGcInvocationCount() { VMDebug.resetAllocCount(VMDebug.KIND_THREAD_GC_INVOCATIONS); } @@ -1029,7 +1092,10 @@ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Lo /** * Clears all the global and thread-local memory allocation counters. * @see #startAllocCounting() + * + * @deprecated Accurate counting is a burden on the runtime and may be removed. */ + @Deprecated public static void resetAllCounts() { VMDebug.resetAllocCount(VMDebug.KIND_ALL_COUNTS); } diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java index 650f3b3f7872..706e0d023b80 100644 --- a/core/java/android/os/UserManager.java +++ b/core/java/android/os/UserManager.java @@ -391,6 +391,15 @@ public class UserManager { public static final String DISALLOW_OUTGOING_BEAM = "no_outgoing_beam"; /** + * Hidden user restriction to disallow access to wallpaper manager APIs. This user restriction + * is always set for managed profiles. + * @hide + * @see #setUserRestrictions(Bundle) + * @see #getUserRestrictions() + */ + public static final String DISALLOW_WALLPAPER = "no_wallpaper"; + + /** * Application restriction key that is used to indicate the pending arrival * of real restrictions for the app. * diff --git a/core/java/android/preference/DialogPreference.java b/core/java/android/preference/DialogPreference.java index 1b226c180529..3d57b4db2598 100644 --- a/core/java/android/preference/DialogPreference.java +++ b/core/java/android/preference/DialogPreference.java @@ -17,6 +17,7 @@ package android.preference; +import android.annotation.CallSuper; import android.annotation.DrawableRes; import android.annotation.StringRes; import android.app.AlertDialog; @@ -360,6 +361,7 @@ public abstract class DialogPreference extends Preference implements * * @param view The content View of the dialog, if it is custom. */ + @CallSuper protected void onBindDialogView(View view) { View dialogMessageView = view.findViewById(com.android.internal.R.id.message); diff --git a/core/java/android/preference/Preference.java b/core/java/android/preference/Preference.java index 78928b2ef24e..ccf2cfabc828 100644 --- a/core/java/android/preference/Preference.java +++ b/core/java/android/preference/Preference.java @@ -16,6 +16,7 @@ package android.preference; +import android.annotation.CallSuper; import com.android.internal.util.CharSequences; import android.annotation.DrawableRes; @@ -508,6 +509,7 @@ public class Preference implements Comparable<Preference> { * @return The View that displays this Preference. * @see #onBindView(View) */ + @CallSuper protected View onCreateView(ViewGroup parent) { final LayoutInflater layoutInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); @@ -537,6 +539,7 @@ public class Preference implements Comparable<Preference> { * @param view The View that shows this Preference. * @see #onCreateView(ViewGroup) */ + @CallSuper protected void onBindView(View view) { final TextView titleView = (TextView) view.findViewById(com.android.internal.R.id.title); if (titleView != null) { @@ -1356,6 +1359,7 @@ public class Preference implements Comparable<Preference> { * should remove any references to this Preference that you know about. Make * sure to call through to the superclass implementation. */ + @CallSuper protected void onPrepareForRemoval() { unregisterDependency(); } diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java index 9cc12b5c9e3e..cc7783f79c9b 100644 --- a/core/java/android/provider/ContactsContract.java +++ b/core/java/android/provider/ContactsContract.java @@ -1010,7 +1010,8 @@ public final class ContactsContract { /** * Types of data used to produce the display name for a contact. In the order * of increasing priority: {@link #EMAIL}, {@link #PHONE}, - * {@link #ORGANIZATION}, {@link #NICKNAME}, {@link #STRUCTURED_NAME}. + * {@link #ORGANIZATION}, {@link #NICKNAME}, {@link #STRUCTURED_PHONETIC_NAME}, + * {@link #STRUCTURED_NAME}. */ public interface DisplayNameSources { public static final int UNDEFINED = 0; @@ -1018,6 +1019,8 @@ public final class ContactsContract { public static final int PHONE = 20; public static final int ORGANIZATION = 30; public static final int NICKNAME = 35; + /** Display name comes from a structured name that only has phonetic components. */ + public static final int STRUCTURED_PHONETIC_NAME = 37; public static final int STRUCTURED_NAME = 40; } diff --git a/core/java/android/provider/DocumentsProvider.java b/core/java/android/provider/DocumentsProvider.java index 13164719a5fb..6979beefa24c 100644 --- a/core/java/android/provider/DocumentsProvider.java +++ b/core/java/android/provider/DocumentsProvider.java @@ -28,6 +28,7 @@ import static android.provider.DocumentsContract.getSearchDocumentsQuery; import static android.provider.DocumentsContract.getTreeDocumentId; import static android.provider.DocumentsContract.isTreeUri; +import android.annotation.CallSuper; import android.content.ContentProvider; import android.content.ContentResolver; import android.content.ContentValues; @@ -541,6 +542,7 @@ public abstract class DocumentsProvider extends ContentProvider { * * @see DocumentsContract#buildDocumentUriUsingTree(Uri, String) */ + @CallSuper @Override public Uri canonicalize(Uri uri) { final Context context = getContext(); @@ -616,6 +618,7 @@ public abstract class DocumentsProvider extends ContentProvider { * call the superclass. If the superclass returns {@code null}, the subclass * may implement custom behavior. */ + @CallSuper @Override public Bundle call(String method, String arg, Bundle extras) { if (!method.startsWith("android:")) { diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java index d1caa43b3301..967e80c4d7b8 100644 --- a/core/java/android/text/StaticLayout.java +++ b/core/java/android/text/StaticLayout.java @@ -28,6 +28,7 @@ import com.android.internal.util.ArrayUtils; import com.android.internal.util.GrowingArrayUtils; import java.util.Arrays; +import java.util.Locale; /** * StaticLayout is a Layout for text that will not be edited after it @@ -51,6 +52,10 @@ public class StaticLayout extends Layout { * @hide */ public final static class Builder { + private Builder() { + mNativePtr = nNewBuilder(); + } + static Builder obtain() { Builder b = null; synchronized (sLock) { @@ -96,6 +101,7 @@ public class StaticLayout extends Layout { // release any expensive state /* package */ void finish() { + nFinishBuilder(mNativePtr); mMeasuredText.finish(); } @@ -160,6 +166,14 @@ public class StaticLayout extends Layout { return this; } + /* @hide */ + public void setLocale(Locale locale) { + if (!locale.equals(mLocale)) { + nBuilderSetLocale(mNativePtr, locale.toLanguageTag()); + mLocale = locale; + } + } + public StaticLayout build() { // TODO: can optimize based on whether ellipsis is needed StaticLayout result = new StaticLayout(mText); @@ -168,6 +182,17 @@ public class StaticLayout extends Layout { return result; } + @Override + protected void finalize() throws Throwable { + try { + nFreeBuilder(mNativePtr); + } finally { + super.finalize(); + } + } + + /* package */ long mNativePtr; + CharSequence mText; int mStart; int mEnd; @@ -186,6 +211,8 @@ public class StaticLayout extends Layout { // This will go away and be subsumed by native builder code MeasuredText mMeasuredText; + Locale mLocale; + private static final Object sLock = new Object(); private static final Builder[] sCached = new Builder[3]; } @@ -322,13 +349,13 @@ public class StaticLayout extends Layout { float spacingadd = b.mSpacingAdd; float ellipsizedWidth = b.mEllipsizedWidth; TextUtils.TruncateAt ellipsize = b.mEllipsize; - LineBreaks lineBreaks = new LineBreaks(); + LineBreaks lineBreaks = new LineBreaks(); // TODO: move to builder to avoid allocation costs // store span end locations int[] spanEndCache = new int[4]; // store fontMetrics per span range // must be a multiple of 4 (and > 0) (store top, bottom, ascent, and descent per range) int[] fmCache = new int[4 * 4]; - final String localeLanguageTag = paint.getTextLocale().toLanguageTag(); + b.setLocale(paint.getTextLocale()); // TODO: also respect LocaleSpan within the text mLineCount = 0; @@ -466,7 +493,7 @@ public class StaticLayout extends Layout { } } - int breakCount = nComputeLineBreaks(localeLanguageTag, chs, widths, paraEnd - paraStart, firstWidth, + int breakCount = nComputeLineBreaks(b.mNativePtr, chs, widths, paraEnd - paraStart, firstWidth, firstWidthLineCount, restWidth, variableTabStops, TAB_INCREMENT, false, lineBreaks, lineBreaks.breaks, lineBreaks.widths, lineBreaks.flags, lineBreaks.breaks.length); @@ -911,11 +938,16 @@ public class StaticLayout extends Layout { // the arrays inside the LineBreaks objects are passed in as well // to reduce the number of JNI calls in the common case where the // arrays do not have to be resized - private static native int nComputeLineBreaks(String locale, char[] text, float[] widths, + private static native int nComputeLineBreaks(long nativePtr, char[] text, float[] widths, int length, float firstWidth, int firstWidthLineCount, float restWidth, int[] variableTabStops, int defaultTabStop, boolean optimize, LineBreaks recycle, int[] recycleBreaks, float[] recycleWidths, boolean[] recycleFlags, int recycleLength); + private static native long nNewBuilder(); + private static native void nFreeBuilder(long nativePtr); + private static native void nFinishBuilder(long nativePtr); + private static native void nBuilderSetLocale(long nativePtr, String locale); + private int mLineCount; private int mTopPadding, mBottomPadding; private int mColumns; diff --git a/core/java/android/text/TextPaint.java b/core/java/android/text/TextPaint.java index 044711711931..4f8cff0fd7c2 100644 --- a/core/java/android/text/TextPaint.java +++ b/core/java/android/text/TextPaint.java @@ -16,6 +16,7 @@ package android.text; +import android.annotation.ColorInt; import android.graphics.Paint; /** @@ -25,8 +26,10 @@ import android.graphics.Paint; public class TextPaint extends Paint { // Special value 0 means no background paint + @ColorInt public int bgColor; public int baselineShift; + @ColorInt public int linkColor; public int[] drawableState; public float density = 1.0f; @@ -34,6 +37,7 @@ public class TextPaint extends Paint { * Special value 0 means no custom underline * @hide */ + @ColorInt public int underlineColor = 0; /** * Defined as a multiplier of the default underline thickness. Use 1.0f for default thickness. diff --git a/core/java/android/text/style/ForegroundColorSpan.java b/core/java/android/text/style/ForegroundColorSpan.java index c9e09bd92d79..f167aab31cf0 100644 --- a/core/java/android/text/style/ForegroundColorSpan.java +++ b/core/java/android/text/style/ForegroundColorSpan.java @@ -16,6 +16,7 @@ package android.text.style; +import android.annotation.ColorInt; import android.os.Parcel; import android.text.ParcelableSpan; import android.text.TextPaint; @@ -26,7 +27,7 @@ public class ForegroundColorSpan extends CharacterStyle private final int mColor; - public ForegroundColorSpan(int color) { + public ForegroundColorSpan(@ColorInt int color) { mColor = color; } @@ -46,6 +47,7 @@ public class ForegroundColorSpan extends CharacterStyle dest.writeInt(mColor); } + @ColorInt public int getForegroundColor() { return mColor; } diff --git a/core/java/android/text/style/QuoteSpan.java b/core/java/android/text/style/QuoteSpan.java index 29dd2732d0f0..17748ca3ae8c 100644 --- a/core/java/android/text/style/QuoteSpan.java +++ b/core/java/android/text/style/QuoteSpan.java @@ -16,6 +16,7 @@ package android.text.style; +import android.annotation.ColorInt; import android.graphics.Paint; import android.graphics.Canvas; import android.os.Parcel; @@ -34,7 +35,7 @@ public class QuoteSpan implements LeadingMarginSpan, ParcelableSpan { mColor = 0xff0000ff; } - public QuoteSpan(int color) { + public QuoteSpan(@ColorInt int color) { super(); mColor = color; } @@ -55,6 +56,7 @@ public class QuoteSpan implements LeadingMarginSpan, ParcelableSpan { dest.writeInt(mColor); } + @ColorInt public int getColor() { return mColor; } diff --git a/core/java/android/util/DebugUtils.java b/core/java/android/util/DebugUtils.java index f607207c0d72..84d9ce89af27 100644 --- a/core/java/android/util/DebugUtils.java +++ b/core/java/android/util/DebugUtils.java @@ -16,6 +16,7 @@ package android.util; +import java.io.PrintWriter; import java.lang.reflect.Method; import java.lang.reflect.InvocationTargetException; import java.util.Locale; @@ -123,4 +124,83 @@ public class DebugUtils { } } + /** @hide */ + public static void printSizeValue(PrintWriter pw, long number) { + float result = number; + String suffix = ""; + if (result > 900) { + suffix = "KB"; + result = result / 1024; + } + if (result > 900) { + suffix = "MB"; + result = result / 1024; + } + if (result > 900) { + suffix = "GB"; + result = result / 1024; + } + if (result > 900) { + suffix = "TB"; + result = result / 1024; + } + if (result > 900) { + suffix = "PB"; + result = result / 1024; + } + String value; + if (result < 1) { + value = String.format("%.2f", result); + } else if (result < 10) { + value = String.format("%.1f", result); + } else if (result < 100) { + value = String.format("%.0f", result); + } else { + value = String.format("%.0f", result); + } + pw.print(value); + pw.print(suffix); + } + + /** @hide */ + public static String sizeValueToString(long number, StringBuilder outBuilder) { + if (outBuilder == null) { + outBuilder = new StringBuilder(32); + } + float result = number; + String suffix = ""; + if (result > 900) { + suffix = "KB"; + result = result / 1024; + } + if (result > 900) { + suffix = "MB"; + result = result / 1024; + } + if (result > 900) { + suffix = "GB"; + result = result / 1024; + } + if (result > 900) { + suffix = "TB"; + result = result / 1024; + } + if (result > 900) { + suffix = "PB"; + result = result / 1024; + } + String value; + if (result < 1) { + value = String.format("%.2f", result); + } else if (result < 10) { + value = String.format("%.1f", result); + } else if (result < 100) { + value = String.format("%.0f", result); + } else { + value = String.format("%.0f", result); + } + outBuilder.append(value); + outBuilder.append(suffix); + return outBuilder.toString(); + } } diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/DisplayListCanvas.java index 0d36949c06d1..90e1f8688795 100644 --- a/core/java/android/view/GLES20Canvas.java +++ b/core/java/android/view/DisplayListCanvas.java @@ -16,6 +16,7 @@ package android.view; +import android.annotation.NonNull; import android.graphics.Bitmap; import android.graphics.CanvasProperty; import android.graphics.NinePatch; @@ -24,19 +25,50 @@ import android.graphics.Path; import android.graphics.Picture; import android.graphics.Rect; import android.graphics.RectF; +import android.util.Pools.SynchronizedPool; /** - * An implementation of Canvas on top of OpenGL ES 2.0. + * An implementation of a GL canvas that records drawing operations. + * This is intended for use with a DisplayList. This class keeps a list of all the Paint and + * Bitmap objects that it draws, preventing the backing memory of Bitmaps from being freed while + * the DisplayList is still holding a native reference to the memory. */ -class GLES20Canvas extends HardwareCanvas { +class DisplayListCanvas extends HardwareCanvas { + // The recording canvas pool should be large enough to handle a deeply nested + // view hierarchy because display lists are generated recursively. + private static final int POOL_LIMIT = 25; + + private static final SynchronizedPool<DisplayListCanvas> sPool = + new SynchronizedPool<DisplayListCanvas>(POOL_LIMIT); + + RenderNode mNode; private int mWidth; private int mHeight; - private float[] mPoint; - private float[] mLine; - private Rect mClipBounds; - private RectF mPathBounds; + static DisplayListCanvas obtain(@NonNull RenderNode node) { + if (node == null) throw new IllegalArgumentException("node cannot be null"); + DisplayListCanvas canvas = sPool.acquire(); + if (canvas == null) { + canvas = new DisplayListCanvas(); + } + canvas.mNode = node; + return canvas; + } + + void recycle() { + mNode = null; + sPool.release(this); + } + + long finishRecording() { + return nFinishRecording(mNativeCanvasWrapper); + } + + @Override + public boolean isRecordingFor(Object o) { + return o == mNode; + } /////////////////////////////////////////////////////////////////////////// // JNI @@ -53,8 +85,8 @@ class GLES20Canvas extends HardwareCanvas { // Constructors /////////////////////////////////////////////////////////////////////////// - // TODO: Merge with GLES20RecordingCanvas - protected GLES20Canvas() { + + private DisplayListCanvas() { super(nCreateDisplayListRenderer()); } @@ -204,7 +236,7 @@ class GLES20Canvas extends HardwareCanvas { Bitmap bitmap = patch.getBitmap(); throwIfCannotDraw(bitmap); final long nativePaint = paint == null ? 0 : paint.getNativeInstance(); - nDrawPatch(mNativeCanvasWrapper, bitmap.mNativeBitmap, patch.mNativeChunk, + nDrawPatch(mNativeCanvasWrapper, bitmap.getSkBitmap(), patch.mNativeChunk, dst.left, dst.top, dst.right, dst.bottom, nativePaint); } @@ -214,7 +246,7 @@ class GLES20Canvas extends HardwareCanvas { Bitmap bitmap = patch.getBitmap(); throwIfCannotDraw(bitmap); final long nativePaint = paint == null ? 0 : paint.getNativeInstance(); - nDrawPatch(mNativeCanvasWrapper, bitmap.mNativeBitmap, patch.mNativeChunk, + nDrawPatch(mNativeCanvasWrapper, bitmap.getSkBitmap(), patch.mNativeChunk, dst.left, dst.top, dst.right, dst.bottom, nativePaint); } diff --git a/core/java/android/view/GLES20RecordingCanvas.java b/core/java/android/view/GLES20RecordingCanvas.java deleted file mode 100644 index 6c780c9f1865..000000000000 --- a/core/java/android/view/GLES20RecordingCanvas.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.view; - -import android.annotation.NonNull; -import android.util.Pools.SynchronizedPool; - -/** - * An implementation of a GL canvas that records drawing operations. - * This is intended for use with a DisplayList. This class keeps a list of all the Paint and - * Bitmap objects that it draws, preventing the backing memory of Bitmaps from being freed while - * the DisplayList is still holding a native reference to the memory. - */ -class GLES20RecordingCanvas extends GLES20Canvas { - // The recording canvas pool should be large enough to handle a deeply nested - // view hierarchy because display lists are generated recursively. - private static final int POOL_LIMIT = 25; - - private static final SynchronizedPool<GLES20RecordingCanvas> sPool = - new SynchronizedPool<GLES20RecordingCanvas>(POOL_LIMIT); - - RenderNode mNode; - - private GLES20RecordingCanvas() { - super(); - } - - static GLES20RecordingCanvas obtain(@NonNull RenderNode node) { - if (node == null) throw new IllegalArgumentException("node cannot be null"); - GLES20RecordingCanvas canvas = sPool.acquire(); - if (canvas == null) { - canvas = new GLES20RecordingCanvas(); - } - canvas.mNode = node; - return canvas; - } - - void recycle() { - mNode = null; - sPool.release(this); - } - - long finishRecording() { - return nFinishRecording(mNativeCanvasWrapper); - } - - @Override - public boolean isRecordingFor(Object o) { - return o == mNode; - } -} diff --git a/core/java/android/view/HardwareCanvas.java b/core/java/android/view/HardwareCanvas.java index cdb350f5173e..fc2b55bc73d1 100644 --- a/core/java/android/view/HardwareCanvas.java +++ b/core/java/android/view/HardwareCanvas.java @@ -119,6 +119,6 @@ public abstract class HardwareCanvas extends Canvas { CanvasProperty<Paint> paint); public static void setProperty(String name, String value) { - GLES20Canvas.setProperty(name, value); + DisplayListCanvas.setProperty(name, value); } } diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java index 9921be2fd8ee..afa7f5114abc 100644 --- a/core/java/android/view/HardwareRenderer.java +++ b/core/java/android/view/HardwareRenderer.java @@ -205,7 +205,7 @@ public abstract class HardwareRenderer { * false otherwise */ public static boolean isAvailable() { - return GLES20Canvas.isAvailable(); + return DisplayListCanvas.isAvailable(); } /** @@ -423,7 +423,7 @@ public abstract class HardwareRenderer { */ static HardwareRenderer create(Context context, boolean translucent) { HardwareRenderer renderer = null; - if (GLES20Canvas.isAvailable()) { + if (DisplayListCanvas.isAvailable()) { renderer = new ThreadedRenderer(context, translucent); } return renderer; diff --git a/core/java/android/view/LayoutInflater.java b/core/java/android/view/LayoutInflater.java index 101457320b25..1a07aee5d482 100644 --- a/core/java/android/view/LayoutInflater.java +++ b/core/java/android/view/LayoutInflater.java @@ -532,10 +532,10 @@ public abstract class LayoutInflater { InflateException ex = new InflateException(e.getMessage()); ex.initCause(e); throw ex; - } catch (IOException e) { + } catch (Exception e) { InflateException ex = new InflateException( parser.getPositionDescription() - + ": " + e.getMessage()); + + ": " + e.getMessage()); ex.initCause(e); throw ex; } finally { diff --git a/core/java/android/view/RenderNode.java b/core/java/android/view/RenderNode.java index 09eb48640bd9..38867a89d467 100644 --- a/core/java/android/view/RenderNode.java +++ b/core/java/android/view/RenderNode.java @@ -225,7 +225,7 @@ public class RenderNode { * @see #isValid() */ public HardwareCanvas start(int width, int height) { - HardwareCanvas canvas = GLES20RecordingCanvas.obtain(this); + HardwareCanvas canvas = DisplayListCanvas.obtain(this); canvas.setViewport(width, height); // The dirty rect should always be null for a display list canvas.onPreDraw(null); @@ -241,11 +241,11 @@ public class RenderNode { * @see #isValid() */ public void end(HardwareCanvas endCanvas) { - if (!(endCanvas instanceof GLES20RecordingCanvas)) { + if (!(endCanvas instanceof DisplayListCanvas)) { throw new IllegalArgumentException("Passed an invalid canvas to end!"); } - GLES20RecordingCanvas canvas = (GLES20RecordingCanvas) endCanvas; + DisplayListCanvas canvas = (DisplayListCanvas) endCanvas; canvas.onPostDraw(); long renderNodeData = canvas.finishRecording(); nSetDisplayListData(mNativeRenderNode, renderNodeData); diff --git a/core/java/android/view/RenderNodeAnimator.java b/core/java/android/view/RenderNodeAnimator.java index 7b35a3b6cb08..379796d58dc9 100644 --- a/core/java/android/view/RenderNodeAnimator.java +++ b/core/java/android/view/RenderNodeAnimator.java @@ -283,10 +283,10 @@ public class RenderNodeAnimator extends Animator { } public void setTarget(Canvas canvas) { - if (!(canvas instanceof GLES20RecordingCanvas)) { + if (!(canvas instanceof DisplayListCanvas)) { throw new IllegalArgumentException("Not a GLES20RecordingCanvas"); } - final GLES20RecordingCanvas recordingCanvas = (GLES20RecordingCanvas) canvas; + final DisplayListCanvas recordingCanvas = (DisplayListCanvas) canvas; setTarget(recordingCanvas.mNode); } diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java index df0838f6a643..69b4c47daad5 100644 --- a/core/java/android/view/ThreadedRenderer.java +++ b/core/java/android/view/ThreadedRenderer.java @@ -364,7 +364,7 @@ public class ThreadedRenderer extends HardwareRenderer { @Override boolean copyLayerInto(final HardwareLayer layer, final Bitmap bitmap) { return nCopyLayerInto(mNativeProxy, - layer.getDeferredLayerUpdater(), bitmap.mNativeBitmap); + layer.getDeferredLayerUpdater(), bitmap.getSkBitmap()); } @Override @@ -465,7 +465,7 @@ public class ThreadedRenderer extends HardwareRenderer { for (int i = 0; i < count; i++) { drawables.valueAt(i).addAtlasableBitmaps(tmpList); for (int j = 0; j < tmpList.size(); j++) { - preloadedPointers.add(tmpList.get(j).mNativeBitmap); + preloadedPointers.add(tmpList.get(j).getSkBitmap()); } tmpList.clear(); } diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index f25b6402c078..7d49969c02cd 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -18,11 +18,15 @@ package android.view; import android.animation.AnimatorInflater; import android.animation.StateListAnimator; +import android.annotation.CallSuper; +import android.annotation.ColorInt; import android.annotation.DrawableRes; +import android.annotation.FloatRange; import android.annotation.IdRes; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.Size; import android.content.ClipData; import android.content.Context; import android.content.res.ColorStateList; @@ -5148,6 +5152,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * passed in as finer grained information about where the focus is coming * from (in addition to direction). Will be <code>null</code> otherwise. */ + @CallSuper protected void onFocusChanged(boolean gainFocus, @FocusDirection int direction, @Nullable Rect previouslyFocusedRect) { if (gainFocus) { @@ -5370,6 +5375,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * @see #sendAccessibilityEvent(int) * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent) */ + @CallSuper public void onPopulateAccessibilityEvent(AccessibilityEvent event) { if (mAccessibilityDelegate != null) { mAccessibilityDelegate.onPopulateAccessibilityEvent(this, event); @@ -5414,6 +5420,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * @see #sendAccessibilityEvent(int) * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent) */ + @CallSuper public void onInitializeAccessibilityEvent(AccessibilityEvent event) { if (mAccessibilityDelegate != null) { mAccessibilityDelegate.onInitializeAccessibilityEvent(this, event); @@ -5528,6 +5535,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * * @param info The instance to initialize. */ + @CallSuper public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { if (mAccessibilityDelegate != null) { mAccessibilityDelegate.onInitializeAccessibilityNodeInfo(this, info); @@ -5849,7 +5857,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * * @see AccessibilityDelegate */ - public void setAccessibilityDelegate(AccessibilityDelegate delegate) { + public void setAccessibilityDelegate(@Nullable AccessibilityDelegate delegate) { mAccessibilityDelegate = delegate; } @@ -6089,6 +6097,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * * @hide pending API council approval */ + @CallSuper protected void onFocusLost() { resetPressedState(); } @@ -10573,7 +10582,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * * @attr ref android.R.styleable#View_alpha */ - public void setAlpha(float alpha) { + public void setAlpha(@FloatRange(from=0.0, to=1.0) float alpha) { ensureTransformationInfo(); if (mTransformationInfo.mAlpha != alpha) { mTransformationInfo.mAlpha = alpha; @@ -13425,6 +13434,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * * @hide */ + @CallSuper protected void onDetachedFromWindowInternal() { mPrivateFlags &= ~PFLAG_CANCEL_NEXT_UP_EVENT; mPrivateFlags3 &= ~PFLAG3_IS_LAID_OUT; @@ -14039,6 +14049,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * * @hide */ + @CallSuper protected void destroyHardwareResources() { // Although the Layer will be destroyed by RenderNode, we want to release // the staging display list, which is also a signal to RenderNode that it's @@ -14311,7 +14322,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * @see #buildDrawingCache() * @see #getDrawingCache() */ - public void setDrawingCacheBackgroundColor(int color) { + public void setDrawingCacheBackgroundColor(@ColorInt int color) { if (color != mDrawingCacheBackgroundColor) { mDrawingCacheBackgroundColor = color; mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; @@ -14323,6 +14334,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * * @return The background color to used for the drawing cache's bitmap */ + @ColorInt public int getDrawingCacheBackgroundColor() { return mDrawingCacheBackgroundColor; } @@ -15227,6 +15239,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * * @param canvas The Canvas to which the View is rendered. */ + @CallSuper public void draw(Canvas canvas) { final int privateFlags = mPrivateFlags; final boolean dirtyOpaque = (privateFlags & PFLAG_DIRTY_MASK) == PFLAG_DIRTY_OPAQUE && @@ -15536,6 +15549,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * @return The known solid color background for this view, or 0 if the color may vary */ @ViewDebug.ExportedProperty(category = "drawing") + @ColorInt public int getSolidColor() { return 0; } @@ -15828,6 +15842,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * <p>Even if the subclass overrides onFinishInflate, they should always be * sure to call the super method, so that we get called. */ + @CallSuper protected void onFinishInflate() { } @@ -15993,6 +16008,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * @see #unscheduleDrawable(android.graphics.drawable.Drawable) * @see #drawableStateChanged() */ + @CallSuper protected boolean verifyDrawable(Drawable who) { return who == mBackground || (mScrollCache != null && mScrollCache.scrollBar == who); } @@ -16008,6 +16024,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * * @see Drawable#setState(int[]) */ + @CallSuper protected void drawableStateChanged() { final int[] state = getDrawableState(); @@ -16040,6 +16057,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * @param x hotspot x coordinate * @param y hotspot y coordinate */ + @CallSuper public void drawableHotspotChanged(float x, float y) { if (mBackground != null) { mBackground.setHotspot(x, y); @@ -16222,7 +16240,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * @param color the color of the background */ @RemotableViewMethod - public void setBackgroundColor(int color) { + public void setBackgroundColor(@ColorInt int color) { if (mBackground instanceof ColorDrawable) { ((ColorDrawable) mBackground.mutate()).setColor(color); computeOpaqueFlags(); @@ -16238,6 +16256,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * * @return The color of the ColorDrawable background, if set, otherwise 0. */ + @ColorInt public int getBackgroundColor() { if (mBackground instanceof ColorDrawable) { return ((ColorDrawable) mBackground).getColor(); @@ -17011,7 +17030,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * * @param location an array of two integers in which to hold the coordinates */ - public void getLocationOnScreen(int[] location) { + public void getLocationOnScreen(@Size(2) int[] location) { getLocationInWindow(location); final AttachInfo info = mAttachInfo; @@ -17028,7 +17047,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * * @param location an array of two integers in which to hold the coordinates */ - public void getLocationInWindow(int[] location) { + public void getLocationInWindow(@Size(2) int[] location) { if (location == null || location.length < 2) { throw new IllegalArgumentException("location must be an array of two integers"); } @@ -17512,6 +17531,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * <p>Subclasses which override this method should call the superclass method to * handle possible request-during-layout errors correctly.</p> */ + @CallSuper public void requestLayout() { if (mMeasureCache != null) mMeasureCache.clear(); @@ -18871,7 +18891,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * @see #dispatchNestedPreScroll(int, int, int[], int[]) */ public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, - int dxUnconsumed, int dyUnconsumed, int[] offsetInWindow) { + int dxUnconsumed, int dyUnconsumed, @Nullable @Size(2) int[] offsetInWindow) { if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { if (dxConsumed != 0 || dyConsumed != 0 || dxUnconsumed != 0 || dyUnconsumed != 0) { int startX = 0; @@ -18919,7 +18939,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * @return true if the parent consumed some or all of the scroll delta * @see #dispatchNestedScroll(int, int, int, int, int[]) */ - public boolean dispatchNestedPreScroll(int dx, int dy, int[] consumed, int[] offsetInWindow) { + public boolean dispatchNestedPreScroll(int dx, int dy, + @Nullable @Size(2) int[] consumed, @Nullable @Size(2) int[] offsetInWindow) { if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { if (dx != 0 || dy != 0) { int startX = 0; diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java index e332135b7e9c..744f66525664 100644 --- a/core/java/android/view/Window.java +++ b/core/java/android/view/Window.java @@ -16,6 +16,7 @@ package android.view; +import android.annotation.ColorInt; import android.annotation.DrawableRes; import android.annotation.IdRes; import android.annotation.LayoutRes; @@ -1069,7 +1070,7 @@ public abstract class Window { public abstract void setTitle(CharSequence title); @Deprecated - public abstract void setTitleColor(int textColor); + public abstract void setTitleColor(@ColorInt int textColor); public abstract void openPanel(int featureId, KeyEvent event); @@ -1835,6 +1836,7 @@ public abstract class Window { /** * @return the color of the status bar. */ + @ColorInt public abstract int getStatusBarColor(); /** @@ -1852,11 +1854,12 @@ public abstract class Window { * The transitionName for the view background will be "android:status:background". * </p> */ - public abstract void setStatusBarColor(int color); + public abstract void setStatusBarColor(@ColorInt int color); /** * @return the color of the navigation bar. */ + @ColorInt public abstract int getNavigationBarColor(); /** @@ -1874,7 +1877,7 @@ public abstract class Window { * The transitionName for the view background will be "android:navigation:background". * </p> */ - public abstract void setNavigationBarColor(int color); + public abstract void setNavigationBarColor(@ColorInt int color); } diff --git a/core/java/android/view/animation/Animation.java b/core/java/android/view/animation/Animation.java index 85d77cb79a00..a5524d86b203 100644 --- a/core/java/android/view/animation/Animation.java +++ b/core/java/android/view/animation/Animation.java @@ -16,6 +16,7 @@ package android.view.animation; +import android.annotation.ColorInt; import android.content.Context; import android.content.res.TypedArray; import android.graphics.RectF; @@ -622,7 +623,7 @@ public abstract class Animation implements Cloneable { * @param bg The background color. If 0, no background. Currently must * be black, with any desired alpha level. */ - public void setBackgroundColor(int bg) { + public void setBackgroundColor(@ColorInt int bg) { mBackgroundColor = bg; } @@ -753,6 +754,7 @@ public abstract class Animation implements Cloneable { /** * Returns the background color behind the animation. */ + @ColorInt public int getBackgroundColor() { return mBackgroundColor; } diff --git a/core/java/android/view/animation/Transformation.java b/core/java/android/view/animation/Transformation.java index 30c12edf3d74..8eb5b5cf5441 100644 --- a/core/java/android/view/animation/Transformation.java +++ b/core/java/android/view/animation/Transformation.java @@ -16,6 +16,7 @@ package android.view.animation; +import android.annotation.FloatRange; import android.graphics.Matrix; import android.graphics.Rect; @@ -163,7 +164,7 @@ public class Transformation { * Sets the degree of transparency * @param alpha 1.0 means fully opaqe and 0.0 means fully transparent */ - public void setAlpha(float alpha) { + public void setAlpha(@FloatRange(from=0.0, to=1.0) float alpha) { mAlpha = alpha; } diff --git a/core/java/android/webkit/WebResourceError.java b/core/java/android/webkit/WebResourceError.java new file mode 100644 index 000000000000..080d1740562b --- /dev/null +++ b/core/java/android/webkit/WebResourceError.java @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.webkit; + +/** + * Encapsulates information about errors occured during loading of web resources. See + * {@link WebViewClient#onReceivedError(WebView, WebResourceRequest, WebResourceError) WebViewClient.onReceivedError(WebView, WebResourceRequest, WebResourceError)} + */ +public abstract class WebResourceError { + /** + * Gets the error code of the error. The code corresponds to one + * of the ERROR_* constants in {@link WebViewClient}. + * + * @return The error code of the error + */ + public abstract int getErrorCode(); + + /** + * Gets the string describing the error. Descriptions are localized, + * and thus can be used for communicating the problem to the user. + * + * @return The description of the error + */ + public abstract String getDescription(); +} diff --git a/core/java/android/webkit/WebResourceResponse.java b/core/java/android/webkit/WebResourceResponse.java index f487a4e93820..a42aaa78deb8 100644 --- a/core/java/android/webkit/WebResourceResponse.java +++ b/core/java/android/webkit/WebResourceResponse.java @@ -25,7 +25,7 @@ import java.util.Map; * class from {@link WebViewClient#shouldInterceptRequest} to provide a custom * response when the WebView requests a particular resource. */ -public class WebResourceResponse { +public class WebResourceResponse extends WebResourceResponseBase { private String mMimeType; private String mEncoding; private int mStatusCode; @@ -75,38 +75,36 @@ public class WebResourceResponse { } /** - * Sets the resource response's MIME type, for example text/html. + * Sets the resource response's MIME type, for example "text/html". * - * @param mimeType the resource response's MIME type + * @param mimeType The resource response's MIME type */ public void setMimeType(String mimeType) { mMimeType = mimeType; } /** - * Gets the resource response's MIME type. - * - * @return the resource response's MIME type + * {@inheritDoc} */ + @Override public String getMimeType() { return mMimeType; } /** - * Sets the resource response's encoding, for example UTF-8. This is used + * Sets the resource response's encoding, for example "UTF-8". This is used * to decode the data from the input stream. * - * @param encoding the resource response's encoding + * @param encoding The resource response's encoding */ public void setEncoding(String encoding) { mEncoding = encoding; } /** - * Gets the resource response's encoding. - * - * @return the resource response's encoding + * {@inheritDoc} */ + @Override public String getEncoding() { return mEncoding; } @@ -142,19 +140,17 @@ public class WebResourceResponse { } /** - * Gets the resource response's status code. - * - * @return the resource response's status code. + * {@inheritDoc} */ + @Override public int getStatusCode() { return mStatusCode; } /** - * Gets the description of the resource response's status code. - * - * @return the description of the resource response's status code. + * {@inheritDoc} */ + @Override public String getReasonPhrase() { return mReasonPhrase; } @@ -162,17 +158,16 @@ public class WebResourceResponse { /** * Sets the headers for the resource response. * - * @param headers mapping of header name -> header value. + * @param headers Mapping of header name -> header value. */ public void setResponseHeaders(Map<String, String> headers) { mResponseHeaders = headers; } /** - * Gets the headers for the resource response. - * - * @return the headers for the resource response. + * {@inheritDoc} */ + @Override public Map<String, String> getResponseHeaders() { return mResponseHeaders; } @@ -190,15 +185,13 @@ public class WebResourceResponse { throw new IllegalArgumentException("StringBufferInputStream is deprecated and must " + "not be passed to a WebResourceResponse"); } - mInputStream = data; } /** - * Gets the input stream that provides the resource response's data. - * - * @return the input stream that provides the resource response's data + * {@inheritDoc} */ + @Override public InputStream getData() { return mInputStream; } diff --git a/core/java/android/webkit/WebResourceResponseBase.java b/core/java/android/webkit/WebResourceResponseBase.java new file mode 100644 index 000000000000..cffde82c673d --- /dev/null +++ b/core/java/android/webkit/WebResourceResponseBase.java @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.webkit; + +import java.io.InputStream; +import java.util.Map; + +/** + * Encapsulates a resource response received from the server. + * This is an abstract class used by WebView callbacks. + */ +public abstract class WebResourceResponseBase { + /** + * Gets the resource response's MIME type. + * + * @return The resource response's MIME type + */ + public abstract String getMimeType(); + + /** + * Gets the resource response's encoding. + * + * @return The resource response's encoding + */ + public abstract String getEncoding(); + + /** + * Gets the resource response's status code. + * + * @return The resource response's status code. + */ + public abstract int getStatusCode(); + + /** + * Gets the description of the resource response's status code. + * + * @return The description of the resource response's status code. + */ + public abstract String getReasonPhrase(); + + /** + * Gets the headers for the resource response. + * + * @return The headers for the resource response. + */ + public abstract Map<String, String> getResponseHeaders(); + + /** + * Gets the input stream that provides the resource response's data. + * + * @return The input stream that provides the resource response's data + */ + public abstract InputStream getData(); +} diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java index 1d2c3119d81d..3df1293578bf 100644 --- a/core/java/android/webkit/WebSettings.java +++ b/core/java/android/webkit/WebSettings.java @@ -1285,7 +1285,7 @@ public abstract class WebSettings { * strongly discouraged. * * @param mode The mixed content mode to use. One of {@link #MIXED_CONTENT_NEVER_ALLOW}, - * {@link #MIXED_CONTENT_NEVER_ALLOW} or {@link #MIXED_CONTENT_COMPATIBILITY_MODE}. + * {@link #MIXED_CONTENT_ALWAYS_ALLOW} or {@link #MIXED_CONTENT_COMPATIBILITY_MODE}. */ public abstract void setMixedContentMode(int mode); @@ -1293,7 +1293,7 @@ public abstract class WebSettings { * Gets the current behavior of the WebView with regard to loading insecure content from a * secure origin. * @return The current setting, one of {@link #MIXED_CONTENT_NEVER_ALLOW}, - * {@link #MIXED_CONTENT_NEVER_ALLOW} or {@link #MIXED_CONTENT_COMPATIBILITY_MODE}. + * {@link #MIXED_CONTENT_ALWAYS_ALLOW} or {@link #MIXED_CONTENT_COMPATIBILITY_MODE}. */ public abstract int getMixedContentMode(); diff --git a/core/java/android/webkit/WebViewClient.java b/core/java/android/webkit/WebViewClient.java index 01f9b37d1e84..34b8cf6348b3 100644 --- a/core/java/android/webkit/WebViewClient.java +++ b/core/java/android/webkit/WebViewClient.java @@ -174,6 +174,8 @@ public class WebViewClient { public static final int ERROR_FILE_NOT_FOUND = -14; /** Too many requests during this load */ public static final int ERROR_TOO_MANY_REQUESTS = -15; + /** Request blocked by the browser */ + public static final int ERROR_BLOCKED = -16; /** * Report an error to the host application. These errors are unrecoverable @@ -183,12 +185,45 @@ public class WebViewClient { * @param errorCode The error code corresponding to an ERROR_* value. * @param description A String describing the error. * @param failingUrl The url that failed to load. + * @deprecated Use {@link #onReceivedError(WebView, WebResourceRequest, WebResourceError) + * onReceivedError(WebView, WebResourceRequest, WebResourceError)} instead. */ + @Deprecated public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) { } /** + * Report web resource loading error to the host application. These errors usually indicate + * inability to connect to the server. Note that unlike the deprecated version of the callback, + * the new version will be called for any resource (iframe, image, etc), not just for the main + * page. Thus, it is recommended to perform minimum required work in this callback. + * @param view The WebView that is initiating the callback. + * @param request The originating request. + * @param error Information about the error occured. + */ + public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) { + if (request.isForMainFrame()) { + onReceivedError(view, + error.getErrorCode(), error.getDescription(), request.getUrl().toString()); + } + } + + /** + * Notify the host application that an HTTP error has been received from the server while + * loading a resource. HTTP errors have status codes >= 400. This callback will be called + * for any resource (iframe, image, etc), not just for the main page. Thus, it is recommended to + * perform minimum required work in this callback. Note that the content of the server + * response may not be provided within the <b>errorResponse</b> parameter. + * @param view The WebView that is initiating the callback. + * @param request The originating request. + * @param errorResponse Information about the error occured. + */ + public void onReceivedHttpError( + WebView view, WebResourceRequest request, WebResourceResponseBase errorResponse) { + } + + /** * As the host application if the browser should resend data as the * requested page was a result of a POST. The default is to not resend the * data. diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java index a6e2952b62dd..168066a30fe4 100644 --- a/core/java/android/widget/AbsListView.java +++ b/core/java/android/widget/AbsListView.java @@ -16,6 +16,7 @@ package android.widget; +import android.annotation.ColorInt; import android.annotation.DrawableRes; import android.content.Context; import android.content.Intent; @@ -5982,7 +5983,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te * * @param color The background color */ - public void setCacheColorHint(int color) { + public void setCacheColorHint(@ColorInt int color) { if (color != mCacheColorHint) { mCacheColorHint = color; int count = getChildCount(); @@ -6000,6 +6001,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te * @return The cache color hint */ @ViewDebug.ExportedProperty(category = "drawing") + @ColorInt public int getCacheColorHint() { return mCacheColorHint; } diff --git a/core/java/android/widget/AdapterView.java b/core/java/android/widget/AdapterView.java index 9b977fa75ef8..72cb0b55dad0 100644 --- a/core/java/android/widget/AdapterView.java +++ b/core/java/android/widget/AdapterView.java @@ -16,6 +16,7 @@ package android.widget; +import android.annotation.Nullable; import android.content.Context; import android.database.DataSetObserver; import android.os.Parcelable; @@ -276,7 +277,7 @@ public abstract class AdapterView<T extends Adapter> extends ViewGroup { * * @param listener The callback that will be invoked. */ - public void setOnItemClickListener(OnItemClickListener listener) { + public void setOnItemClickListener(@Nullable OnItemClickListener listener) { mOnItemClickListener = listener; } @@ -284,6 +285,7 @@ public abstract class AdapterView<T extends Adapter> extends ViewGroup { * @return The callback to be invoked with an item in this AdapterView has * been clicked, or null id no callback has been set. */ + @Nullable public final OnItemClickListener getOnItemClickListener() { return mOnItemClickListener; } @@ -394,10 +396,11 @@ public abstract class AdapterView<T extends Adapter> extends ViewGroup { * * @param listener The callback that will run */ - public void setOnItemSelectedListener(OnItemSelectedListener listener) { + public void setOnItemSelectedListener(@Nullable OnItemSelectedListener listener) { mOnItemSelectedListener = listener; } + @Nullable public final OnItemSelectedListener getOnItemSelectedListener() { return mOnItemSelectedListener; } diff --git a/core/java/android/widget/CalendarView.java b/core/java/android/widget/CalendarView.java index fd1c4b8d3705..5bc16cb63a5a 100644 --- a/core/java/android/widget/CalendarView.java +++ b/core/java/android/widget/CalendarView.java @@ -16,6 +16,7 @@ package android.widget; +import android.annotation.ColorInt; import android.annotation.DrawableRes; import android.annotation.Widget; import android.content.Context; @@ -140,7 +141,7 @@ public class CalendarView extends FrameLayout { * * @attr ref android.R.styleable#CalendarView_selectedWeekBackgroundColor */ - public void setSelectedWeekBackgroundColor(int color) { + public void setSelectedWeekBackgroundColor(@ColorInt int color) { mDelegate.setSelectedWeekBackgroundColor(color); } @@ -151,6 +152,7 @@ public class CalendarView extends FrameLayout { * * @attr ref android.R.styleable#CalendarView_selectedWeekBackgroundColor */ + @ColorInt public int getSelectedWeekBackgroundColor() { return mDelegate.getSelectedWeekBackgroundColor(); } @@ -162,7 +164,7 @@ public class CalendarView extends FrameLayout { * * @attr ref android.R.styleable#CalendarView_focusedMonthDateColor */ - public void setFocusedMonthDateColor(int color) { + public void setFocusedMonthDateColor(@ColorInt int color) { mDelegate.setFocusedMonthDateColor(color); } @@ -173,6 +175,7 @@ public class CalendarView extends FrameLayout { * * @attr ref android.R.styleable#CalendarView_focusedMonthDateColor */ + @ColorInt public int getFocusedMonthDateColor() { return mDelegate.getFocusedMonthDateColor(); } @@ -184,7 +187,7 @@ public class CalendarView extends FrameLayout { * * @attr ref android.R.styleable#CalendarView_unfocusedMonthDateColor */ - public void setUnfocusedMonthDateColor(int color) { + public void setUnfocusedMonthDateColor(@ColorInt int color) { mDelegate.setUnfocusedMonthDateColor(color); } @@ -195,6 +198,7 @@ public class CalendarView extends FrameLayout { * * @attr ref android.R.styleable#CalendarView_unfocusedMonthDateColor */ + @ColorInt public int getUnfocusedMonthDateColor() { return mDelegate.getUnfocusedMonthDateColor(); } @@ -206,7 +210,7 @@ public class CalendarView extends FrameLayout { * * @attr ref android.R.styleable#CalendarView_weekNumberColor */ - public void setWeekNumberColor(int color) { + public void setWeekNumberColor(@ColorInt int color) { mDelegate.setWeekNumberColor(color); } @@ -217,6 +221,7 @@ public class CalendarView extends FrameLayout { * * @attr ref android.R.styleable#CalendarView_weekNumberColor */ + @ColorInt public int getWeekNumberColor() { return mDelegate.getWeekNumberColor(); } @@ -228,7 +233,7 @@ public class CalendarView extends FrameLayout { * * @attr ref android.R.styleable#CalendarView_weekSeparatorLineColor */ - public void setWeekSeparatorLineColor(int color) { + public void setWeekSeparatorLineColor(@ColorInt int color) { mDelegate.setWeekSeparatorLineColor(color); } @@ -239,6 +244,7 @@ public class CalendarView extends FrameLayout { * * @attr ref android.R.styleable#CalendarView_weekSeparatorLineColor */ + @ColorInt public int getWeekSeparatorLineColor() { return mDelegate.getWeekSeparatorLineColor(); } diff --git a/core/java/android/widget/EdgeEffect.java b/core/java/android/widget/EdgeEffect.java index 391347e13ab2..9019f3123135 100644 --- a/core/java/android/widget/EdgeEffect.java +++ b/core/java/android/widget/EdgeEffect.java @@ -16,6 +16,7 @@ package android.widget; +import android.annotation.ColorInt; import android.content.res.TypedArray; import android.graphics.Paint; import android.graphics.PorterDuff; @@ -292,7 +293,7 @@ public class EdgeEffect { * * @param color Color in argb */ - public void setColor(int color) { + public void setColor(@ColorInt int color) { mPaint.setColor(color); } @@ -300,6 +301,7 @@ public class EdgeEffect { * Return the color of this edge effect in argb. * @return The color of this edge effect in argb */ + @ColorInt public int getColor() { return mPaint.getColor(); } diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java index 5d519ed2894d..0f99e8865ea9 100644 --- a/core/java/android/widget/Editor.java +++ b/core/java/android/widget/Editor.java @@ -128,7 +128,7 @@ public class Editor { // Each Editor manages its own undo stack. private final UndoManager mUndoManager = new UndoManager(); private UndoOwner mUndoOwner = mUndoManager.getOwner(UNDO_OWNER_TAG, this); - final InputFilter mUndoInputFilter = new UndoInputFilter(this); + final UndoInputFilter mUndoInputFilter = new UndoInputFilter(this); boolean mAllowUndo = true; // Cursor Controllers. @@ -246,6 +246,15 @@ public class Editor { mUndoOwner = mUndoManager.getOwner(UNDO_OWNER_TAG, this); } + /** + * Forgets all undo and redo operations for this Editor. + */ + void forgetUndoRedo() { + UndoOwner[] owners = { mUndoOwner }; + mUndoManager.forgetUndos(owners, -1 /* all */); + mUndoManager.forgetRedos(owners, -1 /* all */); + } + boolean canUndo() { UndoOwner[] owners = { mUndoOwner }; return mAllowUndo && mUndoManager.countUndos(owners) > 0; @@ -1214,6 +1223,7 @@ public class Editor { ims.mChangedEnd = EXTRACT_UNKNOWN; ims.mContentChanged = false; } + mUndoInputFilter.beginBatchEdit(); mTextView.onBeginBatchEdit(); } } @@ -1240,6 +1250,7 @@ public class Editor { void finishBatchEdit(final InputMethodState ims) { mTextView.onEndBatchEdit(); + mUndoInputFilter.endBatchEdit(); if (ims.mContentChanged || ims.mSelectionModeChanged) { mTextView.updateAfterEdit(); @@ -3315,6 +3326,8 @@ public class Editor { mContainer.setSplitTouchEnabled(true); mContainer.setClippingEnabled(false); mContainer.setWindowLayoutType(WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL); + mContainer.setWidth(ViewGroup.LayoutParams.WRAP_CONTENT); + mContainer.setHeight(ViewGroup.LayoutParams.WRAP_CONTENT); mContainer.setContentView(this); mDrawableLtr = drawableLtr; @@ -4546,10 +4559,30 @@ public class Editor { public static class UndoInputFilter implements InputFilter { private final Editor mEditor; + // Whether the current filter pass is directly caused by an end-user text edit. + private boolean mIsUserEdit; + + // Whether this is the first pass through the filter for a given end-user text edit. + private boolean mFirstFilterPass; + public UndoInputFilter(Editor editor) { mEditor = editor; } + /** + * Signals that a user-triggered edit is starting. + */ + public void beginBatchEdit() { + if (DEBUG_UNDO) Log.d(TAG, "beginBatchEdit"); + mIsUserEdit = true; + mFirstFilterPass = true; + } + + public void endBatchEdit() { + if (DEBUG_UNDO) Log.d(TAG, "endBatchEdit"); + mIsUserEdit = false; + } + @Override public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) { @@ -4558,36 +4591,24 @@ public class Editor { "dest=" + dest + " (" + dstart + "-" + dend + ")"); } - if (!mEditor.mAllowUndo) { - if (DEBUG_UNDO) Log.d(TAG, "filter: undo is disabled"); + // Check to see if this edit should be tracked for undo. + if (!canUndoEdit(source, start, end, dest, dstart, dend)) { return null; } - final UndoManager um = mEditor.mUndoManager; - if (um.isInUndo()) { - if (DEBUG_UNDO) Log.d(TAG, "filter: skipping, currently performing undo/redo"); - return null; - } - - // Text filters run before input operations are applied. However, some input operations - // are invalid and will throw exceptions when applied. This is common in tests. Don't - // attempt to undo invalid operations. - if (!isValidRange(source, start, end) || !isValidRange(dest, dstart, dend)) { - if (DEBUG_UNDO) Log.d(TAG, "filter: invalid op"); - return null; - } - - // Earlier filters can rewrite input to be a no-op, for example due to a length limit - // on an input field. Skip no-op changes. - if (start == end && dstart == dend) { - if (DEBUG_UNDO) Log.d(TAG, "filter: skipping no-op"); - return null; - } + // An application may install a TextWatcher to provide additional modifications after + // the initial input filters run (e.g. a credit card formatter that adds spaces to a + // string). This results in multiple filter() calls for what the user considers to be + // a single operation. Always undo the whole set of changes in one step. + final boolean forceMerge = !mFirstFilterPass; + mFirstFilterPass = false; // Build a new operation with all the information from this edit. - EditOperation edit = new EditOperation(mEditor, source, start, end, dest, dstart, dend); + EditOperation edit = new EditOperation(mEditor, forceMerge, + source, start, end, dest, dstart, dend); // Fetch the last edit operation and attempt to merge in the new edit. + final UndoManager um = mEditor.mUndoManager; um.beginUpdate("Edit text"); EditOperation lastEdit = um.getLastOperation( EditOperation.class, mEditor.mUndoOwner, UndoManager.MERGE_MODE_UNIQUE); @@ -4595,6 +4616,12 @@ public class Editor { // Add this as the first edit. if (DEBUG_UNDO) Log.d(TAG, "filter: adding first op " + edit); um.addOperation(edit, UndoManager.MERGE_MODE_NONE); + } else if (!mIsUserEdit) { + // An application directly modified the Editable outside of a text edit. Treat this + // as a new change and don't attempt to merge. + if (DEBUG_UNDO) Log.d(TAG, "non-user edit, new op " + edit); + um.commitState(mEditor.mUndoOwner); + um.addOperation(edit, UndoManager.MERGE_MODE_NONE); } else if (lastEdit.mergeWith(edit)) { // Merge succeeded, nothing else to do. if (DEBUG_UNDO) Log.d(TAG, "filter: merge succeeded, created " + lastEdit); @@ -4607,6 +4634,36 @@ public class Editor { um.endUpdate(); return null; // Text not changed. } + + private boolean canUndoEdit(CharSequence source, int start, int end, + Spanned dest, int dstart, int dend) { + if (!mEditor.mAllowUndo) { + if (DEBUG_UNDO) Log.d(TAG, "filter: undo is disabled"); + return false; + } + + if (mEditor.mUndoManager.isInUndo()) { + if (DEBUG_UNDO) Log.d(TAG, "filter: skipping, currently performing undo/redo"); + return false; + } + + // Text filters run before input operations are applied. However, some input operations + // are invalid and will throw exceptions when applied. This is common in tests. Don't + // attempt to undo invalid operations. + if (!isValidRange(source, start, end) || !isValidRange(dest, dstart, dend)) { + if (DEBUG_UNDO) Log.d(TAG, "filter: invalid op"); + return false; + } + + // Earlier filters can rewrite input to be a no-op, for example due to a length limit + // on an input field. Skip no-op changes. + if (start == end && dstart == dend) { + if (DEBUG_UNDO) Log.d(TAG, "filter: skipping no-op"); + return false; + } + + return true; + } } /** @@ -4618,6 +4675,7 @@ public class Editor { private static final int TYPE_REPLACE = 2; private int mType; + private boolean mForceMerge; private String mOldText; private int mOldTextStart; private String mNewText; @@ -4629,10 +4687,12 @@ public class Editor { /** * Constructs an edit operation from a text input operation that replaces the range * (dstart, dend) of dest with (start, end) of source. See {@link InputFilter#filter}. + * If forceMerge is true then always forcibly merge this operation with any previous one. */ - public EditOperation(Editor editor, CharSequence source, int start, int end, - Spanned dest, int dstart, int dend) { + public EditOperation(Editor editor, boolean forceMerge, + CharSequence source, int start, int end, Spanned dest, int dstart, int dend) { super(editor.mUndoOwner); + mForceMerge = forceMerge; mOldText = dest.subSequence(dstart, dend).toString(); mNewText = source.subSequence(start, end).toString(); @@ -4660,6 +4720,7 @@ public class Editor { public EditOperation(Parcel src, ClassLoader loader) { super(src, loader); mType = src.readInt(); + mForceMerge = src.readInt() != 0; mOldText = src.readString(); mOldTextStart = src.readInt(); mNewText = src.readString(); @@ -4671,6 +4732,7 @@ public class Editor { @Override public void writeToParcel(Parcel dest, int flags) { dest.writeInt(mType); + dest.writeInt(mForceMerge ? 1 : 0); dest.writeString(mOldText); dest.writeInt(mOldTextStart); dest.writeString(mNewText); @@ -4679,6 +4741,14 @@ public class Editor { dest.writeInt(mNewCursorPos); } + private int getNewTextEnd() { + return mNewTextStart + mNewText.length(); + } + + private int getOldTextEnd() { + return mOldTextStart + mOldText.length(); + } + @Override public void commit() { } @@ -4687,14 +4757,20 @@ public class Editor { public void undo() { if (DEBUG_UNDO) Log.d(TAG, "undo"); // Remove the new text and insert the old. - modifyText(mNewTextStart, getNewTextEnd(), mOldText, mOldTextStart, mOldCursorPos); + Editor editor = getOwnerData(); + Editable text = (Editable) editor.mTextView.getText(); + modifyText(text, mNewTextStart, getNewTextEnd(), mOldText, mOldTextStart, + mOldCursorPos); } @Override public void redo() { if (DEBUG_UNDO) Log.d(TAG, "redo"); // Remove the old text and insert the new. - modifyText(mOldTextStart, getOldTextEnd(), mNewText, mNewTextStart, mNewCursorPos); + Editor editor = getOwnerData(); + Editable text = (Editable) editor.mTextView.getText(); + modifyText(text, mOldTextStart, getOldTextEnd(), mNewText, mNewTextStart, + mNewCursorPos); } /** @@ -4704,6 +4780,14 @@ public class Editor { * object unchanged. */ private boolean mergeWith(EditOperation edit) { + if (DEBUG_UNDO) { + Log.d(TAG, "mergeWith old " + this); + Log.d(TAG, "mergeWith new " + edit); + } + if (edit.mForceMerge) { + forceMergeWith(edit); + return true; + } switch (mType) { case TYPE_INSERT: return mergeInsertWith(edit); @@ -4717,7 +4801,6 @@ public class Editor { } private boolean mergeInsertWith(EditOperation edit) { - if (DEBUG_UNDO) Log.d(TAG, "mergeInsertWith " + edit); // Only merge continuous insertions. if (edit.mType != TYPE_INSERT) { return false; @@ -4733,7 +4816,6 @@ public class Editor { // TODO: Support forward delete. private boolean mergeDeleteWith(EditOperation edit) { - if (DEBUG_UNDO) Log.d(TAG, "mergeDeleteWith " + edit); // Only merge continuous deletes. if (edit.mType != TYPE_DELETE) { return false; @@ -4749,11 +4831,8 @@ public class Editor { } private boolean mergeReplaceWith(EditOperation edit) { - if (DEBUG_UNDO) Log.d(TAG, "mergeReplaceWith " + edit); - // Replacements can merge only with adjacent inserts and adjacent replacements. - if (edit.mType == TYPE_DELETE || - getNewTextEnd() != edit.mOldTextStart || - edit.mOldTextStart != edit.mNewTextStart) { + // Replacements can merge only with adjacent inserts. + if (edit.mType != TYPE_INSERT || getNewTextEnd() != edit.mNewTextStart) { return false; } mOldText += edit.mOldText; @@ -4762,18 +4841,42 @@ public class Editor { return true; } - private int getNewTextEnd() { - return mNewTextStart + mNewText.length(); - } + /** + * Forcibly creates a single merged edit operation by simulating the entire text + * contents being replaced. + */ + private void forceMergeWith(EditOperation edit) { + if (DEBUG_UNDO) Log.d(TAG, "forceMerge"); + Editor editor = getOwnerData(); - private int getOldTextEnd() { - return mOldTextStart + mOldText.length(); + // Copy the text of the current field. + // NOTE: Using StringBuilder instead of SpannableStringBuilder would be somewhat faster, + // but would require two parallel implementations of modifyText() because Editable and + // StringBuilder do not share an interface for replace/delete/insert. + Editable editable = (Editable) editor.mTextView.getText(); + Editable originalText = new SpannableStringBuilder(editable.toString()); + + // Roll back the last operation. + modifyText(originalText, mNewTextStart, getNewTextEnd(), mOldText, mOldTextStart, + mOldCursorPos); + + // Clone the text again and apply the new operation. + Editable finalText = new SpannableStringBuilder(editable.toString()); + modifyText(finalText, edit.mOldTextStart, edit.getOldTextEnd(), edit.mNewText, + edit.mNewTextStart, edit.mNewCursorPos); + + // Convert this operation into a non-mergeable replacement of the entire string. + mType = TYPE_REPLACE; + mNewText = finalText.toString(); + mNewTextStart = 0; + mOldText = originalText.toString(); + mOldTextStart = 0; + mNewCursorPos = edit.mNewCursorPos; + // mOldCursorPos is unchanged. } - private void modifyText(int deleteFrom, int deleteTo, CharSequence newText, - int newTextInsertAt, int newCursorPos) { - Editor editor = getOwnerData(); - Editable text = (Editable) editor.mTextView.getText(); + private static void modifyText(Editable text, int deleteFrom, int deleteTo, + CharSequence newText, int newTextInsertAt, int newCursorPos) { // Apply the edit if it is still valid. if (isValidRange(text, deleteFrom, deleteTo) && newTextInsertAt <= text.length() - (deleteTo - deleteFrom)) { @@ -4791,10 +4894,22 @@ public class Editor { } } + private String getTypeString() { + switch (mType) { + case TYPE_INSERT: + return "insert"; + case TYPE_DELETE: + return "delete"; + case TYPE_REPLACE: + return "replace"; + default: + return ""; + } + } + @Override public String toString() { - return "EditOperation: [" + - "mType=" + mType + ", " + + return "[mType=" + getTypeString() + ", " + "mOldText=" + mOldText + ", " + "mOldTextStart=" + mOldTextStart + ", " + "mNewText=" + mNewText + ", " + diff --git a/core/java/android/widget/FrameLayout.java b/core/java/android/widget/FrameLayout.java index e8dc11fdff1b..f6d198b214e9 100644 --- a/core/java/android/widget/FrameLayout.java +++ b/core/java/android/widget/FrameLayout.java @@ -101,15 +101,16 @@ public class FrameLayout extends ViewGroup { super(context); } - public FrameLayout(Context context, AttributeSet attrs) { + public FrameLayout(Context context, @Nullable AttributeSet attrs) { this(context, attrs, 0); } - public FrameLayout(Context context, AttributeSet attrs, int defStyleAttr) { + public FrameLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { this(context, attrs, defStyleAttr, 0); } - public FrameLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { + public FrameLayout( + Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); final TypedArray a = context.obtainStyledAttributes( diff --git a/core/java/android/widget/GridLayout.java b/core/java/android/widget/GridLayout.java index e8fe1912e405..6cc4bda43510 100644 --- a/core/java/android/widget/GridLayout.java +++ b/core/java/android/widget/GridLayout.java @@ -141,7 +141,9 @@ import static java.lang.Math.min; * view was alone in a column, that column would itself collapse to zero width if and only if * no gravity was defined on the view. If gravity was defined, then the gone-marked * view has no effect on the layout and the container should be laid out as if the view - * had never been added to it. + * had never been added to it. GONE views are taken to have zero weight during excess space + * distribution. + * <p> * These statements apply equally to rows as well as columns, and to groups of rows or columns. * * <p> @@ -1010,12 +1012,10 @@ public class GridLayout extends ViewGroup { LayoutParams lp = getLayoutParams(c); if (firstPass) { measureChildWithMargins2(c, widthSpec, heightSpec, lp.width, lp.height); - mHorizontalAxis.recordOriginalMeasurement(i); - mVerticalAxis.recordOriginalMeasurement(i); } else { boolean horizontal = (mOrientation == HORIZONTAL); Spec spec = horizontal ? lp.columnSpec : lp.rowSpec; - if (spec.alignment == FILL) { + if (spec.getAbsoluteAlignment(horizontal) == FILL) { Interval span = spec.span; Axis axis = horizontal ? mHorizontalAxis : mVerticalAxis; int[] locations = axis.getLocations(); @@ -1091,11 +1091,6 @@ public class GridLayout extends ViewGroup { invalidateValues(); } - final Alignment getAlignment(Alignment alignment, boolean horizontal) { - return (alignment != UNDEFINED_ALIGNMENT) ? alignment : - (horizontal ? START : BASELINE); - } - // Layout container /** @@ -1150,8 +1145,8 @@ public class GridLayout extends ViewGroup { int pWidth = getMeasurement(c, true); int pHeight = getMeasurement(c, false); - Alignment hAlign = getAlignment(columnSpec.alignment, true); - Alignment vAlign = getAlignment(rowSpec.alignment, false); + Alignment hAlign = columnSpec.getAbsoluteAlignment(true); + Alignment vAlign = rowSpec.getAbsoluteAlignment(false); Bounds boundsX = mHorizontalAxis.getGroupBounds().getValue(i); Bounds boundsY = mVerticalAxis.getGroupBounds().getValue(i); @@ -1234,7 +1229,6 @@ public class GridLayout extends ViewGroup { public boolean hasWeights; public boolean hasWeightsValid = false; - public int[] originalMeasurements; public int[] deltas; boolean orderPreserved = DEFAULT_ORDER_PRESERVED; @@ -1297,7 +1291,7 @@ public class GridLayout extends ViewGroup { // we must include views that are GONE here, see introductory javadoc LayoutParams lp = getLayoutParams(c); Spec spec = horizontal ? lp.columnSpec : lp.rowSpec; - Bounds bounds = getAlignment(spec.alignment, horizontal).getBounds(); + Bounds bounds = spec.getAbsoluteAlignment(horizontal).getBounds(); assoc.put(spec, bounds); } return assoc.pack(); @@ -1313,9 +1307,8 @@ public class GridLayout extends ViewGroup { // we must include views that are GONE here, see introductory javadoc LayoutParams lp = getLayoutParams(c); Spec spec = horizontal ? lp.columnSpec : lp.rowSpec; - int size = (spec.weight == 0) ? - getMeasurementIncludingMargin(c, horizontal) : - getOriginalMeasurements()[i] + getDeltas()[i]; + int size = getMeasurementIncludingMargin(c, horizontal) + + ((spec.weight == 0) ? 0 : getDeltas()[i]); groupBounds.getValue(i).include(GridLayout.this, c, spec, this, size); } } @@ -1703,7 +1696,11 @@ public class GridLayout extends ViewGroup { private boolean computeHasWeights() { for (int i = 0, N = getChildCount(); i < N; i++) { - LayoutParams lp = getLayoutParams(getChildAt(i)); + final View child = getChildAt(i); + if (child.getVisibility() == View.GONE) { + continue; + } + LayoutParams lp = getLayoutParams(child); Spec spec = horizontal ? lp.columnSpec : lp.rowSpec; if (spec.weight != 0) { return true; @@ -1720,19 +1717,6 @@ public class GridLayout extends ViewGroup { return hasWeights; } - public int[] getOriginalMeasurements() { - if (originalMeasurements == null) { - originalMeasurements = new int[getChildCount()]; - } - return originalMeasurements; - } - - private void recordOriginalMeasurement(int i) { - if (hasWeights()) { - getOriginalMeasurements()[i] = getMeasurementIncludingMargin(getChildAt(i), horizontal); - } - } - public int[] getDeltas() { if (deltas == null) { deltas = new int[getChildCount()]; @@ -1743,7 +1727,10 @@ public class GridLayout extends ViewGroup { private void shareOutDelta(int totalDelta, float totalWeight) { Arrays.fill(deltas, 0); for (int i = 0, N = getChildCount(); i < N; i++) { - View c = getChildAt(i); + final View c = getChildAt(i); + if (c.getVisibility() == View.GONE) { + continue; + } LayoutParams lp = getLayoutParams(c); Spec spec = horizontal ? lp.columnSpec : lp.rowSpec; float weight = spec.weight; @@ -1796,6 +1783,9 @@ public class GridLayout extends ViewGroup { float totalWeight = 0f; for (int i = 0, N = getChildCount(); i < N; i++) { View c = getChildAt(i); + if (c.getVisibility() == View.GONE) { + continue; + } LayoutParams lp = getLayoutParams(c); Spec spec = horizontal ? lp.columnSpec : lp.rowSpec; totalWeight += spec.weight; @@ -1891,7 +1881,6 @@ public class GridLayout extends ViewGroup { locations = null; - originalMeasurements = null; deltas = null; hasWeightsValid = false; @@ -2011,7 +2000,6 @@ public class GridLayout extends ViewGroup { R.styleable.ViewGroup_MarginLayout_layout_marginRight; private static final int BOTTOM_MARGIN = R.styleable.ViewGroup_MarginLayout_layout_marginBottom; - private static final int COLUMN = R.styleable.GridLayout_Layout_layout_column; private static final int COLUMN_SPAN = R.styleable.GridLayout_Layout_layout_columnSpan; private static final int COLUMN_WEIGHT = R.styleable.GridLayout_Layout_layout_columnWeight; @@ -2405,7 +2393,7 @@ public class GridLayout extends ViewGroup { protected final void include(GridLayout gl, View c, Spec spec, Axis axis, int size) { this.flexibility &= spec.getFlexibility(); boolean horizontal = axis.horizontal; - Alignment alignment = gl.getAlignment(spec.alignment, horizontal); + Alignment alignment = spec.getAbsoluteAlignment(axis.horizontal); // todo test this works correctly when the returned value is UNDEFINED int before = alignment.getAlignmentValue(c, size, gl.getLayoutMode()); include(before, size - before); @@ -2556,6 +2544,16 @@ public class GridLayout extends ViewGroup { this(startDefined, new Interval(start, start + size), alignment, weight); } + private Alignment getAbsoluteAlignment(boolean horizontal) { + if (alignment != UNDEFINED_ALIGNMENT) { + return alignment; + } + if (weight == 0f) { + return horizontal ? START : BASELINE; + } + return FILL; + } + final Spec copyWriteSpan(Interval span) { return new Spec(startDefined, span, alignment, weight); } diff --git a/core/java/android/widget/LinearLayout.java b/core/java/android/widget/LinearLayout.java index f599035a1c3e..da15302b3552 100644 --- a/core/java/android/widget/LinearLayout.java +++ b/core/java/android/widget/LinearLayout.java @@ -19,6 +19,7 @@ package android.widget; import com.android.internal.R; import android.annotation.IntDef; +import android.annotation.Nullable; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; @@ -186,11 +187,11 @@ public class LinearLayout extends ViewGroup { this(context, null); } - public LinearLayout(Context context, AttributeSet attrs) { + public LinearLayout(Context context, @Nullable AttributeSet attrs) { this(context, attrs, 0); } - public LinearLayout(Context context, AttributeSet attrs, int defStyleAttr) { + public LinearLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { this(context, attrs, defStyleAttr, 0); } diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java index dd7fa18468c2..a10be119da45 100644 --- a/core/java/android/widget/RemoteViews.java +++ b/core/java/android/widget/RemoteViews.java @@ -16,6 +16,7 @@ package android.widget; +import android.annotation.ColorInt; import android.app.ActivityOptions; import android.app.ActivityThread; import android.app.Application; @@ -2263,7 +2264,7 @@ public class RemoteViews implements Parcelable, Filter { * @param color Sets the text color for all the states (normal, selected, * focused) to be this color. */ - public void setTextColor(int viewId, int color) { + public void setTextColor(int viewId, @ColorInt int color) { setInt(viewId, "setTextColor", color); } diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 9bef1fecd446..faf1c4096b26 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -17,6 +17,7 @@ package android.widget; import android.R; +import android.annotation.ColorInt; import android.annotation.DrawableRes; import android.annotation.NonNull; import android.annotation.Nullable; @@ -637,16 +638,17 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener this(context, null); } - public TextView(Context context, AttributeSet attrs) { + public TextView(Context context, @Nullable AttributeSet attrs) { this(context, attrs, com.android.internal.R.attr.textViewStyle); } - public TextView(Context context, AttributeSet attrs, int defStyleAttr) { + public TextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { this(context, attrs, defStyleAttr, 0); } @SuppressWarnings("deprecation") - public TextView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { + public TextView( + Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); mText = ""; @@ -2996,7 +2998,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener * @attr ref android.R.styleable#TextView_textColor */ @android.view.RemotableViewMethod - public void setTextColor(int color) { + public void setTextColor(@ColorInt int color) { mTextColor = ColorStateList.valueOf(color); updateTextColors(); } @@ -3037,6 +3039,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener * * @return Returns the current text color. */ + @ColorInt public final int getCurrentTextColor() { return mCurTextColor; } @@ -3047,7 +3050,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener * @attr ref android.R.styleable#TextView_textColorHighlight */ @android.view.RemotableViewMethod - public void setHighlightColor(int color) { + public void setHighlightColor(@ColorInt int color) { if (mHighlightColor != color) { mHighlightColor = color; invalidate(); @@ -3061,6 +3064,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener * * @attr ref android.R.styleable#TextView_textColorHighlight */ + @ColorInt public int getHighlightColor() { return mHighlightColor; } @@ -3155,6 +3159,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener * * @attr ref android.R.styleable#TextView_shadowColor */ + @ColorInt public int getShadowColor() { return mShadowColor; } @@ -3230,7 +3235,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener * @attr ref android.R.styleable#TextView_textColorHint */ @android.view.RemotableViewMethod - public final void setHintTextColor(int color) { + public final void setHintTextColor(@ColorInt int color) { mHintTextColor = ColorStateList.valueOf(color); updateTextColors(); } @@ -3269,6 +3274,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener * * @return Returns the current hint text color. */ + @ColorInt public final int getCurrentHintTextColor() { return mHintTextColor != null ? mCurHintTextColor : mCurTextColor; } @@ -3282,7 +3288,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener * @attr ref android.R.styleable#TextView_textColorLink */ @android.view.RemotableViewMethod - public final void setLinkTextColor(int color) { + public final void setLinkTextColor(@ColorInt int color) { mLinkTextColor = ColorStateList.valueOf(color); updateTextColors(); } @@ -4119,6 +4125,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener if (type == BufferType.EDITABLE || getKeyListener() != null || needEditableForNotification) { createEditorIfNeeded(); + mEditor.forgetUndoRedo(); Editable t = mEditableFactory.newEditable(text); text = t; setFilters(t, mFilters); diff --git a/core/java/android/widget/Toolbar.java b/core/java/android/widget/Toolbar.java index 9bc2aabb49b9..d2430bc6b645 100644 --- a/core/java/android/widget/Toolbar.java +++ b/core/java/android/widget/Toolbar.java @@ -16,6 +16,7 @@ package android.widget; +import android.annotation.ColorInt; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActionBar; @@ -685,7 +686,7 @@ public class Toolbar extends ViewGroup { * * @param color The new text color in 0xAARRGGBB format */ - public void setTitleTextColor(int color) { + public void setTitleTextColor(@ColorInt int color) { mTitleTextColor = color; if (mTitleTextView != null) { mTitleTextView.setTextColor(color); @@ -697,7 +698,7 @@ public class Toolbar extends ViewGroup { * * @param color The new text color in 0xAARRGGBB format */ - public void setSubtitleTextColor(int color) { + public void setSubtitleTextColor(@ColorInt int color) { mSubtitleTextColor = color; if (mSubtitleTextView != null) { mSubtitleTextView.setTextColor(color); diff --git a/core/java/com/android/internal/app/DumpHeapActivity.java b/core/java/com/android/internal/app/DumpHeapActivity.java new file mode 100644 index 000000000000..7e70b0c26ad2 --- /dev/null +++ b/core/java/com/android/internal/app/DumpHeapActivity.java @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.app; + +import android.app.Activity; +import android.app.AlertDialog; +import android.content.ClipData; +import android.content.DialogInterface; +import android.content.Intent; +import android.net.Uri; +import android.os.Bundle; +import android.util.DebugUtils; + +/** + * This activity is displayed when the system has collected a heap dump from + * a large process and the user has selected to share it. + */ +public class DumpHeapActivity extends Activity { + /** The process we are reporting */ + public static final String KEY_PROCESS = "process"; + /** The size limit the process reached */ + public static final String KEY_SIZE = "size"; + + // Broadcast action to determine when to delete the current dump heap data. + public static final String ACTION_DELETE_DUMPHEAP = "com.android.server.am.DELETE_DUMPHEAP"; + + // Extra for above: delay delete of data, since the user is in the process of sharing it. + public static final String EXTRA_DELAY_DELETE = "delay_delete"; + + static final public Uri JAVA_URI = Uri.parse("content://com.android.server.heapdump/java"); + + String mProcess; + long mSize; + AlertDialog mDialog; + boolean mHandled = false; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + mProcess = getIntent().getStringExtra(KEY_PROCESS); + mSize = getIntent().getLongExtra(KEY_SIZE, 0); + AlertDialog.Builder b = new AlertDialog.Builder(this, + android.R.style.Theme_Material_Light_Dialog_Alert); + b.setTitle(com.android.internal.R.string.dump_heap_title); + b.setMessage(getString(com.android.internal.R.string.dump_heap_text, + mProcess, DebugUtils.sizeValueToString(mSize, null))); + b.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + mHandled = true; + sendBroadcast(new Intent(ACTION_DELETE_DUMPHEAP)); + finish(); + } + }); + b.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + mHandled = true; + Intent broadcast = new Intent(ACTION_DELETE_DUMPHEAP); + broadcast.putExtra(EXTRA_DELAY_DELETE, true); + sendBroadcast(broadcast); + Intent intent = new Intent(Intent.ACTION_SEND); + ClipData clip = ClipData.newUri(getContentResolver(), "Heap Dump", JAVA_URI); + intent.setClipData(clip); + intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + intent.setType(clip.getDescription().getMimeType(0)); + intent.putExtra(Intent.EXTRA_STREAM, JAVA_URI); + startActivity(Intent.createChooser(intent, + getText(com.android.internal.R.string.dump_heap_title))); + finish(); + } + }); + mDialog = b.show(); + } + + @Override + protected void onStop() { + super.onStop(); + if (!isChangingConfigurations()) { + if (!mHandled) { + sendBroadcast(new Intent(ACTION_DELETE_DUMPHEAP)); + } + } + } + + @Override + protected void onDestroy() { + super.onDestroy(); + mDialog.dismiss(); + } +} diff --git a/core/java/com/android/internal/app/ProcessStats.java b/core/java/com/android/internal/app/ProcessStats.java index 70fb51072acf..75beee9572f8 100644 --- a/core/java/com/android/internal/app/ProcessStats.java +++ b/core/java/com/android/internal/app/ProcessStats.java @@ -24,6 +24,7 @@ import android.os.UserHandle; import android.text.format.DateFormat; import android.util.ArrayMap; import android.util.ArraySet; +import android.util.DebugUtils; import android.util.Log; import android.util.Slog; import android.util.SparseArray; @@ -897,17 +898,17 @@ public final class ProcessStats implements Parcelable { pw.print(STATE_NAMES[procStates[ip]]); pw.print(": "); pw.print(count); pw.print(" samples "); - printSizeValue(pw, proc.getPssMinimum(bucket) * 1024); + DebugUtils.printSizeValue(pw, proc.getPssMinimum(bucket) * 1024); pw.print(" "); - printSizeValue(pw, proc.getPssAverage(bucket) * 1024); + DebugUtils.printSizeValue(pw, proc.getPssAverage(bucket) * 1024); pw.print(" "); - printSizeValue(pw, proc.getPssMaximum(bucket) * 1024); + DebugUtils.printSizeValue(pw, proc.getPssMaximum(bucket) * 1024); pw.print(" / "); - printSizeValue(pw, proc.getPssUssMinimum(bucket) * 1024); + DebugUtils.printSizeValue(pw, proc.getPssUssMinimum(bucket) * 1024); pw.print(" "); - printSizeValue(pw, proc.getPssUssAverage(bucket) * 1024); + DebugUtils.printSizeValue(pw, proc.getPssUssAverage(bucket) * 1024); pw.print(" "); - printSizeValue(pw, proc.getPssUssMaximum(bucket) * 1024); + DebugUtils.printSizeValue(pw, proc.getPssUssMaximum(bucket) * 1024); pw.println(); } } @@ -924,9 +925,9 @@ public final class ProcessStats implements Parcelable { if (proc.mNumCachedKill != 0) { pw.print(prefix); pw.print("Killed from cached state: "); pw.print(proc.mNumCachedKill); pw.print(" times from pss "); - printSizeValue(pw, proc.mMinCachedKillPss * 1024); pw.print("-"); - printSizeValue(pw, proc.mAvgCachedKillPss * 1024); pw.print("-"); - printSizeValue(pw, proc.mMaxCachedKillPss * 1024); pw.println(); + DebugUtils.printSizeValue(pw, proc.mMinCachedKillPss * 1024); pw.print("-"); + DebugUtils.printSizeValue(pw, proc.mAvgCachedKillPss * 1024); pw.print("-"); + DebugUtils.printSizeValue(pw, proc.mMaxCachedKillPss * 1024); pw.println(); } } @@ -939,11 +940,11 @@ public final class ProcessStats implements Parcelable { int bucket, int index) { pw.print(prefix); pw.print(label); pw.print(": "); - printSizeValue(pw, getSysMemUsageValue(bucket, index) * 1024); + DebugUtils.printSizeValue(pw, getSysMemUsageValue(bucket, index) * 1024); pw.print(" min, "); - printSizeValue(pw, getSysMemUsageValue(bucket, index + 1) * 1024); + DebugUtils.printSizeValue(pw, getSysMemUsageValue(bucket, index + 1) * 1024); pw.print(" avg, "); - printSizeValue(pw, getSysMemUsageValue(bucket, index+2) * 1024); + DebugUtils.printSizeValue(pw, getSysMemUsageValue(bucket, index+2) * 1024); pw.println(" max"); } @@ -1150,43 +1151,6 @@ public final class ProcessStats implements Parcelable { pw.print("%"); } - static void printSizeValue(PrintWriter pw, long number) { - float result = number; - String suffix = ""; - if (result > 900) { - suffix = "KB"; - result = result / 1024; - } - if (result > 900) { - suffix = "MB"; - result = result / 1024; - } - if (result > 900) { - suffix = "GB"; - result = result / 1024; - } - if (result > 900) { - suffix = "TB"; - result = result / 1024; - } - if (result > 900) { - suffix = "PB"; - result = result / 1024; - } - String value; - if (result < 1) { - value = String.format("%.2f", result); - } else if (result < 10) { - value = String.format("%.1f", result); - } else if (result < 100) { - value = String.format("%.0f", result); - } else { - value = String.format("%.0f", result); - } - pw.print(value); - pw.print(suffix); - } - public static void dumpProcessListCsv(PrintWriter pw, ArrayList<ProcessState> procs, boolean sepScreenStates, int[] screenStates, boolean sepMemStates, int[] memStates, boolean sepProcStates, int[] procStates, long now) { @@ -2437,7 +2401,7 @@ public final class ProcessStats implements Parcelable { pw.print(prefix); pw.print(label); pw.print(": "); - printSizeValue(pw, mem); + DebugUtils.printSizeValue(pw, mem); pw.print(" ("); pw.print(samples); pw.print(" samples)"); @@ -2475,7 +2439,7 @@ public final class ProcessStats implements Parcelable { totalPss = printMemoryCategory(pw, " ", "Z-Ram ", totalMem.sysMemZRamWeight, totalMem.totalTime, totalPss, totalMem.sysMemSamples); pw.print(" TOTAL : "); - printSizeValue(pw, totalPss); + DebugUtils.printSizeValue(pw, totalPss); pw.println(); printMemoryCategory(pw, " ", STATE_NAMES[STATE_SERVICE_RESTARTING], totalMem.processStateWeight[STATE_SERVICE_RESTARTING], totalMem.totalTime, totalPss, @@ -3781,17 +3745,17 @@ public final class ProcessStats implements Parcelable { printPercent(pw, (double) totalTime / (double) overallTime); if (numPss > 0) { pw.print(" ("); - printSizeValue(pw, minPss * 1024); + DebugUtils.printSizeValue(pw, minPss * 1024); pw.print("-"); - printSizeValue(pw, avgPss * 1024); + DebugUtils.printSizeValue(pw, avgPss * 1024); pw.print("-"); - printSizeValue(pw, maxPss * 1024); + DebugUtils.printSizeValue(pw, maxPss * 1024); pw.print("/"); - printSizeValue(pw, minUss * 1024); + DebugUtils.printSizeValue(pw, minUss * 1024); pw.print("-"); - printSizeValue(pw, avgUss * 1024); + DebugUtils.printSizeValue(pw, avgUss * 1024); pw.print("-"); - printSizeValue(pw, maxUss * 1024); + DebugUtils.printSizeValue(pw, maxUss * 1024); if (full) { pw.print(" over "); pw.print(numPss); diff --git a/core/java/com/android/internal/backup/LocalTransport.java b/core/java/com/android/internal/backup/LocalTransport.java index c3cc60aabea3..fb0ffb09c215 100644 --- a/core/java/com/android/internal/backup/LocalTransport.java +++ b/core/java/com/android/internal/backup/LocalTransport.java @@ -369,6 +369,9 @@ public class LocalTransport extends BackupTransport { return TRANSPORT_ERROR; } } + if (DEBUG) { + Log.v(TAG, " stored " + numBytes + " of data"); + } return TRANSPORT_OK; } @@ -431,6 +434,10 @@ public class LocalTransport extends BackupTransport { @Override public RestoreDescription nextRestorePackage() { + if (DEBUG) { + Log.v(TAG, "nextRestorePackage() : mRestorePackage=" + mRestorePackage + + " length=" + mRestorePackages.length); + } if (mRestorePackages == null) throw new IllegalStateException("startRestore not called"); boolean found = false; @@ -441,7 +448,10 @@ public class LocalTransport extends BackupTransport { // skip packages where we have a data dir but no actual contents String[] contents = (new File(mRestoreSetIncrementalDir, name)).list(); if (contents != null && contents.length > 0) { - if (DEBUG) Log.v(TAG, " nextRestorePackage(TYPE_KEY_VALUE) = " + name); + if (DEBUG) { + Log.v(TAG, " nextRestorePackage(TYPE_KEY_VALUE) @ " + + mRestorePackage + " = " + name); + } mRestoreType = RestoreDescription.TYPE_KEY_VALUE; found = true; } @@ -450,7 +460,10 @@ public class LocalTransport extends BackupTransport { // No key/value data; check for [non-empty] full data File maybeFullData = new File(mRestoreSetFullDir, name); if (maybeFullData.length() > 0) { - if (DEBUG) Log.v(TAG, " nextRestorePackage(TYPE_FULL_STREAM) = " + name); + if (DEBUG) { + Log.v(TAG, " nextRestorePackage(TYPE_FULL_STREAM) @ " + + mRestorePackage + " = " + name); + } mRestoreType = RestoreDescription.TYPE_FULL_STREAM; mCurFullRestoreStream = null; // ensure starting from the ground state found = true; @@ -460,6 +473,11 @@ public class LocalTransport extends BackupTransport { if (found) { return new RestoreDescription(name, mRestoreType); } + + if (DEBUG) { + Log.v(TAG, " ... package @ " + mRestorePackage + " = " + name + + " has no data; skipping"); + } } if (DEBUG) Log.v(TAG, " no more packages to restore"); diff --git a/core/java/com/android/internal/os/BatterySipper.java b/core/java/com/android/internal/os/BatterySipper.java index cfeca086b2b4..4cd959f11f20 100644 --- a/core/java/com/android/internal/os/BatterySipper.java +++ b/core/java/com/android/internal/os/BatterySipper.java @@ -26,12 +26,15 @@ public class BatterySipper implements Comparable<BatterySipper> { public double value; public double[] values; public DrainType drainType; + + // Measured in milliseconds. public long usageTime; public long cpuTime; public long gpsTime; public long wifiRunningTime; public long cpuFgTime; public long wakeLockTime; + public long mobileRxPackets; public long mobileTxPackets; public long mobileActive; @@ -48,6 +51,14 @@ public class BatterySipper implements Comparable<BatterySipper> { public String[] mPackages; public String packageWithHighestDrain; + // Measured in mAh (milli-ampere per hour). + public double wifiPower; + public double cpuPower; + public double wakeLockPower; + public double mobileRadioPower; + public double gpsPower; + public double sensorPower; + public enum DrainType { IDLE, CELL, @@ -107,4 +118,31 @@ public class BatterySipper implements Comparable<BatterySipper> { } return uidObj.getUid(); } + + /** + * Add stats from other to this BatterySipper. + */ + public void add(BatterySipper other) { + cpuTime += other.cpuTime; + gpsTime += other.gpsTime; + wifiRunningTime += other.wifiRunningTime; + cpuFgTime += other.cpuFgTime; + wakeLockTime += other.wakeLockTime; + mobileRxPackets += other.mobileRxPackets; + mobileTxPackets += other.mobileTxPackets; + mobileActive += other.mobileActive; + mobileActiveCount += other.mobileActiveCount; + wifiRxPackets += other.wifiRxPackets; + wifiTxPackets += other.wifiTxPackets; + mobileRxBytes += other.mobileRxBytes; + mobileTxBytes += other.mobileTxBytes; + wifiRxBytes += other.wifiRxBytes; + wifiTxBytes += other.wifiTxBytes; + wifiPower += other.wifiPower; + gpsPower += other.gpsPower; + cpuPower += other.cpuPower; + sensorPower += other.sensorPower; + mobileRadioPower += other.mobileRadioPower; + wakeLockPower += other.wakeLockPower; + } } diff --git a/core/java/com/android/internal/os/BatteryStatsHelper.java b/core/java/com/android/internal/os/BatteryStatsHelper.java index eae4427aa98c..d3611bf629c2 100644 --- a/core/java/com/android/internal/os/BatteryStatsHelper.java +++ b/core/java/com/android/internal/os/BatteryStatsHelper.java @@ -344,6 +344,7 @@ public final class BatteryStatsHelper { mMobilemsppList.add(bs); } } + for (int i=0; i<mUserSippers.size(); i++) { List<BatterySipper> user = mUserSippers.valueAt(i); for (int j=0; j<user.size(); j++) { @@ -389,8 +390,8 @@ public final class BatteryStatsHelper { private void processAppUsage(SparseArray<UserHandle> asUsers) { final boolean forAllUsers = (asUsers.get(UserHandle.USER_ALL) != null); - SensorManager sensorManager = (SensorManager) mContext.getSystemService( - Context.SENSOR_SERVICE); + final SensorManager sensorManager = + (SensorManager) mContext.getSystemService(Context.SENSOR_SERVICE); final int which = mStatsType; final int speedSteps = mPowerProfile.getNumSpeedSteps(); final double[] powerCpuNormal = new double[speedSteps]; @@ -401,238 +402,317 @@ public final class BatteryStatsHelper { final double mobilePowerPerPacket = getMobilePowerPerPacket(); final double mobilePowerPerMs = getMobilePowerPerMs(); final double wifiPowerPerPacket = getWifiPowerPerPacket(); - long appWakelockTimeUs = 0; + long totalAppWakelockTimeUs = 0; BatterySipper osApp = null; mStatsPeriod = mTypeBatteryRealtime; - SparseArray<? extends Uid> uidStats = mStats.getUidStats(); + + final ArrayList<BatterySipper> appList = new ArrayList<>(); + + // Max values used to normalize later. + double maxWifiPower = 0; + double maxCpuPower = 0; + double maxWakeLockPower = 0; + double maxMobileRadioPower = 0; + double maxGpsPower = 0; + double maxSensorPower = 0; + + final SparseArray<? extends Uid> uidStats = mStats.getUidStats(); final int NU = uidStats.size(); for (int iu = 0; iu < NU; iu++) { - Uid u = uidStats.valueAt(iu); - double p; // in mAs - double power = 0; // in mAs - double highestDrain = 0; - String packageWithHighestDrain = null; - Map<String, ? extends BatteryStats.Uid.Proc> processStats = u.getProcessStats(); - long cpuTime = 0; - long cpuFgTime = 0; - long wakelockTime = 0; - long gpsTime = 0; + final Uid u = uidStats.valueAt(iu); + final BatterySipper app = new BatterySipper( + BatterySipper.DrainType.APP, u, new double[]{0}); + + final Map<String, ? extends BatteryStats.Uid.Proc> processStats = u.getProcessStats(); if (processStats.size() > 0) { - // Process CPU time + // Process CPU time. + + // Keep track of the package with highest drain. + double highestDrain = 0; + for (Map.Entry<String, ? extends BatteryStats.Uid.Proc> ent : processStats.entrySet()) { Uid.Proc ps = ent.getValue(); - final long userTime = ps.getUserTime(which); - final long systemTime = ps.getSystemTime(which); - final long foregroundTime = ps.getForegroundTime(which); - cpuFgTime += foregroundTime * 10; // convert to millis - final long tmpCpuTime = (userTime + systemTime) * 10; // convert to millis - int totalTimeAtSpeeds = 0; - // Get the total first + app.cpuFgTime += ps.getForegroundTime(which); + final long totalCpuTime = ps.getUserTime(which) + ps.getSystemTime(which); + app.cpuTime += totalCpuTime; + + // Calculate the total CPU time spent at the various speed steps. + long totalTimeAtSpeeds = 0; for (int step = 0; step < speedSteps; step++) { cpuSpeedStepTimes[step] = ps.getTimeAtCpuSpeedStep(step, which); totalTimeAtSpeeds += cpuSpeedStepTimes[step]; } - if (totalTimeAtSpeeds == 0) totalTimeAtSpeeds = 1; - // Then compute the ratio of time spent at each speed - double processPower = 0; + totalTimeAtSpeeds = Math.max(totalTimeAtSpeeds, 1); + + // Then compute the ratio of time spent at each speed and figure out + // the total power consumption. + double cpuPower = 0; for (int step = 0; step < speedSteps; step++) { - double ratio = (double) cpuSpeedStepTimes[step] / totalTimeAtSpeeds; - if (DEBUG && ratio != 0) Log.d(TAG, "UID " + u.getUid() + ": CPU step #" - + step + " ratio=" + makemAh(ratio) + " power=" - + makemAh(ratio*tmpCpuTime*powerCpuNormal[step] / (60*60*1000))); - processPower += ratio * tmpCpuTime * powerCpuNormal[step]; + final double ratio = (double) cpuSpeedStepTimes[step] / totalTimeAtSpeeds; + final double cpuSpeedStepPower = + ratio * totalCpuTime * powerCpuNormal[step]; + if (DEBUG && ratio != 0) { + Log.d(TAG, "UID " + u.getUid() + ": CPU step #" + + step + " ratio=" + makemAh(ratio) + " power=" + + makemAh(cpuSpeedStepPower / (60 * 60 * 1000))); + } + cpuPower += cpuSpeedStepPower; } - cpuTime += tmpCpuTime; - if (DEBUG && processPower != 0) { + + if (DEBUG && cpuPower != 0) { Log.d(TAG, String.format("process %s, cpu power=%s", - ent.getKey(), makemAh(processPower / (60*60*1000)))); + ent.getKey(), makemAh(cpuPower / (60 * 60 * 1000)))); } - power += processPower; - if (packageWithHighestDrain == null - || packageWithHighestDrain.startsWith("*")) { - highestDrain = processPower; - packageWithHighestDrain = ent.getKey(); - } else if (highestDrain < processPower - && !ent.getKey().startsWith("*")) { - highestDrain = processPower; - packageWithHighestDrain = ent.getKey(); + app.cpuPower += cpuPower; + + // Each App can have multiple packages and with multiple running processes. + // Keep track of the package who's process has the highest drain. + if (app.packageWithHighestDrain == null || + app.packageWithHighestDrain.startsWith("*")) { + highestDrain = cpuPower; + app.packageWithHighestDrain = ent.getKey(); + } else if (highestDrain < cpuPower && !ent.getKey().startsWith("*")) { + highestDrain = cpuPower; + app.packageWithHighestDrain = ent.getKey(); } } } - if (cpuFgTime > cpuTime) { - if (DEBUG && cpuFgTime > cpuTime + 10000) { + + // Ensure that the CPU times make sense. + if (app.cpuFgTime > app.cpuTime) { + if (DEBUG && app.cpuFgTime > app.cpuTime + 10000) { Log.d(TAG, "WARNING! Cputime is more than 10 seconds behind Foreground time"); } - cpuTime = cpuFgTime; // Statistics may not have been gathered yet. + + // Statistics may not have been gathered yet. + app.cpuTime = app.cpuFgTime; } - power /= (60*60*1000); + + // Convert the CPU power to mAh + app.cpuPower /= (60 * 60 * 1000); + maxCpuPower = Math.max(maxCpuPower, app.cpuPower); // Process wake lock usage - Map<String, ? extends BatteryStats.Uid.Wakelock> wakelockStats = u.getWakelockStats(); + final Map<String, ? extends BatteryStats.Uid.Wakelock> wakelockStats = + u.getWakelockStats(); + long wakeLockTimeUs = 0; for (Map.Entry<String, ? extends BatteryStats.Uid.Wakelock> wakelockEntry : wakelockStats.entrySet()) { - Uid.Wakelock wakelock = wakelockEntry.getValue(); + final Uid.Wakelock wakelock = wakelockEntry.getValue(); + // Only care about partial wake locks since full wake locks // are canceled when the user turns the screen off. BatteryStats.Timer timer = wakelock.getWakeTime(BatteryStats.WAKE_TYPE_PARTIAL); if (timer != null) { - wakelockTime += timer.getTotalTimeLocked(mRawRealtime, which); + wakeLockTimeUs += timer.getTotalTimeLocked(mRawRealtime, which); } } - appWakelockTimeUs += wakelockTime; - wakelockTime /= 1000; // convert to millis - - // Add cost of holding a wake lock - p = (wakelockTime - * mPowerProfile.getAveragePower(PowerProfile.POWER_CPU_AWAKE)) / (60*60*1000); - if (DEBUG && p != 0) Log.d(TAG, "UID " + u.getUid() + ": wake " - + wakelockTime + " power=" + makemAh(p)); - power += p; + app.wakeLockTime = wakeLockTimeUs / 1000; // convert to millis + totalAppWakelockTimeUs += wakeLockTimeUs; + + // Add cost of holding a wake lock. + app.wakeLockPower = (app.wakeLockTime * + mPowerProfile.getAveragePower(PowerProfile.POWER_CPU_AWAKE)) / (60 * 60 * 1000); + if (DEBUG && app.wakeLockPower != 0) { + Log.d(TAG, "UID " + u.getUid() + ": wake " + + app.wakeLockTime + " power=" + makemAh(app.wakeLockPower)); + } + maxWakeLockPower = Math.max(maxWakeLockPower, app.wakeLockPower); - // Add cost of mobile traffic - final long mobileRx = u.getNetworkActivityPackets(NETWORK_MOBILE_RX_DATA, mStatsType); - final long mobileTx = u.getNetworkActivityPackets(NETWORK_MOBILE_TX_DATA, mStatsType); - final long mobileRxB = u.getNetworkActivityBytes(NETWORK_MOBILE_RX_DATA, mStatsType); - final long mobileTxB = u.getNetworkActivityBytes(NETWORK_MOBILE_TX_DATA, mStatsType); + // Add cost of mobile traffic. final long mobileActive = u.getMobileRadioActiveTime(mStatsType); + app.mobileRxPackets = u.getNetworkActivityPackets(NETWORK_MOBILE_RX_DATA, mStatsType); + app.mobileTxPackets = u.getNetworkActivityPackets(NETWORK_MOBILE_TX_DATA, mStatsType); + app.mobileActive = mobileActive / 1000; + app.mobileActiveCount = u.getMobileRadioActiveCount(mStatsType); + app.mobileRxBytes = u.getNetworkActivityBytes(NETWORK_MOBILE_RX_DATA, mStatsType); + app.mobileTxBytes = u.getNetworkActivityBytes(NETWORK_MOBILE_TX_DATA, mStatsType); + if (mobileActive > 0) { // We are tracking when the radio is up, so can use the active time to // determine power use. mAppMobileActive += mobileActive; - p = (mobilePowerPerMs * mobileActive) / 1000; + app.mobileRadioPower = (mobilePowerPerMs * mobileActive) / 1000; } else { // We are not tracking when the radio is up, so must approximate power use // based on the number of packets. - p = (mobileRx + mobileTx) * mobilePowerPerPacket; + app.mobileRadioPower = (app.mobileRxPackets + app.mobileTxPackets) + * mobilePowerPerPacket; } - if (DEBUG && p != 0) Log.d(TAG, "UID " + u.getUid() + ": mobile packets " - + (mobileRx+mobileTx) + " active time " + mobileActive - + " power=" + makemAh(p)); - power += p; + if (DEBUG && app.mobileRadioPower != 0) { + Log.d(TAG, "UID " + u.getUid() + ": mobile packets " + + (app.mobileRxPackets + app.mobileTxPackets) + + " active time " + mobileActive + + " power=" + makemAh(app.mobileRadioPower)); + } + maxMobileRadioPower = Math.max(maxMobileRadioPower, app.mobileRadioPower); // Add cost of wifi traffic - final long wifiRx = u.getNetworkActivityPackets(NETWORK_WIFI_RX_DATA, mStatsType); - final long wifiTx = u.getNetworkActivityPackets(NETWORK_WIFI_TX_DATA, mStatsType); - final long wifiRxB = u.getNetworkActivityBytes(NETWORK_WIFI_RX_DATA, mStatsType); - final long wifiTxB = u.getNetworkActivityBytes(NETWORK_WIFI_TX_DATA, mStatsType); - p = (wifiRx + wifiTx) * wifiPowerPerPacket; - if (DEBUG && p != 0) Log.d(TAG, "UID " + u.getUid() + ": wifi packets " - + (mobileRx+mobileTx) + " power=" + makemAh(p)); - power += p; + app.wifiRxPackets = u.getNetworkActivityPackets(NETWORK_WIFI_RX_DATA, mStatsType); + app.wifiTxPackets = u.getNetworkActivityPackets(NETWORK_WIFI_TX_DATA, mStatsType); + app.wifiRxBytes = u.getNetworkActivityBytes(NETWORK_WIFI_RX_DATA, mStatsType); + app.wifiTxBytes = u.getNetworkActivityBytes(NETWORK_WIFI_TX_DATA, mStatsType); + + final double wifiPacketPower = (app.wifiRxPackets + app.wifiTxPackets) + * wifiPowerPerPacket; + if (DEBUG && wifiPacketPower != 0) { + Log.d(TAG, "UID " + u.getUid() + ": wifi packets " + + (app.wifiRxPackets + app.wifiTxPackets) + + " power=" + makemAh(wifiPacketPower)); + } // Add cost of keeping WIFI running. - long wifiRunningTimeMs = u.getWifiRunningTime(mRawRealtime, which) / 1000; - mAppWifiRunning += wifiRunningTimeMs; - p = (wifiRunningTimeMs - * mPowerProfile.getAveragePower(PowerProfile.POWER_WIFI_ON)) / (60*60*1000); - if (DEBUG && p != 0) Log.d(TAG, "UID " + u.getUid() + ": wifi running " - + wifiRunningTimeMs + " power=" + makemAh(p)); - power += p; + app.wifiRunningTime = u.getWifiRunningTime(mRawRealtime, which) / 1000; + mAppWifiRunning += app.wifiRunningTime; + + final double wifiLockPower = (app.wifiRunningTime + * mPowerProfile.getAveragePower(PowerProfile.POWER_WIFI_ON)) / (60 * 60 * 1000); + if (DEBUG && wifiLockPower != 0) { + Log.d(TAG, "UID " + u.getUid() + ": wifi running " + + app.wifiRunningTime + " power=" + makemAh(wifiLockPower)); + } // Add cost of WIFI scans - long wifiScanTimeMs = u.getWifiScanTime(mRawRealtime, which) / 1000; - p = (wifiScanTimeMs - * mPowerProfile.getAveragePower(PowerProfile.POWER_WIFI_SCAN)) / (60*60*1000); - if (DEBUG) Log.d(TAG, "UID " + u.getUid() + ": wifi scan " + wifiScanTimeMs - + " power=" + makemAh(p)); - power += p; + final long wifiScanTimeMs = u.getWifiScanTime(mRawRealtime, which) / 1000; + final double wifiScanPower = (wifiScanTimeMs + * mPowerProfile.getAveragePower(PowerProfile.POWER_WIFI_SCAN)) + / (60 * 60 * 1000); + if (DEBUG && wifiScanPower != 0) { + Log.d(TAG, "UID " + u.getUid() + ": wifi scan " + wifiScanTimeMs + + " power=" + makemAh(wifiScanPower)); + } + + // Add cost of WIFI batch scans. + double wifiBatchScanPower = 0; for (int bin = 0; bin < BatteryStats.Uid.NUM_WIFI_BATCHED_SCAN_BINS; bin++) { - long batchScanTimeMs = u.getWifiBatchedScanTime(bin, mRawRealtime, which) / 1000; - p = ((batchScanTimeMs + final long batchScanTimeMs = + u.getWifiBatchedScanTime(bin, mRawRealtime, which) / 1000; + final double batchScanPower = ((batchScanTimeMs * mPowerProfile.getAveragePower(PowerProfile.POWER_WIFI_BATCHED_SCAN, bin)) - ) / (60*60*1000); - if (DEBUG && p != 0) Log.d(TAG, "UID " + u.getUid() + ": wifi batched scan # " + bin - + " time=" + batchScanTimeMs + " power=" + makemAh(p)); - power += p; + ) / (60 * 60 * 1000); + if (DEBUG && batchScanPower != 0) { + Log.d(TAG, "UID " + u.getUid() + ": wifi batched scan # " + bin + + " time=" + batchScanTimeMs + " power=" + makemAh(batchScanPower)); + } + wifiBatchScanPower += batchScanPower; } + // Add up all the WiFi costs. + app.wifiPower = wifiPacketPower + wifiLockPower + wifiScanPower + wifiBatchScanPower; + maxWifiPower = Math.max(maxWifiPower, app.wifiPower); + // Process Sensor usage - SparseArray<? extends BatteryStats.Uid.Sensor> sensorStats = u.getSensorStats(); - int NSE = sensorStats.size(); - for (int ise=0; ise<NSE; ise++) { - Uid.Sensor sensor = sensorStats.valueAt(ise); - int sensorHandle = sensorStats.keyAt(ise); - BatteryStats.Timer timer = sensor.getSensorTime(); - long sensorTime = timer.getTotalTimeLocked(mRawRealtime, which) / 1000; - double multiplier = 0; + final SparseArray<? extends BatteryStats.Uid.Sensor> sensorStats = u.getSensorStats(); + final int NSE = sensorStats.size(); + for (int ise = 0; ise < NSE; ise++) { + final Uid.Sensor sensor = sensorStats.valueAt(ise); + final int sensorHandle = sensorStats.keyAt(ise); + final BatteryStats.Timer timer = sensor.getSensorTime(); + final long sensorTime = timer.getTotalTimeLocked(mRawRealtime, which) / 1000; + double sensorPower = 0; switch (sensorHandle) { case Uid.Sensor.GPS: - multiplier = mPowerProfile.getAveragePower(PowerProfile.POWER_GPS_ON); - gpsTime = sensorTime; + app.gpsTime = sensorTime; + app.gpsPower = (app.gpsTime + * mPowerProfile.getAveragePower(PowerProfile.POWER_GPS_ON)) + / (60 * 60 * 1000); + sensorPower = app.gpsPower; + maxGpsPower = Math.max(maxGpsPower, app.gpsPower); break; default: List<Sensor> sensorList = sensorManager.getSensorList( android.hardware.Sensor.TYPE_ALL); for (android.hardware.Sensor s : sensorList) { if (s.getHandle() == sensorHandle) { - multiplier = s.getPower(); + sensorPower = (sensorTime * s.getPower()) / (60 * 60 * 1000); + app.sensorPower += sensorPower; break; } } } - p = (multiplier * sensorTime) / (60*60*1000); - if (DEBUG && p != 0) Log.d(TAG, "UID " + u.getUid() + ": sensor #" + sensorHandle - + " time=" + sensorTime + " power=" + makemAh(p)); - power += p; + if (DEBUG && sensorPower != 0) { + Log.d(TAG, "UID " + u.getUid() + ": sensor #" + sensorHandle + + " time=" + sensorTime + " power=" + makemAh(sensorPower)); + } } + maxSensorPower = Math.max(maxSensorPower, app.sensorPower); - if (DEBUG && power != 0) Log.d(TAG, String.format("UID %d: total power=%s", - u.getUid(), makemAh(power))); - - // Add the app to the list if it is consuming power - final int userId = UserHandle.getUserId(u.getUid()); - if (power != 0 || u.getUid() == 0) { - BatterySipper app = new BatterySipper(BatterySipper.DrainType.APP, u, - new double[] {power}); - app.cpuTime = cpuTime; - app.gpsTime = gpsTime; - app.wifiRunningTime = wifiRunningTimeMs; - app.cpuFgTime = cpuFgTime; - app.wakeLockTime = wakelockTime; - app.mobileRxPackets = mobileRx; - app.mobileTxPackets = mobileTx; - app.mobileActive = mobileActive / 1000; - app.mobileActiveCount = u.getMobileRadioActiveCount(mStatsType); - app.wifiRxPackets = wifiRx; - app.wifiTxPackets = wifiTx; - app.mobileRxBytes = mobileRxB; - app.mobileTxBytes = mobileTxB; - app.wifiRxBytes = wifiRxB; - app.wifiTxBytes = wifiTxB; - app.packageWithHighestDrain = packageWithHighestDrain; - if (u.getUid() == Process.WIFI_UID) { - mWifiSippers.add(app); - mWifiPower += power; - } else if (u.getUid() == Process.BLUETOOTH_UID) { - mBluetoothSippers.add(app); - mBluetoothPower += power; - } else if (!forAllUsers && asUsers.get(userId) == null - && UserHandle.getAppId(u.getUid()) >= Process.FIRST_APPLICATION_UID) { - List<BatterySipper> list = mUserSippers.get(userId); - if (list == null) { - list = new ArrayList<BatterySipper>(); - mUserSippers.put(userId, list); - } - list.add(app); - if (power != 0) { - Double userPower = mUserPower.get(userId); - if (userPower == null) { - userPower = power; - } else { - userPower += power; - } - mUserPower.put(userId, userPower); - } - } else { - mUsageList.add(app); - if (power > mMaxPower) mMaxPower = power; - if (power > mMaxRealPower) mMaxRealPower = power; - mComputedPower += power; + final double totalUnnormalizedPower = app.cpuPower + app.wifiPower + app.wakeLockPower + + app.mobileRadioPower + app.gpsPower + app.sensorPower; + if (DEBUG && totalUnnormalizedPower != 0) { + Log.d(TAG, String.format("UID %d: total power=%s", + u.getUid(), makemAh(totalUnnormalizedPower))); + } + + // Add the app to the list if it is consuming power. + if (totalUnnormalizedPower != 0 || u.getUid() == 0) { + appList.add(app); + } + } + + // Fetch real power consumption from hardware. + double actualTotalWifiPower = 0.0; + if (mStats.getWifiControllerActivity(BatteryStats.CONTROLLER_ENERGY, mStatsType) != 0) { + final double kDefaultVoltage = 3.36; + final long energy = mStats.getWifiControllerActivity( + BatteryStats.CONTROLLER_ENERGY, mStatsType); + final double voltage = mPowerProfile.getAveragePowerOrDefault( + PowerProfile.OPERATING_VOLTAGE_WIFI, kDefaultVoltage); + actualTotalWifiPower = energy / (voltage * 1000*60*60); + } + + final int appCount = appList.size(); + for (int i = 0; i < appCount; i++) { + // Normalize power where possible. + final BatterySipper app = appList.get(i); + if (actualTotalWifiPower != 0) { + app.wifiPower = (app.wifiPower / maxWifiPower) * actualTotalWifiPower; + } + + // Assign the final power consumption here. + final double power = app.wifiPower + app.cpuPower + app.wakeLockPower + + app.mobileRadioPower + app.gpsPower + app.sensorPower; + app.values[0] = app.value = power; + + // + // Add the app to the app list, WiFi, Bluetooth, etc, or into "Other Users" list. + // + + final int uid = app.getUid(); + final int userId = UserHandle.getUserId(uid); + if (uid == Process.WIFI_UID) { + mWifiSippers.add(app); + mWifiPower += power; + } else if (uid == Process.BLUETOOTH_UID) { + mBluetoothSippers.add(app); + mBluetoothPower += power; + } else if (!forAllUsers && asUsers.get(userId) == null + && UserHandle.getAppId(uid) >= Process.FIRST_APPLICATION_UID) { + // We are told to just report this user's apps as one large entry. + List<BatterySipper> list = mUserSippers.get(userId); + if (list == null) { + list = new ArrayList<>(); + mUserSippers.put(userId, list); } - if (u.getUid() == 0) { - osApp = app; + list.add(app); + + Double userPower = mUserPower.get(userId); + if (userPower == null) { + userPower = power; + } else { + userPower += power; } + mUserPower.put(userId, userPower); + } else { + mUsageList.add(app); + if (power > mMaxPower) mMaxPower = power; + if (power > mMaxRealPower) mMaxRealPower = power; + mComputedPower += power; + } + + if (uid == 0) { + osApp = app; } } @@ -641,7 +721,7 @@ public final class BatteryStatsHelper { // this remainder to the OS, if possible. if (osApp != null) { long wakeTimeMillis = mBatteryUptime / 1000; - wakeTimeMillis -= (appWakelockTimeUs / 1000) + wakeTimeMillis -= (totalAppWakelockTimeUs / 1000) + (mStats.getScreenOnTime(mRawRealtime, which) / 1000); if (wakeTimeMillis > 0) { double power = (wakeTimeMillis @@ -741,46 +821,11 @@ public final class BatteryStatsHelper { for (int i=0; i<from.size(); i++) { BatterySipper wbs = from.get(i); if (DEBUG) Log.d(TAG, tag + " adding sipper " + wbs + ": cpu=" + wbs.cpuTime); - bs.cpuTime += wbs.cpuTime; - bs.gpsTime += wbs.gpsTime; - bs.wifiRunningTime += wbs.wifiRunningTime; - bs.cpuFgTime += wbs.cpuFgTime; - bs.wakeLockTime += wbs.wakeLockTime; - bs.mobileRxPackets += wbs.mobileRxPackets; - bs.mobileTxPackets += wbs.mobileTxPackets; - bs.mobileActive += wbs.mobileActive; - bs.mobileActiveCount += wbs.mobileActiveCount; - bs.wifiRxPackets += wbs.wifiRxPackets; - bs.wifiTxPackets += wbs.wifiTxPackets; - bs.mobileRxBytes += wbs.mobileRxBytes; - bs.mobileTxBytes += wbs.mobileTxBytes; - bs.wifiRxBytes += wbs.wifiRxBytes; - bs.wifiTxBytes += wbs.wifiTxBytes; + bs.add(wbs); } bs.computeMobilemspp(); } - private void addWiFiUsage() { - long onTimeMs = mStats.getWifiOnTime(mRawRealtime, mStatsType) / 1000; - long runningTimeMs = mStats.getGlobalWifiRunningTime(mRawRealtime, mStatsType) / 1000; - if (DEBUG) Log.d(TAG, "WIFI runningTime=" + runningTimeMs - + " app runningTime=" + mAppWifiRunning); - runningTimeMs -= mAppWifiRunning; - if (runningTimeMs < 0) runningTimeMs = 0; - double wifiPower = (onTimeMs * 0 /* TODO */ - * mPowerProfile.getAveragePower(PowerProfile.POWER_WIFI_ON) - + runningTimeMs * mPowerProfile.getAveragePower(PowerProfile.POWER_WIFI_ON)) - / (60*60*1000); - if (DEBUG && wifiPower != 0) { - Log.d(TAG, "Wifi: time=" + runningTimeMs + " power=" + makemAh(wifiPower)); - } - if ((wifiPower+mWifiPower) != 0) { - BatterySipper bs = addEntry(BatterySipper.DrainType.WIFI, runningTimeMs, - wifiPower + mWifiPower); - aggregateSippers(bs, mWifiSippers, "WIFI"); - } - } - private void addIdleUsage() { long idleTimeMs = (mTypeBatteryRealtime - mStats.getScreenOnTime(mRawRealtime, mStatsType)) / 1000; @@ -794,24 +839,81 @@ public final class BatteryStatsHelper { } } - private void addBluetoothUsage() { - long btOnTimeMs = mStats.getBluetoothOnTime(mRawRealtime, mStatsType) / 1000; - double btPower = btOnTimeMs * mPowerProfile.getAveragePower(PowerProfile.POWER_BLUETOOTH_ON) - / (60*60*1000); - if (DEBUG && btPower != 0) { - Log.d(TAG, "Bluetooth: time=" + btOnTimeMs + " power=" + makemAh(btPower)); + /** + * We do per-app blaming of WiFi activity. If energy info is reported from the controller, + * then only the WiFi process gets blamed here since we normalize power calculations and + * assign all the power drain to apps. If energy info is not reported, we attribute the + * difference between total running time of WiFi for all apps and the actual running time + * of WiFi to the WiFi subsystem. + */ + private void addWiFiUsage() { + final long idleTimeMs = mStats.getWifiControllerActivity( + BatteryStats.CONTROLLER_IDLE_TIME, mStatsType); + final long txTimeMs = mStats.getWifiControllerActivity( + BatteryStats.CONTROLLER_TX_TIME, mStatsType); + final long rxTimeMs = mStats.getWifiControllerActivity( + BatteryStats.CONTROLLER_RX_TIME, mStatsType); + final long energy = mStats.getWifiControllerActivity( + BatteryStats.CONTROLLER_ENERGY, mStatsType); + final long totalTimeRunning = idleTimeMs + txTimeMs + rxTimeMs; + + double powerDrain = 0; + if (energy == 0 && totalTimeRunning > 0) { + // Energy is not reported, which means we may have left over power drain not attributed + // to any app. Assign this power to the WiFi app. + // TODO(adamlesinski): This mimics the old behavior. However, mAppWifiRunningTime + // is the accumulation of the time each app kept the WiFi chip on. Multiple apps + // can do this at the same time, so these times do not add up to the total time + // the WiFi chip was on. Consider normalizing the time spent running and calculating + // power from that? Normalizing the times will assign a weight to each app which + // should better represent power usage. + powerDrain = ((totalTimeRunning - mAppWifiRunning) + * mPowerProfile.getAveragePower(PowerProfile.POWER_WIFI_ON)) / (60*60*1000); } - int btPingCount = mStats.getBluetoothPingCount(); - double pingPower = (btPingCount - * mPowerProfile.getAveragePower(PowerProfile.POWER_BLUETOOTH_AT_CMD)) - / (60*60*1000); - if (DEBUG && pingPower != 0) { - Log.d(TAG, "Bluetooth ping: count=" + btPingCount + " power=" + makemAh(pingPower)); + + if (DEBUG && powerDrain != 0) { + Log.d(TAG, "Wifi active: time=" + (txTimeMs + rxTimeMs) + + " power=" + makemAh(powerDrain)); + } + + // TODO(adamlesinski): mWifiPower is already added as a BatterySipper... + // Are we double counting here? + final double power = mWifiPower + powerDrain; + if (power > 0) { + BatterySipper bs = addEntry(BatterySipper.DrainType.WIFI, totalTimeRunning, power); + aggregateSippers(bs, mWifiSippers, "WIFI"); } - btPower += pingPower; - if ((btPower+mBluetoothPower) != 0) { - BatterySipper bs = addEntry(BatterySipper.DrainType.BLUETOOTH, btOnTimeMs, - btPower + mBluetoothPower); + } + + /** + * Bluetooth usage is not attributed to any apps yet, so the entire blame goes to the + * Bluetooth Category. + */ + private void addBluetoothUsage() { + final double kDefaultVoltage = 3.36; + final long idleTimeMs = mStats.getBluetoothControllerActivity( + BatteryStats.CONTROLLER_IDLE_TIME, mStatsType); + final long txTimeMs = mStats.getBluetoothControllerActivity( + BatteryStats.CONTROLLER_TX_TIME, mStatsType); + final long rxTimeMs = mStats.getBluetoothControllerActivity( + BatteryStats.CONTROLLER_RX_TIME, mStatsType); + final long energy = mStats.getBluetoothControllerActivity( + BatteryStats.CONTROLLER_ENERGY, mStatsType); + final double voltage = mPowerProfile.getAveragePowerOrDefault( + PowerProfile.OPERATING_VOLTAGE_BLUETOOTH, kDefaultVoltage); + + // energy is measured in mA * V * ms, and we are interested in mAh + final double powerDrain = energy / (voltage * 60*60*1000); + + if (DEBUG && powerDrain != 0) { + Log.d(TAG, "Bluetooth active: time=" + (txTimeMs + rxTimeMs) + + " power=" + makemAh(powerDrain)); + } + + final long totalTime = idleTimeMs + txTimeMs + rxTimeMs; + final double power = mBluetoothPower + powerDrain; + if (power > 0) { + BatterySipper bs = addEntry(BatterySipper.DrainType.BLUETOOTH, totalTime, power); aggregateSippers(bs, mBluetoothSippers, "Bluetooth"); } } diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java index f6c5dc7a0592..f9b1ca11922c 100644 --- a/core/java/com/android/internal/os/BatteryStatsImpl.java +++ b/core/java/com/android/internal/os/BatteryStatsImpl.java @@ -20,11 +20,15 @@ import static android.net.NetworkStats.UID_ALL; import static com.android.server.NetworkManagementSocketTagger.PROP_QTAGUID_ENABLED; import android.app.ActivityManager; +import android.bluetooth.BluetoothActivityEnergyInfo; +import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothHeadset; import android.content.Context; import android.net.ConnectivityManager; import android.net.NetworkStats; +import android.net.wifi.IWifiManager; +import android.net.wifi.WifiActivityEnergyInfo; import android.net.wifi.WifiManager; import android.os.BadParcelableException; import android.os.BatteryManager; @@ -38,6 +42,8 @@ import android.os.Parcel; import android.os.ParcelFormatException; import android.os.Parcelable; import android.os.Process; +import android.os.RemoteException; +import android.os.ServiceManager; import android.os.SystemClock; import android.os.SystemProperties; import android.os.WorkSource; @@ -332,6 +338,12 @@ public final class BatteryStatsImpl extends BatteryStats { final LongSamplingCounter[] mNetworkPacketActivityCounters = new LongSamplingCounter[NUM_NETWORK_ACTIVITY_TYPES]; + final LongSamplingCounter[] mBluetoothActivityCounters = + new LongSamplingCounter[NUM_CONTROLLER_ACTIVITY_TYPES]; + + final LongSamplingCounter[] mWifiActivityCounters = + new LongSamplingCounter[NUM_CONTROLLER_ACTIVITY_TYPES]; + boolean mWifiOn; StopwatchTimer mWifiOnTimer; @@ -4307,6 +4319,20 @@ public final class BatteryStatsImpl extends BatteryStats { return mBluetoothStateTimer[bluetoothState].getCountLocked(which); } + @Override public long getBluetoothControllerActivity(int type, int which) { + if (type >= 0 && type < mBluetoothActivityCounters.length) { + return mBluetoothActivityCounters[type].getCountLocked(which); + } + return 0; + } + + @Override public long getWifiControllerActivity(int type, int which) { + if (type >= 0 && type < mWifiActivityCounters.length) { + return mWifiActivityCounters[type].getCountLocked(which); + } + return 0; + } + @Override public long getFlashlightOnTime(long elapsedRealtimeUs, int which) { return mFlashlightOnTimer.getTotalTimeLocked(elapsedRealtimeUs, which); } @@ -4749,6 +4775,14 @@ public final class BatteryStatsImpl extends BatteryStats { } @Override + public int getWifiScanCount(int which) { + if (mWifiScanTimer == null) { + return 0; + } + return mWifiScanTimer.getCountLocked(which); + } + + @Override public long getWifiBatchedScanTime(int csphBin, long elapsedRealtimeUs, int which) { if (csphBin < 0 || csphBin >= NUM_WIFI_BATCHED_SCAN_BINS) return 0; if (mWifiBatchedScanTimer[csphBin] == null) { @@ -4758,6 +4792,15 @@ public final class BatteryStatsImpl extends BatteryStats { } @Override + public int getWifiBatchedScanCount(int csphBin, int which) { + if (csphBin < 0 || csphBin >= NUM_WIFI_BATCHED_SCAN_BINS) return 0; + if (mWifiBatchedScanTimer[csphBin] == null) { + return 0; + } + return mWifiBatchedScanTimer[csphBin].getCountLocked(which); + } + + @Override public long getWifiMulticastTime(long elapsedRealtimeUs, int which) { if (mWifiMulticastTimer == null) { return 0; @@ -5601,17 +5644,17 @@ public final class BatteryStatsImpl extends BatteryStats { boolean mActive = true; /** - * Total time (in 1/100 sec) spent executing in user code. + * Total time (in ms) spent executing in user code. */ long mUserTime; /** - * Total time (in 1/100 sec) spent executing in kernel code. + * Total time (in ms) spent executing in kernel code. */ long mSystemTime; /** - * Amount of time the process was running in the foreground. + * Amount of time (in ms) the process was running in the foreground. */ long mForegroundTime; @@ -6635,6 +6678,10 @@ public final class BatteryStatsImpl extends BatteryStats { mNetworkByteActivityCounters[i] = new LongSamplingCounter(mOnBatteryTimeBase); mNetworkPacketActivityCounters[i] = new LongSamplingCounter(mOnBatteryTimeBase); } + for (int i = 0; i < NUM_CONTROLLER_ACTIVITY_TYPES; i++) { + mBluetoothActivityCounters[i] = new LongSamplingCounter(mOnBatteryTimeBase); + mWifiActivityCounters[i] = new LongSamplingCounter(mOnBatteryTimeBase); + } mMobileRadioActiveTimer = new StopwatchTimer(null, -400, null, mOnBatteryTimeBase); mMobileRadioActivePerAppTimer = new StopwatchTimer(null, -401, null, mOnBatteryTimeBase); mMobileRadioActiveAdjustedTime = new LongSamplingCounter(mOnBatteryTimeBase); @@ -7222,6 +7269,10 @@ public final class BatteryStatsImpl extends BatteryStats { for (int i=0; i< NUM_BLUETOOTH_STATES; i++) { mBluetoothStateTimer[i].reset(false); } + for (int i=0; i< NUM_CONTROLLER_ACTIVITY_TYPES; i++) { + mBluetoothActivityCounters[i].reset(false); + mWifiActivityCounters[i].reset(false); + } mNumConnectivityChange = mLoadedNumConnectivityChange = mUnpluggedNumConnectivityChange = 0; for (int i=0; i<mUidStats.size(); i++) { @@ -7308,6 +7359,9 @@ public final class BatteryStatsImpl extends BatteryStats { public void pullPendingStateUpdatesLocked() { updateKernelWakelocksLocked(); updateNetworkActivityLocked(NET_UPDATE_ALL, SystemClock.elapsedRealtime()); + // TODO(adamlesinski): enable when bluedroid stops deadlocking. b/19248786 + // updateBluetoothControllerActivityLocked(); + updateWifiControllerActivityLocked(); if (mOnBatteryInternal) { final boolean screenOn = mScreenState == Display.STATE_ON; updateDischargeScreenLevelsLocked(screenOn, screenOn); @@ -7744,6 +7798,65 @@ public final class BatteryStatsImpl extends BatteryStats { } } + private void updateBluetoothControllerActivityLocked() { + BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); + if (adapter == null) { + return; + } + + // We read the data even if we are not on battery. Each read clears + // the previous data, so we must always read to make sure the + // data is for the current interval. + BluetoothActivityEnergyInfo info = adapter.getControllerActivityEnergyInfo( + BluetoothAdapter.ACTIVITY_ENERGY_INFO_REFRESHED); + if (info == null || !info.isValid() || !mOnBatteryInternal) { + // Bad info or we are not on battery. + return; + } + + mBluetoothActivityCounters[CONTROLLER_RX_TIME].addCountLocked( + info.getControllerRxTimeMillis()); + mBluetoothActivityCounters[CONTROLLER_TX_TIME].addCountLocked( + info.getControllerTxTimeMillis()); + mBluetoothActivityCounters[CONTROLLER_IDLE_TIME].addCountLocked( + info.getControllerIdleTimeMillis()); + mBluetoothActivityCounters[CONTROLLER_ENERGY].addCountLocked( + info.getControllerEnergyUsed()); + } + + private void updateWifiControllerActivityLocked() { + IWifiManager wifiManager = IWifiManager.Stub.asInterface( + ServiceManager.getService(Context.WIFI_SERVICE)); + if (wifiManager == null) { + return; + } + + WifiActivityEnergyInfo info; + try { + // We read the data even if we are not on battery. Each read clears + // the previous data, so we must always read to make sure the + // data is for the current interval. + info = wifiManager.reportActivityInfo(); + } catch (RemoteException e) { + // Nothing to report, WiFi is dead. + return; + } + + if (info == null || !info.isValid() || !mOnBatteryInternal) { + // Bad info or we are not on battery. + return; + } + + mWifiActivityCounters[CONTROLLER_RX_TIME].addCountLocked( + info.getControllerRxTimeMillis()); + mWifiActivityCounters[CONTROLLER_TX_TIME].addCountLocked( + info.getControllerTxTimeMillis()); + mWifiActivityCounters[CONTROLLER_IDLE_TIME].addCountLocked( + info.getControllerIdleTimeMillis()); + mWifiActivityCounters[CONTROLLER_ENERGY].addCountLocked( + info.getControllerEnergyUsed()); + } + public long getAwakeTimeBattery() { return computeBatteryUptime(getBatteryUptimeLocked(), STATS_CURRENT); } @@ -8458,6 +8571,15 @@ public final class BatteryStatsImpl extends BatteryStats { for (int i=0; i< NUM_BLUETOOTH_STATES; i++) { mBluetoothStateTimer[i].readSummaryFromParcelLocked(in); } + + for (int i = 0; i < NUM_CONTROLLER_ACTIVITY_TYPES; i++) { + mBluetoothActivityCounters[i].readSummaryFromParcelLocked(in); + } + + for (int i = 0; i < NUM_CONTROLLER_ACTIVITY_TYPES; i++) { + mWifiActivityCounters[i].readSummaryFromParcelLocked(in); + } + mNumConnectivityChange = mLoadedNumConnectivityChange = in.readInt(); mFlashlightOn = false; mFlashlightOnTimer.readSummaryFromParcelLocked(in); @@ -8746,6 +8868,12 @@ public final class BatteryStatsImpl extends BatteryStats { for (int i=0; i< NUM_BLUETOOTH_STATES; i++) { mBluetoothStateTimer[i].writeSummaryFromParcelLocked(out, NOWREAL_SYS); } + for (int i=0; i< NUM_CONTROLLER_ACTIVITY_TYPES; i++) { + mBluetoothActivityCounters[i].writeSummaryFromParcelLocked(out); + } + for (int i=0; i< NUM_CONTROLLER_ACTIVITY_TYPES; i++) { + mWifiActivityCounters[i].writeSummaryFromParcelLocked(out); + } out.writeInt(mNumConnectivityChange); mFlashlightOnTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS); @@ -9050,6 +9178,15 @@ public final class BatteryStatsImpl extends BatteryStats { mBluetoothStateTimer[i] = new StopwatchTimer(null, -500-i, null, mOnBatteryTimeBase, in); } + + for (int i = 0; i < NUM_CONTROLLER_ACTIVITY_TYPES; i++) { + mBluetoothActivityCounters[i] = new LongSamplingCounter(mOnBatteryTimeBase, in); + } + + for (int i = 0; i < NUM_CONTROLLER_ACTIVITY_TYPES; i++) { + mWifiActivityCounters[i] = new LongSamplingCounter(mOnBatteryTimeBase, in); + } + mNumConnectivityChange = in.readInt(); mLoadedNumConnectivityChange = in.readInt(); mUnpluggedNumConnectivityChange = in.readInt(); @@ -9195,6 +9332,12 @@ public final class BatteryStatsImpl extends BatteryStats { for (int i=0; i< NUM_BLUETOOTH_STATES; i++) { mBluetoothStateTimer[i].writeToParcel(out, uSecRealtime); } + for (int i=0; i< NUM_CONTROLLER_ACTIVITY_TYPES; i++) { + mBluetoothActivityCounters[i].writeToParcel(out); + } + for (int i=0; i< NUM_CONTROLLER_ACTIVITY_TYPES; i++) { + mWifiActivityCounters[i].writeToParcel(out); + } out.writeInt(mNumConnectivityChange); out.writeInt(mLoadedNumConnectivityChange); out.writeInt(mUnpluggedNumConnectivityChange); diff --git a/core/java/com/android/internal/os/PowerProfile.java b/core/java/com/android/internal/os/PowerProfile.java index b3bafa1007bd..944eb5aca9e3 100644 --- a/core/java/com/android/internal/os/PowerProfile.java +++ b/core/java/com/android/internal/os/PowerProfile.java @@ -76,6 +76,11 @@ public class PowerProfile { public static final String POWER_WIFI_ACTIVE = "wifi.active"; /** + * Operating voltage of the WiFi controller. + */ + public static final String OPERATING_VOLTAGE_WIFI = "wifi.voltage"; + + /** * Power consumption when GPS is on. */ public static final String POWER_GPS_ON = "gps.on"; @@ -96,6 +101,11 @@ public class PowerProfile { public static final String POWER_BLUETOOTH_AT_CMD = "bluetooth.at"; /** + * Operating voltage of the Bluetooth controller. + */ + public static final String OPERATING_VOLTAGE_BLUETOOTH = "bluetooth.voltage"; + + /** * Power consumption when screen is on, not including the backlight power. */ public static final String POWER_SCREEN_ON = "screen.on"; @@ -224,11 +234,13 @@ public class PowerProfile { } /** - * Returns the average current in mA consumed by the subsystem + * Returns the average current in mA consumed by the subsystem, or the given + * default value if the subsystem has no recorded value. * @param type the subsystem type + * @param defaultValue the value to return if the subsystem has no recorded value. * @return the average current in milliAmps. */ - public double getAveragePower(String type) { + public double getAveragePowerOrDefault(String type, double defaultValue) { if (sPowerMap.containsKey(type)) { Object data = sPowerMap.get(type); if (data instanceof Double[]) { @@ -237,9 +249,18 @@ public class PowerProfile { return (Double) sPowerMap.get(type); } } else { - return 0; + return defaultValue; } } + + /** + * Returns the average current in mA consumed by the subsystem + * @param type the subsystem type + * @return the average current in milliAmps. + */ + public double getAveragePower(String type) { + return getAveragePowerOrDefault(type, 0); + } /** * Returns the average current in mA consumed by the subsystem for the given level. diff --git a/core/java/com/android/internal/os/ProcessCpuTracker.java b/core/java/com/android/internal/os/ProcessCpuTracker.java index 501e0ec9c8ed..29830473255f 100644 --- a/core/java/com/android/internal/os/ProcessCpuTracker.java +++ b/core/java/com/android/internal/os/ProcessCpuTracker.java @@ -22,11 +22,13 @@ import android.os.FileUtils; import android.os.Process; import android.os.StrictMode; import android.os.SystemClock; +import android.system.OsConstants; import android.util.Slog; import com.android.internal.util.FastPrintWriter; import libcore.io.IoUtils; +import libcore.io.Libcore; import java.io.File; import java.io.FileInputStream; @@ -130,6 +132,9 @@ public class ProcessCpuTracker { private final boolean mIncludeThreads; + // How long a CPU jiffy is in milliseconds. + private final long mJiffyMillis; + private float mLoad1 = 0; private float mLoad5 = 0; private float mLoad15 = 0; @@ -269,6 +274,8 @@ public class ProcessCpuTracker { public ProcessCpuTracker(boolean includeThreads) { mIncludeThreads = includeThreads; + long jiffyHz = Libcore.os.sysconf(OsConstants._SC_CLK_TCK); + mJiffyMillis = 1000/jiffyHz; } public void onLoadChanged(float load1, float load5, float load15) { @@ -294,15 +301,15 @@ public class ProcessCpuTracker { if (Process.readProcFile("/proc/stat", SYSTEM_CPU_FORMAT, null, sysCpu, null)) { // Total user time is user + nice time. - final long usertime = sysCpu[0]+sysCpu[1]; + final long usertime = (sysCpu[0]+sysCpu[1]) * mJiffyMillis; // Total system time is simply system time. - final long systemtime = sysCpu[2]; + final long systemtime = sysCpu[2] * mJiffyMillis; // Total idle time is simply idle time. - final long idletime = sysCpu[3]; + final long idletime = sysCpu[3] * mJiffyMillis; // Total irq time is iowait + irq + softirq time. - final long iowaittime = sysCpu[4]; - final long irqtime = sysCpu[5]; - final long softirqtime = sysCpu[6]; + final long iowaittime = sysCpu[4] * mJiffyMillis; + final long irqtime = sysCpu[5] * mJiffyMillis; + final long softirqtime = sysCpu[6] * mJiffyMillis; // This code is trying to avoid issues with idle time going backwards, // but currently it gets into situations where it triggers most of the time. :( @@ -318,10 +325,11 @@ public class ProcessCpuTracker { mRelStatsAreGood = true; if (DEBUG) { - Slog.i("Load", "Total U:" + sysCpu[0] + " N:" + sysCpu[1] - + " S:" + sysCpu[2] + " I:" + sysCpu[3] - + " W:" + sysCpu[4] + " Q:" + sysCpu[5] - + " O:" + sysCpu[6]); + Slog.i("Load", "Total U:" + (sysCpu[0]*mJiffyMillis) + + " N:" + (sysCpu[1]*mJiffyMillis) + + " S:" + (sysCpu[2]*mJiffyMillis) + " I:" + (sysCpu[3]*mJiffyMillis) + + " W:" + (sysCpu[4]*mJiffyMillis) + " Q:" + (sysCpu[5]*mJiffyMillis) + + " O:" + (sysCpu[6]*mJiffyMillis)); Slog.i("Load", "Rel U:" + mRelUserTime + " S:" + mRelSystemTime + " I:" + mRelIdleTime + " Q:" + mRelIrqTime); } @@ -414,8 +422,8 @@ public class ProcessCpuTracker { final long minfaults = procStats[PROCESS_STAT_MINOR_FAULTS]; final long majfaults = procStats[PROCESS_STAT_MAJOR_FAULTS]; - final long utime = procStats[PROCESS_STAT_UTIME]; - final long stime = procStats[PROCESS_STAT_STIME]; + final long utime = procStats[PROCESS_STAT_UTIME] * mJiffyMillis; + final long stime = procStats[PROCESS_STAT_STIME] * mJiffyMillis; if (utime == st.base_utime && stime == st.base_stime) { st.rel_utime = 0; @@ -489,8 +497,8 @@ public class ProcessCpuTracker { st.baseName = procStatsString[0]; st.base_minfaults = procStats[PROCESS_FULL_STAT_MINOR_FAULTS]; st.base_majfaults = procStats[PROCESS_FULL_STAT_MAJOR_FAULTS]; - st.base_utime = procStats[PROCESS_FULL_STAT_UTIME]; - st.base_stime = procStats[PROCESS_FULL_STAT_STIME]; + st.base_utime = procStats[PROCESS_FULL_STAT_UTIME] * mJiffyMillis; + st.base_stime = procStats[PROCESS_FULL_STAT_STIME] * mJiffyMillis; } else { Slog.i(TAG, "Skipping kernel process pid " + pid + " name " + procStatsString[0]); @@ -576,7 +584,7 @@ public class ProcessCpuTracker { null, statsData, null)) { long time = statsData[PROCESS_STAT_UTIME] + statsData[PROCESS_STAT_STIME]; - return time; + return time * mJiffyMillis; } return 0; } @@ -777,7 +785,7 @@ public class ProcessCpuTracker { for (int i=0; i<N; i++) { Stats st = mWorkingProcs.get(i); printProcessCPU(pw, st.added ? " +" : (st.removed ? " -": " "), - st.pid, st.name, (int)(st.rel_uptime+5)/10, + st.pid, st.name, (int)st.rel_uptime, st.rel_utime, st.rel_stime, 0, 0, 0, st.rel_minfaults, st.rel_majfaults); if (!st.removed && st.workingThreads != null) { int M = st.workingThreads.size(); @@ -785,7 +793,7 @@ public class ProcessCpuTracker { Stats tst = st.workingThreads.get(j); printProcessCPU(pw, tst.added ? " +" : (tst.removed ? " -": " "), - tst.pid, tst.name, (int)(st.rel_uptime+5)/10, + tst.pid, tst.name, (int)st.rel_uptime, tst.rel_utime, tst.rel_stime, 0, 0, 0, 0, 0); } } diff --git a/core/java/com/android/internal/transition/EpicenterClipReveal.java b/core/java/com/android/internal/transition/EpicenterClipReveal.java index d8a7f16b607a..abb50c1df692 100644 --- a/core/java/com/android/internal/transition/EpicenterClipReveal.java +++ b/core/java/com/android/internal/transition/EpicenterClipReveal.java @@ -16,6 +16,7 @@ package com.android.internal.transition; import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; import android.animation.ObjectAnimator; import android.animation.RectEvaluator; import android.content.Context; @@ -75,13 +76,13 @@ public class EpicenterClipReveal extends Visibility { return null; } - final Rect start = getEpicenter(); final Rect end = getBestRect(endValues); + final Rect start = getEpicenterOrCenter(end); // Prepare the view. view.setClipBounds(start); - return createRectAnimator(view, start, end); + return createRectAnimator(view, start, end, endValues); } @Override @@ -92,12 +93,23 @@ public class EpicenterClipReveal extends Visibility { } final Rect start = getBestRect(startValues); - final Rect end = getEpicenter(); + final Rect end = getEpicenterOrCenter(start); // Prepare the view. view.setClipBounds(start); - return createRectAnimator(view, start, end); + return createRectAnimator(view, start, end, endValues); + } + + private Rect getEpicenterOrCenter(Rect bestRect) { + final Rect epicenter = getEpicenter(); + if (epicenter != null) { + return epicenter; + } + + int centerX = bestRect.centerX(); + int centerY = bestRect.centerY(); + return new Rect(centerX, centerY, centerX, centerY); } private Rect getBestRect(TransitionValues values) { @@ -108,8 +120,17 @@ public class EpicenterClipReveal extends Visibility { return clipRect; } - private Animator createRectAnimator(View view, Rect start, Rect end) { + private Animator createRectAnimator(final View view, Rect start, Rect end, + TransitionValues endValues) { + final Rect terminalClip = (Rect) endValues.values.get(PROPNAME_CLIP); final RectEvaluator evaluator = new RectEvaluator(new Rect()); - return ObjectAnimator.ofObject(view, "clipBounds", evaluator, start, end); + ObjectAnimator anim = ObjectAnimator.ofObject(view, "clipBounds", evaluator, start, end); + anim.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + view.setClipBounds(terminalClip); + } + }); + return anim; } } diff --git a/core/java/com/android/internal/widget/PagerAdapter.java b/core/java/com/android/internal/widget/PagerAdapter.java new file mode 100644 index 000000000000..910a720eda03 --- /dev/null +++ b/core/java/com/android/internal/widget/PagerAdapter.java @@ -0,0 +1,320 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.widget; + +import android.database.DataSetObservable; +import android.database.DataSetObserver; +import android.os.Parcelable; +import android.view.View; +import android.view.ViewGroup; + +/** + * Base class providing the adapter to populate pages inside of + * a {@link android.support.v4.view.ViewPager}. You will most likely want to use a more + * specific implementation of this, such as + * {@link android.support.v4.app.FragmentPagerAdapter} or + * {@link android.support.v4.app.FragmentStatePagerAdapter}. + * + * <p>When you implement a PagerAdapter, you must override the following methods + * at minimum:</p> + * <ul> + * <li>{@link #instantiateItem(android.view.ViewGroup, int)}</li> + * <li>{@link #destroyItem(android.view.ViewGroup, int, Object)}</li> + * <li>{@link #getCount()}</li> + * <li>{@link #isViewFromObject(android.view.View, Object)}</li> + * </ul> + * + * <p>PagerAdapter is more general than the adapters used for + * {@link android.widget.AdapterView AdapterViews}. Instead of providing a + * View recycling mechanism directly ViewPager uses callbacks to indicate the + * steps taken during an update. A PagerAdapter may implement a form of View + * recycling if desired or use a more sophisticated method of managing page + * Views such as Fragment transactions where each page is represented by its + * own Fragment.</p> + * + * <p>ViewPager associates each page with a key Object instead of working with + * Views directly. This key is used to track and uniquely identify a given page + * independent of its position in the adapter. A call to the PagerAdapter method + * {@link #startUpdate(android.view.ViewGroup)} indicates that the contents of the ViewPager + * are about to change. One or more calls to {@link #instantiateItem(android.view.ViewGroup, int)} + * and/or {@link #destroyItem(android.view.ViewGroup, int, Object)} will follow, and the end + * of an update will be signaled by a call to {@link #finishUpdate(android.view.ViewGroup)}. + * By the time {@link #finishUpdate(android.view.ViewGroup) finishUpdate} returns the views + * associated with the key objects returned by + * {@link #instantiateItem(android.view.ViewGroup, int) instantiateItem} should be added to + * the parent ViewGroup passed to these methods and the views associated with + * the keys passed to {@link #destroyItem(android.view.ViewGroup, int, Object) destroyItem} + * should be removed. The method {@link #isViewFromObject(android.view.View, Object)} identifies + * whether a page View is associated with a given key object.</p> + * + * <p>A very simple PagerAdapter may choose to use the page Views themselves + * as key objects, returning them from {@link #instantiateItem(android.view.ViewGroup, int)} + * after creation and adding them to the parent ViewGroup. A matching + * {@link #destroyItem(android.view.ViewGroup, int, Object)} implementation would remove the + * View from the parent ViewGroup and {@link #isViewFromObject(android.view.View, Object)} + * could be implemented as <code>return view == object;</code>.</p> + * + * <p>PagerAdapter supports data set changes. Data set changes must occur on the + * main thread and must end with a call to {@link #notifyDataSetChanged()} similar + * to AdapterView adapters derived from {@link android.widget.BaseAdapter}. A data + * set change may involve pages being added, removed, or changing position. The + * ViewPager will keep the current page active provided the adapter implements + * the method {@link #getItemPosition(Object)}.</p> + */ +public abstract class PagerAdapter { + private DataSetObservable mObservable = new DataSetObservable(); + + public static final int POSITION_UNCHANGED = -1; + public static final int POSITION_NONE = -2; + + /** + * Return the number of views available. + */ + public abstract int getCount(); + + /** + * Called when a change in the shown pages is going to start being made. + * @param container The containing View which is displaying this adapter's + * page views. + */ + public void startUpdate(ViewGroup container) { + startUpdate((View) container); + } + + /** + * Create the page for the given position. The adapter is responsible + * for adding the view to the container given here, although it only + * must ensure this is done by the time it returns from + * {@link #finishUpdate(android.view.ViewGroup)}. + * + * @param container The containing View in which the page will be shown. + * @param position The page position to be instantiated. + * @return Returns an Object representing the new page. This does not + * need to be a View, but can be some other container of the page. + */ + public Object instantiateItem(ViewGroup container, int position) { + return instantiateItem((View) container, position); + } + + /** + * Remove a page for the given position. The adapter is responsible + * for removing the view from its container, although it only must ensure + * this is done by the time it returns from {@link #finishUpdate(android.view.ViewGroup)}. + * + * @param container The containing View from which the page will be removed. + * @param position The page position to be removed. + * @param object The same object that was returned by + * {@link #instantiateItem(android.view.View, int)}. + */ + public void destroyItem(ViewGroup container, int position, Object object) { + destroyItem((View) container, position, object); + } + + /** + * Called to inform the adapter of which item is currently considered to + * be the "primary", that is the one show to the user as the current page. + * + * @param container The containing View from which the page will be removed. + * @param position The page position that is now the primary. + * @param object The same object that was returned by + * {@link #instantiateItem(android.view.View, int)}. + */ + public void setPrimaryItem(ViewGroup container, int position, Object object) { + setPrimaryItem((View) container, position, object); + } + + /** + * Called when the a change in the shown pages has been completed. At this + * point you must ensure that all of the pages have actually been added or + * removed from the container as appropriate. + * @param container The containing View which is displaying this adapter's + * page views. + */ + public void finishUpdate(ViewGroup container) { + finishUpdate((View) container); + } + + /** + * Called when a change in the shown pages is going to start being made. + * @param container The containing View which is displaying this adapter's + * page views. + * + * @deprecated Use {@link #startUpdate(android.view.ViewGroup)} + */ + public void startUpdate(View container) { + } + + /** + * Create the page for the given position. The adapter is responsible + * for adding the view to the container given here, although it only + * must ensure this is done by the time it returns from + * {@link #finishUpdate(android.view.ViewGroup)}. + * + * @param container The containing View in which the page will be shown. + * @param position The page position to be instantiated. + * @return Returns an Object representing the new page. This does not + * need to be a View, but can be some other container of the page. + * + * @deprecated Use {@link #instantiateItem(android.view.ViewGroup, int)} + */ + public Object instantiateItem(View container, int position) { + throw new UnsupportedOperationException( + "Required method instantiateItem was not overridden"); + } + + /** + * Remove a page for the given position. The adapter is responsible + * for removing the view from its container, although it only must ensure + * this is done by the time it returns from {@link #finishUpdate(android.view.View)}. + * + * @param container The containing View from which the page will be removed. + * @param position The page position to be removed. + * @param object The same object that was returned by + * {@link #instantiateItem(android.view.View, int)}. + * + * @deprecated Use {@link #destroyItem(android.view.ViewGroup, int, Object)} + */ + public void destroyItem(View container, int position, Object object) { + throw new UnsupportedOperationException("Required method destroyItem was not overridden"); + } + + /** + * Called to inform the adapter of which item is currently considered to + * be the "primary", that is the one show to the user as the current page. + * + * @param container The containing View from which the page will be removed. + * @param position The page position that is now the primary. + * @param object The same object that was returned by + * {@link #instantiateItem(android.view.View, int)}. + * + * @deprecated Use {@link #setPrimaryItem(android.view.ViewGroup, int, Object)} + */ + public void setPrimaryItem(View container, int position, Object object) { + } + + /** + * Called when the a change in the shown pages has been completed. At this + * point you must ensure that all of the pages have actually been added or + * removed from the container as appropriate. + * @param container The containing View which is displaying this adapter's + * page views. + * + * @deprecated Use {@link #finishUpdate(android.view.ViewGroup)} + */ + public void finishUpdate(View container) { + } + + /** + * Determines whether a page View is associated with a specific key object + * as returned by {@link #instantiateItem(android.view.ViewGroup, int)}. This method is + * required for a PagerAdapter to function properly. + * + * @param view Page View to check for association with <code>object</code> + * @param object Object to check for association with <code>view</code> + * @return true if <code>view</code> is associated with the key object <code>object</code> + */ + public abstract boolean isViewFromObject(View view, Object object); + + /** + * Save any instance state associated with this adapter and its pages that should be + * restored if the current UI state needs to be reconstructed. + * + * @return Saved state for this adapter + */ + public Parcelable saveState() { + return null; + } + + /** + * Restore any instance state associated with this adapter and its pages + * that was previously saved by {@link #saveState()}. + * + * @param state State previously saved by a call to {@link #saveState()} + * @param loader A ClassLoader that should be used to instantiate any restored objects + */ + public void restoreState(Parcelable state, ClassLoader loader) { + } + + /** + * Called when the host view is attempting to determine if an item's position + * has changed. Returns {@link #POSITION_UNCHANGED} if the position of the given + * item has not changed or {@link #POSITION_NONE} if the item is no longer present + * in the adapter. + * + * <p>The default implementation assumes that items will never + * change position and always returns {@link #POSITION_UNCHANGED}. + * + * @param object Object representing an item, previously returned by a call to + * {@link #instantiateItem(android.view.View, int)}. + * @return object's new position index from [0, {@link #getCount()}), + * {@link #POSITION_UNCHANGED} if the object's position has not changed, + * or {@link #POSITION_NONE} if the item is no longer present. + */ + public int getItemPosition(Object object) { + return POSITION_UNCHANGED; + } + + /** + * This method should be called by the application if the data backing this adapter has changed + * and associated views should update. + */ + public void notifyDataSetChanged() { + mObservable.notifyChanged(); + } + + /** + * Register an observer to receive callbacks related to the adapter's data changing. + * + * @param observer The {@link android.database.DataSetObserver} which will receive callbacks. + */ + public void registerDataSetObserver(DataSetObserver observer) { + mObservable.registerObserver(observer); + } + + /** + * Unregister an observer from callbacks related to the adapter's data changing. + * + * @param observer The {@link android.database.DataSetObserver} which will be unregistered. + */ + public void unregisterDataSetObserver(DataSetObserver observer) { + mObservable.unregisterObserver(observer); + } + + /** + * This method may be called by the ViewPager to obtain a title string + * to describe the specified page. This method may return null + * indicating no title for this page. The default implementation returns + * null. + * + * @param position The position of the title requested + * @return A title for the requested page + */ + public CharSequence getPageTitle(int position) { + return null; + } + + /** + * Returns the proportional width of a given page as a percentage of the + * ViewPager's measured width from (0.f-1.f] + * + * @param position The position of the page requested + * @return Proportional width for the given page position + */ + public float getPageWidth(int position) { + return 1.f; + } +} diff --git a/core/java/com/android/internal/widget/ViewPager.java b/core/java/com/android/internal/widget/ViewPager.java new file mode 100644 index 000000000000..f916e6f784e7 --- /dev/null +++ b/core/java/com/android/internal/widget/ViewPager.java @@ -0,0 +1,2866 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.widget; + +import android.annotation.DrawableRes; +import android.content.Context; +import android.content.res.Resources; +import android.content.res.TypedArray; +import android.database.DataSetObserver; +import android.graphics.Canvas; +import android.graphics.Rect; +import android.graphics.drawable.Drawable; +import android.os.Bundle; +import android.os.Parcel; +import android.os.Parcelable; +import android.os.SystemClock; +import android.util.AttributeSet; +import android.util.Log; +import android.view.FocusFinder; +import android.view.Gravity; +import android.view.KeyEvent; +import android.view.MotionEvent; +import android.view.SoundEffectConstants; +import android.view.VelocityTracker; +import android.view.View; +import android.view.ViewConfiguration; +import android.view.ViewGroup; +import android.view.ViewParent; +import android.view.accessibility.AccessibilityEvent; +import android.view.accessibility.AccessibilityNodeInfo; +import android.view.accessibility.AccessibilityRecord; +import android.view.animation.Interpolator; +import android.widget.EdgeEffect; +import android.widget.Scroller; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; + +/** + * Layout manager that allows the user to flip left and right + * through pages of data. You supply an implementation of a + * {@link android.support.v4.view.PagerAdapter} to generate the pages that the view shows. + * + * <p>Note this class is currently under early design and + * development. The API will likely change in later updates of + * the compatibility library, requiring changes to the source code + * of apps when they are compiled against the newer version.</p> + * + * <p>ViewPager is most often used in conjunction with {@link android.app.Fragment}, + * which is a convenient way to supply and manage the lifecycle of each page. + * There are standard adapters implemented for using fragments with the ViewPager, + * which cover the most common use cases. These are + * {@link android.support.v4.app.FragmentPagerAdapter} and + * {@link android.support.v4.app.FragmentStatePagerAdapter}; each of these + * classes have simple code showing how to build a full user interface + * with them. + * + * <p>For more information about how to use ViewPager, read <a + * href="{@docRoot}training/implementing-navigation/lateral.html">Creating Swipe Views with + * Tabs</a>.</p> + * + * <p>Below is a more complicated example of ViewPager, using it in conjunction + * with {@link android.app.ActionBar} tabs. You can find other examples of using + * ViewPager in the API 4+ Support Demos and API 13+ Support Demos sample code. + * + * {@sample development/samples/Support13Demos/src/com/example/android/supportv13/app/ActionBarTabsPager.java + * complete} + */ +public class ViewPager extends ViewGroup { + private static final String TAG = "ViewPager"; + private static final boolean DEBUG = false; + + private static final boolean USE_CACHE = false; + + private static final int DEFAULT_OFFSCREEN_PAGES = 1; + private static final int MAX_SETTLE_DURATION = 600; // ms + private static final int MIN_DISTANCE_FOR_FLING = 25; // dips + + private static final int DEFAULT_GUTTER_SIZE = 16; // dips + + private static final int MIN_FLING_VELOCITY = 400; // dips + + private static final int[] LAYOUT_ATTRS = new int[] { + com.android.internal.R.attr.layout_gravity + }; + + /** + * Used to track what the expected number of items in the adapter should be. + * If the app changes this when we don't expect it, we'll throw a big obnoxious exception. + */ + private int mExpectedAdapterCount; + + static class ItemInfo { + Object object; + int position; + boolean scrolling; + float widthFactor; + float offset; + } + + private static final Comparator<ItemInfo> COMPARATOR = new Comparator<ItemInfo>(){ + @Override + public int compare(ItemInfo lhs, ItemInfo rhs) { + return lhs.position - rhs.position; + } + }; + + private static final Interpolator sInterpolator = new Interpolator() { + public float getInterpolation(float t) { + t -= 1.0f; + return t * t * t * t * t + 1.0f; + } + }; + + private final ArrayList<ItemInfo> mItems = new ArrayList<ItemInfo>(); + private final ItemInfo mTempItem = new ItemInfo(); + + private final Rect mTempRect = new Rect(); + + private PagerAdapter mAdapter; + private int mCurItem; // Index of currently displayed page. + private int mRestoredCurItem = -1; + private Parcelable mRestoredAdapterState = null; + private ClassLoader mRestoredClassLoader = null; + private Scroller mScroller; + private PagerObserver mObserver; + + private int mPageMargin; + private Drawable mMarginDrawable; + private int mTopPageBounds; + private int mBottomPageBounds; + + // Offsets of the first and last items, if known. + // Set during population, used to determine if we are at the beginning + // or end of the pager data set during touch scrolling. + private float mFirstOffset = -Float.MAX_VALUE; + private float mLastOffset = Float.MAX_VALUE; + + private int mChildWidthMeasureSpec; + private int mChildHeightMeasureSpec; + private boolean mInLayout; + + private boolean mScrollingCacheEnabled; + + private boolean mPopulatePending; + private int mOffscreenPageLimit = DEFAULT_OFFSCREEN_PAGES; + + private boolean mIsBeingDragged; + private boolean mIsUnableToDrag; + private int mDefaultGutterSize; + private int mGutterSize; + private int mTouchSlop; + /** + * Position of the last motion event. + */ + private float mLastMotionX; + private float mLastMotionY; + private float mInitialMotionX; + private float mInitialMotionY; + /** + * ID of the active pointer. This is used to retain consistency during + * drags/flings if multiple pointers are used. + */ + private int mActivePointerId = INVALID_POINTER; + /** + * Sentinel value for no current active pointer. + * Used by {@link #mActivePointerId}. + */ + private static final int INVALID_POINTER = -1; + + /** + * Determines speed during touch scrolling + */ + private VelocityTracker mVelocityTracker; + private int mMinimumVelocity; + private int mMaximumVelocity; + private int mFlingDistance; + private int mCloseEnough; + + // If the pager is at least this close to its final position, complete the scroll + // on touch down and let the user interact with the content inside instead of + // "catching" the flinging pager. + private static final int CLOSE_ENOUGH = 2; // dp + + private boolean mFakeDragging; + private long mFakeDragBeginTime; + + private EdgeEffect mLeftEdge; + private EdgeEffect mRightEdge; + + private boolean mFirstLayout = true; + private boolean mNeedCalculatePageOffsets = false; + private boolean mCalledSuper; + private int mDecorChildCount; + + private OnPageChangeListener mOnPageChangeListener; + private OnPageChangeListener mInternalPageChangeListener; + private OnAdapterChangeListener mAdapterChangeListener; + private PageTransformer mPageTransformer; + + private static final int DRAW_ORDER_DEFAULT = 0; + private static final int DRAW_ORDER_FORWARD = 1; + private static final int DRAW_ORDER_REVERSE = 2; + private int mDrawingOrder; + private ArrayList<View> mDrawingOrderedChildren; + private static final ViewPositionComparator sPositionComparator = new ViewPositionComparator(); + + /** + * Indicates that the pager is in an idle, settled state. The current page + * is fully in view and no animation is in progress. + */ + public static final int SCROLL_STATE_IDLE = 0; + + /** + * Indicates that the pager is currently being dragged by the user. + */ + public static final int SCROLL_STATE_DRAGGING = 1; + + /** + * Indicates that the pager is in the process of settling to a final position. + */ + public static final int SCROLL_STATE_SETTLING = 2; + + private final Runnable mEndScrollRunnable = new Runnable() { + public void run() { + setScrollState(SCROLL_STATE_IDLE); + populate(); + } + }; + + private int mScrollState = SCROLL_STATE_IDLE; + + /** + * Callback interface for responding to changing state of the selected page. + */ + public interface OnPageChangeListener { + + /** + * This method will be invoked when the current page is scrolled, either as part + * of a programmatically initiated smooth scroll or a user initiated touch scroll. + * + * @param position Position index of the first page currently being displayed. + * Page position+1 will be visible if positionOffset is nonzero. + * @param positionOffset Value from [0, 1) indicating the offset from the page at position. + * @param positionOffsetPixels Value in pixels indicating the offset from position. + */ + public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels); + + /** + * This method will be invoked when a new page becomes selected. Animation is not + * necessarily complete. + * + * @param position Position index of the new selected page. + */ + public void onPageSelected(int position); + + /** + * Called when the scroll state changes. Useful for discovering when the user + * begins dragging, when the pager is automatically settling to the current page, + * or when it is fully stopped/idle. + * + * @param state The new scroll state. + * @see com.android.internal.widget.ViewPager#SCROLL_STATE_IDLE + * @see com.android.internal.widget.ViewPager#SCROLL_STATE_DRAGGING + * @see com.android.internal.widget.ViewPager#SCROLL_STATE_SETTLING + */ + public void onPageScrollStateChanged(int state); + } + + /** + * Simple implementation of the {@link OnPageChangeListener} interface with stub + * implementations of each method. Extend this if you do not intend to override + * every method of {@link OnPageChangeListener}. + */ + public static class SimpleOnPageChangeListener implements OnPageChangeListener { + @Override + public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { + // This space for rent + } + + @Override + public void onPageSelected(int position) { + // This space for rent + } + + @Override + public void onPageScrollStateChanged(int state) { + // This space for rent + } + } + + /** + * A PageTransformer is invoked whenever a visible/attached page is scrolled. + * This offers an opportunity for the application to apply a custom transformation + * to the page views using animation properties. + * + * <p>As property animation is only supported as of Android 3.0 and forward, + * setting a PageTransformer on a ViewPager on earlier platform versions will + * be ignored.</p> + */ + public interface PageTransformer { + /** + * Apply a property transformation to the given page. + * + * @param page Apply the transformation to this page + * @param position Position of page relative to the current front-and-center + * position of the pager. 0 is front and center. 1 is one full + * page position to the right, and -1 is one page position to the left. + */ + public void transformPage(View page, float position); + } + + /** + * Used internally to monitor when adapters are switched. + */ + interface OnAdapterChangeListener { + public void onAdapterChanged(PagerAdapter oldAdapter, PagerAdapter newAdapter); + } + + /** + * Used internally to tag special types of child views that should be added as + * pager decorations by default. + */ + interface Decor {} + + public ViewPager(Context context) { + super(context); + initViewPager(); + } + + public ViewPager(Context context, AttributeSet attrs) { + super(context, attrs); + initViewPager(); + } + + void initViewPager() { + setWillNotDraw(false); + setDescendantFocusability(FOCUS_AFTER_DESCENDANTS); + setFocusable(true); + final Context context = getContext(); + mScroller = new Scroller(context, sInterpolator); + final ViewConfiguration configuration = ViewConfiguration.get(context); + final float density = context.getResources().getDisplayMetrics().density; + + mTouchSlop = configuration.getScaledPagingTouchSlop(); + mMinimumVelocity = (int) (MIN_FLING_VELOCITY * density); + mMaximumVelocity = configuration.getScaledMaximumFlingVelocity(); + mLeftEdge = new EdgeEffect(context); + mRightEdge = new EdgeEffect(context); + + mFlingDistance = (int) (MIN_DISTANCE_FOR_FLING * density); + mCloseEnough = (int) (CLOSE_ENOUGH * density); + mDefaultGutterSize = (int) (DEFAULT_GUTTER_SIZE * density); + + setAccessibilityDelegate(new MyAccessibilityDelegate()); + + if (getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) { + setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES); + } + } + + @Override + protected void onDetachedFromWindow() { + removeCallbacks(mEndScrollRunnable); + super.onDetachedFromWindow(); + } + + private void setScrollState(int newState) { + if (mScrollState == newState) { + return; + } + + mScrollState = newState; + if (mPageTransformer != null) { + // PageTransformers can do complex things that benefit from hardware layers. + enableLayers(newState != SCROLL_STATE_IDLE); + } + if (mOnPageChangeListener != null) { + mOnPageChangeListener.onPageScrollStateChanged(newState); + } + } + + /** + * Set a PagerAdapter that will supply views for this pager as needed. + * + * @param adapter Adapter to use + */ + public void setAdapter(PagerAdapter adapter) { + if (mAdapter != null) { + mAdapter.unregisterDataSetObserver(mObserver); + mAdapter.startUpdate(this); + for (int i = 0; i < mItems.size(); i++) { + final ItemInfo ii = mItems.get(i); + mAdapter.destroyItem(this, ii.position, ii.object); + } + mAdapter.finishUpdate(this); + mItems.clear(); + removeNonDecorViews(); + mCurItem = 0; + scrollTo(0, 0); + } + + final PagerAdapter oldAdapter = mAdapter; + mAdapter = adapter; + mExpectedAdapterCount = 0; + + if (mAdapter != null) { + if (mObserver == null) { + mObserver = new PagerObserver(); + } + mAdapter.registerDataSetObserver(mObserver); + mPopulatePending = false; + final boolean wasFirstLayout = mFirstLayout; + mFirstLayout = true; + mExpectedAdapterCount = mAdapter.getCount(); + if (mRestoredCurItem >= 0) { + mAdapter.restoreState(mRestoredAdapterState, mRestoredClassLoader); + setCurrentItemInternal(mRestoredCurItem, false, true); + mRestoredCurItem = -1; + mRestoredAdapterState = null; + mRestoredClassLoader = null; + } else if (!wasFirstLayout) { + populate(); + } else { + requestLayout(); + } + } + + if (mAdapterChangeListener != null && oldAdapter != adapter) { + mAdapterChangeListener.onAdapterChanged(oldAdapter, adapter); + } + } + + private void removeNonDecorViews() { + for (int i = 0; i < getChildCount(); i++) { + final View child = getChildAt(i); + final LayoutParams lp = (LayoutParams) child.getLayoutParams(); + if (!lp.isDecor) { + removeViewAt(i); + i--; + } + } + } + + /** + * Retrieve the current adapter supplying pages. + * + * @return The currently registered PagerAdapter + */ + public PagerAdapter getAdapter() { + return mAdapter; + } + + void setOnAdapterChangeListener(OnAdapterChangeListener listener) { + mAdapterChangeListener = listener; + } + + private int getClientWidth() { + return getMeasuredWidth() - getPaddingLeft() - getPaddingRight(); + } + + /** + * Set the currently selected page. If the ViewPager has already been through its first + * layout with its current adapter there will be a smooth animated transition between + * the current item and the specified item. + * + * @param item Item index to select + */ + public void setCurrentItem(int item) { + mPopulatePending = false; + setCurrentItemInternal(item, !mFirstLayout, false); + } + + /** + * Set the currently selected page. + * + * @param item Item index to select + * @param smoothScroll True to smoothly scroll to the new item, false to transition immediately + */ + public void setCurrentItem(int item, boolean smoothScroll) { + mPopulatePending = false; + setCurrentItemInternal(item, smoothScroll, false); + } + + public int getCurrentItem() { + return mCurItem; + } + + void setCurrentItemInternal(int item, boolean smoothScroll, boolean always) { + setCurrentItemInternal(item, smoothScroll, always, 0); + } + + void setCurrentItemInternal(int item, boolean smoothScroll, boolean always, int velocity) { + if (mAdapter == null || mAdapter.getCount() <= 0) { + setScrollingCacheEnabled(false); + return; + } + if (!always && mCurItem == item && mItems.size() != 0) { + setScrollingCacheEnabled(false); + return; + } + + if (item < 0) { + item = 0; + } else if (item >= mAdapter.getCount()) { + item = mAdapter.getCount() - 1; + } + final int pageLimit = mOffscreenPageLimit; + if (item > (mCurItem + pageLimit) || item < (mCurItem - pageLimit)) { + // We are doing a jump by more than one page. To avoid + // glitches, we want to keep all current pages in the view + // until the scroll ends. + for (int i=0; i<mItems.size(); i++) { + mItems.get(i).scrolling = true; + } + } + final boolean dispatchSelected = mCurItem != item; + + if (mFirstLayout) { + // We don't have any idea how big we are yet and shouldn't have any pages either. + // Just set things up and let the pending layout handle things. + mCurItem = item; + if (dispatchSelected && mOnPageChangeListener != null) { + mOnPageChangeListener.onPageSelected(item); + } + if (dispatchSelected && mInternalPageChangeListener != null) { + mInternalPageChangeListener.onPageSelected(item); + } + requestLayout(); + } else { + populate(item); + scrollToItem(item, smoothScroll, velocity, dispatchSelected); + } + } + + private void scrollToItem(int item, boolean smoothScroll, int velocity, + boolean dispatchSelected) { + final ItemInfo curInfo = infoForPosition(item); + int destX = 0; + if (curInfo != null) { + final int width = getClientWidth(); + destX = (int) (width * Math.max(mFirstOffset, + Math.min(curInfo.offset, mLastOffset))); + } + if (smoothScroll) { + smoothScrollTo(destX, 0, velocity); + if (dispatchSelected && mOnPageChangeListener != null) { + mOnPageChangeListener.onPageSelected(item); + } + if (dispatchSelected && mInternalPageChangeListener != null) { + mInternalPageChangeListener.onPageSelected(item); + } + } else { + if (dispatchSelected && mOnPageChangeListener != null) { + mOnPageChangeListener.onPageSelected(item); + } + if (dispatchSelected && mInternalPageChangeListener != null) { + mInternalPageChangeListener.onPageSelected(item); + } + completeScroll(false); + scrollTo(destX, 0); + pageScrolled(destX); + } + } + + /** + * Set a listener that will be invoked whenever the page changes or is incrementally + * scrolled. See {@link OnPageChangeListener}. + * + * @param listener Listener to set + */ + public void setOnPageChangeListener(OnPageChangeListener listener) { + mOnPageChangeListener = listener; + } + + /** + * Set a {@link PageTransformer} that will be called for each attached page whenever + * the scroll position is changed. This allows the application to apply custom property + * transformations to each page, overriding the default sliding look and feel. + * + * <p><em>Note:</em> Prior to Android 3.0 the property animation APIs did not exist. + * As a result, setting a PageTransformer prior to Android 3.0 (API 11) will have no effect.</p> + * + * @param reverseDrawingOrder true if the supplied PageTransformer requires page views + * to be drawn from last to first instead of first to last. + * @param transformer PageTransformer that will modify each page's animation properties + */ + public void setPageTransformer(boolean reverseDrawingOrder, PageTransformer transformer) { + final boolean hasTransformer = transformer != null; + final boolean needsPopulate = hasTransformer != (mPageTransformer != null); + mPageTransformer = transformer; + setChildrenDrawingOrderEnabled(hasTransformer); + if (hasTransformer) { + mDrawingOrder = reverseDrawingOrder ? DRAW_ORDER_REVERSE : DRAW_ORDER_FORWARD; + } else { + mDrawingOrder = DRAW_ORDER_DEFAULT; + } + if (needsPopulate) populate(); + } + + @Override + protected int getChildDrawingOrder(int childCount, int i) { + final int index = mDrawingOrder == DRAW_ORDER_REVERSE ? childCount - 1 - i : i; + final int result = ((LayoutParams) mDrawingOrderedChildren.get(index).getLayoutParams()).childIndex; + return result; + } + + /** + * Set a separate OnPageChangeListener for internal use by the support library. + * + * @param listener Listener to set + * @return The old listener that was set, if any. + */ + OnPageChangeListener setInternalPageChangeListener(OnPageChangeListener listener) { + OnPageChangeListener oldListener = mInternalPageChangeListener; + mInternalPageChangeListener = listener; + return oldListener; + } + + /** + * Returns the number of pages that will be retained to either side of the + * current page in the view hierarchy in an idle state. Defaults to 1. + * + * @return How many pages will be kept offscreen on either side + * @see #setOffscreenPageLimit(int) + */ + public int getOffscreenPageLimit() { + return mOffscreenPageLimit; + } + + /** + * Set the number of pages that should be retained to either side of the + * current page in the view hierarchy in an idle state. Pages beyond this + * limit will be recreated from the adapter when needed. + * + * <p>This is offered as an optimization. If you know in advance the number + * of pages you will need to support or have lazy-loading mechanisms in place + * on your pages, tweaking this setting can have benefits in perceived smoothness + * of paging animations and interaction. If you have a small number of pages (3-4) + * that you can keep active all at once, less time will be spent in layout for + * newly created view subtrees as the user pages back and forth.</p> + * + * <p>You should keep this limit low, especially if your pages have complex layouts. + * This setting defaults to 1.</p> + * + * @param limit How many pages will be kept offscreen in an idle state. + */ + public void setOffscreenPageLimit(int limit) { + if (limit < DEFAULT_OFFSCREEN_PAGES) { + Log.w(TAG, "Requested offscreen page limit " + limit + " too small; defaulting to " + + DEFAULT_OFFSCREEN_PAGES); + limit = DEFAULT_OFFSCREEN_PAGES; + } + if (limit != mOffscreenPageLimit) { + mOffscreenPageLimit = limit; + populate(); + } + } + + /** + * Set the margin between pages. + * + * @param marginPixels Distance between adjacent pages in pixels + * @see #getPageMargin() + * @see #setPageMarginDrawable(android.graphics.drawable.Drawable) + * @see #setPageMarginDrawable(int) + */ + public void setPageMargin(int marginPixels) { + final int oldMargin = mPageMargin; + mPageMargin = marginPixels; + + final int width = getWidth(); + recomputeScrollPosition(width, width, marginPixels, oldMargin); + + requestLayout(); + } + + /** + * Return the margin between pages. + * + * @return The size of the margin in pixels + */ + public int getPageMargin() { + return mPageMargin; + } + + /** + * Set a drawable that will be used to fill the margin between pages. + * + * @param d Drawable to display between pages + */ + public void setPageMarginDrawable(Drawable d) { + mMarginDrawable = d; + if (d != null) refreshDrawableState(); + setWillNotDraw(d == null); + invalidate(); + } + + /** + * Set a drawable that will be used to fill the margin between pages. + * + * @param resId Resource ID of a drawable to display between pages + */ + public void setPageMarginDrawable(@DrawableRes int resId) { + setPageMarginDrawable(getContext().getDrawable(resId)); + } + + @Override + protected boolean verifyDrawable(Drawable who) { + return super.verifyDrawable(who) || who == mMarginDrawable; + } + + @Override + protected void drawableStateChanged() { + super.drawableStateChanged(); + final Drawable d = mMarginDrawable; + if (d != null && d.isStateful()) { + d.setState(getDrawableState()); + } + } + + // We want the duration of the page snap animation to be influenced by the distance that + // the screen has to travel, however, we don't want this duration to be effected in a + // purely linear fashion. Instead, we use this method to moderate the effect that the distance + // of travel has on the overall snap duration. + float distanceInfluenceForSnapDuration(float f) { + f -= 0.5f; // center the values about 0. + f *= 0.3f * Math.PI / 2.0f; + return (float) Math.sin(f); + } + + /** + * Like {@link android.view.View#scrollBy}, but scroll smoothly instead of immediately. + * + * @param x the number of pixels to scroll by on the X axis + * @param y the number of pixels to scroll by on the Y axis + */ + void smoothScrollTo(int x, int y) { + smoothScrollTo(x, y, 0); + } + + /** + * Like {@link android.view.View#scrollBy}, but scroll smoothly instead of immediately. + * + * @param x the number of pixels to scroll by on the X axis + * @param y the number of pixels to scroll by on the Y axis + * @param velocity the velocity associated with a fling, if applicable. (0 otherwise) + */ + void smoothScrollTo(int x, int y, int velocity) { + if (getChildCount() == 0) { + // Nothing to do. + setScrollingCacheEnabled(false); + return; + } + int sx = getScrollX(); + int sy = getScrollY(); + int dx = x - sx; + int dy = y - sy; + if (dx == 0 && dy == 0) { + completeScroll(false); + populate(); + setScrollState(SCROLL_STATE_IDLE); + return; + } + + setScrollingCacheEnabled(true); + setScrollState(SCROLL_STATE_SETTLING); + + final int width = getClientWidth(); + final int halfWidth = width / 2; + final float distanceRatio = Math.min(1f, 1.0f * Math.abs(dx) / width); + final float distance = halfWidth + halfWidth * + distanceInfluenceForSnapDuration(distanceRatio); + + int duration = 0; + velocity = Math.abs(velocity); + if (velocity > 0) { + duration = 4 * Math.round(1000 * Math.abs(distance / velocity)); + } else { + final float pageWidth = width * mAdapter.getPageWidth(mCurItem); + final float pageDelta = (float) Math.abs(dx) / (pageWidth + mPageMargin); + duration = (int) ((pageDelta + 1) * 100); + } + duration = Math.min(duration, MAX_SETTLE_DURATION); + + mScroller.startScroll(sx, sy, dx, dy, duration); + postInvalidateOnAnimation(); + } + + ItemInfo addNewItem(int position, int index) { + ItemInfo ii = new ItemInfo(); + ii.position = position; + ii.object = mAdapter.instantiateItem(this, position); + ii.widthFactor = mAdapter.getPageWidth(position); + if (index < 0 || index >= mItems.size()) { + mItems.add(ii); + } else { + mItems.add(index, ii); + } + return ii; + } + + void dataSetChanged() { + // This method only gets called if our observer is attached, so mAdapter is non-null. + + final int adapterCount = mAdapter.getCount(); + mExpectedAdapterCount = adapterCount; + boolean needPopulate = mItems.size() < mOffscreenPageLimit * 2 + 1 && + mItems.size() < adapterCount; + int newCurrItem = mCurItem; + + boolean isUpdating = false; + for (int i = 0; i < mItems.size(); i++) { + final ItemInfo ii = mItems.get(i); + final int newPos = mAdapter.getItemPosition(ii.object); + + if (newPos == PagerAdapter.POSITION_UNCHANGED) { + continue; + } + + if (newPos == PagerAdapter.POSITION_NONE) { + mItems.remove(i); + i--; + + if (!isUpdating) { + mAdapter.startUpdate(this); + isUpdating = true; + } + + mAdapter.destroyItem(this, ii.position, ii.object); + needPopulate = true; + + if (mCurItem == ii.position) { + // Keep the current item in the valid range + newCurrItem = Math.max(0, Math.min(mCurItem, adapterCount - 1)); + needPopulate = true; + } + continue; + } + + if (ii.position != newPos) { + if (ii.position == mCurItem) { + // Our current item changed position. Follow it. + newCurrItem = newPos; + } + + ii.position = newPos; + needPopulate = true; + } + } + + if (isUpdating) { + mAdapter.finishUpdate(this); + } + + Collections.sort(mItems, COMPARATOR); + + if (needPopulate) { + // Reset our known page widths; populate will recompute them. + final int childCount = getChildCount(); + for (int i = 0; i < childCount; i++) { + final View child = getChildAt(i); + final LayoutParams lp = (LayoutParams) child.getLayoutParams(); + if (!lp.isDecor) { + lp.widthFactor = 0.f; + } + } + + setCurrentItemInternal(newCurrItem, false, true); + requestLayout(); + } + } + + void populate() { + populate(mCurItem); + } + + void populate(int newCurrentItem) { + ItemInfo oldCurInfo = null; + int focusDirection = View.FOCUS_FORWARD; + if (mCurItem != newCurrentItem) { + focusDirection = mCurItem < newCurrentItem ? View.FOCUS_RIGHT : View.FOCUS_LEFT; + oldCurInfo = infoForPosition(mCurItem); + mCurItem = newCurrentItem; + } + + if (mAdapter == null) { + sortChildDrawingOrder(); + return; + } + + // Bail now if we are waiting to populate. This is to hold off + // on creating views from the time the user releases their finger to + // fling to a new position until we have finished the scroll to + // that position, avoiding glitches from happening at that point. + if (mPopulatePending) { + if (DEBUG) Log.i(TAG, "populate is pending, skipping for now..."); + sortChildDrawingOrder(); + return; + } + + // Also, don't populate until we are attached to a window. This is to + // avoid trying to populate before we have restored our view hierarchy + // state and conflicting with what is restored. + if (getWindowToken() == null) { + return; + } + + mAdapter.startUpdate(this); + + final int pageLimit = mOffscreenPageLimit; + final int startPos = Math.max(0, mCurItem - pageLimit); + final int N = mAdapter.getCount(); + final int endPos = Math.min(N-1, mCurItem + pageLimit); + + if (N != mExpectedAdapterCount) { + String resName; + try { + resName = getResources().getResourceName(getId()); + } catch (Resources.NotFoundException e) { + resName = Integer.toHexString(getId()); + } + throw new IllegalStateException("The application's PagerAdapter changed the adapter's" + + " contents without calling PagerAdapter#notifyDataSetChanged!" + + " Expected adapter item count: " + mExpectedAdapterCount + ", found: " + N + + " Pager id: " + resName + + " Pager class: " + getClass() + + " Problematic adapter: " + mAdapter.getClass()); + } + + // Locate the currently focused item or add it if needed. + int curIndex = -1; + ItemInfo curItem = null; + for (curIndex = 0; curIndex < mItems.size(); curIndex++) { + final ItemInfo ii = mItems.get(curIndex); + if (ii.position >= mCurItem) { + if (ii.position == mCurItem) curItem = ii; + break; + } + } + + if (curItem == null && N > 0) { + curItem = addNewItem(mCurItem, curIndex); + } + + // Fill 3x the available width or up to the number of offscreen + // pages requested to either side, whichever is larger. + // If we have no current item we have no work to do. + if (curItem != null) { + float extraWidthLeft = 0.f; + int itemIndex = curIndex - 1; + ItemInfo ii = itemIndex >= 0 ? mItems.get(itemIndex) : null; + final int clientWidth = getClientWidth(); + final float leftWidthNeeded = clientWidth <= 0 ? 0 : + 2.f - curItem.widthFactor + (float) getPaddingLeft() / (float) clientWidth; + for (int pos = mCurItem - 1; pos >= 0; pos--) { + if (extraWidthLeft >= leftWidthNeeded && pos < startPos) { + if (ii == null) { + break; + } + if (pos == ii.position && !ii.scrolling) { + mItems.remove(itemIndex); + mAdapter.destroyItem(this, pos, ii.object); + if (DEBUG) { + Log.i(TAG, "populate() - destroyItem() with pos: " + pos + + " view: " + ((View) ii.object)); + } + itemIndex--; + curIndex--; + ii = itemIndex >= 0 ? mItems.get(itemIndex) : null; + } + } else if (ii != null && pos == ii.position) { + extraWidthLeft += ii.widthFactor; + itemIndex--; + ii = itemIndex >= 0 ? mItems.get(itemIndex) : null; + } else { + ii = addNewItem(pos, itemIndex + 1); + extraWidthLeft += ii.widthFactor; + curIndex++; + ii = itemIndex >= 0 ? mItems.get(itemIndex) : null; + } + } + + float extraWidthRight = curItem.widthFactor; + itemIndex = curIndex + 1; + if (extraWidthRight < 2.f) { + ii = itemIndex < mItems.size() ? mItems.get(itemIndex) : null; + final float rightWidthNeeded = clientWidth <= 0 ? 0 : + (float) getPaddingRight() / (float) clientWidth + 2.f; + for (int pos = mCurItem + 1; pos < N; pos++) { + if (extraWidthRight >= rightWidthNeeded && pos > endPos) { + if (ii == null) { + break; + } + if (pos == ii.position && !ii.scrolling) { + mItems.remove(itemIndex); + mAdapter.destroyItem(this, pos, ii.object); + if (DEBUG) { + Log.i(TAG, "populate() - destroyItem() with pos: " + pos + + " view: " + ((View) ii.object)); + } + ii = itemIndex < mItems.size() ? mItems.get(itemIndex) : null; + } + } else if (ii != null && pos == ii.position) { + extraWidthRight += ii.widthFactor; + itemIndex++; + ii = itemIndex < mItems.size() ? mItems.get(itemIndex) : null; + } else { + ii = addNewItem(pos, itemIndex); + itemIndex++; + extraWidthRight += ii.widthFactor; + ii = itemIndex < mItems.size() ? mItems.get(itemIndex) : null; + } + } + } + + calculatePageOffsets(curItem, curIndex, oldCurInfo); + } + + if (DEBUG) { + Log.i(TAG, "Current page list:"); + for (int i=0; i<mItems.size(); i++) { + Log.i(TAG, "#" + i + ": page " + mItems.get(i).position); + } + } + + mAdapter.setPrimaryItem(this, mCurItem, curItem != null ? curItem.object : null); + + mAdapter.finishUpdate(this); + + // Check width measurement of current pages and drawing sort order. + // Update LayoutParams as needed. + final int childCount = getChildCount(); + for (int i = 0; i < childCount; i++) { + final View child = getChildAt(i); + final LayoutParams lp = (LayoutParams) child.getLayoutParams(); + lp.childIndex = i; + if (!lp.isDecor && lp.widthFactor == 0.f) { + // 0 means requery the adapter for this, it doesn't have a valid width. + final ItemInfo ii = infoForChild(child); + if (ii != null) { + lp.widthFactor = ii.widthFactor; + lp.position = ii.position; + } + } + } + sortChildDrawingOrder(); + + if (hasFocus()) { + View currentFocused = findFocus(); + ItemInfo ii = currentFocused != null ? infoForAnyChild(currentFocused) : null; + if (ii == null || ii.position != mCurItem) { + for (int i=0; i<getChildCount(); i++) { + View child = getChildAt(i); + ii = infoForChild(child); + if (ii != null && ii.position == mCurItem) { + if (child.requestFocus(focusDirection)) { + break; + } + } + } + } + } + } + + private void sortChildDrawingOrder() { + if (mDrawingOrder != DRAW_ORDER_DEFAULT) { + if (mDrawingOrderedChildren == null) { + mDrawingOrderedChildren = new ArrayList<View>(); + } else { + mDrawingOrderedChildren.clear(); + } + final int childCount = getChildCount(); + for (int i = 0; i < childCount; i++) { + final View child = getChildAt(i); + mDrawingOrderedChildren.add(child); + } + Collections.sort(mDrawingOrderedChildren, sPositionComparator); + } + } + + private void calculatePageOffsets(ItemInfo curItem, int curIndex, ItemInfo oldCurInfo) { + final int N = mAdapter.getCount(); + final int width = getClientWidth(); + final float marginOffset = width > 0 ? (float) mPageMargin / width : 0; + // Fix up offsets for later layout. + if (oldCurInfo != null) { + final int oldCurPosition = oldCurInfo.position; + // Base offsets off of oldCurInfo. + if (oldCurPosition < curItem.position) { + int itemIndex = 0; + ItemInfo ii = null; + float offset = oldCurInfo.offset + oldCurInfo.widthFactor + marginOffset; + for (int pos = oldCurPosition + 1; + pos <= curItem.position && itemIndex < mItems.size(); pos++) { + ii = mItems.get(itemIndex); + while (pos > ii.position && itemIndex < mItems.size() - 1) { + itemIndex++; + ii = mItems.get(itemIndex); + } + while (pos < ii.position) { + // We don't have an item populated for this, + // ask the adapter for an offset. + offset += mAdapter.getPageWidth(pos) + marginOffset; + pos++; + } + ii.offset = offset; + offset += ii.widthFactor + marginOffset; + } + } else if (oldCurPosition > curItem.position) { + int itemIndex = mItems.size() - 1; + ItemInfo ii = null; + float offset = oldCurInfo.offset; + for (int pos = oldCurPosition - 1; + pos >= curItem.position && itemIndex >= 0; pos--) { + ii = mItems.get(itemIndex); + while (pos < ii.position && itemIndex > 0) { + itemIndex--; + ii = mItems.get(itemIndex); + } + while (pos > ii.position) { + // We don't have an item populated for this, + // ask the adapter for an offset. + offset -= mAdapter.getPageWidth(pos) + marginOffset; + pos--; + } + offset -= ii.widthFactor + marginOffset; + ii.offset = offset; + } + } + } + + // Base all offsets off of curItem. + final int itemCount = mItems.size(); + float offset = curItem.offset; + int pos = curItem.position - 1; + mFirstOffset = curItem.position == 0 ? curItem.offset : -Float.MAX_VALUE; + mLastOffset = curItem.position == N - 1 ? + curItem.offset + curItem.widthFactor - 1 : Float.MAX_VALUE; + // Previous pages + for (int i = curIndex - 1; i >= 0; i--, pos--) { + final ItemInfo ii = mItems.get(i); + while (pos > ii.position) { + offset -= mAdapter.getPageWidth(pos--) + marginOffset; + } + offset -= ii.widthFactor + marginOffset; + ii.offset = offset; + if (ii.position == 0) mFirstOffset = offset; + } + offset = curItem.offset + curItem.widthFactor + marginOffset; + pos = curItem.position + 1; + // Next pages + for (int i = curIndex + 1; i < itemCount; i++, pos++) { + final ItemInfo ii = mItems.get(i); + while (pos < ii.position) { + offset += mAdapter.getPageWidth(pos++) + marginOffset; + } + if (ii.position == N - 1) { + mLastOffset = offset + ii.widthFactor - 1; + } + ii.offset = offset; + offset += ii.widthFactor + marginOffset; + } + + mNeedCalculatePageOffsets = false; + } + + /** + * This is the persistent state that is saved by ViewPager. Only needed + * if you are creating a sublass of ViewPager that must save its own + * state, in which case it should implement a subclass of this which + * contains that state. + */ + public static class SavedState extends BaseSavedState { + int position; + Parcelable adapterState; + ClassLoader loader; + + public SavedState(Parcel source) { + super(source); + } + + public SavedState(Parcelable superState) { + super(superState); + } + + @Override + public void writeToParcel(Parcel out, int flags) { + super.writeToParcel(out, flags); + out.writeInt(position); + out.writeParcelable(adapterState, flags); + } + + @Override + public String toString() { + return "FragmentPager.SavedState{" + + Integer.toHexString(System.identityHashCode(this)) + + " position=" + position + "}"; + } + + public static final Creator<SavedState> CREATOR = new Creator<SavedState>() { + @Override + public SavedState createFromParcel(Parcel in) { + return new SavedState(in); + } + @Override + public SavedState[] newArray(int size) { + return new SavedState[size]; + } + }; + + SavedState(Parcel in, ClassLoader loader) { + super(in); + if (loader == null) { + loader = getClass().getClassLoader(); + } + position = in.readInt(); + adapterState = in.readParcelable(loader); + this.loader = loader; + } + } + + @Override + public Parcelable onSaveInstanceState() { + Parcelable superState = super.onSaveInstanceState(); + SavedState ss = new SavedState(superState); + ss.position = mCurItem; + if (mAdapter != null) { + ss.adapterState = mAdapter.saveState(); + } + return ss; + } + + @Override + public void onRestoreInstanceState(Parcelable state) { + if (!(state instanceof SavedState)) { + super.onRestoreInstanceState(state); + return; + } + + SavedState ss = (SavedState)state; + super.onRestoreInstanceState(ss.getSuperState()); + + if (mAdapter != null) { + mAdapter.restoreState(ss.adapterState, ss.loader); + setCurrentItemInternal(ss.position, false, true); + } else { + mRestoredCurItem = ss.position; + mRestoredAdapterState = ss.adapterState; + mRestoredClassLoader = ss.loader; + } + } + + @Override + public void addView(View child, int index, ViewGroup.LayoutParams params) { + if (!checkLayoutParams(params)) { + params = generateLayoutParams(params); + } + final LayoutParams lp = (LayoutParams) params; + lp.isDecor |= child instanceof Decor; + if (mInLayout) { + if (lp != null && lp.isDecor) { + throw new IllegalStateException("Cannot add pager decor view during layout"); + } + lp.needsMeasure = true; + addViewInLayout(child, index, params); + } else { + super.addView(child, index, params); + } + + if (USE_CACHE) { + if (child.getVisibility() != GONE) { + child.setDrawingCacheEnabled(mScrollingCacheEnabled); + } else { + child.setDrawingCacheEnabled(false); + } + } + } + + @Override + public void removeView(View view) { + if (mInLayout) { + removeViewInLayout(view); + } else { + super.removeView(view); + } + } + + ItemInfo infoForChild(View child) { + for (int i=0; i<mItems.size(); i++) { + ItemInfo ii = mItems.get(i); + if (mAdapter.isViewFromObject(child, ii.object)) { + return ii; + } + } + return null; + } + + ItemInfo infoForAnyChild(View child) { + ViewParent parent; + while ((parent=child.getParent()) != this) { + if (parent == null || !(parent instanceof View)) { + return null; + } + child = (View)parent; + } + return infoForChild(child); + } + + ItemInfo infoForPosition(int position) { + for (int i = 0; i < mItems.size(); i++) { + ItemInfo ii = mItems.get(i); + if (ii.position == position) { + return ii; + } + } + return null; + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + mFirstLayout = true; + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + // For simple implementation, our internal size is always 0. + // We depend on the container to specify the layout size of + // our view. We can't really know what it is since we will be + // adding and removing different arbitrary views and do not + // want the layout to change as this happens. + setMeasuredDimension(getDefaultSize(0, widthMeasureSpec), + getDefaultSize(0, heightMeasureSpec)); + + final int measuredWidth = getMeasuredWidth(); + final int maxGutterSize = measuredWidth / 10; + mGutterSize = Math.min(maxGutterSize, mDefaultGutterSize); + + // Children are just made to fill our space. + int childWidthSize = measuredWidth - getPaddingLeft() - getPaddingRight(); + int childHeightSize = getMeasuredHeight() - getPaddingTop() - getPaddingBottom(); + + /* + * Make sure all children have been properly measured. Decor views first. + * Right now we cheat and make this less complicated by assuming decor + * views won't intersect. We will pin to edges based on gravity. + */ + int size = getChildCount(); + for (int i = 0; i < size; ++i) { + final View child = getChildAt(i); + if (child.getVisibility() != GONE) { + final LayoutParams lp = (LayoutParams) child.getLayoutParams(); + if (lp != null && lp.isDecor) { + final int hgrav = lp.gravity & Gravity.HORIZONTAL_GRAVITY_MASK; + final int vgrav = lp.gravity & Gravity.VERTICAL_GRAVITY_MASK; + int widthMode = MeasureSpec.AT_MOST; + int heightMode = MeasureSpec.AT_MOST; + boolean consumeVertical = vgrav == Gravity.TOP || vgrav == Gravity.BOTTOM; + boolean consumeHorizontal = hgrav == Gravity.LEFT || hgrav == Gravity.RIGHT; + + if (consumeVertical) { + widthMode = MeasureSpec.EXACTLY; + } else if (consumeHorizontal) { + heightMode = MeasureSpec.EXACTLY; + } + + int widthSize = childWidthSize; + int heightSize = childHeightSize; + if (lp.width != LayoutParams.WRAP_CONTENT) { + widthMode = MeasureSpec.EXACTLY; + if (lp.width != LayoutParams.FILL_PARENT) { + widthSize = lp.width; + } + } + if (lp.height != LayoutParams.WRAP_CONTENT) { + heightMode = MeasureSpec.EXACTLY; + if (lp.height != LayoutParams.FILL_PARENT) { + heightSize = lp.height; + } + } + final int widthSpec = MeasureSpec.makeMeasureSpec(widthSize, widthMode); + final int heightSpec = MeasureSpec.makeMeasureSpec(heightSize, heightMode); + child.measure(widthSpec, heightSpec); + + if (consumeVertical) { + childHeightSize -= child.getMeasuredHeight(); + } else if (consumeHorizontal) { + childWidthSize -= child.getMeasuredWidth(); + } + } + } + } + + mChildWidthMeasureSpec = MeasureSpec.makeMeasureSpec(childWidthSize, MeasureSpec.EXACTLY); + mChildHeightMeasureSpec = MeasureSpec.makeMeasureSpec(childHeightSize, MeasureSpec.EXACTLY); + + // Make sure we have created all fragments that we need to have shown. + mInLayout = true; + populate(); + mInLayout = false; + + // Page views next. + size = getChildCount(); + for (int i = 0; i < size; ++i) { + final View child = getChildAt(i); + if (child.getVisibility() != GONE) { + if (DEBUG) Log.v(TAG, "Measuring #" + i + " " + child + + ": " + mChildWidthMeasureSpec); + + final LayoutParams lp = (LayoutParams) child.getLayoutParams(); + if (lp == null || !lp.isDecor) { + final int widthSpec = MeasureSpec.makeMeasureSpec( + (int) (childWidthSize * lp.widthFactor), MeasureSpec.EXACTLY); + child.measure(widthSpec, mChildHeightMeasureSpec); + } + } + } + } + + @Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + super.onSizeChanged(w, h, oldw, oldh); + + // Make sure scroll position is set correctly. + if (w != oldw) { + recomputeScrollPosition(w, oldw, mPageMargin, mPageMargin); + } + } + + private void recomputeScrollPosition(int width, int oldWidth, int margin, int oldMargin) { + if (oldWidth > 0 && !mItems.isEmpty()) { + final int widthWithMargin = width - getPaddingLeft() - getPaddingRight() + margin; + final int oldWidthWithMargin = oldWidth - getPaddingLeft() - getPaddingRight() + + oldMargin; + final int xpos = getScrollX(); + final float pageOffset = (float) xpos / oldWidthWithMargin; + final int newOffsetPixels = (int) (pageOffset * widthWithMargin); + + scrollTo(newOffsetPixels, getScrollY()); + if (!mScroller.isFinished()) { + // We now return to your regularly scheduled scroll, already in progress. + final int newDuration = mScroller.getDuration() - mScroller.timePassed(); + ItemInfo targetInfo = infoForPosition(mCurItem); + mScroller.startScroll(newOffsetPixels, 0, + (int) (targetInfo.offset * width), 0, newDuration); + } + } else { + final ItemInfo ii = infoForPosition(mCurItem); + final float scrollOffset = ii != null ? Math.min(ii.offset, mLastOffset) : 0; + final int scrollPos = (int) (scrollOffset * + (width - getPaddingLeft() - getPaddingRight())); + if (scrollPos != getScrollX()) { + completeScroll(false); + scrollTo(scrollPos, getScrollY()); + } + } + } + + @Override + protected void onLayout(boolean changed, int l, int t, int r, int b) { + final int count = getChildCount(); + int width = r - l; + int height = b - t; + int paddingLeft = getPaddingLeft(); + int paddingTop = getPaddingTop(); + int paddingRight = getPaddingRight(); + int paddingBottom = getPaddingBottom(); + final int scrollX = getScrollX(); + + int decorCount = 0; + + // First pass - decor views. We need to do this in two passes so that + // we have the proper offsets for non-decor views later. + for (int i = 0; i < count; i++) { + final View child = getChildAt(i); + if (child.getVisibility() != GONE) { + final LayoutParams lp = (LayoutParams) child.getLayoutParams(); + int childLeft = 0; + int childTop = 0; + if (lp.isDecor) { + final int hgrav = lp.gravity & Gravity.HORIZONTAL_GRAVITY_MASK; + final int vgrav = lp.gravity & Gravity.VERTICAL_GRAVITY_MASK; + switch (hgrav) { + default: + childLeft = paddingLeft; + break; + case Gravity.LEFT: + childLeft = paddingLeft; + paddingLeft += child.getMeasuredWidth(); + break; + case Gravity.CENTER_HORIZONTAL: + childLeft = Math.max((width - child.getMeasuredWidth()) / 2, + paddingLeft); + break; + case Gravity.RIGHT: + childLeft = width - paddingRight - child.getMeasuredWidth(); + paddingRight += child.getMeasuredWidth(); + break; + } + switch (vgrav) { + default: + childTop = paddingTop; + break; + case Gravity.TOP: + childTop = paddingTop; + paddingTop += child.getMeasuredHeight(); + break; + case Gravity.CENTER_VERTICAL: + childTop = Math.max((height - child.getMeasuredHeight()) / 2, + paddingTop); + break; + case Gravity.BOTTOM: + childTop = height - paddingBottom - child.getMeasuredHeight(); + paddingBottom += child.getMeasuredHeight(); + break; + } + childLeft += scrollX; + child.layout(childLeft, childTop, + childLeft + child.getMeasuredWidth(), + childTop + child.getMeasuredHeight()); + decorCount++; + } + } + } + + final int childWidth = width - paddingLeft - paddingRight; + // Page views. Do this once we have the right padding offsets from above. + for (int i = 0; i < count; i++) { + final View child = getChildAt(i); + if (child.getVisibility() != GONE) { + final LayoutParams lp = (LayoutParams) child.getLayoutParams(); + ItemInfo ii; + if (!lp.isDecor && (ii = infoForChild(child)) != null) { + int loff = (int) (childWidth * ii.offset); + int childLeft = paddingLeft + loff; + int childTop = paddingTop; + if (lp.needsMeasure) { + // This was added during layout and needs measurement. + // Do it now that we know what we're working with. + lp.needsMeasure = false; + final int widthSpec = MeasureSpec.makeMeasureSpec( + (int) (childWidth * lp.widthFactor), + MeasureSpec.EXACTLY); + final int heightSpec = MeasureSpec.makeMeasureSpec( + (int) (height - paddingTop - paddingBottom), + MeasureSpec.EXACTLY); + child.measure(widthSpec, heightSpec); + } + if (DEBUG) Log.v(TAG, "Positioning #" + i + " " + child + " f=" + ii.object + + ":" + childLeft + "," + childTop + " " + child.getMeasuredWidth() + + "x" + child.getMeasuredHeight()); + child.layout(childLeft, childTop, + childLeft + child.getMeasuredWidth(), + childTop + child.getMeasuredHeight()); + } + } + } + mTopPageBounds = paddingTop; + mBottomPageBounds = height - paddingBottom; + mDecorChildCount = decorCount; + + if (mFirstLayout) { + scrollToItem(mCurItem, false, 0, false); + } + mFirstLayout = false; + } + + @Override + public void computeScroll() { + if (!mScroller.isFinished() && mScroller.computeScrollOffset()) { + int oldX = getScrollX(); + int oldY = getScrollY(); + int x = mScroller.getCurrX(); + int y = mScroller.getCurrY(); + + if (oldX != x || oldY != y) { + scrollTo(x, y); + if (!pageScrolled(x)) { + mScroller.abortAnimation(); + scrollTo(0, y); + } + } + + // Keep on drawing until the animation has finished. + postInvalidateOnAnimation(); + return; + } + + // Done with scroll, clean up state. + completeScroll(true); + } + + private boolean pageScrolled(int xpos) { + if (mItems.size() == 0) { + mCalledSuper = false; + onPageScrolled(0, 0, 0); + if (!mCalledSuper) { + throw new IllegalStateException( + "onPageScrolled did not call superclass implementation"); + } + return false; + } + final ItemInfo ii = infoForCurrentScrollPosition(); + final int width = getClientWidth(); + final int widthWithMargin = width + mPageMargin; + final float marginOffset = (float) mPageMargin / width; + final int currentPage = ii.position; + final float pageOffset = (((float) xpos / width) - ii.offset) / + (ii.widthFactor + marginOffset); + final int offsetPixels = (int) (pageOffset * widthWithMargin); + + mCalledSuper = false; + onPageScrolled(currentPage, pageOffset, offsetPixels); + if (!mCalledSuper) { + throw new IllegalStateException( + "onPageScrolled did not call superclass implementation"); + } + return true; + } + + /** + * This method will be invoked when the current page is scrolled, either as part + * of a programmatically initiated smooth scroll or a user initiated touch scroll. + * If you override this method you must call through to the superclass implementation + * (e.g. super.onPageScrolled(position, offset, offsetPixels)) before onPageScrolled + * returns. + * + * @param position Position index of the first page currently being displayed. + * Page position+1 will be visible if positionOffset is nonzero. + * @param offset Value from [0, 1) indicating the offset from the page at position. + * @param offsetPixels Value in pixels indicating the offset from position. + */ + protected void onPageScrolled(int position, float offset, int offsetPixels) { + // Offset any decor views if needed - keep them on-screen at all times. + if (mDecorChildCount > 0) { + final int scrollX = getScrollX(); + int paddingLeft = getPaddingLeft(); + int paddingRight = getPaddingRight(); + final int width = getWidth(); + final int childCount = getChildCount(); + for (int i = 0; i < childCount; i++) { + final View child = getChildAt(i); + final LayoutParams lp = (LayoutParams) child.getLayoutParams(); + if (!lp.isDecor) continue; + + final int hgrav = lp.gravity & Gravity.HORIZONTAL_GRAVITY_MASK; + int childLeft = 0; + switch (hgrav) { + default: + childLeft = paddingLeft; + break; + case Gravity.LEFT: + childLeft = paddingLeft; + paddingLeft += child.getWidth(); + break; + case Gravity.CENTER_HORIZONTAL: + childLeft = Math.max((width - child.getMeasuredWidth()) / 2, + paddingLeft); + break; + case Gravity.RIGHT: + childLeft = width - paddingRight - child.getMeasuredWidth(); + paddingRight += child.getMeasuredWidth(); + break; + } + childLeft += scrollX; + + final int childOffset = childLeft - child.getLeft(); + if (childOffset != 0) { + child.offsetLeftAndRight(childOffset); + } + } + } + + if (mOnPageChangeListener != null) { + mOnPageChangeListener.onPageScrolled(position, offset, offsetPixels); + } + if (mInternalPageChangeListener != null) { + mInternalPageChangeListener.onPageScrolled(position, offset, offsetPixels); + } + + if (mPageTransformer != null) { + final int scrollX = getScrollX(); + final int childCount = getChildCount(); + for (int i = 0; i < childCount; i++) { + final View child = getChildAt(i); + final LayoutParams lp = (LayoutParams) child.getLayoutParams(); + + if (lp.isDecor) continue; + + final float transformPos = (float) (child.getLeft() - scrollX) / getClientWidth(); + mPageTransformer.transformPage(child, transformPos); + } + } + + mCalledSuper = true; + } + + private void completeScroll(boolean postEvents) { + boolean needPopulate = mScrollState == SCROLL_STATE_SETTLING; + if (needPopulate) { + // Done with scroll, no longer want to cache view drawing. + setScrollingCacheEnabled(false); + mScroller.abortAnimation(); + int oldX = getScrollX(); + int oldY = getScrollY(); + int x = mScroller.getCurrX(); + int y = mScroller.getCurrY(); + if (oldX != x || oldY != y) { + scrollTo(x, y); + } + } + mPopulatePending = false; + for (int i=0; i<mItems.size(); i++) { + ItemInfo ii = mItems.get(i); + if (ii.scrolling) { + needPopulate = true; + ii.scrolling = false; + } + } + if (needPopulate) { + if (postEvents) { + postOnAnimation(mEndScrollRunnable); + } else { + mEndScrollRunnable.run(); + } + } + } + + private boolean isGutterDrag(float x, float dx) { + return (x < mGutterSize && dx > 0) || (x > getWidth() - mGutterSize && dx < 0); + } + + private void enableLayers(boolean enable) { + final int childCount = getChildCount(); + for (int i = 0; i < childCount; i++) { + final int layerType = enable ? LAYER_TYPE_HARDWARE : LAYER_TYPE_NONE; + getChildAt(i).setLayerType(layerType, null); + } + } + + @Override + public boolean onInterceptTouchEvent(MotionEvent ev) { + /* + * This method JUST determines whether we want to intercept the motion. + * If we return true, onMotionEvent will be called and we do the actual + * scrolling there. + */ + + final int action = ev.getAction() & MotionEvent.ACTION_MASK; + + // Always take care of the touch gesture being complete. + if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) { + // Release the drag. + if (DEBUG) Log.v(TAG, "Intercept done!"); + mIsBeingDragged = false; + mIsUnableToDrag = false; + mActivePointerId = INVALID_POINTER; + if (mVelocityTracker != null) { + mVelocityTracker.recycle(); + mVelocityTracker = null; + } + return false; + } + + // Nothing more to do here if we have decided whether or not we + // are dragging. + if (action != MotionEvent.ACTION_DOWN) { + if (mIsBeingDragged) { + if (DEBUG) Log.v(TAG, "Intercept returning true!"); + return true; + } + if (mIsUnableToDrag) { + if (DEBUG) Log.v(TAG, "Intercept returning false!"); + return false; + } + } + + switch (action) { + case MotionEvent.ACTION_MOVE: { + /* + * mIsBeingDragged == false, otherwise the shortcut would have caught it. Check + * whether the user has moved far enough from his original down touch. + */ + + /* + * Locally do absolute value. mLastMotionY is set to the y value + * of the down event. + */ + final int activePointerId = mActivePointerId; + if (activePointerId == INVALID_POINTER) { + // If we don't have a valid id, the touch down wasn't on content. + break; + } + + final int pointerIndex = ev.findPointerIndex(activePointerId); + final float x = ev.getX(pointerIndex); + final float dx = x - mLastMotionX; + final float xDiff = Math.abs(dx); + final float y = ev.getY(pointerIndex); + final float yDiff = Math.abs(y - mInitialMotionY); + if (DEBUG) Log.v(TAG, "Moved x to " + x + "," + y + " diff=" + xDiff + "," + yDiff); + + if (dx != 0 && !isGutterDrag(mLastMotionX, dx) && + canScroll(this, false, (int) dx, (int) x, (int) y)) { + // Nested view has scrollable area under this point. Let it be handled there. + mLastMotionX = x; + mLastMotionY = y; + mIsUnableToDrag = true; + return false; + } + if (xDiff > mTouchSlop && xDiff * 0.5f > yDiff) { + if (DEBUG) Log.v(TAG, "Starting drag!"); + mIsBeingDragged = true; + requestParentDisallowInterceptTouchEvent(true); + setScrollState(SCROLL_STATE_DRAGGING); + mLastMotionX = dx > 0 ? mInitialMotionX + mTouchSlop : + mInitialMotionX - mTouchSlop; + mLastMotionY = y; + setScrollingCacheEnabled(true); + } else if (yDiff > mTouchSlop) { + // The finger has moved enough in the vertical + // direction to be counted as a drag... abort + // any attempt to drag horizontally, to work correctly + // with children that have scrolling containers. + if (DEBUG) Log.v(TAG, "Starting unable to drag!"); + mIsUnableToDrag = true; + } + if (mIsBeingDragged) { + // Scroll to follow the motion event + if (performDrag(x)) { + postInvalidateOnAnimation(); + } + } + break; + } + + case MotionEvent.ACTION_DOWN: { + /* + * Remember location of down touch. + * ACTION_DOWN always refers to pointer index 0. + */ + mLastMotionX = mInitialMotionX = ev.getX(); + mLastMotionY = mInitialMotionY = ev.getY(); + mActivePointerId = ev.getPointerId(0); + mIsUnableToDrag = false; + + mScroller.computeScrollOffset(); + if (mScrollState == SCROLL_STATE_SETTLING && + Math.abs(mScroller.getFinalX() - mScroller.getCurrX()) > mCloseEnough) { + // Let the user 'catch' the pager as it animates. + mScroller.abortAnimation(); + mPopulatePending = false; + populate(); + mIsBeingDragged = true; + requestParentDisallowInterceptTouchEvent(true); + setScrollState(SCROLL_STATE_DRAGGING); + } else { + completeScroll(false); + mIsBeingDragged = false; + } + + if (DEBUG) Log.v(TAG, "Down at " + mLastMotionX + "," + mLastMotionY + + " mIsBeingDragged=" + mIsBeingDragged + + "mIsUnableToDrag=" + mIsUnableToDrag); + break; + } + + case MotionEvent.ACTION_POINTER_UP: + onSecondaryPointerUp(ev); + break; + } + + if (mVelocityTracker == null) { + mVelocityTracker = VelocityTracker.obtain(); + } + mVelocityTracker.addMovement(ev); + + /* + * The only time we want to intercept motion events is if we are in the + * drag mode. + */ + return mIsBeingDragged; + } + + @Override + public boolean onTouchEvent(MotionEvent ev) { + if (mFakeDragging) { + // A fake drag is in progress already, ignore this real one + // but still eat the touch events. + // (It is likely that the user is multi-touching the screen.) + return true; + } + + if (ev.getAction() == MotionEvent.ACTION_DOWN && ev.getEdgeFlags() != 0) { + // Don't handle edge touches immediately -- they may actually belong to one of our + // descendants. + return false; + } + + if (mAdapter == null || mAdapter.getCount() == 0) { + // Nothing to present or scroll; nothing to touch. + return false; + } + + if (mVelocityTracker == null) { + mVelocityTracker = VelocityTracker.obtain(); + } + mVelocityTracker.addMovement(ev); + + final int action = ev.getAction(); + boolean needsInvalidate = false; + + switch (action & MotionEvent.ACTION_MASK) { + case MotionEvent.ACTION_DOWN: { + mScroller.abortAnimation(); + mPopulatePending = false; + populate(); + + // Remember where the motion event started + mLastMotionX = mInitialMotionX = ev.getX(); + mLastMotionY = mInitialMotionY = ev.getY(); + mActivePointerId = ev.getPointerId(0); + break; + } + case MotionEvent.ACTION_MOVE: + if (!mIsBeingDragged) { + final int pointerIndex = ev.findPointerIndex(mActivePointerId); + final float x = ev.getX(pointerIndex); + final float xDiff = Math.abs(x - mLastMotionX); + final float y = ev.getY(pointerIndex); + final float yDiff = Math.abs(y - mLastMotionY); + if (DEBUG) Log.v(TAG, "Moved x to " + x + "," + y + " diff=" + xDiff + "," + yDiff); + if (xDiff > mTouchSlop && xDiff > yDiff) { + if (DEBUG) Log.v(TAG, "Starting drag!"); + mIsBeingDragged = true; + requestParentDisallowInterceptTouchEvent(true); + mLastMotionX = x - mInitialMotionX > 0 ? mInitialMotionX + mTouchSlop : + mInitialMotionX - mTouchSlop; + mLastMotionY = y; + setScrollState(SCROLL_STATE_DRAGGING); + setScrollingCacheEnabled(true); + + // Disallow Parent Intercept, just in case + ViewParent parent = getParent(); + if (parent != null) { + parent.requestDisallowInterceptTouchEvent(true); + } + } + } + // Not else! Note that mIsBeingDragged can be set above. + if (mIsBeingDragged) { + // Scroll to follow the motion event + final int activePointerIndex = ev.findPointerIndex(mActivePointerId); + final float x = ev.getX(activePointerIndex); + needsInvalidate |= performDrag(x); + } + break; + case MotionEvent.ACTION_UP: + if (mIsBeingDragged) { + final VelocityTracker velocityTracker = mVelocityTracker; + velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity); + int initialVelocity = (int) velocityTracker.getXVelocity(mActivePointerId); + mPopulatePending = true; + final int width = getClientWidth(); + final int scrollX = getScrollX(); + final ItemInfo ii = infoForCurrentScrollPosition(); + final int currentPage = ii.position; + final float pageOffset = (((float) scrollX / width) - ii.offset) / ii.widthFactor; + final int activePointerIndex = + ev.findPointerIndex(mActivePointerId); + final float x = ev.getX(activePointerIndex); + final int totalDelta = (int) (x - mInitialMotionX); + int nextPage = determineTargetPage(currentPage, pageOffset, initialVelocity, + totalDelta); + setCurrentItemInternal(nextPage, true, true, initialVelocity); + + mActivePointerId = INVALID_POINTER; + endDrag(); + mLeftEdge.onRelease(); + mRightEdge.onRelease(); + needsInvalidate = true; + } + break; + case MotionEvent.ACTION_CANCEL: + if (mIsBeingDragged) { + scrollToItem(mCurItem, true, 0, false); + mActivePointerId = INVALID_POINTER; + endDrag(); + mLeftEdge.onRelease(); + mRightEdge.onRelease(); + needsInvalidate = true; + } + break; + case MotionEvent.ACTION_POINTER_DOWN: { + final int index = ev.getActionIndex(); + final float x = ev.getX(index); + mLastMotionX = x; + mActivePointerId = ev.getPointerId(index); + break; + } + case MotionEvent.ACTION_POINTER_UP: + onSecondaryPointerUp(ev); + mLastMotionX = ev.getX(ev.findPointerIndex(mActivePointerId)); + break; + } + if (needsInvalidate) { + postInvalidateOnAnimation(); + } + return true; + } + + private void requestParentDisallowInterceptTouchEvent(boolean disallowIntercept) { + final ViewParent parent = getParent(); + if (parent != null) { + parent.requestDisallowInterceptTouchEvent(disallowIntercept); + } + } + + private boolean performDrag(float x) { + boolean needsInvalidate = false; + + final float deltaX = mLastMotionX - x; + mLastMotionX = x; + + float oldScrollX = getScrollX(); + float scrollX = oldScrollX + deltaX; + final int width = getClientWidth(); + + float leftBound = width * mFirstOffset; + float rightBound = width * mLastOffset; + boolean leftAbsolute = true; + boolean rightAbsolute = true; + + final ItemInfo firstItem = mItems.get(0); + final ItemInfo lastItem = mItems.get(mItems.size() - 1); + if (firstItem.position != 0) { + leftAbsolute = false; + leftBound = firstItem.offset * width; + } + if (lastItem.position != mAdapter.getCount() - 1) { + rightAbsolute = false; + rightBound = lastItem.offset * width; + } + + if (scrollX < leftBound) { + if (leftAbsolute) { + float over = leftBound - scrollX; + mLeftEdge.onPull(Math.abs(over) / width); + needsInvalidate = true; + } + scrollX = leftBound; + } else if (scrollX > rightBound) { + if (rightAbsolute) { + float over = scrollX - rightBound; + mRightEdge.onPull(Math.abs(over) / width); + needsInvalidate = true; + } + scrollX = rightBound; + } + // Don't lose the rounded component + mLastMotionX += scrollX - (int) scrollX; + scrollTo((int) scrollX, getScrollY()); + pageScrolled((int) scrollX); + + return needsInvalidate; + } + + /** + * @return Info about the page at the current scroll position. + * This can be synthetic for a missing middle page; the 'object' field can be null. + */ + private ItemInfo infoForCurrentScrollPosition() { + final int width = getClientWidth(); + final float scrollOffset = width > 0 ? (float) getScrollX() / width : 0; + final float marginOffset = width > 0 ? (float) mPageMargin / width : 0; + int lastPos = -1; + float lastOffset = 0.f; + float lastWidth = 0.f; + boolean first = true; + + ItemInfo lastItem = null; + for (int i = 0; i < mItems.size(); i++) { + ItemInfo ii = mItems.get(i); + float offset; + if (!first && ii.position != lastPos + 1) { + // Create a synthetic item for a missing page. + ii = mTempItem; + ii.offset = lastOffset + lastWidth + marginOffset; + ii.position = lastPos + 1; + ii.widthFactor = mAdapter.getPageWidth(ii.position); + i--; + } + offset = ii.offset; + + final float leftBound = offset; + final float rightBound = offset + ii.widthFactor + marginOffset; + if (first || scrollOffset >= leftBound) { + if (scrollOffset < rightBound || i == mItems.size() - 1) { + return ii; + } + } else { + return lastItem; + } + first = false; + lastPos = ii.position; + lastOffset = offset; + lastWidth = ii.widthFactor; + lastItem = ii; + } + + return lastItem; + } + + private int determineTargetPage(int currentPage, float pageOffset, int velocity, int deltaX) { + int targetPage; + if (Math.abs(deltaX) > mFlingDistance && Math.abs(velocity) > mMinimumVelocity) { + targetPage = velocity > 0 ? currentPage : currentPage + 1; + } else { + final float truncator = currentPage >= mCurItem ? 0.4f : 0.6f; + targetPage = (int) (currentPage + pageOffset + truncator); + } + + if (mItems.size() > 0) { + final ItemInfo firstItem = mItems.get(0); + final ItemInfo lastItem = mItems.get(mItems.size() - 1); + + // Only let the user target pages we have items for + targetPage = Math.max(firstItem.position, Math.min(targetPage, lastItem.position)); + } + + return targetPage; + } + + @Override + public void draw(Canvas canvas) { + super.draw(canvas); + boolean needsInvalidate = false; + + final int overScrollMode = getOverScrollMode(); + if (overScrollMode == View.OVER_SCROLL_ALWAYS || + (overScrollMode == View.OVER_SCROLL_IF_CONTENT_SCROLLS && + mAdapter != null && mAdapter.getCount() > 1)) { + if (!mLeftEdge.isFinished()) { + final int restoreCount = canvas.save(); + final int height = getHeight() - getPaddingTop() - getPaddingBottom(); + final int width = getWidth(); + + canvas.rotate(270); + canvas.translate(-height + getPaddingTop(), mFirstOffset * width); + mLeftEdge.setSize(height, width); + needsInvalidate |= mLeftEdge.draw(canvas); + canvas.restoreToCount(restoreCount); + } + if (!mRightEdge.isFinished()) { + final int restoreCount = canvas.save(); + final int width = getWidth(); + final int height = getHeight() - getPaddingTop() - getPaddingBottom(); + + canvas.rotate(90); + canvas.translate(-getPaddingTop(), -(mLastOffset + 1) * width); + mRightEdge.setSize(height, width); + needsInvalidate |= mRightEdge.draw(canvas); + canvas.restoreToCount(restoreCount); + } + } else { + mLeftEdge.finish(); + mRightEdge.finish(); + } + + if (needsInvalidate) { + // Keep animating + postInvalidateOnAnimation(); + } + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + + // Draw the margin drawable between pages if needed. + if (mPageMargin > 0 && mMarginDrawable != null && mItems.size() > 0 && mAdapter != null) { + final int scrollX = getScrollX(); + final int width = getWidth(); + + final float marginOffset = (float) mPageMargin / width; + int itemIndex = 0; + ItemInfo ii = mItems.get(0); + float offset = ii.offset; + final int itemCount = mItems.size(); + final int firstPos = ii.position; + final int lastPos = mItems.get(itemCount - 1).position; + for (int pos = firstPos; pos < lastPos; pos++) { + while (pos > ii.position && itemIndex < itemCount) { + ii = mItems.get(++itemIndex); + } + + float drawAt; + if (pos == ii.position) { + drawAt = (ii.offset + ii.widthFactor) * width; + offset = ii.offset + ii.widthFactor + marginOffset; + } else { + float widthFactor = mAdapter.getPageWidth(pos); + drawAt = (offset + widthFactor) * width; + offset += widthFactor + marginOffset; + } + + if (drawAt + mPageMargin > scrollX) { + mMarginDrawable.setBounds((int) drawAt, mTopPageBounds, + (int) (drawAt + mPageMargin + 0.5f), mBottomPageBounds); + mMarginDrawable.draw(canvas); + } + + if (drawAt > scrollX + width) { + break; // No more visible, no sense in continuing + } + } + } + } + + /** + * Start a fake drag of the pager. + * + * <p>A fake drag can be useful if you want to synchronize the motion of the ViewPager + * with the touch scrolling of another view, while still letting the ViewPager + * control the snapping motion and fling behavior. (e.g. parallax-scrolling tabs.) + * Call {@link #fakeDragBy(float)} to simulate the actual drag motion. Call + * {@link #endFakeDrag()} to complete the fake drag and fling as necessary. + * + * <p>During a fake drag the ViewPager will ignore all touch events. If a real drag + * is already in progress, this method will return false. + * + * @return true if the fake drag began successfully, false if it could not be started. + * + * @see #fakeDragBy(float) + * @see #endFakeDrag() + */ + public boolean beginFakeDrag() { + if (mIsBeingDragged) { + return false; + } + mFakeDragging = true; + setScrollState(SCROLL_STATE_DRAGGING); + mInitialMotionX = mLastMotionX = 0; + if (mVelocityTracker == null) { + mVelocityTracker = VelocityTracker.obtain(); + } else { + mVelocityTracker.clear(); + } + final long time = SystemClock.uptimeMillis(); + final MotionEvent ev = MotionEvent.obtain(time, time, MotionEvent.ACTION_DOWN, 0, 0, 0); + mVelocityTracker.addMovement(ev); + ev.recycle(); + mFakeDragBeginTime = time; + return true; + } + + /** + * End a fake drag of the pager. + * + * @see #beginFakeDrag() + * @see #fakeDragBy(float) + */ + public void endFakeDrag() { + if (!mFakeDragging) { + throw new IllegalStateException("No fake drag in progress. Call beginFakeDrag first."); + } + + final VelocityTracker velocityTracker = mVelocityTracker; + velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity); + int initialVelocity = (int) velocityTracker.getXVelocity(mActivePointerId); + mPopulatePending = true; + final int width = getClientWidth(); + final int scrollX = getScrollX(); + final ItemInfo ii = infoForCurrentScrollPosition(); + final int currentPage = ii.position; + final float pageOffset = (((float) scrollX / width) - ii.offset) / ii.widthFactor; + final int totalDelta = (int) (mLastMotionX - mInitialMotionX); + int nextPage = determineTargetPage(currentPage, pageOffset, initialVelocity, + totalDelta); + setCurrentItemInternal(nextPage, true, true, initialVelocity); + endDrag(); + + mFakeDragging = false; + } + + /** + * Fake drag by an offset in pixels. You must have called {@link #beginFakeDrag()} first. + * + * @param xOffset Offset in pixels to drag by. + * @see #beginFakeDrag() + * @see #endFakeDrag() + */ + public void fakeDragBy(float xOffset) { + if (!mFakeDragging) { + throw new IllegalStateException("No fake drag in progress. Call beginFakeDrag first."); + } + + mLastMotionX += xOffset; + + float oldScrollX = getScrollX(); + float scrollX = oldScrollX - xOffset; + final int width = getClientWidth(); + + float leftBound = width * mFirstOffset; + float rightBound = width * mLastOffset; + + final ItemInfo firstItem = mItems.get(0); + final ItemInfo lastItem = mItems.get(mItems.size() - 1); + if (firstItem.position != 0) { + leftBound = firstItem.offset * width; + } + if (lastItem.position != mAdapter.getCount() - 1) { + rightBound = lastItem.offset * width; + } + + if (scrollX < leftBound) { + scrollX = leftBound; + } else if (scrollX > rightBound) { + scrollX = rightBound; + } + // Don't lose the rounded component + mLastMotionX += scrollX - (int) scrollX; + scrollTo((int) scrollX, getScrollY()); + pageScrolled((int) scrollX); + + // Synthesize an event for the VelocityTracker. + final long time = SystemClock.uptimeMillis(); + final MotionEvent ev = MotionEvent.obtain(mFakeDragBeginTime, time, MotionEvent.ACTION_MOVE, + mLastMotionX, 0, 0); + mVelocityTracker.addMovement(ev); + ev.recycle(); + } + + /** + * Returns true if a fake drag is in progress. + * + * @return true if currently in a fake drag, false otherwise. + * + * @see #beginFakeDrag() + * @see #fakeDragBy(float) + * @see #endFakeDrag() + */ + public boolean isFakeDragging() { + return mFakeDragging; + } + + private void onSecondaryPointerUp(MotionEvent ev) { + final int pointerIndex = ev.getActionIndex(); + final int pointerId = ev.getPointerId(pointerIndex); + if (pointerId == mActivePointerId) { + // This was our active pointer going up. Choose a new + // active pointer and adjust accordingly. + final int newPointerIndex = pointerIndex == 0 ? 1 : 0; + mLastMotionX = ev.getX(newPointerIndex); + mActivePointerId = ev.getPointerId(newPointerIndex); + if (mVelocityTracker != null) { + mVelocityTracker.clear(); + } + } + } + + private void endDrag() { + mIsBeingDragged = false; + mIsUnableToDrag = false; + + if (mVelocityTracker != null) { + mVelocityTracker.recycle(); + mVelocityTracker = null; + } + } + + private void setScrollingCacheEnabled(boolean enabled) { + if (mScrollingCacheEnabled != enabled) { + mScrollingCacheEnabled = enabled; + if (USE_CACHE) { + final int size = getChildCount(); + for (int i = 0; i < size; ++i) { + final View child = getChildAt(i); + if (child.getVisibility() != GONE) { + child.setDrawingCacheEnabled(enabled); + } + } + } + } + } + + public boolean canScrollHorizontally(int direction) { + if (mAdapter == null) { + return false; + } + + final int width = getClientWidth(); + final int scrollX = getScrollX(); + if (direction < 0) { + return (scrollX > (int) (width * mFirstOffset)); + } else if (direction > 0) { + return (scrollX < (int) (width * mLastOffset)); + } else { + return false; + } + } + + /** + * Tests scrollability within child views of v given a delta of dx. + * + * @param v View to test for horizontal scrollability + * @param checkV Whether the view v passed should itself be checked for scrollability (true), + * or just its children (false). + * @param dx Delta scrolled in pixels + * @param x X coordinate of the active touch point + * @param y Y coordinate of the active touch point + * @return true if child views of v can be scrolled by delta of dx. + */ + protected boolean canScroll(View v, boolean checkV, int dx, int x, int y) { + if (v instanceof ViewGroup) { + final ViewGroup group = (ViewGroup) v; + final int scrollX = v.getScrollX(); + final int scrollY = v.getScrollY(); + final int count = group.getChildCount(); + // Count backwards - let topmost views consume scroll distance first. + for (int i = count - 1; i >= 0; i--) { + // TODO: Add versioned support here for transformed views. + // This will not work for transformed views in Honeycomb+ + final View child = group.getChildAt(i); + if (x + scrollX >= child.getLeft() && x + scrollX < child.getRight() && + y + scrollY >= child.getTop() && y + scrollY < child.getBottom() && + canScroll(child, true, dx, x + scrollX - child.getLeft(), + y + scrollY - child.getTop())) { + return true; + } + } + } + + return checkV && v.canScrollHorizontally(-dx); + } + + @Override + public boolean dispatchKeyEvent(KeyEvent event) { + // Let the focused view and/or our descendants get the key first + return super.dispatchKeyEvent(event) || executeKeyEvent(event); + } + + /** + * You can call this function yourself to have the scroll view perform + * scrolling from a key event, just as if the event had been dispatched to + * it by the view hierarchy. + * + * @param event The key event to execute. + * @return Return true if the event was handled, else false. + */ + public boolean executeKeyEvent(KeyEvent event) { + boolean handled = false; + if (event.getAction() == KeyEvent.ACTION_DOWN) { + switch (event.getKeyCode()) { + case KeyEvent.KEYCODE_DPAD_LEFT: + handled = arrowScroll(FOCUS_LEFT); + break; + case KeyEvent.KEYCODE_DPAD_RIGHT: + handled = arrowScroll(FOCUS_RIGHT); + break; + case KeyEvent.KEYCODE_TAB: + if (event.hasNoModifiers()) { + handled = arrowScroll(FOCUS_FORWARD); + } else if (event.hasModifiers(KeyEvent.META_SHIFT_ON)) { + handled = arrowScroll(FOCUS_BACKWARD); + } + break; + } + } + return handled; + } + + public boolean arrowScroll(int direction) { + View currentFocused = findFocus(); + if (currentFocused == this) { + currentFocused = null; + } else if (currentFocused != null) { + boolean isChild = false; + for (ViewParent parent = currentFocused.getParent(); parent instanceof ViewGroup; + parent = parent.getParent()) { + if (parent == this) { + isChild = true; + break; + } + } + if (!isChild) { + // This would cause the focus search down below to fail in fun ways. + final StringBuilder sb = new StringBuilder(); + sb.append(currentFocused.getClass().getSimpleName()); + for (ViewParent parent = currentFocused.getParent(); parent instanceof ViewGroup; + parent = parent.getParent()) { + sb.append(" => ").append(parent.getClass().getSimpleName()); + } + Log.e(TAG, "arrowScroll tried to find focus based on non-child " + + "current focused view " + sb.toString()); + currentFocused = null; + } + } + + boolean handled = false; + + View nextFocused = FocusFinder.getInstance().findNextFocus(this, currentFocused, + direction); + if (nextFocused != null && nextFocused != currentFocused) { + if (direction == View.FOCUS_LEFT) { + // If there is nothing to the left, or this is causing us to + // jump to the right, then what we really want to do is page left. + final int nextLeft = getChildRectInPagerCoordinates(mTempRect, nextFocused).left; + final int currLeft = getChildRectInPagerCoordinates(mTempRect, currentFocused).left; + if (currentFocused != null && nextLeft >= currLeft) { + handled = pageLeft(); + } else { + handled = nextFocused.requestFocus(); + } + } else if (direction == View.FOCUS_RIGHT) { + // If there is nothing to the right, or this is causing us to + // jump to the left, then what we really want to do is page right. + final int nextLeft = getChildRectInPagerCoordinates(mTempRect, nextFocused).left; + final int currLeft = getChildRectInPagerCoordinates(mTempRect, currentFocused).left; + if (currentFocused != null && nextLeft <= currLeft) { + handled = pageRight(); + } else { + handled = nextFocused.requestFocus(); + } + } + } else if (direction == FOCUS_LEFT || direction == FOCUS_BACKWARD) { + // Trying to move left and nothing there; try to page. + handled = pageLeft(); + } else if (direction == FOCUS_RIGHT || direction == FOCUS_FORWARD) { + // Trying to move right and nothing there; try to page. + handled = pageRight(); + } + if (handled) { + playSoundEffect(SoundEffectConstants.getContantForFocusDirection(direction)); + } + return handled; + } + + private Rect getChildRectInPagerCoordinates(Rect outRect, View child) { + if (outRect == null) { + outRect = new Rect(); + } + if (child == null) { + outRect.set(0, 0, 0, 0); + return outRect; + } + outRect.left = child.getLeft(); + outRect.right = child.getRight(); + outRect.top = child.getTop(); + outRect.bottom = child.getBottom(); + + ViewParent parent = child.getParent(); + while (parent instanceof ViewGroup && parent != this) { + final ViewGroup group = (ViewGroup) parent; + outRect.left += group.getLeft(); + outRect.right += group.getRight(); + outRect.top += group.getTop(); + outRect.bottom += group.getBottom(); + + parent = group.getParent(); + } + return outRect; + } + + boolean pageLeft() { + if (mCurItem > 0) { + setCurrentItem(mCurItem-1, true); + return true; + } + return false; + } + + boolean pageRight() { + if (mAdapter != null && mCurItem < (mAdapter.getCount()-1)) { + setCurrentItem(mCurItem+1, true); + return true; + } + return false; + } + + /** + * We only want the current page that is being shown to be focusable. + */ + @Override + public void addFocusables(ArrayList<View> views, int direction, int focusableMode) { + final int focusableCount = views.size(); + + final int descendantFocusability = getDescendantFocusability(); + + if (descendantFocusability != FOCUS_BLOCK_DESCENDANTS) { + for (int i = 0; i < getChildCount(); i++) { + final View child = getChildAt(i); + if (child.getVisibility() == VISIBLE) { + ItemInfo ii = infoForChild(child); + if (ii != null && ii.position == mCurItem) { + child.addFocusables(views, direction, focusableMode); + } + } + } + } + + // we add ourselves (if focusable) in all cases except for when we are + // FOCUS_AFTER_DESCENDANTS and there are some descendants focusable. this is + // to avoid the focus search finding layouts when a more precise search + // among the focusable children would be more interesting. + if ( + descendantFocusability != FOCUS_AFTER_DESCENDANTS || + // No focusable descendants + (focusableCount == views.size())) { + // Note that we can't call the superclass here, because it will + // add all views in. So we need to do the same thing View does. + if (!isFocusable()) { + return; + } + if ((focusableMode & FOCUSABLES_TOUCH_MODE) == FOCUSABLES_TOUCH_MODE && + isInTouchMode() && !isFocusableInTouchMode()) { + return; + } + if (views != null) { + views.add(this); + } + } + } + + /** + * We only want the current page that is being shown to be touchable. + */ + @Override + public void addTouchables(ArrayList<View> views) { + // Note that we don't call super.addTouchables(), which means that + // we don't call View.addTouchables(). This is okay because a ViewPager + // is itself not touchable. + for (int i = 0; i < getChildCount(); i++) { + final View child = getChildAt(i); + if (child.getVisibility() == VISIBLE) { + ItemInfo ii = infoForChild(child); + if (ii != null && ii.position == mCurItem) { + child.addTouchables(views); + } + } + } + } + + /** + * We only want the current page that is being shown to be focusable. + */ + @Override + protected boolean onRequestFocusInDescendants(int direction, + Rect previouslyFocusedRect) { + int index; + int increment; + int end; + int count = getChildCount(); + if ((direction & FOCUS_FORWARD) != 0) { + index = 0; + increment = 1; + end = count; + } else { + index = count - 1; + increment = -1; + end = -1; + } + for (int i = index; i != end; i += increment) { + View child = getChildAt(i); + if (child.getVisibility() == VISIBLE) { + ItemInfo ii = infoForChild(child); + if (ii != null && ii.position == mCurItem) { + if (child.requestFocus(direction, previouslyFocusedRect)) { + return true; + } + } + } + } + return false; + } + + @Override + public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { + // Dispatch scroll events from this ViewPager. + if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_SCROLLED) { + return super.dispatchPopulateAccessibilityEvent(event); + } + + // Dispatch all other accessibility events from the current page. + final int childCount = getChildCount(); + for (int i = 0; i < childCount; i++) { + final View child = getChildAt(i); + if (child.getVisibility() == VISIBLE) { + final ItemInfo ii = infoForChild(child); + if (ii != null && ii.position == mCurItem && + child.dispatchPopulateAccessibilityEvent(event)) { + return true; + } + } + } + + return false; + } + + @Override + protected ViewGroup.LayoutParams generateDefaultLayoutParams() { + return new LayoutParams(); + } + + @Override + protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) { + return generateDefaultLayoutParams(); + } + + @Override + protected boolean checkLayoutParams(ViewGroup.LayoutParams p) { + return p instanceof LayoutParams && super.checkLayoutParams(p); + } + + @Override + public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) { + return new LayoutParams(getContext(), attrs); + } + + class MyAccessibilityDelegate extends AccessibilityDelegate { + + @Override + public void onInitializeAccessibilityEvent(View host, AccessibilityEvent event) { + super.onInitializeAccessibilityEvent(host, event); + event.setClassName(ViewPager.class.getName()); + final AccessibilityRecord record = AccessibilityRecord.obtain(); + record.setScrollable(canScroll()); + if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_SCROLLED + && mAdapter != null) { + record.setItemCount(mAdapter.getCount()); + record.setFromIndex(mCurItem); + record.setToIndex(mCurItem); + } + } + + @Override + public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) { + super.onInitializeAccessibilityNodeInfo(host, info); + info.setClassName(ViewPager.class.getName()); + info.setScrollable(canScroll()); + if (canScrollHorizontally(1)) { + info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD); + } + if (canScrollHorizontally(-1)) { + info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD); + } + } + + @Override + public boolean performAccessibilityAction(View host, int action, Bundle args) { + if (super.performAccessibilityAction(host, action, args)) { + return true; + } + switch (action) { + case AccessibilityNodeInfo.ACTION_SCROLL_FORWARD: { + if (canScrollHorizontally(1)) { + setCurrentItem(mCurItem + 1); + return true; + } + } return false; + case AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD: { + if (canScrollHorizontally(-1)) { + setCurrentItem(mCurItem - 1); + return true; + } + } return false; + } + return false; + } + + private boolean canScroll() { + return (mAdapter != null) && (mAdapter.getCount() > 1); + } + } + + private class PagerObserver extends DataSetObserver { + @Override + public void onChanged() { + dataSetChanged(); + } + @Override + public void onInvalidated() { + dataSetChanged(); + } + } + + /** + * Layout parameters that should be supplied for views added to a + * ViewPager. + */ + public static class LayoutParams extends ViewGroup.LayoutParams { + /** + * true if this view is a decoration on the pager itself and not + * a view supplied by the adapter. + */ + public boolean isDecor; + + /** + * Gravity setting for use on decor views only: + * Where to position the view page within the overall ViewPager + * container; constants are defined in {@link android.view.Gravity}. + */ + public int gravity; + + /** + * Width as a 0-1 multiplier of the measured pager width + */ + float widthFactor = 0.f; + + /** + * true if this view was added during layout and needs to be measured + * before being positioned. + */ + boolean needsMeasure; + + /** + * Adapter position this view is for if !isDecor + */ + int position; + + /** + * Current child index within the ViewPager that this view occupies + */ + int childIndex; + + public LayoutParams() { + super(FILL_PARENT, FILL_PARENT); + } + + public LayoutParams(Context context, AttributeSet attrs) { + super(context, attrs); + + final TypedArray a = context.obtainStyledAttributes(attrs, LAYOUT_ATTRS); + gravity = a.getInteger(0, Gravity.TOP); + a.recycle(); + } + } + + static class ViewPositionComparator implements Comparator<View> { + @Override + public int compare(View lhs, View rhs) { + final LayoutParams llp = (LayoutParams) lhs.getLayoutParams(); + final LayoutParams rlp = (LayoutParams) rhs.getLayoutParams(); + if (llp.isDecor != rlp.isDecor) { + return llp.isDecor ? 1 : -1; + } + return llp.position - rlp.position; + } + } +} diff --git a/core/jni/Android.mk b/core/jni/Android.mk index 28f1a3a45fd4..9d763350da25 100644 --- a/core/jni/Android.mk +++ b/core/jni/Android.mk @@ -41,25 +41,25 @@ LOCAL_SRC_FILES:= \ android_database_SQLiteDebug.cpp \ android_emoji_EmojiFactory.cpp \ android_view_DisplayEventReceiver.cpp \ - android_view_Surface.cpp \ - android_view_SurfaceControl.cpp \ - android_view_SurfaceSession.cpp \ - android_view_TextureView.cpp \ + android_view_DisplayListCanvas.cpp \ + android_view_GraphicBuffer.cpp \ + android_view_HardwareLayer.cpp \ android_view_InputChannel.cpp \ android_view_InputDevice.cpp \ android_view_InputEventReceiver.cpp \ android_view_InputEventSender.cpp \ android_view_InputQueue.cpp \ - android_view_KeyEvent.cpp \ android_view_KeyCharacterMap.cpp \ - android_view_GraphicBuffer.cpp \ - android_view_GLES20Canvas.cpp \ - android_view_HardwareLayer.cpp \ - android_view_ThreadedRenderer.cpp \ + android_view_KeyEvent.cpp \ android_view_MotionEvent.cpp \ android_view_PointerIcon.cpp \ android_view_RenderNode.cpp \ android_view_RenderNodeAnimator.cpp \ + android_view_Surface.cpp \ + android_view_SurfaceControl.cpp \ + android_view_SurfaceSession.cpp \ + android_view_TextureView.cpp \ + android_view_ThreadedRenderer.cpp \ android_view_VelocityTracker.cpp \ android_text_AndroidCharacter.cpp \ android_text_AndroidBidi.cpp \ @@ -147,7 +147,7 @@ LOCAL_SRC_FILES:= \ android_hardware_location_ActivityRecognitionHardware.cpp \ android_util_FileObserver.cpp \ android/opengl/poly_clip.cpp.arm \ - android/opengl/util.cpp.arm \ + android/opengl/util.cpp \ android_server_FingerprintManager.cpp \ android_server_NetworkManagementSocketTagger.cpp \ android_server_Watchdog.cpp \ diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp index 008f87733178..ad52e3f696dd 100644 --- a/core/jni/AndroidRuntime.cpp +++ b/core/jni/AndroidRuntime.cpp @@ -127,16 +127,16 @@ extern int register_android_graphics_pdf_PdfDocument(JNIEnv* env); extern int register_android_graphics_pdf_PdfEditor(JNIEnv* env); extern int register_android_graphics_pdf_PdfRenderer(JNIEnv* env); extern int register_android_view_DisplayEventReceiver(JNIEnv* env); -extern int register_android_view_RenderNode(JNIEnv* env); -extern int register_android_view_RenderNodeAnimator(JNIEnv* env); +extern int register_android_view_DisplayListCanvas(JNIEnv* env); extern int register_android_view_GraphicBuffer(JNIEnv* env); -extern int register_android_view_GLES20Canvas(JNIEnv* env); extern int register_android_view_HardwareLayer(JNIEnv* env); -extern int register_android_view_ThreadedRenderer(JNIEnv* env); +extern int register_android_view_RenderNode(JNIEnv* env); +extern int register_android_view_RenderNodeAnimator(JNIEnv* env); extern int register_android_view_Surface(JNIEnv* env); extern int register_android_view_SurfaceControl(JNIEnv* env); extern int register_android_view_SurfaceSession(JNIEnv* env); extern int register_android_view_TextureView(JNIEnv* env); +extern int register_android_view_ThreadedRenderer(JNIEnv* env); extern int register_com_android_internal_view_animation_NativeInterpolatorFactoryHelper(JNIEnv *env); extern int register_android_database_CursorWindow(JNIEnv* env); extern int register_android_database_SQLiteConnection(JNIEnv* env); @@ -546,6 +546,9 @@ int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv) char heapgrowthlimitOptsBuf[sizeof("-XX:HeapGrowthLimit=")-1 + PROPERTY_VALUE_MAX]; char heapminfreeOptsBuf[sizeof("-XX:HeapMinFree=")-1 + PROPERTY_VALUE_MAX]; char heapmaxfreeOptsBuf[sizeof("-XX:HeapMaxFree=")-1 + PROPERTY_VALUE_MAX]; + char usejitOptsBuf[sizeof("-Xusejit:")-1 + PROPERTY_VALUE_MAX]; + char jitcodecachesizeOptsBuf[sizeof("-Xjitcodecachesize:")-1 + PROPERTY_VALUE_MAX]; + char jitthresholdOptsBuf[sizeof("-Xjitthreshold:")-1 + PROPERTY_VALUE_MAX]; char gctypeOptsBuf[sizeof("-Xgc:")-1 + PROPERTY_VALUE_MAX]; char backgroundgcOptsBuf[sizeof("-XX:BackgroundGC=")-1 + PROPERTY_VALUE_MAX]; char heaptargetutilizationOptsBuf[sizeof("-XX:HeapTargetUtilization=")-1 + PROPERTY_VALUE_MAX]; @@ -642,6 +645,13 @@ int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv) heaptargetutilizationOptsBuf, "-XX:HeapTargetUtilization="); + /* + * JIT related options. + */ + parseRuntimeOption("dalvik.vm.usejit", usejitOptsBuf, "-Xusejit:"); + parseRuntimeOption("dalvik.vm.jitcodecachesize", jitcodecachesizeOptsBuf, "-Xjitcodecachesize:"); + parseRuntimeOption("dalvik.vm.jitthreshold", jitthresholdOptsBuf, "-Xjitthreshold:"); + property_get("ro.config.low_ram", propBuf, ""); if (strcmp(propBuf, "true") == 0) { addOption("-XX:LowMemoryMode"); @@ -1169,7 +1179,7 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_android_view_RenderNode), REG_JNI(register_android_view_RenderNodeAnimator), REG_JNI(register_android_view_GraphicBuffer), - REG_JNI(register_android_view_GLES20Canvas), + REG_JNI(register_android_view_DisplayListCanvas), REG_JNI(register_android_view_HardwareLayer), REG_JNI(register_android_view_ThreadedRenderer), REG_JNI(register_android_view_Surface), diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp index 672008d7582a..6a50b52e7148 100644 --- a/core/jni/android/graphics/BitmapFactory.cpp +++ b/core/jni/android/graphics/BitmapFactory.cpp @@ -41,7 +41,6 @@ jfieldID gOptions_mimeFieldID; jfieldID gOptions_mCancelID; jfieldID gOptions_bitmapFieldID; -jfieldID gBitmap_nativeBitmapFieldID; jfieldID gBitmap_ninePatchInsetsFieldID; jclass gInsetStruct_class; @@ -262,7 +261,7 @@ static jobject doDecode(JNIEnv* env, SkStreamRewindable* stream, jobject padding SkBitmap* outputBitmap = NULL; unsigned int existingBufferSize = 0; if (javaBitmap != NULL) { - outputBitmap = (SkBitmap*) env->GetLongField(javaBitmap, gBitmap_nativeBitmapFieldID); + outputBitmap = GraphicsJNI::getSkBitmap(env, javaBitmap); if (outputBitmap->isImmutable()) { ALOGW("Unable to reuse an immutable bitmap as an image decoder target."); javaBitmap = NULL; @@ -601,7 +600,6 @@ int register_android_graphics_BitmapFactory(JNIEnv* env) { gOptions_mCancelID = GetFieldIDOrDie(env, options_class, "mCancel", "Z"); jclass bitmap_class = FindClassOrDie(env, "android/graphics/Bitmap"); - gBitmap_nativeBitmapFieldID = GetFieldIDOrDie(env, bitmap_class, "mNativeBitmap", "J"); gBitmap_ninePatchInsetsFieldID = GetFieldIDOrDie(env, bitmap_class, "mNinePatchInsets", "Landroid/graphics/NinePatch$InsetStruct;"); diff --git a/core/jni/android/graphics/BitmapRegionDecoder.cpp b/core/jni/android/graphics/BitmapRegionDecoder.cpp index 90a7f69e637b..04afe3e8cd82 100644 --- a/core/jni/android/graphics/BitmapRegionDecoder.cpp +++ b/core/jni/android/graphics/BitmapRegionDecoder.cpp @@ -213,7 +213,7 @@ static jobject nativeDecodeRegion(JNIEnv* env, jobject, jlong brdHandle, if (tileBitmap != NULL) { // Re-use bitmap. - bitmap = GraphicsJNI::getNativeBitmap(env, tileBitmap); + bitmap = GraphicsJNI::getSkBitmap(env, tileBitmap); } if (bitmap == NULL) { bitmap = new SkBitmap; diff --git a/core/jni/android/graphics/Graphics.cpp b/core/jni/android/graphics/Graphics.cpp index dde1393a2a57..07479699ce67 100644 --- a/core/jni/android/graphics/Graphics.cpp +++ b/core/jni/android/graphics/Graphics.cpp @@ -154,7 +154,7 @@ static jfieldID gPointF_xFieldID; static jfieldID gPointF_yFieldID; static jclass gBitmap_class; -static jfieldID gBitmap_nativeInstanceID; +static jfieldID gBitmap_skBitmapPtr; static jmethodID gBitmap_constructorMethodID; static jmethodID gBitmap_reinitMethodID; static jmethodID gBitmap_getAllocationByteCountMethodID; @@ -338,11 +338,11 @@ SkColorType GraphicsJNI::legacyBitmapConfigToColorType(jint legacyConfig) { return static_cast<SkColorType>(gConfig2ColorType[legacyConfig]); } -SkBitmap* GraphicsJNI::getNativeBitmap(JNIEnv* env, jobject bitmap) { +SkBitmap* GraphicsJNI::getSkBitmap(JNIEnv* env, jobject bitmap) { SkASSERT(env); SkASSERT(bitmap); SkASSERT(env->IsInstanceOf(bitmap, gBitmap_class)); - jlong bitmapHandle = env->GetLongField(bitmap, gBitmap_nativeInstanceID); + jlong bitmapHandle = env->GetLongField(bitmap, gBitmap_skBitmapPtr); SkBitmap* b = reinterpret_cast<SkBitmap*>(bitmapHandle); SkASSERT(b); return b; @@ -676,7 +676,7 @@ int register_android_graphics_Graphics(JNIEnv* env) gPointF_yFieldID = getFieldIDCheck(env, gPointF_class, "y", "F"); gBitmap_class = make_globalref(env, "android/graphics/Bitmap"); - gBitmap_nativeInstanceID = getFieldIDCheck(env, gBitmap_class, "mNativeBitmap", "J"); + gBitmap_skBitmapPtr = getFieldIDCheck(env, gBitmap_class, "mSkBitmapPtr", "J"); gBitmap_constructorMethodID = env->GetMethodID(gBitmap_class, "<init>", "(J[BIIIZZ[BLandroid/graphics/NinePatch$InsetStruct;)V"); gBitmap_reinitMethodID = env->GetMethodID(gBitmap_class, "reinit", "(IIZ)V"); gBitmap_getAllocationByteCountMethodID = env->GetMethodID(gBitmap_class, "getAllocationByteCount", "()I"); diff --git a/core/jni/android/graphics/GraphicsJNI.h b/core/jni/android/graphics/GraphicsJNI.h index a202c38e5018..422d3f1a6646 100644 --- a/core/jni/android/graphics/GraphicsJNI.h +++ b/core/jni/android/graphics/GraphicsJNI.h @@ -48,7 +48,7 @@ public: static void point_to_jpointf(const SkPoint& point, JNIEnv*, jobject jpointf); static SkCanvas* getNativeCanvas(JNIEnv*, jobject canvas); - static SkBitmap* getNativeBitmap(JNIEnv*, jobject bitmap); + static SkBitmap* getSkBitmap(JNIEnv*, jobject bitmap); static SkRegion* getNativeRegion(JNIEnv*, jobject region); // Given the 'native' long held by the Rasterizer.java object, return a diff --git a/core/jni/android/opengl/util.cpp b/core/jni/android/opengl/util.cpp index 461507ffca6c..5c2d0d0bb5cb 100644 --- a/core/jni/android/opengl/util.cpp +++ b/core/jni/android/opengl/util.cpp @@ -16,6 +16,7 @@ #include "jni.h" #include "JNIHelp.h" +#include "GraphicsJNI.h" #include <math.h> #include <stdio.h> @@ -149,10 +150,6 @@ int visibilityTest(float* pWS, float* pPositions, int positionsLength, return result; } -static void doThrowIAE(JNIEnv* env, const char* msg) { - jniThrowException(env, "java/lang/IllegalArgumentException", msg); -} - template<class JArray, class T> class ArrayHelper { public: @@ -548,14 +545,6 @@ void util_multiplyMV(JNIEnv *env, jclass clazz, // --------------------------------------------------------------------------- -static jfieldID nativeBitmapID = 0; - -void nativeUtilsClassInit(JNIEnv *env, jclass clazz) -{ - jclass bitmapClass = env->FindClass("android/graphics/Bitmap"); - nativeBitmapID = env->GetFieldID(bitmapClass, "mNativeBitmap", "J"); -} - extern void setGLDebugLevel(int level); void setTracingLevel(JNIEnv *env, jclass clazz, jint level) { @@ -629,16 +618,14 @@ static int getType(SkColorType colorType) static jint util_getInternalFormat(JNIEnv *env, jclass clazz, jobject jbitmap) { - SkBitmap const * nativeBitmap = - (SkBitmap const *)env->GetLongField(jbitmap, nativeBitmapID); + SkBitmap const * nativeBitmap = GraphicsJNI::getSkBitmap(env, jbitmap); return getInternalFormat(nativeBitmap->colorType()); } static jint util_getType(JNIEnv *env, jclass clazz, jobject jbitmap) { - SkBitmap const * nativeBitmap = - (SkBitmap const *)env->GetLongField(jbitmap, nativeBitmapID); + SkBitmap const * nativeBitmap = GraphicsJNI::getSkBitmap(env, jbitmap); return getType(nativeBitmap->colorType()); } @@ -646,8 +633,7 @@ static jint util_texImage2D(JNIEnv *env, jclass clazz, jint target, jint level, jint internalformat, jobject jbitmap, jint type, jint border) { - SkBitmap const * nativeBitmap = - (SkBitmap const *)env->GetLongField(jbitmap, nativeBitmapID); + SkBitmap const * nativeBitmap = GraphicsJNI::getSkBitmap(env, jbitmap); const SkBitmap& bitmap(*nativeBitmap); SkColorType colorType = bitmap.colorType(); if (internalformat < 0) { @@ -694,8 +680,7 @@ static jint util_texSubImage2D(JNIEnv *env, jclass clazz, jint target, jint level, jint xoffset, jint yoffset, jobject jbitmap, jint format, jint type) { - SkBitmap const * nativeBitmap = - (SkBitmap const *)env->GetLongField(jbitmap, nativeBitmapID); + SkBitmap const * nativeBitmap = GraphicsJNI::getSkBitmap(env, jbitmap); const SkBitmap& bitmap(*nativeBitmap); SkColorType colorType = bitmap.colorType(); if (format < 0) { @@ -1014,7 +999,6 @@ static JNINativeMethod gVisibilityMethods[] = { }; static JNINativeMethod gUtilsMethods[] = { - {"nativeClassInit", "()V", (void*)nativeUtilsClassInit }, { "native_getInternalFormat", "(Landroid/graphics/Bitmap;)I", (void*) util_getInternalFormat }, { "native_getType", "(Landroid/graphics/Bitmap;)I", (void*) util_getType }, { "native_texImage2D", "(IIILandroid/graphics/Bitmap;II)I", (void*)util_texImage2D }, diff --git a/core/jni/android_graphics_Canvas.cpp b/core/jni/android_graphics_Canvas.cpp index f14e89e6e59b..c337a9f0cf53 100644 --- a/core/jni/android_graphics_Canvas.cpp +++ b/core/jni/android_graphics_Canvas.cpp @@ -21,7 +21,6 @@ #include <Canvas.h> #include "SkDrawFilter.h" #include "SkGraphics.h" -#include "SkPorterDuff.h" #include "Paint.h" #include "TypefaceImpl.h" diff --git a/core/jni/android_text_StaticLayout.cpp b/core/jni/android_text_StaticLayout.cpp index db73e69d8fbe..a6f19b13b08c 100644 --- a/core/jni/android_text_StaticLayout.cpp +++ b/core/jni/android_text_StaticLayout.cpp @@ -29,6 +29,7 @@ #include <list> #include <algorithm> + namespace android { struct JLineBreaksID { @@ -40,6 +41,53 @@ struct JLineBreaksID { static jclass gLineBreaks_class; static JLineBreaksID gLineBreaks_fieldID; +class Builder { + public: + ~Builder() { + utext_close(&mUText); + delete mBreakIterator; + } + + void setLocale(const Locale& locale) { + delete mBreakIterator; + UErrorCode status = U_ZERO_ERROR; + mBreakIterator = BreakIterator::createLineInstance(locale, status); + // TODO: check status + } + + void resize(size_t size) { + mTextBuf.resize(size); + } + + uint16_t* buffer() { + return mTextBuf.data(); + } + + // set text to current contents of buffer + void setText() { + UErrorCode status = U_ZERO_ERROR; + utext_openUChars(&mUText, mTextBuf.data(), mTextBuf.size(), &status); + mBreakIterator->setText(&mUText, status); + } + + void finish() { + if (mTextBuf.size() > MAX_TEXT_BUF_RETAIN) { + mTextBuf.clear(); + mTextBuf.shrink_to_fit(); + } + } + + BreakIterator* breakIterator() const { + return mBreakIterator; + } + + private: + const size_t MAX_TEXT_BUF_RETAIN = 32678; + BreakIterator* mBreakIterator = nullptr; + UText mUText = UTEXT_INITIALIZER; + std::vector<uint16_t>mTextBuf; +}; + static const int CHAR_SPACE = 0x20; static const int CHAR_TAB = 0x09; static const int CHAR_NEWLINE = 0x0a; @@ -50,7 +98,7 @@ class TabStops { // specified stops must be a sorted array (allowed to be null) TabStops(JNIEnv* env, jintArray stops, jint defaultTabWidth) : mStops(env), mTabWidth(defaultTabWidth) { - if (stops != NULL) { + if (stops != nullptr) { mStops.reset(stops); mNumStops = mStops.size(); } else { @@ -430,37 +478,6 @@ class GreedyLineBreaker : public LineBreaker { } }; -class ScopedBreakIterator { - public: - ScopedBreakIterator(JNIEnv* env, BreakIterator* breakIterator, const jchar* inputText, - jint length) : mBreakIterator(breakIterator), mChars(inputText) { - UErrorCode status = U_ZERO_ERROR; - mUText = utext_openUChars(NULL, mChars, length, &status); - if (mUText == NULL) { - return; - } - - mBreakIterator->setText(mUText, status); - } - - inline BreakIterator* operator->() { - return mBreakIterator; - } - - ~ScopedBreakIterator() { - utext_close(mUText); - delete mBreakIterator; - } - private: - BreakIterator* mBreakIterator; - const jchar* mChars; - UText* mUText; - - // disable copying and assignment - ScopedBreakIterator(const ScopedBreakIterator&); - void operator=(const ScopedBreakIterator&); -}; - static jint recycleCopy(JNIEnv* env, jobject recycle, jintArray recycleBreaks, jfloatArray recycleWidths, jbooleanArray recycleFlags, jint recycleLength, const std::vector<jint>& breaks, @@ -526,7 +543,7 @@ void computePrimitives(const jchar* textArr, const jfloat* widthsArr, jint lengt primitives->push_back(p); } -static jint nComputeLineBreaks(JNIEnv* env, jclass, jstring javaLocaleName, +static jint nComputeLineBreaks(JNIEnv* env, jclass, jlong nativePtr, jcharArray inputText, jfloatArray widths, jint length, jfloat firstWidth, jint firstWidthLineLimit, jfloat restWidth, jintArray variableTabStops, jint defaultTabStop, jboolean optimize, @@ -535,29 +552,24 @@ static jint nComputeLineBreaks(JNIEnv* env, jclass, jstring javaLocaleName, jint recycleLength) { std::vector<int> breaks; - ScopedCharArrayRO textScopedArr(env, inputText); + Builder* b = reinterpret_cast<Builder*>(nativePtr); + b->resize(length); + env->GetCharArrayRegion(inputText, 0, length, b->buffer()); + b->setText(); + + // TODO: this array access is pretty inefficient, but we'll replace it anyway ScopedFloatArrayRO widthsScopedArr(env, widths); - ScopedIcuLocale icuLocale(env, javaLocaleName); - if (icuLocale.valid()) { - UErrorCode status = U_ZERO_ERROR; - BreakIterator* it = BreakIterator::createLineInstance(icuLocale.locale(), status); - if (!U_SUCCESS(status) || it == NULL) { - if (it) { - delete it; - } - } else { - ScopedBreakIterator breakIterator(env, it, textScopedArr.get(), length); - int loc = breakIterator->first(); - while ((loc = breakIterator->next()) != BreakIterator::DONE) { - breaks.push_back(loc); - } - } + BreakIterator* breakIterator = b->breakIterator(); + int loc = breakIterator->first(); + while ((loc = breakIterator->next()) != BreakIterator::DONE) { + breaks.push_back(loc); } + // TODO: all these allocations can be moved into the builder std::vector<Primitive> primitives; TabStops tabStops(env, variableTabStops, defaultTabStop); - computePrimitives(textScopedArr.get(), widthsScopedArr.get(), length, breaks, tabStops, &primitives); + computePrimitives(b->buffer(), widthsScopedArr.get(), length, breaks, tabStops, &primitives); LineWidth lineWidth(firstWidth, firstWidthLineLimit, restWidth); std::vector<int> computedBreaks; @@ -571,13 +583,41 @@ static jint nComputeLineBreaks(JNIEnv* env, jclass, jstring javaLocaleName, GreedyLineBreaker breaker(primitives, lineWidth); breaker.computeBreaks(&computedBreaks, &computedWidths, &computedFlags); } + b->finish(); return recycleCopy(env, recycle, recycleBreaks, recycleWidths, recycleFlags, recycleLength, computedBreaks, computedWidths, computedFlags); } +static jlong nNewBuilder(JNIEnv*, jclass) { + return reinterpret_cast<jlong>(new Builder); +} + +static void nFreeBuilder(JNIEnv*, jclass, jlong nativePtr) { + delete reinterpret_cast<Builder*>(nativePtr); +} + +static void nFinishBuilder(JNIEnv*, jclass, jlong nativePtr) { + Builder* b = reinterpret_cast<Builder*>(nativePtr); + b->finish(); +} + +static void nBuilderSetLocale(JNIEnv* env, jclass, jlong nativePtr, jstring javaLocaleName) { + ScopedIcuLocale icuLocale(env, javaLocaleName); + Builder* b = reinterpret_cast<Builder*>(nativePtr); + + if (icuLocale.valid()) { + b->setLocale(icuLocale.locale()); + } +} + static JNINativeMethod gMethods[] = { - {"nComputeLineBreaks", "(Ljava/lang/String;[C[FIFIF[IIZLandroid/text/StaticLayout$LineBreaks;[I[F[ZI)I", (void*) nComputeLineBreaks} + {"nNewBuilder", "()J", (void*) nNewBuilder}, + {"nFreeBuilder", "(J)V", (void*) nFreeBuilder}, + {"nFinishBuilder", "(J)V", (void*) nFinishBuilder}, + {"nBuilderSetLocale", "(JLjava/lang/String;)V", (void*) nBuilderSetLocale}, + {"nComputeLineBreaks", "(J[C[FIFIF[IIZLandroid/text/StaticLayout$LineBreaks;[I[F[ZI)I", + (void*) nComputeLineBreaks} }; int register_android_text_StaticLayout(JNIEnv* env) diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_DisplayListCanvas.cpp index 0bee7ae0183b..f2e6c4b5a8fd 100644 --- a/core/jni/android_view_GLES20Canvas.cpp +++ b/core/jni/android_view_DisplayListCanvas.cpp @@ -50,43 +50,43 @@ static struct { // Setup // ---------------------------------------------------------------------------- -static void android_view_GLES20Canvas_setViewport(JNIEnv* env, jobject clazz, +static void android_view_DisplayListCanvas_setViewport(JNIEnv* env, jobject clazz, jlong rendererPtr, jint width, jint height) { DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr); renderer->setViewport(width, height); } -static void android_view_GLES20Canvas_setHighContrastText(JNIEnv* env, jobject clazz, +static void android_view_DisplayListCanvas_setHighContrastText(JNIEnv* env, jobject clazz, jlong rendererPtr, jboolean highContrastText) { DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr); renderer->setHighContrastText(highContrastText); } -static void android_view_GLES20Canvas_insertReorderBarrier(JNIEnv* env, jobject clazz, +static void android_view_DisplayListCanvas_insertReorderBarrier(JNIEnv* env, jobject clazz, jlong rendererPtr, jboolean reorderEnable) { DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr); renderer->insertReorderBarrier(reorderEnable); } -static void android_view_GLES20Canvas_prepare(JNIEnv* env, jobject clazz, +static void android_view_DisplayListCanvas_prepare(JNIEnv* env, jobject clazz, jlong rendererPtr) { DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr); renderer->prepare(); } -static void android_view_GLES20Canvas_prepareDirty(JNIEnv* env, jobject clazz, +static void android_view_DisplayListCanvas_prepareDirty(JNIEnv* env, jobject clazz, jlong rendererPtr, jint left, jint top, jint right, jint bottom) { DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr); renderer->prepareDirty(left, top, right, bottom); } -static void android_view_GLES20Canvas_finish(JNIEnv* env, jobject clazz, +static void android_view_DisplayListCanvas_finish(JNIEnv* env, jobject clazz, jlong rendererPtr) { DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr); renderer->finish(); } -static void android_view_GLES20Canvas_setProperty(JNIEnv* env, +static void android_view_DisplayListCanvas_setProperty(JNIEnv* env, jobject clazz, jstring name, jstring value) { if (!Caches::hasInstance()) { ALOGW("can't set property, no Caches instance"); @@ -108,7 +108,7 @@ static void android_view_GLES20Canvas_setProperty(JNIEnv* env, // Functor // ---------------------------------------------------------------------------- -static void android_view_GLES20Canvas_callDrawGLFunction(JNIEnv* env, jobject clazz, +static void android_view_DisplayListCanvas_callDrawGLFunction(JNIEnv* env, jobject clazz, jlong rendererPtr, jlong functorPtr) { DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr); Functor* functor = reinterpret_cast<Functor*>(functorPtr); @@ -120,11 +120,11 @@ static void android_view_GLES20Canvas_callDrawGLFunction(JNIEnv* env, jobject cl // Misc // ---------------------------------------------------------------------------- -static jint android_view_GLES20Canvas_getMaxTextureWidth(JNIEnv* env, jobject clazz) { +static jint android_view_DisplayListCanvas_getMaxTextureWidth(JNIEnv* env, jobject clazz) { return Caches::getInstance().maxTextureSize; } -static jint android_view_GLES20Canvas_getMaxTextureHeight(JNIEnv* env, jobject clazz) { +static jint android_view_DisplayListCanvas_getMaxTextureHeight(JNIEnv* env, jobject clazz) { return Caches::getInstance().maxTextureSize; } @@ -132,7 +132,7 @@ static jint android_view_GLES20Canvas_getMaxTextureHeight(JNIEnv* env, jobject c // Drawing // ---------------------------------------------------------------------------- -static void android_view_GLES20Canvas_drawPatch(JNIEnv* env, jobject clazz, +static void android_view_DisplayListCanvas_drawPatch(JNIEnv* env, jobject clazz, jlong rendererPtr, jlong bitmapPtr, jlong patchPtr, float left, float top, float right, float bottom, jlong paintPtr) { SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapPtr); @@ -143,7 +143,7 @@ static void android_view_GLES20Canvas_drawPatch(JNIEnv* env, jobject clazz, renderer->drawPatch(bitmap, patch, left, top, right, bottom, paint); } -static void android_view_GLES20Canvas_drawRoundRectProps(JNIEnv* env, jobject clazz, +static void android_view_DisplayListCanvas_drawRoundRectProps(JNIEnv* env, jobject clazz, jlong rendererPtr, jlong leftPropPtr, jlong topPropPtr, jlong rightPropPtr, jlong bottomPropPtr, jlong rxPropPtr, jlong ryPropPtr, jlong paintPropPtr) { DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr); @@ -157,7 +157,7 @@ static void android_view_GLES20Canvas_drawRoundRectProps(JNIEnv* env, jobject cl renderer->drawRoundRect(leftProp, topProp, rightProp, bottomProp, rxProp, ryProp, paintProp); } -static void android_view_GLES20Canvas_drawCircleProps(JNIEnv* env, jobject clazz, +static void android_view_DisplayListCanvas_drawCircleProps(JNIEnv* env, jobject clazz, jlong rendererPtr, jlong xPropPtr, jlong yPropPtr, jlong radiusPropPtr, jlong paintPropPtr) { DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr); CanvasPropertyPrimitive* xProp = reinterpret_cast<CanvasPropertyPrimitive*>(xPropPtr); @@ -167,7 +167,7 @@ static void android_view_GLES20Canvas_drawCircleProps(JNIEnv* env, jobject clazz renderer->drawCircle(xProp, yProp, radiusProp, paintProp); } -static void android_view_GLES20Canvas_drawRegionAsRects(JNIEnv* env, jobject clazz, +static void android_view_DisplayListCanvas_drawRegionAsRects(JNIEnv* env, jobject clazz, jlong rendererPtr, jlong regionPtr, jlong paintPtr) { DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr); SkRegion* region = reinterpret_cast<SkRegion*>(regionPtr); @@ -201,17 +201,17 @@ static void android_view_GLES20Canvas_drawRegionAsRects(JNIEnv* env, jobject cla // Display lists // ---------------------------------------------------------------------------- -static jlong android_view_GLES20Canvas_finishRecording(JNIEnv* env, +static jlong android_view_DisplayListCanvas_finishRecording(JNIEnv* env, jobject clazz, jlong rendererPtr) { DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr); return reinterpret_cast<jlong>(renderer->finishRecording()); } -static jlong android_view_GLES20Canvas_createDisplayListRenderer(JNIEnv* env, jobject clazz) { +static jlong android_view_DisplayListCanvas_createDisplayListRenderer(JNIEnv* env, jobject clazz) { return reinterpret_cast<jlong>(new DisplayListRenderer); } -static void android_view_GLES20Canvas_drawRenderNode(JNIEnv* env, +static void android_view_DisplayListCanvas_drawRenderNode(JNIEnv* env, jobject clazz, jlong rendererPtr, jlong renderNodePtr, jint flags) { DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr); @@ -224,7 +224,7 @@ static void android_view_GLES20Canvas_drawRenderNode(JNIEnv* env, // Layers // ---------------------------------------------------------------------------- -static void android_view_GLES20Canvas_drawLayer(JNIEnv* env, jobject clazz, +static void android_view_DisplayListCanvas_drawLayer(JNIEnv* env, jobject clazz, jlong rendererPtr, jlong layerPtr, jfloat x, jfloat y) { DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr); DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerPtr); @@ -235,7 +235,7 @@ static void android_view_GLES20Canvas_drawLayer(JNIEnv* env, jobject clazz, // Common // ---------------------------------------------------------------------------- -static jboolean android_view_GLES20Canvas_isAvailable(JNIEnv* env, jobject clazz) { +static jboolean android_view_DisplayListCanvas_isAvailable(JNIEnv* env, jobject clazz) { char prop[PROPERTY_VALUE_MAX]; if (property_get("ro.kernel.qemu", prop, NULL) == 0) { // not in the emulator @@ -261,36 +261,36 @@ android_app_ActivityThread_dumpGraphics(JNIEnv* env, jobject clazz, jobject java // JNI Glue // ---------------------------------------------------------------------------- -const char* const kClassPathName = "android/view/GLES20Canvas"; +const char* const kClassPathName = "android/view/DisplayListCanvas"; static JNINativeMethod gMethods[] = { - { "nIsAvailable", "()Z", (void*) android_view_GLES20Canvas_isAvailable }, - { "nSetViewport", "(JII)V", (void*) android_view_GLES20Canvas_setViewport }, - { "nSetHighContrastText","(JZ)V", (void*) android_view_GLES20Canvas_setHighContrastText }, - { "nInsertReorderBarrier","(JZ)V", (void*) android_view_GLES20Canvas_insertReorderBarrier }, - { "nPrepare", "(J)V", (void*) android_view_GLES20Canvas_prepare }, - { "nPrepareDirty", "(JIIII)V", (void*) android_view_GLES20Canvas_prepareDirty }, - { "nFinish", "(J)V", (void*) android_view_GLES20Canvas_finish }, + { "nIsAvailable", "()Z", (void*) android_view_DisplayListCanvas_isAvailable }, + { "nSetViewport", "(JII)V", (void*) android_view_DisplayListCanvas_setViewport }, + { "nSetHighContrastText","(JZ)V", (void*) android_view_DisplayListCanvas_setHighContrastText }, + { "nInsertReorderBarrier","(JZ)V", (void*) android_view_DisplayListCanvas_insertReorderBarrier }, + { "nPrepare", "(J)V", (void*) android_view_DisplayListCanvas_prepare }, + { "nPrepareDirty", "(JIIII)V", (void*) android_view_DisplayListCanvas_prepareDirty }, + { "nFinish", "(J)V", (void*) android_view_DisplayListCanvas_finish }, { "nSetProperty", "(Ljava/lang/String;Ljava/lang/String;)V", - (void*) android_view_GLES20Canvas_setProperty }, + (void*) android_view_DisplayListCanvas_setProperty }, - { "nCallDrawGLFunction", "(JJ)V", (void*) android_view_GLES20Canvas_callDrawGLFunction }, + { "nCallDrawGLFunction", "(JJ)V", (void*) android_view_DisplayListCanvas_callDrawGLFunction }, - { "nDrawPatch", "(JJJFFFFJ)V", (void*) android_view_GLES20Canvas_drawPatch }, + { "nDrawPatch", "(JJJFFFFJ)V", (void*) android_view_DisplayListCanvas_drawPatch }, - { "nDrawRects", "(JJJ)V", (void*) android_view_GLES20Canvas_drawRegionAsRects }, - { "nDrawRoundRect", "(JJJJJJJJ)V", (void*) android_view_GLES20Canvas_drawRoundRectProps }, - { "nDrawCircle", "(JJJJJ)V", (void*) android_view_GLES20Canvas_drawCircleProps }, + { "nDrawRects", "(JJJ)V", (void*) android_view_DisplayListCanvas_drawRegionAsRects }, + { "nDrawRoundRect", "(JJJJJJJJ)V", (void*) android_view_DisplayListCanvas_drawRoundRectProps }, + { "nDrawCircle", "(JJJJJ)V", (void*) android_view_DisplayListCanvas_drawCircleProps }, - { "nFinishRecording", "(J)J", (void*) android_view_GLES20Canvas_finishRecording }, - { "nDrawRenderNode", "(JJI)V", (void*) android_view_GLES20Canvas_drawRenderNode }, + { "nFinishRecording", "(J)J", (void*) android_view_DisplayListCanvas_finishRecording }, + { "nDrawRenderNode", "(JJI)V", (void*) android_view_DisplayListCanvas_drawRenderNode }, - { "nCreateDisplayListRenderer", "()J", (void*) android_view_GLES20Canvas_createDisplayListRenderer }, + { "nCreateDisplayListRenderer", "()J", (void*) android_view_DisplayListCanvas_createDisplayListRenderer }, - { "nDrawLayer", "(JJFF)V", (void*) android_view_GLES20Canvas_drawLayer }, + { "nDrawLayer", "(JJFF)V", (void*) android_view_DisplayListCanvas_drawLayer }, - { "nGetMaximumTextureWidth", "()I", (void*) android_view_GLES20Canvas_getMaxTextureWidth }, - { "nGetMaximumTextureHeight", "()I", (void*) android_view_GLES20Canvas_getMaxTextureHeight }, + { "nGetMaximumTextureWidth", "()I", (void*) android_view_DisplayListCanvas_getMaxTextureWidth }, + { "nGetMaximumTextureHeight", "()I", (void*) android_view_DisplayListCanvas_getMaxTextureHeight }, }; static JNINativeMethod gActivityThreadMethods[] = { @@ -298,7 +298,7 @@ static JNINativeMethod gActivityThreadMethods[] = { (void*) android_app_ActivityThread_dumpGraphics } }; -int register_android_view_GLES20Canvas(JNIEnv* env) { +int register_android_view_DisplayListCanvas(JNIEnv* env) { jclass clazz = FindClassOrDie(env, "android/graphics/Rect"); gRectClassInfo.set = GetMethodIDOrDie(env, clazz, "set", "(IIII)V"); diff --git a/core/jni/android_view_PointerIcon.cpp b/core/jni/android_view_PointerIcon.cpp index bbd031ef04d6..f6d9a1a95ee0 100644 --- a/core/jni/android_view_PointerIcon.cpp +++ b/core/jni/android_view_PointerIcon.cpp @@ -80,7 +80,7 @@ status_t android_view_PointerIcon_load(JNIEnv* env, jobject pointerIconObj, jobj jobject bitmapObj = env->GetObjectField(loadedPointerIconObj, gPointerIconClassInfo.mBitmap); if (bitmapObj) { - SkBitmap* bitmap = GraphicsJNI::getNativeBitmap(env, bitmapObj); + SkBitmap* bitmap = GraphicsJNI::getSkBitmap(env, bitmapObj); if (bitmap) { outPointerIcon->bitmap = *bitmap; // use a shared pixel ref } diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp index bfa0534f0eb5..39064ed22604 100644 --- a/core/jni/android_view_Surface.cpp +++ b/core/jni/android_view_Surface.cpp @@ -130,6 +130,100 @@ jobject android_view_Surface_createFromIGraphicBufferProducer(JNIEnv* env, return surfaceObj; } +int android_view_Surface_mapPublicFormatToHalFormat(PublicFormat f) { + + switch(f) { + case PublicFormat::JPEG: + case PublicFormat::DEPTH_POINT_CLOUD: + return HAL_PIXEL_FORMAT_BLOB; + case PublicFormat::DEPTH16: + return HAL_PIXEL_FORMAT_Y16; + case PublicFormat::RAW_SENSOR: + return HAL_PIXEL_FORMAT_RAW16; + default: + // Most formats map 1:1 + return static_cast<int>(f); + } +} + +android_dataspace android_view_Surface_mapPublicFormatToHalDataspace( + PublicFormat f) { + switch(f) { + case PublicFormat::JPEG: + return HAL_DATASPACE_JFIF; + case PublicFormat::DEPTH_POINT_CLOUD: + case PublicFormat::DEPTH16: + return HAL_DATASPACE_DEPTH; + case PublicFormat::RAW_SENSOR: + case PublicFormat::RAW10: + return HAL_DATASPACE_ARBITRARY; + case PublicFormat::YUV_420_888: + case PublicFormat::NV21: + case PublicFormat::YV12: + return HAL_DATASPACE_JFIF; + default: + // Most formats map to UNKNOWN + return HAL_DATASPACE_UNKNOWN; + } +} + +PublicFormat android_view_Surface_mapHalFormatDataspaceToPublicFormat( + int format, android_dataspace dataSpace) { + switch(format) { + case HAL_PIXEL_FORMAT_RGBA_8888: + case HAL_PIXEL_FORMAT_RGBX_8888: + case HAL_PIXEL_FORMAT_RGB_888: + case HAL_PIXEL_FORMAT_RGB_565: + case HAL_PIXEL_FORMAT_Y8: + case HAL_PIXEL_FORMAT_RAW10: + case HAL_PIXEL_FORMAT_YCbCr_420_888: + case HAL_PIXEL_FORMAT_YV12: + // Enums overlap in both name and value + return static_cast<PublicFormat>(format); + case HAL_PIXEL_FORMAT_RAW16: + // Name differs, though value is the same + return PublicFormat::RAW_SENSOR; + case HAL_PIXEL_FORMAT_YCbCr_422_SP: + // Name differs, though the value is the same + return PublicFormat::NV16; + case HAL_PIXEL_FORMAT_YCrCb_420_SP: + // Name differs, though the value is the same + return PublicFormat::NV21; + case HAL_PIXEL_FORMAT_YCbCr_422_I: + // Name differs, though the value is the same + return PublicFormat::YUY2; + case HAL_PIXEL_FORMAT_Y16: + // Dataspace-dependent + switch (dataSpace) { + case HAL_DATASPACE_DEPTH: + return PublicFormat::DEPTH16; + default: + // Assume non-depth Y16 is just Y16. + return PublicFormat::Y16; + } + break; + case HAL_PIXEL_FORMAT_BLOB: + // Dataspace-dependent + switch (dataSpace) { + case HAL_DATASPACE_DEPTH: + return PublicFormat::DEPTH_POINT_CLOUD; + case HAL_DATASPACE_JFIF: + return PublicFormat::JPEG; + default: + // Assume otherwise-marked blobs are also JPEG + return PublicFormat::JPEG; + } + break; + case HAL_PIXEL_FORMAT_BGRA_8888: + case HAL_PIXEL_FORMAT_RAW_OPAQUE: + case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED: + // Not defined in public API + return PublicFormat::UNKNOWN; + + default: + return PublicFormat::UNKNOWN; + } +} // ---------------------------------------------------------------------------- static inline bool isSurfaceValid(const sp<Surface>& sur) { diff --git a/core/jni/com_google_android_gles_jni_EGLImpl.cpp b/core/jni/com_google_android_gles_jni_EGLImpl.cpp index 6c21babfcb44..7080e2ab5a78 100644 --- a/core/jni/com_google_android_gles_jni_EGLImpl.cpp +++ b/core/jni/com_google_android_gles_jni_EGLImpl.cpp @@ -30,6 +30,7 @@ #include <gui/GLConsumer.h> #include <gui/Surface.h> +#include <GraphicsJNI.h> #include <SkBitmap.h> #include <SkPixelRef.h> @@ -46,7 +47,6 @@ static jfieldID gContext_EGLContextFieldID; static jfieldID gSurface_EGLSurfaceFieldID; static jfieldID gSurface_NativePixelRefFieldID; static jfieldID gConfig_EGLConfigFieldID; -static jfieldID gBitmap_NativeBitmapFieldID; static inline EGLDisplay getDisplay(JNIEnv* env, jobject o) { if (!o) return EGL_NO_DISPLAY; @@ -85,9 +85,6 @@ static void nativeClassInit(JNIEnv *_env, jclass eglImplClass) jclass surface_class = _env->FindClass("com/google/android/gles_jni/EGLSurfaceImpl"); gSurface_EGLSurfaceFieldID = _env->GetFieldID(surface_class, "mEGLSurface", "J"); gSurface_NativePixelRefFieldID = _env->GetFieldID(surface_class, "mNativePixelRef", "J"); - - jclass bitmap_class = _env->FindClass("android/graphics/Bitmap"); - gBitmap_NativeBitmapFieldID = _env->GetFieldID(bitmap_class, "mNativeBitmap", "J"); } static const jint gNull_attrib_base[] = {EGL_NONE}; @@ -280,9 +277,7 @@ static void jni_eglCreatePixmapSurface(JNIEnv *_env, jobject _this, jobject out_ EGLConfig cnf = getConfig(_env, config); jint* base = 0; - SkBitmap const * nativeBitmap = - (SkBitmap const *)_env->GetLongField(native_pixmap, - gBitmap_NativeBitmapFieldID); + SkBitmap const * nativeBitmap = GraphicsJNI::getSkBitmap(_env, native_pixmap); SkPixelRef* ref = nativeBitmap ? nativeBitmap->pixelRef() : 0; if (ref == NULL) { jniThrowException(_env, "java/lang/IllegalArgumentException", "Bitmap has no PixelRef"); diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 2ce5bb36d5c1..ed4776bab525 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -3033,6 +3033,19 @@ android:excludeFromRecents="true" android:process=":ui"> </activity> + <activity android:name="com.android.internal.app.DumpHeapActivity" + android:theme="@style/Theme.Translucent.NoTitleBar" + android:label="@string/dump_heap_title" + android:finishOnCloseSystemDialogs="true" + android:noHistory="true" + android:excludeFromRecents="true" + android:process=":ui"> + </activity> + <provider android:name="com.android.server.am.DumpHeapProvider" + android:authorities="com.android.server.heapdump" + android:grantUriPermissions="true" + android:multiprocess="false" + android:singleUser="true" /> <activity android:name="android.accounts.ChooseAccountActivity" android:excludeFromRecents="true" diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml index 4d93a836fa55..5a12efbc71c2 100644 --- a/core/res/res/values-af/strings.xml +++ b/core/res/res/values-af/strings.xml @@ -796,6 +796,8 @@ <string name="permdesc_accessNotifications" msgid="458457742683431387">"Laat die program toe om kennisgewings op te haal, te bestudeer en te verwyder, insluitende die kennisgewings wat deur ander programme geplaas is."</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"bind aan \'n kennisgewingluisteraardiens"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Laat die houer toe om aan die top-koppelvlak van \'n kennisgewingluisteraardiens te bind. Behoort nooit vir gewone programme nodig te wees nie."</string> + <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"bind aan \'n kieserteikendiens"</string> + <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Laat die houer toe om aan die top-koppelvlak van \'n kieserteikendiens te bind. Behoort nooit vir gewone programme nodig te wees nie."</string> <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"verbind met \'n toestandverskafferdiens"</string> <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Laat die houer toe om met die topvlak-koppelvlak van \'n toestandverskafferdiens te verbind. Behoort nooit vir normale programme nodig te wees nie."</string> <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"bind aan \'n mediaroetediens"</string> @@ -1263,6 +1265,14 @@ <string name="old_app_description" msgid="2082094275580358049">"Moenie die nuwe program begin nie."</string> <string name="new_app_action" msgid="5472756926945440706">"Begin <xliff:g id="OLD_APP">%1$s</xliff:g>"</string> <string name="new_app_description" msgid="1932143598371537340">"Stop die ou program sonder om te stoor."</string> + <!-- no translation found for dump_heap_notification (2618183274836056542) --> + <skip /> + <!-- no translation found for dump_heap_notification_detail (2075673362317481664) --> + <skip /> + <!-- no translation found for dump_heap_title (5864292264307651673) --> + <skip /> + <!-- no translation found for dump_heap_text (4809417337240334941) --> + <skip /> <string name="sendText" msgid="5209874571959469142">"Kies \'n handeling vir teks"</string> <string name="volume_ringtone" msgid="6885421406845734650">"Luiervolume"</string> <string name="volume_music" msgid="5421651157138628171">"Mediavolume"</string> @@ -1776,7 +1786,9 @@ <item quantity="one">Probeer weer oor 1 sekonde</item> </plurals> <string name="restr_pin_try_later" msgid="973144472490532377">"Probeer later weer"</string> - <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Swiep van bo af na onder om volskerm te verlaat."</string> + <string name="immersive_cling_title" msgid="8394201622932303336">"Bekyk tans volskerm"</string> + <string name="immersive_cling_description" msgid="3482371193207536040">"Swiep van bo na onder as jy wil uitgaan."</string> + <string name="immersive_cling_positive" msgid="5016839404568297683">"Het dit"</string> <string name="done_label" msgid="2093726099505892398">"Klaar"</string> <string name="hour_picker_description" msgid="6698199186859736512">"Ure se sirkelglyer"</string> <string name="minute_picker_description" msgid="8606010966873791190">"Minute se sirkelglyer"</string> @@ -1791,7 +1803,8 @@ <string name="managed_profile_label_badge" msgid="2355652472854327647">"Werk-<xliff:g id="LABEL">%1$s</xliff:g>"</string> <string name="lock_to_app_toast" msgid="7570091317001980053">"Om hierdie skerm te ontspeld, raak en hou tegelyk Terug en Oorsig."</string> <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Om hierdie skerm te ontspeld, raak en hou Oorsig."</string> - <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Skerm is vasgespeld. Jou organisasie laat nie toe dat dit ontspeld word nie."</string> + <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) --> + <skip /> <string name="lock_to_app_start" msgid="6643342070839862795">"Skerm vasgespeld"</string> <string name="lock_to_app_exit" msgid="8598219838213787430">"Skerm ontspeld"</string> <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Vra PIN voordat jy ontspeld"</string> diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml index 05818bc7f8ca..1741851ebe82 100644 --- a/core/res/res/values-am/strings.xml +++ b/core/res/res/values-am/strings.xml @@ -796,6 +796,8 @@ <string name="permdesc_accessNotifications" msgid="458457742683431387">"መተግበሪያው ማሳወቂያዎችን እንዲያስመጣ፣ እንዲመረምር እና እንዲያጸዳ ያስችለዋል፣ በሌሎች መተግበሪያዎች የተለጠፉትንም ጨምሮ።"</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"ከአንድ የማሳወቂያ አዳማጭ አገልግሎት ጋር ይሰሩ"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"ያዢው የማሳወቂያ አዳማጭ አገልግሎቱን ከከፍተኛ-ደረጃ በይነገጹ ጋር እንዲያስር ያስችለዋል። ለመደበኛ መተግበሪያዎች በጭራሽ አያስፈልግም።"</string> + <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"ከመራጭ ዒላማ አገልግሎት ጋር ይሰሩ"</string> + <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"ያዢው የመራጩን ዒላማ አገልግሎቱን ከከፍተኛ-ደረጃ በይነገጽ ጋር እንዲያስር ይፈቅዳል። ለመደበኛ መተግበሪያዎች በጭራሽ ሊያስፈልግ አይገባም።"</string> <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"ከአንድ የሁኔታ አቅራቢ አገልግሎት ጋር ይሰሩ"</string> <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"ያዢው የአንድ የሁኔታ አቅራቢ አገልግሎት የከፍተኛ ደረጃ በይነገጽ እንዲያስር ያስችለዋል። ለመደበኛ መተግበሪያዎች በጭራሽ አያስፈልግም።"</string> <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"ከአንድ ማህደረመረጃ ማዞር አገልግሎት ጋር ያስተሳስራል"</string> @@ -1263,6 +1265,14 @@ <string name="old_app_description" msgid="2082094275580358049">"አዲሱን መተግበሪያ አትጀምር።"</string> <string name="new_app_action" msgid="5472756926945440706">"ጀምር <xliff:g id="OLD_APP">%1$s</xliff:g>"</string> <string name="new_app_description" msgid="1932143598371537340">"የድሮውን ትግበራ ሳታስቀምጥ አቁም።"</string> + <!-- no translation found for dump_heap_notification (2618183274836056542) --> + <skip /> + <!-- no translation found for dump_heap_notification_detail (2075673362317481664) --> + <skip /> + <!-- no translation found for dump_heap_title (5864292264307651673) --> + <skip /> + <!-- no translation found for dump_heap_text (4809417337240334941) --> + <skip /> <string name="sendText" msgid="5209874571959469142">"ለፅሁፍ ድርጊት ምረጥ"</string> <string name="volume_ringtone" msgid="6885421406845734650">"የስልክ ጥሪ ድምፅ"</string> <string name="volume_music" msgid="5421651157138628171">" ማህደረ መረጃ ክፍልፍል"</string> @@ -1776,7 +1786,9 @@ <item quantity="other">በ<xliff:g id="COUNT">%d</xliff:g> ሰከንዶች ውስጥ እንደገና ይሞክሩ</item> </plurals> <string name="restr_pin_try_later" msgid="973144472490532377">"ቆይተው እንደገና ይሞክሩ"</string> - <string name="immersive_mode_confirmation" msgid="7227416894979047467">"ከሙሉ ገጽ ማያ ለመውጣት ጣትዎን ከላይ ወደታች ያንሸራትቱ።"</string> + <string name="immersive_cling_title" msgid="8394201622932303336">"ሙሉ ገጽ በማሳየት ላይ"</string> + <string name="immersive_cling_description" msgid="3482371193207536040">"ለመውጣት፣ ከላይ ወደታች ጠረግ ያድርጉ።"</string> + <string name="immersive_cling_positive" msgid="5016839404568297683">"ገባኝ"</string> <string name="done_label" msgid="2093726099505892398">"ተከናውኗል"</string> <string name="hour_picker_description" msgid="6698199186859736512">"የሰዓታት ክብ ተንሸራታች"</string> <string name="minute_picker_description" msgid="8606010966873791190">"የደቂቃዎች ክብ ተንሸራታች"</string> @@ -1791,7 +1803,8 @@ <string name="managed_profile_label_badge" msgid="2355652472854327647">"ስራ <xliff:g id="LABEL">%1$s</xliff:g>"</string> <string name="lock_to_app_toast" msgid="7570091317001980053">"ይህን ማያ ገጽ ለመንቀል ተመለስን እና አጠቃላይ እይታን በተመሳሳይ ይንኳቸውና ይያዟቸው።"</string> <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"ይህን ማያ ገጽ ለመንቀል አጠቃላይ እይታን ይንኩትና ይያዙት።"</string> - <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"ማያ ገጽ ተሰክቷል። መንቀል በድርጅትዎ አይፈቀድም።"</string> + <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) --> + <skip /> <string name="lock_to_app_start" msgid="6643342070839862795">"ማያ ገጽ ተሰክቷል"</string> <string name="lock_to_app_exit" msgid="8598219838213787430">"ማያ ገጽ ተነቅሏል"</string> <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"ከመንቀል በፊት ፒን ጠይቅ"</string> diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml index 8021de05cd1a..1d1fe5469f50 100644 --- a/core/res/res/values-ar/strings.xml +++ b/core/res/res/values-ar/strings.xml @@ -800,6 +800,8 @@ <string name="permdesc_accessNotifications" msgid="458457742683431387">"يتيح للتطبيق استرجاع الإشعارات وفحصها ومسحها، بما في ذلك تلك التي نشرتها تطبيقات أخرى."</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"الربط بخدمة تلقّي الإشعارات الصوتية"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"يتيح للمالك الربط بواجهة المستوى العلوي لخدمة تلقّي الإشعارات الصوتية. ولن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string> + <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"الربط بخدمة اختيار الهدف"</string> + <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"للسماح للمالك بالربط بواجهة المستوى العلوي لخدمة اختيار الهدف. لن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string> <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"الربط بخدمة موفر الحالة"</string> <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"للسماح للمالك بالربط بواجهة المستوى العلوي لخدمة موفر الحالة. لن تكون هناك حاجة إلى هذا الإعداد مطلقًا مع التطبيقات العادية."</string> <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"الربط بخدمة توجيه الوسائط"</string> @@ -1283,6 +1285,14 @@ <string name="old_app_description" msgid="2082094275580358049">"عدم بدء التطبيق الجديد."</string> <string name="new_app_action" msgid="5472756926945440706">"بدء <xliff:g id="OLD_APP">%1$s</xliff:g>"</string> <string name="new_app_description" msgid="1932143598371537340">"إيقاف التطبيق القديم بدون الحفظ."</string> + <!-- no translation found for dump_heap_notification (2618183274836056542) --> + <skip /> + <!-- no translation found for dump_heap_notification_detail (2075673362317481664) --> + <skip /> + <!-- no translation found for dump_heap_title (5864292264307651673) --> + <skip /> + <!-- no translation found for dump_heap_text (4809417337240334941) --> + <skip /> <string name="sendText" msgid="5209874571959469142">"اختيار إجراء للنص"</string> <string name="volume_ringtone" msgid="6885421406845734650">"مستوى صوت الرنين"</string> <string name="volume_music" msgid="5421651157138628171">"مستوى صوت الوسائط"</string> @@ -1812,7 +1822,9 @@ <item quantity="one">حاول مرة أخرى خلال ثانية واحدة</item> </plurals> <string name="restr_pin_try_later" msgid="973144472490532377">"أعد المحاولة لاحقًا"</string> - <string name="immersive_mode_confirmation" msgid="7227416894979047467">"مرر بسرعة من أعلى لأسفل للخروج من وضع ملء الشاشة."</string> + <string name="immersive_cling_title" msgid="8394201622932303336">"جارٍ العرض بملء الشاشة"</string> + <string name="immersive_cling_description" msgid="3482371193207536040">"للخروج، مرر بسرعة من أعلى إلى أسفل."</string> + <string name="immersive_cling_positive" msgid="5016839404568297683">"حسنًا"</string> <string name="done_label" msgid="2093726099505892398">"تم"</string> <string name="hour_picker_description" msgid="6698199186859736512">"شريط التمرير الدائري للساعات"</string> <string name="minute_picker_description" msgid="8606010966873791190">"شريط التمرير الدائري للدقائق"</string> @@ -1827,7 +1839,8 @@ <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> المخصص للعمل"</string> <string name="lock_to_app_toast" msgid="7570091317001980053">"لإلغاء تثبيت هذه الشاشة، يمكنك لمس \"رجوع\" و\"نظرة عامة\" في آن واحد مع الاستمرار."</string> <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"لإلغاء تثبيت هذه الشاشة، يمكنك لمس \"نظرة عامة\" مع الاستمرار."</string> - <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"الشاشة مثبتة. لا تسمح منظمتك بإلغاء التثبيت."</string> + <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) --> + <skip /> <string name="lock_to_app_start" msgid="6643342070839862795">"تم تثبيت الشاشة"</string> <string name="lock_to_app_exit" msgid="8598219838213787430">"تم إلغاء تثبيت الشاشة"</string> <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"المطالبة برقم التعريف الشخصي قبل إزالة التثبيت"</string> diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml index 125611f76e54..0ca9f512e834 100644 --- a/core/res/res/values-bg/strings.xml +++ b/core/res/res/values-bg/strings.xml @@ -796,6 +796,8 @@ <string name="permdesc_accessNotifications" msgid="458457742683431387">"Разрешава на приложението да извлича, преглежда и изчиства известия, включително публикуваните от други приложения."</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"обвързване с услуга за слушател на известия"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Разрешава на притежателя да се обвърже с интерфейса от първо ниво на услуга за слушател на известия. Нормалните приложения не би трябвало никога да се нуждаят от това."</string> + <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"свързване с целева услуга в инструмент за избор"</string> + <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Разрешава на притежателя да се свърже с интерфейса от най-високото ниво на целева услуга в инструмент за избор. Нормалните приложения би трябвало никога да не се нуждаят от това."</string> <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"свързване с услуга за предоставяне на условия"</string> <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Разрешава на притежателя да се свърже с интерфейса от най-високото ниво на услуга за предоставяне на условия. Нормалните приложения би трябвало никога да не се нуждаят от това."</string> <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"свързване с услуга за маршрутизиране на мултимедия"</string> @@ -1263,6 +1265,14 @@ <string name="old_app_description" msgid="2082094275580358049">"Новото приложение да не се стартира."</string> <string name="new_app_action" msgid="5472756926945440706">"Стартиране на <xliff:g id="OLD_APP">%1$s</xliff:g>"</string> <string name="new_app_description" msgid="1932143598371537340">"Спиране на старото приложение без запазване."</string> + <!-- no translation found for dump_heap_notification (2618183274836056542) --> + <skip /> + <!-- no translation found for dump_heap_notification_detail (2075673362317481664) --> + <skip /> + <!-- no translation found for dump_heap_title (5864292264307651673) --> + <skip /> + <!-- no translation found for dump_heap_text (4809417337240334941) --> + <skip /> <string name="sendText" msgid="5209874571959469142">"Избиране на действие за текст"</string> <string name="volume_ringtone" msgid="6885421406845734650">"Сила на звука при звънене"</string> <string name="volume_music" msgid="5421651157138628171">"Сила на звука"</string> @@ -1776,7 +1786,9 @@ <item quantity="one">Опитайте отново след 1 секунда</item> </plurals> <string name="restr_pin_try_later" msgid="973144472490532377">"Опитайте отново по-късно"</string> - <string name="immersive_mode_confirmation" msgid="7227416894979047467">"За изход от цял екран прекарайте пръст отгоре надолу."</string> + <string name="immersive_cling_title" msgid="8394201622932303336">"Изглед на цял екран"</string> + <string name="immersive_cling_description" msgid="3482371193207536040">"За изход прекарайте пръст надолу от горната част."</string> + <string name="immersive_cling_positive" msgid="5016839404568297683">"Разбрах"</string> <string name="done_label" msgid="2093726099505892398">"Готово"</string> <string name="hour_picker_description" msgid="6698199186859736512">"Кръгов плъзгач за часовете"</string> <string name="minute_picker_description" msgid="8606010966873791190">"Кръгов плъзгач за минутите"</string> @@ -1791,7 +1803,8 @@ <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> за работа"</string> <string name="lock_to_app_toast" msgid="7570091317001980053">"За да освободите екрана, докоснете и задръжте едновременно бутона за връщане назад и този за общ преглед."</string> <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"За да освободите този екран, докоснете и задръжте бутона „Общ преглед“."</string> - <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Екранът е фиксиран. Освобождаването не е разрешено от организацията ви."</string> + <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) --> + <skip /> <string name="lock_to_app_start" msgid="6643342070839862795">"Екранът е фиксиран"</string> <string name="lock_to_app_exit" msgid="8598219838213787430">"Екранът е освободен"</string> <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Запитване за ПИН код преди освобождаване"</string> diff --git a/core/res/res/values-bn-rBD/strings.xml b/core/res/res/values-bn-rBD/strings.xml index f9ebf28f6c56..8a603201fb62 100644 --- a/core/res/res/values-bn-rBD/strings.xml +++ b/core/res/res/values-bn-rBD/strings.xml @@ -796,6 +796,8 @@ <string name="permdesc_accessNotifications" msgid="458457742683431387">"অ্যাপ্লিকেশানটিকে অন্যান্য অ্যাপ্লিকেশান যেগুলি পোস্ট করে সেগুলি সমেত, বিজ্ঞপ্তিগুলি পুনরুদ্ধার করতে, পরীক্ষা করতে এবং সাফ করার অনুমতি দেয়৷"</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"একটি বিজ্ঞপ্তি শ্রোতা পরিষেবাতে সংলগ্ন করে"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"ধারককে, একটি বিজ্ঞপ্তি শ্রোতা পরিষেবার উচ্চ স্তরের ইন্টারফেসে জুড়তে অনুমতি দেয়৷ সধারণ অ্যাপ্লিকেশানগুলির জন্য কখনই প্রয়োজন হয় না৷"</string> + <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"একটি লক্ষ চয়নকারী পরিষেবাতে আবদ্ধ করুন"</string> + <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"ধারককে, একটি লক্ষ্য চয়নকারী পরিষেবার উচ্চ স্তরের ইন্টারফেসে জুড়তে অনুমতি দেয়৷ সধারণ অ্যাপ্লিকেশানগুলির জন্য কখনই প্রয়োজন হয় না৷"</string> <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"একটি শর্ত প্রদানকারীর পরিষেবা বাঁধাই করে"</string> <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"ধারককে, একটি শর্ত প্রদানকারী পরিষেবার উচ্চ স্তরের ইন্টারফেসে জুড়তে অনুমতি দেয়৷ সধারণ অ্যাপ্লিকেশানগুলির জন্য কখনই প্রয়োজন হয় না৷"</string> <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"একটি মিডিয়া রুট পরিষেবায় জুড়ুন"</string> @@ -1263,6 +1265,14 @@ <string name="old_app_description" msgid="2082094275580358049">"নতুন অ্যাপ্লিকেশান চালু করবেন না৷"</string> <string name="new_app_action" msgid="5472756926945440706">"<xliff:g id="OLD_APP">%1$s</xliff:g> শুরু করুন"</string> <string name="new_app_description" msgid="1932143598371537340">"সংরক্ষণ না করেই পুরোনো অ্যাপ্লিকেশানটি বন্ধ করুন৷"</string> + <!-- no translation found for dump_heap_notification (2618183274836056542) --> + <skip /> + <!-- no translation found for dump_heap_notification_detail (2075673362317481664) --> + <skip /> + <!-- no translation found for dump_heap_title (5864292264307651673) --> + <skip /> + <!-- no translation found for dump_heap_text (4809417337240334941) --> + <skip /> <string name="sendText" msgid="5209874571959469142">"পাঠ্যের জন্য একটি কাজ বেছে নিন"</string> <string name="volume_ringtone" msgid="6885421406845734650">"রিং ভলিউম"</string> <string name="volume_music" msgid="5421651157138628171">"মিডিয়ার ভলিউম"</string> @@ -1776,7 +1786,9 @@ <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> সেকেন্ডের মধ্যে আবার চেষ্টা করুন</item> </plurals> <string name="restr_pin_try_later" msgid="973144472490532377">"পরে আবার চেষ্টা করুন"</string> - <string name="immersive_mode_confirmation" msgid="7227416894979047467">"পূর্ণস্ক্রীণ থেকে প্রস্থান করতে উপর থেকে নীচের দিকে সোয়াইপ করুন৷"</string> + <string name="immersive_cling_title" msgid="8394201622932303336">"পূর্ণ স্ক্রীণে দেখা হচ্ছে"</string> + <string name="immersive_cling_description" msgid="3482371193207536040">"প্রস্থান করতে উপর থেকে নীচের দিকে সোয়াইপ করুন"</string> + <string name="immersive_cling_positive" msgid="5016839404568297683">"বুঝেছি"</string> <string name="done_label" msgid="2093726099505892398">"সম্পন্ন হয়েছে"</string> <string name="hour_picker_description" msgid="6698199186859736512">"বৃত্তাকার ঘন্টা নির্বাচকের স্লাইডার"</string> <string name="minute_picker_description" msgid="8606010966873791190">"বৃত্তাকার মিনিট নির্বাচকের স্লাইডার"</string> @@ -1791,7 +1803,8 @@ <string name="managed_profile_label_badge" msgid="2355652472854327647">"কর্মক্ষেত্র <xliff:g id="LABEL">%1$s</xliff:g>"</string> <string name="lock_to_app_toast" msgid="7570091317001980053">"এই স্ক্রীনটিকে আনপিন করতে, \'ফিরুন\' এবং \'এক নজরে\' একসাথে স্পর্শ করুন এবং ধরে রাখুন৷"</string> <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"এই স্ক্রীনটিকে আনপিন করতে, \'এক নজরে\' স্পর্শ করুন এবং ধরে রাখুন৷"</string> - <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"স্ক্রীন পিন করা আছে। আপনার প্রতিষ্ঠান এটিকে পিনমুক্ত করার অনুমতি দেয়নি।"</string> + <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) --> + <skip /> <string name="lock_to_app_start" msgid="6643342070839862795">"স্ক্রীন পিন করা হয়েছে"</string> <string name="lock_to_app_exit" msgid="8598219838213787430">"পিন না করা স্ক্রীন"</string> <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"আনপিন করার আগে PIN চান"</string> diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml index 68768d4a6068..8884cae4bdf3 100644 --- a/core/res/res/values-ca/strings.xml +++ b/core/res/res/values-ca/strings.xml @@ -796,6 +796,8 @@ <string name="permdesc_accessNotifications" msgid="458457742683431387">"Permet que l\'aplicació recuperi, examini i esborri les notificacions, incloses les que han publicat altres aplicacions."</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"vincula a un servei oient de notificacions"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Permet que el titular vinculi la interfície de nivell superior d\'un servei oient de notificacions. No s\'hauria de necessitar mai per a les aplicacions normals."</string> + <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"vincular-se a un servei de destí de selector"</string> + <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Permet que el propietari la pugui vincular a la interfície principal d\'un servei de destí de selector. No s\'hauria de necessitar mai per a les aplicacions normals."</string> <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"enllaçar amb el servei de proveïdor de condicions"</string> <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Permet enllaçar amb la interfície de nivell superior d\'un servei de proveïdor de condicions. No ha de ser mai necessari per a aplicacions normals."</string> <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"vincular-se amb un servei de rutes multimèdia"</string> @@ -1263,6 +1265,14 @@ <string name="old_app_description" msgid="2082094275580358049">"No iniciïs l\'aplicació nova."</string> <string name="new_app_action" msgid="5472756926945440706">"Inicia <xliff:g id="OLD_APP">%1$s</xliff:g>"</string> <string name="new_app_description" msgid="1932143598371537340">"Atura l\'aplicació antiga sense desar."</string> + <!-- no translation found for dump_heap_notification (2618183274836056542) --> + <skip /> + <!-- no translation found for dump_heap_notification_detail (2075673362317481664) --> + <skip /> + <!-- no translation found for dump_heap_title (5864292264307651673) --> + <skip /> + <!-- no translation found for dump_heap_text (4809417337240334941) --> + <skip /> <string name="sendText" msgid="5209874571959469142">"Tria una acció per al text"</string> <string name="volume_ringtone" msgid="6885421406845734650">"Volum del timbre"</string> <string name="volume_music" msgid="5421651157138628171">"Volum de multimèdia"</string> @@ -1776,7 +1786,9 @@ <item quantity="one">Torna-ho a provar d\'aquí a 1 segon</item> </plurals> <string name="restr_pin_try_later" msgid="973144472490532377">"Torna-ho a provar més tard"</string> - <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Fes lliscar el dit cap avall per sortir de la pantalla completa."</string> + <string name="immersive_cling_title" msgid="8394201622932303336">"Visualització en pantalla completa"</string> + <string name="immersive_cling_description" msgid="3482371193207536040">"Per sortir, fes lliscar el dit cap avall des de la part superior."</string> + <string name="immersive_cling_positive" msgid="5016839404568297683">"D\'acord"</string> <string name="done_label" msgid="2093726099505892398">"Fet"</string> <string name="hour_picker_description" msgid="6698199186859736512">"Control circular de les hores"</string> <string name="minute_picker_description" msgid="8606010966873791190">"Control circular dels minuts"</string> @@ -1791,7 +1803,8 @@ <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> de la feina"</string> <string name="lock_to_app_toast" msgid="7570091317001980053">"Per anul·lar la fixació d\'aquesta pantalla, mantén premudes les opcions Enrere i Visió general alhora."</string> <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Per anul·lar la fixació d\'aquesta pantalla, mantén premuda l\'opció Visió general."</string> - <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"S\'ha fixat la pantalla. La teva organització no permet anul·lar-ne la fixació."</string> + <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) --> + <skip /> <string name="lock_to_app_start" msgid="6643342070839862795">"Pantalla fixada"</string> <string name="lock_to_app_exit" msgid="8598219838213787430">"Fixació de la pantalla anul·lada"</string> <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Demana el codi PIN abans d\'anul·lar la fixació"</string> diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml index 253f35c54c0b..1a023578a706 100644 --- a/core/res/res/values-cs/strings.xml +++ b/core/res/res/values-cs/strings.xml @@ -798,6 +798,8 @@ <string name="permdesc_accessNotifications" msgid="458457742683431387">"Umožňuje aplikacím načítat, zobrazovat a mazat oznámení včetně těch přidaných jinými aplikacemi."</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"navázání na službu pro poslouchání oznámení"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Umožňuje držiteli navázat se na nejvyšší úroveň služby pro poslouchání oznámení. Běžné aplikace by toto oprávnění neměly nikdy požadovat."</string> + <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"navázat se na cílovou službu nástroje pro výběr"</string> + <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Umožňuje držiteli navázat se na rozhraní nejvyšší úrovně cílové služby nástroje pro výběr. Běžné aplikace by toto oprávnění neměly nikdy potřebovat."</string> <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"navázání na službu poskytovatele podmínky"</string> <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Umožňuje držiteli navázat se na nejvyšší úroveň rozhraní služby poskytovatele podmínky. Běžné aplikace by toto oprávnění neměly nikdy potřebovat."</string> <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"navázání na službu směrování médií"</string> @@ -1273,6 +1275,14 @@ <string name="old_app_description" msgid="2082094275580358049">"Nespouštět novou aplikaci."</string> <string name="new_app_action" msgid="5472756926945440706">"Spustit aplikaci <xliff:g id="OLD_APP">%1$s</xliff:g>"</string> <string name="new_app_description" msgid="1932143598371537340">"Zastavit starou aplikaci bez uložení."</string> + <!-- no translation found for dump_heap_notification (2618183274836056542) --> + <skip /> + <!-- no translation found for dump_heap_notification_detail (2075673362317481664) --> + <skip /> + <!-- no translation found for dump_heap_title (5864292264307651673) --> + <skip /> + <!-- no translation found for dump_heap_text (4809417337240334941) --> + <skip /> <string name="sendText" msgid="5209874571959469142">"Vyberte akci pro text"</string> <string name="volume_ringtone" msgid="6885421406845734650">"Hlasitost vyzvánění"</string> <string name="volume_music" msgid="5421651157138628171">"Hlasitost médií"</string> @@ -1794,7 +1804,9 @@ <item quantity="one">Zkuste to znovu za 1 sekundu</item> </plurals> <string name="restr_pin_try_later" msgid="973144472490532377">"Zkuste to znovu později"</string> - <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Režim celé obrazovky ukončíte přejetím dolů."</string> + <string name="immersive_cling_title" msgid="8394201622932303336">"Zobrazení celé obrazovky"</string> + <string name="immersive_cling_description" msgid="3482371193207536040">"Režim ukončíte přejetím prstem shora dolů."</string> + <string name="immersive_cling_positive" msgid="5016839404568297683">"Rozumím"</string> <string name="done_label" msgid="2093726099505892398">"Hotovo"</string> <string name="hour_picker_description" msgid="6698199186859736512">"Kruhový posuvník hodin"</string> <string name="minute_picker_description" msgid="8606010966873791190">"Kruhový posuvník minut"</string> @@ -1809,7 +1821,8 @@ <string name="managed_profile_label_badge" msgid="2355652472854327647">"Pracovní <xliff:g id="LABEL">%1$s</xliff:g>"</string> <string name="lock_to_app_toast" msgid="7570091317001980053">"Chcete-li tuto obrazovku uvolnit, klepněte současně na možnosti Zpět a Přehled a podržte je."</string> <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Chcete-li tuto obrazovku uvolnit, klepněte na možnost Přehled a podržte ji."</string> - <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Obrazovka je připnuta. Vaše organizace uvolnění zakázala."</string> + <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) --> + <skip /> <string name="lock_to_app_start" msgid="6643342070839862795">"Obrazovka připnuta"</string> <string name="lock_to_app_exit" msgid="8598219838213787430">"Obrazovka uvolněna"</string> <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Před uvolněním požádat o kód PIN"</string> diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml index 59c276f4982a..07a588a18fd8 100644 --- a/core/res/res/values-da/strings.xml +++ b/core/res/res/values-da/strings.xml @@ -786,7 +786,7 @@ <string name="permdesc_bind_connection_service" msgid="4008754499822478114">"Tillader, at appen kan interagere med telefonitjenester for at foretage/modtage opkald."</string> <string name="permlab_control_incall_experience" msgid="9061024437607777619">"leverer brugeroplevelsen under opkald"</string> <string name="permdesc_control_incall_experience" msgid="915159066039828124">"Tillader, at appen leverer brugeroplevelsen under opkald."</string> - <string name="permlab_readNetworkUsageHistory" msgid="7862593283611493232">"læse oversigt over netværksbrug"</string> + <string name="permlab_readNetworkUsageHistory" msgid="7862593283611493232">"læse historisk netværksbrug"</string> <string name="permdesc_readNetworkUsageHistory" msgid="7689060749819126472">"Tillader, at appen kan læse historisk netværksbrug for specifikke netværk og apps."</string> <string name="permlab_manageNetworkPolicy" msgid="2562053592339859990">"administrer netværkspolitik"</string> <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Tillader, at appen kan administrere netværkspolitikker og definere appspecifikke regler."</string> @@ -796,6 +796,8 @@ <string name="permdesc_accessNotifications" msgid="458457742683431387">"Tillader, at appen kan hente, undersøge og rydde underretninger, f.eks. dem, der er sendt af andre apps."</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"forpligte sig til en underretningslyttertjeneste"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Tillader brugeren at forpligte sig til en underretningslyttertjenestes grænseflade på øverste niveau. Bør aldrig være nødvendigt til almindelige apps."</string> + <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"knytte sig til en tjeneste til valg af mål"</string> + <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Tillader, at appen kan knytte sig til det øverste grænsefladeniveau for en tjeneste til valg af mål. Dette bør aldrig være nødvendigt for almindelige apps."</string> <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"oprette binding til en tjeneste til formidling af betingelser"</string> <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Tillader, at brugeren opretter en binding til det øverste niveau af grænsefladen i en tjeneste til formidling af betingelser. Dette bør aldrig være nødvendigt for almindelige apps."</string> <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"opret binding til en medierutetjeneste"</string> @@ -1263,6 +1265,14 @@ <string name="old_app_description" msgid="2082094275580358049">"Åbn ikke den nye app."</string> <string name="new_app_action" msgid="5472756926945440706">"Start <xliff:g id="OLD_APP">%1$s</xliff:g>"</string> <string name="new_app_description" msgid="1932143598371537340">"Stop den gamle app uden at gemme."</string> + <!-- no translation found for dump_heap_notification (2618183274836056542) --> + <skip /> + <!-- no translation found for dump_heap_notification_detail (2075673362317481664) --> + <skip /> + <!-- no translation found for dump_heap_title (5864292264307651673) --> + <skip /> + <!-- no translation found for dump_heap_text (4809417337240334941) --> + <skip /> <string name="sendText" msgid="5209874571959469142">"Vælg en handling for teksten"</string> <string name="volume_ringtone" msgid="6885421406845734650">"Lydstyrke for opkald"</string> <string name="volume_music" msgid="5421651157138628171">"Lydstyrke for medier"</string> @@ -1776,7 +1786,9 @@ <item quantity="other">Prøv igen om <xliff:g id="COUNT">%d</xliff:g> sekunder</item> </plurals> <string name="restr_pin_try_later" msgid="973144472490532377">"Prøv igen senere"</string> - <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Stryg ned fra toppen for at afslutte fuld skærm"</string> + <string name="immersive_cling_title" msgid="8394201622932303336">"Visning i fuld skærm"</string> + <string name="immersive_cling_description" msgid="3482371193207536040">"Stryg ned fra toppen for at afslutte."</string> + <string name="immersive_cling_positive" msgid="5016839404568297683">"OK, det er forstået"</string> <string name="done_label" msgid="2093726099505892398">"Udfør"</string> <string name="hour_picker_description" msgid="6698199186859736512">"Cirkulær timevælger"</string> <string name="minute_picker_description" msgid="8606010966873791190">"Cirkulær minutvælger"</string> @@ -1791,7 +1803,8 @@ <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> – arbejde"</string> <string name="lock_to_app_toast" msgid="7570091317001980053">"Hvis du vil frigøre dette skærmbillede, skal du trykke på Tilbage og Oversigt på samme tid og holde fingeren nede."</string> <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Hvis du vil frigøre dette skærmbillede, skal du trykke på Oversigt og holde fingeren nede."</string> - <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Skærmen er fastgjort. Frigørelse er ikke tilladt af din organisation."</string> + <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) --> + <skip /> <string name="lock_to_app_start" msgid="6643342070839862795">"Skærmen blev fastgjort"</string> <string name="lock_to_app_exit" msgid="8598219838213787430">"Skærmen blev frigjort"</string> <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Bed om pinkode inden frigørelse"</string> diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml index 3af1706e8300..72eff6f177cc 100644 --- a/core/res/res/values-de/strings.xml +++ b/core/res/res/values-de/strings.xml @@ -738,14 +738,10 @@ <string name="permdesc_nfc" msgid="7120611819401789907">"Ermöglicht der App die Kommunikation mit Tags für die Nahfeldkommunikation, Karten und Readern"</string> <string name="permlab_disableKeyguard" msgid="3598496301486439258">"Displaysperre deaktivieren"</string> <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"Ermöglicht der App, die Tastensperre sowie den damit verbundenen Passwortschutz zu deaktivieren. Das Telefon deaktiviert die Tastensperre beispielsweise, wenn ein Anruf eingeht, und aktiviert sie wieder, nachdem das Gespräch beendet wurde."</string> - <!-- no translation found for permlab_manageFingerprint (5640858826254575638) --> - <skip /> - <!-- no translation found for permdesc_manageFingerprint (178208705828055464) --> - <skip /> - <!-- no translation found for permlab_useFingerprint (3150478619915124905) --> - <skip /> - <!-- no translation found for permdesc_useFingerprint (9165097460730684114) --> - <skip /> + <string name="permlab_manageFingerprint" msgid="5640858826254575638">"Fingerabdruckhardware verwalten"</string> + <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Erlaubt der App, Methoden zum Hinzufügen und Löschen zu verwendender Fingerabdruckvorlagen aufzurufen"</string> + <string name="permlab_useFingerprint" msgid="3150478619915124905">"Fingerabdruckhardware verwenden"</string> + <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Erlaubt der App, Fingerabdruckhardware zur Authentifizierung zu verwenden"</string> <string name="permlab_readSyncSettings" msgid="6201810008230503052">"Synchronisierungseinstellungen lesen"</string> <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Ermöglicht der App, die Synchronisierungseinstellungen eines Kontos zu lesen. Beispielsweise kann damit festgestellt werden, ob Kontakte mit einem Konto synchronisiert werden."</string> <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"Synchronisierung aktivieren oder deaktivieren"</string> @@ -800,6 +796,8 @@ <string name="permdesc_accessNotifications" msgid="458457742683431387">"Ermöglicht der App das Abrufen, Überprüfen und Löschen von Benachrichtigungen, einschließlich Benachrichtigungen, die von anderen Apps gepostet wurden"</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"An Benachrichtigungs-Listener-Dienst binden"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Ermöglicht dem Inhaber, sich an die Oberfläche der obersten Ebene eines Benachrichtigungs-Listener-Dienstes zu binden. Sollte nie für normale Apps benötigt werden."</string> + <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"An einen Zielauswahldienst binden"</string> + <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Ermöglicht dem Inhaber, sich an die Oberfläche eines Zielauswahldienstes auf oberster Ebene zu binden. Für normale Apps sollte dies nie erforderlich sein."</string> <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"An einen Bedingungsproviderdienst binden"</string> <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Ermöglicht dem Inhaber, sich an die Oberfläche eines Bedingungsproviderdienstes auf oberster Ebene zu binden. Für normale Apps sollte dies nie erforderlich sein."</string> <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"An Mediarouting-Dienst binden"</string> @@ -1267,6 +1265,14 @@ <string name="old_app_description" msgid="2082094275580358049">"Neue App nicht starten"</string> <string name="new_app_action" msgid="5472756926945440706">"<xliff:g id="OLD_APP">%1$s</xliff:g> starten"</string> <string name="new_app_description" msgid="1932143598371537340">"Alte App beenden, ohne zu speichern"</string> + <!-- no translation found for dump_heap_notification (2618183274836056542) --> + <skip /> + <!-- no translation found for dump_heap_notification_detail (2075673362317481664) --> + <skip /> + <!-- no translation found for dump_heap_title (5864292264307651673) --> + <skip /> + <!-- no translation found for dump_heap_text (4809417337240334941) --> + <skip /> <string name="sendText" msgid="5209874571959469142">"Aktion für Text auswählen"</string> <string name="volume_ringtone" msgid="6885421406845734650">"Klingeltonlautstärke"</string> <string name="volume_music" msgid="5421651157138628171">"Medienlautstärke"</string> @@ -1780,7 +1786,9 @@ <item quantity="one">In 1 Sek. wiederholen</item> </plurals> <string name="restr_pin_try_later" msgid="973144472490532377">"Später erneut versuchen"</string> - <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Zum Schließen des Vollbilds von oben nach unten wischen"</string> + <string name="immersive_cling_title" msgid="8394201622932303336">"Vollbildmodus wird aktiviert"</string> + <string name="immersive_cling_description" msgid="3482371193207536040">"Zum Beenden von oben nach unten wischen"</string> + <string name="immersive_cling_positive" msgid="5016839404568297683">"OK"</string> <string name="done_label" msgid="2093726099505892398">"Fertig"</string> <string name="hour_picker_description" msgid="6698199186859736512">"Kreisförmiger Schieberegler für Stunden"</string> <string name="minute_picker_description" msgid="8606010966873791190">"Kreisförmiger Schieberegler für Minuten"</string> @@ -1795,7 +1803,8 @@ <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> (geschäftlich)"</string> <string name="lock_to_app_toast" msgid="7570091317001980053">"Um die Fixierung dieses Bildschirms aufzuheben, berühren und halten Sie gleichzeitig \"Zurück\" und \"Übersicht\"."</string> <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Um die Fixierung dieses Bildschirms aufzuheben, berühren und halten Sie \"Übersicht\"."</string> - <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Der Bildschirm ist fixiert. Sie sind nicht berechtigt, diese Einstellung zu beenden."</string> + <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) --> + <skip /> <string name="lock_to_app_start" msgid="6643342070839862795">"Bildschirm fixiert"</string> <string name="lock_to_app_exit" msgid="8598219838213787430">"Bildschirm gelöst"</string> <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Vor dem Beenden nach PIN fragen"</string> diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml index 0779d064d37e..caa3408c23ef 100644 --- a/core/res/res/values-el/strings.xml +++ b/core/res/res/values-el/strings.xml @@ -796,6 +796,8 @@ <string name="permdesc_accessNotifications" msgid="458457742683431387">"Επιτρέπει στην εφαρμογή να ανακτά, να εξετάζει και να απαλείφει ειδοποιήσεις, συμπεριλαμβανομένων εκείνων που δημοσιεύονται από άλλες εφαρμογές."</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"δέσμευση σε υπηρεσία ακρόασης ειδοποίησης"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Επιτρέπει στον κάτοχο τη δέσμευση στη διεπαφή ανωτάτου επιπέδου μιας υπηρεσίας ακρόασης ειδοποιήσεων. Δεν απαιτείται σε κανονικές εφαρμογές."</string> + <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"δέσμευση σε υπηρεσία επιλογής στόχευσης"</string> + <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Επιτρέπει στον κάτοχο τη δέσμευση στη διεπαφή ανωτάτου επιπέδου μιας υπηρεσίας επιλογής στόχευσης. Δεν απαιτείται σε κανονικές εφαρμογές."</string> <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"σύνδεση σε μια υπηρεσία παρόχου συνθηκών"</string> <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Επιτρέπει στον κάτοχο τη σύνδεση στη διεπαφή ανωτάτου επιπέδου ενός παρόχου συνθηκών. Δεν απαιτείται για κανονικές εφαρμογές."</string> <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"σύνδεση σε μια υπηρεσία δρομολόγησης μέσων"</string> @@ -1263,6 +1265,14 @@ <string name="old_app_description" msgid="2082094275580358049">"Μην εκκινήσετε τη νέα εφαρμογή."</string> <string name="new_app_action" msgid="5472756926945440706">"Εκκίνηση της εφαρμογής <xliff:g id="OLD_APP">%1$s</xliff:g>"</string> <string name="new_app_description" msgid="1932143598371537340">"Διακοπή της παλιάς εφαρμογής χωρίς αποθήκευση."</string> + <!-- no translation found for dump_heap_notification (2618183274836056542) --> + <skip /> + <!-- no translation found for dump_heap_notification_detail (2075673362317481664) --> + <skip /> + <!-- no translation found for dump_heap_title (5864292264307651673) --> + <skip /> + <!-- no translation found for dump_heap_text (4809417337240334941) --> + <skip /> <string name="sendText" msgid="5209874571959469142">"Επιλέξτε μια ενέργεια για το κείμενο"</string> <string name="volume_ringtone" msgid="6885421406845734650">"Ένταση ήχου ειδοποίησης"</string> <string name="volume_music" msgid="5421651157138628171">"Ένταση ήχου πολυμέσων"</string> @@ -1776,7 +1786,9 @@ <item quantity="one">Δοκιμάστε ξανά σε 1 δευτερόλεπτο</item> </plurals> <string name="restr_pin_try_later" msgid="973144472490532377">"Δοκιμάστε ξανά αργότερα"</string> - <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Σάρωση προς τα κάτω για έξοδο από πλήρη οθόνη"</string> + <string name="immersive_cling_title" msgid="8394201622932303336">"Προβολή σε πλήρη οθόνη"</string> + <string name="immersive_cling_description" msgid="3482371193207536040">"Για έξοδο, σύρετε προς τα κάτω από το επάνω μέρος."</string> + <string name="immersive_cling_positive" msgid="5016839404568297683">"Το κατάλαβα"</string> <string name="done_label" msgid="2093726099505892398">"Τέλος"</string> <string name="hour_picker_description" msgid="6698199186859736512">"Κυκλικό ρυθμιστικό ωρών"</string> <string name="minute_picker_description" msgid="8606010966873791190">"Κυκλικό ρυθμιστικό λεπτών"</string> @@ -1791,7 +1803,8 @@ <string name="managed_profile_label_badge" msgid="2355652472854327647">"Εργασία <xliff:g id="LABEL">%1$s</xliff:g>"</string> <string name="lock_to_app_toast" msgid="7570091317001980053">"Για να ξεκαρφιτσώσετε αυτήν την οθόνη, πατήστε παρατεταμένα \"Επιστροφή\" και \"Επισκόπηση\" ταυτόχρονα."</string> <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Για να ξεκαρφιτσώσετε αυτήν την οθόνη, αγγίξτε παρατεταμένα \"Επισκόπηση\"."</string> - <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Η οθόνη καρφιστώθηκε. Το ξεκαρφίτσωμα δεν επιτρέπεται από τον οργανισμό σας."</string> + <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) --> + <skip /> <string name="lock_to_app_start" msgid="6643342070839862795">"Η οθόνη καρφιτσώθηκε"</string> <string name="lock_to_app_exit" msgid="8598219838213787430">"Η οθόνη ξεκαρφιτσώθηκε"</string> <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Να γίνεται ερώτηση για το PIN, πριν από το ξεκαρφίτσωμα"</string> diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml index b8bd7eb8229f..e75df385b643 100644 --- a/core/res/res/values-en-rGB/strings.xml +++ b/core/res/res/values-en-rGB/strings.xml @@ -796,6 +796,8 @@ <string name="permdesc_accessNotifications" msgid="458457742683431387">"Allows the app to retrieve, examine, and clear notifications, including those posted by other apps."</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"bind to a notification listener service"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Allows the holder to bind to the top-level interface of a notification listener service. Should never be needed for normal apps."</string> + <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"bind to a chooser target service"</string> + <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Allows the holder to bind to the top-level interface of a chooser target service. Should never be needed for normal apps."</string> <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"bind to a condition provider service"</string> <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Allows the holder to bind to the top-level interface of a condition provider service. Should never be needed for normal apps."</string> <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"bind to a media route service"</string> @@ -1263,6 +1265,14 @@ <string name="old_app_description" msgid="2082094275580358049">"Don\'t start the new app."</string> <string name="new_app_action" msgid="5472756926945440706">"Start <xliff:g id="OLD_APP">%1$s</xliff:g>"</string> <string name="new_app_description" msgid="1932143598371537340">"Stop the old app without saving."</string> + <!-- no translation found for dump_heap_notification (2618183274836056542) --> + <skip /> + <!-- no translation found for dump_heap_notification_detail (2075673362317481664) --> + <skip /> + <!-- no translation found for dump_heap_title (5864292264307651673) --> + <skip /> + <!-- no translation found for dump_heap_text (4809417337240334941) --> + <skip /> <string name="sendText" msgid="5209874571959469142">"Choose an action for text"</string> <string name="volume_ringtone" msgid="6885421406845734650">"Ringer volume"</string> <string name="volume_music" msgid="5421651157138628171">"Media volume"</string> @@ -1776,7 +1786,9 @@ <item quantity="one">Try again in 1 second</item> </plurals> <string name="restr_pin_try_later" msgid="973144472490532377">"Try again later"</string> - <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Swipe down from the top to exit full screen."</string> + <string name="immersive_cling_title" msgid="8394201622932303336">"Viewing full screen"</string> + <string name="immersive_cling_description" msgid="3482371193207536040">"To exit, swipe down from the top."</string> + <string name="immersive_cling_positive" msgid="5016839404568297683">"Got it"</string> <string name="done_label" msgid="2093726099505892398">"Done"</string> <string name="hour_picker_description" msgid="6698199186859736512">"Hours circular slider"</string> <string name="minute_picker_description" msgid="8606010966873791190">"Minutes circular slider"</string> @@ -1791,7 +1803,8 @@ <string name="managed_profile_label_badge" msgid="2355652472854327647">"Work <xliff:g id="LABEL">%1$s</xliff:g>"</string> <string name="lock_to_app_toast" msgid="7570091317001980053">"To unpin this screen, touch and hold Back and Overview at the same time."</string> <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"To unpin this screen, touch and hold Overview."</string> - <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Screen is pinned. Unpinning isn\'t allowed by your organisation."</string> + <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) --> + <skip /> <string name="lock_to_app_start" msgid="6643342070839862795">"Screen pinned"</string> <string name="lock_to_app_exit" msgid="8598219838213787430">"Screen unpinned"</string> <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Ask for PIN before unpinning"</string> diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml index b8bd7eb8229f..e75df385b643 100644 --- a/core/res/res/values-en-rIN/strings.xml +++ b/core/res/res/values-en-rIN/strings.xml @@ -796,6 +796,8 @@ <string name="permdesc_accessNotifications" msgid="458457742683431387">"Allows the app to retrieve, examine, and clear notifications, including those posted by other apps."</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"bind to a notification listener service"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Allows the holder to bind to the top-level interface of a notification listener service. Should never be needed for normal apps."</string> + <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"bind to a chooser target service"</string> + <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Allows the holder to bind to the top-level interface of a chooser target service. Should never be needed for normal apps."</string> <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"bind to a condition provider service"</string> <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Allows the holder to bind to the top-level interface of a condition provider service. Should never be needed for normal apps."</string> <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"bind to a media route service"</string> @@ -1263,6 +1265,14 @@ <string name="old_app_description" msgid="2082094275580358049">"Don\'t start the new app."</string> <string name="new_app_action" msgid="5472756926945440706">"Start <xliff:g id="OLD_APP">%1$s</xliff:g>"</string> <string name="new_app_description" msgid="1932143598371537340">"Stop the old app without saving."</string> + <!-- no translation found for dump_heap_notification (2618183274836056542) --> + <skip /> + <!-- no translation found for dump_heap_notification_detail (2075673362317481664) --> + <skip /> + <!-- no translation found for dump_heap_title (5864292264307651673) --> + <skip /> + <!-- no translation found for dump_heap_text (4809417337240334941) --> + <skip /> <string name="sendText" msgid="5209874571959469142">"Choose an action for text"</string> <string name="volume_ringtone" msgid="6885421406845734650">"Ringer volume"</string> <string name="volume_music" msgid="5421651157138628171">"Media volume"</string> @@ -1776,7 +1786,9 @@ <item quantity="one">Try again in 1 second</item> </plurals> <string name="restr_pin_try_later" msgid="973144472490532377">"Try again later"</string> - <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Swipe down from the top to exit full screen."</string> + <string name="immersive_cling_title" msgid="8394201622932303336">"Viewing full screen"</string> + <string name="immersive_cling_description" msgid="3482371193207536040">"To exit, swipe down from the top."</string> + <string name="immersive_cling_positive" msgid="5016839404568297683">"Got it"</string> <string name="done_label" msgid="2093726099505892398">"Done"</string> <string name="hour_picker_description" msgid="6698199186859736512">"Hours circular slider"</string> <string name="minute_picker_description" msgid="8606010966873791190">"Minutes circular slider"</string> @@ -1791,7 +1803,8 @@ <string name="managed_profile_label_badge" msgid="2355652472854327647">"Work <xliff:g id="LABEL">%1$s</xliff:g>"</string> <string name="lock_to_app_toast" msgid="7570091317001980053">"To unpin this screen, touch and hold Back and Overview at the same time."</string> <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"To unpin this screen, touch and hold Overview."</string> - <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Screen is pinned. Unpinning isn\'t allowed by your organisation."</string> + <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) --> + <skip /> <string name="lock_to_app_start" msgid="6643342070839862795">"Screen pinned"</string> <string name="lock_to_app_exit" msgid="8598219838213787430">"Screen unpinned"</string> <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Ask for PIN before unpinning"</string> diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml index e3f347651859..84718dd9af2f 100644 --- a/core/res/res/values-es-rUS/strings.xml +++ b/core/res/res/values-es-rUS/strings.xml @@ -738,14 +738,10 @@ <string name="permdesc_nfc" msgid="7120611819401789907">"Permite que la aplicación se comunique con lectores, tarjetas y etiquetas de Comunicación de campo cercano (NFC)."</string> <string name="permlab_disableKeyguard" msgid="3598496301486439258">"desactivar el bloqueo de pantalla"</string> <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"Permite que la aplicación desactive el bloqueo del teclado y cualquier protección con contraseña asociada. Por ejemplo, el dispositivo puede desactivar el bloqueo del teclado cuando recibe una llamada telefónica y volver a activarlo cuando finaliza la llamada."</string> - <!-- no translation found for permlab_manageFingerprint (5640858826254575638) --> - <skip /> - <!-- no translation found for permdesc_manageFingerprint (178208705828055464) --> - <skip /> - <!-- no translation found for permlab_useFingerprint (3150478619915124905) --> - <skip /> - <!-- no translation found for permdesc_useFingerprint (9165097460730684114) --> - <skip /> + <string name="permlab_manageFingerprint" msgid="5640858826254575638">"Administrar el hardware de huellas digitales"</string> + <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Permite que la aplicación emplee métodos para agregar y eliminar plantillas de huellas digitales para su uso."</string> + <string name="permlab_useFingerprint" msgid="3150478619915124905">"Utilizar hardware de huellas digitales"</string> + <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Permite que la aplicación utilice el hardware de huellas digitales para realizar la autenticación."</string> <string name="permlab_readSyncSettings" msgid="6201810008230503052">"leer la configuración de sincronización"</string> <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Este permiso permite que la aplicación consulte la configuración de sincronización de una cuenta. Esto permite, por ejemplo, determinar si la aplicación Personas está sincronizada con una cuenta."</string> <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"activar y desactivar la sincronización"</string> @@ -800,6 +796,8 @@ <string name="permdesc_accessNotifications" msgid="458457742683431387">"Permite que la aplicación recupere, examine y elimine notificaciones, incluidas aquellas publicadas por otras aplicaciones."</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"Vincular a un servicio de agente de escucha de notificaciones"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Permite al propietario vincularse a la interfaz de nivel superior de un servicio de agente de escucha de notificaciones. Las aplicaciones normales no deberían necesitar este permiso."</string> + <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"vincularse a un servicio de destino selector"</string> + <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Permite al propietario vincularse a la interfaz de nivel superior de un servicio de destino. Las aplicaciones normales no deberían necesitar este permiso."</string> <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"vincular con un servicio de proveedor de condiciones"</string> <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Permite vincular con la interfaz de nivel superior de un servicio de proveedor de condiciones. Las aplicaciones normales no deberían necesitar este permiso."</string> <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"vincular a un servicio de enrutamiento de contenido multimedia"</string> @@ -1267,6 +1265,14 @@ <string name="old_app_description" msgid="2082094275580358049">"No iniciar la nueva aplicación."</string> <string name="new_app_action" msgid="5472756926945440706">"Inicio <xliff:g id="OLD_APP">%1$s</xliff:g>"</string> <string name="new_app_description" msgid="1932143598371537340">"Interrumpe la aplicación anterior sin guardar los cambios."</string> + <!-- no translation found for dump_heap_notification (2618183274836056542) --> + <skip /> + <!-- no translation found for dump_heap_notification_detail (2075673362317481664) --> + <skip /> + <!-- no translation found for dump_heap_title (5864292264307651673) --> + <skip /> + <!-- no translation found for dump_heap_text (4809417337240334941) --> + <skip /> <string name="sendText" msgid="5209874571959469142">"Seleccionar una acción para el texto"</string> <string name="volume_ringtone" msgid="6885421406845734650">"Volumen del timbre"</string> <string name="volume_music" msgid="5421651157138628171">"Volumen de los medios"</string> @@ -1780,7 +1786,9 @@ <item quantity="one">Vuelve a intentarlo en 1 segundo.</item> </plurals> <string name="restr_pin_try_later" msgid="973144472490532377">"Vuelve a intentar más tarde."</string> - <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Desliza el dedo hacia abajo para salir de la pantalla completa."</string> + <string name="immersive_cling_title" msgid="8394201622932303336">"Visualización en pantalla completa"</string> + <string name="immersive_cling_description" msgid="3482371193207536040">"Para salir, desliza el dedo hacia abajo desde la parte superior."</string> + <string name="immersive_cling_positive" msgid="5016839404568297683">"Entendido"</string> <string name="done_label" msgid="2093726099505892398">"Listo"</string> <string name="hour_picker_description" msgid="6698199186859736512">"Control deslizante circular de horas"</string> <string name="minute_picker_description" msgid="8606010966873791190">"Control deslizante circular de minutos"</string> @@ -1795,7 +1803,8 @@ <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> de trabajo"</string> <string name="lock_to_app_toast" msgid="7570091317001980053">"Para dejar de fijar esta pantalla, mantén presionados los botones para volver y Recientes al mismo tiempo."</string> <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Para dejar de fijar esta pantalla, mantén presionado el botón Recientes."</string> - <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"La pantalla está fija. La organización no permite dejar de fijar la pantalla."</string> + <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) --> + <skip /> <string name="lock_to_app_start" msgid="6643342070839862795">"Pantalla fija"</string> <string name="lock_to_app_exit" msgid="8598219838213787430">"Pantalla no fija"</string> <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Solicitar PIN para quitar fijación"</string> diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml index b5d5397f7a82..df148a077965 100644 --- a/core/res/res/values-es/strings.xml +++ b/core/res/res/values-es/strings.xml @@ -738,14 +738,10 @@ <string name="permdesc_nfc" msgid="7120611819401789907">"Permite que la aplicación se comunique con lectores, tarjetas y etiquetas de Comunicación de campo cercano (NFC)."</string> <string name="permlab_disableKeyguard" msgid="3598496301486439258">"inhabilitar el bloqueo de pantalla"</string> <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"Permite que la aplicación inhabilite el bloqueo del teclado y cualquier protección con contraseña asociada. Por ejemplo, el teléfono puede inhabilitar el bloqueo del teclado cuando se recibe una llamada telefónica y volver a habilitarlo cuando finaliza la llamada."</string> - <!-- no translation found for permlab_manageFingerprint (5640858826254575638) --> - <skip /> - <!-- no translation found for permdesc_manageFingerprint (178208705828055464) --> - <skip /> - <!-- no translation found for permlab_useFingerprint (3150478619915124905) --> - <skip /> - <!-- no translation found for permdesc_useFingerprint (9165097460730684114) --> - <skip /> + <string name="permlab_manageFingerprint" msgid="5640858826254575638">"administrar hardware de huellas digitales"</string> + <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Permite que la aplicación invoque métodos para añadir y eliminar plantillas de huellas digitales y utilizarlas."</string> + <string name="permlab_useFingerprint" msgid="3150478619915124905">"utilizar hardware de huellas digitales"</string> + <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Permite que la aplicación utilice el hardware de huellas digitales para realizar la autenticación"</string> <string name="permlab_readSyncSettings" msgid="6201810008230503052">"leer la configuración de sincronización"</string> <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Permite que la aplicación consulte la configuración de sincronización de una cuenta. La aplicación puede utilizar este permiso, por ejemplo, para determinar si la aplicación Contactos está sincronizada con una cuenta."</string> <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"activar y desactivar la sincronización"</string> @@ -800,6 +796,8 @@ <string name="permdesc_accessNotifications" msgid="458457742683431387">"Permite que la aplicación recupere, examine y borre notificaciones, incluidas las que han publicado otras aplicaciones."</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"enlazar con un servicio de detector de notificaciones"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Permite enlazar con la interfaz de nivel superior de un servicio de detector de notificaciones. No debe ser necesario para las aplicaciones normales."</string> + <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"enlazar con un servicio de destino selector"</string> + <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Permite que el titular enlace con la interfaz de nivel superior de un servicio de destino selector. Las aplicaciones normales no deberían necesitar nunca este permiso."</string> <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"enlazar con un servicio de proveedor de condiciones"</string> <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Permite enlazar con la interfaz de nivel superior de un servicio de proveedor de condiciones. Las aplicaciones normales no deberían necesitar este permiso."</string> <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"enlazar a un servicio de rutas multimedia"</string> @@ -1267,6 +1265,14 @@ <string name="old_app_description" msgid="2082094275580358049">"No iniciar la nueva aplicación"</string> <string name="new_app_action" msgid="5472756926945440706">"Iniciar <xliff:g id="OLD_APP">%1$s</xliff:g>"</string> <string name="new_app_description" msgid="1932143598371537340">"Detener la aplicación anterior sin guardar"</string> + <!-- no translation found for dump_heap_notification (2618183274836056542) --> + <skip /> + <!-- no translation found for dump_heap_notification_detail (2075673362317481664) --> + <skip /> + <!-- no translation found for dump_heap_title (5864292264307651673) --> + <skip /> + <!-- no translation found for dump_heap_text (4809417337240334941) --> + <skip /> <string name="sendText" msgid="5209874571959469142">"Selecciona una acción para el texto"</string> <string name="volume_ringtone" msgid="6885421406845734650">"Volumen del timbre"</string> <string name="volume_music" msgid="5421651157138628171">"Volumen multimedia"</string> @@ -1780,7 +1786,9 @@ <item quantity="one">Vuelve a intentarlo en 1 segundo</item> </plurals> <string name="restr_pin_try_later" msgid="973144472490532377">"Volver a intentar más tarde"</string> - <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Desliza el dedo hacia abajo para salir de la pantalla completa"</string> + <string name="immersive_cling_title" msgid="8394201622932303336">"Mostrando pantalla completa"</string> + <string name="immersive_cling_description" msgid="3482371193207536040">"Para salir, desliza el dedo hacia abajo desde la parte superior de la pantalla."</string> + <string name="immersive_cling_positive" msgid="5016839404568297683">"Entendido"</string> <string name="done_label" msgid="2093726099505892398">"Listo"</string> <string name="hour_picker_description" msgid="6698199186859736512">"Control deslizante circular de horas"</string> <string name="minute_picker_description" msgid="8606010966873791190">"Control deslizante circular de minutos"</string> @@ -1795,7 +1803,8 @@ <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> de trabajo"</string> <string name="lock_to_app_toast" msgid="7570091317001980053">"Para desactivar esta pantalla, mantén pulsados los botones de retroceso y Visión general al mismo tiempo."</string> <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Para desactivar esta pantalla, mantén pulsado Visión general."</string> - <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Se ha activado la pantalla. Tu organización no puede desactivarla."</string> + <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) --> + <skip /> <string name="lock_to_app_start" msgid="6643342070839862795">"Pantalla fijada"</string> <string name="lock_to_app_exit" msgid="8598219838213787430">"La pantalla ya no está fija"</string> <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Solicitar PIN para desactivar"</string> diff --git a/core/res/res/values-et-rEE/strings.xml b/core/res/res/values-et-rEE/strings.xml index c7a07b8fb4e3..a428496c32ba 100644 --- a/core/res/res/values-et-rEE/strings.xml +++ b/core/res/res/values-et-rEE/strings.xml @@ -796,6 +796,8 @@ <string name="permdesc_accessNotifications" msgid="458457742683431387">"Võimaldab rakendusel tuua, kontrollida ja kustutada märguandeid, sh neid, mille on postitanud teised rakendused."</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"seo märguannete kuulamisteenusega"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Võimaldab omanikul siduda märguannete kuulamisteenuse ülemise taseme kasutajaliidese. Seda ei tohiks tavarakenduste puhul kunagi vaja olla."</string> + <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"valija sihtteenusega sidumine"</string> + <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Võimaldab omanikul siduda valija sihtteenuse ülataseme liidesega. Tavarakenduste puhul ei peaks seda kunagi vaja minema."</string> <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"seo tingimuse pakkuja teenusega"</string> <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Lubab omanikul siduda tingimuse pakkuja teenuse ülataseme liidesega. Pole kunagi vajalik tavaliste rakenduste puhul."</string> <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"meediumi marsruutimise teenusega sidumine"</string> @@ -1263,6 +1265,14 @@ <string name="old_app_description" msgid="2082094275580358049">"Ärge käivitage uut rakendust."</string> <string name="new_app_action" msgid="5472756926945440706">"Käivitage rakendus <xliff:g id="OLD_APP">%1$s</xliff:g>"</string> <string name="new_app_description" msgid="1932143598371537340">"Peatage vana rakendus salvestamata."</string> + <!-- no translation found for dump_heap_notification (2618183274836056542) --> + <skip /> + <!-- no translation found for dump_heap_notification_detail (2075673362317481664) --> + <skip /> + <!-- no translation found for dump_heap_title (5864292264307651673) --> + <skip /> + <!-- no translation found for dump_heap_text (4809417337240334941) --> + <skip /> <string name="sendText" msgid="5209874571959469142">"Valige teksti jaoks toiming"</string> <string name="volume_ringtone" msgid="6885421406845734650">"Helina helitugevus"</string> <string name="volume_music" msgid="5421651157138628171">"Meediumi helitugevus"</string> @@ -1776,7 +1786,9 @@ <item quantity="one">Proovige uuesti 1 sekundi pärast</item> </plurals> <string name="restr_pin_try_later" msgid="973144472490532377">"Proovige hiljem uuesti"</string> - <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Täisekraanilt väljumiseks pühkige ülevalt alla."</string> + <string name="immersive_cling_title" msgid="8394201622932303336">"Kuvamine täisekraanil"</string> + <string name="immersive_cling_description" msgid="3482371193207536040">"Väljumiseks pühkige ülevalt alla."</string> + <string name="immersive_cling_positive" msgid="5016839404568297683">"Selge"</string> <string name="done_label" msgid="2093726099505892398">"Valmis"</string> <string name="hour_picker_description" msgid="6698199186859736512">"Ringikujuline tunniliugur"</string> <string name="minute_picker_description" msgid="8606010966873791190">"Ringikujuline minutiliugur"</string> @@ -1791,7 +1803,8 @@ <string name="managed_profile_label_badge" msgid="2355652472854327647">"Töö <xliff:g id="LABEL">%1$s</xliff:g>"</string> <string name="lock_to_app_toast" msgid="7570091317001980053">"Ekraanikuva vabastamiseks puudutage pikalt samal ajal nuppe Tagasi ja Ülevaade."</string> <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Ekraanikuva vabastamiseks puudutage pikalt nuppu Ülevaade."</string> - <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Ekraan on kinnitatud. Teie organisatsioon ei luba vabastamist."</string> + <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) --> + <skip /> <string name="lock_to_app_start" msgid="6643342070839862795">"Ekraan on kinnitatud"</string> <string name="lock_to_app_exit" msgid="8598219838213787430">"Ekraan on vabastatud"</string> <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Enne vabastamist küsi PIN-koodi"</string> diff --git a/core/res/res/values-eu-rES/strings.xml b/core/res/res/values-eu-rES/strings.xml index 90b9a62d127f..953a5fad36a7 100644 --- a/core/res/res/values-eu-rES/strings.xml +++ b/core/res/res/values-eu-rES/strings.xml @@ -796,6 +796,8 @@ <string name="permdesc_accessNotifications" msgid="458457742683431387">"Jakinarazpenak berreskuratu, aztertu eta garbitzeko aukera ematen die aplikazioei, beste aplikazioek argitaratutako jakinarazpenak barne."</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"Lotu jakinarazpenak hautemateko zerbitzu batera"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Jakinarazpenak hautemateko zerbitzu baten goi-mailako interfazera lotzeko aukera ematen dio titularrari. Aplikazio normalek ez dute baimen hau behar."</string> + <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"Lotu hautatzailearen zerbitzu jakin batera"</string> + <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Zerbitzu jakin baten goi-mailako interfazera lotzea baimentzen die titularrei. Aplikazio normalek ez dute baimen hau behar."</string> <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"Lotu baldintza-hornitzaileen zerbitzuei"</string> <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Baldintza-hornitzaileen zerbitzuen goi-mailako interfazeari lotzea baimentzen die titularrei. Aplikazio normalek ez lukete beharko."</string> <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"lotetsi multimedia-irteerako zerbitzu bati"</string> @@ -1263,6 +1265,14 @@ <string name="old_app_description" msgid="2082094275580358049">"Ez abiarazi aplikazio berria."</string> <string name="new_app_action" msgid="5472756926945440706">"Hasi <xliff:g id="OLD_APP">%1$s</xliff:g>"</string> <string name="new_app_description" msgid="1932143598371537340">"Gelditu aplikazio zaharra ezer gorde gabe."</string> + <!-- no translation found for dump_heap_notification (2618183274836056542) --> + <skip /> + <!-- no translation found for dump_heap_notification_detail (2075673362317481664) --> + <skip /> + <!-- no translation found for dump_heap_title (5864292264307651673) --> + <skip /> + <!-- no translation found for dump_heap_text (4809417337240334941) --> + <skip /> <string name="sendText" msgid="5209874571959469142">"Aukeratu testurako ekintza"</string> <string name="volume_ringtone" msgid="6885421406845734650">"Tonu-jotzailearen bolumena"</string> <string name="volume_music" msgid="5421651157138628171">"Multimedia-edukiaren bolumena"</string> @@ -1776,7 +1786,9 @@ <item quantity="one">Saiatu berriro segundo bat igarotakoan</item> </plurals> <string name="restr_pin_try_later" msgid="973144472490532377">"Saiatu berriro geroago"</string> - <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Pantaila osotik irteteko, pasatu hatza goitik behera."</string> + <string name="immersive_cling_title" msgid="8394201622932303336">"Pantaila osoan ikusten"</string> + <string name="immersive_cling_description" msgid="3482371193207536040">"Irteteko, pasatu hatza goitik behera."</string> + <string name="immersive_cling_positive" msgid="5016839404568297683">"Ados"</string> <string name="done_label" msgid="2093726099505892398">"Eginda"</string> <string name="hour_picker_description" msgid="6698199186859736512">"Ordua aukeratzeko ikuspegi zirkularra"</string> <string name="minute_picker_description" msgid="8606010966873791190">"Minutuak aukeratzeko ikuspegi zirkularra"</string> @@ -1791,7 +1803,8 @@ <string name="managed_profile_label_badge" msgid="2355652472854327647">"Laneko <xliff:g id="LABEL">%1$s</xliff:g>"</string> <string name="lock_to_app_toast" msgid="7570091317001980053">"Aingura kentzeko, eduki ukituta Atzera eta Ikuspegi orokorra botoiak aldi berean."</string> <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Aingura kentzeko, eduki ukituta Ikuspegi orokorra botoia."</string> - <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Pantaila ainguratu da. Erakundeak ez du aingura kentzea onartzen."</string> + <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) --> + <skip /> <string name="lock_to_app_start" msgid="6643342070839862795">"Pantaila ainguratu da"</string> <string name="lock_to_app_exit" msgid="8598219838213787430">"Aingura kendu zaio pantailari"</string> <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Eskatu PIN kodea aingura kendu aurretik"</string> diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml index 91cbfcd9ca1a..7419f5b5645c 100644 --- a/core/res/res/values-fa/strings.xml +++ b/core/res/res/values-fa/strings.xml @@ -796,6 +796,8 @@ <string name="permdesc_accessNotifications" msgid="458457742683431387">"به برنامه اجازه میدهد به بازیابی، بررسی و پاک کردن اعلانها از جمله موارد پست شده توسط سایر برنامهها بپردازد."</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"اتصال به یک سرویس شنونده اعلان"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"به دارنده اجازه میدهد به یک رابط سطح بالای سرویس شنونده اعلان متصل شود. هرگز نباید برای برنامههای عادی لازم شود."</string> + <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"اتصال به یک سرویس هدفیابی انتخابگر"</string> + <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"به دارنده اجازه میدهد به رابط سطح بالای یک سرویس هدفیابی انتخابگر متصل شود. هرگز برای برنامههای معمولی مورد نیاز نیست."</string> <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"مقید بودن به سرویس ارائهدهنده وضعیت"</string> <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"به دارنده امکان میدهد تا به واسط سطح بالای سرویس ارائهدهنده وضعیت مقید باشد. برای برنامههای عادی هرگز نباید لازم باشد."</string> <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"اتصال به یک سرویس مسیر رسانهای"</string> @@ -1263,6 +1265,14 @@ <string name="old_app_description" msgid="2082094275580358049">"برنامه جدید شروع نشود."</string> <string name="new_app_action" msgid="5472756926945440706">"شروع <xliff:g id="OLD_APP">%1$s</xliff:g>"</string> <string name="new_app_description" msgid="1932143598371537340">"برنامه قدیمی را بدون ذخیره متوقف کنید."</string> + <!-- no translation found for dump_heap_notification (2618183274836056542) --> + <skip /> + <!-- no translation found for dump_heap_notification_detail (2075673362317481664) --> + <skip /> + <!-- no translation found for dump_heap_title (5864292264307651673) --> + <skip /> + <!-- no translation found for dump_heap_text (4809417337240334941) --> + <skip /> <string name="sendText" msgid="5209874571959469142">"انتخاب یک عملکرد برای نوشتار"</string> <string name="volume_ringtone" msgid="6885421406845734650">"میزان صدای زنگ"</string> <string name="volume_music" msgid="5421651157138628171">"میزان صدای رسانه"</string> @@ -1776,7 +1786,9 @@ <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> ثانیه دیگر دوباره امتحان کنید</item> </plurals> <string name="restr_pin_try_later" msgid="973144472490532377">"بعداً دوباره امتحان کنید"</string> - <string name="immersive_mode_confirmation" msgid="7227416894979047467">"برای خروج از حالت تمام صفحه، انگشت خود را به تندی از بالای صفحه به پایین بکشید."</string> + <string name="immersive_cling_title" msgid="8394201622932303336">"مشاهده در حالت تمام صفحه"</string> + <string name="immersive_cling_description" msgid="3482371193207536040">"برای خروج، انگشتتان را از بالای صفحه به پایین بکشید."</string> + <string name="immersive_cling_positive" msgid="5016839404568297683">"متوجه شدم"</string> <string name="done_label" msgid="2093726099505892398">"انجام شد"</string> <string name="hour_picker_description" msgid="6698199186859736512">"لغزنده دایرهای ساعت"</string> <string name="minute_picker_description" msgid="8606010966873791190">"لغزنده دایرهای دقیقه"</string> @@ -1791,7 +1803,8 @@ <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> محل کار"</string> <string name="lock_to_app_toast" msgid="7570091317001980053">"برای برداشتن پین این صفحه، همزمان «بازگشت» و «نمای کلی» را لمس کنید و نگه دارید."</string> <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"برای برداشتن پین این صفحه، «نمای کلی» را لمس کنید و نگه دارید."</string> - <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"صفحه پین شده است. سازمان شما برداشتن پین را غیرمجاز کرده است."</string> + <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) --> + <skip /> <string name="lock_to_app_start" msgid="6643342070839862795">"صفحه پین شد"</string> <string name="lock_to_app_exit" msgid="8598219838213787430">"پین صفحه برداشته شد"</string> <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"درخواست کد پین قبل از برداشتن پین"</string> diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml index 36246cca18a7..9eed4a1cc338 100644 --- a/core/res/res/values-fi/strings.xml +++ b/core/res/res/values-fi/strings.xml @@ -796,6 +796,8 @@ <string name="permdesc_accessNotifications" msgid="458457742683431387">"Antaa sovelluksen noutaa, tutkia ja tyhjentää ilmoituksia (myös muiden sovelluksien lähettämiä)."</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"sido ilmoituskuuntelijapalveluun"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Antaa sovelluksen sitoutua ilmoituskuuntelijan ylimmän tason käyttöliittymään. Ei tavallisten sovelluksien käyttöön."</string> + <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"luo sidos valitsimen kohdepalveluun"</string> + <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Antaa sovelluksen luoda sidoksen valitsimen kohdepalvelun ylemmän tason rajapintaan. Ei tavallisten sovelluksien käyttöön."</string> <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"ehtojen toimituspalveluun sitominen"</string> <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Antaa sovelluksen luoda sidoksen ehtojen toimituspalvelun ylätason rajapintaan. Ei tavallisten sovelluksien käyttöön."</string> <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"median reitityspalveluun sitoutuminen"</string> @@ -1263,6 +1265,14 @@ <string name="old_app_description" msgid="2082094275580358049">"Älä käynnistä uutta sovellusta."</string> <string name="new_app_action" msgid="5472756926945440706">"Käynnistä <xliff:g id="OLD_APP">%1$s</xliff:g>"</string> <string name="new_app_description" msgid="1932143598371537340">"Pysäytä vanha sovellus tallentamatta."</string> + <!-- no translation found for dump_heap_notification (2618183274836056542) --> + <skip /> + <!-- no translation found for dump_heap_notification_detail (2075673362317481664) --> + <skip /> + <!-- no translation found for dump_heap_title (5864292264307651673) --> + <skip /> + <!-- no translation found for dump_heap_text (4809417337240334941) --> + <skip /> <string name="sendText" msgid="5209874571959469142">"Valitse tekstille toiminto"</string> <string name="volume_ringtone" msgid="6885421406845734650">"Soittoäänen voimakkuus"</string> <string name="volume_music" msgid="5421651157138628171">"Median äänenvoimakkuus"</string> @@ -1776,7 +1786,9 @@ <item quantity="one">Yritä uudelleen 1 sekunnin kuluttua</item> </plurals> <string name="restr_pin_try_later" msgid="973144472490532377">"Yritä myöhemmin uudelleen"</string> - <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Poistu koko näytön tilasta pyyhkäisemällä alas."</string> + <string name="immersive_cling_title" msgid="8394201622932303336">"Koko ruudun tilassa"</string> + <string name="immersive_cling_description" msgid="3482371193207536040">"Sulje palkki pyyhkäisemällä alas ruudun ylälaidasta."</string> + <string name="immersive_cling_positive" msgid="5016839404568297683">"Selvä"</string> <string name="done_label" msgid="2093726099505892398">"Valmis"</string> <string name="hour_picker_description" msgid="6698199186859736512">"Tuntien ympyränmuotoinen liukusäädin"</string> <string name="minute_picker_description" msgid="8606010966873791190">"Minuuttien ympyränmuotoinen liukusäädin"</string> @@ -1791,7 +1803,8 @@ <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> (työ)"</string> <string name="lock_to_app_toast" msgid="7570091317001980053">"Poista näytön kiinnitys painamalla Edellinen- ja Viimeisimmät-kohtaa samanaikaisesti pitkään."</string> <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Poista näytön kiinnitys painamalla Viimeisimmät-kohtaa pitkään."</string> - <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Näyttö on kiinnitetty. Irrottaminen ei ole sallittu organisaatiossasi."</string> + <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) --> + <skip /> <string name="lock_to_app_start" msgid="6643342070839862795">"Näyttö kiinnitetty"</string> <string name="lock_to_app_exit" msgid="8598219838213787430">"Näyttö irrotettu"</string> <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Pyydä PIN-koodi ennen irrotusta"</string> diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml index 39a19b633938..80027448610a 100644 --- a/core/res/res/values-fr-rCA/strings.xml +++ b/core/res/res/values-fr-rCA/strings.xml @@ -572,7 +572,7 @@ <string name="permdesc_mediaContentControl" msgid="1637478200272062">"Permet à l\'application de contrôler la lecture des contenus multimédias et d\'accéder aux données associées (titre, auteur...)."</string> <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"modifier vos paramètres audio"</string> <string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"Permet à l\'application de modifier les paramètres audio généraux, tels que le volume et la sortie audio utilisée."</string> - <string name="permlab_recordAudio" msgid="3876049771427466323">"enregistrer fichier audio"</string> + <string name="permlab_recordAudio" msgid="3876049771427466323">"enregistrer des fichiers audio"</string> <string name="permdesc_recordAudio" msgid="4906839301087980680">"Permet à l\'application d\'enregistrer des contenus audio à l\'aide du microphone. Cette autorisation lui donne la possibilité d\'enregistrer du contenu audio à tout moment sans votre consentement."</string> <string name="permlab_sim_communication" msgid="1180265879464893029">"Communication avec la carte SIM"</string> <string name="permdesc_sim_communication" msgid="5725159654279639498">"Permet à l\'application d\'envoyer des commandes à la carte SIM. Cette fonctionnalité est très dangereuse."</string> @@ -738,14 +738,10 @@ <string name="permdesc_nfc" msgid="7120611819401789907">"Permet à l\'application de communiquer avec des bornes, des cartes et des lecteurs compatibles avec la technologie NFC (communication en champ proche)."</string> <string name="permlab_disableKeyguard" msgid="3598496301486439258">"désactiver le verrouillage de l\'écran"</string> <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"Permet à l\'application de désactiver le verrouillage des touches et toute mesure de sécurité par mot de passe associée. Par exemple, votre téléphone désactive le verrouillage des touches lorsque vous recevez un appel, puis le réactive lorsque vous raccrochez."</string> - <!-- no translation found for permlab_manageFingerprint (5640858826254575638) --> - <skip /> - <!-- no translation found for permdesc_manageFingerprint (178208705828055464) --> - <skip /> - <!-- no translation found for permlab_useFingerprint (3150478619915124905) --> - <skip /> - <!-- no translation found for permdesc_useFingerprint (9165097460730684114) --> - <skip /> + <string name="permlab_manageFingerprint" msgid="5640858826254575638">"gérer le matériel d\'empreinte digitale"</string> + <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Permet à l\'application de faire appel à des méthodes d\'ajout et de suppression de modèles d\'empreinte digitale que vous pouvez utiliser."</string> + <string name="permlab_useFingerprint" msgid="3150478619915124905">"utiliser le matériel d\'empreinte digitale"</string> + <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Permet à l\'application d\'utiliser du matériel d\'empreinte digitale pour l\'authentification"</string> <string name="permlab_readSyncSettings" msgid="6201810008230503052">"lire les paramètres de synchronisation"</string> <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Permet à l\'application d\'accéder aux paramètres de synchronisation d\'un compte. Par exemple, cette autorisation peut permettre de déterminer si l\'application Contacts est synchronisée avec un compte ou non."</string> <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"activer ou désactiver la synchronisation"</string> @@ -800,6 +796,8 @@ <string name="permdesc_accessNotifications" msgid="458457742683431387">"Permet aux applications de récupérer, d\'examiner et d\'autoriser les notifications, y compris celles envoyées par d\'autres applications."</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"s\'associer à l\'interface de niveau supérieur d\'un service d\'écoute des notifications"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Permet à l\'application de s\'associer à l\'interface de niveau supérieur d\'un service d\'écoute des notifications. Ne devrait jamais être nécessaire pour les applications normales."</string> + <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"se lier à un service cible de sélecteur"</string> + <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Permet au propriétaire de se lier à l\'interface de haut niveau d\'un service cible de sélecteur. Ne devrait jamais être nécessaire pour les applications normales."</string> <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"s\'associer à un service de fournisseur de conditions"</string> <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Permet à l\'application de s\'associer à l\'interface de niveau supérieur d\'un service de fournisseur de conditions. Ne devrait pas être nécessaire pour les applications standards."</string> <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"s\'associer à un service d\'itinéraires multimédias"</string> @@ -1267,6 +1265,14 @@ <string name="old_app_description" msgid="2082094275580358049">"Ne pas lancer la nouvelle application"</string> <string name="new_app_action" msgid="5472756926945440706">"Démarrer <xliff:g id="OLD_APP">%1$s</xliff:g>"</string> <string name="new_app_description" msgid="1932143598371537340">"Arrêtez l\'ancienne application sans enregistrer."</string> + <!-- no translation found for dump_heap_notification (2618183274836056542) --> + <skip /> + <!-- no translation found for dump_heap_notification_detail (2075673362317481664) --> + <skip /> + <!-- no translation found for dump_heap_title (5864292264307651673) --> + <skip /> + <!-- no translation found for dump_heap_text (4809417337240334941) --> + <skip /> <string name="sendText" msgid="5209874571959469142">"Sélectionner une action pour le texte"</string> <string name="volume_ringtone" msgid="6885421406845734650">"Volume de la sonnerie"</string> <string name="volume_music" msgid="5421651157138628171">"Volume"</string> @@ -1780,7 +1786,9 @@ <item quantity="other">Réessayer dans <xliff:g id="COUNT">%d</xliff:g> secondes</item> </plurals> <string name="restr_pin_try_later" msgid="973144472490532377">"Réessayez plus tard"</string> - <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Balayez vers le bas pour quitter le mode plein écran"</string> + <string name="immersive_cling_title" msgid="8394201622932303336">"Affichage plein écran"</string> + <string name="immersive_cling_description" msgid="3482371193207536040">"Pour quitter, balayez vers le bas à partir du haut."</string> + <string name="immersive_cling_positive" msgid="5016839404568297683">"OK"</string> <string name="done_label" msgid="2093726099505892398">"Terminé"</string> <string name="hour_picker_description" msgid="6698199186859736512">"Curseur circulaire des heures"</string> <string name="minute_picker_description" msgid="8606010966873791190">"Curseur circulaire des minutes"</string> @@ -1795,7 +1803,8 @@ <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> (travail)"</string> <string name="lock_to_app_toast" msgid="7570091317001980053">"Pour annuler l\'épinglage de cet écran, appuyez de manière prolongée sur Retour et Aperçu simultanément."</string> <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Pour annuler l\'épinglage, appuyez de manière prolongée sur Aperçu."</string> - <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"L\'écran est épinglé. Votre organisation n\'autorise pas l\'annulation d\'épinglage."</string> + <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) --> + <skip /> <string name="lock_to_app_start" msgid="6643342070839862795">"Écran épinglé"</string> <string name="lock_to_app_exit" msgid="8598219838213787430">"Épinglage d\'écran annulé"</string> <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Demander le NIP avant d\'annuler l\'épinglage"</string> diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml index 6e57d5827186..c1fe962ea15f 100644 --- a/core/res/res/values-fr/strings.xml +++ b/core/res/res/values-fr/strings.xml @@ -620,7 +620,7 @@ <string name="permdesc_hardware_test" msgid="6597964191208016605">"Permet à l\'application de contrôler différents périphériques à des fins de test matériel."</string> <string name="permlab_fm" msgid="8749504526866832">"accéder aux radios FM"</string> <string name="permdesc_fm" msgid="4145699441237962818">"Permet à l\'application d\'accéder aux radios FM afin d\'écouter des programmes."</string> - <string name="permlab_callPhone" msgid="3925836347681847954">"Appeler directement les numéros de téléphone"</string> + <string name="permlab_callPhone" msgid="3925836347681847954">"appeler directement les numéros de téléphone"</string> <string name="permdesc_callPhone" msgid="3740797576113760827">"Permet à l\'application d\'appeler des numéros de téléphone sans votre intervention. Cette autorisation peut entraîner des frais ou des appels imprévus et ne permet pas à l\'application d\'appeler des numéros d\'urgence. Les applications malveillantes peuvent générer des frais en passant des appels sans votre consentement."</string> <string name="permlab_callPrivileged" msgid="4198349211108497879">"Appel direct de tout numéro de téléphone"</string> <string name="permdesc_callPrivileged" msgid="1689024901509996810">"Permet à l\'application d\'appeler n\'importe quel numéro de téléphone, y compris les numéros d\'urgence, sans votre intervention. Des applications malveillantes peuvent passer des appels inutiles et interdits aux services d\'urgence."</string> @@ -694,7 +694,7 @@ <string name="permdesc_createNetworkSockets" msgid="3403062187779724185">"Permet à l\'application de créer des sockets réseau et d\'utiliser des protocoles réseau personnalisés. Le navigateur et d\'autres applications permettent d\'envoyer des données sur Internet. Cette autorisation n\'est donc pas nécessaire pour envoyer des données sur Internet."</string> <string name="permlab_writeApnSettings" msgid="505660159675751896">"changer/intercepter les paramètres et le trafic du réseau"</string> <string name="permdesc_writeApnSettings" msgid="5333798886412714193">"Permet à l\'application de modifier les paramètres réseau, ainsi que d\'intercepter et de surveiller tout le trafic réseau ayant pour but de modifier le proxy et le port d\'un APN, par exemple. Des applications malveillantes peuvent exploiter cette fonctionnalité pour surveiller, rediriger ou modifier les paquets réseau à votre insu."</string> - <string name="permlab_changeNetworkState" msgid="958884291454327309">"Modification de la connectivité du réseau"</string> + <string name="permlab_changeNetworkState" msgid="958884291454327309">"modifier la connectivité réseau"</string> <string name="permdesc_changeNetworkState" msgid="6789123912476416214">"Permet à l\'application de modifier l\'état de la connectivité du réseau."</string> <string name="permlab_changeTetherState" msgid="5952584964373017960">"changer la connectivité du partage de connexion"</string> <string name="permdesc_changeTetherState" msgid="1524441344412319780">"Permet à l\'application de modifier l\'état de la connectivité du partage de connexion."</string> @@ -738,14 +738,10 @@ <string name="permdesc_nfc" msgid="7120611819401789907">"Permet à l\'application de communiquer avec des tags, des cartes et des lecteurs compatibles avec la technologie NFC (communication en champ proche)."</string> <string name="permlab_disableKeyguard" msgid="3598496301486439258">"désactiver le verrouillage de l\'écran"</string> <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"Permet à l\'application de désactiver le verrouillage des touches et toute mesure de sécurité via mot de passe associée. Par exemple, votre téléphone désactive le verrouillage des touches lorsque vous recevez un appel, puis le réactive lorsque vous raccrochez."</string> - <!-- no translation found for permlab_manageFingerprint (5640858826254575638) --> - <skip /> - <!-- no translation found for permdesc_manageFingerprint (178208705828055464) --> - <skip /> - <!-- no translation found for permlab_useFingerprint (3150478619915124905) --> - <skip /> - <!-- no translation found for permdesc_useFingerprint (9165097460730684114) --> - <skip /> + <string name="permlab_manageFingerprint" msgid="5640858826254575638">"Gérer le matériel d\'empreintes digitales"</string> + <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Autoriser l\'application à invoquer des méthodes pour ajouter et supprimer des modèles d\'empreintes digitales"</string> + <string name="permlab_useFingerprint" msgid="3150478619915124905">"Utiliser le matériel d\'empreintes digitales"</string> + <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Autoriser l\'application à utiliser le matériel d\'empreintes digitales pour l\'authentification"</string> <string name="permlab_readSyncSettings" msgid="6201810008230503052">"lire les paramètres de synchronisation"</string> <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Permet à l\'application d\'accéder aux paramètres de synchronisation d\'un compte. Par exemple, cette autorisation peut permettre de déterminer si l\'application Contacts est synchronisée avec un compte ou non."</string> <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"activer/désactiver la synchronisation"</string> @@ -800,6 +796,8 @@ <string name="permdesc_accessNotifications" msgid="458457742683431387">"Permet aux applications de récupérer, d\'examiner et d\'autoriser les notifications, y compris celles envoyées par d\'autres applications."</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"s\'associer à l\'interface de niveau supérieur d\'un service d\'écoute des notifications"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Permet à l\'application de s\'associer à l\'interface de niveau supérieur d\'un service d\'écoute des notifications. Ne devrait jamais être nécessaire pour les applications normales."</string> + <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"S\'associer à un service de cible d\'un sélecteur"</string> + <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Permet à l\'application autorisée de s\'associer à l\'interface de niveau supérieur du service de cible d\'un sélecteur. Cette fonctionnalité ne devrait pas être nécessaire pour les applications standards."</string> <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"s\'associer à un service de fournisseur de conditions"</string> <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Permet à l\'application de s\'associer à l\'interface de niveau supérieur d\'un service de fournisseur de conditions. Ne devrait pas être nécessaire pour les applications standards."</string> <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"s\'associer à un service d\'itinéraires médias"</string> @@ -1267,6 +1265,14 @@ <string name="old_app_description" msgid="2082094275580358049">"Ne pas lancer la nouvelle application"</string> <string name="new_app_action" msgid="5472756926945440706">"Démarrer <xliff:g id="OLD_APP">%1$s</xliff:g>"</string> <string name="new_app_description" msgid="1932143598371537340">"Arrêtez l\'ancienne application sans enregistrer."</string> + <!-- no translation found for dump_heap_notification (2618183274836056542) --> + <skip /> + <!-- no translation found for dump_heap_notification_detail (2075673362317481664) --> + <skip /> + <!-- no translation found for dump_heap_title (5864292264307651673) --> + <skip /> + <!-- no translation found for dump_heap_text (4809417337240334941) --> + <skip /> <string name="sendText" msgid="5209874571959469142">"Sélectionner une action pour le texte"</string> <string name="volume_ringtone" msgid="6885421406845734650">"Volume de la sonnerie"</string> <string name="volume_music" msgid="5421651157138628171">"Volume"</string> @@ -1780,7 +1786,9 @@ <item quantity="other">Réessayer dans <xliff:g id="COUNT">%d</xliff:g> secondes</item> </plurals> <string name="restr_pin_try_later" msgid="973144472490532377">"Veuillez réessayer ultérieurement."</string> - <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Faites glisser le doigt vers le bas pour quitter le mode plein écran."</string> + <string name="immersive_cling_title" msgid="8394201622932303336">"Affichage en plein écran"</string> + <string name="immersive_cling_description" msgid="3482371193207536040">"Pour quitter, balayez l\'écran du haut vers le bas."</string> + <string name="immersive_cling_positive" msgid="5016839404568297683">"OK"</string> <string name="done_label" msgid="2093726099505892398">"OK"</string> <string name="hour_picker_description" msgid="6698199186859736512">"Curseur circulaire des heures"</string> <string name="minute_picker_description" msgid="8606010966873791190">"Curseur circulaire des minutes"</string> @@ -1795,7 +1803,8 @@ <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> (travail)"</string> <string name="lock_to_app_toast" msgid="7570091317001980053">"Pour annuler l\'épinglage, appuyez de manière prolongée et simultanée sur \"Retour\" et \"Aperçu\"."</string> <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Pour annuler l\'épinglage, appuyez de manière prolongée sur \"Aperçu\"."</string> - <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"L\'écran est épinglé. L\'annulation de l\'épinglage n\'est pas autorisée par votre organisation."</string> + <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) --> + <skip /> <string name="lock_to_app_start" msgid="6643342070839862795">"Écran épinglé."</string> <string name="lock_to_app_exit" msgid="8598219838213787430">"Épinglage d\'écran annulé."</string> <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Demander le code PIN avant d\'annuler l\'épinglage"</string> diff --git a/core/res/res/values-gl-rES/strings.xml b/core/res/res/values-gl-rES/strings.xml index 03f1d87e7c89..e593f88f4f91 100644 --- a/core/res/res/values-gl-rES/strings.xml +++ b/core/res/res/values-gl-rES/strings.xml @@ -796,6 +796,8 @@ <string name="permdesc_accessNotifications" msgid="458457742683431387">"Permite á aplicación recuperar, examinar e borrar notificacións, incluídas as publicadas por outras aplicacións."</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"vincular a un servizo de axente de escoita de notificacións"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Permite ao propietario vincularse á interface de nivel superior dun servizo axente de escoita de notificacións. Non debería ser nunca necesario para as aplicacións normais."</string> + <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"vincular a un servizo de segmento de seleccionador"</string> + <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Permite ao propietario vincularse á interface de nivel superior dun servizo de segmento de seleccionador. Non debería ser nunca necesario para as aplicacións normais."</string> <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"vincular a un servizo de provedor de condicións"</string> <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Permite ao propietario vincularse á interface de nivel superior dun servizo provedor de condicións. As aplicacións normais non deberían necesitar este permiso."</string> <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"vincular a un servizo de ruta de medios"</string> @@ -1263,6 +1265,14 @@ <string name="old_app_description" msgid="2082094275580358049">"Non inicies a aplicación nova."</string> <string name="new_app_action" msgid="5472756926945440706">"Iniciar <xliff:g id="OLD_APP">%1$s</xliff:g>"</string> <string name="new_app_description" msgid="1932143598371537340">"Deter a aplicación antiga sen gardar."</string> + <!-- no translation found for dump_heap_notification (2618183274836056542) --> + <skip /> + <!-- no translation found for dump_heap_notification_detail (2075673362317481664) --> + <skip /> + <!-- no translation found for dump_heap_title (5864292264307651673) --> + <skip /> + <!-- no translation found for dump_heap_text (4809417337240334941) --> + <skip /> <string name="sendText" msgid="5209874571959469142">"Seleccionar unha acción para o texto"</string> <string name="volume_ringtone" msgid="6885421406845734650">"Volume do timbre"</string> <string name="volume_music" msgid="5421651157138628171">"Volume dos elementos multimedia"</string> @@ -1776,7 +1786,9 @@ <item quantity="one">Téntao de novo dentro nun segundo</item> </plurals> <string name="restr_pin_try_later" msgid="973144472490532377">"Téntao de novo máis tarde"</string> - <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Pasa o dedo cara abaixo desde a parte superior para saír da pantalla completa."</string> + <string name="immersive_cling_title" msgid="8394201622932303336">"Vendo pantalla completa"</string> + <string name="immersive_cling_description" msgid="3482371193207536040">"Para saír, pasa o dedo cara abaixo desde arriba."</string> + <string name="immersive_cling_positive" msgid="5016839404568297683">"De acordo"</string> <string name="done_label" msgid="2093726099505892398">"Feito"</string> <string name="hour_picker_description" msgid="6698199186859736512">"Control de desprazamento circular das horas"</string> <string name="minute_picker_description" msgid="8606010966873791190">"Control de desprazamento circular dos minutos"</string> @@ -1791,7 +1803,8 @@ <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> do traballo"</string> <string name="lock_to_app_toast" msgid="7570091317001980053">"Para soltar a pantalla, mantén premido Atrás e Visión xeral ao mesmo tempo."</string> <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Para soltar a pantalla, mantén premido Visión xeral."</string> - <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"A pantalla está fixada. A túa organización non permite desactivar a pantalla."</string> + <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) --> + <skip /> <string name="lock_to_app_start" msgid="6643342070839862795">"Pantalla fixada"</string> <string name="lock_to_app_exit" msgid="8598219838213787430">"Pantalla desactivada"</string> <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Solicitar un PIN antes de soltar a pantalla"</string> diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml index 1505fa9cff7a..f0635609e12b 100644 --- a/core/res/res/values-hi/strings.xml +++ b/core/res/res/values-hi/strings.xml @@ -738,10 +738,10 @@ <string name="permdesc_nfc" msgid="7120611819401789907">"ऐप्स को नियर फ़ील्ड कम्यूनिकेशन (NFC) टैग, कार्ड, और रीडर के साथ संचार करने देता है."</string> <string name="permlab_disableKeyguard" msgid="3598496301486439258">"अपना स्क्रीन लॉक अक्षम करें"</string> <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"ऐप्स को कीलॉक और कोई भी संबद्ध पासवर्ड सुरक्षा अक्षम करने देता है. उदाहरण के लिए, इनकमिंग फ़ोन कॉल प्राप्त करते समय फ़ोन, कीलॉक को अक्षम कर देता है, फिर कॉल समाप्त होने पर कीलॉक को पुन: सक्षम कर देता है."</string> - <string name="permlab_manageFingerprint" msgid="5640858826254575638">"फ़िंगरप्रिंट हार्डवेयर को प्रबंधित करें"</string> - <string name="permdesc_manageFingerprint" msgid="178208705828055464">"फ़िंगरप्रिंट टेम्पलेट का उपयोग करने के लिए जोड़ने और हटाने हेतु ऐप को विधियां प्रारंभ करने देती है."</string> - <string name="permlab_useFingerprint" msgid="3150478619915124905">"फ़िंगरप्रिंट हार्डवेयर का उपयोग करें"</string> - <string name="permdesc_useFingerprint" msgid="9165097460730684114">"ऐप के प्रमाणीकरण के लिए फ़िंगरप्रिंट हार्डवेयर का उपयोग करने देती है"</string> + <string name="permlab_manageFingerprint" msgid="5640858826254575638">"अंगुली की छाप के लिए हार्डवेयर को प्रबंधित करें"</string> + <string name="permdesc_manageFingerprint" msgid="178208705828055464">"अंगुली की छाप वाले टेम्पलेट का उपयोग करने के लिए जोड़ने और हटाने हेतु ऐप को विधियां प्रारंभ करने देती है."</string> + <string name="permlab_useFingerprint" msgid="3150478619915124905">"अंगुली की छाप के लिए हार्डवेयर का उपयोग करें"</string> + <string name="permdesc_useFingerprint" msgid="9165097460730684114">"ऐप के प्रमाणीकरण के लिए अंगुली की छाप हार्डवेयर का उपयोग करने देती है"</string> <string name="permlab_readSyncSettings" msgid="6201810008230503052">"समन्वयन सेटिंग पढ़ें"</string> <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"ऐप्स को किसी खाते की समन्वयन सेटिंग पढ़ने देता है. उदाहरण के लिए, इससे यह निर्धारित किया जा सकता है कि लोग ऐप्स किसी खाते के साथ समन्वयित है या नहीं."</string> <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"समन्वयन बंद या चालू टॉगल करें"</string> @@ -796,6 +796,8 @@ <string name="permdesc_accessNotifications" msgid="458457742683431387">"ऐप्स को नोटिफिकेशन को प्राप्त करने, जांच करने, और साफ़ करने देता है, जिनमें अन्य ऐप्स के द्वारा पोस्ट की गई सूचनाएं भी शामिल हैं."</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"नोटिफिकेशन श्रवणकर्ता सेवा से जुड़ें"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"धारक को नोटिफिकेशन श्रवणकर्ता सेवा के शीर्ष स्तरीय इंटरफ़ेस से जुड़ने देती है. सामान्य ऐप्स के लिए कभी भी आवश्यक नहीं होनी चाहिए."</string> + <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"किसी चयनकर्ता लक्ष्य सेवा से आबद्ध हों"</string> + <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"धारक को किसी चयनकर्ता लक्ष्य सेवा के शीर्ष-स्तरीय इंटरफ़ेस से आबद्ध होने देती है. सामान्य ऐप्स के लिए कभी भी आवश्यक नहीं होना चाहिए."</string> <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"किसी स्थिति प्रदाता सेवा से आबद्ध हों"</string> <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"धारक को किसी स्थिति प्रदाता सेवा के शीर्ष-स्तर के इंटरफ़ेस से आबद्ध होने देती है. सामान्य ऐप्स के लिए कभी भी आवश्यक नहीं होना चाहिए."</string> <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"मीडिया रूट सेवा से आबद्ध हों"</string> @@ -1263,6 +1265,14 @@ <string name="old_app_description" msgid="2082094275580358049">"नया ऐप्स प्रारंभ न करें."</string> <string name="new_app_action" msgid="5472756926945440706">"<xliff:g id="OLD_APP">%1$s</xliff:g> प्रारंभ करें"</string> <string name="new_app_description" msgid="1932143598371537340">"पुराने ऐप्स को बिना सहेजे बंद करें."</string> + <!-- no translation found for dump_heap_notification (2618183274836056542) --> + <skip /> + <!-- no translation found for dump_heap_notification_detail (2075673362317481664) --> + <skip /> + <!-- no translation found for dump_heap_title (5864292264307651673) --> + <skip /> + <!-- no translation found for dump_heap_text (4809417337240334941) --> + <skip /> <string name="sendText" msgid="5209874571959469142">"लेख के लिए किसी क्रिया को चुनें"</string> <string name="volume_ringtone" msgid="6885421406845734650">"रिंगर वॉल्यूम"</string> <string name="volume_music" msgid="5421651157138628171">"मीडिया वॉल्यूम"</string> @@ -1776,7 +1786,9 @@ <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> सेकंड में पुन: प्रयास करें</item> </plurals> <string name="restr_pin_try_later" msgid="973144472490532377">"बाद में फिर से प्रयास करें"</string> - <string name="immersive_mode_confirmation" msgid="7227416894979047467">"पूर्ण स्क्रीन से बाहर आने के लिए ऊपर से नीचे स्वाइप करें."</string> + <string name="immersive_cling_title" msgid="8394201622932303336">"पूर्ण स्क्रीन में देखें"</string> + <string name="immersive_cling_description" msgid="3482371193207536040">"बाहर निकलने के लिए, ऊपर से नीचे स्वाइप करें."</string> + <string name="immersive_cling_positive" msgid="5016839404568297683">"समझ लिया"</string> <string name="done_label" msgid="2093726099505892398">"पूर्ण"</string> <string name="hour_picker_description" msgid="6698199186859736512">"घंटो का चक्राकार स्लाइडर"</string> <string name="minute_picker_description" msgid="8606010966873791190">"मिनटों का चक्राकार स्लाइडर"</string> @@ -1791,7 +1803,8 @@ <string name="managed_profile_label_badge" msgid="2355652472854327647">"कार्यस्थल का <xliff:g id="LABEL">%1$s</xliff:g>"</string> <string name="lock_to_app_toast" msgid="7570091317001980053">"इस स्क्रीन को अनपिन करने के लिए, एक ही समय में वापस जाएं और अवलोकन को स्पर्श करके रखें."</string> <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"इस स्क्रीन को अनपिन करने के लिए, अवलोकन को स्पर्श करके रखें."</string> - <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"स्क्रीन पिन की गई है. आपके संगठन के द्वारा अनपिन करने की अनुमति नहीं है."</string> + <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) --> + <skip /> <string name="lock_to_app_start" msgid="6643342070839862795">"स्क्रीन पिन की गई"</string> <string name="lock_to_app_exit" msgid="8598219838213787430">"स्क्रीन अनपिन की गई"</string> <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"अनपिन करने से पहले पिन के लिए पूछें"</string> diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml index d5a4a0dbd0ef..59893da2c31f 100644 --- a/core/res/res/values-hr/strings.xml +++ b/core/res/res/values-hr/strings.xml @@ -797,6 +797,8 @@ <string name="permdesc_accessNotifications" msgid="458457742683431387">"Omogućuje aplikaciji dohvaćanje, pregledavanje i brisanje obavijesti, uključujući obavijesti drugih aplikacija."</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"vezanje uz uslugu slušatelja obavijesti"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Nositelju omogućuje vezanje uz sučelje najviše razine usluge slušatelja obavijesti. Ne bi smjelo biti potrebno za uobičajene aplikacije."</string> + <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"povezivanje s uslugom biranja cilja"</string> + <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Omogućuje nositelju povezivanje sa sučeljem najviše razine usluge biranja cilja. Ne bi smjelo biti potrebno za uobičajene aplikacije."</string> <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"povezivanje s uslugom davatelja uvjeta"</string> <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Vlasniku omogućuje povezivanje sa sučeljem najviše razine usluge davatelja uvjeta. Nije potrebno za normalne aplikacije."</string> <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"povezivanje s uslugom za usmjeravanje medija"</string> @@ -1268,6 +1270,14 @@ <string name="old_app_description" msgid="2082094275580358049">"Ne pokreći novu aplikaciju."</string> <string name="new_app_action" msgid="5472756926945440706">"Pokreni <xliff:g id="OLD_APP">%1$s</xliff:g>"</string> <string name="new_app_description" msgid="1932143598371537340">"Zaustavi staru aplikaciju bez spremanja."</string> + <!-- no translation found for dump_heap_notification (2618183274836056542) --> + <skip /> + <!-- no translation found for dump_heap_notification_detail (2075673362317481664) --> + <skip /> + <!-- no translation found for dump_heap_title (5864292264307651673) --> + <skip /> + <!-- no translation found for dump_heap_text (4809417337240334941) --> + <skip /> <string name="sendText" msgid="5209874571959469142">"Izaberite radnju za tekst"</string> <string name="volume_ringtone" msgid="6885421406845734650">"Glasnoća zvona"</string> <string name="volume_music" msgid="5421651157138628171">"Glasnoća medija"</string> @@ -1785,7 +1795,9 @@ <item quantity="other">Pokušajte ponovo za <xliff:g id="COUNT">%d</xliff:g> sekundi</item> </plurals> <string name="restr_pin_try_later" msgid="973144472490532377">"Pokušajte ponovo kasnije"</string> - <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Prijeđite prstom s vrha prema dolje za izlaz iz cijelog zaslona."</string> + <string name="immersive_cling_title" msgid="8394201622932303336">"Gledanje preko cijelog zaslona"</string> + <string name="immersive_cling_description" msgid="3482371193207536040">"Za izlaz prijeđite prstom prema od vrha prema dolje."</string> + <string name="immersive_cling_positive" msgid="5016839404568297683">"Shvaćam"</string> <string name="done_label" msgid="2093726099505892398">"Gotovo"</string> <string name="hour_picker_description" msgid="6698199186859736512">"Kružni klizač sati"</string> <string name="minute_picker_description" msgid="8606010966873791190">"Kružni klizač minuta"</string> @@ -1800,7 +1812,8 @@ <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> za posao"</string> <string name="lock_to_app_toast" msgid="7570091317001980053">"Da biste otkvačili ovaj zaslon, istovremeno dodirnite i zadržite Natrag i Pregled."</string> <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Da biste otkvačili ovaj zaslon, dodirnite i zadržite Pregled."</string> - <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Zaslon je pričvršćen. Vaša organizacija ne dopušta otkvačivanje."</string> + <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) --> + <skip /> <string name="lock_to_app_start" msgid="6643342070839862795">"Zaslon je pričvršćen"</string> <string name="lock_to_app_exit" msgid="8598219838213787430">"Zaslon je otkvačen"</string> <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Traži PIN radi otkvačivanja"</string> diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml index 2960784db489..12a0fb7bdeb4 100644 --- a/core/res/res/values-hu/strings.xml +++ b/core/res/res/values-hu/strings.xml @@ -796,6 +796,8 @@ <string name="permdesc_accessNotifications" msgid="458457742683431387">"Lehetővé teszi, hogy az alkalmazás értesítéseket kérdezzen le, vizsgáljon és tisztítson meg, beleértve az egyéb alkalmazások által közzétett értesítéseket is."</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"csatlakozzon értesítésfigyelő szolgáltatáshoz"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Lehetővé teszi a használó számára, hogy csatlakozzon egy értesítésfigyelő szolgáltatás legfelső szintű felületéhez. A normál alkalmazásoknak erre soha nincs szükségük."</string> + <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"csatlakozás célválasztó szolgáltatáshoz"</string> + <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Lehetővé teszi a használó számára, hogy csatlakozzon egy célválasztó szolgáltatás legfelső szintű kezelőfelületéhez. A normál alkalmazásoknak erre soha nincs szükségük."</string> <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"csatlakozás egy feltételbiztosító szolgáltatáshoz"</string> <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Lehetővé teszi a használó számára, hogy csatlakozzon egy feltételbiztosító szolgáltatás legfelső szintű kezelőfelületéhez. A normál alkalmazásoknak erre soha nincs szükségük."</string> <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"csatlakozás egy médiaútvonal-szolgáltatáshoz"</string> @@ -1263,6 +1265,14 @@ <string name="old_app_description" msgid="2082094275580358049">"Ne indítsa el az új alkalmazást."</string> <string name="new_app_action" msgid="5472756926945440706">"<xliff:g id="OLD_APP">%1$s</xliff:g> indítása"</string> <string name="new_app_description" msgid="1932143598371537340">"A régi alkalmazás leállítása mentés nélkül."</string> + <!-- no translation found for dump_heap_notification (2618183274836056542) --> + <skip /> + <!-- no translation found for dump_heap_notification_detail (2075673362317481664) --> + <skip /> + <!-- no translation found for dump_heap_title (5864292264307651673) --> + <skip /> + <!-- no translation found for dump_heap_text (4809417337240334941) --> + <skip /> <string name="sendText" msgid="5209874571959469142">"Válasszon ki egy műveletet a szöveghez"</string> <string name="volume_ringtone" msgid="6885421406845734650">"Csengetés hangereje"</string> <string name="volume_music" msgid="5421651157138628171">"Média hangereje"</string> @@ -1776,7 +1786,9 @@ <item quantity="one">Próbálja újra 1 másodperc múlva</item> </plurals> <string name="restr_pin_try_later" msgid="973144472490532377">"Próbálkozzon később"</string> - <string name="immersive_mode_confirmation" msgid="7227416894979047467">"A teljes képernyős nézetből való kilépéshez húzza ujját a képernyő tetejétől lefelé."</string> + <string name="immersive_cling_title" msgid="8394201622932303336">"Megtekintése teljes képernyőn"</string> + <string name="immersive_cling_description" msgid="3482371193207536040">"Kilépéshez csúsztassa ujját fentről lefelé."</string> + <string name="immersive_cling_positive" msgid="5016839404568297683">"Értem"</string> <string name="done_label" msgid="2093726099505892398">"Kész"</string> <string name="hour_picker_description" msgid="6698199186859736512">"Óra kör alakú csúszkája"</string> <string name="minute_picker_description" msgid="8606010966873791190">"Perc kör alakú csúszkája"</string> @@ -1791,7 +1803,8 @@ <string name="managed_profile_label_badge" msgid="2355652472854327647">"Munkahelyi <xliff:g id="LABEL">%1$s</xliff:g>"</string> <string name="lock_to_app_toast" msgid="7570091317001980053">"A képernyő rögzítésének feloldásához tartsa lenyomva a Vissza és az Áttekintés lehetőséget egyszerre."</string> <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"A képernyő rögzítésének feloldásához tartsa lenyomva az Áttekintés lehetőséget."</string> - <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"A képernyő rögzítve van. Szervezete nem engedélyezi a rögzítés feloldását."</string> + <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) --> + <skip /> <string name="lock_to_app_start" msgid="6643342070839862795">"Képernyő rögzítve"</string> <string name="lock_to_app_exit" msgid="8598219838213787430">"Képernyő rögzítése feloldva"</string> <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"PIN kód kérése a rögzítés feloldásához"</string> diff --git a/core/res/res/values-hy-rAM/strings.xml b/core/res/res/values-hy-rAM/strings.xml index 3fe28337b0ce..29510b34dfda 100644 --- a/core/res/res/values-hy-rAM/strings.xml +++ b/core/res/res/values-hy-rAM/strings.xml @@ -796,6 +796,8 @@ <string name="permdesc_accessNotifications" msgid="458457742683431387">"Թույլ է տալիս հավելվածին առբերել, ուսումնասիրել և մաքրել ծանուցումներն, այդ թվում նաև այլ հավելվածների կողմից գրառվածները:"</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"միանալ ծանուցումների ունկնդրիչ ծառայությանը"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Թույլ է տալիս սեփականատիրոջը միանալ ծանուցումները ունկնդրող ծառայության վերին մակարդակի ինտերֆեյսին: Սովորական հավելվածների համար երբևէ չպետք է անհրաժեշտ լինի:"</string> + <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"միանալ ընտրողի թիրախային ծառայությանը"</string> + <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Թույլ է տալիս միանալ ընտրողի թիրախային ծառայության վերին մակարդակի միջերեսին: Սովորական հավելվածների համար երբևէ չպետք է անհրաժեշտ լինի:"</string> <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"կապվել պայմանների մատակարարի ծառայությանը"</string> <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Թույլ է տալիս սեփականատիրոջը միանալ պայմանների մատակարարների բազային միջերեսին: Սովորական ծրագրերի համար երբևէ չպետք է անհրաժեշտ լինի:"</string> <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"կապվել մեդիա երթուղու ծառայությանը"</string> @@ -1108,7 +1110,7 @@ <string name="permlab_readVoicemail" msgid="8415201752589140137">"կարդալ ձայնային փոստը"</string> <string name="permdesc_readVoicemail" msgid="8926534735321616550">"Ծրագրին թույլ է տալիս կարդալ ձեր ձայնային փոստը"</string> <string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"փոփոխել դիտարկչի աշխարհագրական տեղանքի թույլտվությունները"</string> - <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"Թույլ է տալիս հավելվածին փոփոխել զննարկչի աշխարհագրական դիրքի թույլտվությունները: Վնասարար հավելվածները կարող են օգտագործել սա` թույլատրելու ուղարկել տեղադրության վերաբերյալ տեղեկությունները կամայական վեբ կայքերին:"</string> + <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"Թույլ է տալիս հավելվածին փոփոխել դիտարկչի աշխարհագրական դիրքի թույլտվությունները: Վնասարար հավելվածները կարող են օգտագործել սա` թույլատրելու ուղարկել տեղադրության վերաբերյալ տեղեկությունները կամայական վեբ կայքերին:"</string> <string name="permlab_packageVerificationAgent" msgid="5568139100645829117">"հաստատել փաթեթները"</string> <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Թույլ է տալիս հավելվածին հաստատել, որ փաթեթը տեղադրելի է:"</string> <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"միանալ փաթեթի ստուգիչին"</string> @@ -1263,6 +1265,14 @@ <string name="old_app_description" msgid="2082094275580358049">"Չսկսել նոր հավելված:"</string> <string name="new_app_action" msgid="5472756926945440706">"Սկիզբ <xliff:g id="OLD_APP">%1$s</xliff:g>"</string> <string name="new_app_description" msgid="1932143598371537340">"Դադարեցնել նախկին ծրագիրն առանց պահպանման:"</string> + <!-- no translation found for dump_heap_notification (2618183274836056542) --> + <skip /> + <!-- no translation found for dump_heap_notification_detail (2075673362317481664) --> + <skip /> + <!-- no translation found for dump_heap_title (5864292264307651673) --> + <skip /> + <!-- no translation found for dump_heap_text (4809417337240334941) --> + <skip /> <string name="sendText" msgid="5209874571959469142">"Ընտրեք գործողություն տեքստի համար"</string> <string name="volume_ringtone" msgid="6885421406845734650">"Զանգակի ձայնի ուժգնությունը"</string> <string name="volume_music" msgid="5421651157138628171">"Մեդիա ձայնի բարձրություն"</string> @@ -1776,7 +1786,9 @@ <item quantity="other">Կրկին փորձեք <xliff:g id="COUNT">%d</xliff:g> վայրկյանից</item> </plurals> <string name="restr_pin_try_later" msgid="973144472490532377">"Կրկին փորձեք մի փոքր ուշ"</string> - <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Սահահարվածեք վերից վար՝ ամբողջական էկրանից դուրս գալու համար:"</string> + <string name="immersive_cling_title" msgid="8394201622932303336">"Լիաէկրան դիտում"</string> + <string name="immersive_cling_description" msgid="3482371193207536040">"Դուրս գալու համար վերևից սահահարվածեք դեպի ներքև:"</string> + <string name="immersive_cling_positive" msgid="5016839404568297683">"Պարզ է"</string> <string name="done_label" msgid="2093726099505892398">"Պատրաստ է"</string> <string name="hour_picker_description" msgid="6698199186859736512">"Ժամերի ընտրություն թվատախտակից"</string> <string name="minute_picker_description" msgid="8606010966873791190">"Րոպեների ընտրություն թվատախտակից"</string> @@ -1791,7 +1803,8 @@ <string name="managed_profile_label_badge" msgid="2355652472854327647">"Աշխատանքային <xliff:g id="LABEL">%1$s</xliff:g>"</string> <string name="lock_to_app_toast" msgid="7570091317001980053">"Այս էկրան ապամրացնելու համար միաժամանակ հպեք և պահեք Հետ և Համատեսք կոճակները:"</string> <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Այս էկրանն ապամրացնելու համար հպեք և պահեք Համատեսքի կոճակը:"</string> - <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Էկրանն ամրացված է: Ապամրացումը չի թույլատրվում ձեր կազմակերպության կողմից:"</string> + <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) --> + <skip /> <string name="lock_to_app_start" msgid="6643342070839862795">"Էկրանն ամրացված է"</string> <string name="lock_to_app_exit" msgid="8598219838213787430">"Էկրանն ապամրացված է"</string> <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Ապաամրացնելուց առաջ հարցնել PIN-կոդը"</string> diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml index 96d65aece0c4..502f3183d002 100644 --- a/core/res/res/values-in/strings.xml +++ b/core/res/res/values-in/strings.xml @@ -796,6 +796,8 @@ <string name="permdesc_accessNotifications" msgid="458457742683431387">"Mengizinkan aplikasi mengambil, memeriksa, dan menghapus pemberitahuan, termasuk pemberitahuan yang diposkan oleh aplikasi lain."</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"mengikat layanan pendengar pemberitahuan"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Memungkinkan pemegang mengikat antarmuka tingkat teratas dari suatu layanan pendengar pemberitahuan. Tidak pernah diperlukan oleh aplikasi normal."</string> + <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"mengikat ke layanan sasaran pemilik"</string> + <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Memungkinkan pemegang mengikat antarmuka tingkat tinggi dari layanan interaksi suara. Tidak pernah diperlukan oleh aplikasi normal."</string> <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"mengikat ke layanan penyedia ketentuan"</string> <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Memungkinkan pemegang mengikat antarmuka tingkat tinggi dari layanan penyedia ketentuan. Tidak pernah diperlukan oleh aplikasi normal."</string> <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"mengikat ke layanan rute media"</string> @@ -1263,6 +1265,14 @@ <string name="old_app_description" msgid="2082094275580358049">"Jangan memulai aplikasi baru."</string> <string name="new_app_action" msgid="5472756926945440706">"Mulai <xliff:g id="OLD_APP">%1$s</xliff:g>"</string> <string name="new_app_description" msgid="1932143598371537340">"Hentikan apl lama tanpa menyimpan."</string> + <!-- no translation found for dump_heap_notification (2618183274836056542) --> + <skip /> + <!-- no translation found for dump_heap_notification_detail (2075673362317481664) --> + <skip /> + <!-- no translation found for dump_heap_title (5864292264307651673) --> + <skip /> + <!-- no translation found for dump_heap_text (4809417337240334941) --> + <skip /> <string name="sendText" msgid="5209874571959469142">"Pilih tindakan untuk teks"</string> <string name="volume_ringtone" msgid="6885421406845734650">"Volume dering"</string> <string name="volume_music" msgid="5421651157138628171">"Volume media"</string> @@ -1776,7 +1786,9 @@ <item quantity="one">Coba 1 detik lagi</item> </plurals> <string name="restr_pin_try_later" msgid="973144472490532377">"Coba lagi nanti"</string> - <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Gesek dari atas ke bawah untuk keluar dari layar penuh."</string> + <string name="immersive_cling_title" msgid="8394201622932303336">"Melihat layar penuh"</string> + <string name="immersive_cling_description" msgid="3482371193207536040">"Untuk keluar, gesek ke bawah dari atas."</string> + <string name="immersive_cling_positive" msgid="5016839404568297683">"Mengerti"</string> <string name="done_label" msgid="2093726099505892398">"Selesai"</string> <string name="hour_picker_description" msgid="6698199186859736512">"Penggeser putar jam"</string> <string name="minute_picker_description" msgid="8606010966873791190">"Penggeser putar menit"</string> @@ -1791,7 +1803,8 @@ <string name="managed_profile_label_badge" msgid="2355652472854327647">"Kantor <xliff:g id="LABEL">%1$s</xliff:g>"</string> <string name="lock_to_app_toast" msgid="7570091317001980053">"Untuk melepas pin layar ini, sentuh lama tombol Kembali dan Ringkasan secara bersamaan."</string> <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Untuk melepas pin layar ini, sentuh lama tombol Ringkasan."</string> - <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Layar disematkan. Pelepasan sematan tidak diizinkan oleh organisasi Anda."</string> + <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) --> + <skip /> <string name="lock_to_app_start" msgid="6643342070839862795">"Layar disematkan"</string> <string name="lock_to_app_exit" msgid="8598219838213787430">"Layar dicopot sematannya"</string> <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Meminta PIN sebelum melepas sematan"</string> diff --git a/core/res/res/values-is-rIS/strings.xml b/core/res/res/values-is-rIS/strings.xml index 355becb9e021..11b4d98f0ed8 100644 --- a/core/res/res/values-is-rIS/strings.xml +++ b/core/res/res/values-is-rIS/strings.xml @@ -796,6 +796,8 @@ <string name="permdesc_accessNotifications" msgid="458457742683431387">"Leyfir forriti að sækja, skoða og hreinsa tilkynningar, þ. á m. þær sem önnur forrit birta."</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"bindast hlustunarþjónustu tilkynninga"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Leyfir forriti að bindast efsta viðmótslagi hlustunarþjónustu tilkynninga. Ætti aldrei að vera nauðsynlegt fyrir venjuleg forrit."</string> + <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"bindast valþjónustu fyrir markmið"</string> + <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Leyfir handhafa að bindast efsta viðmótslagi valþjónustu fyrir markmið. Ætti aldrei að vera nauðsynlegt fyrir venjuleg forrit."</string> <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"bindast þjónustu skilyrðaveitu"</string> <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Leyfir handhafa að bindast efsta viðmótslagi skilyrðaveitu. Ætti aldrei að vera nauðsynlegt fyrir venjuleg forrit."</string> <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"bindast beiningarþjónustu fyrir margmiðlun"</string> @@ -1263,6 +1265,14 @@ <string name="old_app_description" msgid="2082094275580358049">"Ekki ræsa nýja forritið."</string> <string name="new_app_action" msgid="5472756926945440706">"Ræsa <xliff:g id="OLD_APP">%1$s</xliff:g>"</string> <string name="new_app_description" msgid="1932143598371537340">"Stöðva gamla forritið án þess að vista."</string> + <!-- no translation found for dump_heap_notification (2618183274836056542) --> + <skip /> + <!-- no translation found for dump_heap_notification_detail (2075673362317481664) --> + <skip /> + <!-- no translation found for dump_heap_title (5864292264307651673) --> + <skip /> + <!-- no translation found for dump_heap_text (4809417337240334941) --> + <skip /> <string name="sendText" msgid="5209874571959469142">"Veldu aðgerð fyrir texta"</string> <string name="volume_ringtone" msgid="6885421406845734650">"Hljóðstyrkur hringingar"</string> <string name="volume_music" msgid="5421651157138628171">"Hljóðstyrkur efnisspilunar"</string> @@ -1776,7 +1786,9 @@ <item quantity="other">Reyndu aftur eftir <xliff:g id="COUNT">%d</xliff:g> sekúndur</item> </plurals> <string name="restr_pin_try_later" msgid="973144472490532377">"Reyndu aftur síðar"</string> - <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Strjúktu niður frá efri brún til að hætta að nota allan skjáinn."</string> + <string name="immersive_cling_title" msgid="8394201622932303336">"Notar allan skjáinn"</string> + <string name="immersive_cling_description" msgid="3482371193207536040">"Strjúktu niður frá efri brún til að hætta."</string> + <string name="immersive_cling_positive" msgid="5016839404568297683">"Ég skil"</string> <string name="done_label" msgid="2093726099505892398">"Lokið"</string> <string name="hour_picker_description" msgid="6698199186859736512">"Valskífa fyrir klukkustundir"</string> <string name="minute_picker_description" msgid="8606010966873791190">"Valskífa fyrir mínútur"</string> @@ -1791,7 +1803,8 @@ <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> í vinnu"</string> <string name="lock_to_app_toast" msgid="7570091317001980053">"Til að taka lásinn af þessari skjámynd skaltu halda inni Til baka og Yfirliti samtímis."</string> <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Til að taka lásinn af þessari skjámynd skaltu halda inni Yfirliti."</string> - <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Skjárinn er festur. Póstskipanin þín leyfir ekki að hann sé losaður."</string> + <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) --> + <skip /> <string name="lock_to_app_start" msgid="6643342070839862795">"Skjár festur"</string> <string name="lock_to_app_exit" msgid="8598219838213787430">"Skjár opnaður"</string> <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Biðja um PIN-númer til að losa"</string> diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml index 9b57ad83284c..2ab192f72386 100644 --- a/core/res/res/values-it/strings.xml +++ b/core/res/res/values-it/strings.xml @@ -738,14 +738,10 @@ <string name="permdesc_nfc" msgid="7120611819401789907">"Consente all\'applicazione di comunicare con tag, schede e lettori NFC (Near Field Communication)."</string> <string name="permlab_disableKeyguard" msgid="3598496301486439258">"disattivazione blocco schermo"</string> <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"Consente all\'applicazione di disattivare il blocco tastiera ed eventuali protezioni tramite password associate. Ad esempio, il telefono disattiva il blocco tastiera quando riceve una telefonata in arrivo e lo riattiva al termine della chiamata."</string> - <!-- no translation found for permlab_manageFingerprint (5640858826254575638) --> - <skip /> - <!-- no translation found for permdesc_manageFingerprint (178208705828055464) --> - <skip /> - <!-- no translation found for permlab_useFingerprint (3150478619915124905) --> - <skip /> - <!-- no translation found for permdesc_useFingerprint (9165097460730684114) --> - <skip /> + <string name="permlab_manageFingerprint" msgid="5640858826254575638">"gestisci hardware per il riconoscimento delle impronte digitali"</string> + <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Consente all\'app di richiamare metodi per aggiungere e rimuovere modelli di impronte digitali da utilizzare."</string> + <string name="permlab_useFingerprint" msgid="3150478619915124905">"utilizza hardware per il riconoscimento delle impronte digitali"</string> + <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Consente all\'app di utilizzare l\'hardware per il riconoscimento delle impronte digitali per eseguire l\'autenticazione"</string> <string name="permlab_readSyncSettings" msgid="6201810008230503052">"lettura impostazioni di sincronizz."</string> <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Consente all\'applicazione di leggere le impostazioni di sincronizzazione per un account. Ad esempio, questa autorizzazione può determinare se l\'applicazione Persone è sincronizzata con un account."</string> <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"attivazione e disattivazione della sincronizzazione"</string> @@ -800,6 +796,8 @@ <string name="permdesc_accessNotifications" msgid="458457742683431387">"Consente all\'app di recuperare, esaminare e cancellare notifiche, comprese quelle pubblicate da altre app."</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"vincolo a un servizio listener di notifica"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Consente al titolare di vincolarsi all\'interfaccia di primo livello di un servizio listener di notifica. Non dovrebbe mai essere necessaria per le normali applicazioni."</string> + <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"collegamento al servizio di destinazione di un utente"</string> + <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Consente al titolare di collegarsi all\'interfaccia di primo livello del servizio di destinazione di un utente. Non dovrebbe essere mai necessaria per le normali applicazioni."</string> <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"collegamento a un servizio provider di condizioni"</string> <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Consente al titolare di collegarsi all\'interfaccia di primo livello di un servizio provider di condizioni. Non dovrebbe essere mai necessaria per le normali app."</string> <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"associa a servizio di routing multimediale"</string> @@ -1267,6 +1265,14 @@ <string name="old_app_description" msgid="2082094275580358049">"Non avviare la nuova applicazione."</string> <string name="new_app_action" msgid="5472756926945440706">"Avvia <xliff:g id="OLD_APP">%1$s</xliff:g>"</string> <string name="new_app_description" msgid="1932143598371537340">"Interrompi la vecchia applicazione senza salvare."</string> + <!-- no translation found for dump_heap_notification (2618183274836056542) --> + <skip /> + <!-- no translation found for dump_heap_notification_detail (2075673362317481664) --> + <skip /> + <!-- no translation found for dump_heap_title (5864292264307651673) --> + <skip /> + <!-- no translation found for dump_heap_text (4809417337240334941) --> + <skip /> <string name="sendText" msgid="5209874571959469142">"Scegli un\'azione per il testo"</string> <string name="volume_ringtone" msgid="6885421406845734650">"Volume suoneria"</string> <string name="volume_music" msgid="5421651157138628171">"Volume contenuti multimediali"</string> @@ -1780,7 +1786,9 @@ <item quantity="one">Riprova tra 1 secondo</item> </plurals> <string name="restr_pin_try_later" msgid="973144472490532377">"Riprova più tardi"</string> - <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Scorri dall\'alto verso il basso per uscire dalla modalità schermo intero."</string> + <string name="immersive_cling_title" msgid="8394201622932303336">"Visualizzazione a schermo intero"</string> + <string name="immersive_cling_description" msgid="3482371193207536040">"Per uscire, scorri dall\'alto verso il basso."</string> + <string name="immersive_cling_positive" msgid="5016839404568297683">"OK"</string> <string name="done_label" msgid="2093726099505892398">"Fine"</string> <string name="hour_picker_description" msgid="6698199186859736512">"Dispositivo di scorrimento circolare per le ore"</string> <string name="minute_picker_description" msgid="8606010966873791190">"Dispositivo di scorrimento circolare per i minuti"</string> @@ -1795,7 +1803,8 @@ <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> lavoro"</string> <string name="lock_to_app_toast" msgid="7570091317001980053">"Per sbloccare questa schermata, tocca e tieni premute contemporaneamente le opzioni Indietro e Panoramica."</string> <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Per sbloccare questa schermata, tocca e tieni premuta l\'opzione Panoramica."</string> - <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"La schermata è bloccata. La tua organizzazione non ne consente lo sblocco."</string> + <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) --> + <skip /> <string name="lock_to_app_start" msgid="6643342070839862795">"Schermata bloccata"</string> <string name="lock_to_app_exit" msgid="8598219838213787430">"Schermata sbloccata"</string> <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Richiedi il PIN prima di sbloccare"</string> diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml index 9f0540fc9475..15c1b352c029 100644 --- a/core/res/res/values-iw/strings.xml +++ b/core/res/res/values-iw/strings.xml @@ -798,6 +798,8 @@ <string name="permdesc_accessNotifications" msgid="458457742683431387">"מאפשר לאפליקציה לאחזר, לבדוק ולמחוק התראות, כולל כאלה שפורסמו על ידי אפליקציות אחרות."</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"איגוד לשירות של מאזין להתראות"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"הרשאה זו מאפשרת למשתמש לבצע איגוד לממשק הרמה העליונה של שירות מאזין להתראות. הרשאה זו אף פעם אינה נחוצה לאפליקציות רגילים."</string> + <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"איגוד אל שירות Chooser Target"</string> + <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"מאפשר לבעלים לאגד לממשק ברמה העליונה של שירות Chooser Target. לעולם לא אמור להיות נחוץ עבור אפליקציות רגילות."</string> <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"איגוד לשירות ספק תנאי"</string> <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"מאפשרת לבעלים לאגד לממשק ברמה העליונה של שירות ספק תנאי. לעולם לא אמורה להיות נחוצה עבור אפליקציות רגילות."</string> <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"איגוד לשירות ניתוב מדיה"</string> @@ -1273,6 +1275,14 @@ <string name="old_app_description" msgid="2082094275580358049">"אל תפעיל את האפליקציה החדש."</string> <string name="new_app_action" msgid="5472756926945440706">"הפעל את <xliff:g id="OLD_APP">%1$s</xliff:g>"</string> <string name="new_app_description" msgid="1932143598371537340">"עצור את האפליקציה הישן ללא שמירה."</string> + <!-- no translation found for dump_heap_notification (2618183274836056542) --> + <skip /> + <!-- no translation found for dump_heap_notification_detail (2075673362317481664) --> + <skip /> + <!-- no translation found for dump_heap_title (5864292264307651673) --> + <skip /> + <!-- no translation found for dump_heap_text (4809417337240334941) --> + <skip /> <string name="sendText" msgid="5209874571959469142">"בחירת פעולה לביצוע עם טקסט"</string> <string name="volume_ringtone" msgid="6885421406845734650">"עוצמת קול של צלצול"</string> <string name="volume_music" msgid="5421651157138628171">"עוצמת קול של מדיה"</string> @@ -1794,7 +1804,9 @@ <item quantity="one">נסה שוב בעוד שנייה אחת</item> </plurals> <string name="restr_pin_try_later" msgid="973144472490532377">"נסה שוב מאוחר יותר"</string> - <string name="immersive_mode_confirmation" msgid="7227416894979047467">"החלק מטה מהחלק העליון כדי לצאת ממסך מלא."</string> + <string name="immersive_cling_title" msgid="8394201622932303336">"צפייה במסך מלא"</string> + <string name="immersive_cling_description" msgid="3482371193207536040">"כדי לצאת, החלק מלמעלה למטה."</string> + <string name="immersive_cling_positive" msgid="5016839404568297683">"הבנתי"</string> <string name="done_label" msgid="2093726099505892398">"בוצע"</string> <string name="hour_picker_description" msgid="6698199186859736512">"מחוון שעות מעגלי"</string> <string name="minute_picker_description" msgid="8606010966873791190">"מחוון דקות מעגלי"</string> @@ -1809,7 +1821,8 @@ <string name="managed_profile_label_badge" msgid="2355652472854327647">"עבודה <xliff:g id="LABEL">%1$s</xliff:g>"</string> <string name="lock_to_app_toast" msgid="7570091317001980053">"כדי לבטל את הקפאת המסך הזה, גע בו-זמנית נגיעה ממושכת ב\'הקודם\' ו\'סקירה\'."</string> <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"כדי לבטל את הקפאת המסך הזה, גע נגיעה ממושכת ב\'סקירה\'."</string> - <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"המסך מוצמד. הארגון אוסר לבטל את הצמדתו."</string> + <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) --> + <skip /> <string name="lock_to_app_start" msgid="6643342070839862795">"המסך מוצמד"</string> <string name="lock_to_app_exit" msgid="8598219838213787430">"הצמדת המסך בוטלה"</string> <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"בקש קוד אימות לפני ביטול הצמדה"</string> diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml index 91f72cf063ea..c4849b22c9b7 100644 --- a/core/res/res/values-ja/strings.xml +++ b/core/res/res/values-ja/strings.xml @@ -528,7 +528,7 @@ <string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"あなたや友だちのソーシャル更新情報へのアクセスと同期をアプリに許可します。情報の共有は慎重に行ってください。これを許可すると、あなたと友だちがソーシャルネットワークで行ったやり取りを、機密性に関係なくアプリから読み取ることができるようになります。注: この許可は、一部のソーシャルネットワークでは適用されない場合があります。"</string> <string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"ソーシャルストリームに書く"</string> <string name="permdesc_writeSocialStream" product="default" msgid="3086557552204114849">"友だちのソーシャル更新情報の表示をアプリに許可します。情報の共有は慎重に行ってください。これによりアプリは、友だちから発信されたかのようなメッセージを作成できるようになります。注: この許可は、一部のソーシャルネットワークでは適用されない場合があります。"</string> - <string name="permlab_readCalendar" msgid="5972727560257612398">"カレンダーの予定と機密情報を読み取る"</string> + <string name="permlab_readCalendar" msgid="5972727560257612398">"カレンダーの予定と機密情報の読み取り"</string> <string name="permdesc_readCalendar" product="tablet" msgid="4216462049057658723">"タブレットに保存されているカレンダーの予定(友だちや同僚の予定も含めすべて)を読み取ることをアプリに許可します。これにより、アプリがカレンダーのデータを機密性に関係なく共有または保存できるようになる可能性があります。"</string> <string name="permdesc_readCalendar" product="tv" msgid="3191352452242394196">"テレビに保存されているカレンダーの予定(友だちや同僚の予定も含めすべて)を読み取ることをアプリに許可します。これにより、アプリがカレンダーのデータを機密性に関係なく共有または保存できるようになる可能性があります。"</string> <string name="permdesc_readCalendar" product="default" msgid="7434548682470851583">"携帯端末に保存されているカレンダーの予定(友だちや同僚の予定も含めすべて)を読み取ることをアプリに許可します。これにより、アプリがカレンダーのデータを機密性に関係なく共有または保存できるようになる可能性があります。"</string> @@ -738,14 +738,10 @@ <string name="permdesc_nfc" msgid="7120611819401789907">"NFCタグ、カード、リーダーとの通信をアプリに許可します。"</string> <string name="permlab_disableKeyguard" msgid="3598496301486439258">"画面ロックの無効化"</string> <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"キーロックとキーロックに関連付けられたパスワードのセキュリティを無効にすることをアプリに許可します。たとえば、かかってきた電話を受ける際にキーロックを無効にし、通話が終了したらキーロックを再度有効にする場合などに使用します。"</string> - <!-- no translation found for permlab_manageFingerprint (5640858826254575638) --> - <skip /> - <!-- no translation found for permdesc_manageFingerprint (178208705828055464) --> - <skip /> - <!-- no translation found for permlab_useFingerprint (3150478619915124905) --> - <skip /> - <!-- no translation found for permdesc_useFingerprint (9165097460730684114) --> - <skip /> + <string name="permlab_manageFingerprint" msgid="5640858826254575638">"指紋ハードウェアの管理"</string> + <string name="permdesc_manageFingerprint" msgid="178208705828055464">"使用する指紋テンプレートの追加や削除を行う方法の呼び出しをアプリに許可します。"</string> + <string name="permlab_useFingerprint" msgid="3150478619915124905">"指紋ハードウェアの使用"</string> + <string name="permdesc_useFingerprint" msgid="9165097460730684114">"指紋ハードウェアを認証に使用することをアプリに許可します"</string> <string name="permlab_readSyncSettings" msgid="6201810008230503052">"同期設定の読み取り"</string> <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"アカウントの同期設定の読み取りをアプリに許可します。たとえば、連絡帳アプリがアカウントと同期しているかどうかをアプリから特定できるようになります。"</string> <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"同期のON/OFFの切り替え"</string> @@ -800,6 +796,8 @@ <string name="permdesc_accessNotifications" msgid="458457742683431387">"通知(他のアプリから投稿されたものも含む)を取得、調査、クリアすることをアプリに許可します。"</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"通知リスナーサービスにバインド"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"通知リスナーサービスのトップレベルインターフェースにバインドすることを所有者に許可します。通常のアプリでは不要です。"</string> + <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"選択した対象サービスへのバインド"</string> + <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"選択した対象サービスのトップレベルインターフェースにバインドすることを所有者に許可します。通常のアプリでは不要です。"</string> <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"コンディションプロバイダサービスへのバインド"</string> <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"コンディションプロバイダサービスのトップレベルインターフェースにバインドすることを所有者に許可します。通常のアプリでは不要です。"</string> <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"メディアルートサービスへのバインド"</string> @@ -1267,6 +1265,14 @@ <string name="old_app_description" msgid="2082094275580358049">"新しいアプリを起動しません。"</string> <string name="new_app_action" msgid="5472756926945440706">"<xliff:g id="OLD_APP">%1$s</xliff:g>を起動"</string> <string name="new_app_description" msgid="1932143598371537340">"古いアプリを保存せずに停止します。"</string> + <!-- no translation found for dump_heap_notification (2618183274836056542) --> + <skip /> + <!-- no translation found for dump_heap_notification_detail (2075673362317481664) --> + <skip /> + <!-- no translation found for dump_heap_title (5864292264307651673) --> + <skip /> + <!-- no translation found for dump_heap_text (4809417337240334941) --> + <skip /> <string name="sendText" msgid="5209874571959469142">"アプリケーションを選択"</string> <string name="volume_ringtone" msgid="6885421406845734650">"着信音量"</string> <string name="volume_music" msgid="5421651157138628171">"メディアの音量"</string> @@ -1780,7 +1786,9 @@ <item quantity="one">1秒後にもう一度お試しください</item> </plurals> <string name="restr_pin_try_later" msgid="973144472490532377">"しばらくしてから再試行"</string> - <string name="immersive_mode_confirmation" msgid="7227416894979047467">"全画面表示を終了するには、上から下にスワイプ"</string> + <string name="immersive_cling_title" msgid="8394201622932303336">"全画面表示"</string> + <string name="immersive_cling_description" msgid="3482371193207536040">"終了するには、上部から下にスワイプします。"</string> + <string name="immersive_cling_positive" msgid="5016839404568297683">"OK"</string> <string name="done_label" msgid="2093726099505892398">"完了"</string> <string name="hour_picker_description" msgid="6698199186859736512">"円形スライダー(時)"</string> <string name="minute_picker_description" msgid="8606010966873791190">"円形スライダー(分)"</string> @@ -1795,7 +1803,8 @@ <string name="managed_profile_label_badge" msgid="2355652472854327647">"仕事の<xliff:g id="LABEL">%1$s</xliff:g>"</string> <string name="lock_to_app_toast" msgid="7570091317001980053">"この画面の固定を解除するには[戻る]と[最近]を同時に押し続けます。"</string> <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"この画面の固定を解除するには[最近]を押し続けます。"</string> - <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"画面が固定されています。会社/組織により解除は許可されていません。"</string> + <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) --> + <skip /> <string name="lock_to_app_start" msgid="6643342070839862795">"画面を固定しました"</string> <string name="lock_to_app_exit" msgid="8598219838213787430">"画面固定を解除しました"</string> <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"オフライン再生を解除する前にPINの入力を求める"</string> diff --git a/core/res/res/values-ka-rGE/strings.xml b/core/res/res/values-ka-rGE/strings.xml index f642062ded20..f0b3f3155339 100644 --- a/core/res/res/values-ka-rGE/strings.xml +++ b/core/res/res/values-ka-rGE/strings.xml @@ -796,6 +796,8 @@ <string name="permdesc_accessNotifications" msgid="458457742683431387">"აპს შეეძლება მოიძიოს, გამოიკვლიოს და წაშალოს შეტყობინებები, მათ შორის სხვა აპების მიერ გამოქვეყნებული."</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"შეტყობინებების მოსმენის სერვისთან დაკავშირება"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"მფლობელს შეეძლება შეტყობინებების მსმენლის სერვისის ზედა დონის ინტერფეისთან დაკავშირება. არ უნდა მოხდეს მისი გამოყენება ჩვეუელებრივი აპებისთვის.ფ"</string> + <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"აკავშირებს შერჩეულ სამიზნე მომსახურებასთან"</string> + <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"საშუალებას აძლევს მფლობელს, დააკავშიროს ზედა დონის ინტერფეისი შერჩეულ სამიზნე მომსახურებასთან. არასდროს უნდა იყოს საჭირო ნორმალურ აპლიკაციებში."</string> <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"მდგომარეობის პროვაიდერის სერვისებთან შეკავშირება"</string> <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"მფლობელს შეეძლება შეკავშირდეს მდგომარეობის პროვაიდერის სერვისების ზედა დონის ინტერფეისთან. ჩვეულებრივ აპს ეს წესით არასოდეს უნდა დასჭირდეს."</string> <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"მედიის მარშრუტის სერვისთან შეკავშირება"</string> @@ -1263,6 +1265,14 @@ <string name="old_app_description" msgid="2082094275580358049">"არ ჩართოთ ახალი აპი."</string> <string name="new_app_action" msgid="5472756926945440706">"დასაწყისი <xliff:g id="OLD_APP">%1$s</xliff:g>"</string> <string name="new_app_description" msgid="1932143598371537340">"შეაჩერე ძველი აპი ცვლილებების შენახვის გარეშე."</string> + <!-- no translation found for dump_heap_notification (2618183274836056542) --> + <skip /> + <!-- no translation found for dump_heap_notification_detail (2075673362317481664) --> + <skip /> + <!-- no translation found for dump_heap_title (5864292264307651673) --> + <skip /> + <!-- no translation found for dump_heap_text (4809417337240334941) --> + <skip /> <string name="sendText" msgid="5209874571959469142">"შეარჩიეთ ქმედება ტექსტისთვის."</string> <string name="volume_ringtone" msgid="6885421406845734650">"მრეკავის ხმა"</string> <string name="volume_music" msgid="5421651157138628171">"მედიის ხმა"</string> @@ -1776,7 +1786,9 @@ <item quantity="one">ხელახლა სცადეთ 1 წამში</item> </plurals> <string name="restr_pin_try_later" msgid="973144472490532377">"სცადეთ მოგვიანებით"</string> - <string name="immersive_mode_confirmation" msgid="7227416894979047467">"ჩამოასრიალეთ ზევიდან სრული ეკრანის დასახურად."</string> + <string name="immersive_cling_title" msgid="8394201622932303336">"სრულ ეკრანზე ნახვა"</string> + <string name="immersive_cling_description" msgid="3482371193207536040">"გამოსვლისათვის, გაასრიალეთ ზემოდან ქვემოთ."</string> + <string name="immersive_cling_positive" msgid="5016839404568297683">"გასაგებია"</string> <string name="done_label" msgid="2093726099505892398">"დასრულდა"</string> <string name="hour_picker_description" msgid="6698199186859736512">"საათების წრიული სლაიდერი"</string> <string name="minute_picker_description" msgid="8606010966873791190">"წუთების წრიული სლაიდერი"</string> @@ -1791,7 +1803,8 @@ <string name="managed_profile_label_badge" msgid="2355652472854327647">"სამსახური <xliff:g id="LABEL">%1$s</xliff:g>"</string> <string name="lock_to_app_toast" msgid="7570091317001980053">"მიმაგრების გასაუქმებლად ერთდროულად შეეხეთ და არ აუშვათ ღილაკებს „უკან“ და „მიმოხილვა“."</string> <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"ამ ეკრანისთვის მიმაგრების გასაუქმებლად, შეეხეთ და არ აუშვათ „მიმოხილვა“-ს."</string> - <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"ეკრანი დაფიქსირებული. ფიქსაციის მოხსნა თქვენო ორგანიზაციის მიერ ნებადართული არ არის."</string> + <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) --> + <skip /> <string name="lock_to_app_start" msgid="6643342070839862795">"ეკრანი დაფიქსირდა"</string> <string name="lock_to_app_exit" msgid="8598219838213787430">"ეკრანს ფიქსაცია მოეხსნა"</string> <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"ფიქსაციის მოხსნამდე PIN-ის მოთხოვნა"</string> diff --git a/core/res/res/values-kk-rKZ/strings.xml b/core/res/res/values-kk-rKZ/strings.xml index 7ce44de9b974..3d5260709a6a 100644 --- a/core/res/res/values-kk-rKZ/strings.xml +++ b/core/res/res/values-kk-rKZ/strings.xml @@ -796,6 +796,8 @@ <string name="permdesc_accessNotifications" msgid="458457742683431387">"Қолданбаға хабарларды алу, тексеру және тазалау мүмкіндігін береді, басқа қолданбалар арқылы қойылған хабарларды қоса."</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"хабар тыңдау қызметіне қосылу"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Пайдаланушыға хабар есту қызметінің жоғары деңгейлі интерфейсіне жалғану мүмкіндігін ұсынады. Қалыпты қолданбаны ешқашан қажет етпеуі тиіс."</string> + <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"таңдау мақсатты қызметіне байластыру"</string> + <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Иесіне таңдау мақсатты қызметінің жоғарғы деңгейлі интерфейсіне байластыруға мүмкіндік береді. Қалыпты қолданбаларға үшін ешқашан қажет болмайды."</string> <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"шарттар провайдері қызметіне байластыру"</string> <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Пайдаланушыға шарт провайдері қызметінің жоғары деңгейлі интерфейсіне байластыруға рұқсат береді. Қалыпты қолданбалар үшін ешқашан қажет болмайды."</string> <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"медианы бағыттау қызметіне байластыру"</string> @@ -1263,6 +1265,14 @@ <string name="old_app_description" msgid="2082094275580358049">"Жаңа қолданбаны іске қоспау."</string> <string name="new_app_action" msgid="5472756926945440706">"<xliff:g id="OLD_APP">%1$s</xliff:g> қолданбасын қосу"</string> <string name="new_app_description" msgid="1932143598371537340">"Ескі қолданбаны сақтаусыз тоқтату."</string> + <!-- no translation found for dump_heap_notification (2618183274836056542) --> + <skip /> + <!-- no translation found for dump_heap_notification_detail (2075673362317481664) --> + <skip /> + <!-- no translation found for dump_heap_title (5864292264307651673) --> + <skip /> + <!-- no translation found for dump_heap_text (4809417337240334941) --> + <skip /> <string name="sendText" msgid="5209874571959469142">"Мәтін үшін әрекет таңдау"</string> <string name="volume_ringtone" msgid="6885421406845734650">"Қоңырау шырылының қаттылығы"</string> <string name="volume_music" msgid="5421651157138628171">"Meдиа дыбысының қаттылығы"</string> @@ -1776,7 +1786,9 @@ <item quantity="one">Әрекетті 1 секундтан кейін қайталаңыз</item> </plurals> <string name="restr_pin_try_later" msgid="973144472490532377">"Кейінірек қайта әрекеттеніңіз."</string> - <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Толық экраннан шығу үшін саусағыңызды жоғарыдан төмен қарай жылжытыңыз."</string> + <string name="immersive_cling_title" msgid="8394201622932303336">"Толық экранда көру"</string> + <string name="immersive_cling_description" msgid="3482371193207536040">"Шығу үшін жоғарыдан төмен қарай жанап өтіңіз."</string> + <string name="immersive_cling_positive" msgid="5016839404568297683">"Түсіндім"</string> <string name="done_label" msgid="2093726099505892398">"Орындалды"</string> <string name="hour_picker_description" msgid="6698199186859736512">"Сағаттар айналымының қозғалтқышы"</string> <string name="minute_picker_description" msgid="8606010966873791190">"Минут айналымын қозғалтқыш"</string> @@ -1791,7 +1803,8 @@ <string name="managed_profile_label_badge" msgid="2355652472854327647">"Жұмыс <xliff:g id="LABEL">%1$s</xliff:g>"</string> <string name="lock_to_app_toast" msgid="7570091317001980053">"Осы экранды босату үшін «Кері» және «Шолу» пәрмендерін бір уақытта түртіп, ұстап тұрыңыз."</string> <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Осы экранды босату үшін «Шолу» пәрменін түртіп, ұстап тұрыңыз."</string> - <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Экран түйрелген. Босатуға ұйымыңыз рұқсат етпейді."</string> + <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) --> + <skip /> <string name="lock_to_app_start" msgid="6643342070839862795">"Экран түйрелді"</string> <string name="lock_to_app_exit" msgid="8598219838213787430">"Экран босатылды"</string> <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Босату алдында PIN кодын сұрау"</string> diff --git a/core/res/res/values-km-rKH/strings.xml b/core/res/res/values-km-rKH/strings.xml index 16f3da2dfa35..f429f59f4122 100644 --- a/core/res/res/values-km-rKH/strings.xml +++ b/core/res/res/values-km-rKH/strings.xml @@ -796,6 +796,8 @@ <string name="permdesc_accessNotifications" msgid="458457742683431387">"ឲ្យកម្មវិធីទៅយក ពិនិត្យ និងសម្អាតការជូនដំណឹង រួមមានប្រកាសដោយកម្មវិធីផ្សេងៗ។"</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"ចងទៅសេវាកម្មស្ដាប់ការជូនដំណឹង"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"ឲ្យម្ចាស់ចងចំណុចប្រទាក់កម្រិតកំពូលនៃសេវាកម្មកម្មវិធីស្ដាប់ការជូនដំណឹង។ មិនគួរចាំបាច់សម្រាប់កម្មវិធីធម្មតាទេ។"</string> + <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"ចងភ្ជាប់ទៅសេវាកម្មគោលដៅជ្រើសរើស"</string> + <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"អនុញ្ញាតឲ្យអ្នកប្រើចងភ្ជាប់ទៅអ៊ីនធឺហ្វេសកម្រិតខ្ពស់នៃសេវាកម្មគោលដៅជ្រើសរើស។ អាចនឹងមិនចាំបាច់សម្រាប់កម្មវិធីធម្មតាទេ។"</string> <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"ភ្ជាប់ទៅសេវាកម្មក្រុមហ៊ុនផ្ដល់លក្ខខណ្ឌ"</string> <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"អនុញ្ញាតឲ្យម្ចាស់ភ្ជាប់ទៅចំណុចប្រទាក់កម្រិតកំពូលរបស់សេវាកម្មក្រុមហ៊ុនផ្ដល់លក្ខខណ្ឌ។ មិនគួរចាំបាច់សម្រាប់កម្មវិធីធម្មតាទេ។"</string> <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"ភ្ជាប់ទៅសេវាផ្លូវមេឌៀ"</string> @@ -1265,6 +1267,14 @@ <string name="old_app_description" msgid="2082094275580358049">"កុំចាប់ផ្ដើមកម្មវិធីថ្មី។"</string> <string name="new_app_action" msgid="5472756926945440706">"ចាប់ផ្ដើម <xliff:g id="OLD_APP">%1$s</xliff:g>"</string> <string name="new_app_description" msgid="1932143598371537340">"បញ្ឈប់កម្មវិធីចាស់ដោយមិនរក្សាទុក"</string> + <!-- no translation found for dump_heap_notification (2618183274836056542) --> + <skip /> + <!-- no translation found for dump_heap_notification_detail (2075673362317481664) --> + <skip /> + <!-- no translation found for dump_heap_title (5864292264307651673) --> + <skip /> + <!-- no translation found for dump_heap_text (4809417337240334941) --> + <skip /> <string name="sendText" msgid="5209874571959469142">"ជ្រើសសកម្មភាពសម្រាប់អត្ថបទ"</string> <string name="volume_ringtone" msgid="6885421406845734650">"កម្រិតសំឡេងរោទ៍"</string> <string name="volume_music" msgid="5421651157138628171">"កម្រិតសំឡេងមេឌៀ"</string> @@ -1778,7 +1788,9 @@ <item quantity="one">ព្យាយាមម្តងទៀតក្នុងរយៈពេល 1 វិនាទី</item> </plurals> <string name="restr_pin_try_later" msgid="973144472490532377">"សូមព្យាយាមម្ដងទៀតនៅពេលក្រោយ។"</string> - <string name="immersive_mode_confirmation" msgid="7227416894979047467">"អូសពីលើចុះក្រោម ដើម្បីចេញពីការបង្ហាញពេញអេក្រង់។"</string> + <string name="immersive_cling_title" msgid="8394201622932303336">"កំពុងមើលពេញអេក្រង់"</string> + <string name="immersive_cling_description" msgid="3482371193207536040">"ដើម្បីចាកចេញ សូមអូសពីលើចុះក្រោម។"</string> + <string name="immersive_cling_positive" msgid="5016839404568297683">"យល់ហើយ"</string> <string name="done_label" msgid="2093726099505892398">"រួចរាល់"</string> <string name="hour_picker_description" msgid="6698199186859736512">"គ្រាប់រំកិលរង្វង់ម៉ោង"</string> <string name="minute_picker_description" msgid="8606010966873791190">"គ្រាប់រំកិលរង្វង់នាទី"</string> @@ -1793,7 +1805,8 @@ <string name="managed_profile_label_badge" msgid="2355652472854327647">"កន្លែងធ្វើការ <xliff:g id="LABEL">%1$s</xliff:g>"</string> <string name="lock_to_app_toast" msgid="7570091317001980053">"ដើម្បីមិនភ្ជាប់អេក្រង់នេះ ប៉ះ ហើយសង្កត់ថយក្រោយ និងទិដ្ឋភាពនៅពេលតែមួយ។"</string> <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"ដើម្បីមិនភ្ជាប់អេក្រង់នេះ ប៉ះ ហើយសង្កត់ទិដ្ឋភាព។"</string> - <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"អេក្រង់ត្រូវបានភ្ជាប់។ ការផ្ដាច់មិនត្រូវបានអនុញ្ញាតដោយស្ថាប័នរបស់អ្នក។"</string> + <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) --> + <skip /> <string name="lock_to_app_start" msgid="6643342070839862795">"បានភ្ជាប់អេក្រង់"</string> <string name="lock_to_app_exit" msgid="8598219838213787430">"មិនបានភ្ជាប់អេក្រង់"</string> <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"សួររកកូដ PIN មុនពេលផ្ដាច់"</string> diff --git a/core/res/res/values-kn-rIN/strings.xml b/core/res/res/values-kn-rIN/strings.xml index ec24705e6a6e..a834721ae56f 100644 --- a/core/res/res/values-kn-rIN/strings.xml +++ b/core/res/res/values-kn-rIN/strings.xml @@ -796,6 +796,8 @@ <string name="permdesc_accessNotifications" msgid="458457742683431387">"ಇತರ ಅಪ್ಲಿಕೇಶನ್ಗಳ ಮೂಲಕ ಪೋಸ್ಟ್ ಮಾಡಿರುವ ಅಧಿಸೂಚನೆಗಳೂ ಸೇರಿದಂತೆ, ಅಂತಹ ಅಧಿಸೂಚನೆಗಳನ್ನು ಹಿಂಪಡೆದುಕೊಳ್ಳಲು, ಪರೀಕ್ಷಿಸಲು ಮತ್ತು ತೆರವುಗೊಳಿಸಲು ಅಪ್ಲಿಕೇಶನ್ಗೆ ಅನುಮತಿಸುತ್ತದೆ."</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"ಅಧಿಸೂಚನೆ ಕೇಳುಗರ ಸೇವೆಗೆ ಪ್ರತಿಬಂಧಿಸಿ"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"ಅಧಿಸೂಚನೆ ಕೇಳುಗ ಸೇವೆಯ ಮೇಲ್ಮಟ್ಟದ ಇಂಟರ್ಫೇಸ್ಗೆ ಪ್ರತಿಬಂಧಿಸಲು ಹೊಂದಿರುವವರಿಗೆ ಅವಕಾಶ ಮಾಡಿಕೊಡುತ್ತದೆ. ಸಾಮಾನ್ಯ ಅಪ್ಲಿಕೇಶನ್ಗಳಿಗೆ ಎಂದಿಗೂ ಅಗತ್ಯವಿರುವುದಿಲ್ಲ."</string> + <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"ಆಯ್ಕೆಮಾಡುವವರ ಗುರಿ ಸೇವೆಗೆ ಪ್ರತಿಬಂಧಿಸಿ"</string> + <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"ಆಯ್ಕೆಮಾಡುವವರ ಗುರಿ ಸೇವೆಯ ಮೇಲ್ಮಟ್ಟದ ಇಂಟರ್ಫೇಸ್ಗೆ ಪ್ರತಿಬಂಧಿಸಲು ಹೊಂದಿರುವವರಿಗೆ ಅವಕಾಶ ಮಾಡಿಕೊಡುತ್ತದೆ. ಸಾಮಾನ್ಯ ಅಪ್ಲಿಕೇಶನ್ಗಳಿಗಾಗಿ ಎಂದಿಗೂ ಅಗತ್ಯವಿರುವುದಿಲ್ಲ."</string> <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"ಕಂಡೀಶನ್ ಪೂರೈಕೆದಾರರ ಸೇವೆಯನ್ನು ಪ್ರತಿಬಂಧಿಸು"</string> <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"ಕಂಡೀಶನ್ ಪೂರೈಕೆದಾರರ ಮೇಲ್ಮಟ್ಟದ ಇಂಟರ್ಫೇಸ್ಗೆ ಪ್ರತಿಬಂಧಿಸಲು ಹೊಂದಿರುವವರಿಗೆ ಅವಕಾಶ ಮಾಡಿಕೊಡುತ್ತದೆ. ಸಾಮಾನ್ಯ ಅಪ್ಲಿಕೇಶನ್ಗಳಿಗೆ ಎಂದಿಗೂ ಅಗತ್ಯವಿರುವುದಿಲ್ಲ."</string> <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"ಮಾಧ್ಯಮ ಮಾರ್ಗ ಸೇವೆಯನ್ನು ಪ್ರತಿಬಂಧಿಸು"</string> @@ -1263,6 +1265,14 @@ <string name="old_app_description" msgid="2082094275580358049">"ಹೊಸ ಅಪ್ಲಿಕೇಶನ್ ಪ್ರಾರಂಭಿಸಬೇಡಿ."</string> <string name="new_app_action" msgid="5472756926945440706">"<xliff:g id="OLD_APP">%1$s</xliff:g> ಪ್ರಾರಂಭಿಸಿ"</string> <string name="new_app_description" msgid="1932143598371537340">"ಉಳಿಸದೇ ಹಳೆಯ ಅಪ್ಲಿಕೇಶನ್ ನಿಲ್ಲಿಸಿ."</string> + <!-- no translation found for dump_heap_notification (2618183274836056542) --> + <skip /> + <!-- no translation found for dump_heap_notification_detail (2075673362317481664) --> + <skip /> + <!-- no translation found for dump_heap_title (5864292264307651673) --> + <skip /> + <!-- no translation found for dump_heap_text (4809417337240334941) --> + <skip /> <string name="sendText" msgid="5209874571959469142">"ಪಠ್ಯಕ್ಕೆ ಕ್ರಿಯೆಯನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string> <string name="volume_ringtone" msgid="6885421406845734650">"ರಿಂಗರ್ ವಾಲ್ಯೂಮ್"</string> <string name="volume_music" msgid="5421651157138628171">"ಮೀಡಿಯಾ ವಾಲ್ಯೂಮ್"</string> @@ -1776,7 +1786,9 @@ <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> ಸೆಕೆಂಡುಗಳಲ್ಲಿ ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ</item> </plurals> <string name="restr_pin_try_later" msgid="973144472490532377">"ನಂತರ ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ"</string> - <string name="immersive_mode_confirmation" msgid="7227416894979047467">"ಪೂರ್ಣ ಪರದೆಯನ್ನು ನಿರ್ಗಮಿಸಲು ಮೇಲಿನಿಂದ ಕೆಳಕ್ಕೆ ಸ್ವೈಪ್ ಮಾಡಿ."</string> + <string name="immersive_cling_title" msgid="8394201622932303336">"ಪೂರ್ಣ ಪರದೆಯನ್ನು ವೀಕ್ಷಿಸಲಾಗುತ್ತಿದೆ"</string> + <string name="immersive_cling_description" msgid="3482371193207536040">"ನಿರ್ಗಮಿಸಲು, ಮೇಲಿನಿಂದ ಕೆಳಕ್ಕೆ ಸ್ವೈಪ್ ಮಾಡಿ."</string> + <string name="immersive_cling_positive" msgid="5016839404568297683">"ತಿಳಿಯಿತು"</string> <string name="done_label" msgid="2093726099505892398">"ಮುಗಿದಿದೆ"</string> <string name="hour_picker_description" msgid="6698199186859736512">"ಗಂಟೆಗಳ ವೃತ್ತಾಕಾರ ಸ್ಲೈಡರ್"</string> <string name="minute_picker_description" msgid="8606010966873791190">"ನಿಮಿಷಗಳ ವೃತ್ತಾಕಾರ ಸ್ಲೈಡರ್"</string> @@ -1791,7 +1803,8 @@ <string name="managed_profile_label_badge" msgid="2355652472854327647">"ಕೆಲಸ <xliff:g id="LABEL">%1$s</xliff:g>"</string> <string name="lock_to_app_toast" msgid="7570091317001980053">"ಈ ಪರದೆಯನ್ನು ಅನ್ಪಿನ್ ಮಾಡಲು, ‘ಹಿಂದೆ’ ಮತ್ತು ‘ಸಮಗ್ರ ನೋಟ’ವನ್ನು ಏಕಕಾಲದಲ್ಲಿ ಸ್ಪರ್ಶಿಸಿ ಮತ್ತು ಒತ್ತಿ ಹಿಡಿದುಕೊಳ್ಳಿ."</string> <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"ಈ ಪರದೆಯನ್ನು ಅನ್ಪಿನ್ ಮಾಡಲು, ‘ಸಮಗ್ರ ನೋಟ’ವನ್ನು ಸ್ಪರ್ಶಿಸಿ ಮತ್ತು ಒತ್ತಿ ಹಿಡಿಯಿರಿ."</string> - <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"ಪರದೆ ಪಿನ್ ಮಾಡಲಾಗಿದೆ. ಅನ್ಪಿನ್ ಮಾಡಲು ನಿಮ್ಮ ಸಂಸ್ಥೆ ಅವಕಾಶ ಮಾಡಿಕೊಟ್ಟಿಲ್ಲ."</string> + <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) --> + <skip /> <string name="lock_to_app_start" msgid="6643342070839862795">"ಸ್ಕ್ರೀನ್ ಪಿನ್ ಮಾಡಲಾಗಿದೆ"</string> <string name="lock_to_app_exit" msgid="8598219838213787430">"ಸ್ಕ್ರೀನ್ ಅನ್ಪಿನ್ ಮಾಡಲಾಗಿದೆ"</string> <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"ಅನ್ಪಿನ್ ಮಾಡುವುದಕ್ಕೂ ಮೊದಲು ಪಿನ್ ಕೇಳಿ"</string> diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml index a40ccac0befb..c263ce94439c 100644 --- a/core/res/res/values-ko/strings.xml +++ b/core/res/res/values-ko/strings.xml @@ -738,14 +738,10 @@ <string name="permdesc_nfc" msgid="7120611819401789907">"앱이 NFC(근거리 무선 통신) 태그, 카드 및 리더와 통신할 수 있도록 허용합니다."</string> <string name="permlab_disableKeyguard" msgid="3598496301486439258">"화면 잠금 사용 중지"</string> <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"앱이 키 잠금 및 관련 비밀번호 보안을 사용중지할 수 있도록 허용합니다. 예를 들어, 휴대전화가 수신전화를 받을 때 키 잠금을 사용중지했다가 통화가 끝나면 키 잠금을 다시 사용할 수 있습니다."</string> - <!-- no translation found for permlab_manageFingerprint (5640858826254575638) --> - <skip /> - <!-- no translation found for permdesc_manageFingerprint (178208705828055464) --> - <skip /> - <!-- no translation found for permlab_useFingerprint (3150478619915124905) --> - <skip /> - <!-- no translation found for permdesc_useFingerprint (9165097460730684114) --> - <skip /> + <string name="permlab_manageFingerprint" msgid="5640858826254575638">"지문 하드웨어 관리"</string> + <string name="permdesc_manageFingerprint" msgid="178208705828055464">"사용할 지문 템플릿의 추가 및 삭제 메소드를 앱에서 실행하도록 허용합니다."</string> + <string name="permlab_useFingerprint" msgid="3150478619915124905">"지문 하드웨어 사용"</string> + <string name="permdesc_useFingerprint" msgid="9165097460730684114">"앱에서 지문 하드웨어를 인증에 사용하도록 허용합니다."</string> <string name="permlab_readSyncSettings" msgid="6201810008230503052">"동기화 설정 읽기"</string> <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"앱이 계정의 동기화 설정을 읽을 수 있도록 허용합니다. 예를 들어, 계정에서 주소록 앱을 동기화할지 여부를 확인할 수 있습니다."</string> <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"동기화 사용 및 사용 중지 전환"</string> @@ -800,6 +796,8 @@ <string name="permdesc_accessNotifications" msgid="458457742683431387">"앱이 다른 앱에서 게시한 알림을 비롯하여 알림을 검색하고 살펴보며 삭제할 수 있도록 허용합니다."</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"알림 수신기 서비스 사용"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"권한을 가진 프로그램이 알림 수신기 서비스에 대한 최상위 인터페이스를 사용하도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string> + <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"선택기 타겟 서비스 사용"</string> + <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"권한을 가진 프로그램이 선택기 타겟 서비스에 대한 최상위 인터페이스를 사용하도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string> <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"조건 제공자 서비스 사용"</string> <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"권한을 가진 프로그램이 조건 제공자 서비스의 최상위 인터페이스를 사용하도록 합니다. 일반 앱에는 필요하지 않습니다."</string> <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"미디어 경로 서비스 사용"</string> @@ -1267,6 +1265,14 @@ <string name="old_app_description" msgid="2082094275580358049">"새 앱을 시작하지 마세요."</string> <string name="new_app_action" msgid="5472756926945440706">"<xliff:g id="OLD_APP">%1$s</xliff:g> 시작"</string> <string name="new_app_description" msgid="1932143598371537340">"저장하지 않고 이전 앱을 중단합니다."</string> + <!-- no translation found for dump_heap_notification (2618183274836056542) --> + <skip /> + <!-- no translation found for dump_heap_notification_detail (2075673362317481664) --> + <skip /> + <!-- no translation found for dump_heap_title (5864292264307651673) --> + <skip /> + <!-- no translation found for dump_heap_text (4809417337240334941) --> + <skip /> <string name="sendText" msgid="5209874571959469142">"텍스트에 대한 작업 선택"</string> <string name="volume_ringtone" msgid="6885421406845734650">"벨소리 볼륨"</string> <string name="volume_music" msgid="5421651157138628171">"미디어 볼륨"</string> @@ -1780,7 +1786,9 @@ <item quantity="one">1초 후에 다시 시도하세요.</item> </plurals> <string name="restr_pin_try_later" msgid="973144472490532377">"나중에 다시 시도"</string> - <string name="immersive_mode_confirmation" msgid="7227416894979047467">"전체화면을 종료하려면 위에서 아래로 스와이프하세요."</string> + <string name="immersive_cling_title" msgid="8394201622932303336">"전체 화면 보기"</string> + <string name="immersive_cling_description" msgid="3482371193207536040">"종료하려면 위에서 아래로 스와이프합니다."</string> + <string name="immersive_cling_positive" msgid="5016839404568297683">"확인"</string> <string name="done_label" msgid="2093726099505892398">"완료"</string> <string name="hour_picker_description" msgid="6698199186859736512">"시간 원형 슬라이더"</string> <string name="minute_picker_description" msgid="8606010966873791190">"분 원형 슬라이더"</string> @@ -1795,7 +1803,8 @@ <string name="managed_profile_label_badge" msgid="2355652472854327647">"업무용 <xliff:g id="LABEL">%1$s</xliff:g>"</string> <string name="lock_to_app_toast" msgid="7570091317001980053">"화면 고정을 해제하려면 \'뒤로\'와 \'개요\'를 동시에 길게 터치합니다."</string> <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"화면 고정을 해제하려면 \'개요\'를 길게 터치합니다."</string> - <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"화면이 고정되었습니다. 소속된 조직에서 고정 해제를 허용하지 않습니다."</string> + <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) --> + <skip /> <string name="lock_to_app_start" msgid="6643342070839862795">"화면 고정됨"</string> <string name="lock_to_app_exit" msgid="8598219838213787430">"화면 고정 해제됨"</string> <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"고정 해제 이전에 PIN 요청"</string> diff --git a/core/res/res/values-ky-rKG/strings.xml b/core/res/res/values-ky-rKG/strings.xml index faa69e6b57c4..f8a1e48b0e77 100644 --- a/core/res/res/values-ky-rKG/strings.xml +++ b/core/res/res/values-ky-rKG/strings.xml @@ -1007,6 +1007,8 @@ <string name="permdesc_accessNotifications" msgid="458457742683431387">"Колдонмого (башка колдонмолор жайгаштырган дагы) эскертүүлөрдү алуу, изилдөө, жана аларды тазалоо мүмкүнчүлүгүн берет."</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"эскертүү тыңшагыч кызматына байланыштыруу"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Ээсине эскертүү тыңшагыч кызматтын жогорку деңгээл интерфейсине туташуу мүмкүнчүлүгүн берет. Жөнөкөй колдонмолордо эч качан керектелбейт."</string> + <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"тандоочунун каалоосу кызматына туташуу"</string> + <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Кармоочуга тандоочунун каалоосу кызматынын жогорку деңгээл интерфейсин жалгаштырууга мүмкүндүк берет. Кадимки колдонмолорго эч качан талап кылынбайт."</string> <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"шарт түзүүчү кызматына жалгаштыруу"</string> <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Кармоочуга шарт түзүүчү кызматтын жогорку деңгээлдеги интерфейсине жалгашуу мүмкүнчүлүгүн берет. Кадимки колдонмолорго эч качан талап кылынбайт."</string> <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"медиа жол кызматына жалгаштыруу"</string> @@ -1655,6 +1657,14 @@ <!-- no translation found for new_app_action (5472756926945440706) --> <skip /> <string name="new_app_description" msgid="1932143598371537340">"Эски колдонмону сактабастан токтотуу."</string> + <!-- no translation found for dump_heap_notification (2618183274836056542) --> + <skip /> + <!-- no translation found for dump_heap_notification_detail (2075673362317481664) --> + <skip /> + <!-- no translation found for dump_heap_title (5864292264307651673) --> + <skip /> + <!-- no translation found for dump_heap_text (4809417337240334941) --> + <skip /> <string name="sendText" msgid="5209874571959469142">"Текст үчүн аракет тандаңыз"</string> <!-- no translation found for volume_ringtone (6885421406845734650) --> <skip /> @@ -2291,7 +2301,9 @@ <item quantity="one">1 секунддан кийин кайталаңыз</item> </plurals> <string name="restr_pin_try_later" msgid="973144472490532377">"Кийинчерээк кайталаңыз"</string> - <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Толук экран абалынан чыгуу үчүн жогорудан төмөн сүрүңүз."</string> + <string name="immersive_cling_title" msgid="8394201622932303336">"Толук экранды көрүүдө"</string> + <string name="immersive_cling_description" msgid="3482371193207536040">"Чыгуу үчүн, жогурдан төмөн сүрүңүз."</string> + <string name="immersive_cling_positive" msgid="5016839404568297683">"Түшүндүм"</string> <string name="done_label" msgid="2093726099505892398">"Даяр"</string> <string name="hour_picker_description" msgid="6698199186859736512">"Саат жебеси"</string> <string name="minute_picker_description" msgid="8606010966873791190">"Мүнөт жебеси"</string> @@ -2306,7 +2318,8 @@ <string name="managed_profile_label_badge" msgid="2355652472854327647">"Жумуш <xliff:g id="LABEL">%1$s</xliff:g>"</string> <string name="lock_to_app_toast" msgid="7570091317001980053">"Бул экранды бошотуу үчүн Артка жана Көз жүгүртүүнү чогуу басып, кармап туруңуз."</string> <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Бул экранды бошотуу үчүн Көз жүгүртүүнү басып, кармап туруңуз."</string> - <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Экран кадалды. Уюмуңуздун уруксатысыз бошото албайсыз."</string> + <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) --> + <skip /> <string name="lock_to_app_start" msgid="6643342070839862795">"Экран кадалды"</string> <string name="lock_to_app_exit" msgid="8598219838213787430">"Экран бошотулду"</string> <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Бошотуудан мурун PIN суралсын"</string> diff --git a/core/res/res/values-lo-rLA/strings.xml b/core/res/res/values-lo-rLA/strings.xml index 80025e6488bd..70d8c6579285 100644 --- a/core/res/res/values-lo-rLA/strings.xml +++ b/core/res/res/values-lo-rLA/strings.xml @@ -796,6 +796,8 @@ <string name="permdesc_accessNotifications" msgid="458457742683431387">"ອະນຸຍາດໃຫ້ແອັບຯດຶງຂໍ້ມູນ, ກວດສອບ ແລະລຶບລ້າງການແຈ້ງເຕືອນ ຮວມທັງພວກທີ່ໂພສໂດຍແອັບຯອື່ນໆນຳ."</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"ເຊື່ອມໂຍງກັບບໍລິການໂຕຟັງການແຈ້ງເຕືອນ"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"ອະນຸຍາດໃຫ້ເຈົ້າຂອງເຊື່ອມໂຍງສ່ວນຕິດຕໍ່ລະດັບເທິງສຸດ ຂອງຜູ່ຟັງບໍລິການການແຈ້ງເຕືອນ. ບໍ່ຈຳເປັນສຳລັບແອັບຯທົ່ວໄປ."</string> + <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"ຜູກພັນກັບເປົ້າໝາຍການບໍລິການຜູ້ເລືອກ"</string> + <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"ອະນຸຍາດໃຫ້ຜູ້ຖືຜູກພັນກັບຕົວປະສານລະດັບສູງສຸດຂອງການບໍລິການເປົ້າໝາຍຜູ້ເລືອກ. ບໍ່ຈຳເປັນສຳລັບແອັບຯທົ່ວໄປ."</string> <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"ເຊື່ອມໂຍງກັບບໍລິການຜູ່ສະໜອງເງື່ອນໄຂ"</string> <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"ອະນຸຍາດໃຫ້ເຈົ້າຂອງເຊື່ອມໂຍງສ່ວນຕິດຕໍ່ລະດັບສູງສຸດຂອງບໍລິການສະໜອງເງື່ອນໄຂ. ບໍ່ຈຳເປັນສຳລັບແອັບຯທົ່ວໄປ."</string> <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"ເຊື່ອມໂຍງກັບບໍລິການເສັ້ນທາງມີເດຍ"</string> @@ -1263,6 +1265,14 @@ <string name="old_app_description" msgid="2082094275580358049">"ຫ້າມເປີດແອັບຯໃໝ່."</string> <string name="new_app_action" msgid="5472756926945440706">"ເລີ່ມຕົ້ນ <xliff:g id="OLD_APP">%1$s</xliff:g>"</string> <string name="new_app_description" msgid="1932143598371537340">"ຢຸດແອັບຯເກົ່າໂດຍບໍ່ຕ້ອງບັນທຶກ."</string> + <!-- no translation found for dump_heap_notification (2618183274836056542) --> + <skip /> + <!-- no translation found for dump_heap_notification_detail (2075673362317481664) --> + <skip /> + <!-- no translation found for dump_heap_title (5864292264307651673) --> + <skip /> + <!-- no translation found for dump_heap_text (4809417337240334941) --> + <skip /> <string name="sendText" msgid="5209874571959469142">"ເລືອກການເຮັດວຽກຂອງຂໍ້ຄວາມ"</string> <string name="volume_ringtone" msgid="6885421406845734650">"ລະດັບສຽງເອີ້ນເຂົ້າ"</string> <string name="volume_music" msgid="5421651157138628171">"ລະດັບສຽງຂອງສື່"</string> @@ -1776,7 +1786,9 @@ <item quantity="one">ລອງໃໝ່ໃນອີກ 1 ວິນາທີ</item> </plurals> <string name="restr_pin_try_later" msgid="973144472490532377">"ລອງໃໝ່ອີກຄັ້ງໃນພາຍຫລັງ."</string> - <string name="immersive_mode_confirmation" msgid="7227416894979047467">"ປັດລົງມາຈາກທາງເທິງເພື່ອອອກຈາກໂໝດເຕັມໜ້າຈໍ."</string> + <string name="immersive_cling_title" msgid="8394201622932303336">"ການເບິ່ງເຕັມໜ້າຈໍ"</string> + <string name="immersive_cling_description" msgid="3482371193207536040">"ເພື່ອອອກ, ຮູດລົງລຸ່ມຈາກດ້ານເທິງ."</string> + <string name="immersive_cling_positive" msgid="5016839404568297683">"ໄດ້ແລ້ວ"</string> <string name="done_label" msgid="2093726099505892398">"ແລ້ວໆ"</string> <string name="hour_picker_description" msgid="6698199186859736512">"ໂຕໝຸນປັບຊົ່ວໂມງ"</string> <string name="minute_picker_description" msgid="8606010966873791190">"ໂຕໝຸນປັບນາທີ"</string> @@ -1791,7 +1803,8 @@ <string name="managed_profile_label_badge" msgid="2355652472854327647">"ບ່ອນເຮັດວຽກ <xliff:g id="LABEL">%1$s</xliff:g>"</string> <string name="lock_to_app_toast" msgid="7570091317001980053">"ເພື່ອຖອດການປັກໝຸດໜ້າຈໍນີ້, ສຳຜັດປຸ່ມ ກັບຄືນ ແລະ ພາບຮວມ ຄ້າງໄວ້ພ້ອມກັນ."</string> <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"ເພື່ອຖອດການປັກໝຸດໜ້າຈໍນີ້, ສຳຜັດປຸ່ມ ພາບຮວມ ຄ້າງໄວ້."</string> - <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"ໜ້າຈໍຖືກປັກໝຸດໄວ້. ອົງກອນຂອງທ່ານບໍ່ອະນຸຍາດໃຫ້ຍົກເລີກການປັກໝຸດໄດ້."</string> + <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) --> + <skip /> <string name="lock_to_app_start" msgid="6643342070839862795">"ປັກໝຸດໜ້າຈໍແລ້ວ"</string> <string name="lock_to_app_exit" msgid="8598219838213787430">"ຍົກເລີກການປັກໝຸນຫນ້າຈໍແລ້ວ"</string> <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"ຖາມຫາ PIN ກ່ອນຍົກເລີກການປັກໝຸດ"</string> diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml index d1c2f9ae0efb..6eda58a9d602 100644 --- a/core/res/res/values-lt/strings.xml +++ b/core/res/res/values-lt/strings.xml @@ -798,6 +798,8 @@ <string name="permdesc_accessNotifications" msgid="458457742683431387">"Programai leidžiama gauti, patikrinti ir išvalyti pranešimus, įskaitant pranešimus, kuriuos paskelbė kitos programos."</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"susisaistyti su pranešimų skaitymo priemonės paslauga"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Leidžiama turėtojui susisaistyti su pranešimų skaitymo priemonės paslaugos aukščiausio lygio sąsaja. Įprastoms programoms to neturėtų prireikti."</string> + <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"susaistyti programą su tikslo pasirinkimo paslauga"</string> + <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Savininkui leidžiama susaistyti programą su tikslo pasirinkimo paslaugos aukščiausio lygio sąsaja. Įprastoms programoms to neturėtų prireikti."</string> <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"susaistyti su sąlygos teikėjo paslauga"</string> <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Turėtojui leidžiama susaistyti programą su sąlygos teikėjo paslaugos aukščiausio lygio sąsaja. Įprastoms programoms to niekada neturėtų prireikti."</string> <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"susaistyti su medijos maršruto paslauga"</string> @@ -1273,6 +1275,14 @@ <string name="old_app_description" msgid="2082094275580358049">"Nepaleiskite naujos programos."</string> <string name="new_app_action" msgid="5472756926945440706">"Paleisti „<xliff:g id="OLD_APP">%1$s</xliff:g>“"</string> <string name="new_app_description" msgid="1932143598371537340">"Sustabdyti seną programą jos neišsaugant."</string> + <!-- no translation found for dump_heap_notification (2618183274836056542) --> + <skip /> + <!-- no translation found for dump_heap_notification_detail (2075673362317481664) --> + <skip /> + <!-- no translation found for dump_heap_title (5864292264307651673) --> + <skip /> + <!-- no translation found for dump_heap_text (4809417337240334941) --> + <skip /> <string name="sendText" msgid="5209874571959469142">"Pasirinkite teksto veiksmą"</string> <string name="volume_ringtone" msgid="6885421406845734650">"Skambučio garsumas"</string> <string name="volume_music" msgid="5421651157138628171">"Medijos garsumas"</string> @@ -1794,7 +1804,9 @@ <item quantity="other">Bandykite dar kartą po <xliff:g id="COUNT">%d</xliff:g> sekundžių</item> </plurals> <string name="restr_pin_try_later" msgid="973144472490532377">"Vėliau bandykite dar kartą"</string> - <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Perbraukite nuo viršaus žemyn, kad išeitumėte iš viso ekrano režimo"</string> + <string name="immersive_cling_title" msgid="8394201622932303336">"Peržiūrima viso ekrano režimu"</string> + <string name="immersive_cling_description" msgid="3482371193207536040">"Jei norite išeiti, perbraukite žemyn iš viršaus."</string> + <string name="immersive_cling_positive" msgid="5016839404568297683">"Supratau"</string> <string name="done_label" msgid="2093726099505892398">"Atlikta"</string> <string name="hour_picker_description" msgid="6698199186859736512">"Apskritas valandų slankiklis"</string> <string name="minute_picker_description" msgid="8606010966873791190">"Apskritas minučių slankiklis"</string> @@ -1809,7 +1821,8 @@ <string name="managed_profile_label_badge" msgid="2355652472854327647">"Darbo <xliff:g id="LABEL">%1$s</xliff:g>"</string> <string name="lock_to_app_toast" msgid="7570091317001980053">"Jei norite atsegti šį ekraną, vienu metu palieskite ir palaikykite „Atgal“ ir „Apžvalga“."</string> <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Jei norite atsegti šį ekraną, palieskite ir palaikykite „Apžvalga“."</string> - <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Ekranas yra prisegtas. Jūsų organizacija neleidžia jo atsegti."</string> + <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) --> + <skip /> <string name="lock_to_app_start" msgid="6643342070839862795">"Ekrano prisegtas"</string> <string name="lock_to_app_exit" msgid="8598219838213787430">"Ekranas atsegtas"</string> <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Prašyti PIN kodo prieš atsegant"</string> diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml index 1f48ecfd7a03..6360a42d39f2 100644 --- a/core/res/res/values-lv/strings.xml +++ b/core/res/res/values-lv/strings.xml @@ -797,6 +797,8 @@ <string name="permdesc_accessNotifications" msgid="458457742683431387">"Ļauj lietotnei izgūt, pārbaudīt un dzēst paziņojumus, tostarp lietotņu publicētos paziņojumus."</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"saites izveidošana ar paziņojumu uztvērēja pakalpojumu"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Ļauj īpašniekam izveidot saiti ar paziņojumu uztvērēja pakalpojuma augšējā līmeņa saskarni. Parastajām lietotnēm tas nekad nav nepieciešams."</string> + <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"izveidot savienojumu ar atlasītāja mērķa pakalpojumu"</string> + <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Ļauj atļaujas īpašniekam izveidot savienojumu ar atlasītāja mērķa pakalpojuma augstākā līmeņa saskarni. Parastām lietotnēm tas nekad nav nepieciešams."</string> <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"Saistīšana ar nosacījumu sniedzēja pakalpojumu"</string> <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Ļauj īpašniekam izveidot savienojumu ar drukas nosacījumu sniedzēja pakalpojuma augšējā līmeņa saskarni. Parastajām lietotnēm tas nekad nav nepieciešams."</string> <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"Saistīšana ar multivides datu maršrutēšanas pakalpojumu"</string> @@ -1268,6 +1270,14 @@ <string name="old_app_description" msgid="2082094275580358049">"Nestartējiet jauno lietotni."</string> <string name="new_app_action" msgid="5472756926945440706">"Startēt: <xliff:g id="OLD_APP">%1$s</xliff:g>"</string> <string name="new_app_description" msgid="1932143598371537340">"Aptur vecās lietotnes darbību, neko nesaglabājot."</string> + <!-- no translation found for dump_heap_notification (2618183274836056542) --> + <skip /> + <!-- no translation found for dump_heap_notification_detail (2075673362317481664) --> + <skip /> + <!-- no translation found for dump_heap_title (5864292264307651673) --> + <skip /> + <!-- no translation found for dump_heap_text (4809417337240334941) --> + <skip /> <string name="sendText" msgid="5209874571959469142">"Izvēlieties darbību tekstam"</string> <string name="volume_ringtone" msgid="6885421406845734650">"Zvanītāja skaļums"</string> <string name="volume_music" msgid="5421651157138628171">"Multivides skaļums"</string> @@ -1785,7 +1795,9 @@ <item quantity="other">Mēģiniet vēlreiz pēc <xliff:g id="COUNT">%d</xliff:g> sekundēm</item> </plurals> <string name="restr_pin_try_later" msgid="973144472490532377">"Vēlāk mēģiniet vēlreiz."</string> - <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Lai izietu no pilnekrāna režīma, velciet no augšas uz leju."</string> + <string name="immersive_cling_title" msgid="8394201622932303336">"Skatīšanās pilnekrāna režīmā"</string> + <string name="immersive_cling_description" msgid="3482371193207536040">"Lai izietu, no augšdaļas velciet lejup."</string> + <string name="immersive_cling_positive" msgid="5016839404568297683">"Labi"</string> <string name="done_label" msgid="2093726099505892398">"Gatavs"</string> <string name="hour_picker_description" msgid="6698199186859736512">"Stundu apļveida slīdnis"</string> <string name="minute_picker_description" msgid="8606010966873791190">"Minūšu apļveida slīdnis"</string> @@ -1800,7 +1812,8 @@ <string name="managed_profile_label_badge" msgid="2355652472854327647">"Darbā: <xliff:g id="LABEL">%1$s</xliff:g>"</string> <string name="lock_to_app_toast" msgid="7570091317001980053">"Lai atspraustu šo ekrānu, vienlaicīgi pieskarieties pogām “Atpakaļ” un “Pārskats” un turiet tās."</string> <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Lai atspraustu šo ekrānu, pieskarieties pogai “Pārskats” un turiet to."</string> - <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Ekrāns ir piesprausts. Jūsu organizācija nav atļāvusi atspraušanu."</string> + <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) --> + <skip /> <string name="lock_to_app_start" msgid="6643342070839862795">"Ekrāns ir piesprausts"</string> <string name="lock_to_app_exit" msgid="8598219838213787430">"Ekrāns ir atsprausts"</string> <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Pirms atspraušanas pieprasīt PIN"</string> diff --git a/core/res/res/values-mk-rMK/strings.xml b/core/res/res/values-mk-rMK/strings.xml index 4ee7a81f6692..86e31e547e54 100644 --- a/core/res/res/values-mk-rMK/strings.xml +++ b/core/res/res/values-mk-rMK/strings.xml @@ -796,6 +796,8 @@ <string name="permdesc_accessNotifications" msgid="458457742683431387">"Овозможува апликацијата да враќа, проверува и брише известувања, вклучувајќи ги и оние објавени од други апликации."</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"поврзи се со услугата слушател на известувања"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Овозможува сопственикот да се поврзе со интерфејс од највисоко ниво на услугата слушател на известувања. Не треба да се користи за стандардни апликации."</string> + <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"сврзи се со услугата избирач на цел"</string> + <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Дозволува сопственикот да се сврзе со интерфејс од највисоко ниво на услугата избирач на цел. Не треба да се користи за стандардни апликации."</string> <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"поврзување со услуга за давател на услов"</string> <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Дозволува сопственикот да се поврзе со интерфејс од највисоко ниво на давател на услуги за услов. Не треба да се користи за стандардни апликации."</string> <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"врзува со услуга за насочување медиуми"</string> @@ -1263,6 +1265,14 @@ <string name="old_app_description" msgid="2082094275580358049">"Не стартувајте ја новата апликација."</string> <string name="new_app_action" msgid="5472756926945440706">"Вклучи <xliff:g id="OLD_APP">%1$s</xliff:g>"</string> <string name="new_app_description" msgid="1932143598371537340">"Запрете ја старата апликација без зачувување."</string> + <!-- no translation found for dump_heap_notification (2618183274836056542) --> + <skip /> + <!-- no translation found for dump_heap_notification_detail (2075673362317481664) --> + <skip /> + <!-- no translation found for dump_heap_title (5864292264307651673) --> + <skip /> + <!-- no translation found for dump_heap_text (4809417337240334941) --> + <skip /> <string name="sendText" msgid="5209874571959469142">"Избери дејство за текст"</string> <string name="volume_ringtone" msgid="6885421406845734650">"Јачина на звук на ѕвонче"</string> <string name="volume_music" msgid="5421651157138628171">"Јачина на звук на медиуми"</string> @@ -1778,7 +1788,9 @@ <item quantity="other">Обидете се повторно по <xliff:g id="COUNT">%d</xliff:g> секунди</item> </plurals> <string name="restr_pin_try_later" msgid="973144472490532377">"Обиди се повторно подоцна"</string> - <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Помини со прстот одозгора надолу да излезе од режим на цел екран."</string> + <string name="immersive_cling_title" msgid="8394201622932303336">"Се прикажува на цел екран"</string> + <string name="immersive_cling_description" msgid="3482371193207536040">"За да излезете, повлечете одозгора надолу."</string> + <string name="immersive_cling_positive" msgid="5016839404568297683">"Разбрав"</string> <string name="done_label" msgid="2093726099505892398">"Готово"</string> <string name="hour_picker_description" msgid="6698199186859736512">"Приказ на часови во кружно движење"</string> <string name="minute_picker_description" msgid="8606010966873791190">"Приказ на минути во кружно движење"</string> @@ -1793,7 +1805,8 @@ <string name="managed_profile_label_badge" msgid="2355652472854327647">"Работа <xliff:g id="LABEL">%1$s</xliff:g>"</string> <string name="lock_to_app_toast" msgid="7570091317001980053">"За да го откачите екранот, допрете и задржете Назад и Краток преглед во исто време."</string> <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"За да го откачите екранот, допрете и задржете Краток преглед."</string> - <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Екранот е закачен. Откачување не е дозволено од вашата организација."</string> + <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) --> + <skip /> <string name="lock_to_app_start" msgid="6643342070839862795">"Екранот е закачен"</string> <string name="lock_to_app_exit" msgid="8598219838213787430">"Екранот е откачен"</string> <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Прашај за ПИН пред откачување"</string> diff --git a/core/res/res/values-ml-rIN/strings.xml b/core/res/res/values-ml-rIN/strings.xml index db538cd80fc7..959d0a747860 100644 --- a/core/res/res/values-ml-rIN/strings.xml +++ b/core/res/res/values-ml-rIN/strings.xml @@ -738,9 +738,9 @@ <string name="permdesc_nfc" msgid="7120611819401789907">"നിയർ ഫീൽഡ് കമ്മ്യൂണിക്കേഷൻ (NFC) ടാഗുകളുമായും കാർഡുകളുമായും റീഡറുകളുമായുള്ള ആശയവിനിമയത്തിന് അപ്ലിക്കേഷനുകളെ അനുവദിക്കുന്നു."</string> <string name="permlab_disableKeyguard" msgid="3598496301486439258">"നിങ്ങളുടെ സ്ക്രീൻ ലോക്ക് പ്രവർത്തനരഹിതമാക്കുക"</string> <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"കീലോക്കും ഏതെങ്കിലും അനുബന്ധ പാസ്വേഡ് സുരക്ഷയും പ്രവർത്തനരഹിതമാക്കാൻ അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു. ഉദാഹരണത്തിന്, ഒരു ഇൻകമിംഗ് കോൾ സ്വീകരിക്കുമ്പോൾ ഫോൺ കീലോക്ക് പ്രവർത്തനരഹിതമാക്കുന്നു, കോൾ അവസാനിക്കുമ്പോൾ കീലോക്ക് വീണ്ടും പ്രവർത്തനക്ഷമമാകുന്നു."</string> - <string name="permlab_manageFingerprint" msgid="5640858826254575638">"വിരലടയാള ഹാർഡ്വെയർ നിയന്ത്രിക്കുക"</string> + <string name="permlab_manageFingerprint" msgid="5640858826254575638">"ഫിംഗർപ്രിന്റ് ഹാർഡ്വെയർ നിയന്ത്രിക്കുക"</string> <string name="permdesc_manageFingerprint" msgid="178208705828055464">"ഉപയോഗിക്കാനായി വിരലടയാള ടെംപ്ലേറ്റുകൾ ചേർക്കാനും ഇല്ലാതാക്കാനുമുള്ള രീതികൾ അഭ്യർത്ഥിക്കാൻ അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു."</string> - <string name="permlab_useFingerprint" msgid="3150478619915124905">"വിരലടയാള ഹാർഡ്വെയർ ഉപയോഗിക്കുക"</string> + <string name="permlab_useFingerprint" msgid="3150478619915124905">"ഫിംഗർപ്രിന്റ് ഹാർഡ്വെയർ ഉപയോഗിക്കുക"</string> <string name="permdesc_useFingerprint" msgid="9165097460730684114">"പ്രാമാണീകരണത്തിനായി വിരലടയാളം ഉപയോഗിക്കാൻ അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു"</string> <string name="permlab_readSyncSettings" msgid="6201810008230503052">"സമന്വയ ക്രമീകരണങ്ങൾ റീഡുചെയ്യുക"</string> <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"ഒരു അക്കൗണ്ടിനായി സമന്വയ ക്രമീകരണങ്ങൾ റീഡുചെയ്യാൻ അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു. ഉദാഹരണത്തിന്, ആളുകൾ അപ്ലിക്കേഷൻ ഒരു അക്കൗണ്ടിൽ സമന്വയിപ്പിച്ചിട്ടുണ്ടോയെന്നത് നിർണ്ണയിക്കാൻ ഇതിനാകും."</string> @@ -796,6 +796,8 @@ <string name="permdesc_accessNotifications" msgid="458457742683431387">"മറ്റ് അപ്ലിക്കേഷനുകൾ പോസ്റ്റുചെയ്തവയുൾപ്പെടെയുള്ള, അറിയിപ്പുകൾ വീണ്ടെടുക്കാനും പരിശോധിക്കാനും മായ്ക്കാനും അപ്ലിക്കേഷനുകളെ അനുവദിക്കുന്നു."</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"ഒരു അറിയിപ്പ് ലിസണർ സേവനവുമായി ബന്ധിപ്പിക്കുക"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"ഒരു അറിയിപ്പ് ലിസണർ സേവനത്തിന്റെ ഉയർന്ന നിലയിലുള്ള ഇന്റർഫേസിലേക്ക് ബന്ധിപ്പിക്കാൻ ഹോൾഡറിനെ അനുവദിക്കുന്നു. സാധാരണ അപ്ലിക്കേഷനുകൾക്ക് ഒരിക്കലും ആവശ്യമില്ല."</string> + <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"ഒരു ചൂസർ ടാർഗെറ്റ് സേവനത്തിലേക്ക് ബന്ധിപ്പിക്കുക"</string> + <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"ഒരു ചൂസർ ടാർഗെറ്റ് സേവനത്തിന്റെ ഉയർന്ന ലെവൽ ഇന്റർഫേസിലേക്ക് ബന്ധിപ്പിക്കാൻ ഉടമയെ അനുവദിക്കുന്നു. സാധാരണ അപ്ലിക്കേഷനുകൾക്ക് ഒരിക്കലും ആവശ്യമില്ല."</string> <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"കണ്ടീഷൻ പ്രൊവൈഡർ സേവനവുമായി ബന്ധിപ്പിക്കുക"</string> <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"ഒരു കണ്ടീഷൻ പ്രൊവൈഡർ സേവനത്തിന്റെ ഉയർന്ന നിലയിലുള്ള ഇന്റർഫേസിലേക്ക് ബന്ധിപ്പിക്കാൻ ഹോൾഡറിനെ അനുവദിക്കുന്നു. സാധാരണ അപ്ലിക്കേഷനുകൾക്ക് ഒരിക്കലും ആവശ്യമില്ല."</string> <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"മീഡിയ റൂട്ട് സേവനവുമായി ബന്ധിപ്പിക്കുക"</string> @@ -1263,6 +1265,14 @@ <string name="old_app_description" msgid="2082094275580358049">"പുതിയ അപ്ലിക്കേഷൻ ആരംഭിക്കരുത്."</string> <string name="new_app_action" msgid="5472756926945440706">"<xliff:g id="OLD_APP">%1$s</xliff:g> ആരംഭിക്കുക"</string> <string name="new_app_description" msgid="1932143598371537340">"സംരക്ഷിക്കാതെ തന്നെ പഴയ അപ്ലിക്കേഷൻ നിർത്തുക."</string> + <!-- no translation found for dump_heap_notification (2618183274836056542) --> + <skip /> + <!-- no translation found for dump_heap_notification_detail (2075673362317481664) --> + <skip /> + <!-- no translation found for dump_heap_title (5864292264307651673) --> + <skip /> + <!-- no translation found for dump_heap_text (4809417337240334941) --> + <skip /> <string name="sendText" msgid="5209874571959469142">"വാചകസന്ദേശത്തിനായി ഒരു പ്രവർത്തനം തിരഞ്ഞെടുക്കുക"</string> <string name="volume_ringtone" msgid="6885421406845734650">"റിംഗർ വോളിയം"</string> <string name="volume_music" msgid="5421651157138628171">"മീഡിയ വോളിയം"</string> @@ -1776,7 +1786,9 @@ <item quantity="one">ഒരു സെക്കൻഡിനുള്ളിൽ വീണ്ടും ശ്രമിക്കുക</item> </plurals> <string name="restr_pin_try_later" msgid="973144472490532377">"പിന്നീട് വീണ്ടും ശ്രമിക്കുക"</string> - <string name="immersive_mode_confirmation" msgid="7227416894979047467">"പൂർണ്ണസ്ക്രീനിൽനിന്നും പുറത്തുകടക്കുന്നതിന് മുകളിൽ നിന്നും താഴേക്ക് സ്വൈപ്പുചെയ്യുക."</string> + <string name="immersive_cling_title" msgid="8394201622932303336">"പൂർണ്ണ സ്ക്രീനിൽ കാണുന്നു"</string> + <string name="immersive_cling_description" msgid="3482371193207536040">"അവസാനിപ്പിക്കാൻ, മുകളിൽ നിന്ന് താഴോട്ട് സ്വൈപ്പുചെയ്യുക."</string> + <string name="immersive_cling_positive" msgid="5016839404568297683">"മനസ്സിലായി"</string> <string name="done_label" msgid="2093726099505892398">"പൂർത്തിയാക്കി"</string> <string name="hour_picker_description" msgid="6698199186859736512">"ചാക്രികമായി മണിക്കൂറുകൾ ദൃശ്യമാകുന്ന സ്ലൈഡർ"</string> <string name="minute_picker_description" msgid="8606010966873791190">"ചാക്രികമായി മിനിറ്റുകൾ ദൃശ്യമാകുന്ന സ്ലൈഡർ"</string> @@ -1791,7 +1803,8 @@ <string name="managed_profile_label_badge" msgid="2355652472854327647">"ഔദ്യോഗികം <xliff:g id="LABEL">%1$s</xliff:g>"</string> <string name="lock_to_app_toast" msgid="7570091317001980053">"ഈ സ്ക്രീൻ അൺപിൻ ചെയ്യാൻ \'മടങ്ങുക\', \'കാഴ്ച\' എന്നിവ ഒരേ സമയം സ്പർശിച്ച് പിടിക്കുക."</string> <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"ഈ സ്ക്രീൻ അൺപിൻ ചെയ്യാൻ, കാഴ്ച സ്പർശിച്ച് പിടിക്കുക."</string> - <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"സ്ക്രീൻ പിൻ ചെയ്തിരിക്കുന്നു. നിങ്ങളുടെ ഓർഗനൈസേഷൻ അൺപിൻ ചെയ്യൽ അനുവദിക്കുന്നില്ല."</string> + <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) --> + <skip /> <string name="lock_to_app_start" msgid="6643342070839862795">"സ്ക്രീൻ പിൻ ചെയ്തു"</string> <string name="lock_to_app_exit" msgid="8598219838213787430">"സ്ക്രീൻ അൺപിൻ ചെയ്തു"</string> <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"അൺപിൻ ചെയ്യുന്നതിനുമുമ്പ് പിൻ ആവശ്യപ്പെടുക"</string> diff --git a/core/res/res/values-mn-rMN/strings.xml b/core/res/res/values-mn-rMN/strings.xml index 9839ff112bbc..ba53123bbe2c 100644 --- a/core/res/res/values-mn-rMN/strings.xml +++ b/core/res/res/values-mn-rMN/strings.xml @@ -796,6 +796,8 @@ <string name="permdesc_accessNotifications" msgid="458457742683431387">"Апп нь бусад апп-уудын илгээсэн мэдэгдлүүдийг дуудах, шалгах, болон цэвэрлэх боломжтой."</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"мэдэгдэл сонсогч үйлчилгээтэй холбох"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Эзэмшигч нь мэдэгдэл сонсох үйлчилгээний дээд-төвшиний интерфейстэй холбох боломжтой. Энгийн апп-д шаардлагагүй."</string> + <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"Сонгогчийн зорилтот үйлчилгээнд холбогдох"</string> + <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Эзэмшигчид сонгогчийн зорилтот үйлчилгээний дээд түвшний интерфэйс рүү холбогдох боломжийг олгоно. Энэ нь энгийн апп-уудад огт шаардлагагүй."</string> <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"нөхцөл нийлүүлэгч үйлчилгээнд холбох"</string> <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Эзэмшигчид нөхцөл нийлүүлэгч үйлчилгээний дээд-түвшний интерфейстэй холбох боломж олгоно. Энгийн апп-уудад хэзээ ч ашиглагдахгүй."</string> <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"медиа маршрут үйлчилгээтэй холбох"</string> @@ -1263,6 +1265,14 @@ <string name="old_app_description" msgid="2082094275580358049">"Шинэ апп-г эхлүүлж болохгүй."</string> <string name="new_app_action" msgid="5472756926945440706">"<xliff:g id="OLD_APP">%1$s</xliff:g> эхлүүлэх"</string> <string name="new_app_description" msgid="1932143598371537340">"Хуучин апп-г хадгалахгүйгээр зогсооно уу."</string> + <!-- no translation found for dump_heap_notification (2618183274836056542) --> + <skip /> + <!-- no translation found for dump_heap_notification_detail (2075673362317481664) --> + <skip /> + <!-- no translation found for dump_heap_title (5864292264307651673) --> + <skip /> + <!-- no translation found for dump_heap_text (4809417337240334941) --> + <skip /> <string name="sendText" msgid="5209874571959469142">"Текст илгээх үйлдлийг сонгох"</string> <string name="volume_ringtone" msgid="6885421406845734650">"Хонхны аяны хэмжээ"</string> <string name="volume_music" msgid="5421651157138628171">"Медиа дууны хэмжээ"</string> @@ -1776,7 +1786,9 @@ <item quantity="one">1 секундын дараа дахин оролдоно уу</item> </plurals> <string name="restr_pin_try_later" msgid="973144472490532377">"Дараа дахин оролдоно уу"</string> - <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Бүтэн дэлгэцээс гарахын тулд дээрээс нь доош шудрана уу."</string> + <string name="immersive_cling_title" msgid="8394201622932303336">"Бүтэн дэлгэцээр үзэж байна"</string> + <string name="immersive_cling_description" msgid="3482371193207536040">"Гарахаар бол дээрээс нь доош нь чирнэ үү."</string> + <string name="immersive_cling_positive" msgid="5016839404568297683">"Ойлголоо"</string> <string name="done_label" msgid="2093726099505892398">"Дууссан"</string> <string name="hour_picker_description" msgid="6698199186859736512">"Цаг гүйлгэгч"</string> <string name="minute_picker_description" msgid="8606010966873791190">"Минут гүйлгэгч"</string> @@ -1791,7 +1803,8 @@ <string name="managed_profile_label_badge" msgid="2355652472854327647">"Ажлын <xliff:g id="LABEL">%1$s</xliff:g>"</string> <string name="lock_to_app_toast" msgid="7570091317001980053">"Энэ дэлгэцийг цуцлахын тулд Буцах болон Тойм-д зэрэг хүрч барина."</string> <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Энэ дэлгэцийг цуцлахын тулд Тойм харагдацанд хүрч барина."</string> - <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Дэлгэцийг тогтоосон. Дэлгэц суллахыг таны байгууллага зөвшөөрөөгүй."</string> + <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) --> + <skip /> <string name="lock_to_app_start" msgid="6643342070839862795">"Дэлгэцийг тогтоосон"</string> <string name="lock_to_app_exit" msgid="8598219838213787430">"Дэлгэцийг сулласан"</string> <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Тогтоосныг суллахаас өмнө PIN асуух"</string> diff --git a/core/res/res/values-mr-rIN/strings.xml b/core/res/res/values-mr-rIN/strings.xml index 493ae99ffb34..884687ed95f6 100644 --- a/core/res/res/values-mr-rIN/strings.xml +++ b/core/res/res/values-mr-rIN/strings.xml @@ -796,6 +796,8 @@ <string name="permdesc_accessNotifications" msgid="458457742683431387">"अनुप्रयोगाला इतर अॅप्सद्वारे पोस्ट केलेल्यांसह पुनर्प्राप्त करण्याची, तपासण्याची आणि सूचना साफ करण्याची अनुमती देते."</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"सूचना ऐकणार्या सेवेशी प्रतिबद्ध"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"होल्डरला सूचना ऐकणार्या सेवेच्या शीर्ष-दर्जाच्या इंटरफेसशी प्रतिबद्ध करण्याची अनुमती देते. सामान्य अॅप्ससाठी कधीही आवश्यक नसावे."</string> + <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"एका निवडकर्ता लक्ष्य सेवेसाठी प्रतिबद्ध करा"</string> + <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"धारकास निवडकर्ता लक्ष्य सेवेच्या शीर्ष-स्तराच्या इंटरफेसशी प्रतिबद्ध करण्यास अनुमती देते. सामान्य अॅप्सकरिता कधीही आवश्यक नसते."</string> <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"एका अट प्रदाता सेवेवर प्रतिबद्ध करा"</string> <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"स्थिती प्रदाता सेवेचा शीर्ष-स्तर इंटरफेस प्रतिबद्ध करण्यासाठी होल्डरला अनुमती देते. सामान्य अॅप्सकरिता कधीही आवश्यक नसते."</string> <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"मीडिया मार्ग सेवेशी प्रतिबद्ध व्हा"</string> @@ -1263,6 +1265,14 @@ <string name="old_app_description" msgid="2082094275580358049">"नवीन अॅप प्रारंभ करू नका."</string> <string name="new_app_action" msgid="5472756926945440706">"<xliff:g id="OLD_APP">%1$s</xliff:g> प्रारंभ करा"</string> <string name="new_app_description" msgid="1932143598371537340">"जतन न करता जुना अॅप थांबवा."</string> + <!-- no translation found for dump_heap_notification (2618183274836056542) --> + <skip /> + <!-- no translation found for dump_heap_notification_detail (2075673362317481664) --> + <skip /> + <!-- no translation found for dump_heap_title (5864292264307651673) --> + <skip /> + <!-- no translation found for dump_heap_text (4809417337240334941) --> + <skip /> <string name="sendText" msgid="5209874571959469142">"मजकुरासाठी क्रिया निवडा"</string> <string name="volume_ringtone" msgid="6885421406845734650">"रिंगर व्हॉल्यूम"</string> <string name="volume_music" msgid="5421651157138628171">"मीडिया व्हॉल्यूम"</string> @@ -1776,7 +1786,9 @@ <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> सेकंदांमध्ये पुन्हा प्रयत्न करा</item> </plurals> <string name="restr_pin_try_later" msgid="973144472490532377">"नंतर पुन्हा प्रयत्न करा"</string> - <string name="immersive_mode_confirmation" msgid="7227416894979047467">"पूर्ण स्क्रीनमधून निर्गमन करण्यासाठी शीर्षावरून खाली स्वाइप करा."</string> + <string name="immersive_cling_title" msgid="8394201622932303336">"पूर्ण स्क्रीन पाहत आहे"</string> + <string name="immersive_cling_description" msgid="3482371193207536040">"बाहेर पडण्यासाठी, वरून खाली स्वाइप करा."</string> + <string name="immersive_cling_positive" msgid="5016839404568297683">"समजले"</string> <string name="done_label" msgid="2093726099505892398">"पूर्ण झाले"</string> <string name="hour_picker_description" msgid="6698199186859736512">"तास परिपत्रक स्लायडर"</string> <string name="minute_picker_description" msgid="8606010966873791190">"मिनिटे परिपत्रक स्लायडर"</string> @@ -1791,7 +1803,8 @@ <string name="managed_profile_label_badge" msgid="2355652472854327647">"कार्य <xliff:g id="LABEL">%1$s</xliff:g>"</string> <string name="lock_to_app_toast" msgid="7570091317001980053">"ही स्क्रीन अनपिन करण्यासाठी, एकाच वेळी परत आणि विहंगावलोकनास स्पर्श करा आणि धरून ठेवा."</string> <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"ही स्क्रीन अनपिन करण्यासाठी, विहंगावलोकनास स्पर्श करा आणि धरून ठेवा."</string> - <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"स्क्रीन पिन केली आहे. आपल्या संस्थेद्वारे अनपिन करण्यास अनुमती नाही."</string> + <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) --> + <skip /> <string name="lock_to_app_start" msgid="6643342070839862795">"स्क्रीन पिन केली"</string> <string name="lock_to_app_exit" msgid="8598219838213787430">"स्क्रीन अनपिन केली"</string> <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"अनपिन करण्यापूर्वी पिन साठी विचारा"</string> diff --git a/core/res/res/values-ms-rMY/strings.xml b/core/res/res/values-ms-rMY/strings.xml index b512d96702f2..255d2e86d10b 100644 --- a/core/res/res/values-ms-rMY/strings.xml +++ b/core/res/res/values-ms-rMY/strings.xml @@ -796,6 +796,8 @@ <string name="permdesc_accessNotifications" msgid="458457742683431387">"Membenarkan apl untuk mendapatkan semula, memeriksa dan memadam bersih pemberitahuan, termasuk yang disiarkan oleh apl lain."</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"ikat kepada perkhidmatan pendengar pemberitahuan"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Membenarkan pemegang terikat dengan antara muka peringkat tertinggi bagi perkhidmatan pendengar pemberitahuan. Tidak sekali-kali diperlukan untuk apl biasa."</string> + <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"terikat kepada perkhidmatan sasaran pemilih"</string> + <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Membenarkan pemegang terikat dengan antara muka peringkat tertinggi bagi perkhidmatan sasaran pemilih. Tidak sekali-kali diperlukan untuk apl biasa."</string> <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"terikat kepada perkhidmatan pembekal keadaan"</string> <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Membenarkan pemegang terikat dengan antara muka peringkat tertinggi bagi perkhidmatan pembekal keadaan. Tidak sekali-kali diperlukan untuk apl biasa."</string> <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"terikat kepada perkhidmatan laluan media"</string> @@ -1263,6 +1265,14 @@ <string name="old_app_description" msgid="2082094275580358049">"Jangan mulakan apl baharu."</string> <string name="new_app_action" msgid="5472756926945440706">"Mulakan <xliff:g id="OLD_APP">%1$s</xliff:g>"</string> <string name="new_app_description" msgid="1932143598371537340">"Hentikan apl lama tanpa menyimpan."</string> + <!-- no translation found for dump_heap_notification (2618183274836056542) --> + <skip /> + <!-- no translation found for dump_heap_notification_detail (2075673362317481664) --> + <skip /> + <!-- no translation found for dump_heap_title (5864292264307651673) --> + <skip /> + <!-- no translation found for dump_heap_text (4809417337240334941) --> + <skip /> <string name="sendText" msgid="5209874571959469142">"Pilih tindakan untuk teks"</string> <string name="volume_ringtone" msgid="6885421406845734650">"Kelantangan pendering"</string> <string name="volume_music" msgid="5421651157138628171">"Kelantangan media"</string> @@ -1776,7 +1786,9 @@ <item quantity="one">Cuba lagi dalam masa 1 saat</item> </plurals> <string name="restr_pin_try_later" msgid="973144472490532377">"Cuba sebentar lagi"</string> - <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Leret ke bawah dari atas untuk keluar dari skrin penuh."</string> + <string name="immersive_cling_title" msgid="8394201622932303336">"Melihat skrin penuh"</string> + <string name="immersive_cling_description" msgid="3482371193207536040">"Untuk keluar, leret dari atas ke bawah."</string> + <string name="immersive_cling_positive" msgid="5016839404568297683">"Faham"</string> <string name="done_label" msgid="2093726099505892398">"Selesai"</string> <string name="hour_picker_description" msgid="6698199186859736512">"Penggelangsar bulatan jam"</string> <string name="minute_picker_description" msgid="8606010966873791190">"Penggelangsar bulatan minit"</string> @@ -1791,7 +1803,8 @@ <string name="managed_profile_label_badge" msgid="2355652472854327647">"Kerja <xliff:g id="LABEL">%1$s</xliff:g>"</string> <string name="lock_to_app_toast" msgid="7570091317001980053">"Untuk menyahsemat skrin ini, sentuh dan tahan Kembali serta Ikhtisar pada masa yang sama."</string> <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Untuk menyahsemat skrin ini, sentuh dan tahan Ikhtisar."</string> - <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Skrin disemat. Menyahsemat tidak dibenarkan oleh organisasi anda."</string> + <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) --> + <skip /> <string name="lock_to_app_start" msgid="6643342070839862795">"Skrin disemat"</string> <string name="lock_to_app_exit" msgid="8598219838213787430">"Skrin dinyahsemat"</string> <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Minta PIN sebelum menyahsemat"</string> diff --git a/core/res/res/values-my-rMM/strings.xml b/core/res/res/values-my-rMM/strings.xml index 7ed089cd7f99..bf4e321246b2 100644 --- a/core/res/res/values-my-rMM/strings.xml +++ b/core/res/res/values-my-rMM/strings.xml @@ -796,6 +796,8 @@ <string name="permdesc_accessNotifications" msgid="458457742683431387">"အပလီကေးရှင်းကို အကြောင်းကြားချက်များအား ထုတ်လုပ်ရန်၊ လေ့လာရန်၊ ဖျက်ပစ်ရန် ခွင့်ပြုခြင်း။ တခြား အပလီကေးရှင်းများမှ သတိပေးချက်များလည်း ပါဝင်ပါသည်"</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"သတိပေးချက် နားထောင်ခြင်း ဆားဗစ် နှင့် ပူးပေါင်းခြင်း"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"ဖုန်းကိုင်ထားသူနှင့် အကြောင်းကြားချက် နားစွင့်သော ဆားဗစ်မှ ထိပ်ပိုင်းအင်တာဖေ့စ် ကို ပူးပေါင်းခွင့်ပေးခြင်း။ ပုံမှန် အပလီကေးရှင်းများမှာ မလိုအပ်ပါ"</string> + <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"ရွေးချယ်သူဦးစားပေး ဝန်ဆောင်မှုနှင့် ပူးပေါင်းခြင်း"</string> + <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"လက်ဝယ်ရှိသူအား ရွေးချယ်သူဦးစားပေး ဝန်ဆောင်မှု၏ ထိပ်သီးအဆင့် အင်တာဖေ့စ်သို့ ချိတ်တွဲခွင့်ပြုပါ။ သာမန် app များ အတွက် မည်သည့်အခါမျှ မလိုအပ်ပါ။"</string> <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"အခြေအနေ စီမံပေးရေး ဝန်ဆောင်မှု တစ်ခုဆီသို့ ချိတ်တွဲခြင်း"</string> <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"စွဲကိုင်ထားသူအား အခြေအနေကို စီမံပေးသူ၏ ထိပ်သီး အဆင့် အင်တာဖေ့စ်သို့ ချိတ်တွဲခွင့်ကို ပေးသည်။ သာမန် appများ အတွက် ဘယ်တော့မှ မလိုအပ်နိုင်ပါ။"</string> <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"မီဒီယာ လမ်းကြောင်း ဝန်ဆောင်မှုသို့ တွဲချည်ရန်"</string> @@ -1263,6 +1265,14 @@ <string name="old_app_description" msgid="2082094275580358049">"pp အသစ်ကို မစတင်ပါနှင့်။"</string> <string name="new_app_action" msgid="5472756926945440706">"<xliff:g id="OLD_APP">%1$s</xliff:g>စတင်ပါ"</string> <string name="new_app_description" msgid="1932143598371537340">"app အဟောင်းကို မသိမ်းဆည်းဘဲ ရပ်လိုက်ပါ။"</string> + <!-- no translation found for dump_heap_notification (2618183274836056542) --> + <skip /> + <!-- no translation found for dump_heap_notification_detail (2075673362317481664) --> + <skip /> + <!-- no translation found for dump_heap_title (5864292264307651673) --> + <skip /> + <!-- no translation found for dump_heap_text (4809417337240334941) --> + <skip /> <string name="sendText" msgid="5209874571959469142">"စာတိုအတွက် လုပ်ဆောင်ချက် ရေးပါ"</string> <string name="volume_ringtone" msgid="6885421406845734650">"ဖုန်းမြည်သံအတိုးအကျယ်"</string> <string name="volume_music" msgid="5421651157138628171">"မီဒီယာအသံအတိုးအကျယ်"</string> @@ -1776,7 +1786,9 @@ <item quantity="one">1 စက္ကန့်အတွင်း ထပ်မံကြိုးစားပါ</item> </plurals> <string name="restr_pin_try_later" msgid="973144472490532377">"နောက်မှ ပြန်ကြိုးစားပါ"</string> - <string name="immersive_mode_confirmation" msgid="7227416894979047467">"မျက်နှာပြင်အပြည့်ကနေ ပြန်ပြောင်းရန် အပေါ်အောက် ဆွဲချပါ"</string> + <string name="immersive_cling_title" msgid="8394201622932303336">"မျက်နှာပြင်အပြည့် ကြည့်နေစဉ်"</string> + <string name="immersive_cling_description" msgid="3482371193207536040">"ထွက်ရန်၊ ထိပ်ဘက်မှ အောက်ဘက်သို့ ဆွဲချပါ။"</string> + <string name="immersive_cling_positive" msgid="5016839404568297683">"ရပါပြီ"</string> <string name="done_label" msgid="2093726099505892398">"ပြီးပါပြီ"</string> <string name="hour_picker_description" msgid="6698199186859736512">"နာရီရွေးချက်စရာ"</string> <string name="minute_picker_description" msgid="8606010966873791190">"မိနစ်လှည့်သော ရွေ့လျားတန်"</string> @@ -1791,7 +1803,8 @@ <string name="managed_profile_label_badge" msgid="2355652472854327647">"အလုပ် <xliff:g id="LABEL">%1$s</xliff:g>"</string> <string name="lock_to_app_toast" msgid="7570091317001980053">"ဒီမျက်နှာပြင် ပင်ထိုးမှုကို ဖြုတ်ရန်၊ နောက်သို့ နှင့် ခြုံကြည့်မှု ခလုတ်များကို တစ်ချိန်တည်း ထိကိုင်ထားပါ။"</string> <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"ဒီမျက်နှာပြင် ပင်ထိုးမှုကို ဖြုတ်ရန် ခြုံကြည့်မှု ခလုတ်ကို ထိကိုင်ထားပါ။"</string> - <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"မျက်နှာပြင်ကို ပင်ထိုးထားသည်။ ပင်ထိုးထားမှု ဖြုတ်ခြင်းကို သင့် အဖွဲ့အစည်းက ခွင့် မပြုပါ။"</string> + <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) --> + <skip /> <string name="lock_to_app_start" msgid="6643342070839862795">"မျက်နှာပြင်ကို ပင်ထိုးထား"</string> <string name="lock_to_app_exit" msgid="8598219838213787430">"မျက်နှာပြင် ပင်ထိုးမှု ဖြတ်လိုက်ပြီ"</string> <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"ပင်မဖြုတ်မီမှာ PIN ကို မေးကြည့်ရန်"</string> diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml index f466da043d6d..01415c0b9f6d 100644 --- a/core/res/res/values-nb/strings.xml +++ b/core/res/res/values-nb/strings.xml @@ -796,6 +796,8 @@ <string name="permdesc_accessNotifications" msgid="458457742683431387">"Lar appen hente, gjennomgå og fjerne varsler, inkludert de som sendes fra andre apper."</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"binding til en varsellyttertjeneste"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Lar innehaveren binde seg til det øverste grensesnittnivået for en varsellyttertjeneste. Skal aldri være nødvendig for vanlige apper."</string> + <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"velge om de vil binde seg til målrettingstjenester"</string> + <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Lar innehavere velge om de vil binde seg til toppnivået av grensesnittet i målrettingstjenester. Skal aldri være nødvendig for vanlige apper."</string> <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"binde seg til en leverandørtjeneste for betingelser"</string> <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Gir innehaveren tillatelse til å binde til toppnivået av brukergrensesnittet for en leverandørtjeneste for betingelser. Dette skal ikke være nødvendig for vanlige apper."</string> <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"binde seg til en mediarutingstjeneste"</string> @@ -1263,6 +1265,14 @@ <string name="old_app_description" msgid="2082094275580358049">"Ikke start den nye appen."</string> <string name="new_app_action" msgid="5472756926945440706">"Start <xliff:g id="OLD_APP">%1$s</xliff:g>"</string> <string name="new_app_description" msgid="1932143598371537340">"Stopp den gamle appen uten å lagre."</string> + <!-- no translation found for dump_heap_notification (2618183274836056542) --> + <skip /> + <!-- no translation found for dump_heap_notification_detail (2075673362317481664) --> + <skip /> + <!-- no translation found for dump_heap_title (5864292264307651673) --> + <skip /> + <!-- no translation found for dump_heap_text (4809417337240334941) --> + <skip /> <string name="sendText" msgid="5209874571959469142">"Velg handling for tekst"</string> <string name="volume_ringtone" msgid="6885421406845734650">"Ringetonevolum"</string> <string name="volume_music" msgid="5421651157138628171">"Medievolum"</string> @@ -1776,7 +1786,9 @@ <item quantity="one">Prøv på nytt om 1 sekund</item> </plurals> <string name="restr_pin_try_later" msgid="973144472490532377">"Prøv på nytt senere"</string> - <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Sveip ned fra toppen av skjermen for å gå ut av fullskjermvisningen."</string> + <string name="immersive_cling_title" msgid="8394201622932303336">"Visning i fullskjerm"</string> + <string name="immersive_cling_description" msgid="3482371193207536040">"Sveip ned fra toppen for å avslutte."</string> + <string name="immersive_cling_positive" msgid="5016839404568297683">"Skjønner"</string> <string name="done_label" msgid="2093726099505892398">"Ferdig"</string> <string name="hour_picker_description" msgid="6698199186859736512">"Sirkulær glidebryter for timer"</string> <string name="minute_picker_description" msgid="8606010966873791190">"Sirkulær glidebryter for minutter"</string> @@ -1791,7 +1803,8 @@ <string name="managed_profile_label_badge" msgid="2355652472854327647">"Jobb-<xliff:g id="LABEL">%1$s</xliff:g>"</string> <string name="lock_to_app_toast" msgid="7570091317001980053">"Hvis du vil avslutte én-appsmodusen for denne skjermen, trykker og holder du på Tilbake og Oversikt samtidig."</string> <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Hvis du vil avslutte én-appsmodusen for denne skjermen, trykker og holder du på Oversikt."</string> - <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Skjermen er festet. Løsning er ikke tillatt av organisasjonen din."</string> + <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) --> + <skip /> <string name="lock_to_app_start" msgid="6643342070839862795">"Skjermen er festet"</string> <string name="lock_to_app_exit" msgid="8598219838213787430">"Skjermen er løsnet"</string> <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Krev PIN-kode for å løsne apper"</string> diff --git a/core/res/res/values-ne-rNP/strings.xml b/core/res/res/values-ne-rNP/strings.xml index 1d2e442fbd94..a5558aaeb422 100644 --- a/core/res/res/values-ne-rNP/strings.xml +++ b/core/res/res/values-ne-rNP/strings.xml @@ -796,6 +796,8 @@ <string name="permdesc_accessNotifications" msgid="458457742683431387">"अन्य अनुप्रयोगहरूबाट पोस्ट गरिएकासहित पुनःप्राप्त गर्न, परीक्षण गर्न र सूचनाहरू हटाउन अनुप्रयोगहरूलाई अनुमति दिन्छ।"</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"जानकारी श्रोता सेवामा बाँध्नुहोस्"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"होल्डरलाई सूचना श्रोता सेवाको शीर्ष-स्तरको इन्टरफेस बाँध्न अनुमति दिन्छ। सामान्य अनुप्रयोगहरूलाई कहिले पनि आवश्यक नपर्न सक्दछ।"</string> + <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"एक चयनकर्ता लक्षित सेवामा बाँध्नुहोस्"</string> + <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"होल्डरलाई चयनकर्ता लक्षित सेवाको शीर्ष-स्तर इन्टरफेस बाँध्न अनुमति दिन्छ। सामान्य अनुप्रयोगहरूको लागि कहिल्यै आवश्यकता पर्दैन।"</string> <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"सर्त प्रदायक सेवामा जोड्न"</string> <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"सर्त प्रदायक सेवाको माथिल्लो स्तरको इन्टरफेसमा जोड्न बाहकलाई अनुमति दिन्छ। साधारण अनुप्रयोगहरूको लागि कहिल्यै पनि आवश्यक पर्दैन।"</string> <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"मिडिया मार्ग सेवासँग बाँध्नुहोस्"</string> @@ -1269,6 +1271,14 @@ <string name="old_app_description" msgid="2082094275580358049">"नयाँ अनुप्रयोग सुरु नगर्नुहोस्।"</string> <string name="new_app_action" msgid="5472756926945440706">"<xliff:g id="OLD_APP">%1$s</xliff:g> सुरु गर्नुहोस्"</string> <string name="new_app_description" msgid="1932143598371537340">"बचत नगरी पुरानो अनुप्रयोग रोक्नुहोस्।"</string> + <!-- no translation found for dump_heap_notification (2618183274836056542) --> + <skip /> + <!-- no translation found for dump_heap_notification_detail (2075673362317481664) --> + <skip /> + <!-- no translation found for dump_heap_title (5864292264307651673) --> + <skip /> + <!-- no translation found for dump_heap_text (4809417337240334941) --> + <skip /> <string name="sendText" msgid="5209874571959469142">"पाठको लागि एउटा प्रकार्य छान्नुहोस्"</string> <string name="volume_ringtone" msgid="6885421406845734650">"बजाउने मात्रा"</string> <string name="volume_music" msgid="5421651157138628171">"मिडियाको मात्रा"</string> @@ -1782,7 +1792,9 @@ <item quantity="one">1 सेकेन्ड पछि पुनः प्रयास गर्नुहोस्।</item> </plurals> <string name="restr_pin_try_later" msgid="973144472490532377">"पछि पुनः प्रयास गर्नुहोस्"</string> - <string name="immersive_mode_confirmation" msgid="7227416894979047467">"पूर्णस्क्रिनबाट बाहिर निस्कन माथिबाट तलतिर स्वाइप गर्नुहोस्।"</string> + <string name="immersive_cling_title" msgid="8394201622932303336">"पूरा पर्दा हेर्दै"</string> + <string name="immersive_cling_description" msgid="3482371193207536040">"बाहिर निस्कन, माथिबाट तल स्वाइप गर्नुहोस्।"</string> + <string name="immersive_cling_positive" msgid="5016839404568297683">"बुझेँ"</string> <string name="done_label" msgid="2093726099505892398">"भयो"</string> <string name="hour_picker_description" msgid="6698199186859736512">"घण्टा गोलाकार स्लाइडर"</string> <string name="minute_picker_description" msgid="8606010966873791190">"मिनेट गोलाकार स्लाइडर"</string> @@ -1797,7 +1809,8 @@ <string name="managed_profile_label_badge" msgid="2355652472854327647">"कार्य <xliff:g id="LABEL">%1$s</xliff:g>"</string> <string name="lock_to_app_toast" msgid="7570091317001980053">"यस पर्दालाई अनपिन गर्न एकै समय फिर्ता र सारांशलाई छोई पक्डिनुहोस्।"</string> <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"यस पर्दालाई अनपिन गर्न सारांशलाई छुनुहोस् र पक्डनुहोस्।"</string> - <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"स्क्रिन अनपिन हुँदैछ। अनपिन गर्ने तपाईँको संगठन द्वारा समर्थित छैन।"</string> + <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) --> + <skip /> <string name="lock_to_app_start" msgid="6643342070839862795">"स्क्रिन पिन गरियो"</string> <string name="lock_to_app_exit" msgid="8598219838213787430">"स्क्रिन अनपिन गरियो"</string> <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"पिन निकाल्नुअघि PIN सोध्नुहोस्"</string> diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml index 2b4fe5672c11..7352267c3c12 100644 --- a/core/res/res/values-nl/strings.xml +++ b/core/res/res/values-nl/strings.xml @@ -196,9 +196,9 @@ <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Stille modus"</string> <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Geluid is UIT"</string> <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"Geluid is AAN"</string> - <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Vliegmodus"</string> - <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Vliegmodus is AAN"</string> - <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Vliegmodus is UIT"</string> + <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Vliegtuigmodus"</string> + <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Vliegtuigmodus is AAN"</string> + <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Vliegtuigmodus is UIT"</string> <string name="global_action_settings" msgid="1756531602592545966">"Instellingen"</string> <string name="global_action_voice_assist" msgid="7751191495200504480">"Spraakassistent"</string> <string name="global_action_lockdown" msgid="8751542514724332873">"Nu vergrendelen"</string> @@ -796,6 +796,8 @@ <string name="permdesc_accessNotifications" msgid="458457742683431387">"Hiermee kan de app meldingen ophalen, onderzoeken en wissen, waaronder meldingen die zijn verzonden door andere apps."</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"koppelen aan een listener-service voor meldingen"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Hiermee kan de houder koppelen aan de hoofdinterface van een listener-service voor meldingen. Nooit vereist voor normale apps."</string> + <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"verbinding maken met een doelservice voor kiezers"</string> + <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Hiermee kan de houder verbinding maken met de hoofdinterface van een doelservice voor kiezers. Nooit vereist voor normale apps."</string> <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"binden aan de service van een provider van voorwaarden"</string> <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Hiermee kan de houder binden aan de hoofdinterface van de service van een provider van voorwaarden. Nooit vereist voor normale apps."</string> <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"binden aan een service voor mediaroutering"</string> @@ -1263,6 +1265,14 @@ <string name="old_app_description" msgid="2082094275580358049">"De nieuwe app niet starten."</string> <string name="new_app_action" msgid="5472756926945440706">"<xliff:g id="OLD_APP">%1$s</xliff:g> starten"</string> <string name="new_app_description" msgid="1932143598371537340">"De oude app stoppen zonder opslaan."</string> + <!-- no translation found for dump_heap_notification (2618183274836056542) --> + <skip /> + <!-- no translation found for dump_heap_notification_detail (2075673362317481664) --> + <skip /> + <!-- no translation found for dump_heap_title (5864292264307651673) --> + <skip /> + <!-- no translation found for dump_heap_text (4809417337240334941) --> + <skip /> <string name="sendText" msgid="5209874571959469142">"Een actie voor tekst selecteren"</string> <string name="volume_ringtone" msgid="6885421406845734650">"Belvolume"</string> <string name="volume_music" msgid="5421651157138628171">"Mediavolume"</string> @@ -1776,7 +1786,9 @@ <item quantity="one">Probeer het over 1 seconde opnieuw</item> </plurals> <string name="restr_pin_try_later" msgid="973144472490532377">"Probeer het later opnieuw"</string> - <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Veeg omlaag vanaf de bovenkant om het volledige scherm te sluiten."</string> + <string name="immersive_cling_title" msgid="8394201622932303336">"Volledig scherm wordt weergegeven"</string> + <string name="immersive_cling_description" msgid="3482371193207536040">"Veeg omlaag vanaf de bovenkant van het scherm om af te sluiten."</string> + <string name="immersive_cling_positive" msgid="5016839404568297683">"Ik snap het"</string> <string name="done_label" msgid="2093726099505892398">"Gereed"</string> <string name="hour_picker_description" msgid="6698199186859736512">"Ronde schuifregelaar voor uren"</string> <string name="minute_picker_description" msgid="8606010966873791190">"Ronde schuifregelaar voor minuten"</string> @@ -1791,7 +1803,8 @@ <string name="managed_profile_label_badge" msgid="2355652472854327647">"Werk <xliff:g id="LABEL">%1$s</xliff:g>"</string> <string name="lock_to_app_toast" msgid="7570091317001980053">"Blijf \'Terug\' en \'Overzicht\' tegelijk aanraken om dit scherm los te maken."</string> <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Blijf \'Overzicht\' aanraken om dit scherm los te maken."</string> - <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Scherm is vastgezet. Losmaken is niet toegestaan door uw organisatie."</string> + <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) --> + <skip /> <string name="lock_to_app_start" msgid="6643342070839862795">"Scherm vastgezet"</string> <string name="lock_to_app_exit" msgid="8598219838213787430">"Scherm losgemaakt"</string> <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Vragen om pincode voordat items worden losgemaakt"</string> diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml index feebdba2a2ea..4816897f7edb 100644 --- a/core/res/res/values-pl/strings.xml +++ b/core/res/res/values-pl/strings.xml @@ -798,6 +798,8 @@ <string name="permdesc_accessNotifications" msgid="458457742683431387">"Umożliwia aplikacji pobieranie, sprawdzanie i usuwanie powiadomień, także tych, które pochodzą z innych aplikacji."</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"utwórz połączenie z usługą odbiornika powiadomień"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Zezwala na tworzenie powiązania z interfejsem najwyższego poziomu usługi odbiornika powiadomień. Nie powinno być nigdy potrzebne dla zwykłych aplikacji."</string> + <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"powiązanie z usługą docelową wybierania"</string> + <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Umożliwia posiadaczowi tworzenie powiązania z interfejsem najwyższego poziomu usługi docelowej wybierania. Zwykłe aplikacje nie powinny potrzebować tego uprawnienia."</string> <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"powiąż z usługą dostawcy warunków"</string> <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Zezwala na tworzenie powiązania z interfejsem najwyższego poziomu usługi dostawcy warunków. Nieprzeznaczone dla zwykłych aplikacji."</string> <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"powiązanie z usługą kierowania multimediów"</string> @@ -1273,6 +1275,14 @@ <string name="old_app_description" msgid="2082094275580358049">"Nie uruchamiaj nowej aplikacji."</string> <string name="new_app_action" msgid="5472756926945440706">"Uruchom <xliff:g id="OLD_APP">%1$s</xliff:g>"</string> <string name="new_app_description" msgid="1932143598371537340">"Zatrzymaj starą aplikację bez zapisywania."</string> + <!-- no translation found for dump_heap_notification (2618183274836056542) --> + <skip /> + <!-- no translation found for dump_heap_notification_detail (2075673362317481664) --> + <skip /> + <!-- no translation found for dump_heap_title (5864292264307651673) --> + <skip /> + <!-- no translation found for dump_heap_text (4809417337240334941) --> + <skip /> <string name="sendText" msgid="5209874571959469142">"Wybierz czynność, jaka ma zostać wykonana na tekście"</string> <string name="volume_ringtone" msgid="6885421406845734650">"Głośność dzwonka"</string> <string name="volume_music" msgid="5421651157138628171">"Głośność multimediów"</string> @@ -1794,7 +1804,9 @@ <item quantity="one">Spróbuj ponownie za sekundę</item> </plurals> <string name="restr_pin_try_later" msgid="973144472490532377">"Spróbuj ponownie później"</string> - <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Przesuń z góry w dół, by zamknąć pełny ekran."</string> + <string name="immersive_cling_title" msgid="8394201622932303336">"Widok na pełnym ekranie"</string> + <string name="immersive_cling_description" msgid="3482371193207536040">"Aby wyjść, przesuń palcem z góry na dół."</string> + <string name="immersive_cling_positive" msgid="5016839404568297683">"OK"</string> <string name="done_label" msgid="2093726099505892398">"Gotowe"</string> <string name="hour_picker_description" msgid="6698199186859736512">"Kołowy suwak godzin"</string> <string name="minute_picker_description" msgid="8606010966873791190">"Kołowy suwak minut"</string> @@ -1809,7 +1821,8 @@ <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> (praca)"</string> <string name="lock_to_app_toast" msgid="7570091317001980053">"Aby odpiąć ten ekran, naciśnij i przytrzymaj jednocześnie Wstecz i Przegląd."</string> <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Aby odpiąć ten ekran, naciśnij i przytrzymaj Przegląd."</string> - <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Ekran jest przypięty. Ustawienia organizacji nie pozwalają go odpiąć."</string> + <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) --> + <skip /> <string name="lock_to_app_start" msgid="6643342070839862795">"Ekran przypięty"</string> <string name="lock_to_app_exit" msgid="8598219838213787430">"Ekran odpięty"</string> <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Aby odpiąć, poproś o PIN"</string> diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml index 466879202fff..18d498eaeae3 100644 --- a/core/res/res/values-pt-rPT/strings.xml +++ b/core/res/res/values-pt-rPT/strings.xml @@ -796,6 +796,8 @@ <string name="permdesc_accessNotifications" msgid="458457742683431387">"Permite que a aplicação obtenha, examine e limpe notificações, incluindo as que foram publicadas por outras aplicações."</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"vincular a um serviço de escuta de notificações"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Permite que o titular vincule a interface de nível superior de um serviço de escuta de notificações. Nunca deverá ser necessário para aplicações normais."</string> + <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"vincular a um serviço de destino do selecionador"</string> + <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Permite ao detentor ficar vinculado à interface de nível superior de um serviço de destino do selecionador. Nunca deve ser necessário para aplicações normais."</string> <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"vincular a um serviço de fornecedor de condição"</string> <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Permite que o titular vincule a interface de nível superior de um serviço de fornecedor de condição. Nunca deverá ser necessário para aplicações normais."</string> <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"vincular a um serviço de encaminhamento multimédia"</string> @@ -1263,6 +1265,14 @@ <string name="old_app_description" msgid="2082094275580358049">"Não iniciar a nova aplicação."</string> <string name="new_app_action" msgid="5472756926945440706">"Iniciar <xliff:g id="OLD_APP">%1$s</xliff:g>"</string> <string name="new_app_description" msgid="1932143598371537340">"Parar a aplicação antiga sem guardar."</string> + <!-- no translation found for dump_heap_notification (2618183274836056542) --> + <skip /> + <!-- no translation found for dump_heap_notification_detail (2075673362317481664) --> + <skip /> + <!-- no translation found for dump_heap_title (5864292264307651673) --> + <skip /> + <!-- no translation found for dump_heap_text (4809417337240334941) --> + <skip /> <string name="sendText" msgid="5209874571959469142">"Escolha uma ação para o texto"</string> <string name="volume_ringtone" msgid="6885421406845734650">"Volume da campainha"</string> <string name="volume_music" msgid="5421651157138628171">"Volume de multimédia"</string> @@ -1776,7 +1786,9 @@ <item quantity="one">Tente novamente dentro de 1 segundo</item> </plurals> <string name="restr_pin_try_later" msgid="973144472490532377">"Tente novamente mais tarde"</string> - <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Deslize rapidamente para baixo para sair do ecrã inteiro."</string> + <string name="immersive_cling_title" msgid="8394201622932303336">"Visualização de ecrã inteiro"</string> + <string name="immersive_cling_description" msgid="3482371193207536040">"Para sair, deslize rapidamente para baixo a partir da parte superior."</string> + <string name="immersive_cling_positive" msgid="5016839404568297683">"Compreendi"</string> <string name="done_label" msgid="2093726099505892398">"Concluído"</string> <string name="hour_picker_description" msgid="6698199186859736512">"Controlo de deslize circular das horas"</string> <string name="minute_picker_description" msgid="8606010966873791190">"Controlo de deslize circular dos minutos"</string> @@ -1791,7 +1803,8 @@ <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> de trabalho"</string> <string name="lock_to_app_toast" msgid="7570091317001980053">"Para soltar este ecrã, toque sem soltar em Retroceder e Visão geral em simultâneo."</string> <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Para soltar este ecrã, toque sem soltar em Visão geral."</string> - <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"O ecrã está fixo. A sua entidade não o(a) autoriza a soltá-lo."</string> + <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) --> + <skip /> <string name="lock_to_app_start" msgid="6643342070839862795">"Ecrã fixo"</string> <string name="lock_to_app_exit" msgid="8598219838213787430">"Ecrã solto"</string> <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Pedir PIN antes de soltar"</string> diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml index 0c9b2bab0017..14733e00f892 100644 --- a/core/res/res/values-pt/strings.xml +++ b/core/res/res/values-pt/strings.xml @@ -738,14 +738,10 @@ <string name="permdesc_nfc" msgid="7120611819401789907">"Permite que o app se comunique com leitores, cartões e etiqueta NFC (Comunicação a curta distância)."</string> <string name="permlab_disableKeyguard" msgid="3598496301486439258">"desativar o bloqueio de tela"</string> <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"Permite que o app desative o bloqueio de teclas e qualquer segurança por senha associada. Por exemplo, o telefone desativa o bloqueio de telas ao receber uma chamada e o reativa quando a chamada é finalizada."</string> - <!-- no translation found for permlab_manageFingerprint (5640858826254575638) --> - <skip /> - <!-- no translation found for permdesc_manageFingerprint (178208705828055464) --> - <skip /> - <!-- no translation found for permlab_useFingerprint (3150478619915124905) --> - <skip /> - <!-- no translation found for permdesc_useFingerprint (9165097460730684114) --> - <skip /> + <string name="permlab_manageFingerprint" msgid="5640858826254575638">"gerenciar hardware de impressão digital"</string> + <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Permite que o app execute métodos para adicionar e excluir modelos de impressão digital para uso."</string> + <string name="permlab_useFingerprint" msgid="3150478619915124905">"usar hardware de impressão digital"</string> + <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Permite que o app use hardware de impressão digital para autenticação."</string> <string name="permlab_readSyncSettings" msgid="6201810008230503052">"ler as configurações de sincronização"</string> <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Permite que o app leia as configurações de sincronização de uma conta. Por exemplo, pode determinar se o app People está sincronizado com uma conta."</string> <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"ativar e desativar sincronização"</string> @@ -800,6 +796,8 @@ <string name="permdesc_accessNotifications" msgid="458457742683431387">"Permite que o app recupere, examine e limpe notificações, inclusive as postadas por outros apps."</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"sujeitar a um serviço ouvinte de notificações"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Permite que o proprietário sujeite a interface de nível superior a um serviço ouvinte de notificações. Não deve ser necessário para apps comuns."</string> + <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"associar a um serviço seletor alvo"</string> + <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Permite que o sistema se associe à interface de nível superior de um serviço seletor alvo. Não deve ser necessário para apps comuns."</string> <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"associar a um serviço provedor de condições"</string> <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Permite que o proprietário use a interface de nível superior de um serviço provedor de condições. Não deve ser necessário para apps comuns."</string> <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"usar serviço de roteamento de mídia"</string> @@ -1267,6 +1265,14 @@ <string name="old_app_description" msgid="2082094275580358049">"Não inicie o novo app."</string> <string name="new_app_action" msgid="5472756926945440706">"Iniciar <xliff:g id="OLD_APP">%1$s</xliff:g>"</string> <string name="new_app_description" msgid="1932143598371537340">"Parar o app antigo sem salvar."</string> + <!-- no translation found for dump_heap_notification (2618183274836056542) --> + <skip /> + <!-- no translation found for dump_heap_notification_detail (2075673362317481664) --> + <skip /> + <!-- no translation found for dump_heap_title (5864292264307651673) --> + <skip /> + <!-- no translation found for dump_heap_text (4809417337240334941) --> + <skip /> <string name="sendText" msgid="5209874571959469142">"Escolha uma ação para o texto"</string> <string name="volume_ringtone" msgid="6885421406845734650">"Volume da campainha"</string> <string name="volume_music" msgid="5421651157138628171">"Volume da mídia"</string> @@ -1780,7 +1786,9 @@ <item quantity="other">Tente novamente em <xliff:g id="COUNT">%d</xliff:g> segundos</item> </plurals> <string name="restr_pin_try_later" msgid="973144472490532377">"Tente novamente mais tarde"</string> - <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Deslize de cima para baixo para sair da tela inteira"</string> + <string name="immersive_cling_title" msgid="8394201622932303336">"Visualização em tela cheia"</string> + <string name="immersive_cling_description" msgid="3482371193207536040">"Para sair, deslize de cima para baixo."</string> + <string name="immersive_cling_positive" msgid="5016839404568297683">"Entendi"</string> <string name="done_label" msgid="2093726099505892398">"Concluído"</string> <string name="hour_picker_description" msgid="6698199186859736512">"Controle deslizante circular das horas"</string> <string name="minute_picker_description" msgid="8606010966873791190">"Controle deslizante circular dos minutos"</string> @@ -1795,7 +1803,8 @@ <string name="managed_profile_label_badge" msgid="2355652472854327647">"Trabalho: <xliff:g id="LABEL">%1$s</xliff:g>"</string> <string name="lock_to_app_toast" msgid="7570091317001980053">"Para liberar esta tela, toque e mantenha pressionados \"Voltar\" e \"Visão geral\" ao mesmo tempo."</string> <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Para liberar esta tela, toque e mantenha pressionado \"Visão geral\"."</string> - <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"A tela está fixada. A liberação não é permitida por sua organização."</string> + <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) --> + <skip /> <string name="lock_to_app_start" msgid="6643342070839862795">"Tela fixada"</string> <string name="lock_to_app_exit" msgid="8598219838213787430">"Tela liberada"</string> <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Pedir PIN antes de liberar"</string> diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml index 0dda24e50dcd..dd87d74c3cb9 100644 --- a/core/res/res/values-ro/strings.xml +++ b/core/res/res/values-ro/strings.xml @@ -797,6 +797,8 @@ <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> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"conectare la un serviciu de citire a notificărilor"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Permite proprietarului să se conecteze la interfața de nivel superior a unui serviciu de citire a notificărilor. În mod normal aplicațiile nu ar trebui să aibă nevoie de această permisiune."</string> + <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"se conectează la un serviciu de alegere a țintei"</string> + <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Permite aplicației să se conecteze la interfața de nivel superior a unui serviciu de alegere a țintei. Nu ar trebui să fie necesară pentru aplicațiile obișnuite."</string> <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"conectare la un serviciu furnizor de condiții"</string> <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Permite proprietarului să se conecteze la interfața de nivel superior a unui serviciu furnizor de condiții. Nu ar trebui să fie necesară pentru aplicațiile obișnuite."</string> <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"se conectează la un serviciu de trasee multimedia"</string> @@ -1268,6 +1270,14 @@ <string name="old_app_description" msgid="2082094275580358049">"Nu porniţi aplicaţia nouă."</string> <string name="new_app_action" msgid="5472756926945440706">"Porniţi <xliff:g id="OLD_APP">%1$s</xliff:g>"</string> <string name="new_app_description" msgid="1932143598371537340">"Opriţi vechea aplicaţie fără să salvaţi."</string> + <!-- no translation found for dump_heap_notification (2618183274836056542) --> + <skip /> + <!-- no translation found for dump_heap_notification_detail (2075673362317481664) --> + <skip /> + <!-- no translation found for dump_heap_title (5864292264307651673) --> + <skip /> + <!-- no translation found for dump_heap_text (4809417337240334941) --> + <skip /> <string name="sendText" msgid="5209874571959469142">"Alegeţi o acţiune pentru text"</string> <string name="volume_ringtone" msgid="6885421406845734650">"Volum sonerie"</string> <string name="volume_music" msgid="5421651157138628171">"Volum media"</string> @@ -1785,7 +1795,9 @@ <item quantity="one">Reîncercați într-o secundă</item> </plurals> <string name="restr_pin_try_later" msgid="973144472490532377">"Reîncercați mai târziu"</string> - <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Glisați în jos pentru a ieși din ecran complet."</string> + <string name="immersive_cling_title" msgid="8394201622932303336">"Vizualizare pe ecran complet"</string> + <string name="immersive_cling_description" msgid="3482371193207536040">"Pentru a ieși, glisați de sus în jos."</string> + <string name="immersive_cling_positive" msgid="5016839404568297683">"Am înțeles"</string> <string name="done_label" msgid="2093726099505892398">"Terminat"</string> <string name="hour_picker_description" msgid="6698199186859736512">"Selector circular pentru ore"</string> <string name="minute_picker_description" msgid="8606010966873791190">"Selector circular pentru minute"</string> @@ -1800,7 +1812,8 @@ <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> de serviciu"</string> <string name="lock_to_app_toast" msgid="7570091317001980053">"Pentru a anula fixarea pe ecran, apăsați lung, simultan, pe Înapoi și pe Vizualizare generală."</string> <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Pentru a anula fixarea pe ecran, apăsați lung pe Vizualizare generală."</string> - <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Ecranul este fixat. Anularea fixării nu este permisă de organizația dvs."</string> + <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) --> + <skip /> <string name="lock_to_app_start" msgid="6643342070839862795">"Ecran fixat"</string> <string name="lock_to_app_exit" msgid="8598219838213787430">"Fixarea ecranului anulată"</string> <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Solicită codul PIN înainte de a anula fixarea"</string> diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml index 61464e6ea7e0..a03d02d4ad69 100644 --- a/core/res/res/values-ru/strings.xml +++ b/core/res/res/values-ru/strings.xml @@ -740,14 +740,10 @@ <string name="permdesc_nfc" msgid="7120611819401789907">"Приложение сможет обмениваться данными с NFC-метками, картами и устройствами считывания, используя связь малого радиуса действия."</string> <string name="permlab_disableKeyguard" msgid="3598496301486439258">"Отключение функции блокировки экрана"</string> <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"Приложение сможет отключать блокировку экрана и другие функции защиты. Например, блокировка экрана будет отключаться при получении входящего вызова и включаться после завершения разговора."</string> - <!-- no translation found for permlab_manageFingerprint (5640858826254575638) --> - <skip /> - <!-- no translation found for permdesc_manageFingerprint (178208705828055464) --> - <skip /> - <!-- no translation found for permlab_useFingerprint (3150478619915124905) --> - <skip /> - <!-- no translation found for permdesc_useFingerprint (9165097460730684114) --> - <skip /> + <string name="permlab_manageFingerprint" msgid="5640858826254575638">"управление сканером отпечатков"</string> + <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Приложение сможет добавлять и удалять шаблоны отпечатков пальцев."</string> + <string name="permlab_useFingerprint" msgid="3150478619915124905">"использование сканера отпечатков"</string> + <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Приложение сможет использовать сканер отпечатков пальцев для аутентификации."</string> <string name="permlab_readSyncSettings" msgid="6201810008230503052">"Просмотр настроек синхронизации"</string> <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Приложение сможет просматривать настройки синхронизации аккаунта, например определять, включена ли синхронизация для приложения \"Контакты\"."</string> <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"Включение/выключение синхронизации"</string> @@ -802,6 +798,8 @@ <string name="permdesc_accessNotifications" msgid="458457742683431387">"Приложение сможет получать, проверять и удалять уведомления, включая те, что опубликованы другими приложениями."</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"Подключение к службе просмотра уведомлений"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Приложение сможет подключаться к базовому интерфейсу службы просмотра уведомлений. Это разрешение не используется обычными приложениями."</string> + <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"Подключение к сервису выбора цели"</string> + <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Подключение к базовому интерфейсу для выбора цели. Это разрешение не требуется для работы обычных приложений."</string> <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"Подключение к серверам поставщиков условий"</string> <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Приложение сможет подключаться к базовому интерфейсу поставщиков условий. Это разрешение обычно используется только специальными приложениями."</string> <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"Привязка к средству передачи медиафайлов"</string> @@ -1277,6 +1275,14 @@ <string name="old_app_description" msgid="2082094275580358049">"Не запускать новое приложение."</string> <string name="new_app_action" msgid="5472756926945440706">"Запустить приложение <xliff:g id="OLD_APP">%1$s</xliff:g>"</string> <string name="new_app_description" msgid="1932143598371537340">"Остановить старое приложение без сохранения изменений."</string> + <!-- no translation found for dump_heap_notification (2618183274836056542) --> + <skip /> + <!-- no translation found for dump_heap_notification_detail (2075673362317481664) --> + <skip /> + <!-- no translation found for dump_heap_title (5864292264307651673) --> + <skip /> + <!-- no translation found for dump_heap_text (4809417337240334941) --> + <skip /> <string name="sendText" msgid="5209874571959469142">"Выберите действие для текста"</string> <string name="volume_ringtone" msgid="6885421406845734650">"Громкость звонка"</string> <string name="volume_music" msgid="5421651157138628171">"Громкость мультимедиа"</string> @@ -1798,7 +1804,9 @@ <item quantity="other">Повторите попытку через <xliff:g id="COUNT">%d</xliff:g> секунд</item> </plurals> <string name="restr_pin_try_later" msgid="973144472490532377">"Повторите попытку позже."</string> - <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Чтобы вернуться в обычный режим, проведите пальцем вниз."</string> + <string name="immersive_cling_title" msgid="8394201622932303336">"Полноэкранный режим"</string> + <string name="immersive_cling_description" msgid="3482371193207536040">"Чтобы выйти, проведите по экрану сверху вниз."</string> + <string name="immersive_cling_positive" msgid="5016839404568297683">"ОК"</string> <string name="done_label" msgid="2093726099505892398">"Готово"</string> <string name="hour_picker_description" msgid="6698199186859736512">"Выбор часов на циферблате"</string> <string name="minute_picker_description" msgid="8606010966873791190">"Выбор минут на циферблате"</string> @@ -1813,7 +1821,8 @@ <string name="managed_profile_label_badge" msgid="2355652472854327647">"Рабочий <xliff:g id="LABEL">%1$s</xliff:g>"</string> <string name="lock_to_app_toast" msgid="7570091317001980053">"Чтобы открепить экран, нажмите и удерживайте кнопки \"Назад\" и \"Обзор\" одновременно."</string> <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Чтобы открепить экран, нажмите и удерживайте кнопку \"Обзор\"."</string> - <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Блокировка включена. Ее отключение запрещено правилами организации."</string> + <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) --> + <skip /> <string name="lock_to_app_start" msgid="6643342070839862795">"Блокировка включена"</string> <string name="lock_to_app_exit" msgid="8598219838213787430">"Блокировка выключена"</string> <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Запрашивать PIN-код для отключения блокировки"</string> diff --git a/core/res/res/values-si-rLK/strings.xml b/core/res/res/values-si-rLK/strings.xml index 960fb1e465b2..8e046733b260 100644 --- a/core/res/res/values-si-rLK/strings.xml +++ b/core/res/res/values-si-rLK/strings.xml @@ -739,7 +739,7 @@ <string name="permlab_disableKeyguard" msgid="3598496301486439258">"ඔබගේ තිරයේ අගුල අබල කරන්න"</string> <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"යතුරු අගුල සහ ඕනෑම සම්බන්ධිත මුරපද ආරක්ෂාවක් අබල කිරීමට යෙදුමට අවසර දෙන්න. මෙහි උදාහරණයක් වන්නේ පැමිණෙන ඇමතුමක් ලැබෙද්දී, දුරකථනය අක්රිය වන අතර ඇමතුම අවසාන වන විට යතුරු අගුල නැවත සක්රිය වෙයි."</string> <string name="permlab_manageFingerprint" msgid="5640858826254575638">"ඇඟිලි සලකුණු දෘඩාංග කළමනාකරණය කිරීම."</string> - <string name="permdesc_manageFingerprint" msgid="178208705828055464">"ඇඟිලි සලකුණු සැකිලි එක් කිරීමට සහ ඉවත් කිරීමට අදාළ විධික්රම භාවිතය සඳහා මෙම යෙදුමට අවසර දෙයි."</string> + <string name="permdesc_manageFingerprint" msgid="178208705828055464">"ඇඟිලි සලකුණු සැකිලි එකතු කිරීමට සහ ඉවත් කිරීමට අදාළ විධික්රම භාවිතය සඳහා මෙම යෙදුමට අවසර දෙයි."</string> <string name="permlab_useFingerprint" msgid="3150478619915124905">"ඇඟිලි සලකුණු දෘඩාංග භාවිතා කරන්න."</string> <string name="permdesc_useFingerprint" msgid="9165097460730684114">"අනන්යතාවය තහවුරු කරගැනීමට ඇඟිලි සලකුණු දෘඩාංග භාවිතා කිරීමට මෙම යෙදුමට ඉඩ දෙන්න."</string> <string name="permlab_readSyncSettings" msgid="6201810008230503052">"සමමුහුර්ත සැකසීම් කියවන්න"</string> @@ -796,6 +796,8 @@ <string name="permdesc_accessNotifications" msgid="458457742683431387">"වෙනත් යෙදුම් විසින් කළ පල කිරීම්ද ඇතුළත්ව දැන්වීම් ලබා ගැනීමට, පරීක්ෂා කිරීමට සහ හිස් කිරීමට යෙදුමට අවසර දෙන්න."</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"දැනුම්දීම ඇහුම්කන් දීම් සේවාවක් වෙත බඳින්න"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"දැනුම්දීම් අසන්නාගේ සේවාවේ ඉහළ මට්ටමේ අතුරුමුහුණතට බැඳීමට දරන්නාට අවසර දේ. සාමාන්ය යෙදුම් සඳහා කිසිසේත් අවශ්ය නොවේ."</string> + <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"තෝරන්නා ඉලක්ක කරගත් සේවාවකට සම්බන්ධ කරන්න"</string> + <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"තෝරන්නා ඉලක්ක කරගත් සේවාවක ඉහළ මට්ටමේ අතුරු මුහුණත වෙත සම්බන්ධ වීමට ධාරකයාට ඉඩදෙන්න. සාමාන්ය යෙදුම් සඳහා කිසිදා අවශ්ය නොවනු ඇත."</string> <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"තත්ත්වය සපයන්නාගේ සේවාවට බඳින්න"</string> <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"තත්ත්වය සපයන්නාගේ සේවාවට ඉහළ-මට්ටමේ අතුරු මුහුණතක් බැඳිමට ධාරකයාට අවසර දෙන්න. සාමාන්ය යෙදුම් සඳහා කවදාවත් අවශ්යය නොවෙයි."</string> <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"මාධ්ය ගමන් කරන සේවාව බඳින්න"</string> @@ -1265,6 +1267,14 @@ <string name="old_app_description" msgid="2082094275580358049">"නව යෙදුම ආරම්භ නොකරන්න."</string> <string name="new_app_action" msgid="5472756926945440706">"<xliff:g id="OLD_APP">%1$s</xliff:g> අරඹන්න"</string> <string name="new_app_description" msgid="1932143598371537340">"සුරැකීමකින් තොරව පරණ යෙදුම නවත්වන්න."</string> + <!-- no translation found for dump_heap_notification (2618183274836056542) --> + <skip /> + <!-- no translation found for dump_heap_notification_detail (2075673362317481664) --> + <skip /> + <!-- no translation found for dump_heap_title (5864292264307651673) --> + <skip /> + <!-- no translation found for dump_heap_text (4809417337240334941) --> + <skip /> <string name="sendText" msgid="5209874571959469142">"පෙළ සඳහා ක්රියාව තෝරන්න"</string> <string name="volume_ringtone" msgid="6885421406845734650">"හඬ නඟනයේ ශබ්දය"</string> <string name="volume_music" msgid="5421651157138628171">"මාධ්ය ශබ්දය"</string> @@ -1778,7 +1788,9 @@ <item quantity="other">තත්පර <xliff:g id="COUNT">%d</xliff:g> කින් නැවත උත්සාහ කරන්න</item> </plurals> <string name="restr_pin_try_later" msgid="973144472490532377">"පසුව නැවත උත්සාහ කරන්න"</string> - <string name="immersive_mode_confirmation" msgid="7227416894979047467">"උඩ සිට පහළට ස්වයිප් කර පූර්ණ තිරයෙන් ඉවත්වන්න."</string> + <string name="immersive_cling_title" msgid="8394201622932303336">"මුළු තිරය නරඹමින්"</string> + <string name="immersive_cling_description" msgid="3482371193207536040">"ඉවත් වීමට, ඉහළ සිට පහළට ස්වයිප් කරන්න"</string> + <string name="immersive_cling_positive" msgid="5016839404568297683">"වැටහුණි"</string> <string name="done_label" msgid="2093726099505892398">"අවසන්"</string> <string name="hour_picker_description" msgid="6698199186859736512">"පැය කවාකාර සර්පනය"</string> <string name="minute_picker_description" msgid="8606010966873791190">"මිනිත්තු කවාකාර සර්පනය"</string> @@ -1793,7 +1805,8 @@ <string name="managed_profile_label_badge" msgid="2355652472854327647">"වැඩ <xliff:g id="LABEL">%1$s</xliff:g>"</string> <string name="lock_to_app_toast" msgid="7570091317001980053">"මෙම තීරයේ ඇමුණුම ඉවත් කිරීමට, ආපසු සහ දළ විශ්ලේෂණය එකම වේලාවේ ස්පර්ශ කර අල්ලා සිටින්න."</string> <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"මෙම තීරයේ ඇමුණුම ඉවත් කිරීමට, දළ විශ්ලේෂණය ස්පර්ශ කර අල්ලා සිටින්න."</string> - <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"තිරය අගුළු දමා ඇත. ඔබගේ සංවිධානය විසින් අගුළු ඇරීමට ඉඩ නොදෙයි."</string> + <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) --> + <skip /> <string name="lock_to_app_start" msgid="6643342070839862795">"තිරය අගුළු දමා ඇත"</string> <string name="lock_to_app_exit" msgid="8598219838213787430">"තිරයේ අගුළු ඇර ඇත"</string> <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"ගැලවීමට පෙර PIN විමසන්න"</string> diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml index bae9b639d3cd..60cb66233cfc 100644 --- a/core/res/res/values-sk/strings.xml +++ b/core/res/res/values-sk/strings.xml @@ -798,6 +798,8 @@ <string name="permdesc_accessNotifications" msgid="458457742683431387">"Umožňuje aplikácii načítať, zobrazovať a mazať upozornenia vrátane tých, ktoré boli uverejnené inými aplikáciami."</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"naviazanie sa na službu na počúvanie upozornení"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Umožňuje držiteľovi naviazať sa na najvyššiu úroveň služby na počúvanie upozornení. Bežné aplikácie by toto nastavenie nemali nikdy požadovať."</string> + <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"viazať sa na výber cieľovej služby"</string> + <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Umožňuje držiteľovi viazať sa na najvyššiu úroveň rozhrania na výber cieľovej služby. Bežné aplikácie by toto povolenie nemali nikdy potrebovať."</string> <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"viazanie na službu poskytovateľa podmienky"</string> <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Umožňuje držiteľovi viazať sa na najvyššiu úroveň rozhrania služby poskytovateľa podmienky. Bežné aplikácie by toto povolenie nemali nikdy potrebovať."</string> <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"viazanie na službu smerovania médií"</string> @@ -1273,6 +1275,14 @@ <string name="old_app_description" msgid="2082094275580358049">"Nespúšťať novú aplikáciu."</string> <string name="new_app_action" msgid="5472756926945440706">"Spustiť <xliff:g id="OLD_APP">%1$s</xliff:g>"</string> <string name="new_app_description" msgid="1932143598371537340">"Zastaviť starú aplikáciu bez uloženia."</string> + <!-- no translation found for dump_heap_notification (2618183274836056542) --> + <skip /> + <!-- no translation found for dump_heap_notification_detail (2075673362317481664) --> + <skip /> + <!-- no translation found for dump_heap_title (5864292264307651673) --> + <skip /> + <!-- no translation found for dump_heap_text (4809417337240334941) --> + <skip /> <string name="sendText" msgid="5209874571959469142">"Zvoľte akciu pre text"</string> <string name="volume_ringtone" msgid="6885421406845734650">"Hlasitosť vyzváňania"</string> <string name="volume_music" msgid="5421651157138628171">"Hlasitosť médií"</string> @@ -1794,7 +1804,9 @@ <item quantity="one">Skúste to znova o 1 sekundu</item> </plurals> <string name="restr_pin_try_later" msgid="973144472490532377">"Skúste to znova neskôr"</string> - <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Režim celej obrazovky ukončíte posunutím nadol."</string> + <string name="immersive_cling_title" msgid="8394201622932303336">"Zobrazenie na celú obrazovku"</string> + <string name="immersive_cling_description" msgid="3482371193207536040">"Ukončite prejdením prstom z hornej časti nadol."</string> + <string name="immersive_cling_positive" msgid="5016839404568297683">"Rozumiem"</string> <string name="done_label" msgid="2093726099505892398">"Hotovo"</string> <string name="hour_picker_description" msgid="6698199186859736512">"Kruhový posúvač hodín"</string> <string name="minute_picker_description" msgid="8606010966873791190">"Kruhový posúvač minút"</string> @@ -1809,7 +1821,8 @@ <string name="managed_profile_label_badge" msgid="2355652472854327647">"Práca – <xliff:g id="LABEL">%1$s</xliff:g>"</string> <string name="lock_to_app_toast" msgid="7570091317001980053">"Ak chcete uvoľniť túto obrazovku, súčasne klepnite na tlačidlá Späť a Prehľad a podržte ich."</string> <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Ak chcete uvoľniť túto obrazovku, klepnite na tlačidlo Prehľad a podržte ho."</string> - <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Obrazovka je pripnutá. Uvoľnenie vaša organizácia nepovoľuje."</string> + <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) --> + <skip /> <string name="lock_to_app_start" msgid="6643342070839862795">"Obrazovka bola pripnutá"</string> <string name="lock_to_app_exit" msgid="8598219838213787430">"Obrazovka bola uvoľnená"</string> <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Pred uvoľnením požiadať o číslo PIN"</string> diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml index e1f15dd7a13c..6fe00d140a33 100644 --- a/core/res/res/values-sl/strings.xml +++ b/core/res/res/values-sl/strings.xml @@ -798,6 +798,8 @@ <string name="permdesc_accessNotifications" msgid="458457742683431387">"Dovoli aplikaciji, da prenese, razišče in izbriše obvestila, tudi tista, ki so jih objavile druge aplikacije."</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"poveži se s storitvijo poslušalca obvestil"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Lastniku omogoča povezovanje z vmesnikom storitve poslušalca obvestil najvišje ravni. Tega nikoli ni treba uporabiti za navadne aplikacije."</string> + <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"povezava s storitvijo izbirnika cilja"</string> + <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Imetniku omogoča povezovanje z vmesnikom storitve izbirnika cilja najvišje ravni. Nikoli ni potrebno za navadne aplikacije."</string> <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"povezovanje s storitvijo ponudnika pogojev"</string> <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Imetniku omogoča povezovanje z vmesnikom storitve ponudnika pogojev najvišje ravni. Tega ni treba nikoli uporabiti za navadne aplikacije."</string> <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"povezovanje s storitvijo poti predstavnosti"</string> @@ -1273,6 +1275,14 @@ <string name="old_app_description" msgid="2082094275580358049">"Ne zaženite nove aplikacije."</string> <string name="new_app_action" msgid="5472756926945440706">"Začni <xliff:g id="OLD_APP">%1$s</xliff:g>"</string> <string name="new_app_description" msgid="1932143598371537340">"Ustavi prejšnjo aplikacijo brez shranjevanja."</string> + <!-- no translation found for dump_heap_notification (2618183274836056542) --> + <skip /> + <!-- no translation found for dump_heap_notification_detail (2075673362317481664) --> + <skip /> + <!-- no translation found for dump_heap_title (5864292264307651673) --> + <skip /> + <!-- no translation found for dump_heap_text (4809417337240334941) --> + <skip /> <string name="sendText" msgid="5209874571959469142">"Izberite dejanje za besedilo"</string> <string name="volume_ringtone" msgid="6885421406845734650">"Glasnost zvonjenja"</string> <string name="volume_music" msgid="5421651157138628171">"Glasnost predstavnosti"</string> @@ -1794,7 +1804,9 @@ <item quantity="other">Poskusite znova čez <xliff:g id="COUNT">%d</xliff:g> sekund</item> </plurals> <string name="restr_pin_try_later" msgid="973144472490532377">"Poskusite znova pozneje"</string> - <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Povlecite z vrha, da zaprete celozaslonski način."</string> + <string name="immersive_cling_title" msgid="8394201622932303336">"Celozaslonski način"</string> + <string name="immersive_cling_description" msgid="3482371193207536040">"Zaprete tako, da z vrha s prstom povlečete navzdol."</string> + <string name="immersive_cling_positive" msgid="5016839404568297683">"Razumem"</string> <string name="done_label" msgid="2093726099505892398">"Dokončano"</string> <string name="hour_picker_description" msgid="6698199186859736512">"Okrogli drsnik za ure"</string> <string name="minute_picker_description" msgid="8606010966873791190">"Okrogli drsnik za minute"</string> @@ -1809,7 +1821,8 @@ <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> za delo"</string> <string name="lock_to_app_toast" msgid="7570091317001980053">"Če želite odpeti ta zaslon, se hkrati dotaknite tipk Nazaj in Pregled ter ju pridržite."</string> <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Če želite odpeti ta zaslon, se dotaknite tipke Pregled in jo pridržite."</string> - <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Zaslon je pripet. Vaša organizacija ne dovoli odpenjanja."</string> + <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) --> + <skip /> <string name="lock_to_app_start" msgid="6643342070839862795">"Zaslon je pripet"</string> <string name="lock_to_app_exit" msgid="8598219838213787430">"Zaslon je odpet"</string> <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Pred odpenjanjem vprašaj za PIN"</string> diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml index ecf1958bda4e..7a753eb4b630 100644 --- a/core/res/res/values-sr/strings.xml +++ b/core/res/res/values-sr/strings.xml @@ -797,6 +797,8 @@ <string name="permdesc_accessNotifications" msgid="458457742683431387">"Дозвољава апликацији да преузима, испитује и брише обавештења, укључујући она која постављају друге апликације."</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"повезивање са услугом монитора обавештења"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Дозвољава власнику да се повеже са интерфејсом услуге монитора обавештења највишег нивоа. Уобичајене апликације никада не би требало да је користе."</string> + <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"повежи се са циљном услугом за бирање"</string> + <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Дозвољава власнику да се повеже са интерфејсом највишег нивоа циљне услуге за бирање. Никада не би требало да буде потребна за уобичајене апликације."</string> <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"повежи са услугом добављача услова"</string> <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Дозвољава власнику да се повеже са интерфејсом највишег нивоа услуге добављача услова. Не би требало никада да буде потребно за уобичајене апликације."</string> <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"повезивање са услугом усмеравања медија"</string> @@ -1268,6 +1270,14 @@ <string name="old_app_description" msgid="2082094275580358049">"Не покрећите нову апликацију."</string> <string name="new_app_action" msgid="5472756926945440706">"Покрени <xliff:g id="OLD_APP">%1$s</xliff:g>"</string> <string name="new_app_description" msgid="1932143598371537340">"Зауставља стару апликацију без чувања."</string> + <!-- no translation found for dump_heap_notification (2618183274836056542) --> + <skip /> + <!-- no translation found for dump_heap_notification_detail (2075673362317481664) --> + <skip /> + <!-- no translation found for dump_heap_title (5864292264307651673) --> + <skip /> + <!-- no translation found for dump_heap_text (4809417337240334941) --> + <skip /> <string name="sendText" msgid="5209874571959469142">"Изаберите радњу за текст"</string> <string name="volume_ringtone" msgid="6885421406845734650">"Јачина звука звона"</string> <string name="volume_music" msgid="5421651157138628171">"Јачина звука медија"</string> @@ -1785,7 +1795,9 @@ <item quantity="other">Покушајте поново за <xliff:g id="COUNT">%d</xliff:g> секунди</item> </plurals> <string name="restr_pin_try_later" msgid="973144472490532377">"Покушајте поново касније"</string> - <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Превуците прстом одозго надоле да бисте изашли из целог екрана."</string> + <string name="immersive_cling_title" msgid="8394201622932303336">"Приказује се цео екран"</string> + <string name="immersive_cling_description" msgid="3482371193207536040">"Да бисте изашли, превуците надоле одозго."</string> + <string name="immersive_cling_positive" msgid="5016839404568297683">"Важи"</string> <string name="done_label" msgid="2093726099505892398">"Готово"</string> <string name="hour_picker_description" msgid="6698199186859736512">"Кружни клизач за сате"</string> <string name="minute_picker_description" msgid="8606010966873791190">"Кружни клизач за минуте"</string> @@ -1800,7 +1812,8 @@ <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> на послу"</string> <string name="lock_to_app_toast" msgid="7570091317001980053">"Да бисте откачили овај екран, истовремено додирните и задржите Назад и Преглед."</string> <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Да бисте откачили овај екран, додирните и задржите Преглед."</string> - <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Екран је закачен. Ваша организација не дозвољава откачињање."</string> + <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) --> + <skip /> <string name="lock_to_app_start" msgid="6643342070839862795">"Екран је закачен"</string> <string name="lock_to_app_exit" msgid="8598219838213787430">"Екран је откачен"</string> <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Тражи PIN пре откачињања"</string> diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml index 26a1343392cd..a47cb65ce660 100644 --- a/core/res/res/values-sv/strings.xml +++ b/core/res/res/values-sv/strings.xml @@ -796,6 +796,8 @@ <string name="permdesc_accessNotifications" msgid="458457742683431387">"Tillåter att appen hämtar, granskar och raderar meddelanden, även sådana som skickats av andra appar."</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"binda till en meddelandelyssnare"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Innehavaren tillåts att binda till den översta nivåns gränssnitt för en meddelandelyssnare. Ska inte behövas för vanliga appar."</string> + <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"binda till en målväljartjänst"</string> + <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Innehavaren tillåts att binda till den översta nivåns gränssnitt för en målväljartjänst. Ska inte behövas för vanliga appar."</string> <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"bind till en leverantörstjänst"</string> <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Innehavaren tillåts att binda till den översta nivåns gränssnitt för en leverantörstjänst. Ska inte behövas för vanliga appar."</string> <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"binda till medieruttjänst"</string> @@ -1263,6 +1265,14 @@ <string name="old_app_description" msgid="2082094275580358049">"Starta inte den nya appen."</string> <string name="new_app_action" msgid="5472756926945440706">"Starta <xliff:g id="OLD_APP">%1$s</xliff:g>"</string> <string name="new_app_description" msgid="1932143598371537340">"Avbryt den gamla appen utan att spara."</string> + <!-- no translation found for dump_heap_notification (2618183274836056542) --> + <skip /> + <!-- no translation found for dump_heap_notification_detail (2075673362317481664) --> + <skip /> + <!-- no translation found for dump_heap_title (5864292264307651673) --> + <skip /> + <!-- no translation found for dump_heap_text (4809417337240334941) --> + <skip /> <string name="sendText" msgid="5209874571959469142">"Välj en åtgärd för text"</string> <string name="volume_ringtone" msgid="6885421406845734650">"Ringvolym"</string> <string name="volume_music" msgid="5421651157138628171">"Mediavolym"</string> @@ -1776,7 +1786,9 @@ <item quantity="one">Försök igen om en sekund</item> </plurals> <string name="restr_pin_try_later" msgid="973144472490532377">"Försök igen senare"</string> - <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Dra nedåt om du vill avbryta fullskärmsläget."</string> + <string name="immersive_cling_title" msgid="8394201622932303336">"Visar på fullskärm"</string> + <string name="immersive_cling_description" msgid="3482371193207536040">"Dra nedåt från skärmens överkant för att avsluta."</string> + <string name="immersive_cling_positive" msgid="5016839404568297683">"OK"</string> <string name="done_label" msgid="2093726099505892398">"Klart"</string> <string name="hour_picker_description" msgid="6698199186859736512">"Cirkelreglage för timmar"</string> <string name="minute_picker_description" msgid="8606010966873791190">"Cirkelreglage för minuter"</string> @@ -1791,7 +1803,8 @@ <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> för arbetet"</string> <string name="lock_to_app_toast" msgid="7570091317001980053">"Om du vill lossa skärmen trycker du länge på Tillbaka och Översikt samtidigt."</string> <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Om du vill lossa skämen trycker du länge på Översikt."</string> - <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Skärmen är fäst. Din organisation tillåter inte att du avslutar läget."</string> + <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) --> + <skip /> <string name="lock_to_app_start" msgid="6643342070839862795">"Skärmen är fäst"</string> <string name="lock_to_app_exit" msgid="8598219838213787430">"Skärmen är inte längre fäst"</string> <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Be om pinkod innan skärmen slutar fästas"</string> diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml index 82791e5e05ca..1576c67e28b0 100644 --- a/core/res/res/values-sw/strings.xml +++ b/core/res/res/values-sw/strings.xml @@ -796,6 +796,8 @@ <string name="permdesc_accessNotifications" msgid="458457742683431387">"Huruhusu programu kurejesha, kuchunguza, na kuondoa arifa, ikiwa ni pamoja na zile zilizochapishwa na programu nyingine."</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"unganisha kwenye huduma ya kisikilizi cha arifa"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Inaruhusu kishikilizi kuunganishwa kwenye kusano cha kiwango cha juu cha huduma ya kisikilizi cha arifa. Haipaswi kuhitajika tena kwa programu za kawaida."</string> + <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"bandika kwenye huduma lengwa ya mchaguaji"</string> + <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Huruhusu mmiliki kubandika kwenye kiolesura cha kiwango cha juu cha huduma lengwa ya mchaguaji. Haitahitajika kamwe kwa programu za kawaida."</string> <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"bandika kwenye huduma ya mtoa masharti"</string> <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Humruhusu mmiliki kubandika kwenye kiolesura cha kiwango cha juu cha huduma ya mtoa masharti. Isihitajike kamwe kwa pogramu za kawaida."</string> <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"bandika kwenye huduma ya njia za sauti, picha na video."</string> @@ -1263,6 +1265,14 @@ <string name="old_app_description" msgid="2082094275580358049">"Usianzishe programu mpya."</string> <string name="new_app_action" msgid="5472756926945440706">"Anza <xliff:g id="OLD_APP">%1$s</xliff:g>"</string> <string name="new_app_description" msgid="1932143598371537340">"Komesha programu ya zamani bila kuhifadhi."</string> + <!-- no translation found for dump_heap_notification (2618183274836056542) --> + <skip /> + <!-- no translation found for dump_heap_notification_detail (2075673362317481664) --> + <skip /> + <!-- no translation found for dump_heap_title (5864292264307651673) --> + <skip /> + <!-- no translation found for dump_heap_text (4809417337240334941) --> + <skip /> <string name="sendText" msgid="5209874571959469142">"Chagua kitendo kwa ajili ya maandishi"</string> <string name="volume_ringtone" msgid="6885421406845734650">"Sauti ya mlio"</string> <string name="volume_music" msgid="5421651157138628171">"Sauti ya media"</string> @@ -1776,7 +1786,9 @@ <item quantity="one">Jaribu tena baada ya sekunde 1</item> </plurals> <string name="restr_pin_try_later" msgid="973144472490532377">"Jaribu tena baadaye"</string> - <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Telezesha kidole kwa kasi chini kuanzia juu ili uondoke kwenye skrini zima."</string> + <string name="immersive_cling_title" msgid="8394201622932303336">"Unatazama skrini nzima"</string> + <string name="immersive_cling_description" msgid="3482371193207536040">"Ili kuondoka, telezesha kidole chini kutoka sehemu ya juu."</string> + <string name="immersive_cling_positive" msgid="5016839404568297683">"Nimeelewa"</string> <string name="done_label" msgid="2093726099505892398">"Imekamilika"</string> <string name="hour_picker_description" msgid="6698199186859736512">"Kitelezi cha mviringo wa saa"</string> <string name="minute_picker_description" msgid="8606010966873791190">"Kitelezi cha mviringo wa dakika"</string> @@ -1791,7 +1803,8 @@ <string name="managed_profile_label_badge" msgid="2355652472854327647">"Ya kazini <xliff:g id="LABEL">%1$s</xliff:g>"</string> <string name="lock_to_app_toast" msgid="7570091317001980053">"Ili ubanue skrini hii, gusa na ushikilie Nyuma na Muhtasari kwa wakati mmoja."</string> <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Ili ubanue skrini hii, gusa na ushikilie Muhtasari."</string> - <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Skrini imebandikwa. Ubanduaji hauruhusiwi na shirika lako."</string> + <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) --> + <skip /> <string name="lock_to_app_start" msgid="6643342070839862795">"Skrini imebandikwa"</string> <string name="lock_to_app_exit" msgid="8598219838213787430">"Skrini imebanduliwa"</string> <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Omba PIN kabla hujabandua"</string> diff --git a/core/res/res/values-ta-rIN/strings.xml b/core/res/res/values-ta-rIN/strings.xml index fe4faf04a945..828f36b43ec6 100644 --- a/core/res/res/values-ta-rIN/strings.xml +++ b/core/res/res/values-ta-rIN/strings.xml @@ -796,6 +796,8 @@ <string name="permdesc_accessNotifications" msgid="458457742683431387">"பிற பயன்பாடுகளால் இடுகையிடப்பட்ட அறிவிப்புகள் உள்பட எல்லா அறிவிப்புகளையும் பெற, பார்க்க மற்றும் அழிக்கப் பயன்பாட்டை அனுமதிக்கிறது."</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"அறிவிப்புகளைக் கண்காணிக்கும் சேவையுடன் இணைத்தல்"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"அறிவிப்புகளைக் கண்காணிக்கும் சேவையின் உயர் நிலை இடைமுகத்துடன் இணைப்பதற்கு ஹோல்டரை அனுமதிக்கிறது. இயல்பான பயன்பாடுகளுக்கு எப்போதுமே தேவைப்படாது."</string> + <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"பயனர் தேர்வுசெய்த இடச் சேவையுடன் இணைக்கும்"</string> + <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"பயனர் தேர்வுசெய்த இடச் சேவையின் உயர் நிலை இடைமுகத்துடன் இணைப்பதற்கு, ஹோல்டரை அனுமதிக்கும். இயல்பான பயன்பாடுகளுக்கு எப்போதுமே தேவைப்படாது."</string> <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"நிபந்தனை வழங்குநர் சேவையுடன் இணைத்தல்"</string> <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"நிபந்தனை வழங்குநர் சேவையின் உயர் நிலை இடைமுகத்துடன் இணைப்பதற்கு ஹோல்டரை அனுமதிக்கிறது. சாதாரண பயன்பாடுகளுக்கு எப்போதுமே தேவைப்படாது."</string> <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"மீடியா வழிச் சேவையுடன் இணைத்தல்"</string> @@ -1263,6 +1265,14 @@ <string name="old_app_description" msgid="2082094275580358049">"புதிய பயன்பாட்டைத் தொடங்க வேண்டாம்."</string> <string name="new_app_action" msgid="5472756926945440706">"<xliff:g id="OLD_APP">%1$s</xliff:g> ஐத் தொடங்கு"</string> <string name="new_app_description" msgid="1932143598371537340">"சேமிக்காமல், பழைய பயன்பாட்டை நிறுத்தவும்."</string> + <!-- no translation found for dump_heap_notification (2618183274836056542) --> + <skip /> + <!-- no translation found for dump_heap_notification_detail (2075673362317481664) --> + <skip /> + <!-- no translation found for dump_heap_title (5864292264307651673) --> + <skip /> + <!-- no translation found for dump_heap_text (4809417337240334941) --> + <skip /> <string name="sendText" msgid="5209874571959469142">"உரைக்கான செயலைத் தேர்வுசெய்யவும்"</string> <string name="volume_ringtone" msgid="6885421406845734650">"ரிங்கரின் ஒலியளவு"</string> <string name="volume_music" msgid="5421651157138628171">"மீடியாவின் ஒலியளவு"</string> @@ -1776,7 +1786,9 @@ <item quantity="one">1 வினாடி கழித்து முயற்சிக்கவும்</item> </plurals> <string name="restr_pin_try_later" msgid="973144472490532377">"மீண்டும் முயற்சிக்கவும்"</string> - <string name="immersive_mode_confirmation" msgid="7227416894979047467">"முழுத் திரையிலிருந்து வெளியேற மேலிருந்து கீழே ஸ்வைப் செய்யவும்."</string> + <string name="immersive_cling_title" msgid="8394201622932303336">"முழுத் திரையில் காட்டுகிறது"</string> + <string name="immersive_cling_description" msgid="3482371193207536040">"வெளியேற, மேலிருந்து கீழே ஸ்வைப் செய்யவும்"</string> + <string name="immersive_cling_positive" msgid="5016839404568297683">"புரிந்தது"</string> <string name="done_label" msgid="2093726099505892398">"முடிந்தது"</string> <string name="hour_picker_description" msgid="6698199186859736512">"மணிநேர வட்ட வடிவ ஸ்லைடர்"</string> <string name="minute_picker_description" msgid="8606010966873791190">"நிமிடங்களுக்கான வட்டவடிவ ஸ்லைடர்"</string> @@ -1791,7 +1803,8 @@ <string name="managed_profile_label_badge" msgid="2355652472854327647">"பணியிடம் <xliff:g id="LABEL">%1$s</xliff:g>"</string> <string name="lock_to_app_toast" msgid="7570091317001980053">"இந்தத் திரையை விலக்க, பின் மற்றும் மேலோட்டப் பார்வையை ஒரே நேரத்தில் தொட்டுப் பிடித்திருக்கவும்."</string> <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"இந்தத் திரையை விலக்க, மேலோட்டப் பார்வையைத் தொட்டுப் பிடித்திருக்கவும்."</string> - <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"திரை பின் செய்யப்பட்டது. பின்னை அகற்ற உங்கள் நிறுவனம் ஆதரிக்கவில்லை."</string> + <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) --> + <skip /> <string name="lock_to_app_start" msgid="6643342070839862795">"திரை பின் செய்யப்பட்டது"</string> <string name="lock_to_app_exit" msgid="8598219838213787430">"திரையின் பின் அகற்றப்பட்டது"</string> <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"அகற்றும் முன் PINஐக் கேள்"</string> diff --git a/core/res/res/values-te-rIN/strings.xml b/core/res/res/values-te-rIN/strings.xml index eec41de99abf..af672ccb0e6c 100644 --- a/core/res/res/values-te-rIN/strings.xml +++ b/core/res/res/values-te-rIN/strings.xml @@ -796,6 +796,8 @@ <string name="permdesc_accessNotifications" msgid="458457742683431387">"నోటిఫికేషన్లను, ఇతర అనువర్తనాల ద్వారా పోస్ట్ చేయబడిన వాటిని తిరిగి పొందడానికి, పరిశీలించడానికి మరియు క్లియర్ చేయడానికి అనువర్తనాన్ని అనుమతిస్తుంది."</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"నోటిఫికేషన్ పరిశీలన సేవకు అనుబంధించడం"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"నోటిఫికేషన్ పరిశీలన సేవ యొక్క అగ్ర-స్థాయి ఇంటర్ఫేస్కు అనుబంధించడానికి హోల్డర్ను అనుమతిస్తుంది. సాధారణ అనువర్తనాల కోసం ఎప్పటికీ అవసరం ఉండకూడదు."</string> + <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"ఎంపిక లక్ష్యం సేవకు నిర్బంధించడం"</string> + <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"ఎంపిక లక్ష్యం సేవ అగ్ర-స్థాయి ఇంటర్ఫేస్కు నిర్బంధించడానికి హోల్డర్ను అనుమతిస్తుంది. సాధారణ అనువర్తనాలకు ఎప్పటికీ అవసరం ఉండదు."</string> <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"షరతు ప్రదాత సేవకు అనుబంధించడం"</string> <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"షరతు ప్రదాత సేవ యొక్క అగ్ర-స్థాయి ఇంటర్ఫేస్కు అనుబంధించడానికి హోల్డర్ను అనుమతిస్తుంది. సాధారణ అనువర్తనాలకు ఎప్పటికీ అవసరం ఉండదు."</string> <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"మీడియా మార్గ సేవకు అనుబంధించడం"</string> @@ -1263,6 +1265,14 @@ <string name="old_app_description" msgid="2082094275580358049">"కొత్త అనువర్తనాన్ని ప్రారంభించవద్దు."</string> <string name="new_app_action" msgid="5472756926945440706">"<xliff:g id="OLD_APP">%1$s</xliff:g>ని ప్రారంభించండి"</string> <string name="new_app_description" msgid="1932143598371537340">"పాత అనువర్తనాన్ని సేవ్ చేయకుండానే ఆపివేయండి."</string> + <!-- no translation found for dump_heap_notification (2618183274836056542) --> + <skip /> + <!-- no translation found for dump_heap_notification_detail (2075673362317481664) --> + <skip /> + <!-- no translation found for dump_heap_title (5864292264307651673) --> + <skip /> + <!-- no translation found for dump_heap_text (4809417337240334941) --> + <skip /> <string name="sendText" msgid="5209874571959469142">"వచనం కోసం చర్యను ఎంచుకోండి"</string> <string name="volume_ringtone" msgid="6885421406845734650">"రింగర్ వాల్యూమ్"</string> <string name="volume_music" msgid="5421651157138628171">"మీడియా వాల్యూమ్"</string> @@ -1776,7 +1786,9 @@ <item quantity="one">1 సెకనులో మళ్లీ ప్రయత్నించండి</item> </plurals> <string name="restr_pin_try_later" msgid="973144472490532377">"తర్వాత మళ్లీ ప్రయత్నించండి"</string> - <string name="immersive_mode_confirmation" msgid="7227416894979047467">"పూర్తి స్క్రీన్ నుండి నిష్క్రమించడానికి పైనుండి కిందికి స్వైప్ చేయండి."</string> + <string name="immersive_cling_title" msgid="8394201622932303336">"పూర్తి స్క్రీన్లో వీక్షిస్తున్నారు"</string> + <string name="immersive_cling_description" msgid="3482371193207536040">"నిష్క్రమించడానికి, పై నుండి క్రిందికి స్వైప్ చేయండి."</string> + <string name="immersive_cling_positive" msgid="5016839404568297683">"అర్థమైంది"</string> <string name="done_label" msgid="2093726099505892398">"పూర్తయింది"</string> <string name="hour_picker_description" msgid="6698199186859736512">"గంటల వృత్తాకార స్లయిడర్"</string> <string name="minute_picker_description" msgid="8606010966873791190">"నిమిషాల వృత్తాకార స్లయిడర్"</string> @@ -1791,7 +1803,8 @@ <string name="managed_profile_label_badge" msgid="2355652472854327647">"కార్యాలయం <xliff:g id="LABEL">%1$s</xliff:g>"</string> <string name="lock_to_app_toast" msgid="7570091317001980053">"ఈ స్క్రీన్ను అన్పిన్ చేయడానికి, వెనుకకు మరియు అవలోకనం బటన్లను ఒకేసారి నొక్కి, ఉంచండి."</string> <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"ఈ స్క్రీన్ని అన్పిన్ చేయడానికి, అవలోకనం నొక్కి, ఉంచండి."</string> - <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"స్క్రీన్ పిన్ చేయబడింది. మీ సంస్థలో అన్పిన్ చేయడానికి అనుమతి లేదు."</string> + <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) --> + <skip /> <string name="lock_to_app_start" msgid="6643342070839862795">"స్క్రీన్ పిన్ చేయబడింది"</string> <string name="lock_to_app_exit" msgid="8598219838213787430">"స్క్రీన్ అన్పిన్ చేయబడింది"</string> <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"అన్పిన్ చేయడానికి ముందు పిన్ కోసం అడుగు"</string> diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml index a4071780eb7b..15e70c36f9ff 100644 --- a/core/res/res/values-th/strings.xml +++ b/core/res/res/values-th/strings.xml @@ -796,6 +796,8 @@ <string name="permdesc_accessNotifications" msgid="458457742683431387">"ทำให้แอปสามารถเรียกดู ตรวจสอบ และล้างการแจ้งเตือนได้ ซึ่งรวมถึงการแจ้งเตือนที่โพสต์โดยแอปอื่นๆ ด้วย"</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"เชื่อมโยงกับบริการตัวฟังการแจ้งเตือน"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"อนุญาตให้เจ้าของเชื่อมโยงกับอินเตอร์เฟซระดับสูงสุดของบริการตัวฟังการแจ้งเตือน ซึ่งไม่มีความจำเป็นสำหรับแอปธรรมดา"</string> + <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"เชื่อมโยงกับบริการเป้าหมายของผู้เลือก"</string> + <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"อนุญาตให้แอปเชื่อมโยงกับอินเทอร์เฟซระดับบนสุดของบริการเป้าหมายของผู้เลือก ไม่จำเป็นสำหรับแอปทั่วไป"</string> <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"เชื่อมโยงกับบริการของผู้เสนอเงื่อนไข"</string> <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"อนุญาตให้ผู้ใช้อุปกรณ์เชื่อมโยงกับอินเทอร์เฟซระดับบนสุดของบริการของผู้เสนอเงื่อนไข ไม่จำเป็นสำหรับแอปทั่วไป"</string> <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"เชื่อมโยงกับบริการเส้นทางสื่อ"</string> @@ -1263,6 +1265,14 @@ <string name="old_app_description" msgid="2082094275580358049">"อย่าเริ่มแอปพลิเคชันใหม่"</string> <string name="new_app_action" msgid="5472756926945440706">"เริ่มต้น <xliff:g id="OLD_APP">%1$s</xliff:g>"</string> <string name="new_app_description" msgid="1932143598371537340">"หยุดการทำงานของแอปพลิเคชันเก่าโดยไม่บันทึก"</string> + <!-- no translation found for dump_heap_notification (2618183274836056542) --> + <skip /> + <!-- no translation found for dump_heap_notification_detail (2075673362317481664) --> + <skip /> + <!-- no translation found for dump_heap_title (5864292264307651673) --> + <skip /> + <!-- no translation found for dump_heap_text (4809417337240334941) --> + <skip /> <string name="sendText" msgid="5209874571959469142">"เลือกการทำงานกับข้อความ"</string> <string name="volume_ringtone" msgid="6885421406845734650">"ระดับความดังเสียงเรียกเข้า"</string> <string name="volume_music" msgid="5421651157138628171">"ระดับเสียงของสื่อ"</string> @@ -1776,7 +1786,9 @@ <item quantity="one">ลองอีกครั้งใน 1 วินาที</item> </plurals> <string name="restr_pin_try_later" msgid="973144472490532377">"ลองอีกครั้งในภายหลัง"</string> - <string name="immersive_mode_confirmation" msgid="7227416894979047467">"กวาดนิ้วบนลงล่างเพื่อออกจากโหมดเต็มหน้าจอ"</string> + <string name="immersive_cling_title" msgid="8394201622932303336">"กำลังดูแบบเต็มหน้าจอ"</string> + <string name="immersive_cling_description" msgid="3482371193207536040">"หากต้องการออกไป ให้กวาดนิ้วลงจากด้านบน"</string> + <string name="immersive_cling_positive" msgid="5016839404568297683">"รับทราบ"</string> <string name="done_label" msgid="2093726099505892398">"เสร็จสิ้น"</string> <string name="hour_picker_description" msgid="6698199186859736512">"ตัวเลื่อนหมุนระบุชั่วโมง"</string> <string name="minute_picker_description" msgid="8606010966873791190">"ตัวเลื่อนหมุนระบุนาที"</string> @@ -1791,7 +1803,8 @@ <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g>ที่ทำงาน"</string> <string name="lock_to_app_toast" msgid="7570091317001980053">"หากต้องการเลิกตรึงหน้าจอนี้ แตะ \"กลับ\" และ \"ภาพรวม\" ค้างไว้พร้อมกัน"</string> <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"หากต้องการเลิกตรึงหน้าจอ แตะ \"ภาพรวม\" ค้างไว้"</string> - <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"ตรึงหน้าจอแล้ว องค์กรของคุณไม่อนุญาตให้เลิกตรึง"</string> + <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) --> + <skip /> <string name="lock_to_app_start" msgid="6643342070839862795">"ตรึงหน้าจอแล้ว"</string> <string name="lock_to_app_exit" msgid="8598219838213787430">"เลิกตรึงหน้าจอแล้ว"</string> <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"ขอ PIN ก่อนเลิกตรึง"</string> diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml index 6e0d4fc6021e..f19e06f82af9 100644 --- a/core/res/res/values-tl/strings.xml +++ b/core/res/res/values-tl/strings.xml @@ -796,6 +796,8 @@ <string name="permdesc_accessNotifications" msgid="458457742683431387">"Pinapayagan ang app na kumuha, sumuri, at mag-clear ng mga notification, kabilang ang mga na-post ng iba pang apps."</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"mapailalim sa isang serbisyo ng notification listener"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Nagbibigay-daan sa may-ari na mapailalim sa interface sa tuktok na antas ng isang serbisyo ng notification listener. Hindi dapat kailanganin para sa karaniwang apps kahit kailan."</string> + <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"sumailalim sa isang serbisyo ng chooser target"</string> + <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Nagbibigay-daan sa may-ari na sumailalim sa top-level interface ng isang serbisyo ng chooser target. Hindi dapat kailanman kailanganin para sa mga karaniwang app."</string> <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"i-bind sa isang serbisyo sa pagbibigay ng kundisyon"</string> <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Nagbibigay-daan sa naghahawak na i-bind ang top-level na interface ng isang serbisyo sa pagbibigay ng kundisyon. Hindi kailanman dapat kailanganin ng mga normal na app."</string> <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"mag-bind sa isang serbisyo ng media route"</string> @@ -1263,6 +1265,14 @@ <string name="old_app_description" msgid="2082094275580358049">"Huwag simulan ang bagong app."</string> <string name="new_app_action" msgid="5472756926945440706">"Simulan ang <xliff:g id="OLD_APP">%1$s</xliff:g>"</string> <string name="new_app_description" msgid="1932143598371537340">"Ihinto ang lumang app nang hindi nagse-save."</string> + <!-- no translation found for dump_heap_notification (2618183274836056542) --> + <skip /> + <!-- no translation found for dump_heap_notification_detail (2075673362317481664) --> + <skip /> + <!-- no translation found for dump_heap_title (5864292264307651673) --> + <skip /> + <!-- no translation found for dump_heap_text (4809417337240334941) --> + <skip /> <string name="sendText" msgid="5209874571959469142">"Pumili ng pagkilos para sa teksto"</string> <string name="volume_ringtone" msgid="6885421406845734650">"Lakas ng tunog ng ringer"</string> <string name="volume_music" msgid="5421651157138628171">"Lakas ng tunog ng media"</string> @@ -1776,7 +1786,9 @@ <item quantity="other">Subukang muli sa loob ng <xliff:g id="COUNT">%d</xliff:g> na segundo</item> </plurals> <string name="restr_pin_try_later" msgid="973144472490532377">"Subukang muli sa ibang pagkakataon"</string> - <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Mag-swipe pababa mula sa itaas upang lumabas sa full screen."</string> + <string name="immersive_cling_title" msgid="8394201622932303336">"Panonood sa full screen"</string> + <string name="immersive_cling_description" msgid="3482371193207536040">"Upang lumabas, mag-swipe mula sa itaas pababa."</string> + <string name="immersive_cling_positive" msgid="5016839404568297683">"Nakuha ko"</string> <string name="done_label" msgid="2093726099505892398">"Tapos na"</string> <string name="hour_picker_description" msgid="6698199186859736512">"Pabilog na slider ng mga oras"</string> <string name="minute_picker_description" msgid="8606010966873791190">"Pabilog na slider ng mga minuto"</string> @@ -1791,7 +1803,8 @@ <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> sa Trabaho"</string> <string name="lock_to_app_toast" msgid="7570091317001980053">"Upang i-unpin ang screen na ito, pindutin nang matagal ang Bumalik at Overview nang sabay-sabay."</string> <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Upang i-unpin ang screen na ito, pindutin nang matagal ang Overview."</string> - <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Naka-pin ang screen. Hindi pinapayagan ng iyong organisasyon ang pag-a-unpin."</string> + <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) --> + <skip /> <string name="lock_to_app_start" msgid="6643342070839862795">"Naka-pin ang screen"</string> <string name="lock_to_app_exit" msgid="8598219838213787430">"Naka-unpin ang screen"</string> <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Humingi ng PIN bago mag-unpin"</string> diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml index a49d93d57f9b..1b5bd6c0bd56 100644 --- a/core/res/res/values-tr/strings.xml +++ b/core/res/res/values-tr/strings.xml @@ -796,6 +796,8 @@ <string name="permdesc_accessNotifications" msgid="458457742683431387">"Uygulamanın bildirimler almasına, bildirimleri incelemesine ve temizlemesine izin verir. Buna diğer uygulamalar tarafından yayınlanan bildirimler de dahildir."</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"bildirim dinleyici hizmetine bağlan"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"İzin sahibine bir bildirim dinleyici hizmetinin en üst düzey arayüzüne bağlanma izni verir. Normal uygulamalarda hiçbir zaman gerek duyulmaz."</string> + <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"seçici hedef hizmetine bağlanma"</string> + <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"İzin sahibine bir seçici hedef hizmetinin üst seviye arayüzüne bağlanma olanağı sunar. Normal uygulamalarda hiçbir zaman gerek duyulmaz."</string> <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"bir durum sağlayıcı hizmetine bağlanma"</string> <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"İzin sahibinin, bir durum sağlayıcı hizmete ait üst düzey arayüze bağlanmasına izin verir. Normal uygulamalar için hiçbir zaman gerekli değildir."</string> <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"bir medya yönlendirme hizmetine bağlan"</string> @@ -1263,6 +1265,14 @@ <string name="old_app_description" msgid="2082094275580358049">"Yeni uygulamayı başlatmayın."</string> <string name="new_app_action" msgid="5472756926945440706">"<xliff:g id="OLD_APP">%1$s</xliff:g> uygulamasını başlat"</string> <string name="new_app_description" msgid="1932143598371537340">"Kaydetmeden eski uygulamayı durdurun."</string> + <!-- no translation found for dump_heap_notification (2618183274836056542) --> + <skip /> + <!-- no translation found for dump_heap_notification_detail (2075673362317481664) --> + <skip /> + <!-- no translation found for dump_heap_title (5864292264307651673) --> + <skip /> + <!-- no translation found for dump_heap_text (4809417337240334941) --> + <skip /> <string name="sendText" msgid="5209874571959469142">"Kısa mesaj için bir işlem seçin"</string> <string name="volume_ringtone" msgid="6885421406845734650">"Zil sesi düzeyi"</string> <string name="volume_music" msgid="5421651157138628171">"Medya ses düzeyi"</string> @@ -1776,7 +1786,9 @@ <item quantity="one">1 saniye içinde tekrar deneyin</item> </plurals> <string name="restr_pin_try_later" msgid="973144472490532377">"Daha sonra tekrar deneyin"</string> - <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Tam ekrandan çıkmak için yukarıdan aşağıya hızlıca kaydırın."</string> + <string name="immersive_cling_title" msgid="8394201622932303336">"Tam ekran olarak görüntüleme"</string> + <string name="immersive_cling_description" msgid="3482371193207536040">"Çıkmak için yukarıdan aşağıya doğru hızlıca kaydırın."</string> + <string name="immersive_cling_positive" msgid="5016839404568297683">"Anladım"</string> <string name="done_label" msgid="2093726099505892398">"Bitti"</string> <string name="hour_picker_description" msgid="6698199186859736512">"Saat kaydırma çemberi"</string> <string name="minute_picker_description" msgid="8606010966873791190">"Dakika kaydırma çemberi"</string> @@ -1791,7 +1803,8 @@ <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> (İş)"</string> <string name="lock_to_app_toast" msgid="7570091317001980053">"Bu ekranın sabitlemesini kaldırmak için Geri ve Genel Bakış\'a aynı anda dokunup basılı tutun."</string> <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Bu ekranın sabitlemesini kaldırmak için Genel Bakış\'a dokunup basılı tutun."</string> - <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Ekran sabitlendi. Kuruluşunuz sabitlemenin kaldırılmasına izin vermiyor."</string> + <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) --> + <skip /> <string name="lock_to_app_start" msgid="6643342070839862795">"Ekran sabitlendi"</string> <string name="lock_to_app_exit" msgid="8598219838213787430">"Ekran sabitlemesi kaldırıldı"</string> <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Sabitlemeyi kaldırmadan önce PIN\'i sor"</string> diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml index 4fc776d106dc..306137e77024 100644 --- a/core/res/res/values-uk/strings.xml +++ b/core/res/res/values-uk/strings.xml @@ -798,6 +798,8 @@ <string name="permdesc_accessNotifications" msgid="458457742683431387">"Дозволяє програмі отримувати, перевіряти й очищати сповіщення, зокрема опубліковані іншими програмами."</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"прив’язуватися до служби читання сповіщень"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Дозволяє власнику прив’язуватися до інтерфейсу верхнього рівня служби читання сповіщень. Ніколи не застосовується для звичайних програм."</string> + <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"підключатися до цільової служби для вибору"</string> + <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Додаток зможе підключатися до інтерфейсу верхнього рівня цільової служби для вибору. Звичайні додатки ніколи не використовують цей дозвіл."</string> <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"підключитися до служби постачання умов"</string> <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Додаток зможе підключатися до інтерфейсу верхнього рівня служби постачання умов. Звичайні додатки ніколи не використовують цей дозвіл."</string> <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"підключатися до служби передавання медіафайлів"</string> @@ -1273,6 +1275,14 @@ <string name="old_app_description" msgid="2082094275580358049">"Не запускати нову програму."</string> <string name="new_app_action" msgid="5472756926945440706">"Запуст. <xliff:g id="OLD_APP">%1$s</xliff:g>"</string> <string name="new_app_description" msgid="1932143598371537340">"Зупинити попередню програму без збереження."</string> + <!-- no translation found for dump_heap_notification (2618183274836056542) --> + <skip /> + <!-- no translation found for dump_heap_notification_detail (2075673362317481664) --> + <skip /> + <!-- no translation found for dump_heap_title (5864292264307651673) --> + <skip /> + <!-- no translation found for dump_heap_text (4809417337240334941) --> + <skip /> <string name="sendText" msgid="5209874571959469142">"Виберіть дію для тексту"</string> <string name="volume_ringtone" msgid="6885421406845734650">"Гучність дзвінка"</string> <string name="volume_music" msgid="5421651157138628171">"Гучність медіа"</string> @@ -1794,7 +1804,9 @@ <item quantity="other">Повтор через <xliff:g id="COUNT">%d</xliff:g> секунди</item> </plurals> <string name="restr_pin_try_later" msgid="973144472490532377">"Спробуйте пізніше"</string> - <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Проведіть пальцем зверху вниз, щоб вийти з повноекранного режиму."</string> + <string name="immersive_cling_title" msgid="8394201622932303336">"Перегляд на весь екран"</string> + <string name="immersive_cling_description" msgid="3482371193207536040">"Щоб вийти, проведіть пальцем зверху вниз."</string> + <string name="immersive_cling_positive" msgid="5016839404568297683">"Зрозуміло"</string> <string name="done_label" msgid="2093726099505892398">"Готово"</string> <string name="hour_picker_description" msgid="6698199186859736512">"Вибір годин на циферблаті"</string> <string name="minute_picker_description" msgid="8606010966873791190">"Вибір хвилин на циферблаті"</string> @@ -1809,7 +1821,8 @@ <string name="managed_profile_label_badge" msgid="2355652472854327647">"Робоча <xliff:g id="LABEL">%1$s</xliff:g>"</string> <string name="lock_to_app_toast" msgid="7570091317001980053">"Щоб відкріпити екран, одночасно натисніть і утримуйте кнопки \"Назад\" та \"Огляд\"."</string> <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Щоб відкріпити екран, натисніть і утримуйте кнопку \"Огляд\"."</string> - <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Екран закріплено. Ваша організація заборонила відкріплювати його."</string> + <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) --> + <skip /> <string name="lock_to_app_start" msgid="6643342070839862795">"Екран закріплено"</string> <string name="lock_to_app_exit" msgid="8598219838213787430">"Екран відкріплено"</string> <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Запитувати PIN-код перед відкріпленням"</string> diff --git a/core/res/res/values-ur-rPK/strings.xml b/core/res/res/values-ur-rPK/strings.xml index adc11a602462..596774477a14 100644 --- a/core/res/res/values-ur-rPK/strings.xml +++ b/core/res/res/values-ur-rPK/strings.xml @@ -796,6 +796,8 @@ <string name="permdesc_accessNotifications" msgid="458457742683431387">"دوسرے ایپس کے ذریعے شائع کردہ کے بشمول ایپ کو اطلاعات کی بازیابی، تفتیش اور انہیں صاف کرنے کی اجازت دیتا ہے۔"</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"اطلاع سننے والی سروس کے پابند بنیں"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"حامل کو اطلاع سننے والی سروس کے اعلی سطحی انٹرفیس کا پابند ہونے کی اجازت دیتا ہے۔ عام ایپس کیلئے کبھی بھی اس کی ضرورت نہيں ہونی چاہئے۔"</string> + <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"ایک انتخاب کنندہ کی اہدافی سروس کا پابند بنائیں"</string> + <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"حامل کو ایک انتخاب کنندہ کی اہدافی سروس کے اعلی سطحی انٹرفیس کا پابند بنانے کی اجازت دیتا ہے۔ عام اطلاقات کیلئے کبھی بھی اس کی ضرورت نہيں ہونی چاہئے۔"</string> <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"شرط فراہم کرنے والی ایک سروس کے پابند بنیں"</string> <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"حامل کو شرط فراہم کنندہ کی سروس کے اعلی سطحی انٹرفیس کا پابند ہونے کی اجازت دیتا ہے۔ عام ایپس کیلئے کبھی بھی اس کی ضرورت نہيں ہونی چاہئے۔"</string> <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"میڈیا روٹ سروس کا پابند بنیں"</string> @@ -1263,6 +1265,14 @@ <string name="old_app_description" msgid="2082094275580358049">"نئی ایپ شروع نہ کریں۔"</string> <string name="new_app_action" msgid="5472756926945440706">"<xliff:g id="OLD_APP">%1$s</xliff:g> شروع کریں"</string> <string name="new_app_description" msgid="1932143598371537340">"محفوظ کیے بغیر پرانی ایپ بند کریں۔"</string> + <!-- no translation found for dump_heap_notification (2618183274836056542) --> + <skip /> + <!-- no translation found for dump_heap_notification_detail (2075673362317481664) --> + <skip /> + <!-- no translation found for dump_heap_title (5864292264307651673) --> + <skip /> + <!-- no translation found for dump_heap_text (4809417337240334941) --> + <skip /> <string name="sendText" msgid="5209874571959469142">"متن کیلئے ایک کارروائی منتخب کریں"</string> <string name="volume_ringtone" msgid="6885421406845734650">"رنگر والیوم"</string> <string name="volume_music" msgid="5421651157138628171">"میڈیا والیوم"</string> @@ -1776,7 +1786,9 @@ <item quantity="one">1 سیکنڈ میں دوبارہ کوشش کریں</item> </plurals> <string name="restr_pin_try_later" msgid="973144472490532377">"بعد میں دوبارہ کوشش کریں"</string> - <string name="immersive_mode_confirmation" msgid="7227416894979047467">"مکمل اسکرین سے نکلنے کیلئے اوپر سے نیچے سوائپ کریں۔"</string> + <string name="immersive_cling_title" msgid="8394201622932303336">"پوری اسکرین میں دیکھ رہے ہیں"</string> + <string name="immersive_cling_description" msgid="3482371193207536040">"خارج ہونے کیلئے اوپر سے نیچے سوائپ کریں۔"</string> + <string name="immersive_cling_positive" msgid="5016839404568297683">"سمجھ آ گئی"</string> <string name="done_label" msgid="2093726099505892398">"ہو گیا"</string> <string name="hour_picker_description" msgid="6698199186859736512">"گھنٹوں کا سرکلر سلائیڈر"</string> <string name="minute_picker_description" msgid="8606010966873791190">"منٹس سرکلر سلائیڈر"</string> @@ -1791,7 +1803,8 @@ <string name="managed_profile_label_badge" msgid="2355652472854327647">"دفتر <xliff:g id="LABEL">%1$s</xliff:g>"</string> <string name="lock_to_app_toast" msgid="7570091317001980053">"اس اسکرین سے پن ہٹانے کیلئے، واپس جائیں اور مجموعی جائزہ کو ایک ساتھ ٹچ کریں اور دبا کر رکھیں۔"</string> <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"اس اسکرین سے پن ہٹانے کیلئے، مجموعی جائزہ کو ٹچ کریں اور دبا کر رکھیں۔"</string> - <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"اسکرین کو پن کر دیا گیا ہے۔ آپ کی تنظیم کی جانب سے پن ہٹانے کی اجازت نہیں ہے۔"</string> + <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) --> + <skip /> <string name="lock_to_app_start" msgid="6643342070839862795">"اسکرین کو پن کر دیا گیا"</string> <string name="lock_to_app_exit" msgid="8598219838213787430">"اسکرین کا پن ہٹا دیا گیا"</string> <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"پن ہٹانے سے پہلے PIN طلب کریں"</string> diff --git a/core/res/res/values-uz-rUZ/strings.xml b/core/res/res/values-uz-rUZ/strings.xml index 27237f5457e6..812f34eb7b43 100644 --- a/core/res/res/values-uz-rUZ/strings.xml +++ b/core/res/res/values-uz-rUZ/strings.xml @@ -796,6 +796,8 @@ <string name="permdesc_accessNotifications" msgid="458457742683431387">"Dasturga bildirishnomalar va boshqa dasturlar jo‘natgan xabarlarni qabul qilish, ko‘rib chiqish hamda tozalash imkonini beradi."</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"bildirishnomani tinglash xizmatiga bog‘lash"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Foydalanuvchiga bildirishnomani eshituvchi xizmat yuqori darajali interfeysini bog‘lash imkonini beradi. Oddiy dasturlar uchun hech qachon kerak bo‘lmaydi."</string> + <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"mo‘ljaldagi xizmat bilan bog‘lanish"</string> + <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Egasiga mo‘ljaldagi xizmatning yuqori darajali interfeysiga bog‘lanish uchun ruxsat beradi. Oddiy ilovalar uchun hech qachon kerak bo‘lmaydi."</string> <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"shartlarni taqdim etuvchilarning serveriga ulanish"</string> <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Ilova shartlarni taqdim etuvchining yuqori darajali interfeysiga ulanishi mumkin. Oddiy ilovalar uchun talab qilinmaydi."</string> <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"media fayllarni uzatish vositasiga bog‘lab qo‘yish"</string> @@ -1263,6 +1265,14 @@ <string name="old_app_description" msgid="2082094275580358049">"Yangi ilova ishga tushirilmasin."</string> <string name="new_app_action" msgid="5472756926945440706">"<xliff:g id="OLD_APP">%1$s</xliff:g>ni ishga tushirish"</string> <string name="new_app_description" msgid="1932143598371537340">"O‘zgarishlarni saqlamasdan, eski ilova yopilsin"</string> + <!-- no translation found for dump_heap_notification (2618183274836056542) --> + <skip /> + <!-- no translation found for dump_heap_notification_detail (2075673362317481664) --> + <skip /> + <!-- no translation found for dump_heap_title (5864292264307651673) --> + <skip /> + <!-- no translation found for dump_heap_text (4809417337240334941) --> + <skip /> <string name="sendText" msgid="5209874571959469142">"Matn uchun amalni tanlash"</string> <string name="volume_ringtone" msgid="6885421406845734650">"Qo‘ng‘iroq tovushi"</string> <string name="volume_music" msgid="5421651157138628171">"Media tovushi"</string> @@ -1776,7 +1786,9 @@ <item quantity="one">1 soniyadan so‘ng qayta urinib ko‘ring</item> </plurals> <string name="restr_pin_try_later" msgid="973144472490532377">"Keyinroq urinib ko‘ring"</string> - <string name="immersive_mode_confirmation" msgid="7227416894979047467">"\"Butun ekran\" usulidan chiqish uchun barmoq bilan ekran tepasidan pastga tomon silang."</string> + <string name="immersive_cling_title" msgid="8394201622932303336">"To‘liq ekran ko‘rsatilmoqda"</string> + <string name="immersive_cling_description" msgid="3482371193207536040">"Chiqish uchun tepadan pastga torting."</string> + <string name="immersive_cling_positive" msgid="5016839404568297683">"OK"</string> <string name="done_label" msgid="2093726099505892398">"Tayyor"</string> <string name="hour_picker_description" msgid="6698199186859736512">"Doiradan soatni tanlang"</string> <string name="minute_picker_description" msgid="8606010966873791190">"Doiradan daqiqani tanlang"</string> @@ -1791,7 +1803,8 @@ <string name="managed_profile_label_badge" msgid="2355652472854327647">"Ish <xliff:g id="LABEL">%1$s</xliff:g>"</string> <string name="lock_to_app_toast" msgid="7570091317001980053">"Ushbu ekrandan chiqish uchun “Orqaga” va “Umumiy nazar” tugmalarini bir vaqtda bosib turing."</string> <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Ushbu ekrandan chiqish uchun “Umumiy nazar” tugmasini bosib turing."</string> - <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Ekran qadab qo‘yildi. Uni bo‘shatishga tashkilotingiz ruxsat bermagan."</string> + <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) --> + <skip /> <string name="lock_to_app_start" msgid="6643342070839862795">"Ekran qadab qo‘yildi"</string> <string name="lock_to_app_exit" msgid="8598219838213787430">"Ekran bo‘shatildi"</string> <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Bo‘shatishdan oldin PIN kod so‘ralsin"</string> diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml index ce5fc5a418fa..8c8c30530f61 100644 --- a/core/res/res/values-vi/strings.xml +++ b/core/res/res/values-vi/strings.xml @@ -796,6 +796,8 @@ <string name="permdesc_accessNotifications" msgid="458457742683431387">"Cho phép ứng dụng truy xuất, kiểm tra và xóa thông báo, bao gồm những thông báo được đăng bởi các ứng dụng khác."</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"liên kết với dịch vụ trình xử lý thông báo"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Cho phép chủ sở hữu liên kết với giao diện cấp cao nhất của dịch vụ trình xử lý thông báo. Không cần thiết cho các ứng dụng thông thường."</string> + <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"liên kết với dịch vụ nhắm mục tiêu trình chọn"</string> + <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Cho phép chủ sở hữu liên kết với giao diện cấp cao nhất của dịch vụ nhắm mục tiêu trình chọn. Không cần thiết cho các ứng dụng thông thường."</string> <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"liên kết với dịch vụ trình cung cấp điều kiện"</string> <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Cho phép chủ sở hữu liên kết với giao diện cấp cao nhất của dịch vụ trình cung cấp điều kiện. Không cần thiết cho các ứng dụng thông thường."</string> <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"liên kết với dịch vụ định tuyến phương tiện"</string> @@ -1263,6 +1265,14 @@ <string name="old_app_description" msgid="2082094275580358049">"Không khởi động ứng dụng mới."</string> <string name="new_app_action" msgid="5472756926945440706">"Bắt đầu <xliff:g id="OLD_APP">%1$s</xliff:g>"</string> <string name="new_app_description" msgid="1932143598371537340">"Dừng ứng dụng cũ mà không lưu."</string> + <!-- no translation found for dump_heap_notification (2618183274836056542) --> + <skip /> + <!-- no translation found for dump_heap_notification_detail (2075673362317481664) --> + <skip /> + <!-- no translation found for dump_heap_title (5864292264307651673) --> + <skip /> + <!-- no translation found for dump_heap_text (4809417337240334941) --> + <skip /> <string name="sendText" msgid="5209874571959469142">"Chọn một tác vụ cho văn bản"</string> <string name="volume_ringtone" msgid="6885421406845734650">"Âm lượng chuông"</string> <string name="volume_music" msgid="5421651157138628171">"Âm lượng phương tiện"</string> @@ -1776,7 +1786,9 @@ <item quantity="one">Hãy thử lại sau 1 giây</item> </plurals> <string name="restr_pin_try_later" msgid="973144472490532377">"Hãy thử lại sau"</string> - <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Vuốt từ trên xuống để thoát toàn màn hình."</string> + <string name="immersive_cling_title" msgid="8394201622932303336">"Xem toàn màn hình"</string> + <string name="immersive_cling_description" msgid="3482371193207536040">"Để thoát, hãy vuốt xuống từ trên cùng."</string> + <string name="immersive_cling_positive" msgid="5016839404568297683">"OK"</string> <string name="done_label" msgid="2093726099505892398">"Xong"</string> <string name="hour_picker_description" msgid="6698199186859736512">"Thanh trượt giờ hình tròn"</string> <string name="minute_picker_description" msgid="8606010966873791190">"Thanh trượt phút hình tròn"</string> @@ -1791,7 +1803,8 @@ <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> làm việc"</string> <string name="lock_to_app_toast" msgid="7570091317001980053">"Để bỏ khóa màn hình này, chạm và giữ Quay lại và Tổng quan cùng lúc."</string> <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Để bỏ khóa màn hình này, chạm và giữ Tổng quan."</string> - <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Màn hình đã được ghim. Tổ chức của bạn không cho phép bỏ ghim."</string> + <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) --> + <skip /> <string name="lock_to_app_start" msgid="6643342070839862795">"Đã ghim màn hình"</string> <string name="lock_to_app_exit" msgid="8598219838213787430">"Đã bỏ ghim màn hình"</string> <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Hỏi mã PIN trước khi bỏ ghim"</string> diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml index 507e53050ad1..497a9dc54606 100644 --- a/core/res/res/values-zh-rCN/strings.xml +++ b/core/res/res/values-zh-rCN/strings.xml @@ -738,14 +738,10 @@ <string name="permdesc_nfc" msgid="7120611819401789907">"允许应用与近距离无线通信(NFC)标签、卡和读取器通信。"</string> <string name="permlab_disableKeyguard" msgid="3598496301486439258">"停用屏幕锁定"</string> <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"允许该应用停用键锁以及任何关联的密码安全措施。例如,让手机在接听来电时停用键锁,在通话结束后重新启用键锁。"</string> - <!-- no translation found for permlab_manageFingerprint (5640858826254575638) --> - <skip /> - <!-- no translation found for permdesc_manageFingerprint (178208705828055464) --> - <skip /> - <!-- no translation found for permlab_useFingerprint (3150478619915124905) --> - <skip /> - <!-- no translation found for permdesc_useFingerprint (9165097460730684114) --> - <skip /> + <string name="permlab_manageFingerprint" msgid="5640858826254575638">"管理指纹硬件"</string> + <string name="permdesc_manageFingerprint" msgid="178208705828055464">"允许该应用调用方法来添加和删除可用的指纹模板。"</string> + <string name="permlab_useFingerprint" msgid="3150478619915124905">"使用指纹硬件"</string> + <string name="permdesc_useFingerprint" msgid="9165097460730684114">"允许该应用使用指纹硬件进行身份验证"</string> <string name="permlab_readSyncSettings" msgid="6201810008230503052">"读取同步设置"</string> <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"允许该应用读取某个帐户的同步设置。例如,此权限可确定“联系人”应用是否与某个帐户同步。"</string> <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"启用和停用同步"</string> @@ -800,6 +796,10 @@ <string name="permdesc_accessNotifications" msgid="458457742683431387">"允许该应用检索、检查并清除通知,包括其他应用发布的通知。"</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"绑定到通知侦听器服务"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"允许应用绑定到通知侦听器服务的顶级接口(普通应用绝不需要此权限)。"</string> + <!-- no translation found for permlab_bindChooserTargetService (3443261076710185673) --> + <skip /> + <!-- no translation found for permdesc_bindChooserTargetService (1413908999583734970) --> + <skip /> <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"绑定到条件提供程序服务"</string> <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"允许应用绑定到条件提供程序服务的顶级接口。普通应用绝不需要此权限。"</string> <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"绑定至媒体转接服务"</string> @@ -1267,6 +1267,14 @@ <string name="old_app_description" msgid="2082094275580358049">"不启动新的应用。"</string> <string name="new_app_action" msgid="5472756926945440706">"启动<xliff:g id="OLD_APP">%1$s</xliff:g>"</string> <string name="new_app_description" msgid="1932143598371537340">"停止旧的应用,但不保存。"</string> + <!-- no translation found for dump_heap_notification (2618183274836056542) --> + <skip /> + <!-- no translation found for dump_heap_notification_detail (2075673362317481664) --> + <skip /> + <!-- no translation found for dump_heap_title (5864292264307651673) --> + <skip /> + <!-- no translation found for dump_heap_text (4809417337240334941) --> + <skip /> <string name="sendText" msgid="5209874571959469142">"选择要对文字执行的操作"</string> <string name="volume_ringtone" msgid="6885421406845734650">"铃声音量"</string> <string name="volume_music" msgid="5421651157138628171">"媒体音量"</string> @@ -1780,7 +1788,12 @@ <item quantity="one">1 秒后重试</item> </plurals> <string name="restr_pin_try_later" msgid="973144472490532377">"稍后重试"</string> - <string name="immersive_mode_confirmation" msgid="7227416894979047467">"从顶部向下滑动即可退出全屏模式。"</string> + <!-- no translation found for immersive_cling_title (8394201622932303336) --> + <skip /> + <!-- no translation found for immersive_cling_description (3482371193207536040) --> + <skip /> + <!-- no translation found for immersive_cling_positive (5016839404568297683) --> + <skip /> <string name="done_label" msgid="2093726099505892398">"完成"</string> <string name="hour_picker_description" msgid="6698199186859736512">"小时转盘"</string> <string name="minute_picker_description" msgid="8606010966873791190">"分钟转盘"</string> @@ -1795,7 +1808,8 @@ <string name="managed_profile_label_badge" msgid="2355652472854327647">"工作<xliff:g id="LABEL">%1$s</xliff:g>"</string> <string name="lock_to_app_toast" msgid="7570091317001980053">"要取消固定此屏幕,请同时触摸并按住“返回”和“概览”按钮。"</string> <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"要取消固定此屏幕,请触摸并按住概览按钮。"</string> - <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"屏幕处于固定状态。您所属的单位不允许取消固定。"</string> + <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) --> + <skip /> <string name="lock_to_app_start" msgid="6643342070839862795">"已固定屏幕"</string> <string name="lock_to_app_exit" msgid="8598219838213787430">"已取消固定屏幕"</string> <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"取消时要求输入PIN码"</string> diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml index c60a1bee2586..2f6f3fec0909 100644 --- a/core/res/res/values-zh-rHK/strings.xml +++ b/core/res/res/values-zh-rHK/strings.xml @@ -796,6 +796,8 @@ <string name="permdesc_accessNotifications" msgid="458457742683431387">"允許應用程式擷取、檢查及清除通知 (包括由其他應用程式發佈的通知)。"</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"繫結至通知接聽器服務"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"允許應用程式繫結至通知接聽器服務的頂層介面 (不建議一般應用程式使用)。"</string> + <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"繫結至所選服務"</string> + <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"允許應用程式繫結至所選服務的頂層介面 (一般應用程式並不需要)。"</string> <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"繫結至條件供應商服務"</string> <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"允許應用程式繫結至條件供應商服務的頂層介面,但一般應用程式並不需要使用。"</string> <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"繫結至媒體轉送服務"</string> @@ -1263,6 +1265,14 @@ <string name="old_app_description" msgid="2082094275580358049">"請勿啟動新的應用程式。"</string> <string name="new_app_action" msgid="5472756926945440706">"啟動 <xliff:g id="OLD_APP">%1$s</xliff:g>"</string> <string name="new_app_description" msgid="1932143598371537340">"停止舊的應用程式,且不儲存。"</string> + <!-- no translation found for dump_heap_notification (2618183274836056542) --> + <skip /> + <!-- no translation found for dump_heap_notification_detail (2075673362317481664) --> + <skip /> + <!-- no translation found for dump_heap_title (5864292264307651673) --> + <skip /> + <!-- no translation found for dump_heap_text (4809417337240334941) --> + <skip /> <string name="sendText" msgid="5209874571959469142">"選擇處理文字的操作"</string> <string name="volume_ringtone" msgid="6885421406845734650">"鈴聲音量"</string> <string name="volume_music" msgid="5421651157138628171">"媒體音量"</string> @@ -1776,7 +1786,9 @@ <item quantity="one">1 秒後再試一次</item> </plurals> <string name="restr_pin_try_later" msgid="973144472490532377">"稍後再試"</string> - <string name="immersive_mode_confirmation" msgid="7227416894979047467">"由頂端往下快速滑動即可離開全螢幕。"</string> + <string name="immersive_cling_title" msgid="8394201622932303336">"開啟全螢幕"</string> + <string name="immersive_cling_description" msgid="3482371193207536040">"由上往下刷退出。"</string> + <string name="immersive_cling_positive" msgid="5016839404568297683">"知道了"</string> <string name="done_label" msgid="2093726099505892398">"完成"</string> <string name="hour_picker_description" msgid="6698199186859736512">"小時環形滑桿"</string> <string name="minute_picker_description" msgid="8606010966873791190">"分鐘環形滑桿"</string> @@ -1791,7 +1803,8 @@ <string name="managed_profile_label_badge" msgid="2355652472854327647">"公司<xliff:g id="LABEL">%1$s</xliff:g>"</string> <string name="lock_to_app_toast" msgid="7570091317001980053">"如要取消固定這個畫面,請同時輕觸並按住 [返回] 和 [概覽]。"</string> <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"如要取消固定這個畫面,請輕觸並按住 [概覽]。"</string> - <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"螢幕已固定,而您的機構不允許取消固定。"</string> + <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) --> + <skip /> <string name="lock_to_app_start" msgid="6643342070839862795">"螢幕已固定"</string> <string name="lock_to_app_exit" msgid="8598219838213787430">"已取消固定螢幕"</string> <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"取消固定時必須輸入 PIN"</string> diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml index 6925d9f09d77..35421aee99b2 100644 --- a/core/res/res/values-zh-rTW/strings.xml +++ b/core/res/res/values-zh-rTW/strings.xml @@ -796,6 +796,8 @@ <string name="permdesc_accessNotifications" msgid="458457742683431387">"允許應用程式擷取、檢查及清除通知 (包括由其他應用程式發佈的通知)。"</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"繫結至通知接聽器服務"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"允許應用程式繫結至通知接聽器服務的頂層介面 (一般應用程式不需使用)。"</string> + <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"與選擇器目標服務繫結"</string> + <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"允許應用程式繫結至選擇器目標服務的頂層介面 (一般應用程式並不需要)。"</string> <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"繫結至條件提供者服務"</string> <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"允許應用程式繫結至條件提供者服務的頂層介面 (一般應用程式並不需要)。"</string> <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"繫結至媒體轉送服務"</string> @@ -1263,6 +1265,14 @@ <string name="old_app_description" msgid="2082094275580358049">"請勿啟動新的應用程式。"</string> <string name="new_app_action" msgid="5472756926945440706">"啟動 <xliff:g id="OLD_APP">%1$s</xliff:g>"</string> <string name="new_app_description" msgid="1932143598371537340">"停止舊的應用程式且不儲存。"</string> + <!-- no translation found for dump_heap_notification (2618183274836056542) --> + <skip /> + <!-- no translation found for dump_heap_notification_detail (2075673362317481664) --> + <skip /> + <!-- no translation found for dump_heap_title (5864292264307651673) --> + <skip /> + <!-- no translation found for dump_heap_text (4809417337240334941) --> + <skip /> <string name="sendText" msgid="5209874571959469142">"選取傳送文字內容的方式"</string> <string name="volume_ringtone" msgid="6885421406845734650">"鈴聲音量"</string> <string name="volume_music" msgid="5421651157138628171">"媒體音量"</string> @@ -1776,7 +1786,9 @@ <item quantity="one">請於 1 秒後再試一次</item> </plurals> <string name="restr_pin_try_later" msgid="973144472490532377">"稍後再試"</string> - <string name="immersive_mode_confirmation" msgid="7227416894979047467">"從頂端往下滑動即可退出全螢幕模式。"</string> + <string name="immersive_cling_title" msgid="8394201622932303336">"以全螢幕檢視"</string> + <string name="immersive_cling_description" msgid="3482371193207536040">"如要退出,請從畫面頂端向下滑動。"</string> + <string name="immersive_cling_positive" msgid="5016839404568297683">"知道了"</string> <string name="done_label" msgid="2093726099505892398">"完成"</string> <string name="hour_picker_description" msgid="6698199186859736512">"小時數環狀滑桿"</string> <string name="minute_picker_description" msgid="8606010966873791190">"分鐘數環狀滑桿"</string> @@ -1791,7 +1803,8 @@ <string name="managed_profile_label_badge" msgid="2355652472854327647">"公司<xliff:g id="LABEL">%1$s</xliff:g>"</string> <string name="lock_to_app_toast" msgid="7570091317001980053">"如要取消固定這個畫面,請同時輕觸並按住返回按鈕和總覽按鈕。"</string> <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"如要取消固定這個畫面,請輕觸並按住總覽按鈕。"</string> - <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"螢幕已固定,且貴機構不允許取消固定。"</string> + <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) --> + <skip /> <string name="lock_to_app_start" msgid="6643342070839862795">"已固定螢幕"</string> <string name="lock_to_app_exit" msgid="8598219838213787430">"已取消固定螢幕"</string> <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"取消固定時必須輸入 PIN"</string> diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml index 1313a5a5412b..98b9e73dc133 100644 --- a/core/res/res/values-zu/strings.xml +++ b/core/res/res/values-zu/strings.xml @@ -796,6 +796,8 @@ <string name="permdesc_accessNotifications" msgid="458457742683431387">"Ivumela uhlelo lokusebenza ukuthi lithole, lihlole, liphinde lisuse izaziso, ezifaka lezo ezithunyelwe ezinye izinhlelo zokusebenza."</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"bophezela kwisevisi yomlaleli wesaziso"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Ivumela umbambi ukubophezela kwisixhumi esibonakalayo sezinga eliphezulu lesevisi yomlaleli wesaziso. Akusoze kwadingeka kwizinhlelo zokusebenza ezivamile."</string> + <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"bophezela isevisi eqondisiwe yesikhethi"</string> + <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Ivumela umbambi ukuthi ahlanganise kuleveli ephezulu yesevisi yesikhethi. Akudingeki kuzinhlelo zokusebenza ezimvamile."</string> <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"hlanganisa kwisevisi yomhlinzeki wesimo"</string> <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Ivumela umbambi ukuhlanganisa isixhumi esibonakalayo seleveli ephezulu sesevisi yomhlinzeki wesimo. Akufanele kudingekele izinhlelo zokusebenza ezivamile."</string> <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"hlanganisela kusevisi yomzila yemidiya"</string> @@ -1263,6 +1265,14 @@ <string name="old_app_description" msgid="2082094275580358049">"Ungayiqali uhlelo lokusebenza entsha."</string> <string name="new_app_action" msgid="5472756926945440706">"Qala <xliff:g id="OLD_APP">%1$s</xliff:g>"</string> <string name="new_app_description" msgid="1932143598371537340">"Misa uhlelo lokusebenza endala ngaphandle kokulondoloza."</string> + <!-- no translation found for dump_heap_notification (2618183274836056542) --> + <skip /> + <!-- no translation found for dump_heap_notification_detail (2075673362317481664) --> + <skip /> + <!-- no translation found for dump_heap_title (5864292264307651673) --> + <skip /> + <!-- no translation found for dump_heap_text (4809417337240334941) --> + <skip /> <string name="sendText" msgid="5209874571959469142">"Khetha okufanele kwenziwe okomqhafazo"</string> <string name="volume_ringtone" msgid="6885421406845734650">"Ivolumu yesishayeli"</string> <string name="volume_music" msgid="5421651157138628171">"Ivolumu yemidiya"</string> @@ -1776,7 +1786,9 @@ <item quantity="other">Zama futhi kumasekhondi angu-<xliff:g id="COUNT">%d</xliff:g></item> </plurals> <string name="restr_pin_try_later" msgid="973144472490532377">"Zama futhi emva kwesikhathi"</string> - <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Swayiphela phansi kusukela phezulu ukuze uphume kusikrini esigcwele."</string> + <string name="immersive_cling_title" msgid="8394201622932303336">"Ukubuka isikrini esigcwele"</string> + <string name="immersive_cling_description" msgid="3482371193207536040">"Ukuze uphume, swayiphela phansi kusuka phezulu."</string> + <string name="immersive_cling_positive" msgid="5016839404568297683">"Ngiyitholile"</string> <string name="done_label" msgid="2093726099505892398">"Kwenziwe"</string> <string name="hour_picker_description" msgid="6698199186859736512">"Amahora weslayidi esiyindingilizi"</string> <string name="minute_picker_description" msgid="8606010966873791190">"Amaminithi weslayidi esiyindingilizi"</string> @@ -1791,7 +1803,8 @@ <string name="managed_profile_label_badge" msgid="2355652472854327647">"Umsebenzi <xliff:g id="LABEL">%1$s</xliff:g>"</string> <string name="lock_to_app_toast" msgid="7570091317001980053">"Ukuze ususe ukuphina kulesi sikrini, thinta uphinde ubambe i-Emuva ne-Buka konke ngesikhathi esisodwa."</string> <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Ukuze ususe ukuphina lesi sikrini, thinta uphinde ubambe Buka konke."</string> - <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Isikrini siphiniwe. Ukususa ukuphina akuvumelekile inhlangano yakho."</string> + <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) --> + <skip /> <string name="lock_to_app_start" msgid="6643342070839862795">"Isikrini siphiniwe"</string> <string name="lock_to_app_exit" msgid="8598219838213787430">"Isikrini sisuswe ukuphina"</string> <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Cela iphinikhodi ngaphambi kokuphina"</string> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index a383359ca0f6..3ca88e5b0ed3 100755 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -515,6 +515,8 @@ <bool name="config_allowTheaterModeWakeFromWindowLayout">false</bool> <!-- If this is true, go to sleep when theater mode is enabled from button press --> <bool name="config_goToSleepOnButtonPressTheaterMode">true</bool> + <!-- If this is true, long press on power button will be available from the non-interactive state --> + <bool name="config_supportLongPressPowerWhenNonInteractive">false</bool> <!-- Auto-rotation behavior --> @@ -2078,4 +2080,7 @@ <!-- Specifies the maximum burn-in offset vertically. --> <integer name="config_burnInProtectionMaxVerticalOffset">0</integer> + + <!-- Keyguard component --> + <string name="config_keyguardComponent" translatable="false">com.android.systemui/com.android.systemui.keyguard.KeyguardService</string> </resources> diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index 67ce15931e74..bf370f44fb1d 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -3715,6 +3715,23 @@ <string name="new_app_action">Start <xliff:g id="old_app">%1$s</xliff:g></string> <string name="new_app_description">Stop the old app without saving.</string> + <!-- Notification text to tell the user that a process has exceeded its memory limit. --> + <string name="dump_heap_notification"><xliff:g id="proc">%1$s</xliff:g> exceeded memory + limit</string> + + <!-- Notification details to tell the user that a process has exceeded its memory limit. --> + <string name="dump_heap_notification_detail">Heap dump has been collected; + touch to share</string> + + <!-- Title of dialog prompting the user to share a heap dump. --> + <string name="dump_heap_title">Share heap dump?</string> + + <!-- Text of dialog prompting the user to share a heap dump. --> + <string name="dump_heap_text">The process <xliff:g id="proc">%1$s</xliff:g> has exceeded + its process memory limit of <xliff:g id="size">%2$s</xliff:g>. A heap dump is available + for you to share with its developer. Be careful: this heap dump can contain any + of your personal information that the application has access to.</string> + <!-- Displayed in the title of the chooser for things to do with text that is to be sent to another application. For example, I can send text through SMS or IM. A dialog with those choices would be shown, diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 078c12fd6647..f16c5cfbca2b 100755 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -1603,6 +1603,7 @@ <java-symbol type="bool" name="config_allowTheaterModeWakeFromDock" /> <java-symbol type="bool" name="config_allowTheaterModeWakeFromWindowLayout" /> <java-symbol type="bool" name="config_goToSleepOnButtonPressTheaterMode" /> + <java-symbol type="bool" name="config_supportLongPressPowerWhenNonInteractive" /> <java-symbol type="bool" name="config_wifi_background_scan_support" /> <java-symbol type="bool" name="config_wifi_dual_band_support" /> <java-symbol type="bool" name="config_wimaxEnabled" /> @@ -1723,6 +1724,10 @@ <java-symbol type="string" name="data_usage_wifi_limit_title" /> <java-symbol type="string" name="default_wallpaper_component" /> <java-symbol type="string" name="dlg_ok" /> + <java-symbol type="string" name="dump_heap_notification" /> + <java-symbol type="string" name="dump_heap_notification_detail" /> + <java-symbol type="string" name="dump_heap_text" /> + <java-symbol type="string" name="dump_heap_title" /> <java-symbol type="string" name="factorytest_failed" /> <java-symbol type="string" name="factorytest_no_action" /> <java-symbol type="string" name="factorytest_not_system" /> @@ -2044,6 +2049,9 @@ <java-symbol type="array" name="config_clockTickVibePattern" /> <java-symbol type="array" name="config_calendarDateVibePattern" /> + <!-- From KeyguardServiceDelegate --> + <java-symbol type="string" name="config_keyguardComponent" /> + <!-- From various Material changes --> <java-symbol type="attr" name="titleTextAppearance" /> <java-symbol type="attr" name="subtitleTextAppearance" /> diff --git a/docs/html/google/play-services/wallet.jd b/docs/html/google/play-services/wallet.jd index 3d0c64af69b9..744c8d367881 100644 --- a/docs/html/google/play-services/wallet.jd +++ b/docs/html/google/play-services/wallet.jd @@ -17,14 +17,14 @@ header.hide=1 available to US-based merchants. Once you've completed integration, you can apply for production access by <a class="external-link" href="https://support.google.com/wallet/business/contact/ui_review">submitting your sandbox integration for review</a>.</p> - <p>Check out the <a + <p>Check out the <a href="{@docRoot}reference/com/google/android/gms/wallet/package-summary.html">Instant Buy API reference</a> and visit <a href="https://developers.google.com/wallet/instant-buy/">developers.google.com/wallet/instant-buy/</a> for complete information about integrating Google Wallet Instant Buy into your app.</p> </div> -<div class="col-4"> +<div class="col-4"> <img src="{@docRoot}images/google/gps-wallet-instant.png" alt="" style="padding-bottom:14px;width:210px"> </div> </div> @@ -44,16 +44,16 @@ header.hide=1 <h4>Streamline Purchases with Google+ Sign-On</h4> <p>For users ready to purchase, you can simplify the login and account creation steps by adding Google+ sign in. Users can sign in with a single click and share their - profile information during the purchase. + profile information during the purchase. <br /> <a href="https://developers.google.com/commerce/wallet/instant-buy/wallet-sso#android" class="external-link">Add Google+ Sign-In for Wallet</a>.</p> - + <h4>Minimize User Data Entry</h4> <p>Google Wallet provides auto-completion of addresses, minimizing user data entry. You can also retrieve billing and shipping addresses directly from the user’s Wallet to-do form pre-fills.<br /> <a class="external-link" - href="{@docRoot}reference/com/google/android/gms/wallet/MaskedWallet#getBillingAddress()">Get + href="{@docRoot}reference/com/google/android/gms/wallet/MaskedWallet.html#getBillingAddress()">Get billing addresses</a>.</p> </div> @@ -75,7 +75,7 @@ header.hide=1 class="external-link" href="https://developers.google.com/wallet/instant-buy/android/tutorial">Instant Buy Android API tutorial</a> provides directions on how to get the Wallet sample up and running.</p> <h4>3. Read the documentation</h4> - <p>For quick access while developing your Android apps, the <a + <p>For quick access while developing your Android apps, the <a href="{@docRoot}reference/com/google/android/gms/wallet/package-summary.html">Google Wallet API reference</a> is available here on developer.android.com.</p> diff --git a/docs/html/guide/topics/connectivity/usb/host.jd b/docs/html/guide/topics/connectivity/usb/host.jd index 355dd2dd9199..f957b60f5fd6 100644 --- a/docs/html/guide/topics/connectivity/usb/host.jd +++ b/docs/html/guide/topics/connectivity/usb/host.jd @@ -31,7 +31,7 @@ page.title=USB Host <li><a href="{@docRoot}resources/samples/USB/AdbTest/index.html">AdbTest</a></li> <li><a href= - "{@docRoot}resources/samples/USB/MissileLauncher/index.html">MissleLauncher</a></li> + "{@docRoot}resources/samples/USB/MissileLauncher/index.html">MissileLauncher</a></li> </ol> </div> </div> @@ -283,7 +283,7 @@ while(deviceIterator.hasNext()){ <h3 id="permission-d">Obtaining permission to communicate with a device</h3> - <p>Before communicating with the USB device, your applicaton must have permission from your + <p>Before communicating with the USB device, your application must have permission from your users.</p> <p class="note"><strong>Note:</strong> If your application <a href="#using-intents">uses an @@ -388,7 +388,7 @@ mUsbManager.requestPermission(device, mPermissionIntent); should have more logic to correctly find the correct interface and endpoints to communicate on and also should do any transferring of data in a different thread than the main UI thread:</p> <pre> -private Byte[] bytes +private Byte[] bytes; private static int TIMEOUT = 0; private boolean forceClaim = true; @@ -409,7 +409,7 @@ connection.bulkTransfer(endpoint, bytes, bytes.length, TIMEOUT); //do in another <p>For more information, see the <a href= "{@docRoot}resources/samples/USB/AdbTest/index.html">AdbTest sample</a>, which shows how to do asynchronous bulk transfers, and the <a href= - "{@docRoot}resources/samples/USB/MissileLauncher/index.html">MissleLauncher sample</a>, which + "{@docRoot}resources/samples/USB/MissileLauncher/index.html">MissileLauncher sample</a>, which shows how to listen on an interrupt endpoint asynchronously.</p> <h3 id="terminating-d">Terminating communication with a device</h3> diff --git a/docs/html/images/training/geofence.png b/docs/html/images/training/geofence.png Binary files differnew file mode 100644 index 000000000000..2d5d3aa0b176 --- /dev/null +++ b/docs/html/images/training/geofence.png diff --git a/docs/html/images/training/geofence@2x.png b/docs/html/images/training/geofence@2x.png Binary files differnew file mode 100644 index 000000000000..2f83105a29d7 --- /dev/null +++ b/docs/html/images/training/geofence@2x.png diff --git a/docs/html/tools/adk/adk.jd b/docs/html/tools/adk/adk.jd index 7e75c11be020..3f45c3c1cca9 100644 --- a/docs/html/tools/adk/adk.jd +++ b/docs/html/tools/adk/adk.jd @@ -331,7 +331,7 @@ href="http://arduino.cc/en/Main/ArduinoBoardADK">Arduino Mega ADK</a> (for EU na <li>Install the application to your device.</li> <li>Connect the ADK board (USB-A) to your Android-powered device (micro-USB). Ensure that the - power cable to the accessory is plugged in or that the micro-USB port on the accesory is + power cable to the accessory is plugged in or that the micro-USB port on the accessory is connected to your computer for power (this also allows you to <a href="#monitoring">monitor the ADK board</a>). When connected, accept the prompt that asks for whether or not to open the DemoKit application to connect to the accessory. If the prompt does not show up, connect and diff --git a/docs/html/tools/sdk/tools-notes.jd b/docs/html/tools/sdk/tools-notes.jd index b5a64778f165..47b603a77474 100644 --- a/docs/html/tools/sdk/tools-notes.jd +++ b/docs/html/tools/sdk/tools-notes.jd @@ -24,7 +24,7 @@ href="http://tools.android.com/knownissues">http://tools.android.com/knownissues <div class="toggle-content opened"> <p><a href="#" onclick="return toggleContent(this)"> <img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-content-img" - alt=""/>SDK Tools, Revision 24.1.2</a> <em>(February 2014)</em> + alt=""/>SDK Tools, Revision 24.1.2</a> <em>(February 2015)</em> </p> <div class="toggle-content-toggleme"> diff --git a/docs/html/training/location/geofencing.jd b/docs/html/training/location/geofencing.jd index 748b6ece8b87..59fc4c665a53 100644 --- a/docs/html/training/location/geofencing.jd +++ b/docs/html/training/location/geofencing.jd @@ -9,9 +9,11 @@ trainingnavtop=true <h2>This lesson teaches you to</h2> <ol> - <li><a href="#RequestGeofences">Request Geofence Monitoring</a></li> + <li><a href="#RequestGeofences">Set up for Geofence Monitoring</a></li> + <li><a href="#CreateAdd">Create and Add Geofences</a></li> <li><a href="#HandleGeofenceTransitions">Handle Geofence Transitions</a></li> <li><a href="#StopGeofenceMonitoring">Stop Geofence Monitoring</a></li> + </ol> <h2>You should also read</h2> @@ -23,577 +25,148 @@ trainingnavtop=true <h2>Try it out</h2> -<div class="download-box"> - <a href="http://developer.android.com/shareables/training/GeofenceDetection.zip" class="button">Download the sample</a> - <p class="filename">GeofenceDetection.zip</p> -</div> + <ul> + <li> + <a href="https://github.com/googlesamples/android-play-location/tree/master/Geofencing" + class="external-link">Geofencing</a> + </li> + </ul> </div> </div> <p> - Geofencing combines awareness of the user's current location with awareness of nearby - features, defined as the user's proximity to locations that may be of interest. To mark a + Geofencing combines awareness of the user's current location with awareness of the user's + proximity to locations that may be of interest. To mark a location of interest, you specify its latitude and longitude. To adjust the proximity for the - location, you add a radius. The latitude, longitude, and radius define a geofence. - You can have multiple active geofences at one time. + location, you add a radius. The latitude, longitude, and radius define a geofence, creating a + circular area, or fence, around the location of interest. </p> <p> - Location Services treats a geofences as an area rather than as a points and proximity. This - allows it to detect when the user enters or exits a geofence. For each geofence, you can ask - Location Services to send you entrance events or exit events or both. You can also limit the - duration of a geofence by specifying an expiration duration in milliseconds. After the geofence - expires, Location Services automatically removes it. + You can have multiple active geofences, with a limit of 100 per device user. For each geofence, + you can ask Location Services to send you entrance and exit events, or you can specify a + duration within the geofence area to wait, or <em>dwell</em>, before triggering an event. You + can limit the duration of any geofence by specifying an expiration duration in milliseconds. + After the geofence expires, Location Services automatically removes it. </p> -<!-- - Send geofences to Location Services - --> -<h2 id="RequestGeofences">Request Geofence Monitoring</h2> + +<img src="{@docRoot}images/training/geofence@2x.png" +srcset="{@docRoot}images/training/geofence.png 1x, {@docRoot}images/training/geofence@2x.png 2x" alt="" + width="400" height="400"/> +<p> + This lesson shows you how to add and remove geofences, and then listen for geofence transitions + using an {@link android.app.IntentService}.</p> + +<h2 id="RequestGeofences">Set up for Geofence Monitoring</h2> <p> The first step in requesting geofence monitoring is to request the necessary permission. To use geofencing, your app must request {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION}. To request this permission, add the following element as a child element of the <code><a href="{@docRoot}guide/topics/manifest/manifest-element.html"><manifest></a></code> - element: + element in your app manifest: </p> <pre> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> </pre> -<!-- Check for Google Play services --> -<h3>Check for Google Play Services</h3> -<p> - Location Services is part of the Google Play services APK. Since it's hard to anticipate the - state of the user's device, you should always check that the APK is installed before you attempt - to connect to Location Services. To check that the APK is installed, call -<code><a href="{@docRoot}reference/com/google/android/gms/common/GooglePlayServicesUtil.html#isGooglePlayServicesAvailable(android.content.Context)">GooglePlayServicesUtil.isGooglePlayServicesAvailable()</a></code>, - which returns one of the - integer result codes listed in the API reference documentation. If you encounter an error, - call -<code><a href="{@docRoot}reference/com/google/android/gms/common/GooglePlayServicesUtil.html#getErrorDialog(int, android.app.Activity, int)">GooglePlayServicesUtil.getErrorDialog()</a></code> - to retrieve localized dialog that prompts users to take the correct action, then display - the dialog in a {@link android.support.v4.app.DialogFragment}. The dialog may allow the - user to correct the problem, in which case Google Play services may send a result back to your - activity. To handle this result, override the method - {@link android.support.v4.app.FragmentActivity#onActivityResult onActivityResult()} -</p> -<p class="note"> - <strong>Note:</strong> To make your app compatible with - platform version 1.6 and later, the activity that displays the - {@link android.support.v4.app.DialogFragment} must subclass - {@link android.support.v4.app.FragmentActivity} instead of {@link android.app.Activity}. Using - {@link android.support.v4.app.FragmentActivity} also allows you to call - {@link android.support.v4.app.FragmentActivity#getSupportFragmentManager - getSupportFragmentManager()} to display the {@link android.support.v4.app.DialogFragment}. -</p> <p> - Since you usually need to check for Google Play services in more than one place in your code, - define a method that encapsulates the check, then call the method before each connection - attempt. The following snippet contains all of the code required to check for Google - Play services: + If you want to use an {@link android.app.IntentService} to listen for geofence transitions, + add an element specifying the service name. This element must be + a child of the <code><a href="{@docRoot}guide/topics/manifest/application-element.html"> + <application></a></code> element: </p> -<pre> -public class MainActivity extends FragmentActivity { - ... - // Global constants - /* - * Define a request code to send to Google Play services - * This code is returned in Activity.onActivityResult - */ - private final static int - CONNECTION_FAILURE_RESOLUTION_REQUEST = 9000; - ... - // Define a DialogFragment that displays the error dialog - public static class ErrorDialogFragment extends DialogFragment { - // Global field to contain the error dialog - private Dialog mDialog; - ... - // Default constructor. Sets the dialog field to null - public ErrorDialogFragment() { - super(); - mDialog = null; - } - ... - // Set the dialog to display - public void setDialog(Dialog dialog) { - mDialog = dialog; - } - ... - // Return a Dialog to the DialogFragment. - @Override - public Dialog onCreateDialog(Bundle savedInstanceState) { - return mDialog; - } - ... - } - ... - /* - * Handle results returned to the FragmentActivity - * by Google Play services - */ - @Override - protected void onActivityResult( - int requestCode, int resultCode, Intent data) { - // Decide what to do based on the original request code - switch (requestCode) { - ... - case CONNECTION_FAILURE_RESOLUTION_REQUEST : - /* - * If the result code is Activity.RESULT_OK, try - * to connect again - */ - switch (resultCode) { - ... - case Activity.RESULT_OK : - /* - * Try the request again - */ - ... - break; - } - ... - } - ... - } - ... - private boolean servicesConnected() { - // Check that Google Play services is available - int resultCode = - GooglePlayServicesUtil. - isGooglePlayServicesAvailable(this); - // If Google Play services is available - if (ConnectionResult.SUCCESS == resultCode) { - // In debug mode, log the status - Log.d("Geofence Detection", - "Google Play services is available."); - // Continue - return true; - // Google Play services was not available for some reason - } else { - // Get the error code - int errorCode = connectionResult.getErrorCode(); - // Get the error dialog from Google Play services - Dialog errorDialog = GooglePlayServicesUtil.getErrorDialog( - errorCode, - this, - CONNECTION_FAILURE_RESOLUTION_REQUEST); - // If Google Play services can provide an error dialog - if (errorDialog != null) { - // Create a new DialogFragment for the error dialog - ErrorDialogFragment errorFragment = - new ErrorDialogFragment(); - // Set the dialog in the DialogFragment - errorFragment.setDialog(errorDialog); - // Show the error dialog in the DialogFragment - errorFragment.show( - getSupportFragmentManager(), - "Geofence Detection"); - } - } - } - ... -} +<pre> +<application + android:allowBackup="true"> + ... + <service android:name=".GeofenceTransitionsIntentService"/> +<application/> </pre> -<p> - Snippets in the following sections call this method to verify that Google Play services is - available. -</p> -<p> - To use geofencing, start by defining the geofences you want to monitor. Although you usually - store geofence data in a local database or download it from the network, you need to send - a geofence to Location Services as an instance of -<code><a href="{@docRoot}reference/com/google/android/gms/location/Geofence.html">Geofence</a></code>, - which you create with -<code><a href="{@docRoot}reference/com/google/android/gms/location/Geofence.Builder.html">Geofence.Builder</a></code>. - Each -<code><a href="{@docRoot}reference/com/google/android/gms/location/Geofence.html">Geofence</a></code> - object contains the following information: -</p> -<dl> - <dt>Latitude, longitude, and radius</dt> - <dd> - Define a circular area for the geofence. Use the latitude and longitude to mark a location - of interest, and then use the radius to adjust how close the user needs to approach the - location before the geofence is detected. The larger the radius, the more likely the - user will trigger a geofence transition alert by approaching the geofence. For example, - providing a large radius for a geofencing app that turns on lights in the user's house as - the user returns home might cause the lights to go on even if the user is simply passing by. - </dd> - <dt>Expiration time</dt> - <dd> - How long the geofence should remain active. Once the expiration time is reached, Location - Services deletes the geofence. Most of the time, you should specify an expiration time, but - you may want to keep permanent geofences for the user's home or place of work. - </dd> - <dt>Transition type</dt> - <dd> - Location Services can detect when the user steps within the radius of the geofence ("entry") - and when the user steps outside the radius of the geofence ("exit"), or both. - </dd> - <dt>Geofence ID</dt> - <dd> - A string that is stored with the geofence. You should make this unique, so that you can - use it to remove a geofence from Location Services tracking. - </dd> -</dl> -<h3>Define geofence storage</h3> -<p> - A geofencing app needs to read and write geofence data to persistent storage. You shouldn't use -<code><a href="{@docRoot}reference/com/google/android/gms/location/Geofence.html">Geofence</a></code> - objects to do this; instead, use storage techniques such as databases that can store groups of - related data. + +<p>To access the location APIs, you need to create an instance of the + Google Play services API client. To learn how to connect your client, see + <a href="{@docRoot}training/location/retrieve-current.html#play-services">Connect + to Google Play Services</a>.</p> + +<h2 id="CreateAdd">Create and Add Geofences</h2> + +<p>Your app needs to create and add geofences using the location API's builder class for + creating Geofence objects, and the convenience class for adding them. Also, to handle the + intents sent from Location Services when geofence transitions occur, you can define a + {@link android.app.PendingIntent} as shown in this section. </p> + +<h3>Create geofence objects</h3> + <p> - As an example of storing geofence data, the following snippet defines two classes that use - the app's {@link android.content.SharedPreferences} instance for persistent storage. The class - {@code SimpleGeofence}, analogous to a database record, stores the - data for a single -<code><a href="{@docRoot}reference/com/google/android/gms/location/Geofence.html">Geofence</a></code> - object in a "flattened" form. The class {@code SimpleGeofenceStore}, analogous to a database, - reads and writes {@code SimpleGeofence} data to the - {@link android.content.SharedPreferences} instance. -</p> -<pre> -public class MainActivity extends FragmentActivity { - ... - /** - * A single Geofence object, defined by its center and radius. - */ - public class SimpleGeofence { - // Instance variables - private final String mId; - private final double mLatitude; - private final double mLongitude; - private final float mRadius; - private long mExpirationDuration; - private int mTransitionType; + First, use <code><a href="{@docRoot}reference/com/google/android/gms/location/Geofence.Builder. + html">Geofence.Builder</a></code> to create a geofence, setting the desired radius, duration, and + transition types for the geofence. For example, to populate a list object named + {@code mGeofenceList}: + </p> - /** - * @param geofenceId The Geofence's request ID - * @param latitude Latitude of the Geofence's center. - * @param longitude Longitude of the Geofence's center. - * @param radius Radius of the geofence circle. - * @param expiration Geofence expiration duration - * @param transition Type of Geofence transition. - */ - public SimpleGeofence( - String geofenceId, - double latitude, - double longitude, - float radius, - long expiration, - int transition) { - // Set the instance fields from the constructor - this.mId = geofenceId; - this.mLatitude = latitude; - this.mLongitude = longitude; - this.mRadius = radius; - this.mExpirationDuration = expiration; - this.mTransitionType = transition; - } - // Instance field getters - public String getId() { - return mId; - } - public double getLatitude() { - return mLatitude; - } - public double getLongitude() { - return mLongitude; - } - public float getRadius() { - return mRadius; - } - public long getExpirationDuration() { - return mExpirationDuration; - } - public int getTransitionType() { - return mTransitionType; - } - /** - * Creates a Location Services Geofence object from a - * SimpleGeofence. - * - * @return A Geofence object - */ - public Geofence toGeofence() { - // Build a new Geofence object - return new Geofence.Builder() - .setRequestId(getId()) - .setTransitionTypes(mTransitionType) - .setCircularRegion( - getLatitude(), getLongitude(), getRadius()) - .setExpirationDuration(mExpirationDuration) - .build(); - } - } - ... - /** - * Storage for geofence values, implemented in SharedPreferences. - */ - public class SimpleGeofenceStore { - // Keys for flattened geofences stored in SharedPreferences - public static final String KEY_LATITUDE = - "com.example.android.geofence.KEY_LATITUDE"; - public static final String KEY_LONGITUDE = - "com.example.android.geofence.KEY_LONGITUDE"; - public static final String KEY_RADIUS = - "com.example.android.geofence.KEY_RADIUS"; - public static final String KEY_EXPIRATION_DURATION = - "com.example.android.geofence.KEY_EXPIRATION_DURATION"; - public static final String KEY_TRANSITION_TYPE = - "com.example.android.geofence.KEY_TRANSITION_TYPE"; - // The prefix for flattened geofence keys - public static final String KEY_PREFIX = - "com.example.android.geofence.KEY"; - /* - * Invalid values, used to test geofence storage when - * retrieving geofences - */ - public static final long INVALID_LONG_VALUE = -999l; - public static final float INVALID_FLOAT_VALUE = -999.0f; - public static final int INVALID_INT_VALUE = -999; - // The SharedPreferences object in which geofences are stored - private final SharedPreferences mPrefs; - // The name of the SharedPreferences - private static final String SHARED_PREFERENCES = - "SharedPreferences"; - // Create the SharedPreferences storage with private access only - public SimpleGeofenceStore(Context context) { - mPrefs = - context.getSharedPreferences( - SHARED_PREFERENCES, - Context.MODE_PRIVATE); - } - /** - * Returns a stored geofence by its id, or returns {@code null} - * if it's not found. - * - * @param id The ID of a stored geofence - * @return A geofence defined by its center and radius. See - */ - public SimpleGeofence getGeofence(String id) { - /* - * Get the latitude for the geofence identified by id, or - * INVALID_FLOAT_VALUE if it doesn't exist - */ - double lat = mPrefs.getFloat( - getGeofenceFieldKey(id, KEY_LATITUDE), - INVALID_FLOAT_VALUE); - /* - * Get the longitude for the geofence identified by id, or - * INVALID_FLOAT_VALUE if it doesn't exist - */ - double lng = mPrefs.getFloat( - getGeofenceFieldKey(id, KEY_LONGITUDE), - INVALID_FLOAT_VALUE); - /* - * Get the radius for the geofence identified by id, or - * INVALID_FLOAT_VALUE if it doesn't exist - */ - float radius = mPrefs.getFloat( - getGeofenceFieldKey(id, KEY_RADIUS), - INVALID_FLOAT_VALUE); - /* - * Get the expiration duration for the geofence identified - * by id, or INVALID_LONG_VALUE if it doesn't exist - */ - long expirationDuration = mPrefs.getLong( - getGeofenceFieldKey(id, KEY_EXPIRATION_DURATION), - INVALID_LONG_VALUE); - /* - * Get the transition type for the geofence identified by - * id, or INVALID_INT_VALUE if it doesn't exist - */ - int transitionType = mPrefs.getInt( - getGeofenceFieldKey(id, KEY_TRANSITION_TYPE), - INVALID_INT_VALUE); - // If none of the values is incorrect, return the object - if ( - lat != GeofenceUtils.INVALID_FLOAT_VALUE && - lng != GeofenceUtils.INVALID_FLOAT_VALUE && - radius != GeofenceUtils.INVALID_FLOAT_VALUE && - expirationDuration != - GeofenceUtils.INVALID_LONG_VALUE && - transitionType != GeofenceUtils.INVALID_INT_VALUE) { +<pre> +mGeofenceList.add(new Geofence.Builder() + // Set the request ID of the geofence. This is a string to identify this + // geofence. + .setRequestId(entry.getKey()) - // Return a true Geofence object - return new SimpleGeofence( - id, lat, lng, radius, expirationDuration, - transitionType); - // Otherwise, return null. - } else { - return null; - } - } - /** - * Save a geofence. - * @param geofence The SimpleGeofence containing the - * values you want to save in SharedPreferences - */ - public void setGeofence(String id, SimpleGeofence geofence) { - /* - * Get a SharedPreferences editor instance. Among other - * things, SharedPreferences ensures that updates are atomic - * and non-concurrent - */ - Editor editor = mPrefs.edit(); - // Write the Geofence values to SharedPreferences - editor.putFloat( - getGeofenceFieldKey(id, KEY_LATITUDE), - (float) geofence.getLatitude()); - editor.putFloat( - getGeofenceFieldKey(id, KEY_LONGITUDE), - (float) geofence.getLongitude()); - editor.putFloat( - getGeofenceFieldKey(id, KEY_RADIUS), - geofence.getRadius()); - editor.putLong( - getGeofenceFieldKey(id, KEY_EXPIRATION_DURATION), - geofence.getExpirationDuration()); - editor.putInt( - getGeofenceFieldKey(id, KEY_TRANSITION_TYPE), - geofence.getTransitionType()); - // Commit the changes - editor.commit(); - } - public void clearGeofence(String id) { - /* - * Remove a flattened geofence object from storage by - * removing all of its keys - */ - Editor editor = mPrefs.edit(); - editor.remove(getGeofenceFieldKey(id, KEY_LATITUDE)); - editor.remove(getGeofenceFieldKey(id, KEY_LONGITUDE)); - editor.remove(getGeofenceFieldKey(id, KEY_RADIUS)); - editor.remove(getGeofenceFieldKey(id, - KEY_EXPIRATION_DURATION)); - editor.remove(getGeofenceFieldKey(id, KEY_TRANSITION_TYPE)); - editor.commit(); - } - /** - * Given a Geofence object's ID and the name of a field - * (for example, KEY_LATITUDE), return the key name of the - * object's values in SharedPreferences. - * - * @param id The ID of a Geofence object - * @param fieldName The field represented by the key - * @return The full key name of a value in SharedPreferences - */ - private String getGeofenceFieldKey(String id, - String fieldName) { - return KEY_PREFIX + "_" + id + "_" + fieldName; - } - } - ... -} + .setCircularRegion( + entry.getValue().latitude, + entry.getValue().longitude, + Constants.GEOFENCE_RADIUS_IN_METERS + ) + .setExpirationDuration(Constants.GEOFENCE_EXPIRATION_IN_MILLISECONDS) + .setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER | + Geofence.GEOFENCE_TRANSITION_EXIT) + .build()); </pre> -<h3>Create Geofence objects</h3> + +<p>This example pulls data from a constants file. In actual practice, apps might + dynamically create geofences based on the user's location.</p> + +<h3>Specify geofences and initial triggers</h3> + <p> - The following snippet uses the {@code SimpleGeofence} and {@code SimpleGeofenceStore} classes - gets geofence data from the UI, stores it in {@code SimpleGeofence} objects, stores these - objects in a {@code SimpleGeofenceStore} object, and then creates -<code><a href="{@docRoot}reference/com/google/android/gms/location/Geofence.html">Geofence</a></code> - objects: + The following snippet uses the <code><a href="{@docRoot}reference/com/google/android/gms/location/GeofencingRequest.html"> + GeofencingRequest</a></code> class + and its nested <code><a href="{@docRoot}reference/com/google/android/gms/location/GeofencingRequest.Builder.html"> + GeofencingRequestBuilder</a></code> class to + specify the geofences to monitor and to set how related geofence events are triggered: </p> <pre> -public class MainActivity extends FragmentActivity { - ... - /* - * Use to set an expiration time for a geofence. After this amount - * of time Location Services will stop tracking the geofence. - */ - private static final long SECONDS_PER_HOUR = 60; - private static final long MILLISECONDS_PER_SECOND = 1000; - private static final long GEOFENCE_EXPIRATION_IN_HOURS = 12; - private static final long GEOFENCE_EXPIRATION_TIME = - GEOFENCE_EXPIRATION_IN_HOURS * - SECONDS_PER_HOUR * - MILLISECONDS_PER_SECOND; - ... - /* - * Handles to UI views containing geofence data - */ - // Handle to geofence 1 latitude in the UI - private EditText mLatitude1; - // Handle to geofence 1 longitude in the UI - private EditText mLongitude1; - // Handle to geofence 1 radius in the UI - private EditText mRadius1; - // Handle to geofence 2 latitude in the UI - private EditText mLatitude2; - // Handle to geofence 2 longitude in the UI - private EditText mLongitude2; - // Handle to geofence 2 radius in the UI - private EditText mRadius2; - /* - * Internal geofence objects for geofence 1 and 2 - */ - private SimpleGeofence mUIGeofence1; - private SimpleGeofence mUIGeofence2; - ... - // Internal List of Geofence objects - List<Geofence> mGeofenceList; - // Persistent storage for geofences - private SimpleGeofenceStore mGeofenceStorage; - ... - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - ... - // Instantiate a new geofence storage area - mGeofenceStorage = new SimpleGeofenceStore(this); - - // Instantiate the current List of geofences - mCurrentGeofences = new ArrayList<Geofence>(); - } - ... - /** - * Get the geofence parameters for each geofence from the UI - * and add them to a List. - */ - public void createGeofences() { - /* - * Create an internal object to store the data. Set its - * ID to "1". This is a "flattened" object that contains - * a set of strings - */ - mUIGeofence1 = new SimpleGeofence( - "1", - Double.valueOf(mLatitude1.getText().toString()), - Double.valueOf(mLongitude1.getText().toString()), - Float.valueOf(mRadius1.getText().toString()), - GEOFENCE_EXPIRATION_TIME, - // This geofence records only entry transitions - Geofence.GEOFENCE_TRANSITION_ENTER); - // Store this flat version - mGeofenceStorage.setGeofence("1", mUIGeofence1); - // Create another internal object. Set its ID to "2" - mUIGeofence2 = new SimpleGeofence( - "2", - Double.valueOf(mLatitude2.getText().toString()), - Double.valueOf(mLongitude2.getText().toString()), - Float.valueOf(mRadius2.getText().toString()), - GEOFENCE_EXPIRATION_TIME, - // This geofence records both entry and exit transitions - Geofence.GEOFENCE_TRANSITION_ENTER | - Geofence.GEOFENCE_TRANSITION_EXIT); - // Store this flat version - mGeofenceStorage.setGeofence(2, mUIGeofence2); - mGeofenceList.add(mUIGeofence1.toGeofence()); - mGeofenceList.add(mUIGeofence2.toGeofence()); - } - ... +private GeofencingRequest getGeofencingRequest() { + GeofencingRequest.Builder builder = new GeofencingRequest.Builder(); + builder.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER); + builder.addGeofences(mGeofenceList); + return builder.build(); } </pre> + <p> - In addition to the {@link java.util.List} of -<code><a href="{@docRoot}reference/com/google/android/gms/location/Geofence.html">Geofence</a></code> - objects you want to monitor, you need to provide Location Services with the - {@link android.content.Intent} that it sends to your app when it detects geofence - transitions. -<h4>Define a Intent for geofence transitions</h4> + This example shows the use of two geofence triggers. The <code><a href="{@docRoot}reference/com/google/android/gms/location/Geofence.html#GEOFENCE_TRANSITION_ENTER"> + GEOFENCE_TRANSITION_ENTER</a></code> + transition triggers when a device enters a geofence, and the <code><a href="{@docRoot}reference/com/google/android/gms/location/Geofence.html#GEOFENCE_TRANSITION_EXIT"> + GEOFENCE_TRANSITION_EXIT</a></code> + transition triggers when a device exits a geofence. Specifying + <code><a href="{@docRoot}reference/com/google/android/gms/location/GeofencingRequest.html#INITIAL_TRIGGER_ENTER"> + INITIAL_TRIGGER_ENTER</a></code> tells Location services that + <code><a href="{@docRoot}reference/com/google/android/gms/location/Geofence.html#GEOFENCE_TRANSITION_ENTER"> + GEOFENCE_TRANSITION_ENTER</a></code> + should be triggered if the the device is already inside the geofence.</p> +</p> + +<p>In many cases, it may be preferable to use instead <code><a href="{@docRoot}reference/com/google/android/gms/location/GeofencingRequest.html#INITIAL_TRIGGER_DWELL"> + INITIAL_TRIGGER_DWELL</a></code>, + which triggers events only when the user stops for a defined duration within a geofence. + This approach can help reduce "alert spam" resulting from large numbers notifications when a + device briefly enters and exits geofences. Another strategy for getting best results from your + geofences is to set a minimum radius of 100 meters. This helps account for the location accuracy + of typical WiFi networks, and also helps reduce device power consumption. +</p> + +<h3>Define an Intent for geofence transitions</h3> <p> The {@link android.content.Intent} sent from Location Services can trigger various actions in your app, but you should <i>not</i> have it start an activity or fragment, because components @@ -601,807 +174,133 @@ public class MainActivity extends FragmentActivity { {@link android.app.IntentService} is a good way to handle the intent. An {@link android.app.IntentService} can post a notification, do long-running background work, send intents to other services, or send a broadcast intent. The following snippet shows how - how to define a {@link android.app.PendingIntent} that starts an - {@link android.app.IntentService}: + to define a {@link android.app.PendingIntent} that starts an {@link android.app.IntentService}: </p> <pre> public class MainActivity extends FragmentActivity { ... - /* - * Create a PendingIntent that triggers an IntentService in your - * app when a geofence transition occurs. - */ - private PendingIntent getTransitionPendingIntent() { - // Create an explicit Intent - Intent intent = new Intent(this, - ReceiveTransitionsIntentService.class); - /* - * Return the PendingIntent - */ - return PendingIntent.getService( - this, - 0, - intent, - PendingIntent.FLAG_UPDATE_CURRENT); - } - ... -} -</pre> -<p> - Now you have all the code you need to send a request to monitor geofences to Location - Services. -</p> -<!-- Send the monitoring request --> -<h3 id="requestmonitoring">Send the monitoring request</h3> -<p> - Sending the monitoring request requires two asynchronous operations. The first operation gets a - location client for the request, and the second makes the request using the client. In both - cases, Location Services invokes a callback method when it finishes the operation. The best way - to handle these operations is to chain together the method calls. The following snippets - demonstrate how to set up an activity, define the methods, and call them in the proper order. -</p> -<p> - First, modify the activity's class definition to implement the necessary callback interfaces. - Add the following interfaces: -</p> -<dl> - <dt> -<code><a href="{@docRoot}reference/com/google/android/gms/common/GooglePlayServicesClient.ConnectionCallbacks.html">ConnectionCallbacks</a></code> - </dt> - <dd> - Specifies methods that Location Services calls when a location client is connected or - disconnected. - </dd> - <dt> -<code><a href="{@docRoot}reference/com/google/android/gms/common/GooglePlayServicesClient.OnConnectionFailedListener.html">OnConnectionFailedListener</a></code> - </dt> - <dd> - Specifies a method that Location Services calls if an error occurs while attempting to - connect the location client. - </dd> - <dt> -<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationClient.OnAddGeofencesResultListener.html">OnAddGeofencesResultListener</a></code> - </dt> - <dd> - Specifies a method that Location Services calls once it has added the geofences. - </dd> -</dl> -<p> - For example: -</p> -<pre> -public class MainActivity extends FragmentActivity implements - ConnectionCallbacks, - OnConnectionFailedListener, - OnAddGeofencesResultListener { - ... -} -</pre> -<h4>Start the request process</h4> -<p> - Next, define a method that starts the request process by connecting to Location Services. - Mark this as a request to add a geofence by setting a global variable. This allows you to - use the callback -<code><a href="{@docRoot}reference/com/google/android/gms/common/GooglePlayServicesClient.ConnectionCallbacks.html#onConnected(android.os.Bundle)">ConnectionCallbacks.onConnected()</a></code> - to add geofences and to remove them, as described in succeeding sections. -</p> -<p> -<p> - To guard against race conditions that might arise if your app tries to start another request - before the first one finishes, define a boolean flag that tracks the state of the current - request: -</p> -<pre> -public class MainActivity extends FragmentActivity implements - ConnectionCallbacks, - OnConnectionFailedListener, - OnAddGeofencesResultListener { - ... - // Holds the location client - private LocationClient mLocationClient; - // Stores the PendingIntent used to request geofence monitoring - private PendingIntent mGeofenceRequestIntent; - // Defines the allowable request types. - public enum REQUEST_TYPE = {ADD} - private REQUEST_TYPE mRequestType; - // Flag that indicates if a request is underway. - private boolean mInProgress; - ... - @Override - protected void onCreate(Bundle savedInstanceState) { - ... - // Start with the request flag set to false - mInProgress = false; - ... - } - ... - /** - * Start a request for geofence monitoring by calling - * LocationClient.connect(). - */ - public void addGeofences() { - // Start a request to add geofences - mRequestType = ADD; - /* - * Test for Google Play services after setting the request type. - * If Google Play services isn't present, the proper request - * can be restarted. - */ - if (!servicesConnected()) { - return; - } - /* - * Create a new location client object. Since the current - * activity class implements ConnectionCallbacks and - * OnConnectionFailedListener, pass the current activity object - * as the listener for both parameters - */ - mLocationClient = new LocationClient(this, this, this) - // If a request is not already underway - if (!mInProgress) { - // Indicate that a request is underway - mInProgress = true; - // Request a connection from the client to Location Services - mLocationClient.connect(); - } else { - /* - * A request is already underway. You can handle - * this situation by disconnecting the client, - * re-setting the flag, and then re-trying the - * request. - */ - } - } - ... -} -</pre> -<h4>Send a request to add the geofences</h4> -<p> - In your implementation of -<code><a href="{@docRoot}reference/com/google/android/gms/common/GooglePlayServicesClient.ConnectionCallbacks.html#onConnected(android.os.Bundle)">ConnectionCallbacks.onConnected()</a></code>, - call -<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationClient.html#addGeofences(java.util.List<com.google.android.gms.location.Geofence>, android.app.PendingIntent, com.google.android.gms.location.LocationClient.OnAddGeofencesResultListener)">LocationClient.addGeofences()</a></code>. - Notice that if the connection fails, -<code><a href="{@docRoot}reference/com/google/android/gms/common/GooglePlayServicesClient.ConnectionCallbacks.html#onConnected(android.os.Bundle)">onConnected()</a></code> - isn't called, and the request stops. -</p> -<pre> -public class MainActivity extends FragmentActivity implements - ConnectionCallbacks, - OnConnectionFailedListener, - OnAddGeofencesResultListener { - ... - /* - * Provide the implementation of ConnectionCallbacks.onConnected() - * Once the connection is available, send a request to add the - * Geofences - */ - @Override - private void onConnected(Bundle dataBundle) { - ... - switch (mRequestType) { - case ADD : - // Get the PendingIntent for the request - mTransitionPendingIntent = - getTransitionPendingIntent(); - // Send a request to add the current geofences - mLocationClient.addGeofences( - mCurrentGeofences, pendingIntent, this); - ... + private PendingIntent getGeofencePendingIntent() { + // Reuse the PendingIntent if we already have it. + if (mGeofencePendingIntent != null) { + return mGeofencePendingIntent; } + Intent intent = new Intent(this, GeofenceTransitionsIntentService.class); + // We use FLAG_UPDATE_CURRENT so that we get the same pending intent back when + // calling addGeofences() and removeGeofences(). + return PendingIntent.getService(this, 0, intent, PendingIntent. + FLAG_UPDATE_CURRENT); } - ... -} </pre> + +<h3>Add geofences</h3> + <p> - Notice that -<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationClient.html#addGeofences(java.util.List<com.google.android.gms.location.Geofence>, android.app.PendingIntent, com.google.android.gms.location.LocationClient.OnAddGeofencesResultListener)">addGeofences()</a></code> - returns immediately, but the status of the request is indeterminate until Location Services - calls -<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationClient.OnAddGeofencesResultListener.html#onAddGeofencesResult(int, java.lang.String[])">onAddGeofencesResult()</a></code> - Once this method is called, you can determine if the request was successful or not. -</p> -<h4>Check the result returned by Location Services</h4> -<p> - When Location Services invokes your implementation of the callback method -<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationClient.OnAddGeofencesResultListener.html#onAddGeofencesResult(int, java.lang.String[])">onAddGeofencesResult()</a></code>, - indicating that the request is complete, examine the incoming status code. If the request - was successful, the geofences you requested are active. If the request was unsuccessful, - the geofences aren't active, and you need to re-try the request or report an error. For example: -</p> -<pre> -public class MainActivity extends FragmentActivity implements - ConnectionCallbacks, - OnConnectionFailedListener, - OnAddGeofencesResultListener { - ... - /* - * Provide the implementation of - * OnAddGeofencesResultListener.onAddGeofencesResult. - * Handle the result of adding the geofences - * - */ - @Override - public void onAddGeofencesResult( - int statusCode, String[] geofenceRequestIds) { - // If adding the geofences was successful - if (LocationStatusCodes.SUCCESS == statusCode) { - /* - * Handle successful addition of geofences here. - * You can send out a broadcast intent or update the UI. - * geofences into the Intent's extended data. - */ - } else { - // If adding the geofences failed - /* - * Report errors here. - * You can log the error using Log.e() or update - * the UI. - */ - } - // Turn off the in progress flag and disconnect the client - mInProgress = false; - mLocationClient.disconnect(); - } - ... -} -</pre> -<!-- Handle disconnections --> -<h3>Handle disconnections</h3> -<p> - In some cases, Location Services may disconnect from the activity recognition client before - you call -<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationClient.html#disconnect()">disconnect()</a></code>. - To handle this situation, implement <code> -<a href="{@docRoot}reference/com/google/android/gms/common/GooglePlayServicesClient.ConnectionCallbacks.html#onDisconnected()">onDisconnected()</a></code>. - In this method, set the request flag to indicate that a request is not in progress, and - delete the client: -</p> -<pre> -public class MainActivity extends FragmentActivity implements - ConnectionCallbacks, - OnConnectionFailedListener, - OnAddGeofencesResultListener { - ... - /* - * Implement ConnectionCallbacks.onDisconnected() - * Called by Location Services once the location client is - * disconnected. - */ - @Override - public void onDisconnected() { - // Turn off the request flag - mInProgress = false; - // Destroy the current location client - mLocationClient = null; - } - ... -} -</pre> -<!-- Handle connection errors --> -<h3>Handle connection errors</h3> -<p> - Besides handling the normal callbacks from Location Services, you have to provide a callback - method that Location Services calls if a connection error occurs. This callback method - can re-use the {@link android.support.v4.app.DialogFragment} class that you defined to - handle the check for Google Play services. It can also re-use the override you defined - for {@link android.support.v4.app.FragmentActivity#onActivityResult onActivityResult()} that - receives any Google Play services results that occur when the user interacts with the - error dialog. The following snippet shows you a sample implementation of the callback method: + To add geofences, use the <code><a href="{@docRoot}reference/com/google/android/gms/location/GeofencingApi.html#addGeofences(com.google.android.gms.common.api.GoogleApiClient, com.google.android.gms.location.GeofencingRequest, android.app.PendingIntent)">{@code GeoencingApi.addGeofences()}</a></code> method. + Provide the Google API client, the <code><a href="{@docRoot}reference/com/google/android/gms/location/GeofencingRequest"> + GeofencingRequest</a></code> object, and the {@link android.app.PendingIntent}. + The following snippet, which processes the results in <code><a href="{@docRoot}reference/com/google/android/gms/common/api/ResultCallback.html#onResult(R)"> + onResult()</a></code>, assumes that the main activity implements <code><a href="{@docRoot}reference/com/google/android/gms/common/api/ResultCallback.html"> + ResultCallback</a></code>: </p> <pre> -public class MainActivity extends FragmentActivity implements - ConnectionCallbacks, - OnConnectionFailedListener, - OnAddGeofencesResultListener { - ... - // Implementation of OnConnectionFailedListener.onConnectionFailed - @Override - public void onConnectionFailed(ConnectionResult connectionResult) { - // Turn off the request flag - mInProgress = false; - /* - * If the error has a resolution, start a Google Play services - * activity to resolve it. - */ - if (connectionResult.hasResolution()) { - try { - connectionResult.startResolutionForResult( - this, - CONNECTION_FAILURE_RESOLUTION_REQUEST); - } catch (SendIntentException e) { - // Log the error - e.printStackTrace(); - } - // If no resolution is available, display an error dialog - } else { - // Get the error code - int errorCode = connectionResult.getErrorCode(); - // Get the error dialog from Google Play services - Dialog errorDialog = GooglePlayServicesUtil.getErrorDialog( - errorCode, - this, - CONNECTION_FAILURE_RESOLUTION_REQUEST); - // If Google Play services can provide an error dialog - if (errorDialog != null) { - // Create a new DialogFragment for the error dialog - ErrorDialogFragment errorFragment = - new ErrorDialogFragment(); - // Set the dialog in the DialogFragment - errorFragment.setDialog(errorDialog); - // Show the error dialog in the DialogFragment - errorFragment.show( - getSupportFragmentManager(), - "Geofence Detection"); - } - } - } +public class MainActivity extends FragmentActivity { ... -} + LocationServices.GeofencingApi.addGeofences( + mGoogleApiClient, + getGeofencingRequest(), + getGeofencePendingIntent() + ).setResultCallback(this); </pre> -<!-- - Handle Geofence Transitions - --> + + <h2 id="HandleGeofenceTransitions">Handle Geofence Transitions</h2> <p> When Location Services detects that the user has entered or exited a geofence, it sends out the {@link android.content.Intent} contained in the {@link android.app.PendingIntent} - you included in the request to add geofences. This {@link android.content.Intent} is + you included in the request to add geofences. This {@link android.content.Intent} is received + by a service like <code>GeofenceTransitionsIntentService</code>, + which obtains the geofencing event from the intent, determines the type of Geofence transition(s), + and determines which of the defined geofences was triggered. It then sends a notification as + the output. </p> -<h3>Define an IntentService</h3> <p> The following snippet shows how to define an {@link android.app.IntentService} that posts a notification when a geofence transition occurs. When the user clicks the notification, the app's main activity appears: </p> <pre> -public class ReceiveTransitionsIntentService extends IntentService { - ... - /** - * Sets an identifier for the service - */ - public ReceiveTransitionsIntentService() { - super("ReceiveTransitionsIntentService"); - } - /** - * Handles incoming intents - *@param intent The Intent sent by Location Services. This - * Intent is provided - * to Location Services (inside a PendingIntent) when you call - * addGeofences() - */ - @Override +public class GeofenceTransitionsIntentService extends IntentService { + ... protected void onHandleIntent(Intent intent) { - // First check for errors - if (LocationClient.hasError(intent)) { - // Get the error code with a static method - int errorCode = LocationClient.getErrorCode(intent); - // Log the error - Log.e("ReceiveTransitionsIntentService", - "Location Services error: " + - Integer.toString(errorCode)); - /* - * You can also send the error code to an Activity or - * Fragment with a broadcast Intent - */ - /* - * If there's no error, get the transition type and the IDs - * of the geofence or geofences that triggered the transition - */ - } else { - // Get the type of transition (entry or exit) - int transitionType = - LocationClient.getGeofenceTransition(intent); - // Test that a valid transition was reported - if ( - (transitionType == Geofence.GEOFENCE_TRANSITION_ENTER) - || - (transitionType == Geofence.GEOFENCE_TRANSITION_EXIT) - ) { - List <Geofence> triggerList = - getTriggeringGeofences(intent); + GeofencingEvent geofencingEvent = GeofencingEvent.fromIntent(intent); + if (geofencingEvent.hasError()) { + String errorMessage = GeofenceErrorMessages.getErrorString(this, + geofencingEvent.getErrorCode()); + Log.e(TAG, errorMessage); + return; + } - String[] triggerIds = new String[geofenceList.size()]; + // Get the transition type. + int geofenceTransition = geofencingEvent.getGeofenceTransition(); + + // Test that the reported transition was of interest. + if (geofenceTransition == Geofence.GEOFENCE_TRANSITION_ENTER || + geofenceTransition == Geofence.GEOFENCE_TRANSITION_EXIT) { + + // Get the geofences that were triggered. A single event can trigger + // multiple geofences. + List<Geofence> triggeringGeofences = geofencingEvent.getTriggeringGeofences(); + + // Get the transition details as a String. + String geofenceTransitionDetails = getGeofenceTransitionDetails( + this, + geofenceTransition, + triggeringGeofences + ); - for (int i = 0; i < triggerIds.length; i++) { - // Store the Id of each geofence - triggerIds[i] = triggerList.get(i).getRequestId(); - } - /* - * At this point, you can store the IDs for further use - * display them, or display the details associated with - * them. - */ - } - // An invalid transition was reported + // Send notification and log the transition details. + sendNotification(geofenceTransitionDetails); + Log.i(TAG, geofenceTransitionDetails); } else { - Log.e("ReceiveTransitionsIntentService", - "Geofence transition error: " + - Integer.toString()transitionType)); + // Log the error. + Log.e(TAG, getString(R.string.geofence_transition_invalid_type, + geofenceTransition)); } } - ... -} -</pre> -<!-- Specify the IntentService in the manifest --> -<h3>Specify the IntentService in the manifest</h3> -<p> - To identify the {@link android.app.IntentService} to the system, add a - <code><a href="{@docRoot}guide/topics/manifest/service-element.html"><service></a></code> - element to the app manifest. For example: -</p> -<pre> -<service - android:name="com.example.android.location.ReceiveTransitionsIntentService" - android:label="@string/app_name" - android:exported="false"> -</service> </pre> -<p> - Notice that you don't have to specify intent filters for the service, because it only receives - explicit intents. How the incoming geofence transition intents are created is described in the - section <a href="#requestmonitoring">Send the monitoring request</a>. -</p> + +<p>After detecting the transition event via the {@link android.app.PendingIntent}, + this {@link android.app.IntentService} gets the geofence transition type and tests whether + it is one of the events the app uses to trigger notifications -- either + <code><a href="{@docRoot}reference/com/google/android/gms/location/Geofence.html#GEOFENCE_TRANSITION_ENTER">GEOFENCE_TRANSITION_ENTER</a></code> + or <code><a href="{@docRoot}reference/com/google/android/gms/location/Geofence.html#GEOFENCE_TRANSITION_EXIT">GEOFENCE_TRANSITION_EXIT</a></code> + in this case. The service then sends a notification and logs the transition details.</p> <!-- Remove Geofences --> <h2 id="StopGeofenceMonitoring">Stop Geofence Monitoring</h2> -<p> - To stop geofence monitoring, you remove the geofences themselves. You can remove a specific - set of geofences or all the geofences associated with a {@link android.app.PendingIntent}. The - procedure is similar to adding geofences. The first operation gets a location - client for the removal request, and the second makes the request using the client. -</p> -<p> - The callback methods that Location Services invokes when it has finished removing geofences - are defined in the interface -<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationClient.OnRemoveGeofencesResultListener.html">LocationClient.OnRemoveGeofencesResultListener</a></code>. Declare - this interface as part of your class definition, and then add definitions for its two methods: -</p> -<dl> - <dt> -<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationClient.OnRemoveGeofencesResultListener.html#onRemoveGeofencesByPendingIntentResult(int, android.app.PendingIntent)">onRemoveGeofencesByPendingIntentResult()</a></code> - </dt> - <dd> - Callback invoked when Location Services finishes a request to remove all geofences made - by the method -<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationClient.html#removeGeofences(android.app.PendingIntent, com.google.android.gms.location.LocationClient.OnRemoveGeofencesResultListener)">removeGeofences(PendingIntent, LocationClient.OnRemoveGeofencesResultListener)</a></code>. - </dd> - <dt> -<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationClient.OnRemoveGeofencesResultListener.html#onRemoveGeofencesByRequestIdsResult(int, java.lang.String[])">onRemoveGeofencesByRequestIdsResult(List<String>, LocationClient.OnRemoveGeofencesResultListener)</a></code> - </dt> - <dd> - Callback invoked when Location Services finished a request to remove a set of geofences, - specified by their geofence IDs, by the method -<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationClient.html#removeGeofences(java.util.List<java.lang.String>, com.google.android.gms.location.LocationClient.OnRemoveGeofencesResultListener)">removeGeofences(List<String>, LocationClient.OnRemoveGeofencesResultListener)</a></code>. - </dd> -</dl> -<p> - Examples of implementing these methods are shown in the next snippets. -</p> -<h3>Remove all geofences</h3> -<p> - Since removing geofences uses some of the methods you use to add geofences, start by defining - another request type: -</p> -<pre> -public class MainActivity extends FragmentActivity implements - ConnectionCallbacks, - OnConnectionFailedListener, - OnAddGeofencesResultListener { - ... - // Enum type for controlling the type of removal requested - public enum REQUEST_TYPE = {ADD, REMOVE_INTENT} - ... -} -</pre> -<p> - Start the removal request by getting a connection to Location Services. If the connection fails, -<code><a href="{@docRoot}reference/com/google/android/gms/common/GooglePlayServicesClient.ConnectionCallbacks.html#onConnected(android.os.Bundle)">onConnected()</a></code> isn't called, - and the request stops. The following snippet shows how to start the request: -</p> -<pre> -public class MainActivity extends FragmentActivity implements - ConnectionCallbacks, - OnConnectionFailedListener, - OnAddGeofencesResultListener { - ... - /** - * Start a request to remove geofences by calling - * LocationClient.connect() - */ - public void removeGeofences(PendingIntent requestIntent) { - // Record the type of removal request - mRequestType = REMOVE_INTENT; - /* - * Test for Google Play services after setting the request type. - * If Google Play services isn't present, the request can be - * restarted. - */ - if (!servicesConnected()) { - return; - } - // Store the PendingIntent - mGeofenceRequestIntent = requestIntent; - /* - * Create a new location client object. Since the current - * activity class implements ConnectionCallbacks and - * OnConnectionFailedListener, pass the current activity object - * as the listener for both parameters - */ - mLocationClient = new LocationClient(this, this, this); - // If a request is not already underway - if (!mInProgress) { - // Indicate that a request is underway - mInProgress = true; - // Request a connection from the client to Location Services - mLocationClient.connect(); - } else { - /* - * A request is already underway. You can handle - * this situation by disconnecting the client, - * re-setting the flag, and then re-trying the - * request. - */ - } - } - ... -} -</pre> -<p> - When Location Services invokes the callback method indicating that the connection is open, - make the request to remove all geofences. Disconnect the client after making the request. - For example: -</p> -<pre> -public class MainActivity extends FragmentActivity implements - ConnectionCallbacks, - OnConnectionFailedListener, - OnAddGeofencesResultListener { - ... - /** - * Once the connection is available, send a request to remove the - * Geofences. The method signature used depends on which type of - * remove request was originally received. - */ - private void onConnected(Bundle dataBundle) { - /* - * Choose what to do based on the request type set in - * removeGeofences - */ - switch (mRequestType) { - ... - case REMOVE_INTENT : - mLocationClient.removeGeofences( - mGeofenceRequestIntent, this); - break; - ... - } - } - ... -} -</pre> -<p> - Although the call to -<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationClient.html#removeGeofences(android.app.PendingIntent, com.google.android.gms.location.LocationClient.OnRemoveGeofencesResultListener)">removeGeofences(PendingIntent, LocationClient.OnRemoveGeofencesResultListener)</a></code> Services calls - returns immediately, the result of the removal request is indeterminate until Location Services - calls -<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationClient.OnRemoveGeofencesResultListener.html#onRemoveGeofencesByPendingIntentResult(int, android.app.PendingIntent)">onRemoveGeofencesByPendingIntentResult()</a></code>. - The following snippet shows how to define this method: -</p> -<pre> -public class MainActivity extends FragmentActivity implements - ConnectionCallbacks, - OnConnectionFailedListener, - OnAddGeofencesResultListener { - ... - /** - * When the request to remove geofences by PendingIntent returns, - * handle the result. - * - *@param statusCode the code returned by Location Services - *@param requestIntent The Intent used to request the removal. - */ - @Override - public void onRemoveGeofencesByPendingIntentResult(int statusCode, - PendingIntent requestIntent) { - // If removing the geofences was successful - if (statusCode == LocationStatusCodes.SUCCESS) { - /* - * Handle successful removal of geofences here. - * You can send out a broadcast intent or update the UI. - * geofences into the Intent's extended data. - */ - } else { - // If adding the geocodes failed - /* - * Report errors here. - * You can log the error using Log.e() or update - * the UI. - */ - } - /* - * Disconnect the location client regardless of the - * request status, and indicate that a request is no - * longer in progress - */ - mInProgress = false; - mLocationClient.disconnect(); - } - ... -} -</pre> -<h3>Remove individual geofences</h3> -<p> - The procedure for removing an individual geofence or set of geofences is similar to the - removal of all geofences. To specify the geofences you want remove, add their geofence ID - values to a {@link java.util.List} of String objects. Pass this {@link java.util.List} to a - different definition of {@code removeGeofences} with the appropriate signature. This method - then starts the removal process. -</p> -<p> - Start by adding a request type for removing geofences by a list, and also add a global variable - for storing the list of geofences: -</p> -<pre> - ... - // Enum type for controlling the type of removal requested - public enum REQUEST_TYPE = {ADD, REMOVE_INTENT, REMOVE_LIST} - // Store the list of geofence Ids to remove - String<List> mGeofencesToRemove; -</pre> -<p> - Next, define a list of geofences you want to remove. For example, this snippet removes the -<code><a href="{@docRoot}reference/com/google/android/gms/location/Geofence.html">Geofence</a></code> - defined by the geofence ID "1": -</p> -<pre> -public class MainActivity extends FragmentActivity implements - ConnectionCallbacks, - OnConnectionFailedListener, - OnAddGeofencesResultListener { - ... - List<String> listOfGeofences = - Collections.singletonList("1"); - removeGeofences(listOfGeofences); - ... -} -</pre> -<p> - The following snippet defines the {@code removeGeofences()} method: -</p> -<pre> -public class MainActivity extends FragmentActivity implements - ConnectionCallbacks, - OnConnectionFailedListener, - OnAddGeofencesResultListener { - ... - /** - * Start a request to remove monitoring by - * calling LocationClient.connect() - * - */ - public void removeGeofences(List<String> geofenceIds) { - // If Google Play services is unavailable, exit - // Record the type of removal request - mRequestType = REMOVE_LIST; - /* - * Test for Google Play services after setting the request type. - * If Google Play services isn't present, the request can be - * restarted. - */ - if (!servicesConnected()) { - return; - } - // Store the list of geofences to remove - mGeofencesToRemove = geofenceIds; - /* - * Create a new location client object. Since the current - * activity class implements ConnectionCallbacks and - * OnConnectionFailedListener, pass the current activity object - * as the listener for both parameters - */ - mLocationClient = new LocationClient(this, this, this); - // If a request is not already underway - if (!mInProgress) { - // Indicate that a request is underway - mInProgress = true; - // Request a connection from the client to Location Services - mLocationClient.connect(); - } else { - /* - * A request is already underway. You can handle - * this situation by disconnecting the client, - * re-setting the flag, and then re-trying the - * request. - */ - } - } - ... -} -</pre> -<p> - When Location Services invokes the callback method indicating that the connection is open, - make the request to remove the list of geofences. Disconnect the client after making the request. - For example: + +<p>Stopping geofence monitoring when it is no longer needed or desired can help save battery + power and CPU cycles on the device. You can stop geofence monitoring + in the main activity used to add and remove geofences; removing a geofence stops it + immediately. The API provides methods to + remove geofences either by request IDs, or by removing geofences associated with a given + {@link android.app.PendingIntent}. </p> -<pre> -public class MainActivity extends FragmentActivity implements - ConnectionCallbacks, - OnConnectionFailedListener, - OnAddGeofencesResultListener { - ... - private void onConnected(Bundle dataBundle) { - ... - switch (mRequestType) { - ... - // If removeGeofencesById was called - case REMOVE_LIST : - mLocationClient.removeGeofences( - mGeofencesToRemove, this); - break; - ... - } - ... - } - ... -} -</pre> <p> - Define an implementation of -<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationClient.OnRemoveGeofencesResultListener.html#onRemoveGeofencesByRequestIdsResult(int, java.lang.String[])">onRemoveGeofencesByRequestIdsResult()</a></code>. - Location Services invokes this callback method to indicate that the request to remove a list of - geofences is complete. In this method, examine the incoming status code and take the - appropriate action: + The following snippet removes geofences by {@link android.app.PendingIntent}, stopping all + further notification when the device enters or exits previously added geofences: </p> <pre> -public class MainActivity extends FragmentActivity implements - ConnectionCallbacks, - OnConnectionFailedListener, - OnAddGeofencesResultListener { - ... - /** - * When the request to remove geofences by IDs returns, handle the - * result. - * - * @param statusCode The code returned by Location Services - * @param geofenceRequestIds The IDs removed - */ - @Override - public void onRemoveGeofencesByRequestIdsResult( - int statusCode, String[] geofenceRequestIds) { - // If removing the geocodes was successful - if (LocationStatusCodes.SUCCESS == statusCode) { - /* - * Handle successful removal of geofences here. - * You can send out a broadcast intent or update the UI. - * geofences into the Intent's extended data. - */ - } else { - // If removing the geofences failed - /* - * Report errors here. - * You can log the error using Log.e() or update - * the UI. - */ - } - // Indicate that a request is no longer in progress - mInProgress = false; - // Disconnect the location client - mLocationClient.disconnect(); - } - ... +LocationServices.GeofencingApi.removeGeofences( + mGoogleApiClient, + // This is the same pending intent that was used in addGeofences(). + getGeofencePendingIntent() + ).setResultCallback(this); // Result processed in onResult(). } </pre> + <p> - You can combine geofencing with other location-aware features, such as periodic location updates - or activity recognition, which are described in other lessons in this class. -</p> -<p> - The next lesson, - <a href="activity-recognition.html">Recognizing the User's Current Activity</a>, shows you how - to request and receive activity updates. At regular intervals, Location Services can send you - information about the user's current physical activity. Based on this information, you can - change your app's behavior; for example, you can switch to a longer update interval if you - detect that the user is walking instead of driving. + You can combine geofencing with other location-aware features, such as periodic location updates. + For more information, see the other lessons in this class. </p> diff --git a/docs/html/training/location/index.jd b/docs/html/training/location/index.jd index 35e177f923b0..c4dec9928d82 100644 --- a/docs/html/training/location/index.jd +++ b/docs/html/training/location/index.jd @@ -81,4 +81,10 @@ startpage=true Learn how to convert a location's latitude and longitude into an address (reverse geocoding). </dd> + <dt> + <b><a href="geofencing.html">Creating and Monitoring Geofences</a></b> + </dt> <dd> + Learn how to define one or more geographic areas as locations of interest, + called geofences, and detect when the user is close to or inside a geofence. + </dd> </dl> diff --git a/docs/html/training/training_toc.cs b/docs/html/training/training_toc.cs index 89e72f1706b9..11ae1a6f2d67 100644 --- a/docs/html/training/training_toc.cs +++ b/docs/html/training/training_toc.cs @@ -736,6 +736,10 @@ include the action bar on devices running Android 2.1 or higher." Displaying a Location Address </a> </li> + <li><a href="<?cs var:toroot ?>training/location/geofencing.html"> + Creating and Monitoring Geofences + </a> + </li> </ul> </li> </ul> diff --git a/docs/html/wear/images/partners/acer.png b/docs/html/wear/images/partners/acer.png Binary files differnew file mode 100644 index 000000000000..439de80535b3 --- /dev/null +++ b/docs/html/wear/images/partners/acer.png diff --git a/docs/html/wear/images/partners/arm.png b/docs/html/wear/images/partners/arm.png Binary files differnew file mode 100644 index 000000000000..3e2f642f02b9 --- /dev/null +++ b/docs/html/wear/images/partners/arm.png diff --git a/docs/html/wear/images/partners/huawei.png b/docs/html/wear/images/partners/huawei.png Binary files differnew file mode 100644 index 000000000000..9099ed4751e8 --- /dev/null +++ b/docs/html/wear/images/partners/huawei.png diff --git a/docs/html/wear/index.jd b/docs/html/wear/index.jd index 27e809825aec..316f5ca03881 100644 --- a/docs/html/wear/index.jd +++ b/docs/html/wear/index.jd @@ -202,6 +202,12 @@ page.type=about <div class="landing-partners cols"> <div class="col-4"> + <img src="/wear/images/partners/acer.png" alt="Acer"> + </div> + <div class="col-4"> + <img src="/wear/images/partners/arm.png" alt="ARM"> + </div> + <div class="col-4"> <img src="/wear/images/partners/asus.png" alt="Asus"> </div> <div class="col-4"> @@ -214,6 +220,9 @@ page.type=about <img src="/wear/images/partners/htc.png" alt="HTC"> </div> <div class="col-4"> + <img src="/wear/images/partners/huawei.png" alt="Huawei"> + </div> + <div class="col-4"> <img src="/wear/images/partners/intel.png" alt="Intel"> </div> <div class="col-4"> diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java index 132c6ef6fa30..e2f7799786a0 100644 --- a/graphics/java/android/graphics/Bitmap.java +++ b/graphics/java/android/graphics/Bitmap.java @@ -16,11 +16,14 @@ package android.graphics; +import android.annotation.CheckResult; +import android.annotation.ColorInt; import android.annotation.NonNull; import android.os.Parcel; import android.os.Parcelable; import android.os.Trace; import android.util.DisplayMetrics; + import dalvik.system.VMRuntime; import java.io.OutputStream; @@ -37,21 +40,14 @@ public final class Bitmap implements Parcelable { * @see Bitmap#setDensity(int) */ public static final int DENSITY_NONE = 0; - - /** - * Note: mNativeBitmap is used by FaceDetector_jni.cpp - * Don't change/rename without updating FaceDetector_jni.cpp - * - * @hide - */ - public final long mNativeBitmap; + + private final long mSkBitmapPtr; /** * Backing buffer for the Bitmap. */ private byte[] mBuffer; - @SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"}) // Keep to finalize native resources private final BitmapFinalizer mFinalizer; private final boolean mIsMutable; @@ -92,11 +88,11 @@ public final class Bitmap implements Parcelable { sDefaultDensity = density; } + @SuppressWarnings("deprecation") static int getDefaultDensity() { if (sDefaultDensity >= 0) { return sDefaultDensity; } - //noinspection deprecation sDefaultDensity = DisplayMetrics.DENSITY_DEVICE; return sDefaultDensity; } @@ -105,7 +101,7 @@ public final class Bitmap implements Parcelable { * Private constructor that must received an already allocated native bitmap * int (pointer). */ - @SuppressWarnings({"UnusedDeclaration"}) // called from JNI + // called from JNI Bitmap(long nativeBitmap, byte[] buffer, int width, int height, int density, boolean isMutable, boolean requestPremultiplied, byte[] ninePatchChunk, NinePatch.InsetStruct ninePatchInsets) { @@ -120,7 +116,7 @@ public final class Bitmap implements Parcelable { mBuffer = buffer; // we delete this in our finalizer - mNativeBitmap = nativeBitmap; + mSkBitmapPtr = nativeBitmap; mNinePatchChunk = ninePatchChunk; mNinePatchInsets = ninePatchInsets; @@ -136,7 +132,7 @@ public final class Bitmap implements Parcelable { * Native bitmap has been reconfigured, so set premult and cached * width/height values */ - @SuppressWarnings({"UnusedDeclaration"}) // called from JNI + // called from JNI void reinit(int width, int height, boolean requestPremultiplied) { mWidth = width; mHeight = height; @@ -227,7 +223,7 @@ public final class Bitmap implements Parcelable { throw new IllegalStateException("native-backed bitmaps may not be reconfigured"); } - nativeReconfigure(mNativeBitmap, width, height, config.nativeInt, mBuffer.length, + nativeReconfigure(mSkBitmapPtr, width, height, config.nativeInt, mBuffer.length, mRequestPremultiplied); mWidth = width; mHeight = height; @@ -305,7 +301,7 @@ public final class Bitmap implements Parcelable { */ public void recycle() { if (!mRecycled && mFinalizer.mNativeBitmap != 0) { - if (nativeRecycle(mNativeBitmap)) { + if (nativeRecycle(mSkBitmapPtr)) { // return value indicates whether native pixel object was actually recycled. // false indicates that it is still in use at the native level and these // objects should not be collected now. They will be collected later when the @@ -331,13 +327,13 @@ public final class Bitmap implements Parcelable { * Returns the generation ID of this bitmap. The generation ID changes * whenever the bitmap is modified. This can be used as an efficient way to * check if a bitmap has changed. - * + * * @return The current generation ID for this bitmap. */ public int getGenerationId() { - return nativeGenerationId(mNativeBitmap); + return nativeGenerationId(mSkBitmapPtr); } - + /** * This is called by methods that want to throw an exception if the bitmap * has already been recycled. @@ -399,12 +395,12 @@ public final class Bitmap implements Parcelable { * encoded: red is stored with 5 bits of precision (32 possible * values), green is stored with 6 bits of precision (64 possible * values) and blue is stored with 5 bits of precision. - * + * * This configuration can produce slight visual artifacts depending * on the configuration of the source. For instance, without * dithering, the result might show a greenish tint. To get better * results dithering should be applied. - * + * * This configuration may be useful when using opaque bitmaps * that do not require high color fidelity. */ @@ -414,18 +410,18 @@ public final class Bitmap implements Parcelable { * Each pixel is stored on 2 bytes. The three RGB color channels * and the alpha channel (translucency) are stored with a 4 bits * precision (16 possible values.) - * + * * This configuration is mostly useful if the application needs * to store translucency information but also needs to save * memory. - * + * * It is recommended to use {@link #ARGB_8888} instead of this * configuration. * * Note: as of {@link android.os.Build.VERSION_CODES#KITKAT}, * any bitmap created with this configuration will be created * using {@link #ARGB_8888} instead. - * + * * @deprecated Because of the poor quality of this configuration, * it is advised to use {@link #ARGB_8888} instead. */ @@ -436,7 +432,7 @@ public final class Bitmap implements Parcelable { * Each pixel is stored on 4 bytes. Each channel (RGB and alpha * for translucency) is stored with 8 bits of precision (256 * possible values.) - * + * * This configuration is very flexible and offers the best * quality. It should be used whenever possible. */ @@ -444,11 +440,10 @@ public final class Bitmap implements Parcelable { final int nativeInt; - @SuppressWarnings({"deprecation"}) private static Config sConfigs[] = { null, ALPHA_8, null, RGB_565, ARGB_4444, ARGB_8888 }; - + Config(int ni) { this.nativeInt = ni; } @@ -492,7 +487,7 @@ public final class Bitmap implements Parcelable { throw new RuntimeException("Buffer not large enough for pixels"); } - nativeCopyPixelsToBuffer(mNativeBitmap, dst); + nativeCopyPixelsToBuffer(mSkBitmapPtr, dst); // now update the buffer's position int position = dst.position(); @@ -532,7 +527,7 @@ public final class Bitmap implements Parcelable { throw new RuntimeException("Buffer not large enough for pixels"); } - nativeCopyPixelsFromBuffer(mNativeBitmap, src); + nativeCopyPixelsFromBuffer(mSkBitmapPtr, src); // now update the buffer's position int position = src.position(); @@ -554,7 +549,7 @@ public final class Bitmap implements Parcelable { */ public Bitmap copy(Config config, boolean isMutable) { checkRecycled("Can't copy a recycled bitmap"); - Bitmap b = nativeCopy(mNativeBitmap, config.nativeInt, isMutable); + Bitmap b = nativeCopy(mSkBitmapPtr, config.nativeInt, isMutable); if (b != null) { b.setPremultiplied(mRequestPremultiplied); b.mDensity = mDensity; @@ -564,7 +559,7 @@ public final class Bitmap implements Parcelable { /** * Creates a new bitmap, scaled from an existing bitmap, when possible. If the - * specified width and height are the same as the current width and height of + * specified width and height are the same as the current width and height of * the source bitmap, the source bitmap is returned and no new bitmap is * created. * @@ -639,7 +634,7 @@ public final class Bitmap implements Parcelable { * transformed by the optional matrix. The new bitmap may be the * same object as source, or a copy may have been made. It is * initialized with the same density as the original bitmap. - * + * * If the source bitmap is immutable and the requested subset is the * same as the source bitmap itself, then the source bitmap is * returned and no new bitmap is created. @@ -781,8 +776,8 @@ public final class Bitmap implements Parcelable { * @param config The bitmap config to create. * @param hasAlpha If the bitmap is ARGB_8888 this flag can be used to mark the * bitmap as opaque. Doing so will clear the bitmap in black - * instead of transparent. - * + * instead of transparent. + * * @throws IllegalArgumentException if the width or height are <= 0 */ private static Bitmap createBitmap(int width, int height, Config config, boolean hasAlpha) { @@ -800,8 +795,8 @@ public final class Bitmap implements Parcelable { * @param config The bitmap config to create. * @param hasAlpha If the bitmap is ARGB_8888 this flag can be used to mark the * bitmap as opaque. Doing so will clear the bitmap in black - * instead of transparent. - * + * instead of transparent. + * * @throws IllegalArgumentException if the width or height are <= 0 */ private static Bitmap createBitmap(DisplayMetrics display, int width, int height, @@ -815,7 +810,7 @@ public final class Bitmap implements Parcelable { } bm.setHasAlpha(hasAlpha); if (config == Config.ARGB_8888 && !hasAlpha) { - nativeErase(bm.mNativeBitmap, 0xff000000); + nativeErase(bm.mSkBitmapPtr, 0xff000000); } // No need to initialize the bitmap to zeroes with other configs; // it is backed by a VM byte array which is by definition preinitialized @@ -1005,7 +1000,7 @@ public final class Bitmap implements Parcelable { throw new IllegalArgumentException("quality must be 0..100"); } Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, "Bitmap.compress"); - boolean result = nativeCompress(mNativeBitmap, format.nativeInt, quality, + boolean result = nativeCompress(mSkBitmapPtr, format.nativeInt, quality, stream, new byte[WORKING_COMPRESS_STORAGE]); Trace.traceEnd(Trace.TRACE_TAG_RESOURCES); return result; @@ -1022,12 +1017,12 @@ public final class Bitmap implements Parcelable { * <p>Indicates whether pixels stored in this bitmaps are stored pre-multiplied. * When a pixel is pre-multiplied, the RGB components have been multiplied by * the alpha component. For instance, if the original color is a 50% - * translucent red <code>(128, 255, 0, 0)</code>, the pre-multiplied form is + * translucent red <code>(128, 255, 0, 0)</code>, the pre-multiplied form is * <code>(128, 128, 0, 0)</code>.</p> - * + * * <p>This method always returns false if {@link #getConfig()} is * {@link Bitmap.Config#RGB_565}.</p> - * + * * <p>The return value is undefined if {@link #getConfig()} is * {@link Bitmap.Config#ALPHA_8}.</p> * @@ -1046,7 +1041,7 @@ public final class Bitmap implements Parcelable { * @see BitmapFactory.Options#inPremultiplied */ public final boolean isPremultiplied() { - return nativeIsPremultiplied(mNativeBitmap); + return nativeIsPremultiplied(mSkBitmapPtr); } /** @@ -1071,7 +1066,7 @@ public final class Bitmap implements Parcelable { */ public final void setPremultiplied(boolean premultiplied) { mRequestPremultiplied = premultiplied; - nativeSetPremultiplied(mNativeBitmap, premultiplied); + nativeSetPremultiplied(mSkBitmapPtr, premultiplied); } /** Returns the bitmap's width */ @@ -1137,7 +1132,7 @@ public final class Bitmap implements Parcelable { public int getScaledHeight(int targetDensity) { return scaleFromDensity(getHeight(), mDensity, targetDensity); } - + /** * @hide */ @@ -1145,11 +1140,11 @@ public final class Bitmap implements Parcelable { if (sdensity == DENSITY_NONE || tdensity == DENSITY_NONE || sdensity == tdensity) { return size; } - + // Scale by tdensity / sdensity, rounding up. return ((size * tdensity) + (sdensity >> 1)) / sdensity; } - + /** * Return the number of bytes between rows in the bitmap's pixels. Note that * this refers to the pixels as stored natively by the bitmap. If you call @@ -1163,7 +1158,7 @@ public final class Bitmap implements Parcelable { * @return number of bytes between rows of the native bitmap pixels. */ public final int getRowBytes() { - return nativeRowBytes(mNativeBitmap); + return nativeRowBytes(mSkBitmapPtr); } /** @@ -1206,7 +1201,7 @@ public final class Bitmap implements Parcelable { * that config, otherwise return null. */ public final Config getConfig() { - return Config.nativeToConfig(nativeConfig(mNativeBitmap)); + return Config.nativeToConfig(nativeConfig(mSkBitmapPtr)); } /** Returns true if the bitmap's config supports per-pixel alpha, and @@ -1218,7 +1213,7 @@ public final class Bitmap implements Parcelable { * it will return true by default. */ public final boolean hasAlpha() { - return nativeHasAlpha(mNativeBitmap); + return nativeHasAlpha(mSkBitmapPtr); } /** @@ -1232,28 +1227,28 @@ public final class Bitmap implements Parcelable { * non-opaque per-pixel alpha values. */ public void setHasAlpha(boolean hasAlpha) { - nativeSetHasAlpha(mNativeBitmap, hasAlpha, mRequestPremultiplied); + nativeSetHasAlpha(mSkBitmapPtr, hasAlpha, mRequestPremultiplied); } /** * Indicates whether the renderer responsible for drawing this * bitmap should attempt to use mipmaps when this bitmap is drawn * scaled down. - * + * * If you know that you are going to draw this bitmap at less than * 50% of its original size, you may be able to obtain a higher * quality - * + * * This property is only a suggestion that can be ignored by the * renderer. It is not guaranteed to have any effect. - * + * * @return true if the renderer should attempt to use mipmaps, * false otherwise - * + * * @see #setHasMipMap(boolean) */ public final boolean hasMipMap() { - return nativeHasMipMap(mNativeBitmap); + return nativeHasMipMap(mSkBitmapPtr); } /** @@ -1264,7 +1259,7 @@ public final class Bitmap implements Parcelable { * If you know that you are going to draw this bitmap at less than * 50% of its original size, you may be able to obtain a higher * quality by turning this property on. - * + * * Note that if the renderer respects this hint it might have to * allocate extra memory to hold the mipmap levels for this bitmap. * @@ -1277,7 +1272,7 @@ public final class Bitmap implements Parcelable { * @see #hasMipMap() */ public final void setHasMipMap(boolean hasMipMap) { - nativeSetHasMipMap(mNativeBitmap, hasMipMap); + nativeSetHasMipMap(mSkBitmapPtr, hasMipMap); } /** @@ -1285,12 +1280,12 @@ public final class Bitmap implements Parcelable { * * @throws IllegalStateException if the bitmap is not mutable. */ - public void eraseColor(int c) { + public void eraseColor(@ColorInt int c) { checkRecycled("Can't erase a recycled bitmap"); if (!isMutable()) { throw new IllegalStateException("cannot erase immutable bitmaps"); } - nativeErase(mNativeBitmap, c); + nativeErase(mSkBitmapPtr, c); } /** @@ -1303,10 +1298,11 @@ public final class Bitmap implements Parcelable { * @return The argb {@link Color} at the specified coordinate * @throws IllegalArgumentException if x, y exceed the bitmap's bounds */ + @ColorInt public int getPixel(int x, int y) { checkRecycled("Can't call getPixel() on a recycled bitmap"); checkPixelAccess(x, y); - return nativeGetPixel(mNativeBitmap, x, y); + return nativeGetPixel(mSkBitmapPtr, x, y); } /** @@ -1332,21 +1328,21 @@ public final class Bitmap implements Parcelable { * @throws ArrayIndexOutOfBoundsException if the pixels array is too small * to receive the specified number of pixels. */ - public void getPixels(int[] pixels, int offset, int stride, + public void getPixels(@ColorInt int[] pixels, int offset, int stride, int x, int y, int width, int height) { checkRecycled("Can't call getPixels() on a recycled bitmap"); if (width == 0 || height == 0) { return; // nothing to do } checkPixelsAccess(x, y, width, height, offset, stride, pixels); - nativeGetPixels(mNativeBitmap, pixels, offset, stride, + nativeGetPixels(mSkBitmapPtr, pixels, offset, stride, x, y, width, height); } /** * Shared code to check for illegal arguments passed to getPixel() * or setPixel() - * + * * @param x x coordinate of the pixel * @param y y coordinate of the pixel */ @@ -1414,13 +1410,13 @@ public final class Bitmap implements Parcelable { * @throws IllegalArgumentException if x, y are outside of the bitmap's * bounds. */ - public void setPixel(int x, int y, int color) { + public void setPixel(int x, int y, @ColorInt int color) { checkRecycled("Can't call setPixel() on a recycled bitmap"); if (!isMutable()) { throw new IllegalStateException(); } checkPixelAccess(x, y); - nativeSetPixel(mNativeBitmap, x, y, color); + nativeSetPixel(mSkBitmapPtr, x, y, color); } /** @@ -1446,7 +1442,7 @@ public final class Bitmap implements Parcelable { * @throws ArrayIndexOutOfBoundsException if the pixels array is too small * to receive the specified number of pixels. */ - public void setPixels(int[] pixels, int offset, int stride, + public void setPixels(@ColorInt int[] pixels, int offset, int stride, int x, int y, int width, int height) { checkRecycled("Can't call setPixels() on a recycled bitmap"); if (!isMutable()) { @@ -1456,7 +1452,7 @@ public final class Bitmap implements Parcelable { return; // nothing to do } checkPixelsAccess(x, y, width, height, offset, stride, pixels); - nativeSetPixels(mNativeBitmap, pixels, offset, stride, + nativeSetPixels(mSkBitmapPtr, pixels, offset, stride, x, y, width, height); } @@ -1494,7 +1490,7 @@ public final class Bitmap implements Parcelable { */ public void writeToParcel(Parcel p, int flags) { checkRecycled("Can't parcel a recycled bitmap"); - if (!nativeWriteToParcel(mNativeBitmap, mIsMutable, mDensity, p)) { + if (!nativeWriteToParcel(mSkBitmapPtr, mIsMutable, mDensity, p)) { throw new RuntimeException("native writeToParcel failed"); } } @@ -1506,6 +1502,7 @@ public final class Bitmap implements Parcelable { * * @return new bitmap containing the alpha channel of the original bitmap. */ + @CheckResult public Bitmap extractAlpha() { return extractAlpha(null, null); } @@ -1522,9 +1519,9 @@ public final class Bitmap implements Parcelable { * -2, -2, so that drawing the alpha bitmap offset by (-2, -2) and then * drawing the original would result in the blur visually aligning with * the original. - * + * * <p>The initial density of the returned bitmap is the same as the original's. - * + * * @param paint Optional paint used to modify the alpha values in the * resulting bitmap. Pass null for default behavior. * @param offsetXY Optional array that returns the X (index 0) and Y @@ -1535,10 +1532,11 @@ public final class Bitmap implements Parcelable { * Canvas.drawBitmap(), where the color(s) will be taken from the * paint that is passed to the draw call. */ + @CheckResult public Bitmap extractAlpha(Paint paint, int[] offsetXY) { checkRecycled("Can't extractAlpha on a recycled bitmap"); long nativePaint = paint != null ? paint.getNativeInstance() : 0; - Bitmap bm = nativeExtractAlpha(mNativeBitmap, nativePaint, offsetXY); + Bitmap bm = nativeExtractAlpha(mSkBitmapPtr, nativePaint, offsetXY); if (bm == null) { throw new RuntimeException("Failed to extractAlpha on Bitmap"); } @@ -1552,7 +1550,7 @@ public final class Bitmap implements Parcelable { * If other is null, return false. */ public boolean sameAs(Bitmap other) { - return this == other || (other != null && nativeSameAs(mNativeBitmap, other.mNativeBitmap)); + return this == other || (other != null && nativeSameAs(mSkBitmapPtr, other.mSkBitmapPtr)); } /** @@ -1567,7 +1565,12 @@ public final class Bitmap implements Parcelable { * and therefore is harmless. */ public void prepareToDraw() { - nativePrepareToDraw(mNativeBitmap); + nativePrepareToDraw(mSkBitmapPtr); + } + + /** @hide */ + public final long getSkBitmap() { + return mSkBitmapPtr; } private static class BitmapFinalizer { @@ -1658,8 +1661,4 @@ public final class Bitmap implements Parcelable { private static native boolean nativeHasMipMap(long nativeBitmap); private static native void nativeSetHasMipMap(long nativeBitmap, boolean hasMipMap); private static native boolean nativeSameAs(long nativeBitmap0, long nativeBitmap1); - - /* package */ final long ni() { - return mNativeBitmap; - } } diff --git a/graphics/java/android/graphics/BitmapShader.java b/graphics/java/android/graphics/BitmapShader.java index 5e004a370342..f2f890e0c5a7 100644 --- a/graphics/java/android/graphics/BitmapShader.java +++ b/graphics/java/android/graphics/BitmapShader.java @@ -42,7 +42,7 @@ public class BitmapShader extends Shader { mBitmap = bitmap; mTileX = tileX; mTileY = tileY; - final long b = bitmap.ni(); + final long b = bitmap.getSkBitmap(); init(nativeCreate(b, tileX.nativeInt, tileY.nativeInt)); } diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java index e4c2f0e7ffc1..150f1950a81f 100644 --- a/graphics/java/android/graphics/Canvas.java +++ b/graphics/java/android/graphics/Canvas.java @@ -16,9 +16,11 @@ package android.graphics; +import android.annotation.ColorInt; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.Size; import android.text.GraphicsOperations; import android.text.SpannableString; import android.text.SpannedString; @@ -154,7 +156,7 @@ public class Canvas { throw new IllegalStateException("Immutable bitmap passed to Canvas constructor"); } throwIfCannotDraw(bitmap); - mNativeCanvasWrapper = initRaster(bitmap.ni()); + mNativeCanvasWrapper = initRaster(bitmap.getSkBitmap()); mFinalizer = new CanvasFinalizer(mNativeCanvasWrapper); mBitmap = bitmap; mDensity = bitmap.mDensity; @@ -219,7 +221,7 @@ public class Canvas { } throwIfCannotDraw(bitmap); - native_setBitmap(mNativeCanvasWrapper, bitmap.ni(), true); + native_setBitmap(mNativeCanvasWrapper, bitmap.getSkBitmap(), true); mDensity = bitmap.mDensity; } @@ -1012,7 +1014,7 @@ public class Canvas { * * @param color the color to draw onto the canvas */ - public void drawColor(int color) { + public void drawColor(@ColorInt int color) { native_drawColor(mNativeCanvasWrapper, color, PorterDuff.Mode.SRC_OVER.nativeInt); } @@ -1023,7 +1025,7 @@ public class Canvas { * @param color the color to draw with * @param mode the porter-duff mode to apply to the color */ - public void drawColor(int color, @NonNull PorterDuff.Mode mode) { + public void drawColor(@ColorInt int color, @NonNull PorterDuff.Mode mode) { native_drawColor(mNativeCanvasWrapper, color, mode.nativeInt); } @@ -1054,14 +1056,15 @@ public class Canvas { * "points" that are drawn is really (count >> 1). * @param paint The paint used to draw the points */ - public void drawPoints(float[] pts, int offset, int count, @NonNull Paint paint) { + public void drawPoints(@Size(multiple=2) float[] pts, int offset, int count, + @NonNull Paint paint) { native_drawPoints(mNativeCanvasWrapper, pts, offset, count, paint.getNativeInstance()); } /** * Helper for drawPoints() that assumes you want to draw the entire array */ - public void drawPoints(@NonNull float[] pts, @NonNull Paint paint) { + public void drawPoints(@Size(multiple=2) @NonNull float[] pts, @NonNull Paint paint) { drawPoints(pts, 0, pts.length, paint); } @@ -1104,11 +1107,11 @@ public class Canvas { * (count >> 2). * @param paint The paint used to draw the points */ - public void drawLines(float[] pts, int offset, int count, Paint paint) { + public void drawLines(@Size(min=4,multiple=2) float[] pts, int offset, int count, Paint paint) { native_drawLines(mNativeCanvasWrapper, pts, offset, count, paint.getNativeInstance()); } - public void drawLines(@NonNull float[] pts, @NonNull Paint paint) { + public void drawLines(@Size(min=4,multiple=2) @NonNull float[] pts, @NonNull Paint paint) { drawLines(pts, 0, pts.length, paint); } @@ -1339,7 +1342,7 @@ public class Canvas { */ public void drawBitmap(@NonNull Bitmap bitmap, float left, float top, @Nullable Paint paint) { throwIfCannotDraw(bitmap); - native_drawBitmap(mNativeCanvasWrapper, bitmap.ni(), left, top, + native_drawBitmap(mNativeCanvasWrapper, bitmap.getSkBitmap(), left, top, paint != null ? paint.getNativeInstance() : 0, mDensity, mScreenDensity, bitmap.mDensity); } @@ -1385,7 +1388,7 @@ public class Canvas { bottom = src.bottom; } - native_drawBitmap(mNativeCanvasWrapper, bitmap.ni(), left, top, right, bottom, + native_drawBitmap(mNativeCanvasWrapper, bitmap.getSkBitmap(), left, top, right, bottom, dst.left, dst.top, dst.right, dst.bottom, nativePaint, mScreenDensity, bitmap.mDensity); } @@ -1432,7 +1435,7 @@ public class Canvas { bottom = src.bottom; } - native_drawBitmap(mNativeCanvasWrapper, bitmap.ni(), left, top, right, bottom, + native_drawBitmap(mNativeCanvasWrapper, bitmap.getSkBitmap(), left, top, right, bottom, dst.left, dst.top, dst.right, dst.bottom, nativePaint, mScreenDensity, bitmap.mDensity); } @@ -1513,7 +1516,7 @@ public class Canvas { * @param paint May be null. The paint used to draw the bitmap */ public void drawBitmap(@NonNull Bitmap bitmap, @NonNull Matrix matrix, @Nullable Paint paint) { - nativeDrawBitmapMatrix(mNativeCanvasWrapper, bitmap.ni(), matrix.ni(), + nativeDrawBitmapMatrix(mNativeCanvasWrapper, bitmap.getSkBitmap(), matrix.ni(), paint != null ? paint.getNativeInstance() : 0); } @@ -1568,7 +1571,7 @@ public class Canvas { // no mul by 2, since we need only 1 color per vertex checkRange(colors.length, colorOffset, count); } - nativeDrawBitmapMesh(mNativeCanvasWrapper, bitmap.ni(), meshWidth, meshHeight, + nativeDrawBitmapMesh(mNativeCanvasWrapper, bitmap.getSkBitmap(), meshWidth, meshHeight, verts, vertOffset, colors, colorOffset, paint != null ? paint.getNativeInstance() : 0); } @@ -1828,7 +1831,8 @@ public class Canvas { * @param paint The paint used for the text (e.g. color, size, style) */ @Deprecated - public void drawPosText(@NonNull char[] text, int index, int count, @NonNull float[] pos, + public void drawPosText(@NonNull char[] text, int index, int count, + @NonNull @Size(multiple=2) float[] pos, @NonNull Paint paint) { if (index < 0 || index + count > text.length || count*2 > pos.length) { throw new IndexOutOfBoundsException(); @@ -1851,7 +1855,8 @@ public class Canvas { * @param paint The paint used for the text (e.g. color, size, style) */ @Deprecated - public void drawPosText(@NonNull String text, @NonNull float[] pos, @NonNull Paint paint) { + public void drawPosText(@NonNull String text, @NonNull @Size(multiple=2) float[] pos, + @NonNull Paint paint) { drawPosText(text.toCharArray(), 0, text.length(), pos, paint); } diff --git a/graphics/java/android/graphics/Color.java b/graphics/java/android/graphics/Color.java index 3fe567279591..666dbd89139f 100644 --- a/graphics/java/android/graphics/Color.java +++ b/graphics/java/android/graphics/Color.java @@ -16,6 +16,8 @@ package android.graphics; +import android.annotation.ColorInt; +import android.annotation.Size; import android.util.MathUtils; import com.android.internal.util.XmlUtils; @@ -35,23 +37,24 @@ import java.util.Locale; * 0xFFFFFFFF */ public class Color { - public static final int BLACK = 0xFF000000; - public static final int DKGRAY = 0xFF444444; - public static final int GRAY = 0xFF888888; - public static final int LTGRAY = 0xFFCCCCCC; - public static final int WHITE = 0xFFFFFFFF; - public static final int RED = 0xFFFF0000; - public static final int GREEN = 0xFF00FF00; - public static final int BLUE = 0xFF0000FF; - public static final int YELLOW = 0xFFFFFF00; - public static final int CYAN = 0xFF00FFFF; - public static final int MAGENTA = 0xFFFF00FF; - public static final int TRANSPARENT = 0; + @ColorInt public static final int BLACK = 0xFF000000; + @ColorInt public static final int DKGRAY = 0xFF444444; + @ColorInt public static final int GRAY = 0xFF888888; + @ColorInt public static final int LTGRAY = 0xFFCCCCCC; + @ColorInt public static final int WHITE = 0xFFFFFFFF; + @ColorInt public static final int RED = 0xFFFF0000; + @ColorInt public static final int GREEN = 0xFF00FF00; + @ColorInt public static final int BLUE = 0xFF0000FF; + @ColorInt public static final int YELLOW = 0xFFFFFF00; + @ColorInt public static final int CYAN = 0xFF00FFFF; + @ColorInt public static final int MAGENTA = 0xFFFF00FF; + @ColorInt public static final int TRANSPARENT = 0; /** * Return the alpha component of a color int. This is the same as saying * color >>> 24 */ + @ColorInt public static int alpha(int color) { return color >>> 24; } @@ -60,6 +63,7 @@ public class Color { * Return the red component of a color int. This is the same as saying * (color >> 16) & 0xFF */ + @ColorInt public static int red(int color) { return (color >> 16) & 0xFF; } @@ -68,6 +72,7 @@ public class Color { * Return the green component of a color int. This is the same as saying * (color >> 8) & 0xFF */ + @ColorInt public static int green(int color) { return (color >> 8) & 0xFF; } @@ -76,6 +81,7 @@ public class Color { * Return the blue component of a color int. This is the same as saying * color & 0xFF */ + @ColorInt public static int blue(int color) { return color & 0xFF; } @@ -90,6 +96,7 @@ public class Color { * @param green Green component [0..255] of the color * @param blue Blue component [0..255] of the color */ + @ColorInt public static int rgb(int red, int green, int blue) { return (0xFF << 24) | (red << 16) | (green << 8) | blue; } @@ -104,6 +111,7 @@ public class Color { * @param green Green component [0..255] of the color * @param blue Blue component [0..255] of the color */ + @ColorInt public static int argb(int alpha, int red, int green, int blue) { return (alpha << 24) | (red << 16) | (green << 8) | blue; } @@ -115,7 +123,7 @@ public class Color { * * @hide Pending API council */ - public static float hue(int color) { + public static float hue(@ColorInt int color) { int r = (color >> 16) & 0xFF; int g = (color >> 8) & 0xFF; int b = color & 0xFF; @@ -157,7 +165,7 @@ public class Color { * * @hide Pending API council */ - public static float saturation(int color) { + public static float saturation(@ColorInt int color) { int r = (color >> 16) & 0xFF; int g = (color >> 8) & 0xFF; int b = color & 0xFF; @@ -184,7 +192,7 @@ public class Color { * * @hide Pending API council */ - public static float brightness(int color) { + public static float brightness(@ColorInt int color) { int r = (color >> 16) & 0xFF; int g = (color >> 8) & 0xFF; int b = color & 0xFF; @@ -206,7 +214,8 @@ public class Color { * 'aqua', 'fuchsia', 'lime', 'maroon', 'navy', 'olive', 'purple', * 'silver', 'teal'. */ - public static int parseColor(String colorString) { + @ColorInt + public static int parseColor(@Size(min=1) String colorString) { if (colorString.charAt(0) == '#') { // Use a long to avoid rollovers on #ffXXXXXX long color = Long.parseLong(colorString.substring(1), 16); @@ -237,7 +246,8 @@ public class Color { * * @hide Pending API council */ - public static int HSBtoColor(float[] hsb) { + @ColorInt + public static int HSBtoColor(@Size(3) float[] hsb) { return HSBtoColor(hsb[0], hsb[1], hsb[2]); } @@ -254,6 +264,7 @@ public class Color { * * @hide Pending API council */ + @ColorInt public static int HSBtoColor(float h, float s, float b) { h = MathUtils.constrain(h, 0.0f, 1.0f); s = MathUtils.constrain(s, 0.0f, 1.0f); @@ -317,7 +328,7 @@ public class Color { * @param blue blue component value [0..255] * @param hsv 3 element array which holds the resulting HSV components. */ - public static void RGBToHSV(int red, int green, int blue, float hsv[]) { + public static void RGBToHSV(int red, int green, int blue, @Size(3) float hsv[]) { if (hsv.length < 3) { throw new RuntimeException("3 components required for hsv"); } @@ -332,7 +343,7 @@ public class Color { * @param color the argb color to convert. The alpha component is ignored. * @param hsv 3 element array which holds the resulting HSV components. */ - public static void colorToHSV(int color, float hsv[]) { + public static void colorToHSV(@ColorInt int color, @Size(3) float hsv[]) { RGBToHSV((color >> 16) & 0xFF, (color >> 8) & 0xFF, color & 0xFF, hsv); } @@ -345,7 +356,7 @@ public class Color { * @param hsv 3 element array which holds the input HSV components. * @return the resulting argb color */ - public static int HSVToColor(float hsv[]) { + public static int HSVToColor(@Size(3) float hsv[]) { return HSVToColor(0xFF, hsv); } @@ -360,7 +371,7 @@ public class Color { * @param hsv 3 element array which holds the input HSV components. * @return the resulting argb color */ - public static int HSVToColor(int alpha, float hsv[]) { + public static int HSVToColor(int alpha, @Size(3) float hsv[]) { if (hsv.length < 3) { throw new RuntimeException("3 components required for hsv"); } @@ -379,6 +390,7 @@ public class Color { * * @hide */ + @ColorInt public static int getHtmlColor(String color) { Integer i = sColorNameMap.get(color.toLowerCase(Locale.ROOT)); if (i != null) { diff --git a/graphics/java/android/graphics/ImageFormat.java b/graphics/java/android/graphics/ImageFormat.java index 3efb9c0bf67d..49c424748fdd 100644 --- a/graphics/java/android/graphics/ImageFormat.java +++ b/graphics/java/android/graphics/ImageFormat.java @@ -356,6 +356,38 @@ public class ImageFormat { public static final int RAW10 = 0x25; /** + * Android dense depth image format. + * + * Each pixel is 16 bits, representing a depth ranging measurement from + * a depth camera or similar sensor. + * + * <p>This format assumes + * <ul> + * <li>an even width</li> + * <li>an even height</li> + * <li>a horizontal stride multiple of 16 pixels</li> + * </ul> + * </p> + * + * <pre> y_size = stride * height </pre> + * + * When produced by a camera, the units are millimeters. + */ + public static final int DEPTH16 = 0x44363159; + + /** + * Android sparse depth point cloud format. + * + * <p>A variable-length list of 3D points, with each point represented + * by a triple of floats.</p> + * + * <p>The number of points is {@code (size of the buffer in bytes) / 12}. + * + * The coordinate system and units depend on the source of the point cloud data. + */ + public static final int DEPTH_POINT_CLOUD = 0x101; + + /** * Use this function to retrieve the number of bits per pixel of an * ImageFormat. * @@ -376,6 +408,7 @@ public class ImageFormat { case Y8: return 8; case Y16: + case DEPTH16: return 16; case NV21: return 12; @@ -412,6 +445,8 @@ public class ImageFormat { case YUV_420_888: case RAW_SENSOR: case RAW10: + case DEPTH16: + case DEPTH_POINT_CLOUD: return true; } diff --git a/graphics/java/android/graphics/NinePatch.java b/graphics/java/android/graphics/NinePatch.java index ebc86aad37a9..9c4299aa5d70 100644 --- a/graphics/java/android/graphics/NinePatch.java +++ b/graphics/java/android/graphics/NinePatch.java @@ -98,7 +98,7 @@ public class NinePatch { public NinePatch(Bitmap bitmap, byte[] chunk, String srcName) { mBitmap = bitmap; mSrcName = srcName; - mNativeChunk = validateNinePatchChunk(mBitmap.ni(), chunk); + mNativeChunk = validateNinePatchChunk(mBitmap.getSkBitmap(), chunk); } /** @@ -199,12 +199,12 @@ public class NinePatch { } void drawSoftware(Canvas canvas, RectF location, Paint paint) { - nativeDraw(canvas.getNativeCanvasWrapper(), location, mBitmap.ni(), mNativeChunk, + nativeDraw(canvas.getNativeCanvasWrapper(), location, mBitmap.getSkBitmap(), mNativeChunk, paint != null ? paint.getNativeInstance() : 0, canvas.mDensity, mBitmap.mDensity); } void drawSoftware(Canvas canvas, Rect location, Paint paint) { - nativeDraw(canvas.getNativeCanvasWrapper(), location, mBitmap.ni(), mNativeChunk, + nativeDraw(canvas.getNativeCanvasWrapper(), location, mBitmap.getSkBitmap(), mNativeChunk, paint != null ? paint.getNativeInstance() : 0, canvas.mDensity, mBitmap.mDensity); } @@ -252,7 +252,7 @@ public class NinePatch { * that are transparent. */ public final Region getTransparentRegion(Rect bounds) { - long r = nativeGetTransparentRegion(mBitmap.ni(), mNativeChunk, bounds); + long r = nativeGetTransparentRegion(mBitmap.getSkBitmap(), mNativeChunk, bounds); return r != 0 ? new Region(r) : null; } diff --git a/graphics/java/android/graphics/Outline.java b/graphics/java/android/graphics/Outline.java index f76184fe77e1..aa404082715e 100644 --- a/graphics/java/android/graphics/Outline.java +++ b/graphics/java/android/graphics/Outline.java @@ -16,6 +16,7 @@ package android.graphics; +import android.annotation.FloatRange; import android.annotation.NonNull; import android.graphics.drawable.Drawable; @@ -101,7 +102,7 @@ public final class Outline { * assumed by the drawing system to fully cover content beneath it, * meaning content beneath may be optimized away. */ - public void setAlpha(float alpha) { + public void setAlpha(@FloatRange(from=0.0, to=1.0) float alpha) { mAlpha = alpha; } diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java index 681bc62ca53f..0656b2e42bcd 100644 --- a/graphics/java/android/graphics/Paint.java +++ b/graphics/java/android/graphics/Paint.java @@ -16,6 +16,7 @@ package android.graphics; +import android.annotation.ColorInt; import android.text.GraphicsOperations; import android.text.SpannableString; import android.text.SpannedString; @@ -777,6 +778,7 @@ public class Paint { * * @return the paint's color (and alpha). */ + @ColorInt public native int getColor(); /** @@ -787,7 +789,7 @@ public class Paint { * * @param color The new color (including alpha) to set in the paint. */ - public native void setColor(int color); + public native void setColor(@ColorInt int color); /** * Helper to getColor() that just returns the color's alpha value. This is diff --git a/graphics/java/android/graphics/PorterDuff.java b/graphics/java/android/graphics/PorterDuff.java index f5fbe70e2658..dcccf35b88de 100644 --- a/graphics/java/android/graphics/PorterDuff.java +++ b/graphics/java/android/graphics/PorterDuff.java @@ -51,7 +51,7 @@ public class PorterDuff { Sc*(1 - Da) + Dc*(1 - Sa) + max(Sc, Dc)] */ LIGHTEN (17), /** [Sa * Da, Sc * Dc] */ - MULTIPLY (24), + MULTIPLY (13), /** [Sa + Da - Sa * Da, Sc + Dc - Sc * Dc] */ SCREEN (14), /** Saturate(S + D) */ diff --git a/graphics/java/android/graphics/drawable/ColorDrawable.java b/graphics/java/android/graphics/drawable/ColorDrawable.java index 85e02b7ab274..f75ab36b0e99 100644 --- a/graphics/java/android/graphics/drawable/ColorDrawable.java +++ b/graphics/java/android/graphics/drawable/ColorDrawable.java @@ -16,6 +16,7 @@ package android.graphics.drawable; +import android.annotation.ColorInt; import android.annotation.NonNull; import android.graphics.*; import android.graphics.PorterDuff.Mode; @@ -62,7 +63,7 @@ public class ColorDrawable extends Drawable { * * @param color The color to draw. */ - public ColorDrawable(int color) { + public ColorDrawable(@ColorInt int color) { mColorState = new ColorState(); setColor(color); @@ -117,6 +118,7 @@ public class ColorDrawable extends Drawable { * * @return int The color to draw. */ + @ColorInt public int getColor() { return mColorState.mUseColor; } @@ -128,7 +130,7 @@ public class ColorDrawable extends Drawable { * * @param color The color to draw. */ - public void setColor(int color) { + public void setColor(@ColorInt int color) { if (mColorState.mBaseColor != color || mColorState.mUseColor != color) { mColorState.mBaseColor = mColorState.mUseColor = color; invalidateSelf(); diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java index 2cc192c5ce0a..16760c7e5769 100644 --- a/graphics/java/android/graphics/drawable/Drawable.java +++ b/graphics/java/android/graphics/drawable/Drawable.java @@ -16,6 +16,7 @@ package android.graphics.drawable; +import android.annotation.ColorInt; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.res.ColorStateList; @@ -544,7 +545,7 @@ public abstract class Drawable { * @see #setTintList(ColorStateList) * @see #setTintMode(PorterDuff.Mode) */ - public void setTint(int tintColor) { + public void setTint(@ColorInt int tintColor) { setTintList(ColorStateList.valueOf(tintColor)); } diff --git a/graphics/java/android/graphics/drawable/GradientDrawable.java b/graphics/java/android/graphics/drawable/GradientDrawable.java index 6ea23d49949f..eff152c8d2f4 100644 --- a/graphics/java/android/graphics/drawable/GradientDrawable.java +++ b/graphics/java/android/graphics/drawable/GradientDrawable.java @@ -16,6 +16,7 @@ package android.graphics.drawable; +import android.annotation.ColorInt; import android.content.res.ColorStateList; import android.content.res.Resources; import android.content.res.TypedArray; @@ -181,7 +182,7 @@ public class GradientDrawable extends Drawable { * Create a new gradient drawable given an orientation and an array * of colors for the gradient. */ - public GradientDrawable(Orientation orientation, int[] colors) { + public GradientDrawable(Orientation orientation, @ColorInt int[] colors) { this(new GradientState(orientation, colors), null); } @@ -250,7 +251,7 @@ public class GradientDrawable extends Drawable { * @see #mutate() * @see #setStroke(int, int, float, float) */ - public void setStroke(int width, int color) { + public void setStroke(int width, @ColorInt int color) { setStroke(width, color, 0, 0); } @@ -286,7 +287,7 @@ public class GradientDrawable extends Drawable { * @see #mutate() * @see #setStroke(int, int) */ - public void setStroke(int width, int color, float dashWidth, float dashGap) { + public void setStroke(int width, @ColorInt int color, float dashWidth, float dashGap) { mGradientState.setStroke(width, ColorStateList.valueOf(color), dashWidth, dashGap); setStrokeInternal(width, color, dashWidth, dashGap); } @@ -501,7 +502,7 @@ public class GradientDrawable extends Drawable { * @see #mutate() * @see #setColor(int) */ - public void setColors(int[] colors) { + public void setColors(@ColorInt int[] colors) { mGradientState.setColors(colors); mGradientIsDirty = true; invalidateSelf(); @@ -713,7 +714,7 @@ public class GradientDrawable extends Drawable { * @see #mutate() * @see #setColors(int[]) */ - public void setColor(int argb) { + public void setColor(@ColorInt int argb) { mGradientState.setColorStateList(ColorStateList.valueOf(argb)); mFillPaint.setColor(argb); invalidateSelf(); diff --git a/graphics/java/android/graphics/drawable/Ripple.java b/graphics/java/android/graphics/drawable/Ripple.java deleted file mode 100644 index 138d73a8a4a3..000000000000 --- a/graphics/java/android/graphics/drawable/Ripple.java +++ /dev/null @@ -1,578 +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 android.graphics.drawable; - -import android.animation.Animator; -import android.animation.AnimatorListenerAdapter; -import android.animation.ObjectAnimator; -import android.animation.TimeInterpolator; -import android.graphics.Canvas; -import android.graphics.CanvasProperty; -import android.graphics.Paint; -import android.graphics.Rect; -import android.util.MathUtils; -import android.view.HardwareCanvas; -import android.view.RenderNodeAnimator; -import android.view.animation.LinearInterpolator; - -import java.util.ArrayList; - -/** - * Draws a Material ripple. - */ -class Ripple { - private static final TimeInterpolator LINEAR_INTERPOLATOR = new LinearInterpolator(); - private static final TimeInterpolator DECEL_INTERPOLATOR = new LogInterpolator(); - - private static final float GLOBAL_SPEED = 1.0f; - private static final float WAVE_TOUCH_DOWN_ACCELERATION = 1024.0f * GLOBAL_SPEED; - private static final float WAVE_TOUCH_UP_ACCELERATION = 3400.0f * GLOBAL_SPEED; - private static final float WAVE_OPACITY_DECAY_VELOCITY = 3.0f / GLOBAL_SPEED; - - private static final long RIPPLE_ENTER_DELAY = 80; - - // Hardware animators. - private final ArrayList<RenderNodeAnimator> mRunningAnimations = new ArrayList<>(); - - private final RippleDrawable mOwner; - - /** Bounds used for computing max radius. */ - private final Rect mBounds; - - /** Maximum ripple radius. */ - private float mOuterRadius; - - /** Screen density used to adjust pixel-based velocities. */ - private float mDensity; - - private float mStartingX; - private float mStartingY; - private float mClampedStartingX; - private float mClampedStartingY; - - // Hardware rendering properties. - private CanvasProperty<Paint> mPropPaint; - private CanvasProperty<Float> mPropRadius; - private CanvasProperty<Float> mPropX; - private CanvasProperty<Float> mPropY; - - // Software animators. - private ObjectAnimator mAnimRadius; - private ObjectAnimator mAnimOpacity; - private ObjectAnimator mAnimX; - private ObjectAnimator mAnimY; - - // Temporary paint used for creating canvas properties. - private Paint mTempPaint; - - // Software rendering properties. - private float mOpacity = 1; - private float mOuterX; - private float mOuterY; - - // Values used to tween between the start and end positions. - private float mTweenRadius = 0; - private float mTweenX = 0; - private float mTweenY = 0; - - /** Whether we should be drawing hardware animations. */ - private boolean mHardwareAnimating; - - /** Whether we can use hardware acceleration for the exit animation. */ - private boolean mCanUseHardware; - - /** Whether we have an explicit maximum radius. */ - private boolean mHasMaxRadius; - - /** Whether we were canceled externally and should avoid self-removal. */ - private boolean mCanceled; - - private boolean mHasPendingHardwareExit; - private int mPendingRadiusDuration; - private int mPendingOpacityDuration; - - /** - * Creates a new ripple. - */ - public Ripple(RippleDrawable owner, Rect bounds, float startingX, float startingY) { - mOwner = owner; - mBounds = bounds; - - mStartingX = startingX; - mStartingY = startingY; - } - - public void setup(float maxRadius, float density) { - if (maxRadius >= 0) { - mHasMaxRadius = true; - mOuterRadius = maxRadius; - } else { - final float halfWidth = mBounds.width() / 2.0f; - final float halfHeight = mBounds.height() / 2.0f; - mOuterRadius = (float) Math.sqrt(halfWidth * halfWidth + halfHeight * halfHeight); - } - - mOuterX = 0; - mOuterY = 0; - mDensity = density; - - clampStartingPosition(); - } - - public boolean isHardwareAnimating() { - return mHardwareAnimating; - } - - private void clampStartingPosition() { - final float cX = mBounds.exactCenterX(); - final float cY = mBounds.exactCenterY(); - final float dX = mStartingX - cX; - final float dY = mStartingY - cY; - final float r = mOuterRadius; - if (dX * dX + dY * dY > r * r) { - // Point is outside the circle, clamp to the circumference. - final double angle = Math.atan2(dY, dX); - mClampedStartingX = cX + (float) (Math.cos(angle) * r); - mClampedStartingY = cY + (float) (Math.sin(angle) * r); - } else { - mClampedStartingX = mStartingX; - mClampedStartingY = mStartingY; - } - } - - public void onHotspotBoundsChanged() { - if (!mHasMaxRadius) { - final float halfWidth = mBounds.width() / 2.0f; - final float halfHeight = mBounds.height() / 2.0f; - mOuterRadius = (float) Math.sqrt(halfWidth * halfWidth + halfHeight * halfHeight); - - clampStartingPosition(); - } - } - - public void setOpacity(float a) { - mOpacity = a; - invalidateSelf(); - } - - public float getOpacity() { - return mOpacity; - } - - @SuppressWarnings("unused") - public void setRadiusGravity(float r) { - mTweenRadius = r; - invalidateSelf(); - } - - @SuppressWarnings("unused") - public float getRadiusGravity() { - return mTweenRadius; - } - - @SuppressWarnings("unused") - public void setXGravity(float x) { - mTweenX = x; - invalidateSelf(); - } - - @SuppressWarnings("unused") - public float getXGravity() { - return mTweenX; - } - - @SuppressWarnings("unused") - public void setYGravity(float y) { - mTweenY = y; - invalidateSelf(); - } - - @SuppressWarnings("unused") - public float getYGravity() { - return mTweenY; - } - - /** - * Draws the ripple centered at (0,0) using the specified paint. - */ - public boolean draw(Canvas c, Paint p) { - final boolean canUseHardware = c.isHardwareAccelerated(); - if (mCanUseHardware != canUseHardware && mCanUseHardware) { - // We've switched from hardware to non-hardware mode. Panic. - cancelHardwareAnimations(true); - } - mCanUseHardware = canUseHardware; - - final boolean hasContent; - if (canUseHardware && (mHardwareAnimating || mHasPendingHardwareExit)) { - hasContent = drawHardware((HardwareCanvas) c, p); - } else { - hasContent = drawSoftware(c, p); - } - - return hasContent; - } - - private boolean drawHardware(HardwareCanvas c, Paint p) { - if (mHasPendingHardwareExit) { - cancelHardwareAnimations(false); - startPendingHardwareExit(c, p); - } - - c.drawCircle(mPropX, mPropY, mPropRadius, mPropPaint); - - return true; - } - - private boolean drawSoftware(Canvas c, Paint p) { - boolean hasContent = false; - - final int paintAlpha = p.getAlpha(); - final int alpha = (int) (paintAlpha * mOpacity + 0.5f); - final float radius = MathUtils.lerp(0, mOuterRadius, mTweenRadius); - if (alpha > 0 && radius > 0) { - final float x = MathUtils.lerp( - mClampedStartingX - mBounds.exactCenterX(), mOuterX, mTweenX); - final float y = MathUtils.lerp( - mClampedStartingY - mBounds.exactCenterY(), mOuterY, mTweenY); - p.setAlpha(alpha); - c.drawCircle(x, y, radius, p); - p.setAlpha(paintAlpha); - hasContent = true; - } - - return hasContent; - } - - /** - * Returns the maximum bounds of the ripple relative to the ripple center. - */ - public void getBounds(Rect bounds) { - final int outerX = (int) mOuterX; - final int outerY = (int) mOuterY; - final int r = (int) mOuterRadius + 1; - bounds.set(outerX - r, outerY - r, outerX + r, outerY + r); - } - - /** - * Specifies the starting position relative to the drawable bounds. No-op if - * the ripple has already entered. - */ - public void move(float x, float y) { - mStartingX = x; - mStartingY = y; - - clampStartingPosition(); - } - - /** - * Starts the enter animation. - */ - public void enter() { - cancel(); - - final int radiusDuration = (int) - (1000 * Math.sqrt(mOuterRadius / WAVE_TOUCH_DOWN_ACCELERATION * mDensity) + 0.5); - - final ObjectAnimator radius = ObjectAnimator.ofFloat(this, "radiusGravity", 1); - radius.setAutoCancel(true); - radius.setDuration(radiusDuration); - radius.setInterpolator(LINEAR_INTERPOLATOR); - radius.setStartDelay(RIPPLE_ENTER_DELAY); - - final ObjectAnimator cX = ObjectAnimator.ofFloat(this, "xGravity", 1); - cX.setAutoCancel(true); - cX.setDuration(radiusDuration); - cX.setInterpolator(LINEAR_INTERPOLATOR); - cX.setStartDelay(RIPPLE_ENTER_DELAY); - - final ObjectAnimator cY = ObjectAnimator.ofFloat(this, "yGravity", 1); - cY.setAutoCancel(true); - cY.setDuration(radiusDuration); - cY.setInterpolator(LINEAR_INTERPOLATOR); - cY.setStartDelay(RIPPLE_ENTER_DELAY); - - mAnimRadius = radius; - mAnimX = cX; - mAnimY = cY; - - // Enter animations always run on the UI thread, since it's unlikely - // that anything interesting is happening until the user lifts their - // finger. - radius.start(); - cX.start(); - cY.start(); - } - - /** - * Starts the exit animation. - */ - public void exit() { - final float radius = MathUtils.lerp(0, mOuterRadius, mTweenRadius); - final float remaining; - if (mAnimRadius != null && mAnimRadius.isRunning()) { - remaining = mOuterRadius - radius; - } else { - remaining = mOuterRadius; - } - - cancel(); - - final int radiusDuration = (int) (1000 * Math.sqrt(remaining / (WAVE_TOUCH_UP_ACCELERATION - + WAVE_TOUCH_DOWN_ACCELERATION) * mDensity) + 0.5); - final int opacityDuration = (int) (1000 * mOpacity / WAVE_OPACITY_DECAY_VELOCITY + 0.5f); - - if (mCanUseHardware) { - createPendingHardwareExit(radiusDuration, opacityDuration); - } else { - exitSoftware(radiusDuration, opacityDuration); - } - } - - private void createPendingHardwareExit(int radiusDuration, int opacityDuration) { - mHasPendingHardwareExit = true; - mPendingRadiusDuration = radiusDuration; - mPendingOpacityDuration = opacityDuration; - - // The animation will start on the next draw(). - invalidateSelf(); - } - - private void startPendingHardwareExit(HardwareCanvas c, Paint p) { - mHasPendingHardwareExit = false; - - final int radiusDuration = mPendingRadiusDuration; - final int opacityDuration = mPendingOpacityDuration; - - final float startX = MathUtils.lerp( - mClampedStartingX - mBounds.exactCenterX(), mOuterX, mTweenX); - final float startY = MathUtils.lerp( - mClampedStartingY - mBounds.exactCenterY(), mOuterY, mTweenY); - - final float startRadius = MathUtils.lerp(0, mOuterRadius, mTweenRadius); - final Paint paint = getTempPaint(p); - paint.setAlpha((int) (paint.getAlpha() * mOpacity + 0.5f)); - mPropPaint = CanvasProperty.createPaint(paint); - mPropRadius = CanvasProperty.createFloat(startRadius); - mPropX = CanvasProperty.createFloat(startX); - mPropY = CanvasProperty.createFloat(startY); - - final RenderNodeAnimator radiusAnim = new RenderNodeAnimator(mPropRadius, mOuterRadius); - radiusAnim.setDuration(radiusDuration); - radiusAnim.setInterpolator(DECEL_INTERPOLATOR); - radiusAnim.setTarget(c); - radiusAnim.start(); - - final RenderNodeAnimator xAnim = new RenderNodeAnimator(mPropX, mOuterX); - xAnim.setDuration(radiusDuration); - xAnim.setInterpolator(DECEL_INTERPOLATOR); - xAnim.setTarget(c); - xAnim.start(); - - final RenderNodeAnimator yAnim = new RenderNodeAnimator(mPropY, mOuterY); - yAnim.setDuration(radiusDuration); - yAnim.setInterpolator(DECEL_INTERPOLATOR); - yAnim.setTarget(c); - yAnim.start(); - - final RenderNodeAnimator opacityAnim = new RenderNodeAnimator(mPropPaint, - RenderNodeAnimator.PAINT_ALPHA, 0); - opacityAnim.setDuration(opacityDuration); - opacityAnim.setInterpolator(LINEAR_INTERPOLATOR); - opacityAnim.addListener(mAnimationListener); - opacityAnim.setTarget(c); - opacityAnim.start(); - - mRunningAnimations.add(radiusAnim); - mRunningAnimations.add(opacityAnim); - mRunningAnimations.add(xAnim); - mRunningAnimations.add(yAnim); - - mHardwareAnimating = true; - - // Set up the software values to match the hardware end values. - mOpacity = 0; - mTweenX = 1; - mTweenY = 1; - mTweenRadius = 1; - } - - /** - * Jump all animations to their end state. The caller is responsible for - * removing the ripple from the list of animating ripples. - */ - public void jump() { - mCanceled = true; - endSoftwareAnimations(); - cancelHardwareAnimations(true); - mCanceled = false; - } - - private void endSoftwareAnimations() { - if (mAnimRadius != null) { - mAnimRadius.end(); - mAnimRadius = null; - } - - if (mAnimOpacity != null) { - mAnimOpacity.end(); - mAnimOpacity = null; - } - - if (mAnimX != null) { - mAnimX.end(); - mAnimX = null; - } - - if (mAnimY != null) { - mAnimY.end(); - mAnimY = null; - } - } - - private Paint getTempPaint(Paint original) { - if (mTempPaint == null) { - mTempPaint = new Paint(); - } - mTempPaint.set(original); - return mTempPaint; - } - - private void exitSoftware(int radiusDuration, int opacityDuration) { - final ObjectAnimator radiusAnim = ObjectAnimator.ofFloat(this, "radiusGravity", 1); - radiusAnim.setAutoCancel(true); - radiusAnim.setDuration(radiusDuration); - radiusAnim.setInterpolator(DECEL_INTERPOLATOR); - - final ObjectAnimator xAnim = ObjectAnimator.ofFloat(this, "xGravity", 1); - xAnim.setAutoCancel(true); - xAnim.setDuration(radiusDuration); - xAnim.setInterpolator(DECEL_INTERPOLATOR); - - final ObjectAnimator yAnim = ObjectAnimator.ofFloat(this, "yGravity", 1); - yAnim.setAutoCancel(true); - yAnim.setDuration(radiusDuration); - yAnim.setInterpolator(DECEL_INTERPOLATOR); - - final ObjectAnimator opacityAnim = ObjectAnimator.ofFloat(this, "opacity", 0); - opacityAnim.setAutoCancel(true); - opacityAnim.setDuration(opacityDuration); - opacityAnim.setInterpolator(LINEAR_INTERPOLATOR); - opacityAnim.addListener(mAnimationListener); - - mAnimRadius = radiusAnim; - mAnimOpacity = opacityAnim; - mAnimX = xAnim; - mAnimY = yAnim; - - radiusAnim.start(); - opacityAnim.start(); - xAnim.start(); - yAnim.start(); - } - - /** - * Cancels all animations. The caller is responsible for removing - * the ripple from the list of animating ripples. - */ - public void cancel() { - mCanceled = true; - cancelSoftwareAnimations(); - cancelHardwareAnimations(false); - mCanceled = false; - } - - private void cancelSoftwareAnimations() { - if (mAnimRadius != null) { - mAnimRadius.cancel(); - mAnimRadius = null; - } - - if (mAnimOpacity != null) { - mAnimOpacity.cancel(); - mAnimOpacity = null; - } - - if (mAnimX != null) { - mAnimX.cancel(); - mAnimX = null; - } - - if (mAnimY != null) { - mAnimY.cancel(); - mAnimY = null; - } - } - - /** - * Cancels any running hardware animations. - */ - private void cancelHardwareAnimations(boolean jumpToEnd) { - final ArrayList<RenderNodeAnimator> runningAnimations = mRunningAnimations; - final int N = runningAnimations.size(); - for (int i = 0; i < N; i++) { - if (jumpToEnd) { - runningAnimations.get(i).end(); - } else { - runningAnimations.get(i).cancel(); - } - } - runningAnimations.clear(); - - if (mHasPendingHardwareExit) { - // If we had a pending hardware exit, jump to the end state. - mHasPendingHardwareExit = false; - - if (jumpToEnd) { - mOpacity = 0; - mTweenX = 1; - mTweenY = 1; - mTweenRadius = 1; - } - } - - mHardwareAnimating = false; - } - - private void removeSelf() { - // The owner will invalidate itself. - if (!mCanceled) { - mOwner.removeRipple(this); - } - } - - private void invalidateSelf() { - mOwner.invalidateSelf(); - } - - private final AnimatorListenerAdapter mAnimationListener = new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - removeSelf(); - } - }; - - /** - * Interpolator with a smooth log deceleration - */ - private static final class LogInterpolator implements TimeInterpolator { - @Override - public float getInterpolation(float input) { - return 1 - (float) Math.pow(400, -input * 1.4); - } - } -} diff --git a/graphics/java/android/graphics/drawable/RippleBackground.java b/graphics/java/android/graphics/drawable/RippleBackground.java index ef352890e424..6d1b1fecd51c 100644 --- a/graphics/java/android/graphics/drawable/RippleBackground.java +++ b/graphics/java/android/graphics/drawable/RippleBackground.java @@ -17,432 +17,162 @@ package android.graphics.drawable; import android.animation.Animator; -import android.animation.AnimatorListenerAdapter; +import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.animation.TimeInterpolator; import android.graphics.Canvas; import android.graphics.CanvasProperty; -import android.graphics.Color; import android.graphics.Paint; import android.graphics.Rect; -import android.util.MathUtils; +import android.util.FloatProperty; import android.view.HardwareCanvas; import android.view.RenderNodeAnimator; import android.view.animation.LinearInterpolator; -import java.util.ArrayList; - /** - * Draws a Material ripple. + * Draws a ripple background. */ -class RippleBackground { +class RippleBackground extends RippleComponent { private static final TimeInterpolator LINEAR_INTERPOLATOR = new LinearInterpolator(); - private static final float GLOBAL_SPEED = 1.0f; - private static final float WAVE_OPACITY_DECAY_VELOCITY = 3.0f / GLOBAL_SPEED; - private static final float WAVE_OUTER_OPACITY_EXIT_VELOCITY_MAX = 4.5f * GLOBAL_SPEED; - private static final float WAVE_OUTER_OPACITY_EXIT_VELOCITY_MIN = 1.5f * GLOBAL_SPEED; - private static final float WAVE_OUTER_SIZE_INFLUENCE_MAX = 200f; - private static final float WAVE_OUTER_SIZE_INFLUENCE_MIN = 40f; - - private static final int ENTER_DURATION = 667; - private static final int ENTER_DURATION_FAST = 100; - - // Hardware animators. - private final ArrayList<RenderNodeAnimator> mRunningAnimations = new ArrayList<>(); - - private final RippleDrawable mOwner; - - /** Bounds used for computing max radius. */ - private final Rect mBounds; - - /** ARGB color for drawing this ripple. */ - private int mColor; - - /** Maximum ripple radius. */ - private float mOuterRadius; - - /** Screen density used to adjust pixel-based velocities. */ - private float mDensity; + private static final int OPACITY_ENTER_DURATION = 600; + private static final int OPACITY_ENTER_DURATION_FAST = 120; + private static final int OPACITY_EXIT_DURATION = 480; // Hardware rendering properties. - private CanvasProperty<Paint> mPropOuterPaint; - private CanvasProperty<Float> mPropOuterRadius; - private CanvasProperty<Float> mPropOuterX; - private CanvasProperty<Float> mPropOuterY; - - // Software animators. - private ObjectAnimator mAnimOuterOpacity; - - // Temporary paint used for creating canvas properties. - private Paint mTempPaint; + private CanvasProperty<Paint> mPropPaint; + private CanvasProperty<Float> mPropRadius; + private CanvasProperty<Float> mPropX; + private CanvasProperty<Float> mPropY; // Software rendering properties. - private float mOuterOpacity = 0; - private float mOuterX; - private float mOuterY; - - /** Whether we should be drawing hardware animations. */ - private boolean mHardwareAnimating; - - /** Whether we can use hardware acceleration for the exit animation. */ - private boolean mCanUseHardware; - - /** Whether we have an explicit maximum radius. */ - private boolean mHasMaxRadius; - - private boolean mHasPendingHardwareExit; - private int mPendingOpacityDuration; - private int mPendingInflectionDuration; - private int mPendingInflectionOpacity; + private float mOpacity = 0; - /** - * Creates a new ripple. - */ public RippleBackground(RippleDrawable owner, Rect bounds) { - mOwner = owner; - mBounds = bounds; - } - - public void setup(float maxRadius, float density) { - if (maxRadius >= 0) { - mHasMaxRadius = true; - mOuterRadius = maxRadius; - } else { - final float halfWidth = mBounds.width() / 2.0f; - final float halfHeight = mBounds.height() / 2.0f; - mOuterRadius = (float) Math.sqrt(halfWidth * halfWidth + halfHeight * halfHeight); - } - - mOuterX = 0; - mOuterY = 0; - mDensity = density; + super(owner, bounds); } - public void onHotspotBoundsChanged() { - if (!mHasMaxRadius) { - final float halfWidth = mBounds.width() / 2.0f; - final float halfHeight = mBounds.height() / 2.0f; - mOuterRadius = (float) Math.sqrt(halfWidth * halfWidth + halfHeight * halfHeight); - } - } - - @SuppressWarnings("unused") - public void setOuterOpacity(float a) { - mOuterOpacity = a; - invalidateSelf(); - } - - @SuppressWarnings("unused") - public float getOuterOpacity() { - return mOuterOpacity; - } - - /** - * Draws the ripple centered at (0,0) using the specified paint. - */ - public boolean draw(Canvas c, Paint p) { - mColor = p.getColor(); - - final boolean canUseHardware = c.isHardwareAccelerated(); - if (mCanUseHardware != canUseHardware && mCanUseHardware) { - // We've switched from hardware to non-hardware mode. Panic. - cancelHardwareAnimations(true); - } - mCanUseHardware = canUseHardware; - - final boolean hasContent; - if (canUseHardware && (mHardwareAnimating || mHasPendingHardwareExit)) { - hasContent = drawHardware((HardwareCanvas) c, p); - } else { - hasContent = drawSoftware(c, p); - } - - return hasContent; + public boolean isVisible() { + return mOpacity > 0 || isHardwareAnimating(); } - public boolean shouldDraw() { - return (mCanUseHardware && mHardwareAnimating) || (mOuterOpacity > 0 && mOuterRadius > 0); - } - - private boolean drawHardware(HardwareCanvas c, Paint p) { - if (mHasPendingHardwareExit) { - cancelHardwareAnimations(false); - startPendingHardwareExit(c, p); - } - - c.drawCircle(mPropOuterX, mPropOuterY, mPropOuterRadius, mPropOuterPaint); - - return true; - } - - private boolean drawSoftware(Canvas c, Paint p) { + @Override + protected boolean drawSoftware(Canvas c, Paint p) { boolean hasContent = false; - final int paintAlpha = p.getAlpha(); - final int alpha = (int) (paintAlpha * mOuterOpacity + 0.5f); - final float radius = mOuterRadius; - if (alpha > 0 && radius > 0) { + final int origAlpha = p.getAlpha(); + final int alpha = (int) (origAlpha * mOpacity + 0.5f); + if (alpha > 0) { p.setAlpha(alpha); - c.drawCircle(mOuterX, mOuterY, radius, p); - p.setAlpha(paintAlpha); + c.drawCircle(0, 0, mTargetRadius, p); + p.setAlpha(origAlpha); hasContent = true; } return hasContent; } - /** - * Returns the maximum bounds of the ripple relative to the ripple center. - */ - public void getBounds(Rect bounds) { - final int outerX = (int) mOuterX; - final int outerY = (int) mOuterY; - final int r = (int) mOuterRadius + 1; - bounds.set(outerX - r, outerY - r, outerX + r, outerY + r); + @Override + protected boolean drawHardware(HardwareCanvas c) { + c.drawCircle(mPropX, mPropY, mPropRadius, mPropPaint); + return true; } - /** - * Starts the enter animation. - */ - public void enter(boolean fast) { - cancel(); + @Override + protected Animator createSoftwareEnter(boolean fast) { + // Linear enter based on current opacity. + final int maxDuration = fast ? OPACITY_ENTER_DURATION_FAST : OPACITY_ENTER_DURATION; + final int duration = (int) ((1 - mOpacity) * maxDuration); - final ObjectAnimator opacity = ObjectAnimator.ofFloat(this, "outerOpacity", 0, 1); + final ObjectAnimator opacity = ObjectAnimator.ofFloat(this, OPACITY, 1); opacity.setAutoCancel(true); - opacity.setDuration(fast ? ENTER_DURATION_FAST : ENTER_DURATION); + opacity.setDuration(duration); opacity.setInterpolator(LINEAR_INTERPOLATOR); - mAnimOuterOpacity = opacity; - - // Enter animations always run on the UI thread, since it's unlikely - // that anything interesting is happening until the user lifts their - // finger. - opacity.start(); - } - - /** - * Starts the exit animation. - */ - public void exit() { - cancel(); - - // Scale the outer max opacity and opacity velocity based - // on the size of the outer radius. - final int opacityDuration = (int) (1000 / WAVE_OPACITY_DECAY_VELOCITY + 0.5f); - final float outerSizeInfluence = MathUtils.constrain( - (mOuterRadius - WAVE_OUTER_SIZE_INFLUENCE_MIN * mDensity) - / (WAVE_OUTER_SIZE_INFLUENCE_MAX * mDensity), 0, 1); - final float outerOpacityVelocity = MathUtils.lerp(WAVE_OUTER_OPACITY_EXIT_VELOCITY_MIN, - WAVE_OUTER_OPACITY_EXIT_VELOCITY_MAX, outerSizeInfluence); - - // Determine at what time the inner and outer opacity intersect. - // inner(t) = mOpacity - t * WAVE_OPACITY_DECAY_VELOCITY / 1000 - // outer(t) = mOuterOpacity + t * WAVE_OUTER_OPACITY_VELOCITY / 1000 - final int inflectionDuration = Math.max(0, (int) (1000 * (1 - mOuterOpacity) - / (WAVE_OPACITY_DECAY_VELOCITY + outerOpacityVelocity) + 0.5f)); - final int inflectionOpacity = (int) (Color.alpha(mColor) * (mOuterOpacity - + inflectionDuration * outerOpacityVelocity * outerSizeInfluence / 1000) + 0.5f); - - if (mCanUseHardware) { - createPendingHardwareExit(opacityDuration, inflectionDuration, inflectionOpacity); - } else { - exitSoftware(opacityDuration, inflectionDuration, inflectionOpacity); - } - } - - private void createPendingHardwareExit( - int opacityDuration, int inflectionDuration, int inflectionOpacity) { - mHasPendingHardwareExit = true; - mPendingOpacityDuration = opacityDuration; - mPendingInflectionDuration = inflectionDuration; - mPendingInflectionOpacity = inflectionOpacity; - - // The animation will start on the next draw(). - invalidateSelf(); + return opacity; } - private void startPendingHardwareExit(HardwareCanvas c, Paint p) { - mHasPendingHardwareExit = false; + @Override + protected Animator createSoftwareExit() { + final AnimatorSet set = new AnimatorSet(); - final int opacityDuration = mPendingOpacityDuration; - final int inflectionDuration = mPendingInflectionDuration; - final int inflectionOpacity = mPendingInflectionOpacity; + // Linear exit after enter is completed. + final ObjectAnimator exit = ObjectAnimator.ofFloat(this, RippleBackground.OPACITY, 0); + exit.setInterpolator(LINEAR_INTERPOLATOR); + exit.setDuration(OPACITY_EXIT_DURATION); + exit.setAutoCancel(true); - final Paint outerPaint = getTempPaint(p); - outerPaint.setAlpha((int) (outerPaint.getAlpha() * mOuterOpacity + 0.5f)); - mPropOuterPaint = CanvasProperty.createPaint(outerPaint); - mPropOuterRadius = CanvasProperty.createFloat(mOuterRadius); - mPropOuterX = CanvasProperty.createFloat(mOuterX); - mPropOuterY = CanvasProperty.createFloat(mOuterY); + final AnimatorSet.Builder builder = set.play(exit); - final RenderNodeAnimator outerOpacityAnim; - if (inflectionDuration > 0) { - // Outer opacity continues to increase for a bit. - outerOpacityAnim = new RenderNodeAnimator(mPropOuterPaint, - RenderNodeAnimator.PAINT_ALPHA, inflectionOpacity); - outerOpacityAnim.setDuration(inflectionDuration); - outerOpacityAnim.setInterpolator(LINEAR_INTERPOLATOR); + // Linear "fast" enter based on current opacity. + final int fastEnterDuration = (int) ((1 - mOpacity) * OPACITY_ENTER_DURATION_FAST); + if (fastEnterDuration > 0) { + final ObjectAnimator enter = ObjectAnimator.ofFloat(this, RippleBackground.OPACITY, 1); + enter.setInterpolator(LINEAR_INTERPOLATOR); + enter.setDuration(fastEnterDuration); + enter.setAutoCancel(true); - // Chain the outer opacity exit animation. - final int outerDuration = opacityDuration - inflectionDuration; - if (outerDuration > 0) { - final RenderNodeAnimator outerFadeOutAnim = new RenderNodeAnimator( - mPropOuterPaint, RenderNodeAnimator.PAINT_ALPHA, 0); - outerFadeOutAnim.setDuration(outerDuration); - outerFadeOutAnim.setInterpolator(LINEAR_INTERPOLATOR); - outerFadeOutAnim.setStartDelay(inflectionDuration); - outerFadeOutAnim.setStartValue(inflectionOpacity); - outerFadeOutAnim.addListener(mAnimationListener); - outerFadeOutAnim.setTarget(c); - outerFadeOutAnim.start(); - - mRunningAnimations.add(outerFadeOutAnim); - } else { - outerOpacityAnim.addListener(mAnimationListener); - } - } else { - outerOpacityAnim = new RenderNodeAnimator( - mPropOuterPaint, RenderNodeAnimator.PAINT_ALPHA, 0); - outerOpacityAnim.setInterpolator(LINEAR_INTERPOLATOR); - outerOpacityAnim.setDuration(opacityDuration); - outerOpacityAnim.addListener(mAnimationListener); + builder.after(enter); } - outerOpacityAnim.setTarget(c); - outerOpacityAnim.start(); - - mRunningAnimations.add(outerOpacityAnim); - - mHardwareAnimating = true; - - // Set up the software values to match the hardware end values. - mOuterOpacity = 0; + return set; } - /** - * Jump all animations to their end state. The caller is responsible for - * removing the ripple from the list of animating ripples. - */ - public void jump() { - endSoftwareAnimations(); - cancelHardwareAnimations(true); - } - - private void endSoftwareAnimations() { - if (mAnimOuterOpacity != null) { - mAnimOuterOpacity.end(); - mAnimOuterOpacity = null; - } - } - - private Paint getTempPaint(Paint original) { - if (mTempPaint == null) { - mTempPaint = new Paint(); - } - mTempPaint.set(original); - return mTempPaint; - } - - private void exitSoftware(int opacityDuration, int inflectionDuration, int inflectionOpacity) { - final ObjectAnimator outerOpacityAnim; - if (inflectionDuration > 0) { - // Outer opacity continues to increase for a bit. - outerOpacityAnim = ObjectAnimator.ofFloat(this, - "outerOpacity", inflectionOpacity / 255.0f); - outerOpacityAnim.setAutoCancel(true); - outerOpacityAnim.setDuration(inflectionDuration); - outerOpacityAnim.setInterpolator(LINEAR_INTERPOLATOR); - - // Chain the outer opacity exit animation. - final int outerDuration = opacityDuration - inflectionDuration; - if (outerDuration > 0) { - outerOpacityAnim.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - final ObjectAnimator outerFadeOutAnim = ObjectAnimator.ofFloat( - RippleBackground.this, "outerOpacity", 0); - outerFadeOutAnim.setAutoCancel(true); - outerFadeOutAnim.setDuration(outerDuration); - outerFadeOutAnim.setInterpolator(LINEAR_INTERPOLATOR); - outerFadeOutAnim.addListener(mAnimationListener); + @Override + protected RenderNodeAnimatorSet createHardwareExit(Paint p) { + final RenderNodeAnimatorSet set = new RenderNodeAnimatorSet(); - mAnimOuterOpacity = outerFadeOutAnim; + final int targetAlpha = p.getAlpha(); + final int currentAlpha = (int) (mOpacity * targetAlpha + 0.5f); + p.setAlpha(currentAlpha); - outerFadeOutAnim.start(); - } + mPropPaint = CanvasProperty.createPaint(p); + mPropRadius = CanvasProperty.createFloat(mTargetRadius); + mPropX = CanvasProperty.createFloat(0); + mPropY = CanvasProperty.createFloat(0); - @Override - public void onAnimationCancel(Animator animation) { - animation.removeListener(this); - } - }); - } else { - outerOpacityAnim.addListener(mAnimationListener); - } - } else { - outerOpacityAnim = ObjectAnimator.ofFloat(this, "outerOpacity", 0); - outerOpacityAnim.setAutoCancel(true); - outerOpacityAnim.setDuration(opacityDuration); - outerOpacityAnim.addListener(mAnimationListener); + // Linear "fast" enter based on current opacity. + final int fastEnterDuration = (int) ((1 - mOpacity) * OPACITY_ENTER_DURATION_FAST); + if (fastEnterDuration > 0) { + final RenderNodeAnimator enter = new RenderNodeAnimator( + mPropPaint, RenderNodeAnimator.PAINT_ALPHA, targetAlpha); + enter.setInterpolator(LINEAR_INTERPOLATOR); + enter.setDuration(fastEnterDuration); + set.add(enter); } - mAnimOuterOpacity = outerOpacityAnim; + // Linear exit after enter is completed. + final RenderNodeAnimator exit = new RenderNodeAnimator( + mPropPaint, RenderNodeAnimator.PAINT_ALPHA, 0); + exit.setInterpolator(LINEAR_INTERPOLATOR); + exit.setDuration(OPACITY_EXIT_DURATION); + exit.setStartDelay(fastEnterDuration); + set.add(exit); - outerOpacityAnim.start(); + return set; } - /** - * Cancel all animations. The caller is responsible for removing - * the ripple from the list of animating ripples. - */ - public void cancel() { - cancelSoftwareAnimations(); - cancelHardwareAnimations(false); + @Override + protected void jumpValuesToExit() { + mOpacity = 0; } - private void cancelSoftwareAnimations() { - if (mAnimOuterOpacity != null) { - mAnimOuterOpacity.cancel(); - mAnimOuterOpacity = null; + private static abstract class BackgroundProperty extends FloatProperty<RippleBackground> { + public BackgroundProperty(String name) { + super(name); } } - /** - * Cancels any running hardware animations. - */ - private void cancelHardwareAnimations(boolean jumpToEnd) { - final ArrayList<RenderNodeAnimator> runningAnimations = mRunningAnimations; - final int N = runningAnimations.size(); - for (int i = 0; i < N; i++) { - if (jumpToEnd) { - runningAnimations.get(i).end(); - } else { - runningAnimations.get(i).cancel(); - } - } - runningAnimations.clear(); - - if (mHasPendingHardwareExit) { - // If we had a pending hardware exit, jump to the end state. - mHasPendingHardwareExit = false; - - if (jumpToEnd) { - mOuterOpacity = 0; - } + private static final BackgroundProperty OPACITY = new BackgroundProperty("opacity") { + @Override + public void setValue(RippleBackground object, float value) { + object.mOpacity = value; + object.invalidateSelf(); } - mHardwareAnimating = false; - } - - private void invalidateSelf() { - mOwner.invalidateSelf(); - } - - private final AnimatorListenerAdapter mAnimationListener = new AnimatorListenerAdapter() { @Override - public void onAnimationEnd(Animator animation) { - mHardwareAnimating = false; + public Float get(RippleBackground object) { + return object.mOpacity; } }; } diff --git a/graphics/java/android/graphics/drawable/RippleComponent.java b/graphics/java/android/graphics/drawable/RippleComponent.java new file mode 100644 index 000000000000..fd3e06cad0d3 --- /dev/null +++ b/graphics/java/android/graphics/drawable/RippleComponent.java @@ -0,0 +1,332 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.graphics.drawable; + +import android.animation.Animator; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Rect; +import android.view.HardwareCanvas; +import android.view.RenderNodeAnimator; + +import java.util.ArrayList; + +/** + * Abstract class that handles hardware/software hand-off and lifecycle for + * animated ripple foreground and background components. + */ +abstract class RippleComponent { + private final RippleDrawable mOwner; + + /** Bounds used for computing max radius. May be modified by the owner. */ + protected final Rect mBounds; + + /** Whether we can use hardware acceleration for the exit animation. */ + private boolean mHasHardwareCanvas; + + private boolean mHasPendingHardwareAnimator; + private RenderNodeAnimatorSet mHardwareAnimator; + + private Animator mSoftwareAnimator; + + /** Whether we have an explicit maximum radius. */ + private boolean mHasMaxRadius; + + /** How big this ripple should be when fully entered. */ + protected float mTargetRadius; + + /** Screen density used to adjust pixel-based constants. */ + protected float mDensity; + + public RippleComponent(RippleDrawable owner, Rect bounds) { + mOwner = owner; + mBounds = bounds; + } + + public final void setup(float maxRadius, float density) { + if (maxRadius >= 0) { + mHasMaxRadius = true; + mTargetRadius = maxRadius; + } else { + final float halfWidth = mBounds.width() / 2.0f; + final float halfHeight = mBounds.height() / 2.0f; + mTargetRadius = (float) Math.sqrt(halfWidth * halfWidth + halfHeight * halfHeight); + } + + mDensity = density; + + onSetup(); + onTargetRadiusChanged(mTargetRadius); + } + + /** + * Starts a ripple enter animation. + * + * @param fast whether the ripple should enter quickly + */ + public final void enter(boolean fast) { + cancel(); + + mSoftwareAnimator = createSoftwareEnter(fast); + mSoftwareAnimator.start(); + } + + /** + * Starts a ripple exit animation. + */ + public final void exit() { + cancel(); + + if (mHasHardwareCanvas) { + // We don't have access to a canvas here, but we expect one on the + // next frame. We'll start the render thread animation then. + mHasPendingHardwareAnimator = true; + + // Request another frame. + invalidateSelf(); + } else { + mSoftwareAnimator = createSoftwareExit(); + mSoftwareAnimator.start(); + } + } + + /** + * Cancels all animations. Software animation values are left in the + * current state, while hardware animation values jump to the end state. + */ + public void cancel() { + cancelSoftwareAnimations(); + endHardwareAnimations(); + } + + /** + * Ends all animations, jumping values to the end state. + */ + public void end() { + endSoftwareAnimations(); + endHardwareAnimations(); + } + + /** + * Draws the ripple to the canvas, inheriting the paint's color and alpha + * properties. + * + * @param c the canvas to which the ripple should be drawn + * @param p the paint used to draw the ripple + * @return {@code true} if something was drawn, {@code false} otherwise + */ + public boolean draw(Canvas c, Paint p) { + final boolean hasHardwareCanvas = c.isHardwareAccelerated() + && c instanceof HardwareCanvas; + if (mHasHardwareCanvas != hasHardwareCanvas) { + mHasHardwareCanvas = hasHardwareCanvas; + + if (!hasHardwareCanvas) { + // We've switched from hardware to non-hardware mode. Panic. + endHardwareAnimations(); + } + } + + if (hasHardwareCanvas) { + final HardwareCanvas hw = (HardwareCanvas) c; + startPendingAnimation(hw, p); + + if (mHardwareAnimator != null) { + return drawHardware(hw); + } + } + + return drawSoftware(c, p); + } + + /** + * Populates {@code bounds} with the maximum drawing bounds of the ripple + * relative to its center. The resulting bounds should be translated into + * parent drawable coordinates before use. + * + * @param bounds the rect to populate with drawing bounds + */ + public void getBounds(Rect bounds) { + final int r = (int) Math.ceil(mTargetRadius); + bounds.set(-r, -r, r, r); + } + + /** + * Starts the pending hardware animation, if available. + * + * @param hw hardware canvas on which the animation should draw + * @param p paint whose properties the hardware canvas should use + */ + private void startPendingAnimation(HardwareCanvas hw, Paint p) { + if (mHasPendingHardwareAnimator) { + mHasPendingHardwareAnimator = false; + + mHardwareAnimator = createHardwareExit(new Paint(p)); + mHardwareAnimator.start(hw); + + // Preemptively jump the software values to the end state now that + // the hardware exit has read whatever values it needs. + jumpValuesToExit(); + } + } + + /** + * Cancels any current software animations, leaving the values in their + * current state. + */ + private void cancelSoftwareAnimations() { + if (mSoftwareAnimator != null) { + mSoftwareAnimator.cancel(); + } + } + + /** + * Ends any current software animations, jumping the values to their end + * state. + */ + private void endSoftwareAnimations() { + if (mSoftwareAnimator != null) { + mSoftwareAnimator.end(); + } + } + + /** + * Ends any pending or current hardware animations. + * <p> + * Hardware animations can't synchronize values back to the software + * thread, so there is no "cancel" equivalent. + */ + private void endHardwareAnimations() { + if (mHardwareAnimator != null) { + mHardwareAnimator.end(); + mHardwareAnimator = null; + } + + if (mHasPendingHardwareAnimator) { + mHasPendingHardwareAnimator = false; + } + } + + protected final void invalidateSelf() { + mOwner.invalidateSelf(); + } + + protected final boolean isHardwareAnimating() { + return mHardwareAnimator != null && mHardwareAnimator.isRunning() + || mHasPendingHardwareAnimator; + } + + protected final void onHotspotBoundsChanged() { + if (!mHasMaxRadius) { + final float halfWidth = mBounds.width() / 2.0f; + final float halfHeight = mBounds.height() / 2.0f; + final float targetRadius = (float) Math.sqrt(halfWidth * halfWidth + + halfHeight * halfHeight); + + onTargetRadiusChanged(targetRadius); + } + } + + /** + * Called when the target radius changes. + * + * @param targetRadius the new target radius + */ + protected void onTargetRadiusChanged(float targetRadius) { + // Stub. + } + + /** + * Called during ripple setup, which occurs before the first enter + * animation. + */ + protected void onSetup() { + // Stub. + } + + protected abstract Animator createSoftwareEnter(boolean fast); + + protected abstract Animator createSoftwareExit(); + + protected abstract RenderNodeAnimatorSet createHardwareExit(Paint p); + + protected abstract boolean drawHardware(HardwareCanvas c); + + protected abstract boolean drawSoftware(Canvas c, Paint p); + + /** + * Called when the hardware exit is cancelled. Jumps software values to end + * state to ensure that software and hardware values are synchronized. + */ + protected abstract void jumpValuesToExit(); + + public static class RenderNodeAnimatorSet { + private final ArrayList<RenderNodeAnimator> mAnimators = new ArrayList<>(); + + public void add(RenderNodeAnimator anim) { + mAnimators.add(anim); + } + + public void clear() { + mAnimators.clear(); + } + + public void start(HardwareCanvas target) { + if (target == null) { + throw new IllegalArgumentException("Hardware canvas must be non-null"); + } + + final ArrayList<RenderNodeAnimator> animators = mAnimators; + final int N = animators.size(); + for (int i = 0; i < N; i++) { + final RenderNodeAnimator anim = animators.get(i); + anim.setTarget(target); + anim.start(); + } + } + + public void cancel() { + final ArrayList<RenderNodeAnimator> animators = mAnimators; + final int N = animators.size(); + for (int i = 0; i < N; i++) { + final RenderNodeAnimator anim = animators.get(i); + anim.cancel(); + } + } + + public void end() { + final ArrayList<RenderNodeAnimator> animators = mAnimators; + final int N = animators.size(); + for (int i = 0; i < N; i++) { + final RenderNodeAnimator anim = animators.get(i); + anim.end(); + } + } + + public boolean isRunning() { + final ArrayList<RenderNodeAnimator> animators = mAnimators; + final int N = animators.size(); + for (int i = 0; i < N; i++) { + final RenderNodeAnimator anim = animators.get(i); + if (anim.isRunning()) { + return true; + } + } + return false; + } + } +} diff --git a/graphics/java/android/graphics/drawable/RippleDrawable.java b/graphics/java/android/graphics/drawable/RippleDrawable.java index b028eeb0612a..bc8c7d2ff246 100644 --- a/graphics/java/android/graphics/drawable/RippleDrawable.java +++ b/graphics/java/android/graphics/drawable/RippleDrawable.java @@ -137,7 +137,7 @@ public class RippleDrawable extends LayerDrawable { private boolean mBackgroundActive; /** The current ripple. May be actively animating or pending entry. */ - private Ripple mRipple; + private RippleForeground mRipple; /** Whether we expect to draw a ripple when visible. */ private boolean mRippleActive; @@ -151,7 +151,7 @@ public class RippleDrawable extends LayerDrawable { * Lazily-created array of actively animating ripples. Inactive ripples are * pruned during draw(). The locations of these will not change. */ - private Ripple[] mExitingRipples; + private RippleForeground[] mExitingRipples; private int mExitingRipplesCount = 0; /** Paint used to control appearance of ripples. */ @@ -204,11 +204,11 @@ public class RippleDrawable extends LayerDrawable { super.jumpToCurrentState(); if (mRipple != null) { - mRipple.jump(); + mRipple.end(); } if (mBackground != null) { - mBackground.jump(); + mBackground.end(); } cancelExitingRipples(); @@ -219,10 +219,13 @@ public class RippleDrawable extends LayerDrawable { boolean needsDraw = false; final int count = mExitingRipplesCount; - final Ripple[] ripples = mExitingRipples; + final RippleForeground[] ripples = mExitingRipples; for (int i = 0; i < count; i++) { + // If the ripple is animating on the hardware thread, we'll need to + // draw an additional frame after canceling to restore the software + // drawing path. needsDraw |= ripples[i].isHardwareAnimating(); - ripples[i].cancel(); + ripples[i].end(); } if (ripples != null) { @@ -264,11 +267,9 @@ public class RippleDrawable extends LayerDrawable { for (int state : stateSet) { if (state == R.attr.state_enabled) { enabled = true; - } - if (state == R.attr.state_focused) { + } else if (state == R.attr.state_focused) { focused = true; - } - if (state == R.attr.state_pressed) { + } else if (state == R.attr.state_pressed) { pressed = true; } } @@ -563,11 +564,11 @@ public class RippleDrawable extends LayerDrawable { x = mHotspotBounds.exactCenterX(); y = mHotspotBounds.exactCenterY(); } - mRipple = new Ripple(this, mHotspotBounds, x, y); + mRipple = new RippleForeground(this, mHotspotBounds, x, y); } mRipple.setup(mState.mMaxRadius, mDensity); - mRipple.enter(); + mRipple.enter(false); } /** @@ -577,7 +578,7 @@ public class RippleDrawable extends LayerDrawable { private void tryRippleExit() { if (mRipple != null) { if (mExitingRipples == null) { - mExitingRipples = new Ripple[MAX_RIPPLES]; + mExitingRipples = new RippleForeground[MAX_RIPPLES]; } mExitingRipples[mExitingRipplesCount++] = mRipple; mRipple.exit(); @@ -591,13 +592,13 @@ public class RippleDrawable extends LayerDrawable { */ private void clearHotspots() { if (mRipple != null) { - mRipple.cancel(); + mRipple.end(); mRipple = null; mRippleActive = false; } if (mBackground != null) { - mBackground.cancel(); + mBackground.end(); mBackground = null; mBackgroundActive = false; } @@ -624,7 +625,7 @@ public class RippleDrawable extends LayerDrawable { */ private void onHotspotBoundsChanged() { final int count = mExitingRipplesCount; - final Ripple[] ripples = mExitingRipples; + final RippleForeground[] ripples = mExitingRipples; for (int i = 0; i < count; i++) { ripples[i].onHotspotBoundsChanged(); } @@ -662,6 +663,8 @@ public class RippleDrawable extends LayerDrawable { */ @Override public void draw(@NonNull Canvas canvas) { + pruneRipples(); + // Clip to the dirty bounds, which will be the drawable bounds if we // have a mask or content and the ripple bounds if we're projecting. final Rect bounds = getDirtyBounds(); @@ -682,6 +685,26 @@ public class RippleDrawable extends LayerDrawable { mHasValidMask = false; } + private void pruneRipples() { + int remaining = 0; + + // Move remaining entries into pruned spaces. + final RippleForeground[] ripples = mExitingRipples; + final int count = mExitingRipplesCount; + for (int i = 0; i < count; i++) { + if (!ripples[i].hasFinishedExit()) { + ripples[remaining++] = ripples[i]; + } + } + + // Null out the remaining entries. + for (int i = remaining; i < count; i++) { + ripples[i] = null; + } + + mExitingRipplesCount = remaining; + } + /** * @return whether we need to use a mask */ @@ -747,7 +770,7 @@ public class RippleDrawable extends LayerDrawable { private int getMaskType() { if (mRipple == null && mExitingRipplesCount <= 0 - && (mBackground == null || !mBackground.shouldDraw())) { + && (mBackground == null || !mBackground.isVisible())) { // We might need a mask later. return MASK_UNKNOWN; } @@ -774,36 +797,6 @@ public class RippleDrawable extends LayerDrawable { return MASK_NONE; } - /** - * Removes a ripple from the exiting ripple list. - * - * @param ripple the ripple to remove - */ - void removeRipple(Ripple ripple) { - // Ripple ripple ripple ripple. Ripple ripple. - final Ripple[] ripples = mExitingRipples; - final int count = mExitingRipplesCount; - final int index = getRippleIndex(ripple); - if (index >= 0) { - System.arraycopy(ripples, index + 1, ripples, index, count - (index + 1)); - ripples[count - 1] = null; - mExitingRipplesCount--; - - invalidateSelf(); - } - } - - private int getRippleIndex(Ripple ripple) { - final Ripple[] ripples = mExitingRipples; - final int count = mExitingRipplesCount; - for (int i = 0; i < count; i++) { - if (ripples[i] == ripple) { - return i; - } - } - return -1; - } - private void drawContent(Canvas canvas) { // Draw everything except the mask. final ChildDrawable[] array = mLayerState.mChildren; @@ -816,10 +809,10 @@ public class RippleDrawable extends LayerDrawable { } private void drawBackgroundAndRipples(Canvas canvas) { - final Ripple active = mRipple; + final RippleForeground active = mRipple; final RippleBackground background = mBackground; final int count = mExitingRipplesCount; - if (active == null && count <= 0 && (background == null || !background.shouldDraw())) { + if (active == null && count <= 0 && (background == null || !background.isVisible())) { // Move along, nothing to draw here. return; } @@ -859,12 +852,12 @@ public class RippleDrawable extends LayerDrawable { p.setShader(null); } - if (background != null && background.shouldDraw()) { + if (background != null && background.isVisible()) { background.draw(canvas, p); } if (count > 0) { - final Ripple[] ripples = mExitingRipples; + final RippleForeground[] ripples = mExitingRipples; for (int i = 0; i < count; i++) { ripples[i].draw(canvas, p); } @@ -902,7 +895,7 @@ public class RippleDrawable extends LayerDrawable { final int cY = (int) mHotspotBounds.exactCenterY(); final Rect rippleBounds = mTempRect; - final Ripple[] activeRipples = mExitingRipples; + final RippleForeground[] activeRipples = mExitingRipples; final int N = mExitingRipplesCount; for (int i = 0; i < N; i++) { activeRipples[i].getBounds(rippleBounds); diff --git a/graphics/java/android/graphics/drawable/RippleForeground.java b/graphics/java/android/graphics/drawable/RippleForeground.java new file mode 100644 index 000000000000..2023f04c92e4 --- /dev/null +++ b/graphics/java/android/graphics/drawable/RippleForeground.java @@ -0,0 +1,345 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.graphics.drawable; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.AnimatorSet; +import android.animation.ObjectAnimator; +import android.animation.TimeInterpolator; +import android.graphics.Canvas; +import android.graphics.CanvasProperty; +import android.graphics.Paint; +import android.graphics.Rect; +import android.util.FloatProperty; +import android.util.MathUtils; +import android.view.HardwareCanvas; +import android.view.RenderNodeAnimator; +import android.view.animation.LinearInterpolator; + +/** + * Draws a ripple foreground. + */ +class RippleForeground extends RippleComponent { + private static final TimeInterpolator LINEAR_INTERPOLATOR = new LinearInterpolator(); + private static final TimeInterpolator DECELERATE_INTERPOLATOR = new LogDecelerateInterpolator( + 400f, 1.4f, 0); + + // Pixel-based accelerations and velocities. + private static final float WAVE_TOUCH_DOWN_ACCELERATION = 1024; + private static final float WAVE_TOUCH_UP_ACCELERATION = 3400; + private static final float WAVE_OPACITY_DECAY_VELOCITY = 3; + + private static final int RIPPLE_ENTER_DELAY = 80; + private static final int OPACITY_ENTER_DURATION_FAST = 120; + + private float mStartingX; + private float mStartingY; + private float mClampedStartingX; + private float mClampedStartingY; + + // Hardware rendering properties. + private CanvasProperty<Paint> mPropPaint; + private CanvasProperty<Float> mPropRadius; + private CanvasProperty<Float> mPropX; + private CanvasProperty<Float> mPropY; + + // Software rendering properties. + private float mOpacity = 1; + private float mOuterX; + private float mOuterY; + + // Values used to tween between the start and end positions. + private float mTweenRadius = 0; + private float mTweenX = 0; + private float mTweenY = 0; + + /** Whether this ripple has finished its exit animation. */ + private boolean mHasFinishedExit; + + public RippleForeground(RippleDrawable owner, Rect bounds, float startingX, float startingY) { + super(owner, bounds); + + mStartingX = startingX; + mStartingY = startingY; + } + + @Override + public void onSetup() { + mOuterX = 0; + mOuterY = 0; + } + + @Override + protected void onTargetRadiusChanged(float targetRadius) { + clampStartingPosition(); + } + + @Override + protected boolean drawSoftware(Canvas c, Paint p) { + boolean hasContent = false; + + final int origAlpha = p.getAlpha(); + final int alpha = (int) (origAlpha * mOpacity + 0.5f); + final float radius = MathUtils.lerp(0, mTargetRadius, mTweenRadius); + if (alpha > 0 && radius > 0) { + final float x = MathUtils.lerp( + mClampedStartingX - mBounds.exactCenterX(), mOuterX, mTweenX); + final float y = MathUtils.lerp( + mClampedStartingY - mBounds.exactCenterY(), mOuterY, mTweenY); + p.setAlpha(alpha); + c.drawCircle(x, y, radius, p); + p.setAlpha(origAlpha); + hasContent = true; + } + + return hasContent; + } + + @Override + protected boolean drawHardware(HardwareCanvas c) { + c.drawCircle(mPropX, mPropY, mPropRadius, mPropPaint); + return true; + } + + /** + * Returns the maximum bounds of the ripple relative to the ripple center. + */ + public void getBounds(Rect bounds) { + final int outerX = (int) mOuterX; + final int outerY = (int) mOuterY; + final int r = (int) mTargetRadius + 1; + bounds.set(outerX - r, outerY - r, outerX + r, outerY + r); + } + + /** + * Specifies the starting position relative to the drawable bounds. No-op if + * the ripple has already entered. + */ + public void move(float x, float y) { + mStartingX = x; + mStartingY = y; + + clampStartingPosition(); + } + + /** + * @return {@code true} if this ripple has finished its exit animation + */ + public boolean hasFinishedExit() { + return mHasFinishedExit; + } + + @Override + protected Animator createSoftwareEnter(boolean fast) { + final int duration = (int) + (1000 * Math.sqrt(mTargetRadius / WAVE_TOUCH_DOWN_ACCELERATION * mDensity) + 0.5); + + final ObjectAnimator tweenAll = ObjectAnimator.ofFloat(this, TWEEN_ALL, 1); + tweenAll.setAutoCancel(true); + tweenAll.setDuration(duration); + tweenAll.setInterpolator(LINEAR_INTERPOLATOR); + tweenAll.setStartDelay(RIPPLE_ENTER_DELAY); + + final ObjectAnimator opacity = ObjectAnimator.ofFloat(this, OPACITY, 1); + opacity.setAutoCancel(true); + opacity.setDuration(OPACITY_ENTER_DURATION_FAST); + opacity.setInterpolator(LINEAR_INTERPOLATOR); + + final AnimatorSet set = new AnimatorSet(); + set.play(tweenAll).with(opacity); + + return set; + } + + private int getRadiusExitDuration() { + final float radius = MathUtils.lerp(0, mTargetRadius, mTweenRadius); + final float remaining = mTargetRadius - radius; + return (int) (1000 * Math.sqrt(remaining / (WAVE_TOUCH_UP_ACCELERATION + + WAVE_TOUCH_DOWN_ACCELERATION) * mDensity) + 0.5); + } + + private int getOpacityExitDuration() { + return (int) (1000 * mOpacity / WAVE_OPACITY_DECAY_VELOCITY + 0.5f); + } + + @Override + protected Animator createSoftwareExit() { + final int radiusDuration = getRadiusExitDuration(); + final int opacityDuration = getOpacityExitDuration(); + + final ObjectAnimator tweenAll = ObjectAnimator.ofFloat(this, TWEEN_ALL, 1); + tweenAll.setAutoCancel(true); + tweenAll.setDuration(radiusDuration); + tweenAll.setInterpolator(DECELERATE_INTERPOLATOR); + + final ObjectAnimator opacity = ObjectAnimator.ofFloat(this, OPACITY, 0); + opacity.setAutoCancel(true); + opacity.setDuration(opacityDuration); + opacity.setInterpolator(LINEAR_INTERPOLATOR); + + final AnimatorSet set = new AnimatorSet(); + set.play(tweenAll).with(opacity); + set.addListener(mAnimationListener); + + return set; + } + + @Override + protected RenderNodeAnimatorSet createHardwareExit(Paint p) { + final int radiusDuration = getRadiusExitDuration(); + final int opacityDuration = getOpacityExitDuration(); + + final float startX = MathUtils.lerp( + mClampedStartingX - mBounds.exactCenterX(), mOuterX, mTweenX); + final float startY = MathUtils.lerp( + mClampedStartingY - mBounds.exactCenterY(), mOuterY, mTweenY); + + final float startRadius = MathUtils.lerp(0, mTargetRadius, mTweenRadius); + p.setAlpha((int) (p.getAlpha() * mOpacity + 0.5f)); + + mPropPaint = CanvasProperty.createPaint(p); + mPropRadius = CanvasProperty.createFloat(startRadius); + mPropX = CanvasProperty.createFloat(startX); + mPropY = CanvasProperty.createFloat(startY); + + final RenderNodeAnimator radius = new RenderNodeAnimator(mPropRadius, mTargetRadius); + radius.setDuration(radiusDuration); + radius.setInterpolator(DECELERATE_INTERPOLATOR); + + final RenderNodeAnimator x = new RenderNodeAnimator(mPropX, mOuterX); + x.setDuration(radiusDuration); + x.setInterpolator(DECELERATE_INTERPOLATOR); + + final RenderNodeAnimator y = new RenderNodeAnimator(mPropY, mOuterY); + y.setDuration(radiusDuration); + y.setInterpolator(DECELERATE_INTERPOLATOR); + + final RenderNodeAnimator opacity = new RenderNodeAnimator(mPropPaint, + RenderNodeAnimator.PAINT_ALPHA, 0); + opacity.setDuration(opacityDuration); + opacity.setInterpolator(LINEAR_INTERPOLATOR); + opacity.addListener(mAnimationListener); + + final RenderNodeAnimatorSet set = new RenderNodeAnimatorSet(); + set.add(radius); + set.add(opacity); + set.add(x); + set.add(y); + + return set; + } + + @Override + protected void jumpValuesToExit() { + mOpacity = 0; + mTweenX = 1; + mTweenY = 1; + mTweenRadius = 1; + } + + /** + * Clamps the starting position to fit within the ripple bounds. + */ + private void clampStartingPosition() { + final float cX = mBounds.exactCenterX(); + final float cY = mBounds.exactCenterY(); + final float dX = mStartingX - cX; + final float dY = mStartingY - cY; + final float r = mTargetRadius; + if (dX * dX + dY * dY > r * r) { + // Point is outside the circle, clamp to the perimeter. + final double angle = Math.atan2(dY, dX); + mClampedStartingX = cX + (float) (Math.cos(angle) * r); + mClampedStartingY = cY + (float) (Math.sin(angle) * r); + } else { + mClampedStartingX = mStartingX; + mClampedStartingY = mStartingY; + } + } + + private final AnimatorListenerAdapter mAnimationListener = new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animator) { + mHasFinishedExit = true; + } + }; + + /** + * Interpolator with a smooth log deceleration. + */ + private static final class LogDecelerateInterpolator implements TimeInterpolator { + private final float mBase; + private final float mDrift; + private final float mTimeScale; + private final float mOutputScale; + + public LogDecelerateInterpolator(float base, float timeScale, float drift) { + mBase = base; + mDrift = drift; + mTimeScale = 1f / timeScale; + + mOutputScale = 1f / computeLog(1f); + } + + private float computeLog(float t) { + return 1f - (float) Math.pow(mBase, -t * mTimeScale) + (mDrift * t); + } + + @Override + public float getInterpolation(float t) { + return computeLog(t) * mOutputScale; + } + } + + /** + * Property for animating radius, center X, and center Y between their + * initial and target values. + */ + private static final FloatProperty<RippleForeground> TWEEN_ALL = + new FloatProperty<RippleForeground>("tweenAll") { + @Override + public void setValue(RippleForeground object, float value) { + object.mTweenRadius = value; + object.mTweenX = value; + object.mTweenY = value; + object.invalidateSelf(); + } + + @Override + public Float get(RippleForeground object) { + return object.mTweenRadius; + } + }; + + /** + * Property for animating opacity between 0 and its target value. + */ + private static final FloatProperty<RippleForeground> OPACITY = + new FloatProperty<RippleForeground>("opacity") { + @Override + public void setValue(RippleForeground object, float value) { + object.mOpacity = value; + object.invalidateSelf(); + } + + @Override + public Float get(RippleForeground object) { + return object.mOpacity; + } + }; +} diff --git a/graphics/java/android/graphics/pdf/PdfRenderer.java b/graphics/java/android/graphics/pdf/PdfRenderer.java index 79934da09aa1..b32dcc69ea7b 100644 --- a/graphics/java/android/graphics/pdf/PdfRenderer.java +++ b/graphics/java/android/graphics/pdf/PdfRenderer.java @@ -380,7 +380,7 @@ public final class PdfRenderer implements AutoCloseable { final long transformPtr = (transform != null) ? transform.native_instance : 0; - nativeRenderPage(mNativeDocument, mNativePage, destination.mNativeBitmap, contentLeft, + nativeRenderPage(mNativeDocument, mNativePage, destination.getSkBitmap(), contentLeft, contentTop, contentRight, contentBottom, transformPtr, renderMode); } diff --git a/include/android_runtime/android_view_Surface.h b/include/android_runtime/android_view_Surface.h index 53e8b4970c8d..a6836a8bed2d 100644 --- a/include/android_runtime/android_view_Surface.h +++ b/include/android_runtime/android_view_Surface.h @@ -26,6 +26,33 @@ namespace android { class Surface; class IGraphicBufferProducer; +/** + * Enum mirroring the public API definitions for image and pixel formats. + * Some of these are hidden in the public API + * + * Keep up to date with android.graphics.ImageFormat and + * android.graphics.PixelFormat + */ +enum class PublicFormat { + UNKNOWN = 0x0, + RGBA_8888 = 0x1, + RGBX_8888 = 0x2, + RGB_888 = 0x3, + RGB_565 = 0x4, + NV16 = 0x10, + NV21 = 0x11, + YUY2 = 0x14, + RAW_SENSOR = 0x20, + YUV_420_888 = 0x23, + RAW10 = 0x25, + JPEG = 0x100, + DEPTH_POINT_CLOUD = 0x101, + YV12 = 0x32315659, + Y8 = 0x20203859, // @hide + Y16 = 0x20363159, // @hide + DEPTH16 = 0x44363159 +}; + /* Gets the underlying ANativeWindow for a Surface. */ extern sp<ANativeWindow> android_view_Surface_getNativeWindow( JNIEnv* env, jobject surfaceObj); @@ -40,6 +67,21 @@ extern sp<Surface> android_view_Surface_getSurface(JNIEnv* env, jobject surfaceO extern jobject android_view_Surface_createFromIGraphicBufferProducer(JNIEnv* env, const sp<IGraphicBufferProducer>& bufferProducer); +/* Convert from android.graphics.ImageFormat/PixelFormat enums to graphics.h HAL + * format */ +extern int android_view_Surface_mapPublicFormatToHalFormat(PublicFormat f); + +/* Convert from android.graphics.ImageFormat/PixelFormat enums to graphics.h HAL + * dataspace */ +extern android_dataspace android_view_Surface_mapPublicFormatToHalDataspace( + PublicFormat f); + +/* Convert from HAL format, dataspace pair to + * android.graphics.ImageFormat/PixelFormat. + * For unknown/unspecified pairs, returns PublicFormat::UNKNOWN */ +extern PublicFormat android_view_Surface_mapHalFormatDataspaceToPublicFormat( + int format, android_dataspace dataSpace); + } // namespace android #endif // _ANDROID_VIEW_SURFACE_H diff --git a/libs/hwui/Glop.h b/libs/hwui/Glop.h index 62da6e086531..2c6f6c120d16 100644 --- a/libs/hwui/Glop.h +++ b/libs/hwui/Glop.h @@ -78,7 +78,7 @@ struct Glop { // TODO: enforce mutual exclusion with restricted setters and/or unions struct Vertices { GLuint bufferObject; - VertexAttribFlags flags; + int attribFlags; const void* position; const void* texCoord; const void* color; diff --git a/libs/hwui/GlopBuilder.cpp b/libs/hwui/GlopBuilder.cpp index 54360f9fad78..a9ce7f4acdfd 100644 --- a/libs/hwui/GlopBuilder.cpp +++ b/libs/hwui/GlopBuilder.cpp @@ -66,7 +66,7 @@ GlopBuilder& GlopBuilder::setMeshUnitQuad() { mOutGlop->mesh.indices = { 0, nullptr }; mOutGlop->mesh.vertices = { mRenderState.meshState().getUnitQuadVBO(), - VertexAttribFlags::kNone, + static_cast<int>(VertexAttribFlags::kNone), nullptr, nullptr, nullptr, kTextureVertexStride }; mOutGlop->mesh.elementCount = 4; @@ -85,7 +85,7 @@ GlopBuilder& GlopBuilder::setMeshTexturedUnitQuad(const UvMapper* uvMapper) { mOutGlop->mesh.indices = { 0, nullptr }; mOutGlop->mesh.vertices = { mRenderState.meshState().getUnitQuadVBO(), - VertexAttribFlags::kTextureCoord, + static_cast<int>(VertexAttribFlags::kTextureCoord), nullptr, (const void*) kMeshTextureOffset, nullptr, kTextureVertexStride }; mOutGlop->mesh.elementCount = 4; @@ -105,7 +105,7 @@ GlopBuilder& GlopBuilder::setMeshTexturedUvQuad(const UvMapper* uvMapper, Rect u mOutGlop->mesh.indices = { 0, nullptr }; mOutGlop->mesh.vertices = { 0, - VertexAttribFlags::kTextureCoord, + static_cast<int>(VertexAttribFlags::kTextureCoord), &textureVertex[0].x, &textureVertex[0].u, nullptr, kTextureVertexStride }; mOutGlop->mesh.elementCount = 4; @@ -119,7 +119,7 @@ GlopBuilder& GlopBuilder::setMeshIndexedQuads(Vertex* vertexData, int quadCount) mOutGlop->mesh.indices = { mRenderState.meshState().getQuadListIBO(), nullptr }; mOutGlop->mesh.vertices = { 0, - VertexAttribFlags::kNone, + static_cast<int>(VertexAttribFlags::kNone), vertexData, nullptr, nullptr, kVertexStride }; mOutGlop->mesh.elementCount = 6 * quadCount; @@ -133,7 +133,7 @@ GlopBuilder& GlopBuilder::setMeshTexturedIndexedQuads(TextureVertex* vertexData, mOutGlop->mesh.indices = { mRenderState.meshState().getQuadListIBO(), nullptr }; mOutGlop->mesh.vertices = { 0, - VertexAttribFlags::kTextureCoord, + static_cast<int>(VertexAttribFlags::kTextureCoord), &vertexData[0].x, &vertexData[0].u, nullptr, kTextureVertexStride }; mOutGlop->mesh.elementCount = elementCount; @@ -147,7 +147,7 @@ GlopBuilder& GlopBuilder::setMeshTexturedMesh(TextureVertex* vertexData, int ele mOutGlop->mesh.indices = { 0, nullptr }; mOutGlop->mesh.vertices = { 0, - VertexAttribFlags::kTextureCoord, + static_cast<int>(VertexAttribFlags::kTextureCoord), &vertexData[0].x, &vertexData[0].u, nullptr, kTextureVertexStride }; mOutGlop->mesh.elementCount = elementCount; @@ -161,7 +161,7 @@ GlopBuilder& GlopBuilder::setMeshColoredTexturedMesh(ColorTextureVertex* vertexD mOutGlop->mesh.indices = { 0, nullptr }; mOutGlop->mesh.vertices = { 0, - static_cast<VertexAttribFlags>(VertexAttribFlags::kTextureCoord | VertexAttribFlags::kColor), + VertexAttribFlags::kTextureCoord | VertexAttribFlags::kColor, &vertexData[0].x, &vertexData[0].u, &vertexData[0].r, kColorTextureVertexStride }; mOutGlop->mesh.elementCount = elementCount; @@ -180,7 +180,7 @@ GlopBuilder& GlopBuilder::setMeshVertexBuffer(const VertexBuffer& vertexBuffer, mOutGlop->mesh.indices = { 0, vertexBuffer.getIndices() }; mOutGlop->mesh.vertices = { 0, - alphaVertex ? VertexAttribFlags::kAlpha : VertexAttribFlags::kNone, + static_cast<int>(alphaVertex ? VertexAttribFlags::kAlpha : VertexAttribFlags::kNone), vertexBuffer.getBuffer(), nullptr, nullptr, alphaVertex ? kAlphaVertexStride : kVertexStride }; mOutGlop->mesh.elementCount = indices @@ -197,7 +197,7 @@ GlopBuilder& GlopBuilder::setMeshPatchQuads(const Patch& patch) { mOutGlop->mesh.indices = { mRenderState.meshState().getQuadListIBO(), nullptr }; mOutGlop->mesh.vertices = { mCaches.patchCache.getMeshBuffer(), - VertexAttribFlags::kTextureCoord, + static_cast<int>(VertexAttribFlags::kTextureCoord), (void*)patch.positionOffset, (void*)patch.textureOffset, nullptr, kTextureVertexStride }; mOutGlop->mesh.elementCount = patch.indexCount; @@ -230,7 +230,7 @@ void GlopBuilder::setFill(int color, float alphaScale, mOutGlop->blend = { GL_ZERO, GL_ZERO }; if (mOutGlop->fill.color.a < 1.0f - || (mOutGlop->mesh.vertices.flags & VertexAttribFlags::kAlpha) + || (mOutGlop->mesh.vertices.attribFlags & VertexAttribFlags::kAlpha) || (mOutGlop->fill.texture.texture && mOutGlop->fill.texture.texture->blend) || mOutGlop->roundRectClipState || PaintUtils::isBlendedShader(shader) @@ -324,7 +324,7 @@ GlopBuilder& GlopBuilder::setFillTexturePaint(Texture& texture, int textureFillF mOutGlop->fill.color = { alphaScale, alphaScale, alphaScale, alphaScale }; if (alphaScale < 1.0f - || (mOutGlop->mesh.vertices.flags & VertexAttribFlags::kAlpha) + || (mOutGlop->mesh.vertices.attribFlags & VertexAttribFlags::kAlpha) || texture.blend || mOutGlop->roundRectClipState) { Blend::getFactors(SkXfermode::kSrcOver_Mode, Blend::ModeOrderSwap::NoSwap, @@ -546,12 +546,25 @@ GlopBuilder& GlopBuilder::setRoundRectClipState(const RoundRectClipState* roundR //////////////////////////////////////////////////////////////////////////////// void verify(const ProgramDescription& description, const Glop& glop) { - bool hasTexture = glop.fill.texture.texture != nullptr; - LOG_ALWAYS_FATAL_IF(description.hasTexture && description.hasExternalTexture); - LOG_ALWAYS_FATAL_IF((description.hasTexture || description.hasExternalTexture )!= hasTexture); - LOG_ALWAYS_FATAL_IF((glop.mesh.vertices.flags & VertexAttribFlags::kTextureCoord) != hasTexture); + if (glop.fill.texture.texture != nullptr) { + LOG_ALWAYS_FATAL_IF(((description.hasTexture && description.hasExternalTexture) + || (!description.hasTexture && !description.hasExternalTexture) + || ((glop.mesh.vertices.attribFlags & VertexAttribFlags::kTextureCoord) == 0)), + "Texture %p, hT%d, hET %d, attribFlags %x", + glop.fill.texture.texture, + description.hasTexture, description.hasExternalTexture, + glop.mesh.vertices.attribFlags); + } else { + LOG_ALWAYS_FATAL_IF((description.hasTexture + || description.hasExternalTexture + || ((glop.mesh.vertices.attribFlags & VertexAttribFlags::kTextureCoord) != 0)), + "No texture, hT%d, hET %d, attribFlags %x", + description.hasTexture, description.hasExternalTexture, + glop.mesh.vertices.attribFlags); + } - if ((glop.mesh.vertices.flags & VertexAttribFlags::kAlpha) && glop.mesh.vertices.bufferObject) { + if ((glop.mesh.vertices.attribFlags & VertexAttribFlags::kAlpha) + && glop.mesh.vertices.bufferObject) { LOG_ALWAYS_FATAL("VBO and alpha attributes are not currently compatible"); } @@ -562,12 +575,12 @@ void verify(const ProgramDescription& description, const Glop& glop) { void GlopBuilder::build() { REQUIRE_STAGES(kAllStages); - if (mOutGlop->mesh.vertices.flags & VertexAttribFlags::kTextureCoord) { + if (mOutGlop->mesh.vertices.attribFlags & VertexAttribFlags::kTextureCoord) { mDescription.hasTexture = mOutGlop->fill.texture.target == GL_TEXTURE_2D; mDescription.hasExternalTexture = mOutGlop->fill.texture.target == GL_TEXTURE_EXTERNAL_OES; } - mDescription.hasColors = mOutGlop->mesh.vertices.flags & VertexAttribFlags::kColor; - mDescription.hasVertexAlpha = mOutGlop->mesh.vertices.flags & VertexAttribFlags::kAlpha; + mDescription.hasColors = mOutGlop->mesh.vertices.attribFlags & VertexAttribFlags::kColor; + mDescription.hasVertexAlpha = mOutGlop->mesh.vertices.attribFlags & VertexAttribFlags::kAlpha; // serialize shader info into ShaderData GLuint textureUnit = mOutGlop->fill.texture.texture ? 1 : 0; diff --git a/libs/hwui/JankTracker.cpp b/libs/hwui/JankTracker.cpp index d0ea3a6dfa2d..46b094556ad7 100644 --- a/libs/hwui/JankTracker.cpp +++ b/libs/hwui/JankTracker.cpp @@ -15,6 +15,7 @@ */ #include "JankTracker.h" +#include <algorithm> #include <cstdio> #include <inttypes.h> @@ -95,7 +96,12 @@ void JankTracker::addFrame(const FrameInfo& frame) { // Fast-path for jank-free frames int64_t totalDuration = frame[FrameInfoIndex::kFrameCompleted] - frame[FrameInfoIndex::kIntendedVsync]; + uint32_t framebucket = std::min( + static_cast<typeof sizeof(mFrameCounts)>(ns2ms(totalDuration)), + sizeof(mFrameCounts) / sizeof(mFrameCounts[0])); + // Keep the fast path as fast as possible. if (CC_LIKELY(totalDuration < mFrameInterval)) { + mFrameCounts[framebucket]++; return; } @@ -103,6 +109,7 @@ void JankTracker::addFrame(const FrameInfo& frame) { return; } + mFrameCounts[framebucket]++; mJankFrameCount++; for (int i = 0; i < NUM_BUCKETS; i++) { @@ -119,6 +126,9 @@ void JankTracker::dump(int fd) { fprintf(file, "\n Total frames rendered: %u", mTotalFrameCount); fprintf(file, "\n Janky frames: %u (%.2f%%)", mJankFrameCount, (float) mJankFrameCount / (float) mTotalFrameCount * 100.0f); + fprintf(file, "\n 90th percentile: %ums", findPercentile(90)); + fprintf(file, "\n 95th percentile: %ums", findPercentile(95)); + fprintf(file, "\n 99th percentile: %ums", findPercentile(99)); for (int i = 0; i < NUM_BUCKETS; i++) { fprintf(file, "\n Number %s: %u", JANK_TYPE_NAMES[i], mBuckets[i].count); } @@ -127,10 +137,23 @@ void JankTracker::dump(int fd) { } void JankTracker::reset() { - memset(mBuckets, 0, sizeof(JankBucket) * NUM_BUCKETS); + memset(mBuckets, 0, sizeof(mBuckets)); + memset(mFrameCounts, 0, sizeof(mFrameCounts)); mTotalFrameCount = 0; mJankFrameCount = 0; } +uint32_t JankTracker::findPercentile(int percentile) { + int pos = percentile * mTotalFrameCount / 100; + int remaining = mTotalFrameCount - pos; + for (int i = sizeof(mFrameCounts) / sizeof(mFrameCounts[0]) - 1; i >= 0; i--) { + remaining -= mFrameCounts[i]; + if (remaining <= 0) { + return i; + } + } + return 0; +} + } /* namespace uirenderer */ } /* namespace android */ diff --git a/libs/hwui/JankTracker.h b/libs/hwui/JankTracker.h index aa554cd65664..3d4929b215c6 100644 --- a/libs/hwui/JankTracker.h +++ b/libs/hwui/JankTracker.h @@ -54,8 +54,11 @@ public: void reset(); private: + uint32_t findPercentile(int p); + JankBucket mBuckets[NUM_BUCKETS]; int64_t mThresholds[NUM_BUCKETS]; + uint32_t mFrameCounts[128]; int64_t mFrameInterval; uint32_t mTotalFrameCount; diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index 61cbde7fe0db..622b5708c065 100644 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -2896,8 +2896,6 @@ void OpenGLRenderer::drawPosText(const char* text, int bytesCount, int count, const Rect& clip(pureTranslate ? writableSnapshot()->getClipRect() : writableSnapshot()->getLocalClip()); Rect bounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f); - const bool hasActiveLayer = hasLayer(); - TextSetupFunctor functor(this, x, y, pureTranslate, alpha, mode, paint); if (fontRenderer.renderPosText(paint, &clip, text, 0, bytesCount, count, x, y, positions, hasLayer() ? &bounds : nullptr, &functor)) { @@ -3097,10 +3095,8 @@ void OpenGLRenderer::drawTextOnPath(const char* text, int bytesCount, int count, const Rect* clip = &writableSnapshot()->getLocalClip(); Rect bounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f); - const bool hasActiveLayer = hasLayer(); - if (fontRenderer.renderTextOnPath(paint, clip, text, 0, bytesCount, count, path, - hOffset, vOffset, hasActiveLayer ? &bounds : nullptr, &functor)) { + hOffset, vOffset, hasLayer() ? &bounds : nullptr, &functor)) { dirtyLayer(bounds.left, bounds.top, bounds.right, bounds.bottom, *currentTransform()); mDirty = true; } diff --git a/libs/hwui/ProgramCache.cpp b/libs/hwui/ProgramCache.cpp index 8c6a91ccb309..e9b22e20bc18 100644 --- a/libs/hwui/ProgramCache.cpp +++ b/libs/hwui/ProgramCache.cpp @@ -380,9 +380,9 @@ const char* gBlendOps[18] = { // Xor "return vec4(src.rgb * (1.0 - dst.a) + (1.0 - src.a) * dst.rgb, " "src.a + dst.a - 2.0 * src.a * dst.a);\n", - // Add + // Plus "return min(src + dst, 1.0);\n", - // Multiply + // Modulate "return src * dst;\n", // Screen "return src + dst - src * dst;\n", @@ -830,7 +830,7 @@ void ProgramCache::printLongString(const String8& shader) const { while ((index = shader.find("\n", index)) > -1) { String8 line(str, index - lastIndex); if (line.length() == 0) line.append("\n"); - PROGRAM_LOGD("%s", line.string()); + ALOGD("%s", line.string()); index++; str += (index - lastIndex); lastIndex = index; diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp index efbb7094c96a..71088b7129a4 100644 --- a/libs/hwui/SkiaCanvas.cpp +++ b/libs/hwui/SkiaCanvas.cpp @@ -22,7 +22,6 @@ #include <SkDeque.h> #include <SkDrawFilter.h> #include <SkGraphics.h> -#include <SkPorterDuff.h> #include <SkShader.h> #include <SkTArray.h> #include <SkTemplates.h> diff --git a/libs/hwui/renderstate/RenderState.cpp b/libs/hwui/renderstate/RenderState.cpp index ca3a4c2f2f30..7b44d6db9a81 100644 --- a/libs/hwui/renderstate/RenderState.cpp +++ b/libs/hwui/renderstate/RenderState.cpp @@ -259,7 +259,7 @@ void RenderState::render(const Glop& glop) { // indices meshState().bindIndicesBufferInternal(indices.bufferObject); - if (vertices.flags & VertexAttribFlags::kTextureCoord) { + if (vertices.attribFlags & VertexAttribFlags::kTextureCoord) { const Glop::Fill::TextureData& texture = fill.texture; // texture always takes slot 0, shader samplers increment from there mCaches->textureState().activateTexture(0); @@ -283,13 +283,13 @@ void RenderState::render(const Glop& glop) { meshState().disableTexCoordsVertexArray(); } int colorLocation = -1; - if (vertices.flags & VertexAttribFlags::kColor) { + if (vertices.attribFlags & VertexAttribFlags::kColor) { colorLocation = fill.program->getAttrib("colors"); glEnableVertexAttribArray(colorLocation); glVertexAttribPointer(colorLocation, 4, GL_FLOAT, GL_FALSE, vertices.stride, vertices.color); } int alphaLocation = -1; - if (vertices.flags & VertexAttribFlags::kAlpha) { + if (vertices.attribFlags & VertexAttribFlags::kAlpha) { // NOTE: alpha vertex position is computed assuming no VBO const void* alphaCoords = ((const GLbyte*) vertices.position) + kVertexAlphaOffset; alphaLocation = fill.program->getAttrib("vtxAlpha"); @@ -317,7 +317,7 @@ void RenderState::render(const Glop& glop) { // rebind pointers without forcing, since initial bind handled above meshState().bindPositionVertexPointer(false, vertexData, vertices.stride); - if (vertices.flags & VertexAttribFlags::kTextureCoord) { + if (vertices.attribFlags & VertexAttribFlags::kTextureCoord) { meshState().bindTexCoordsVertexPointer(false, vertexData + kMeshTextureOffset, vertices.stride); } @@ -335,10 +335,10 @@ void RenderState::render(const Glop& glop) { // ----------------------------------- // ---------- Mesh teardown ---------- // ----------------------------------- - if (vertices.flags & VertexAttribFlags::kAlpha) { + if (vertices.attribFlags & VertexAttribFlags::kAlpha) { glDisableVertexAttribArray(alphaLocation); } - if (vertices.flags & VertexAttribFlags::kColor) { + if (vertices.attribFlags & VertexAttribFlags::kColor) { glDisableVertexAttribArray(colorLocation); } } diff --git a/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java index 09f4bac8dbae..452683942ab5 100644 --- a/media/java/android/media/AudioAttributes.java +++ b/media/java/android/media/AudioAttributes.java @@ -279,6 +279,7 @@ public final class AudioAttributes implements Parcelable { * Internal use only * @return a combined mask of all flags */ + @SystemApi public int getAllFlags() { return (mFlags & FLAG_ALL); } @@ -541,14 +542,15 @@ public final class AudioAttributes implements Parcelable { /** * @hide * Same as {@link #setCapturePreset(int)} but authorizes the use of HOTWORD, - * REMOTE_SUBMIX and FM_TUNER. + * REMOTE_SUBMIX and RADIO_TUNER. * @param preset * @return the same Builder instance. */ + @SystemApi public Builder setInternalCapturePreset(int preset) { if ((preset == MediaRecorder.AudioSource.HOTWORD) || (preset == MediaRecorder.AudioSource.REMOTE_SUBMIX) - || (preset == MediaRecorder.AudioSource.FM_TUNER)) { + || (preset == MediaRecorder.AudioSource.RADIO_TUNER)) { mSource = preset; } else { setCapturePreset(preset); diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java index de10ef9abef9..259fe37884e6 100644 --- a/media/java/android/media/AudioRecord.java +++ b/media/java/android/media/AudioRecord.java @@ -20,6 +20,7 @@ import java.lang.ref.WeakReference; import java.nio.ByteBuffer; import java.util.Iterator; +import android.annotation.SystemApi; import android.os.Binder; import android.os.Handler; import android.os.IBinder; @@ -238,7 +239,6 @@ public class AudioRecord /** * @hide - * CANDIDATE FOR PUBLIC API * Class constructor with {@link AudioAttributes} and {@link AudioFormat}. * @param attributes a non-null {@link AudioAttributes} instance. Use * {@link AudioAttributes.Builder#setCapturePreset(int)} for configuring the capture @@ -257,6 +257,7 @@ public class AudioRecord * construction. * @throws IllegalArgumentException */ + @SystemApi public AudioRecord(AudioAttributes attributes, AudioFormat format, int bufferSizeInBytes, int sessionId) throws IllegalArgumentException { mRecordingState = RECORDSTATE_STOPPED; @@ -376,7 +377,7 @@ public class AudioRecord // audio source if ( (audioSource < MediaRecorder.AudioSource.DEFAULT) || ((audioSource > MediaRecorder.getAudioSourceMax()) && - (audioSource != MediaRecorder.AudioSource.FM_TUNER) && + (audioSource != MediaRecorder.AudioSource.RADIO_TUNER) && (audioSource != MediaRecorder.AudioSource.HOTWORD)) ) { throw new IllegalArgumentException("Invalid audio source."); } diff --git a/media/java/android/media/ImageReader.java b/media/java/android/media/ImageReader.java index 8d6a5883c6c4..824a7adcf057 100644 --- a/media/java/android/media/ImageReader.java +++ b/media/java/android/media/ImageReader.java @@ -483,6 +483,8 @@ public class ImageReader implements AutoCloseable { case ImageFormat.Y16: case ImageFormat.RAW_SENSOR: case ImageFormat.RAW10: + case ImageFormat.DEPTH16: + case ImageFormat.DEPTH_POINT_CLOUD: return 1; default: throw new UnsupportedOperationException( diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java index 97b3f6336bf3..58c86f20605a 100644 --- a/media/java/android/media/MediaRecorder.java +++ b/media/java/android/media/MediaRecorder.java @@ -16,6 +16,7 @@ package android.media; +import android.annotation.SystemApi; import android.app.ActivityThread; import android.hardware.Camera; import android.os.Handler; @@ -222,12 +223,11 @@ public class MediaRecorder public static final int REMOTE_SUBMIX = 8; /** - * Audio source for FM, which is used to capture current FM tuner output by FMRadio app. - * There are two use cases, one is for record FM stream for later listening, another is - * for FM indirect mode(the routing except FM to headset(headphone) device routing). + * Audio source for capturing broadcast radio tuner output. * @hide */ - public static final int FM_TUNER = 1998; + @SystemApi + public static final int RADIO_TUNER = 1998; /** * Audio source for preemptible, low-priority software hotword detection @@ -240,7 +240,8 @@ public class MediaRecorder * This is a hidden audio source. * @hide */ - protected static final int HOTWORD = 1999; + @SystemApi + public static final int HOTWORD = 1999; } /** diff --git a/media/java/android/media/midi/IMidiDeviceServer.aidl b/media/java/android/media/midi/IMidiDeviceServer.aidl index 71914ad5892d..3331aae649bf 100644 --- a/media/java/android/media/midi/IMidiDeviceServer.aidl +++ b/media/java/android/media/midi/IMidiDeviceServer.aidl @@ -21,6 +21,7 @@ import android.os.ParcelFileDescriptor; /** @hide */ interface IMidiDeviceServer { - ParcelFileDescriptor openInputPort(int portNumber); - ParcelFileDescriptor openOutputPort(int portNumber); + ParcelFileDescriptor openInputPort(IBinder token, int portNumber); + ParcelFileDescriptor openOutputPort(IBinder token, int portNumber); + void closePort(IBinder token); } diff --git a/media/java/android/media/midi/MidiDevice.java b/media/java/android/media/midi/MidiDevice.java index 87af362d21da..af0737da516f 100644 --- a/media/java/android/media/midi/MidiDevice.java +++ b/media/java/android/media/midi/MidiDevice.java @@ -16,30 +16,47 @@ package android.media.midi; +import android.content.Context; +import android.content.ServiceConnection; +import android.os.Binder; +import android.os.IBinder; import android.os.ParcelFileDescriptor; import android.os.RemoteException; import android.util.Log; +import dalvik.system.CloseGuard; + +import java.io.Closeable; +import java.io.IOException; + /** - * This class is used for sending and receiving data to and from an MIDI device + * This class is used for sending and receiving data to and from a MIDI device * Instances of this class are created by {@link MidiManager#openDevice}. * * CANDIDATE FOR PUBLIC API * @hide */ -public final class MidiDevice { +public final class MidiDevice implements Closeable { private static final String TAG = "MidiDevice"; private final MidiDeviceInfo mDeviceInfo; - private final IMidiDeviceServer mServer; + private final IMidiDeviceServer mDeviceServer; + private Context mContext; + private ServiceConnection mServiceConnection; - /** - * MidiDevice should only be instantiated by MidiManager - * @hide - */ - public MidiDevice(MidiDeviceInfo deviceInfo, IMidiDeviceServer server) { + private final CloseGuard mGuard = CloseGuard.get(); + + /* package */ MidiDevice(MidiDeviceInfo deviceInfo, IMidiDeviceServer server) { + this(deviceInfo, server, null, null); + } + + /* package */ MidiDevice(MidiDeviceInfo deviceInfo, IMidiDeviceServer server, + Context context, ServiceConnection serviceConnection) { mDeviceInfo = deviceInfo; - mServer = server; + mDeviceServer = server; + mContext = context; + mServiceConnection = serviceConnection; + mGuard.open("close"); } /** @@ -59,11 +76,12 @@ public final class MidiDevice { */ public MidiInputPort openInputPort(int portNumber) { try { - ParcelFileDescriptor pfd = mServer.openInputPort(portNumber); + IBinder token = new Binder(); + ParcelFileDescriptor pfd = mDeviceServer.openInputPort(token, portNumber); if (pfd == null) { return null; } - return new MidiInputPort(pfd, portNumber); + return new MidiInputPort(mDeviceServer, token, pfd, portNumber); } catch (RemoteException e) { Log.e(TAG, "RemoteException in openInputPort"); return null; @@ -78,11 +96,12 @@ public final class MidiDevice { */ public MidiOutputPort openOutputPort(int portNumber) { try { - ParcelFileDescriptor pfd = mServer.openOutputPort(portNumber); + IBinder token = new Binder(); + ParcelFileDescriptor pfd = mDeviceServer.openOutputPort(token, portNumber); if (pfd == null) { return null; } - return new MidiOutputPort(pfd, portNumber); + return new MidiOutputPort(mDeviceServer, token, pfd, portNumber); } catch (RemoteException e) { Log.e(TAG, "RemoteException in openOutputPort"); return null; @@ -90,6 +109,28 @@ public final class MidiDevice { } @Override + public void close() throws IOException { + synchronized (mGuard) { + mGuard.close(); + if (mContext != null && mServiceConnection != null) { + mContext.unbindService(mServiceConnection); + mContext = null; + mServiceConnection = null; + } + } + } + + @Override + protected void finalize() throws Throwable { + try { + mGuard.warnIfOpen(); + close(); + } finally { + super.finalize(); + } + } + + @Override public String toString() { return ("MidiDevice: " + mDeviceInfo.toString()); } diff --git a/media/java/android/media/midi/MidiDeviceInfo.java b/media/java/android/media/midi/MidiDeviceInfo.java index b7756fdb6f17..1e97258fe37a 100644 --- a/media/java/android/media/midi/MidiDeviceInfo.java +++ b/media/java/android/media/midi/MidiDeviceInfo.java @@ -31,7 +31,7 @@ import android.os.Parcelable; * CANDIDATE FOR PUBLIC API * @hide */ -public class MidiDeviceInfo implements Parcelable { +public final class MidiDeviceInfo implements Parcelable { private static final String TAG = "MidiDeviceInfo"; diff --git a/media/java/android/media/midi/MidiDeviceServer.java b/media/java/android/media/midi/MidiDeviceServer.java index 24ef5288f9d6..3b4b6f0f0283 100644 --- a/media/java/android/media/midi/MidiDeviceServer.java +++ b/media/java/android/media/midi/MidiDeviceServer.java @@ -24,10 +24,14 @@ import android.os.RemoteException; import android.system.OsConstants; import android.util.Log; +import dalvik.system.CloseGuard; + import libcore.io.IoUtils; import java.io.Closeable; import java.io.IOException; +import java.util.HashMap; +import java.util.concurrent.CopyOnWriteArrayList; /** * Internal class used for providing an implementation for a MIDI device. @@ -53,11 +57,75 @@ public final class MidiDeviceServer implements Closeable { // MidiOutputPorts for clients connected to our input ports private final MidiOutputPort[] mInputPortOutputPorts; + // List of all MidiInputPorts we created + private final CopyOnWriteArrayList<MidiInputPort> mInputPorts + = new CopyOnWriteArrayList<MidiInputPort>(); + + private final CloseGuard mGuard = CloseGuard.get(); + + abstract private class PortClient implements IBinder.DeathRecipient { + final IBinder mToken; + + PortClient(IBinder token) { + mToken = token; + + try { + token.linkToDeath(this, 0); + } catch (RemoteException e) { + close(); + } + } + + abstract void close(); + + @Override + public void binderDied() { + close(); + } + } + + private class InputPortClient extends PortClient { + private final MidiOutputPort mOutputPort; + + InputPortClient(IBinder token, MidiOutputPort outputPort) { + super(token); + mOutputPort = outputPort; + } + + @Override + void close() { + mToken.unlinkToDeath(this, 0); + synchronized (mInputPortOutputPorts) { + mInputPortOutputPorts[mOutputPort.getPortNumber()] = null; + } + IoUtils.closeQuietly(mOutputPort); + } + } + + private class OutputPortClient extends PortClient { + private final MidiInputPort mInputPort; + + OutputPortClient(IBinder token, MidiInputPort inputPort) { + super(token); + mInputPort = inputPort; + } + + @Override + void close() { + mToken.unlinkToDeath(this, 0); + mOutputPortDispatchers[mInputPort.getPortNumber()].getSender().disconnect(mInputPort); + mInputPorts.remove(mInputPort); + IoUtils.closeQuietly(mInputPort); + } + } + + private final HashMap<IBinder, PortClient> mPortClients = new HashMap<IBinder, PortClient>(); + // Binder interface stub for receiving connection requests from clients private final IMidiDeviceServer mServer = new IMidiDeviceServer.Stub() { @Override - public ParcelFileDescriptor openInputPort(int portNumber) { + public ParcelFileDescriptor openInputPort(IBinder token, int portNumber) { if (mDeviceInfo.isPrivate()) { if (Binder.getCallingUid() != Process.myUid()) { throw new SecurityException("Can't access private device from different UID"); @@ -78,25 +146,13 @@ public final class MidiDeviceServer implements Closeable { try { ParcelFileDescriptor[] pair = ParcelFileDescriptor.createSocketPair( OsConstants.SOCK_SEQPACKET); - final MidiOutputPort outputPort = new MidiOutputPort(pair[0], portNumber); + MidiOutputPort outputPort = new MidiOutputPort(pair[0], portNumber); mInputPortOutputPorts[portNumber] = outputPort; - final int portNumberF = portNumber; - final MidiReceiver inputPortReceviver = mInputPortReceivers[portNumber]; - - outputPort.connect(new MidiReceiver() { - @Override - public void post(byte[] msg, int offset, int count, long timestamp) - throws IOException { - try { - inputPortReceviver.post(msg, offset, count, timestamp); - } catch (IOException e) { - IoUtils.closeQuietly(mInputPortOutputPorts[portNumberF]); - mInputPortOutputPorts[portNumberF] = null; - // FIXME also flush the receiver - } - } - }); - + outputPort.connect(mInputPortReceivers[portNumber]); + InputPortClient client = new InputPortClient(token, outputPort); + synchronized (mPortClients) { + mPortClients.put(token, client); + } return pair[1]; } catch (IOException e) { Log.e(TAG, "unable to create ParcelFileDescriptors in openInputPort"); @@ -106,7 +162,7 @@ public final class MidiDeviceServer implements Closeable { } @Override - public ParcelFileDescriptor openOutputPort(int portNumber) { + public ParcelFileDescriptor openOutputPort(IBinder token, int portNumber) { if (mDeviceInfo.isPrivate()) { if (Binder.getCallingUid() != Process.myUid()) { throw new SecurityException("Can't access private device from different UID"); @@ -121,28 +177,29 @@ public final class MidiDeviceServer implements Closeable { try { ParcelFileDescriptor[] pair = ParcelFileDescriptor.createSocketPair( OsConstants.SOCK_SEQPACKET); - final MidiInputPort inputPort = new MidiInputPort(pair[0], portNumber); - final MidiSender sender = mOutputPortDispatchers[portNumber].getSender(); - sender.connect(new MidiReceiver() { - @Override - public void post(byte[] msg, int offset, int count, long timestamp) - throws IOException { - try { - inputPort.post(msg, offset, count, timestamp); - } catch (IOException e) { - IoUtils.closeQuietly(inputPort); - sender.disconnect(this); - // FIXME also flush the receiver? - } - } - }); - + MidiInputPort inputPort = new MidiInputPort(pair[0], portNumber); + mOutputPortDispatchers[portNumber].getSender().connect(inputPort); + mInputPorts.add(inputPort); + OutputPortClient client = new OutputPortClient(token, inputPort); + synchronized (mPortClients) { + mPortClients.put(token, client); + } return pair[1]; } catch (IOException e) { Log.e(TAG, "unable to create ParcelFileDescriptors in openOutputPort"); return null; } } + + @Override + public void closePort(IBinder token) { + synchronized (mPortClients) { + PortClient client = mPortClients.remove(token); + if (client != null) { + client.close(); + } + } + } }; /* package */ MidiDeviceServer(IMidiManager midiManager, MidiReceiver[] inputPortReceivers, @@ -158,6 +215,8 @@ public final class MidiDeviceServer implements Closeable { for (int i = 0; i < numOutputPorts; i++) { mOutputPortDispatchers[i] = new MidiDispatcher(); } + + mGuard.open("close"); } /* package */ IMidiDeviceServer getBinderInterface() { @@ -173,11 +232,35 @@ public final class MidiDeviceServer implements Closeable { @Override public void close() throws IOException { + synchronized (mGuard) { + mGuard.close(); + + for (int i = 0; i < mInputPortCount; i++) { + MidiOutputPort outputPort = mInputPortOutputPorts[i]; + if (outputPort != null) { + IoUtils.closeQuietly(outputPort); + mInputPortOutputPorts[i] = null; + } + } + for (MidiInputPort inputPort : mInputPorts) { + IoUtils.closeQuietly(inputPort); + } + mInputPorts.clear(); + try { + mMidiManager.unregisterDeviceServer(mServer); + } catch (RemoteException e) { + Log.e(TAG, "RemoteException in unregisterDeviceServer"); + } + } + } + + @Override + protected void finalize() throws Throwable { try { - // FIXME - close input and output ports too? - mMidiManager.unregisterDeviceServer(mServer); - } catch (RemoteException e) { - Log.e(TAG, "RemoteException in unregisterDeviceServer"); + mGuard.warnIfOpen(); + close(); + } finally { + super.finalize(); } } diff --git a/media/java/android/media/midi/MidiDeviceService.java b/media/java/android/media/midi/MidiDeviceService.java index 1d91be2ae192..64f69cdcd132 100644 --- a/media/java/android/media/midi/MidiDeviceService.java +++ b/media/java/android/media/midi/MidiDeviceService.java @@ -55,6 +55,7 @@ abstract public class MidiDeviceService extends Service { private IMidiManager mMidiManager; private MidiDeviceServer mServer; + private MidiDeviceInfo mDeviceInfo; @Override public void onCreate() { @@ -64,6 +65,11 @@ abstract public class MidiDeviceService extends Service { try { MidiDeviceInfo deviceInfo = mMidiManager.getServiceDeviceInfo(getPackageName(), this.getClass().getName()); + if (deviceInfo == null) { + Log.e(TAG, "Could not find MidiDeviceInfo for MidiDeviceService " + this); + return; + } + mDeviceInfo = deviceInfo; MidiReceiver[] inputPortReceivers = getInputPortReceivers(); if (inputPortReceivers == null) { inputPortReceivers = new MidiReceiver[0]; @@ -100,6 +106,14 @@ abstract public class MidiDeviceService extends Service { } } + /** + * returns the {@link MidiDeviceInfo} instance for this service + * @return our MidiDeviceInfo + */ + public MidiDeviceInfo getDeviceInfo() { + return mDeviceInfo; + } + @Override public IBinder onBind(Intent intent) { if (SERVICE_INTERFACE.equals(intent.getAction()) && mServer != null) { diff --git a/media/java/android/media/midi/MidiDispatcher.java b/media/java/android/media/midi/MidiDispatcher.java index 165061f1f09d..a5193f10aad5 100644 --- a/media/java/android/media/midi/MidiDispatcher.java +++ b/media/java/android/media/midi/MidiDispatcher.java @@ -17,21 +17,22 @@ package android.media.midi; import java.io.IOException; -import java.util.ArrayList; +import java.util.concurrent.CopyOnWriteArrayList; /** * Utility class for dispatching MIDI data to a list of {@link MidiReceiver}s. * This class subclasses {@link MidiReceiver} and dispatches any data it receives * to its receiver list. Any receivers that throw an exception upon receiving data will * be automatically removed from the receiver list, but no IOException will be returned - * from the dispatcher's {@link #post} in that case. + * from the dispatcher's {@link #receive} in that case. * * CANDIDATE FOR PUBLIC API * @hide */ -public class MidiDispatcher implements MidiReceiver { +public final class MidiDispatcher extends MidiReceiver { - private final ArrayList<MidiReceiver> mReceivers = new ArrayList<MidiReceiver>(); + private final CopyOnWriteArrayList<MidiReceiver> mReceivers + = new CopyOnWriteArrayList<MidiReceiver>(); private final MidiSender mSender = new MidiSender() { /** @@ -71,18 +72,13 @@ public class MidiDispatcher implements MidiReceiver { } @Override - public void post(byte[] msg, int offset, int count, long timestamp) throws IOException { - synchronized (mReceivers) { - for (int i = 0; i < mReceivers.size(); ) { - MidiReceiver receiver = mReceivers.get(i); - try { - receiver.post(msg, offset, count, timestamp); - i++; // increment only on success. on failure we remove the receiver - // so i should not be incremented - } catch (IOException e) { - // if the receiver fails we remove the receiver but do not propogate the exception - mSender.disconnect(receiver); - } + public void receive(byte[] msg, int offset, int count, long timestamp) throws IOException { + for (MidiReceiver receiver : mReceivers) { + try { + receiver.receive(msg, offset, count, timestamp); + } catch (IOException e) { + // if the receiver fails we remove the receiver but do not propogate the exception + mReceivers.remove(receiver); } } } diff --git a/media/java/android/media/midi/MidiInputPort.java b/media/java/android/media/midi/MidiInputPort.java index 730d36442336..86749699bf81 100644 --- a/media/java/android/media/midi/MidiInputPort.java +++ b/media/java/android/media/midi/MidiInputPort.java @@ -16,10 +16,16 @@ package android.media.midi; +import android.os.IBinder; import android.os.ParcelFileDescriptor; +import android.os.RemoteException; +import android.util.Log; + +import dalvik.system.CloseGuard; import libcore.io.IoUtils; +import java.io.Closeable; import java.io.FileOutputStream; import java.io.IOException; @@ -29,52 +35,93 @@ import java.io.IOException; * CANDIDATE FOR PUBLIC API * @hide */ -public class MidiInputPort extends MidiPort implements MidiReceiver { +public final class MidiInputPort extends MidiReceiver implements Closeable { + private static final String TAG = "MidiInputPort"; + private IMidiDeviceServer mDeviceServer; + private final IBinder mToken; + private final int mPortNumber; private final FileOutputStream mOutputStream; - // buffer to use for sending messages out our output stream - private final byte[] mBuffer = new byte[MAX_PACKET_SIZE]; + private final CloseGuard mGuard = CloseGuard.get(); + private boolean mIsClosed; + + // buffer to use for sending data out our output stream + private final byte[] mBuffer = new byte[MidiPortImpl.MAX_PACKET_SIZE]; - /* package */ MidiInputPort(ParcelFileDescriptor pfd, int portNumber) { - super(portNumber); + /* package */ MidiInputPort(IMidiDeviceServer server, IBinder token, + ParcelFileDescriptor pfd, int portNumber) { + mDeviceServer = server; + mToken = token; + mPortNumber = portNumber; mOutputStream = new ParcelFileDescriptor.AutoCloseOutputStream(pfd); + mGuard.open("close"); + } + + /* package */ MidiInputPort(ParcelFileDescriptor pfd, int portNumber) { + this(null, null, pfd, portNumber); + } + + /** + * Returns the port number of this port + * + * @return the port's port number + */ + public final int getPortNumber() { + return mPortNumber; } /** - * Writes a MIDI message to the input port + * Writes MIDI data to the input port * - * @param msg byte array containing the message - * @param offset offset of first byte of the message in msg byte array - * @param count size of the message in bytes - * @param timestamp future time to post the message (based on + * @param msg byte array containing the data + * @param offset offset of first byte of the data in msg byte array + * @param count size of the data in bytes + * @param timestamp future time to post the data (based on * {@link java.lang.System#nanoTime} */ - public void post(byte[] msg, int offset, int count, long timestamp) throws IOException { + public void receive(byte[] msg, int offset, int count, long timestamp) throws IOException { assert(offset >= 0 && count >= 0 && offset + count <= msg.length); synchronized (mBuffer) { - try { - while (count > 0) { - int length = packMessage(msg, offset, count, timestamp, mBuffer); - mOutputStream.write(mBuffer, 0, length); - int sent = getMessageSize(mBuffer, length); - assert(sent >= 0 && sent <= length); - - offset += sent; - count -= sent; - } - } catch (IOException e) { - IoUtils.closeQuietly(mOutputStream); - // report I/O failure - onIOException(); - throw e; + while (count > 0) { + int length = MidiPortImpl.packMessage(msg, offset, count, timestamp, mBuffer); + mOutputStream.write(mBuffer, 0, length); + int sent = MidiPortImpl.getMessageSize(mBuffer, length); + assert(sent >= 0 && sent <= length); + + offset += sent; + count -= sent; } } } @Override public void close() throws IOException { - mOutputStream.close(); + synchronized (mGuard) { + if (mIsClosed) return; + mGuard.close(); + mOutputStream.close(); + if (mDeviceServer != null) { + try { + mDeviceServer.closePort(mToken); + } catch (RemoteException e) { + Log.e(TAG, "RemoteException in MidiInputPort.close()"); + } + } + mIsClosed = true; + } + } + + @Override + protected void finalize() throws Throwable { + try { + mGuard.warnIfOpen(); + // not safe to make binder calls from finalize() + mDeviceServer = null; + close(); + } finally { + super.finalize(); + } } } diff --git a/media/java/android/media/midi/MidiManager.java b/media/java/android/media/midi/MidiManager.java index ca7d3c25c293..d7b8c5702bd8 100644 --- a/media/java/android/media/midi/MidiManager.java +++ b/media/java/android/media/midi/MidiManager.java @@ -42,7 +42,7 @@ import java.util.HashMap; * CANDIDATE FOR PUBLIC API * @hide */ -public class MidiManager { +public final class MidiManager { private static final String TAG = "MidiManager"; private final Context mContext; @@ -223,7 +223,7 @@ public class MidiManager { public void onServiceConnected(ComponentName name, IBinder binder) { IMidiDeviceServer server = IMidiDeviceServer.Stub.asInterface(binder); - MidiDevice device = new MidiDevice(deviceInfoF, server); + MidiDevice device = new MidiDevice(deviceInfoF, server, mContext, this); sendOpenDeviceResponse(deviceInfoF, device, callbackF, handlerF); } diff --git a/media/java/android/media/midi/MidiOutputPort.java b/media/java/android/media/midi/MidiOutputPort.java index c195603a204c..b31cdd37bb5f 100644 --- a/media/java/android/media/midi/MidiOutputPort.java +++ b/media/java/android/media/midi/MidiOutputPort.java @@ -16,11 +16,16 @@ package android.media.midi; +import android.os.IBinder; import android.os.ParcelFileDescriptor; +import android.os.RemoteException; import android.util.Log; +import dalvik.system.CloseGuard; + import libcore.io.IoUtils; +import java.io.Closeable; import java.io.FileInputStream; import java.io.IOException; @@ -30,18 +35,24 @@ import java.io.IOException; * CANDIDATE FOR PUBLIC API * @hide */ -public class MidiOutputPort extends MidiPort implements MidiSender { +public final class MidiOutputPort extends MidiSender implements Closeable { private static final String TAG = "MidiOutputPort"; + private IMidiDeviceServer mDeviceServer; + private final IBinder mToken; + private final int mPortNumber; private final FileInputStream mInputStream; private final MidiDispatcher mDispatcher = new MidiDispatcher(); + private final CloseGuard mGuard = CloseGuard.get(); + private boolean mIsClosed; + // This thread reads MIDI events from a socket and distributes them to the list of // MidiReceivers attached to this device. private final Thread mThread = new Thread() { @Override public void run() { - byte[] buffer = new byte[MAX_PACKET_SIZE]; + byte[] buffer = new byte[MidiPortImpl.MAX_PACKET_SIZE]; try { while (true) { @@ -52,12 +63,12 @@ public class MidiOutputPort extends MidiPort implements MidiSender { // FIXME - inform receivers here? } - int offset = getMessageOffset(buffer, count); - int size = getMessageSize(buffer, count); - long timestamp = getMessageTimeStamp(buffer, count); + int offset = MidiPortImpl.getMessageOffset(buffer, count); + int size = MidiPortImpl.getMessageSize(buffer, count); + long timestamp = MidiPortImpl.getMessageTimeStamp(buffer, count); // dispatch to all our receivers - mDispatcher.post(buffer, offset, size, timestamp); + mDispatcher.receive(buffer, offset, size, timestamp); } } catch (IOException e) { // FIXME report I/O failure? @@ -68,10 +79,27 @@ public class MidiOutputPort extends MidiPort implements MidiSender { } }; - /* package */ MidiOutputPort(ParcelFileDescriptor pfd, int portNumber) { - super(portNumber); + /* package */ MidiOutputPort(IMidiDeviceServer server, IBinder token, + ParcelFileDescriptor pfd, int portNumber) { + mDeviceServer = server; + mToken = token; + mPortNumber = portNumber; mInputStream = new ParcelFileDescriptor.AutoCloseInputStream(pfd); mThread.start(); + mGuard.open("close"); + } + + /* package */ MidiOutputPort(ParcelFileDescriptor pfd, int portNumber) { + this(null, null, pfd, portNumber); + } + + /** + * Returns the port number of this port + * + * @return the port's port number + */ + public final int getPortNumber() { + return mPortNumber; } @Override @@ -86,6 +114,31 @@ public class MidiOutputPort extends MidiPort implements MidiSender { @Override public void close() throws IOException { - mInputStream.close(); + synchronized (mGuard) { + if (mIsClosed) return; + + mGuard.close(); + mInputStream.close(); + if (mDeviceServer != null) { + try { + mDeviceServer.closePort(mToken); + } catch (RemoteException e) { + Log.e(TAG, "RemoteException in MidiOutputPort.close()"); + } + } + mIsClosed = true; + } + } + + @Override + protected void finalize() throws Throwable { + try { + mGuard.warnIfOpen(); + // not safe to make binder calls from finalize() + mDeviceServer = null; + close(); + } finally { + super.finalize(); + } } } diff --git a/media/java/android/media/midi/MidiPort.java b/media/java/android/media/midi/MidiPortImpl.java index 3aa03f2de0d8..5795045edc7d 100644 --- a/media/java/android/media/midi/MidiPort.java +++ b/media/java/android/media/midi/MidiPortImpl.java @@ -16,31 +16,20 @@ package android.media.midi; -import java.io.Closeable; - /** - * This class represents a MIDI input or output port. - * Base class for {@link MidiInputPort} and {@link MidiOutputPort} - * - * CANDIDATE FOR PUBLIC API - * @hide + * This class contains utilities for socket communication between a + * MidiInputPort and MidiOutputPort */ -abstract public class MidiPort implements Closeable { +/* package */ class MidiPortImpl { private static final String TAG = "MidiPort"; - private final int mPortNumber; - /** * Maximum size of a packet that can pass through our ParcelFileDescriptor. - * For internal use only. Implementation details may change in the future. - * @hide */ public static final int MAX_PACKET_SIZE = 1024; /** * size of message timestamp in bytes - * For internal use only. Implementation details may change in the future. - * @hide */ private static final int TIMESTAMP_SIZE = 8; @@ -49,29 +38,6 @@ abstract public class MidiPort implements Closeable { */ public static final int MAX_PACKET_DATA_SIZE = MAX_PACKET_SIZE - TIMESTAMP_SIZE; - - /* package */ MidiPort(int portNumber) { - mPortNumber = portNumber; - } - - /** - * Returns the port number of this port - * - * @return the port's port number - */ - public final int getPortNumber() { - return mPortNumber; - } - - /** - * Called when an IOExeption occurs while sending or receiving data. - * Subclasses can override to be notified of such errors - * - * @hide - */ - public void onIOException() { - } - /** * Utility function for packing a MIDI message to be sent through our ParcelFileDescriptor * @@ -80,9 +46,6 @@ abstract public class MidiPort implements Closeable { * timestamp is message timestamp to pack * dest is buffer to pack into * returns size of packed message - * - * For internal use only. Implementation details may change in the future. - * @hide */ public static int packMessage(byte[] message, int offset, int size, long timestamp, byte[] dest) { @@ -104,9 +67,6 @@ abstract public class MidiPort implements Closeable { /** * Utility function for unpacking a MIDI message received from our ParcelFileDescriptor * returns the offset of the MIDI message in packed buffer - * - * For internal use only. Implementation details may change in the future. - * @hide */ public static int getMessageOffset(byte[] buffer, int bufferLength) { // message is at the beginning @@ -116,9 +76,6 @@ abstract public class MidiPort implements Closeable { /** * Utility function for unpacking a MIDI message received from our ParcelFileDescriptor * returns size of MIDI data in packed buffer - * - * For internal use only. Implementation details may change in the future. - * @hide */ public static int getMessageSize(byte[] buffer, int bufferLength) { // message length is total buffer length minus size of the timestamp @@ -128,9 +85,6 @@ abstract public class MidiPort implements Closeable { /** * Utility function for unpacking a MIDI message received from our ParcelFileDescriptor * unpacks timestamp from packed buffer - * - * For internal use only. Implementation details may change in the future. - * @hide */ public static long getMessageTimeStamp(byte[] buffer, int bufferLength) { // timestamp is at end of the packet diff --git a/media/java/android/media/midi/MidiReceiver.java b/media/java/android/media/midi/MidiReceiver.java index 64c0c072fa40..674c9743500f 100644 --- a/media/java/android/media/midi/MidiReceiver.java +++ b/media/java/android/media/midi/MidiReceiver.java @@ -24,7 +24,7 @@ import java.io.IOException; * CANDIDATE FOR PUBLIC API * @hide */ -public interface MidiReceiver { +abstract public class MidiReceiver { /** * Called to pass MIDI data to the receiver. * @@ -32,7 +32,7 @@ public interface MidiReceiver { * The msg bytes should be copied by the receiver rather than retaining a reference * to this parameter. * Also, modifying the contents of the msg array parameter may result in other receivers - * in the same application receiving incorrect values in their post() method. + * in the same application receiving incorrect values in their receive() method. * * @param msg a byte array containing the MIDI data * @param offset the offset of the first byte of the data in the byte array @@ -40,5 +40,6 @@ public interface MidiReceiver { * @param timestamp the timestamp of the message (based on {@link java.lang.System#nanoTime} * @throws IOException */ - public void post(byte[] msg, int offset, int count, long timestamp) throws IOException; + abstract public void receive(byte[] msg, int offset, int count, long timestamp) + throws IOException; } diff --git a/media/java/android/media/midi/MidiSender.java b/media/java/android/media/midi/MidiSender.java index 455047670167..9285973234e0 100644 --- a/media/java/android/media/midi/MidiSender.java +++ b/media/java/android/media/midi/MidiSender.java @@ -23,18 +23,18 @@ package android.media.midi; * CANDIDATE FOR PUBLIC API * @hide */ -public interface MidiSender { +abstract public class MidiSender { /** * Called to connect a {@link MidiReceiver} to the sender * * @param receiver the receiver to connect */ - public void connect(MidiReceiver receiver); + abstract public void connect(MidiReceiver receiver); /** * Called to disconnect a {@link MidiReceiver} from the sender * * @param receiver the receiver to disconnect */ - public void disconnect(MidiReceiver receiver); + abstract public void disconnect(MidiReceiver receiver); } diff --git a/media/jni/android_media_ImageReader.cpp b/media/jni/android_media_ImageReader.cpp index cf69b8f829b0..b2474931e9c6 100644 --- a/media/jni/android_media_ImageReader.cpp +++ b/media/jni/android_media_ImageReader.cpp @@ -95,6 +95,9 @@ public: void setBufferFormat(int format) { mFormat = format; } int getBufferFormat() { return mFormat; } + void setBufferDataspace(android_dataspace dataSpace) { mDataSpace = dataSpace; } + android_dataspace getBufferDataspace() { return mDataSpace; } + void setBufferWidth(int width) { mWidth = width; } int getBufferWidth() { return mWidth; } @@ -111,6 +114,7 @@ private: jobject mWeakThiz; jclass mClazz; int mFormat; + android_dataspace mDataSpace; int mWidth; int mHeight; }; @@ -263,29 +267,6 @@ static void Image_setBuffer(JNIEnv* env, jobject thiz, env->SetLongField(thiz, gSurfaceImageClassInfo.mLockedBuffer, reinterpret_cast<jlong>(buffer)); } -// Some formats like JPEG defined with different values between android.graphics.ImageFormat and -// graphics.h, need convert to the one defined in graphics.h here. -static int Image_getPixelFormat(JNIEnv* env, int format) -{ - int jpegFormat; - jfieldID fid; - - ALOGV("%s: format = 0x%x", __FUNCTION__, format); - - jclass imageFormatClazz = env->FindClass("android/graphics/ImageFormat"); - ALOG_ASSERT(imageFormatClazz != NULL); - - fid = env->GetStaticFieldID(imageFormatClazz, "JPEG", "I"); - jpegFormat = env->GetStaticIntField(imageFormatClazz, fid); - - // Translate the JPEG to BLOB for camera purpose. - if (format == jpegFormat) { - format = HAL_PIXEL_FORMAT_BLOB; - } - - return format; -} - static uint32_t Image_getJpegSize(CpuConsumer::LockedBuffer* buffer, bool usingRGBAOverride) { ALOG_ASSERT(buffer != NULL, "Input buffer is NULL!!!"); @@ -483,7 +464,7 @@ static void Image_getLockedBufferInfo(JNIEnv* env, CpuConsumer::LockedBuffer* bu } static jint Image_imageGetPixelStride(JNIEnv* env, CpuConsumer::LockedBuffer* buffer, int idx, - int32_t readerFormat) + int32_t halReaderFormat) { ALOGV("%s: buffer index: %d", __FUNCTION__, idx); ALOG_ASSERT((idx < IMAGE_READER_MAX_NUM_PLANES) && (idx >= 0), "Index is out of range:%d", idx); @@ -493,7 +474,7 @@ static jint Image_imageGetPixelStride(JNIEnv* env, CpuConsumer::LockedBuffer* bu int32_t fmt = buffer->flexFormat; - fmt = applyFormatOverrides(fmt, readerFormat); + fmt = applyFormatOverrides(fmt, halReaderFormat); switch (fmt) { case HAL_PIXEL_FORMAT_YCbCr_420_888: @@ -543,7 +524,7 @@ static jint Image_imageGetPixelStride(JNIEnv* env, CpuConsumer::LockedBuffer* bu } static jint Image_imageGetRowStride(JNIEnv* env, CpuConsumer::LockedBuffer* buffer, int idx, - int32_t readerFormat) + int32_t halReaderFormat) { ALOGV("%s: buffer index: %d", __FUNCTION__, idx); ALOG_ASSERT((idx < IMAGE_READER_MAX_NUM_PLANES) && (idx >= 0)); @@ -553,7 +534,7 @@ static jint Image_imageGetRowStride(JNIEnv* env, CpuConsumer::LockedBuffer* buff int32_t fmt = buffer->flexFormat; - fmt = applyFormatOverrides(fmt, readerFormat); + fmt = applyFormatOverrides(fmt, halReaderFormat); switch (fmt) { case HAL_PIXEL_FORMAT_YCbCr_420_888: @@ -682,11 +663,16 @@ static void ImageReader_init(JNIEnv* env, jobject thiz, jobject weakThiz, { status_t res; int nativeFormat; + android_dataspace nativeDataspace; ALOGV("%s: width:%d, height: %d, format: 0x%x, maxImages:%d", __FUNCTION__, width, height, format, maxImages); - nativeFormat = Image_getPixelFormat(env, format); + PublicFormat publicFormat = static_cast<PublicFormat>(format); + nativeFormat = android_view_Surface_mapPublicFormatToHalFormat( + publicFormat); + nativeDataspace = android_view_Surface_mapPublicFormatToHalDataspace( + publicFormat); sp<IGraphicBufferProducer> gbProducer; sp<IGraphicBufferConsumer> gbConsumer; @@ -710,10 +696,11 @@ static void ImageReader_init(JNIEnv* env, jobject thiz, jobject weakThiz, consumer->setFrameAvailableListener(ctx); ImageReader_setNativeContext(env, thiz, ctx); ctx->setBufferFormat(nativeFormat); + ctx->setBufferDataspace(nativeDataspace); ctx->setBufferWidth(width); ctx->setBufferHeight(height); - // Set the width/height/format to the CpuConsumer + // Set the width/height/format/dataspace to the CpuConsumer res = consumer->setDefaultBufferSize(width, height); if (res != OK) { jniThrowException(env, "java/lang/IllegalStateException", @@ -725,6 +712,12 @@ static void ImageReader_init(JNIEnv* env, jobject thiz, jobject weakThiz, jniThrowException(env, "java/lang/IllegalStateException", "Failed to set CpuConsumer buffer format"); } + res = consumer->setDefaultBufferDataSpace(nativeDataspace); + if (res != OK) { + jniThrowException(env, "java/lang/IllegalStateException", + "Failed to set CpuConsumer buffer dataSpace"); + } + } static void ImageReader_close(JNIEnv* env, jobject thiz) @@ -884,6 +877,8 @@ static jobject ImageReader_getSurface(JNIEnv* env, jobject thiz) static jobject Image_createSurfacePlane(JNIEnv* env, jobject thiz, int idx, int readerFormat) { int rowStride, pixelStride; + PublicFormat publicReaderFormat = static_cast<PublicFormat>(readerFormat); + ALOGV("%s: buffer index: %d", __FUNCTION__, idx); CpuConsumer::LockedBuffer* buffer = Image_getLockedBuffer(env, thiz); @@ -893,10 +888,11 @@ static jobject Image_createSurfacePlane(JNIEnv* env, jobject thiz, int idx, int jniThrowException(env, "java/lang/IllegalStateException", "Image was released"); } - readerFormat = Image_getPixelFormat(env, readerFormat); + int halReaderFormat = android_view_Surface_mapPublicFormatToHalFormat( + publicReaderFormat); - rowStride = Image_imageGetRowStride(env, buffer, idx, readerFormat); - pixelStride = Image_imageGetPixelStride(env, buffer, idx, readerFormat); + rowStride = Image_imageGetRowStride(env, buffer, idx, halReaderFormat); + pixelStride = Image_imageGetPixelStride(env, buffer, idx, halReaderFormat); jobject surfPlaneObj = env->NewObject(gSurfacePlaneClassInfo.clazz, gSurfacePlaneClassInfo.ctor, thiz, idx, rowStride, pixelStride); @@ -909,6 +905,7 @@ static jobject Image_getByteBuffer(JNIEnv* env, jobject thiz, int idx, int reade uint8_t *base = NULL; uint32_t size = 0; jobject byteBuffer; + PublicFormat readerPublicFormat = static_cast<PublicFormat>(readerFormat); ALOGV("%s: buffer index: %d", __FUNCTION__, idx); @@ -918,10 +915,11 @@ static jobject Image_getByteBuffer(JNIEnv* env, jobject thiz, int idx, int reade jniThrowException(env, "java/lang/IllegalStateException", "Image was released"); } - readerFormat = Image_getPixelFormat(env, readerFormat); + int readerHalFormat = android_view_Surface_mapPublicFormatToHalFormat( + readerPublicFormat); // Create byteBuffer from native buffer - Image_getLockedBufferInfo(env, buffer, idx, &base, &size, readerFormat); + Image_getLockedBufferInfo(env, buffer, idx, &base, &size, readerHalFormat); if (size > static_cast<uint32_t>(INT32_MAX)) { // Byte buffer have 'int capacity', so check the range diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp index 1cf589d15670..16758d05327a 100644 --- a/media/jni/android_media_MediaCodec.cpp +++ b/media/jni/android_media_MediaCodec.cpp @@ -215,7 +215,7 @@ void JMediaCodec::deleteJavaObjects(JNIEnv *env) { status_t JMediaCodec::setCallback(jobject cb) { if (cb != NULL) { if (mCallbackNotification == NULL) { - mCallbackNotification = new AMessage(kWhatCallbackNotify, id()); + mCallbackNotification = new AMessage(kWhatCallbackNotify, this); } } else { mCallbackNotification.clear(); diff --git a/media/jni/android_media_MediaMetadataRetriever.cpp b/media/jni/android_media_MediaMetadataRetriever.cpp index 93138fae1588..2f6bbf4cc9b4 100644 --- a/media/jni/android_media_MediaMetadataRetriever.cpp +++ b/media/jni/android_media_MediaMetadataRetriever.cpp @@ -40,7 +40,6 @@ using namespace android; struct fields_t { jfieldID context; jclass bitmapClazz; // Must be a global ref - jfieldID nativeBitmap; jmethodID createBitmapMethod; jmethodID createScaledBitmapMethod; jclass configClazz; // Must be a global ref @@ -282,8 +281,7 @@ static jobject android_media_MediaMetadataRetriever_getFrameAtTime(JNIEnv *env, return NULL; } - SkBitmap *bitmap = - (SkBitmap *) env->GetLongField(jBitmap, fields.nativeBitmap); + SkBitmap *bitmap = GraphicsJNI::getSkBitmap(env, jBitmap); bitmap->lockPixels(); rotate((uint16_t*)bitmap->getPixels(), @@ -421,10 +419,6 @@ static void android_media_MediaMetadataRetriever_native_init(JNIEnv *env) if (fields.createScaledBitmapMethod == NULL) { return; } - fields.nativeBitmap = env->GetFieldID(fields.bitmapClazz, "mNativeBitmap", "J"); - if (fields.nativeBitmap == NULL) { - return; - } jclass configClazz = env->FindClass("android/graphics/Bitmap$Config"); if (configClazz == NULL) { diff --git a/media/jni/soundpool/SoundPool.cpp b/media/jni/soundpool/SoundPool.cpp index dfe2844222a1..1205f9d3a2f2 100644 --- a/media/jni/soundpool/SoundPool.cpp +++ b/media/jni/soundpool/SoundPool.cpp @@ -256,7 +256,7 @@ int SoundPool::play(int sampleID, float leftVolume, float rightVolume, dump(); // allocate a channel - channel = allocateChannel_l(priority, sampleID); + channel = allocateChannel_l(priority); // no channel allocated - return 0 if (!channel) { @@ -271,25 +271,13 @@ int SoundPool::play(int sampleID, float leftVolume, float rightVolume, return channelID; } -SoundChannel* SoundPool::allocateChannel_l(int priority, int sampleID) +SoundChannel* SoundPool::allocateChannel_l(int priority) { List<SoundChannel*>::iterator iter; SoundChannel* channel = NULL; - // check if channel for given sampleID still available + // allocate a channel if (!mChannels.empty()) { - for (iter = mChannels.begin(); iter != mChannels.end(); ++iter) { - if (sampleID == (*iter)->getPrevSampleID() && (*iter)->state() == SoundChannel::IDLE) { - channel = *iter; - mChannels.erase(iter); - ALOGV("Allocated recycled channel for same sampleID"); - break; - } - } - } - - // allocate any channel - if (!channel && !mChannels.empty()) { iter = mChannels.begin(); if (priority >= (*iter)->priority()) { channel = *iter; @@ -638,7 +626,7 @@ status_t Sample::doLoad() goto error; } - if ((numChannels < 1) || (numChannels > 2)) { + if ((numChannels < 1) || (numChannels > 8)) { ALOGE("Sample channel count (%d) out of range", numChannels); status = BAD_VALUE; goto error; @@ -660,7 +648,6 @@ error: void SoundChannel::init(SoundPool* soundPool) { mSoundPool = soundPool; - mPrevSampleID = -1; } // call with sound pool lock held @@ -669,7 +656,7 @@ void SoundChannel::play(const sp<Sample>& sample, int nextChannelID, float leftV { sp<AudioTrack> oldTrack; sp<AudioTrack> newTrack; - status_t status = NO_ERROR; + status_t status; { // scope for the lock Mutex::Autolock lock(&mLock); @@ -702,8 +689,10 @@ void SoundChannel::play(const sp<Sample>& sample, int nextChannelID, float leftV size_t frameCount = 0; if (loop) { - frameCount = sample->size()/numChannels/ - ((sample->format() == AUDIO_FORMAT_PCM_16_BIT) ? sizeof(int16_t) : sizeof(uint8_t)); + const audio_format_t format = sample->format(); + const size_t frameSize = audio_is_linear_pcm(format) + ? numChannels * audio_bytes_per_sample(format) : 1; + frameCount = sample->size() / frameSize; } #ifndef USE_SHARED_MEM_BUFFER @@ -714,43 +703,38 @@ void SoundChannel::play(const sp<Sample>& sample, int nextChannelID, float leftV } #endif - if (!mAudioTrack.get() || mPrevSampleID != sample->sampleID()) { - // mToggle toggles each time a track is started on a given channel. - // The toggle is concatenated with the SoundChannel address and passed to AudioTrack - // as callback user data. This enables the detection of callbacks received from the old - // audio track while the new one is being started and avoids processing them with - // wrong audio audio buffer size (mAudioBufferSize) - unsigned long toggle = mToggle ^ 1; - void *userData = (void *)((unsigned long)this | toggle); - audio_channel_mask_t channelMask = audio_channel_out_mask_from_count(numChannels); - - // do not create a new audio track if current track is compatible with sample parameters - #ifdef USE_SHARED_MEM_BUFFER - newTrack = new AudioTrack(streamType, sampleRate, sample->format(), - channelMask, sample->getIMemory(), AUDIO_OUTPUT_FLAG_FAST, callback, userData); - #else - uint32_t bufferFrames = (totalFrames + (kDefaultBufferCount - 1)) / kDefaultBufferCount; - newTrack = new AudioTrack(streamType, sampleRate, sample->format(), - channelMask, frameCount, AUDIO_OUTPUT_FLAG_FAST, callback, userData, - bufferFrames); - #endif - oldTrack = mAudioTrack; - status = newTrack->initCheck(); - if (status != NO_ERROR) { - ALOGE("Error creating AudioTrack"); - goto exit; - } - // From now on, AudioTrack callbacks received with previous toggle value will be ignored. - mToggle = toggle; - mAudioTrack = newTrack; - ALOGV("using new track %p for sample %d", newTrack.get(), sample->sampleID()); - } else { - newTrack = mAudioTrack; - newTrack->setSampleRate(sampleRate); - ALOGV("reusing track %p for sample %d", mAudioTrack.get(), sample->sampleID()); + // mToggle toggles each time a track is started on a given channel. + // The toggle is concatenated with the SoundChannel address and passed to AudioTrack + // as callback user data. This enables the detection of callbacks received from the old + // audio track while the new one is being started and avoids processing them with + // wrong audio audio buffer size (mAudioBufferSize) + unsigned long toggle = mToggle ^ 1; + void *userData = (void *)((unsigned long)this | toggle); + audio_channel_mask_t channelMask = audio_channel_out_mask_from_count(numChannels); + + // do not create a new audio track if current track is compatible with sample parameters +#ifdef USE_SHARED_MEM_BUFFER + newTrack = new AudioTrack(streamType, sampleRate, sample->format(), + channelMask, sample->getIMemory(), AUDIO_OUTPUT_FLAG_FAST, callback, userData); +#else + uint32_t bufferFrames = (totalFrames + (kDefaultBufferCount - 1)) / kDefaultBufferCount; + newTrack = new AudioTrack(streamType, sampleRate, sample->format(), + channelMask, frameCount, AUDIO_OUTPUT_FLAG_FAST, callback, userData, + bufferFrames); +#endif + oldTrack = mAudioTrack; + status = newTrack->initCheck(); + if (status != NO_ERROR) { + ALOGE("Error creating AudioTrack"); + goto exit; } + ALOGV("setVolume %p", newTrack.get()); newTrack->setVolume(leftVolume, rightVolume); newTrack->setLoop(0, frameCount, loop); + + // From now on, AudioTrack callbacks received with previous toggle value will be ignored. + mToggle = toggle; + mAudioTrack = newTrack; mPos = 0; mSample = sample; mChannelID = nextChannelID; @@ -893,7 +877,6 @@ bool SoundChannel::doStop_l() setVolume_l(0, 0); ALOGV("stop"); mAudioTrack->stop(); - mPrevSampleID = mSample->sampleID(); mSample.clear(); mState = IDLE; mPriority = IDLE_PRIORITY; diff --git a/media/jni/soundpool/SoundPool.h b/media/jni/soundpool/SoundPool.h index f520406e8753..d19cd9103222 100644 --- a/media/jni/soundpool/SoundPool.h +++ b/media/jni/soundpool/SoundPool.h @@ -72,8 +72,8 @@ private: volatile int32_t mRefCount; uint16_t mSampleID; uint16_t mSampleRate; - uint8_t mState : 3; - uint8_t mNumChannels : 2; + uint8_t mState; + uint8_t mNumChannels; audio_format_t mFormat; int mFd; int64_t mOffset; @@ -136,7 +136,6 @@ public: void nextEvent(); int nextChannelID() { return mNextEvent.channelID(); } void dump(); - int getPrevSampleID(void) { return mPrevSampleID; } private: static void callback(int event, void* user, void *info); @@ -153,7 +152,6 @@ private: int mAudioBufferSize; unsigned long mToggle; bool mAutoPaused; - int mPrevSampleID; }; // application object for managing a pool of sounds @@ -195,7 +193,7 @@ private: sp<Sample> findSample(int sampleID) { return mSamples.valueFor(sampleID); } SoundChannel* findChannel (int channelID); SoundChannel* findNextChannel (int channelID); - SoundChannel* allocateChannel_l(int priority, int sampleID); + SoundChannel* allocateChannel_l(int priority); void moveToFront_l(SoundChannel* channel); void notify(SoundPoolEvent event); void dump(); diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java index 3cae19db269d..d756d058e0f1 100644 --- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java @@ -161,8 +161,7 @@ public class CameraDeviceBinderTest extends AndroidTestCase { assertFalse(request.isEmpty()); assertFalse(metadata.isEmpty()); if (needStream) { - int streamId = mCameraUser.createStream(/* ignored */10, /* ignored */20, - /* ignored */30, mSurface); + int streamId = mCameraUser.createStream(mSurface); assertEquals(0, streamId); request.addTarget(mSurface); } @@ -235,12 +234,11 @@ public class CameraDeviceBinderTest extends AndroidTestCase { @SmallTest public void testCreateStream() throws Exception { - int streamId = mCameraUser.createStream(/* ignored */10, /* ignored */20, /* ignored */30, - mSurface); + int streamId = mCameraUser.createStream(mSurface); assertEquals(0, streamId); assertEquals(CameraBinderTestUtils.ALREADY_EXISTS, - mCameraUser.createStream(/* ignored */0, /* ignored */0, /* ignored */0, mSurface)); + mCameraUser.createStream(mSurface)); assertEquals(CameraBinderTestUtils.NO_ERROR, mCameraUser.deleteStream(streamId)); } @@ -257,20 +255,18 @@ public class CameraDeviceBinderTest extends AndroidTestCase { public void testCreateStreamTwo() throws Exception { // Create first stream - int streamId = mCameraUser.createStream(/* ignored */0, /* ignored */0, /* ignored */0, - mSurface); + int streamId = mCameraUser.createStream(mSurface); assertEquals(0, streamId); assertEquals(CameraBinderTestUtils.ALREADY_EXISTS, - mCameraUser.createStream(/* ignored */0, /* ignored */0, /* ignored */0, mSurface)); + mCameraUser.createStream(mSurface)); // Create second stream with a different surface. SurfaceTexture surfaceTexture = new SurfaceTexture(/* ignored */0); surfaceTexture.setDefaultBufferSize(640, 480); Surface surface2 = new Surface(surfaceTexture); - int streamId2 = mCameraUser.createStream(/* ignored */0, /* ignored */0, /* ignored */0, - surface2); + int streamId2 = mCameraUser.createStream(surface2); assertEquals(1, streamId2); // Clean up streams diff --git a/native/graphics/jni/bitmap.cpp b/native/graphics/jni/bitmap.cpp index ea32edc9955e..ddb01a0671ed 100644 --- a/native/graphics/jni/bitmap.cpp +++ b/native/graphics/jni/bitmap.cpp @@ -27,7 +27,7 @@ int AndroidBitmap_getInfo(JNIEnv* env, jobject jbitmap, return ANDROID_BITMAP_RESULT_BAD_PARAMETER; } - SkBitmap* bm = GraphicsJNI::getNativeBitmap(env, jbitmap); + SkBitmap* bm = GraphicsJNI::getSkBitmap(env, jbitmap); if (NULL == bm) { return ANDROID_BITMAP_RESULT_JNI_EXCEPTION; } @@ -64,7 +64,7 @@ int AndroidBitmap_lockPixels(JNIEnv* env, jobject jbitmap, void** addrPtr) { return ANDROID_BITMAP_RESULT_BAD_PARAMETER; } - SkBitmap* bm = GraphicsJNI::getNativeBitmap(env, jbitmap); + SkBitmap* bm = GraphicsJNI::getSkBitmap(env, jbitmap); if (NULL == bm) { return ANDROID_BITMAP_RESULT_JNI_EXCEPTION; } @@ -87,7 +87,7 @@ int AndroidBitmap_unlockPixels(JNIEnv* env, jobject jbitmap) { return ANDROID_BITMAP_RESULT_BAD_PARAMETER; } - SkBitmap* bm = GraphicsJNI::getNativeBitmap(env, jbitmap); + SkBitmap* bm = GraphicsJNI::getSkBitmap(env, jbitmap); if (NULL == bm) { return ANDROID_BITMAP_RESULT_JNI_EXCEPTION; } diff --git a/opengl/java/android/opengl/GLUtils.java b/opengl/java/android/opengl/GLUtils.java index a9d33dd23827..4d890c9438a3 100644 --- a/opengl/java/android/opengl/GLUtils.java +++ b/opengl/java/android/opengl/GLUtils.java @@ -29,14 +29,6 @@ import javax.microedition.khronos.egl.EGL11; public final class GLUtils { - /* - * We use a class initializer to allow the native code to cache some - * field offsets. - */ - static { - nativeClassInit(); - } - private GLUtils() { } @@ -275,8 +267,6 @@ public final class GLUtils { */ native public static void setTracingLevel(int level); - native private static void nativeClassInit(); - native private static int native_getInternalFormat(Bitmap bitmap); native private static int native_getType(Bitmap bitmap); native private static int native_texImage2D(int target, int level, int internalformat, diff --git a/packages/Keyguard/res/values-pl/strings.xml b/packages/Keyguard/res/values-pl/strings.xml index b47b76e3869f..40cd5e63750a 100644 --- a/packages/Keyguard/res/values-pl/strings.xml +++ b/packages/Keyguard/res/values-pl/strings.xml @@ -79,7 +79,7 @@ <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Zbyt wiele prób narysowania wzoru"</string> <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Po raz <xliff:g id="NUMBER_0">%d</xliff:g> wpisałeś nieprawidłowy PIN. \n\nSpróbuj ponownie za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string> <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Po raz <xliff:g id="NUMBER_0">%d</xliff:g> wpisałeś nieprawidłowe hasło. \n\nSpróbuj ponownie za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string> - <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Po raz <xliff:g id="NUMBER_0">%d</xliff:g> narysowałeś nieprawidłowy wzór odblokowania. \n\nSpróbuj ponownie za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string> + <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"<xliff:g id="NUMBER_0">%d</xliff:g> razy narysowałeś nieprawidłowy wzór odblokowania. \n\nSpróbuj ponownie za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string> <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Próbowałeś <xliff:g id="NUMBER_0">%d</xliff:g> razy nieprawidłowo odblokować tablet. Po kolejnych <xliff:g id="NUMBER_1">%d</xliff:g> nieudanych próbach tablet zostanie zresetowany, co spowoduje skasowanie z niego wszystkich danych."</string> <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Próbowałeś <xliff:g id="NUMBER_0">%d</xliff:g> razy nieprawidłowo odblokować telefon. Po kolejnych <xliff:g id="NUMBER_1">%d</xliff:g> nieudanych próbach telefon zostanie zresetowany, co spowoduje skasowanie z niego wszystkich danych."</string> <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="258925501999698032">"Próbowałeś <xliff:g id="NUMBER">%d</xliff:g> razy nieprawidłowo odblokować tablet. Zostanie on zresetowany, co spowoduje skasowanie z niego wszystkich danych."</string> diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java index a66fc226f369..396fe4f34f41 100644 --- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java +++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java @@ -371,24 +371,11 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { } private boolean isTrustDisabled(int userId) { - final DevicePolicyManager dpm = - (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE); - if (dpm != null) { - // TODO once UI is finalized - final boolean disabledByGlobalActions = false; - final boolean disabledBySettings = false; - - // Don't allow trust agent if device is secured with a SIM PIN. This is here - // mainly because there's no other way to prompt the user to enter their SIM PIN - // once they get past the keyguard screen. - final boolean disabledBySimPin = isSimPinSecure(); - - final boolean disabledByDpm = (dpm.getKeyguardDisabledFeatures(null, userId) - & DevicePolicyManager.KEYGUARD_DISABLE_TRUST_AGENTS) != 0; - return disabledByDpm || disabledByGlobalActions || disabledBySettings - || disabledBySimPin; - } - return false; + // Don't allow trust agent if device is secured with a SIM PIN. This is here + // mainly because there's no other way to prompt the user to enter their SIM PIN + // once they get past the keyguard screen. + final boolean disabledBySimPin = isSimPinSecure(); + return disabledBySimPin; } private boolean isFingerprintDisabled(int userId) { diff --git a/packages/SystemUI/res/layout/remote_input.xml b/packages/SystemUI/res/layout/remote_input.xml new file mode 100644 index 000000000000..8ca5634ea9f1 --- /dev/null +++ b/packages/SystemUI/res/layout/remote_input.xml @@ -0,0 +1,46 @@ +<?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 --> +<com.android.systemui.statusbar.policy.RemoteInputView + xmlns:android="http://schemas.android.com/apk/res/android" + android:theme="@style/systemui_theme_light" + android:layout_height="match_parent" + android:layout_width="match_parent" + android:paddingStart="4dp" + android:paddingEnd="2dp" + android:paddingBottom="4dp" + android:paddingTop="2dp"> + + <view class="com.android.systemui.statusbar.policy.RemoteInputView$RemoteEditText" + android:id="@+id/remote_input_text" + android:layout_height="wrap_content" + android:layout_width="match_parent" + android:singleLine="true" + android:imeOptions="actionSend" /> + + <ProgressBar + android:id="@+id/remote_input_progress" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_gravity="bottom" + android:visibility="invisible" + android:indeterminate="true" + style="?android:attr/progressBarStyleHorizontal" /> + +</com.android.systemui.statusbar.policy.RemoteInputView> diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml index 905ccd9ff9df..d69cf29c93dc 100644 --- a/packages/SystemUI/res/values-nl/strings.xml +++ b/packages/SystemUI/res/values-nl/strings.xml @@ -44,7 +44,7 @@ <string name="battery_saver_start_action" msgid="5576697451677486320">"Accubesparing inschakelen"</string> <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Instellingen"</string> <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wifi"</string> - <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Vliegmodus"</string> + <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Vliegtuigmodus"</string> <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Scherm automatisch draaien"</string> <string name="status_bar_settings_mute_label" msgid="554682549917429396">"DEMPEN"</string> <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"AUTO"</string> @@ -144,7 +144,7 @@ <string name="accessibility_data_connection_wifi" msgid="2324496756590645221">"Wifi"</string> <string name="accessibility_no_sim" msgid="8274017118472455155">"Geen simkaart."</string> <string name="accessibility_bluetooth_tether" msgid="4102784498140271969">"Bluetooth-tethering."</string> - <string name="accessibility_airplane_mode" msgid="834748999790763092">"Vliegmodus."</string> + <string name="accessibility_airplane_mode" msgid="834748999790763092">"Vliegtuigmodus."</string> <string name="accessibility_battery_level" msgid="7451474187113371965">"Accu: <xliff:g id="NUMBER">%d</xliff:g> procent."</string> <string name="accessibility_settings_button" msgid="799583911231893380">"Systeeminstellingen."</string> <string name="accessibility_notifications_button" msgid="4498000369779421892">"Meldingen."</string> @@ -172,10 +172,10 @@ <string name="accessibility_quick_settings_wifi_changed_on" msgid="6440117170789528622">"Wifi ingeschakeld."</string> <string name="accessibility_quick_settings_mobile" msgid="4876806564086241341">"Mobiel <xliff:g id="SIGNAL">%1$s</xliff:g>. <xliff:g id="TYPE">%2$s</xliff:g>. <xliff:g id="NETWORK">%3$s</xliff:g>."</string> <string name="accessibility_quick_settings_battery" msgid="1480931583381408972">"Accu: <xliff:g id="STATE">%s</xliff:g>."</string> - <string name="accessibility_quick_settings_airplane_off" msgid="7786329360056634412">"Vliegmodus uit."</string> - <string name="accessibility_quick_settings_airplane_on" msgid="6406141469157599296">"Vliegmodus aan."</string> - <string name="accessibility_quick_settings_airplane_changed_off" msgid="66846307818850664">"Vliegmodus uitgeschakeld."</string> - <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Vliegmodus ingeschakeld."</string> + <string name="accessibility_quick_settings_airplane_off" msgid="7786329360056634412">"Vliegtuigmodus uit."</string> + <string name="accessibility_quick_settings_airplane_on" msgid="6406141469157599296">"Vliegtuigmodus aan."</string> + <string name="accessibility_quick_settings_airplane_changed_off" msgid="66846307818850664">"Vliegtuigmodus uitgeschakeld."</string> + <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Vliegtuigmodus ingeschakeld."</string> <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"Niet storen aan, alleen prioriteit."</string> <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"Niet storen aan, geen onderbrekingen."</string> <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"Niet storen uit."</string> @@ -228,7 +228,7 @@ <string name="dessert_case" msgid="1295161776223959221">"Dessertshowcase"</string> <string name="start_dreams" msgid="7219575858348719790">"Dagdroom"</string> <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string> - <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Vliegmodus"</string> + <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Vliegtuigmodus"</string> <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Niet storen"</string> <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Alleen prioriteit"</string> <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"Geen onderbrekingen"</string> diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml index 3b912bb470aa..07e0ef796ae2 100644 --- a/packages/SystemUI/res/values-sv/strings.xml +++ b/packages/SystemUI/res/values-sv/strings.xml @@ -303,7 +303,7 @@ <string name="description_direction_left" msgid="7207478719805562165">"Dra åt vänster för <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ."</string> <string name="zen_no_interruptions_with_warning" msgid="4396898053735625287">"Inga avbrott. Inte ens alarm."</string> <string name="zen_no_interruptions" msgid="7970973750143632592">"Inga avbrott"</string> - <string name="zen_important_interruptions" msgid="3477041776609757628">"Endast prioriterade avbrott"</string> + <string name="zen_important_interruptions" msgid="3477041776609757628">"Endast prioriterade samtal och aviseringar"</string> <string name="zen_alarm_information_time" msgid="5235772206174372272">"Nästa alarm är kl. <xliff:g id="ALARM_TIME">%s</xliff:g>"</string> <string name="zen_alarm_information_day_time" msgid="8422733576255047893">"Nästa alarm är <xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g>"</string> <string name="zen_alarm_warning" msgid="6873910860111498041">"Alarmet kommer inte att höras kl. <xliff:g id="ALARM_TIME">%s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml index 94f77c6d5246..07fcb8217c87 100644 --- a/packages/SystemUI/res/values/styles.xml +++ b/packages/SystemUI/res/values/styles.xml @@ -211,6 +211,11 @@ <item name="android:colorControlActivated">@color/system_accent_color</item> </style> + <style name="systemui_theme_light" parent="@android:style/Theme.DeviceDefault.Light"> + <item name="android:colorPrimary">@color/system_primary_color</item> + <item name="android:colorControlActivated">@color/system_accent_color</item> + </style> + <style name="Theme.SystemUI.Dialog" parent="@android:style/Theme.DeviceDefault.Light.Dialog"> <item name="android:colorPrimary">@color/system_primary_color</item> <item name="android:colorControlActivated">@color/system_accent_color</item> diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java b/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java index 925d17ef4ae6..84544ffa3bf8 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java +++ b/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java @@ -33,7 +33,7 @@ public class Utilities { private static Method sPropertyMethod; static { try { - Class<?> c = Class.forName("android.view.GLES20Canvas"); + Class<?> c = Class.forName("android.view.DisplayListCanvas"); sPropertyMethod = c.getDeclaredMethod("setProperty", String.class, String.class); if (!sPropertyMethod.isAccessible()) sPropertyMethod.setAccessible(true); } catch (ClassNotFoundException e) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java index 3a812cc071e5..8347a22652c6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java @@ -24,6 +24,7 @@ import android.app.ActivityManagerNative; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; +import android.app.RemoteInput; import android.app.TaskStackBuilder; import android.app.admin.DevicePolicyManager; import android.content.BroadcastReceiver; @@ -49,6 +50,7 @@ import android.os.Message; import android.os.PowerManager; import android.os.RemoteException; import android.os.ServiceManager; +import android.os.SystemProperties; import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; @@ -59,6 +61,7 @@ import android.service.notification.NotificationListenerService.RankingMap; import android.service.notification.StatusBarNotification; import android.text.TextUtils; import android.util.Log; +import android.util.Slog; import android.util.SparseArray; import android.util.SparseBooleanArray; import android.view.Display; @@ -97,6 +100,7 @@ import com.android.systemui.statusbar.phone.NavigationBarView; import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; import com.android.systemui.statusbar.policy.HeadsUpNotificationView; import com.android.systemui.statusbar.policy.PreviewInflater; +import com.android.systemui.statusbar.policy.RemoteInputView; import com.android.systemui.statusbar.stack.NotificationStackScrollLayout; import java.util.ArrayList; @@ -116,6 +120,9 @@ public abstract class BaseStatusBar extends SystemUI implements // STOPSHIP disable once we resolve b/18102199 private static final boolean NOTIFICATION_CLICK_DEBUG = true; + public static final boolean ENABLE_REMOTE_INPUT = + Build.IS_DEBUGGABLE && SystemProperties.getBoolean("debug.enable_remote_input", false); + protected static final int MSG_SHOW_RECENT_APPS = 1019; protected static final int MSG_HIDE_RECENT_APPS = 1020; protected static final int MSG_TOGGLE_RECENTS_APPS = 1021; @@ -409,6 +416,7 @@ public abstract class BaseStatusBar extends SystemUI implements @Override public void run() { for (StatusBarNotification sbn : notifications) { + processForRemoteInput(sbn.getNotification()); addNotification(sbn, currentRanking); } } @@ -423,6 +431,7 @@ public abstract class BaseStatusBar extends SystemUI implements mHandler.post(new Runnable() { @Override public void run() { + processForRemoteInput(sbn.getNotification()); Notification n = sbn.getNotification(); boolean isUpdate = mNotificationData.get(sbn.getKey()) != null || isHeadsUp(sbn.getKey()); @@ -1356,6 +1365,9 @@ public abstract class BaseStatusBar extends SystemUI implements (NotificationContentView) row.findViewById(R.id.expandedPublic); row.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS); + if (ENABLE_REMOTE_INPUT) { + row.setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS); + } PendingIntent contentIntent = sbn.getNotification().contentIntent; if (contentIntent != null) { @@ -1517,9 +1529,103 @@ public abstract class BaseStatusBar extends SystemUI implements } row.setUserLocked(userLocked); row.setStatusBarNotification(entry.notification); + applyRemoteInput(entry); return true; } + /** + * Adds RemoteInput actions from the WearableExtender; to be removed once more apps support this + * via first-class API. + * + * TODO: Remove once enough apps specify remote inputs on their own. + */ + private void processForRemoteInput(Notification n) { + if (!ENABLE_REMOTE_INPUT) return; + + if (n.extras != null && n.extras.containsKey("android.wearable.EXTENSIONS") && + (n.actions == null || n.actions.length == 0)) { + Notification.Action viableAction = null; + Notification.WearableExtender we = new Notification.WearableExtender(n); + + List<Notification.Action> actions = we.getActions(); + final int numActions = actions.size(); + + for (int i = 0; i < numActions; i++) { + Notification.Action action = actions.get(i); + RemoteInput[] remoteInputs = action.getRemoteInputs(); + for (RemoteInput ri : action.getRemoteInputs()) { + if (ri.getAllowFreeFormInput()) { + viableAction = action; + break; + } + } + if (viableAction != null) { + break; + } + } + + if (viableAction != null) { + Notification stripped = n.clone(); + Notification.Builder.stripForDelivery(stripped); + stripped.actions = new Notification.Action[] { viableAction }; + stripped.extras.putBoolean("android.rebuild.contentView", true); + stripped.contentView = null; + stripped.extras.putBoolean("android.rebuild.bigView", true); + stripped.bigContentView = null; + + // Don't create the HUN input view for now because input doesn't work there yet. + // TODO: Enable once HUNs can take remote input correctly. + if (false) { + stripped.extras.putBoolean("android.rebuild.hudView", true); + stripped.headsUpContentView = null; + } + + Notification rebuilt = Notification.Builder.rebuild(mContext, stripped); + + n.actions = rebuilt.actions; + n.bigContentView = rebuilt.bigContentView; + n.headsUpContentView = rebuilt.headsUpContentView; + n.publicVersion = rebuilt.publicVersion; + } + } + } + + private void applyRemoteInput(final Entry entry) { + if (!ENABLE_REMOTE_INPUT) return; + + RemoteInput remoteInput = null; + + // See if the notification has exactly one action and this action allows free-form input + // TODO: relax restrictions once we support more than one remote input action. + Notification.Action[] actions = entry.notification.getNotification().actions; + if (actions != null && actions.length == 1) { + if (actions[0].getRemoteInputs() != null) { + for (RemoteInput ri : actions[0].getRemoteInputs()) { + if (ri.getAllowFreeFormInput()) { + remoteInput = ri; + break; + } + } + } + } + + // See if we have somewhere to put that remote input + ViewGroup actionContainer = null; + if (remoteInput != null && entry.expandedBig != null) { + View actionContainerCandidate = entry.expandedBig + .findViewById(com.android.internal.R.id.actions); + if (actionContainerCandidate instanceof ViewGroup) { + actionContainer = (ViewGroup) actionContainerCandidate; + } + } + + if (actionContainer != null) { + actionContainer.removeAllViews(); + actionContainer.addView( + RemoteInputView.inflate(mContext, actionContainer, actions[0], remoteInput)); + } + } + public NotificationClicker makeClicker(PendingIntent intent, String notificationKey) { return new NotificationClicker(intent, notificationKey); } @@ -2036,6 +2142,8 @@ public abstract class BaseStatusBar extends SystemUI implements entry.row.setStatusBarNotification(notification); entry.row.notifyContentUpdated(); entry.row.resetHeight(); + + applyRemoteInput(entry); } protected void notifyHeadsUpScreenOn(boolean screenOn) { @@ -2150,6 +2258,14 @@ public abstract class BaseStatusBar extends SystemUI implements } public boolean isKeyguardSecure() { + if (mStatusBarKeyguardViewManager == null) { + // startKeyguard() hasn't been called yet, so we don't know. + // Make sure anything that needs to know isKeyguardSecure() checks and re-checks this + // value onVisibilityChanged(). + Slog.w(TAG, "isKeyguardSecure() called before startKeyguard(), returning false", + new Throwable()); + return false; + } return mStatusBarKeyguardViewManager.isSecure(); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java index acf7af91f897..0c21b2044643 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java @@ -220,6 +220,7 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL public void setPhoneStatusBar(PhoneStatusBar phoneStatusBar) { mPhoneStatusBar = phoneStatusBar; + updateCameraVisibility(); // in case onFinishInflate() was called too early } private Intent getCameraIntent() { @@ -231,6 +232,10 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL } private void updateCameraVisibility() { + if (mCameraImageView == null) { + // Things are not set up yet; reply hazy, ask again later + return; + } ResolveInfo resolved = mContext.getPackageManager().resolveActivityAsUser(getCameraIntent(), PackageManager.MATCH_DEFAULT_ONLY, mLockPatternUtils.getCurrentUser()); @@ -253,7 +258,7 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL private boolean isCameraDisabledByDpm() { final DevicePolicyManager dpm = (DevicePolicyManager) getContext().getSystemService(Context.DEVICE_POLICY_SERVICE); - if (dpm != null) { + if (dpm != null && mPhoneStatusBar != null) { try { final int userId = ActivityManagerNative.getDefault().getCurrentUser().id; final int disabledFlags = dpm.getKeyguardDisabledFeatures(null, userId); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java index eba7d9ffb948..63bbf973dcd6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java @@ -115,7 +115,8 @@ public class StatusBarWindowManager { private void applyFocusableFlag(State state) { if (state.isKeyguardShowingAndNotOccluded() && state.keyguardNeedsInput - && state.bouncerShowing) { + && state.bouncerShowing + || BaseStatusBar.ENABLE_REMOTE_INPUT && state.statusBarExpanded) { mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; } else if (state.isKeyguardShowingAndNotOccluded() || state.statusBarFocusable) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java new file mode 100644 index 000000000000..7d721c22415b --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java @@ -0,0 +1,191 @@ +/* + * 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.statusbar.policy; + +import com.android.systemui.R; + +import android.annotation.NonNull; +import android.app.Notification; +import android.app.PendingIntent; +import android.app.RemoteInput; +import android.content.Context; +import android.content.Intent; +import android.graphics.drawable.Drawable; +import android.os.Bundle; +import android.util.AttributeSet; +import android.util.Log; +import android.view.KeyEvent; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.inputmethod.EditorInfo; +import android.view.inputmethod.InputMethodManager; +import android.widget.EditText; +import android.widget.FrameLayout; +import android.widget.ProgressBar; +import android.widget.TextView; + +/** + * Host for the remote input. + */ +public class RemoteInputView extends FrameLayout implements View.OnClickListener { + + private static final String TAG = "RemoteInput"; + + private RemoteEditText mEditText; + private ProgressBar mProgressBar; + private PendingIntent mPendingIntent; + private RemoteInput mRemoteInput; + private Notification.Action mAction; + + public RemoteInputView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + @Override + protected void onFinishInflate() { + super.onFinishInflate(); + + mProgressBar = (ProgressBar) findViewById(R.id.remote_input_progress); + + mEditText = (RemoteEditText) getChildAt(0); + mEditText.setOnEditorActionListener(new TextView.OnEditorActionListener() { + @Override + public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { + + // Check if this was the result of hitting the enter key + final boolean isSoftImeEvent = event == null + && (actionId == EditorInfo.IME_ACTION_DONE + || actionId == EditorInfo.IME_ACTION_NEXT + || actionId == EditorInfo.IME_ACTION_SEND); + final boolean isKeyboardEnterKey = event != null + && KeyEvent.isConfirmKey(event.getKeyCode()) + && event.getAction() == KeyEvent.ACTION_DOWN; + + if (isSoftImeEvent || isKeyboardEnterKey) { + sendRemoteInput(); + return true; + } + return false; + } + }); + mEditText.setOnClickListener(this); + mEditText.setInnerFocusable(false); + } + + private void sendRemoteInput() { + Bundle results = new Bundle(); + results.putString(mRemoteInput.getResultKey(), mEditText.getText().toString()); + Intent fillInIntent = new Intent(); + RemoteInput.addResultsToIntent(mAction.getRemoteInputs(), fillInIntent, + results); + + mEditText.setEnabled(false); + mProgressBar.setVisibility(VISIBLE); + + try { + mPendingIntent.send(mContext, 0, fillInIntent); + } catch (PendingIntent.CanceledException e) { + Log.i(TAG, "Unable to send remote input result", e); + } + } + + public static RemoteInputView inflate(Context context, ViewGroup root, + Notification.Action action, RemoteInput remoteInput) { + RemoteInputView v = (RemoteInputView) + LayoutInflater.from(context).inflate(R.layout.remote_input, root, false); + + v.mEditText.setHint(action.title); + v.mPendingIntent = action.actionIntent; + v.mRemoteInput = remoteInput; + v.mAction = action; + + return v; + } + + @Override + public void onClick(View v) { + if (v == mEditText) { + if (!mEditText.isFocusable()) { + mEditText.setInnerFocusable(true); + InputMethodManager imm = InputMethodManager.getInstance(); + if (imm != null) { + imm.viewClicked(mEditText); + imm.showSoftInput(mEditText, 0); + } + } + } + } + + /** + * An EditText that changes appearance based on whether it's focusable and becomes + * un-focusable whenever the user navigates away from it or it becomes invisible. + */ + public static class RemoteEditText extends EditText { + + private final Drawable mBackground; + + public RemoteEditText(Context context, AttributeSet attrs) { + super(context, attrs); + mBackground = getBackground(); + } + + private void defocusIfNeeded() { + if (isFocusable() && isEnabled()) { + setInnerFocusable(false); + } + } + + @Override + protected void onVisibilityChanged(View changedView, int visibility) { + super.onVisibilityChanged(changedView, visibility); + + if (!isShown()) { + defocusIfNeeded(); + } + } + + @Override + protected void onFocusLost() { + super.onFocusLost(); + defocusIfNeeded(); + } + + @Override + public boolean onKeyPreIme(int keyCode, KeyEvent event) { + if (keyCode == KeyEvent.KEYCODE_BACK) { + defocusIfNeeded(); + } + return super.onKeyPreIme(keyCode, event); + } + + + void setInnerFocusable(boolean focusable) { + setFocusableInTouchMode(focusable); + setFocusable(focusable); + setCursorVisible(focusable); + + if (focusable) { + requestFocus(); + setBackground(mBackground); + } else { + setBackground(null); + } + + } + } +} diff --git a/rs/java/android/renderscript/Allocation.java b/rs/java/android/renderscript/Allocation.java index ede63a92b385..c6afa2cc3920 100644 --- a/rs/java/android/renderscript/Allocation.java +++ b/rs/java/android/renderscript/Allocation.java @@ -60,6 +60,7 @@ public class Allocation extends BaseObj { boolean mReadAllowed = true; boolean mWriteAllowed = true; + boolean mAutoPadding = false; int mSelectedX; int mSelectedY; int mSelectedZ; @@ -270,6 +271,17 @@ public class Allocation extends BaseObj { } /** + * @hide + * Enable/Disable AutoPadding for Vec3 elements. + * + * @param useAutoPadding True: enable AutoPadding; flase: disable AutoPadding + * + */ + public void setAutoPadding(boolean useAutoPadding) { + mAutoPadding = useAutoPadding; + } + + /** * Get the size of the Allocation in bytes. * * @return size of the Allocation in bytes. @@ -785,6 +797,7 @@ public class Allocation extends BaseObj { copy1DRangeFromUnchecked(xoff, count, data); } + /** * This is only intended to be used by auto-generated code reflected from * the RenderScript script files. @@ -804,20 +817,6 @@ public class Allocation extends BaseObj { * * @param xoff * @param yoff - * @param component_number - * @param fp - */ - public void setFromFieldPacker(int xoff, int yoff, int component_number, FieldPacker fp) { - setFromFieldPacker(xoff, yoff, 0, component_number, fp); - } - - /** - * @hide - * This is only intended to be used by auto-generated code reflected from - * the RenderScript script files. - * - * @param xoff - * @param yoff * @param zoff * @param component_number * @param fp @@ -851,7 +850,7 @@ public class Allocation extends BaseObj { component_number, data, data_length); } - private void data1DChecks(int off, int count, int len, int dataSize) { + private void data1DChecks(int off, int count, int len, int dataSize, boolean usePadding) { mRS.validate(); if(off < 0) { throw new RSIllegalArgumentException("Offset must be >= 0."); @@ -863,8 +862,14 @@ public class Allocation extends BaseObj { throw new RSIllegalArgumentException("Overflow, Available count " + mCurrentCount + ", got " + count + " at offset " + off + "."); } - if(len < dataSize) { - throw new RSIllegalArgumentException("Array too small for allocation type."); + if(usePadding) { + if(len < dataSize / 4 * 3) { + throw new RSIllegalArgumentException("Array too small for allocation type."); + } + } else { + if(len < dataSize) { + throw new RSIllegalArgumentException("Array too small for allocation type."); + } } } @@ -886,8 +891,14 @@ public class Allocation extends BaseObj { Element.DataType dt, int arrayLen) { Trace.traceBegin(RenderScript.TRACE_TAG, "copy1DRangeFromUnchecked"); final int dataSize = mType.mElement.getBytesSize() * count; - data1DChecks(off, count, arrayLen * dt.mSize, dataSize); - mRS.nAllocationData1D(getIDSafe(), off, mSelectedLOD, count, array, dataSize, dt); + // AutoPadding for Vec3 Element + boolean usePadding = false; + if (mAutoPadding && (mType.getElement().getVectorSize() == 3)) { + usePadding = true; + } + data1DChecks(off, count, arrayLen * dt.mSize, dataSize, usePadding); + mRS.nAllocationData1D(getIDSafe(), off, mSelectedLOD, count, array, dataSize, dt, + mType.mElement.mType.mSize, usePadding); Trace.traceEnd(RenderScript.TRACE_TAG); } @@ -1064,8 +1075,24 @@ public class Allocation extends BaseObj { Trace.traceBegin(RenderScript.TRACE_TAG, "copy2DRangeFromUnchecked"); mRS.validate(); validate2DRange(xoff, yoff, w, h); + final int dataSize = mType.mElement.getBytesSize() * w * h; + // AutoPadding for Vec3 Element + boolean usePadding = false; + int sizeBytes = arrayLen * dt.mSize; + if (mAutoPadding && (mType.getElement().getVectorSize() == 3)) { + if (dataSize / 4 * 3 > sizeBytes) { + throw new RSIllegalArgumentException("Array too small for allocation type."); + } + usePadding = true; + sizeBytes = dataSize; + } else { + if (dataSize > sizeBytes) { + throw new RSIllegalArgumentException("Array too small for allocation type."); + } + } mRS.nAllocationData2D(getIDSafe(), xoff, yoff, mSelectedLOD, mSelectedFace.mID, w, h, - array, arrayLen * dt.mSize, dt); + array, sizeBytes, dt, + mType.mElement.mType.mSize, usePadding); Trace.traceEnd(RenderScript.TRACE_TAG); } @@ -1226,8 +1253,24 @@ public class Allocation extends BaseObj { Trace.traceBegin(RenderScript.TRACE_TAG, "copy3DRangeFromUnchecked"); mRS.validate(); validate3DRange(xoff, yoff, zoff, w, h, d); + final int dataSize = mType.mElement.getBytesSize() * w * h * d; + // AutoPadding for Vec3 Element + boolean usePadding = false; + int sizeBytes = arrayLen * dt.mSize; + if (mAutoPadding && (mType.getElement().getVectorSize() == 3)) { + if (dataSize / 4 * 3 > sizeBytes) { + throw new RSIllegalArgumentException("Array too small for allocation type."); + } + usePadding = true; + sizeBytes = dataSize; + } else { + if (dataSize > sizeBytes) { + throw new RSIllegalArgumentException("Array too small for allocation type."); + } + } mRS.nAllocationData3D(getIDSafe(), xoff, yoff, zoff, mSelectedLOD, w, h, d, - array, arrayLen * dt.mSize, dt); + array, sizeBytes, dt, + mType.mElement.mType.mSize, usePadding); Trace.traceEnd(RenderScript.TRACE_TAG); } @@ -1242,7 +1285,7 @@ public class Allocation extends BaseObj { * @param w Width of the region to update * @param h Height of the region to update * @param d Depth of the region to update - * @param data to be placed into the allocation + * @param array to be placed into the allocation */ public void copy3DRangeFrom(int xoff, int yoff, int zoff, int w, int h, int d, Object array) { Trace.traceBegin(RenderScript.TRACE_TAG, "copy3DRangeFrom"); @@ -1300,7 +1343,11 @@ public class Allocation extends BaseObj { "Size of output array cannot be smaller than size of allocation."); } mRS.validate(); - mRS.nAllocationRead(getID(mRS), array, dt); + boolean usePadding = false; + if (mAutoPadding && (mType.getElement().getVectorSize() == 3)) { + usePadding = true; + } + mRS.nAllocationRead(getID(mRS), array, dt, mType.mElement.mType.mSize, usePadding); Trace.traceEnd(RenderScript.TRACE_TAG); } @@ -1367,35 +1414,8 @@ public class Allocation extends BaseObj { /** * @hide - * Copy subelement from the Allocation into an object array. - * This is intended to be used with user defined structs - * - * @param xoff - * @param component_number - * @param array - */ - public void copyElementTo(int xoff, int component_number, Object array) { - copyElementTo(xoff, 0, 0, component_number, array); - } - - /** - * @hide - * Copy subelement from the Allocation into an object array. - * This is intended to be used with user defined structs - * - * @param xoff - * @param yoff - * @param component_number - * @param array - */ - public void copyElementTo(int xoff, int yoff, int component_number, Object array) { - copyElementTo(xoff, yoff, 0, component_number, array); - } - - /** - * @hide - * Copy subelement from the Allocation into an object array. - * This is intended to be used with user defined structs + * This is only intended to be used by auto-generated code reflected from + * the RenderScript script files and should not be used by developers. * * @param xoff * @param yoff @@ -1403,8 +1423,7 @@ public class Allocation extends BaseObj { * @param component_number * @param array */ - public void copyElementTo(int xoff, int yoff, int zoff, int component_number, Object array) { - Trace.traceBegin(RenderScript.TRACE_TAG, "copyElementTo"); + public void copyToFieldPacker(int xoff, int yoff, int zoff, int component_number, FieldPacker fp) { mRS.validate(); if (component_number >= mType.mElement.mElements.length) { throw new RSIllegalArgumentException("Component_number " + component_number + " out of range."); @@ -1419,19 +1438,18 @@ public class Allocation extends BaseObj { throw new RSIllegalArgumentException("Offset z must be >= 0."); } - Element.DataType dt = validateObjectIsPrimitiveArray(array, false); - int array_size = java.lang.reflect.Array.getLength(array) * dt.mSize; + final byte[] data = fp.getData(); + int data_length = fp.getPos(); int eSize = mType.mElement.mElements[component_number].getBytesSize(); eSize *= mType.mElement.mArraySizes[component_number]; - if (array_size < eSize) { - throw new RSIllegalArgumentException("Array Size (bytes)" + array_size + - " is smaller than component size " + eSize + "."); + if (data_length != eSize) { + throw new RSIllegalArgumentException("Field packer sizelength " + data_length + + " does not match component size " + eSize + "."); } mRS.nAllocationElementRead(getIDSafe(), xoff, yoff, zoff, mSelectedLOD, - component_number, array, eSize, dt); - Trace.traceEnd(RenderScript.TRACE_TAG); + component_number, data, data_length); } /** * Resize a 1D allocation. The contents of the allocation are preserved. @@ -1469,8 +1487,14 @@ public class Allocation extends BaseObj { Element.DataType dt, int arrayLen) { Trace.traceBegin(RenderScript.TRACE_TAG, "copy1DRangeToUnchecked"); final int dataSize = mType.mElement.getBytesSize() * count; - data1DChecks(off, count, arrayLen * dt.mSize, dataSize); - mRS.nAllocationRead1D(getIDSafe(), off, mSelectedLOD, count, array, dataSize, dt); + // AutoPadding for Vec3 Element + boolean usePadding = false; + if (mAutoPadding && (mType.getElement().getVectorSize() == 3)) { + usePadding = true; + } + data1DChecks(off, count, arrayLen * dt.mSize, dataSize, usePadding); + mRS.nAllocationRead1D(getIDSafe(), off, mSelectedLOD, count, array, dataSize, dt, + mType.mElement.mType.mSize, usePadding); Trace.traceEnd(RenderScript.TRACE_TAG); } @@ -1624,8 +1648,23 @@ public class Allocation extends BaseObj { Trace.traceBegin(RenderScript.TRACE_TAG, "copy2DRangeToUnchecked"); mRS.validate(); validate2DRange(xoff, yoff, w, h); + final int dataSize = mType.mElement.getBytesSize() * w * h; + // AutoPadding for Vec3 Element + boolean usePadding = false; + int sizeBytes = arrayLen * dt.mSize; + if (mAutoPadding && (mType.getElement().getVectorSize() == 3)) { + if (dataSize / 4 * 3 > sizeBytes) { + throw new RSIllegalArgumentException("Array too small for allocation type."); + } + usePadding = true; + sizeBytes = dataSize; + } else { + if (dataSize > sizeBytes) { + throw new RSIllegalArgumentException("Array too small for allocation type."); + } + } mRS.nAllocationRead2D(getIDSafe(), xoff, yoff, mSelectedLOD, mSelectedFace.mID, w, h, - array, arrayLen * dt.mSize, dt); + array, sizeBytes, dt, mType.mElement.mType.mSize, usePadding); Trace.traceEnd(RenderScript.TRACE_TAG); } @@ -1653,7 +1692,7 @@ public class Allocation extends BaseObj { * @param yoff Y offset of the region to copy in this Allocation * @param w Width of the region to copy * @param h Height of the region to copy - * @param array Dest Array to be copied into + * @param data Dest Array to be copied into */ public void copy2DRangeTo(int xoff, int yoff, int w, int h, byte[] data) { validateIsInt8(); @@ -1669,7 +1708,7 @@ public class Allocation extends BaseObj { * @param yoff Y offset of the region to copy in this Allocation * @param w Width of the region to copy * @param h Height of the region to copy - * @param array Dest Array to be copied into + * @param data Dest Array to be copied into */ public void copy2DRangeTo(int xoff, int yoff, int w, int h, short[] data) { validateIsInt16(); @@ -1685,7 +1724,7 @@ public class Allocation extends BaseObj { * @param yoff Y offset of the region to copy in this Allocation * @param w Width of the region to copy * @param h Height of the region to copy - * @param array Dest Array to be copied into + * @param data Dest Array to be copied into */ public void copy2DRangeTo(int xoff, int yoff, int w, int h, int[] data) { validateIsInt32(); @@ -1701,7 +1740,7 @@ public class Allocation extends BaseObj { * @param yoff Y offset of the region to copy in this Allocation * @param w Width of the region to copy * @param h Height of the region to copy - * @param array Dest Array to be copied into + * @param data Dest Array to be copied into */ public void copy2DRangeTo(int xoff, int yoff, int w, int h, float[] data) { validateIsFloat32(); @@ -1719,8 +1758,23 @@ public class Allocation extends BaseObj { Trace.traceBegin(RenderScript.TRACE_TAG, "copy3DRangeToUnchecked"); mRS.validate(); validate3DRange(xoff, yoff, zoff, w, h, d); + final int dataSize = mType.mElement.getBytesSize() * w * h * d; + // AutoPadding for Vec3 Element + boolean usePadding = false; + int sizeBytes = arrayLen * dt.mSize; + if (mAutoPadding && (mType.getElement().getVectorSize() == 3)) { + if (dataSize / 4 * 3 > sizeBytes) { + throw new RSIllegalArgumentException("Array too small for allocation type."); + } + usePadding = true; + sizeBytes = dataSize; + } else { + if (dataSize > sizeBytes) { + throw new RSIllegalArgumentException("Array too small for allocation type."); + } + } mRS.nAllocationRead3D(getIDSafe(), xoff, yoff, zoff, mSelectedLOD, w, h, d, - array, arrayLen * dt.mSize, dt); + array, sizeBytes, dt, mType.mElement.mType.mSize, usePadding); Trace.traceEnd(RenderScript.TRACE_TAG); } diff --git a/rs/java/android/renderscript/RenderScript.java b/rs/java/android/renderscript/RenderScript.java index 1f3b63e864fa..3d6d07fa08b4 100644 --- a/rs/java/android/renderscript/RenderScript.java +++ b/rs/java/android/renderscript/RenderScript.java @@ -484,10 +484,12 @@ public class RenderScript { } - native void rsnAllocationData1D(long con, long id, int off, int mip, int count, Object d, int sizeBytes, int dt); - synchronized void nAllocationData1D(long id, int off, int mip, int count, Object d, int sizeBytes, Element.DataType dt) { + native void rsnAllocationData1D(long con, long id, int off, int mip, int count, Object d, int sizeBytes, int dt, + int mSize, boolean usePadding); + synchronized void nAllocationData1D(long id, int off, int mip, int count, Object d, int sizeBytes, Element.DataType dt, + int mSize, boolean usePadding) { validate(); - rsnAllocationData1D(mContext, id, off, mip, count, d, sizeBytes, dt.mID); + rsnAllocationData1D(mContext, id, off, mip, count, d, sizeBytes, dt.mID, mSize, usePadding); } native void rsnAllocationElementData(long con,long id, int xoff, int yoff, int zoff, int mip, int compIdx, byte[] d, int sizeBytes); @@ -517,11 +519,13 @@ public class RenderScript { } native void rsnAllocationData2D(long con, long id, int xoff, int yoff, int mip, int face, - int w, int h, Object d, int sizeBytes, int dt); + int w, int h, Object d, int sizeBytes, int dt, + int mSize, boolean usePadding); synchronized void nAllocationData2D(long id, int xoff, int yoff, int mip, int face, - int w, int h, Object d, int sizeBytes, Element.DataType dt) { + int w, int h, Object d, int sizeBytes, Element.DataType dt, + int mSize, boolean usePadding) { validate(); - rsnAllocationData2D(mContext, id, xoff, yoff, mip, face, w, h, d, sizeBytes, dt.mID); + rsnAllocationData2D(mContext, id, xoff, yoff, mip, face, w, h, d, sizeBytes, dt.mID, mSize, usePadding); } native void rsnAllocationData2D(long con, long id, int xoff, int yoff, int mip, int face, Bitmap b); @@ -549,50 +553,56 @@ public class RenderScript { } native void rsnAllocationData3D(long con, long id, int xoff, int yoff, int zoff, int mip, - int w, int h, int depth, Object d, int sizeBytes, int dt); + int w, int h, int depth, Object d, int sizeBytes, int dt, + int mSize, boolean usePadding); synchronized void nAllocationData3D(long id, int xoff, int yoff, int zoff, int mip, - int w, int h, int depth, Object d, int sizeBytes, Element.DataType dt) { + int w, int h, int depth, Object d, int sizeBytes, Element.DataType dt, + int mSize, boolean usePadding) { validate(); - rsnAllocationData3D(mContext, id, xoff, yoff, zoff, mip, w, h, depth, d, sizeBytes, dt.mID); + rsnAllocationData3D(mContext, id, xoff, yoff, zoff, mip, w, h, depth, d, sizeBytes, + dt.mID, mSize, usePadding); } - native void rsnAllocationRead(long con, long id, Object d, int dt); - synchronized void nAllocationRead(long id, Object d, Element.DataType dt) { + native void rsnAllocationRead(long con, long id, Object d, int dt, int mSize, boolean usePadding); + synchronized void nAllocationRead(long id, Object d, Element.DataType dt, int mSize, boolean usePadding) { validate(); - rsnAllocationRead(mContext, id, d, dt.mID); + rsnAllocationRead(mContext, id, d, dt.mID, mSize, usePadding); } native void rsnAllocationRead1D(long con, long id, int off, int mip, int count, Object d, - int sizeBytes, int dt); + int sizeBytes, int dt, int mSize, boolean usePadding); synchronized void nAllocationRead1D(long id, int off, int mip, int count, Object d, - int sizeBytes, Element.DataType dt) { + int sizeBytes, Element.DataType dt, int mSize, boolean usePadding) { validate(); - rsnAllocationRead1D(mContext, id, off, mip, count, d, sizeBytes, dt.mID); + rsnAllocationRead1D(mContext, id, off, mip, count, d, sizeBytes, dt.mID, mSize, usePadding); } native void rsnAllocationElementRead(long con,long id, int xoff, int yoff, int zoff, - int mip, int compIdx, Object d, int sizeBytes, int dt); + int mip, int compIdx, byte[] d, int sizeBytes); synchronized void nAllocationElementRead(long id, int xoff, int yoff, int zoff, - int mip, int compIdx, Object d, int sizeBytes, - Element.DataType dt) { + int mip, int compIdx, byte[] d, int sizeBytes) { validate(); - rsnAllocationElementRead(mContext, id, xoff, yoff, zoff, mip, compIdx, d, sizeBytes, dt.mID); + rsnAllocationElementRead(mContext, id, xoff, yoff, zoff, mip, compIdx, d, sizeBytes); } native void rsnAllocationRead2D(long con, long id, int xoff, int yoff, int mip, int face, - int w, int h, Object d, int sizeBytes, int dt); + int w, int h, Object d, int sizeBytes, int dt, + int mSize, boolean usePadding); synchronized void nAllocationRead2D(long id, int xoff, int yoff, int mip, int face, - int w, int h, Object d, int sizeBytes, Element.DataType dt) { + int w, int h, Object d, int sizeBytes, Element.DataType dt, + int mSize, boolean usePadding) { validate(); - rsnAllocationRead2D(mContext, id, xoff, yoff, mip, face, w, h, d, sizeBytes, dt.mID); + rsnAllocationRead2D(mContext, id, xoff, yoff, mip, face, w, h, d, sizeBytes, dt.mID, mSize, usePadding); } native void rsnAllocationRead3D(long con, long id, int xoff, int yoff, int zoff, int mip, - int w, int h, int depth, Object d, int sizeBytes, int dt); + int w, int h, int depth, Object d, int sizeBytes, int dt, + int mSize, boolean usePadding); synchronized void nAllocationRead3D(long id, int xoff, int yoff, int zoff, int mip, - int w, int h, int depth, Object d, int sizeBytes, Element.DataType dt) { + int w, int h, int depth, Object d, int sizeBytes, Element.DataType dt, + int mSize, boolean usePadding) { validate(); - rsnAllocationRead3D(mContext, id, xoff, yoff, zoff, mip, w, h, depth, d, sizeBytes, dt.mID); + rsnAllocationRead3D(mContext, id, xoff, yoff, zoff, mip, w, h, depth, d, sizeBytes, dt.mID, mSize, usePadding); } native long rsnAllocationGetType(long con, long id); diff --git a/rs/jni/Android.mk b/rs/jni/Android.mk index f1f0bfccc0b5..94f08595746c 100644 --- a/rs/jni/Android.mk +++ b/rs/jni/Android.mk @@ -14,7 +14,8 @@ LOCAL_SHARED_LIBRARIES := \ libskia \ libutils \ libui \ - libgui + libgui \ + libjnigraphics LOCAL_STATIC_LIBRARIES := @@ -23,6 +24,7 @@ rs_generated_include_dir := $(call intermediates-dir-for,SHARED_LIBRARIES,libRS, LOCAL_C_INCLUDES += \ $(JNI_H_INCLUDE) \ frameworks/rs \ + frameworks/base/core/jni \ $(rs_generated_include_dir) LOCAL_CFLAGS += -Wno-unused-parameter -std=c++11 diff --git a/rs/jni/android_renderscript_RenderScript.cpp b/rs/jni/android_renderscript_RenderScript.cpp index a145166f79a7..848350794236 100644 --- a/rs/jni/android_renderscript_RenderScript.cpp +++ b/rs/jni/android_renderscript_RenderScript.cpp @@ -24,8 +24,6 @@ #include <utils/misc.h> #include <inttypes.h> -#include <SkBitmap.h> - #include <androidfw/Asset.h> #include <androidfw/AssetManager.h> #include <androidfw/ResourceTypes.h> @@ -35,6 +33,7 @@ #include "android_runtime/AndroidRuntime.h" #include "android_runtime/android_view_Surface.h" #include "android_runtime/android_util_AssetManager.h" +#include "android/graphics/GraphicsJNI.h" #include <rs.h> #include <rsEnv.h> @@ -54,10 +53,12 @@ void UNUSED(T... t) {} #define PER_ARRAY_TYPE(flag, fnc, readonly, ...) { \ jint len = 0; \ void *ptr = nullptr; \ + void *srcPtr = nullptr; \ size_t typeBytes = 0; \ jint relFlag = 0; \ if (readonly) { \ /* The on-release mode should only be JNI_ABORT for read-only accesses. */ \ + /* readonly = true, also indicates we are copying to the allocation . */ \ relFlag = JNI_ABORT; \ } \ switch(dataType) { \ @@ -65,14 +66,50 @@ void UNUSED(T... t) {} len = _env->GetArrayLength((jfloatArray)data); \ ptr = _env->GetFloatArrayElements((jfloatArray)data, flag); \ typeBytes = 4; \ - fnc(__VA_ARGS__); \ + if (usePadding) { \ + srcPtr = ptr; \ + len = len / 3 * 4; \ + if (count == 0) { \ + count = len / 4; \ + } \ + ptr = malloc (len * typeBytes); \ + if (readonly) { \ + copyWithPadding(ptr, srcPtr, mSize, count); \ + fnc(__VA_ARGS__); \ + } else { \ + fnc(__VA_ARGS__); \ + copyWithUnPadding(srcPtr, ptr, mSize, count); \ + } \ + free(ptr); \ + ptr = srcPtr; \ + } else { \ + fnc(__VA_ARGS__); \ + } \ _env->ReleaseFloatArrayElements((jfloatArray)data, (jfloat *)ptr, relFlag); \ return; \ case RS_TYPE_FLOAT_64: \ len = _env->GetArrayLength((jdoubleArray)data); \ ptr = _env->GetDoubleArrayElements((jdoubleArray)data, flag); \ typeBytes = 8; \ - fnc(__VA_ARGS__); \ + if (usePadding) { \ + srcPtr = ptr; \ + len = len / 3 * 4; \ + if (count == 0) { \ + count = len / 4; \ + } \ + ptr = malloc (len * typeBytes); \ + if (readonly) { \ + copyWithPadding(ptr, srcPtr, mSize, count); \ + fnc(__VA_ARGS__); \ + } else { \ + fnc(__VA_ARGS__); \ + copyWithUnPadding(srcPtr, ptr, mSize, count); \ + } \ + free(ptr); \ + ptr = srcPtr; \ + } else { \ + fnc(__VA_ARGS__); \ + } \ _env->ReleaseDoubleArrayElements((jdoubleArray)data, (jdouble *)ptr, relFlag); \ return; \ case RS_TYPE_SIGNED_8: \ @@ -80,7 +117,25 @@ void UNUSED(T... t) {} len = _env->GetArrayLength((jbyteArray)data); \ ptr = _env->GetByteArrayElements((jbyteArray)data, flag); \ typeBytes = 1; \ - fnc(__VA_ARGS__); \ + if (usePadding) { \ + srcPtr = ptr; \ + len = len / 3 * 4; \ + if (count == 0) { \ + count = len / 4; \ + } \ + ptr = malloc (len * typeBytes); \ + if (readonly) { \ + copyWithPadding(ptr, srcPtr, mSize, count); \ + fnc(__VA_ARGS__); \ + } else { \ + fnc(__VA_ARGS__); \ + copyWithUnPadding(srcPtr, ptr, mSize, count); \ + } \ + free(ptr); \ + ptr = srcPtr; \ + } else { \ + fnc(__VA_ARGS__); \ + } \ _env->ReleaseByteArrayElements((jbyteArray)data, (jbyte*)ptr, relFlag); \ return; \ case RS_TYPE_SIGNED_16: \ @@ -88,7 +143,25 @@ void UNUSED(T... t) {} len = _env->GetArrayLength((jshortArray)data); \ ptr = _env->GetShortArrayElements((jshortArray)data, flag); \ typeBytes = 2; \ - fnc(__VA_ARGS__); \ + if (usePadding) { \ + srcPtr = ptr; \ + len = len / 3 * 4; \ + if (count == 0) { \ + count = len / 4; \ + } \ + ptr = malloc (len * typeBytes); \ + if (readonly) { \ + copyWithPadding(ptr, srcPtr, mSize, count); \ + fnc(__VA_ARGS__); \ + } else { \ + fnc(__VA_ARGS__); \ + copyWithUnPadding(srcPtr, ptr, mSize, count); \ + } \ + free(ptr); \ + ptr = srcPtr; \ + } else { \ + fnc(__VA_ARGS__); \ + } \ _env->ReleaseShortArrayElements((jshortArray)data, (jshort *)ptr, relFlag); \ return; \ case RS_TYPE_SIGNED_32: \ @@ -96,7 +169,25 @@ void UNUSED(T... t) {} len = _env->GetArrayLength((jintArray)data); \ ptr = _env->GetIntArrayElements((jintArray)data, flag); \ typeBytes = 4; \ - fnc(__VA_ARGS__); \ + if (usePadding) { \ + srcPtr = ptr; \ + len = len / 3 * 4; \ + if (count == 0) { \ + count = len / 4; \ + } \ + ptr = malloc (len * typeBytes); \ + if (readonly) { \ + copyWithPadding(ptr, srcPtr, mSize, count); \ + fnc(__VA_ARGS__); \ + } else { \ + fnc(__VA_ARGS__); \ + copyWithUnPadding(srcPtr, ptr, mSize, count); \ + } \ + free(ptr); \ + ptr = srcPtr; \ + } else { \ + fnc(__VA_ARGS__); \ + } \ _env->ReleaseIntArrayElements((jintArray)data, (jint *)ptr, relFlag); \ return; \ case RS_TYPE_SIGNED_64: \ @@ -104,13 +195,31 @@ void UNUSED(T... t) {} len = _env->GetArrayLength((jlongArray)data); \ ptr = _env->GetLongArrayElements((jlongArray)data, flag); \ typeBytes = 8; \ - fnc(__VA_ARGS__); \ + if (usePadding) { \ + srcPtr = ptr; \ + len = len / 3 * 4; \ + if (count == 0) { \ + count = len / 4; \ + } \ + ptr = malloc (len * typeBytes); \ + if (readonly) { \ + copyWithPadding(ptr, srcPtr, mSize, count); \ + fnc(__VA_ARGS__); \ + } else { \ + fnc(__VA_ARGS__); \ + copyWithUnPadding(srcPtr, ptr, mSize, count); \ + } \ + free(ptr); \ + ptr = srcPtr; \ + } else { \ + fnc(__VA_ARGS__); \ + } \ _env->ReleaseLongArrayElements((jlongArray)data, (jlong *)ptr, relFlag); \ return; \ default: \ break; \ } \ - UNUSED(len, ptr, typeBytes, relFlag); \ + UNUSED(len, ptr, srcPtr, typeBytes, relFlag); \ } @@ -172,18 +281,40 @@ private: // --------------------------------------------------------------------------- static jfieldID gContextId = 0; -static jfieldID gNativeBitmapID = 0; static void _nInit(JNIEnv *_env, jclass _this) { gContextId = _env->GetFieldID(_this, "mContext", "J"); - - jclass bitmapClass = _env->FindClass("android/graphics/Bitmap"); - gNativeBitmapID = _env->GetFieldID(bitmapClass, "mNativeBitmap", "J"); } // --------------------------------------------------------------------------- +static void copyWithPadding(void* ptr, void* srcPtr, int mSize, int count) { + int sizeBytesPad = mSize * 4; + int sizeBytes = mSize * 3; + uint8_t *dst = static_cast<uint8_t *>(ptr); + uint8_t *src = static_cast<uint8_t *>(srcPtr); + for (int i = 0; i < count; i++) { + memcpy(dst, src, sizeBytes); + dst += sizeBytesPad; + src += sizeBytes; + } +} + +static void copyWithUnPadding(void* ptr, void* srcPtr, int mSize, int count) { + int sizeBytesPad = mSize * 4; + int sizeBytes = mSize * 3; + uint8_t *dst = static_cast<uint8_t *>(ptr); + uint8_t *src = static_cast<uint8_t *>(srcPtr); + for (int i = 0; i < count; i++) { + memcpy(dst, src, sizeBytes); + dst += sizeBytes; + src += sizeBytesPad; + } +} + + +// --------------------------------------------------------------------------- static void nContextFinish(JNIEnv *_env, jobject _this, jlong con) { @@ -934,7 +1065,7 @@ nAllocationCreateFromBitmap(JNIEnv *_env, jobject _this, jlong con, jlong type, jobject jbitmap, jint usage) { SkBitmap const * nativeBitmap = - (SkBitmap const *)_env->GetLongField(jbitmap, gNativeBitmapID); + GraphicsJNI::getSkBitmap(_env, jbitmap); const SkBitmap& bitmap(*nativeBitmap); bitmap.lockPixels(); @@ -951,7 +1082,7 @@ nAllocationCreateBitmapBackedAllocation(JNIEnv *_env, jobject _this, jlong con, jint mip, jobject jbitmap, jint usage) { SkBitmap const * nativeBitmap = - (SkBitmap const *)_env->GetLongField(jbitmap, gNativeBitmapID); + GraphicsJNI::getSkBitmap(_env, jbitmap); const SkBitmap& bitmap(*nativeBitmap); bitmap.lockPixels(); @@ -968,7 +1099,7 @@ nAllocationCubeCreateFromBitmap(JNIEnv *_env, jobject _this, jlong con, jlong ty jobject jbitmap, jint usage) { SkBitmap const * nativeBitmap = - (SkBitmap const *)_env->GetLongField(jbitmap, gNativeBitmapID); + GraphicsJNI::getSkBitmap(_env, jbitmap); const SkBitmap& bitmap(*nativeBitmap); bitmap.lockPixels(); @@ -984,7 +1115,7 @@ static void nAllocationCopyFromBitmap(JNIEnv *_env, jobject _this, jlong con, jlong alloc, jobject jbitmap) { SkBitmap const * nativeBitmap = - (SkBitmap const *)_env->GetLongField(jbitmap, gNativeBitmapID); + GraphicsJNI::getSkBitmap(_env, jbitmap); const SkBitmap& bitmap(*nativeBitmap); int w = bitmap.width(); int h = bitmap.height(); @@ -1001,7 +1132,7 @@ static void nAllocationCopyToBitmap(JNIEnv *_env, jobject _this, jlong con, jlong alloc, jobject jbitmap) { SkBitmap const * nativeBitmap = - (SkBitmap const *)_env->GetLongField(jbitmap, gNativeBitmapID); + GraphicsJNI::getSkBitmap(_env, jbitmap); const SkBitmap& bitmap(*nativeBitmap); bitmap.lockPixels(); @@ -1014,7 +1145,8 @@ nAllocationCopyToBitmap(JNIEnv *_env, jobject _this, jlong con, jlong alloc, job // Copies from the Java object data into the Allocation pointed to by _alloc. static void nAllocationData1D(JNIEnv *_env, jobject _this, jlong con, jlong _alloc, jint offset, jint lod, - jint count, jobject data, jint sizeBytes, jint dataType) + jint count, jobject data, jint sizeBytes, jint dataType, jint mSize, + jboolean usePadding) { RsAllocation *alloc = (RsAllocation *)_alloc; if (kLogApi) { @@ -1022,8 +1154,8 @@ nAllocationData1D(JNIEnv *_env, jobject _this, jlong con, jlong _alloc, jint off "dataType(%i)", (RsContext)con, (RsAllocation)alloc, offset, count, sizeBytes, dataType); } - PER_ARRAY_TYPE(nullptr, rsAllocation1DData, true, (RsContext)con, alloc, offset, lod, count, - ptr, sizeBytes); + PER_ARRAY_TYPE(nullptr, rsAllocation1DData, true, + (RsContext)con, alloc, offset, lod, count, ptr, sizeBytes); } static void @@ -1048,7 +1180,8 @@ nAllocationElementData(JNIEnv *_env, jobject _this, jlong con, jlong alloc, // Copies from the Java object data into the Allocation pointed to by _alloc. static void nAllocationData2D(JNIEnv *_env, jobject _this, jlong con, jlong _alloc, jint xoff, jint yoff, jint lod, jint _face, - jint w, jint h, jobject data, jint sizeBytes, jint dataType) + jint w, jint h, jobject data, jint sizeBytes, jint dataType, jint mSize, + jboolean usePadding) { RsAllocation *alloc = (RsAllocation *)_alloc; RsAllocationCubemapFace face = (RsAllocationCubemapFace)_face; @@ -1056,7 +1189,9 @@ nAllocationData2D(JNIEnv *_env, jobject _this, jlong con, jlong _alloc, jint xof ALOGD("nAllocation2DData, con(%p), adapter(%p), xoff(%i), yoff(%i), w(%i), h(%i), len(%i) " "type(%i)", (RsContext)con, alloc, xoff, yoff, w, h, sizeBytes, dataType); } - PER_ARRAY_TYPE(nullptr, rsAllocation2DData, true, (RsContext)con, alloc, xoff, yoff, lod, face, w, h, ptr, sizeBytes, 0); + int count = w * h; + PER_ARRAY_TYPE(nullptr, rsAllocation2DData, true, + (RsContext)con, alloc, xoff, yoff, lod, face, w, h, ptr, sizeBytes, 0); } // Copies from the Allocation pointed to by srcAlloc into the Allocation @@ -1090,7 +1225,8 @@ nAllocationData2D_alloc(JNIEnv *_env, jobject _this, jlong con, // Copies from the Java object data into the Allocation pointed to by _alloc. static void nAllocationData3D(JNIEnv *_env, jobject _this, jlong con, jlong _alloc, jint xoff, jint yoff, jint zoff, jint lod, - jint w, jint h, jint d, jobject data, int sizeBytes, int dataType) + jint w, jint h, jint d, jobject data, jint sizeBytes, jint dataType, + jint mSize, jboolean usePadding) { RsAllocation *alloc = (RsAllocation *)_alloc; if (kLogApi) { @@ -1098,7 +1234,9 @@ nAllocationData3D(JNIEnv *_env, jobject _this, jlong con, jlong _alloc, jint xof " h(%i), d(%i), sizeBytes(%i)", (RsContext)con, (RsAllocation)alloc, xoff, yoff, zoff, lod, w, h, d, sizeBytes); } - PER_ARRAY_TYPE(nullptr, rsAllocation3DData, true, (RsContext)con, alloc, xoff, yoff, zoff, lod, w, h, d, ptr, sizeBytes, 0); + int count = w * h * d; + PER_ARRAY_TYPE(nullptr, rsAllocation3DData, true, + (RsContext)con, alloc, xoff, yoff, zoff, lod, w, h, d, ptr, sizeBytes, 0); } // Copies from the Allocation pointed to by srcAlloc into the Allocation @@ -1130,47 +1268,57 @@ nAllocationData3D_alloc(JNIEnv *_env, jobject _this, jlong con, // Copies from the Allocation pointed to by _alloc into the Java object data. static void -nAllocationRead(JNIEnv *_env, jobject _this, jlong con, jlong _alloc, jobject data, int dataType) +nAllocationRead(JNIEnv *_env, jobject _this, jlong con, jlong _alloc, jobject data, jint dataType, + jint mSize, jboolean usePadding) { RsAllocation *alloc = (RsAllocation *)_alloc; if (kLogApi) { ALOGD("nAllocationRead, con(%p), alloc(%p)", (RsContext)con, (RsAllocation)alloc); } - PER_ARRAY_TYPE(0, rsAllocationRead, false, (RsContext)con, alloc, ptr, len * typeBytes); + int count = 0; + PER_ARRAY_TYPE(0, rsAllocationRead, false, + (RsContext)con, alloc, ptr, len * typeBytes); } // Copies from the Allocation pointed to by _alloc into the Java object data. static void nAllocationRead1D(JNIEnv *_env, jobject _this, jlong con, jlong _alloc, jint offset, jint lod, - jint count, jobject data, int sizeBytes, int dataType) + jint count, jobject data, jint sizeBytes, jint dataType, + jint mSize, jboolean usePadding) { RsAllocation *alloc = (RsAllocation *)_alloc; if (kLogApi) { ALOGD("nAllocation1DRead, con(%p), adapter(%p), offset(%i), count(%i), sizeBytes(%i), " "dataType(%i)", (RsContext)con, alloc, offset, count, sizeBytes, dataType); } - PER_ARRAY_TYPE(0, rsAllocation1DRead, false, (RsContext)con, alloc, offset, lod, count, ptr, sizeBytes); + PER_ARRAY_TYPE(0, rsAllocation1DRead, false, + (RsContext)con, alloc, offset, lod, count, ptr, sizeBytes); } // Copies from the Element in the Allocation pointed to by _alloc into the Java array data. static void -nAllocationElementRead(JNIEnv *_env, jobject _this, jlong con, jlong _alloc, +nAllocationElementRead(JNIEnv *_env, jobject _this, jlong con, jlong alloc, jint xoff, jint yoff, jint zoff, - jint lod, jint compIdx, jobject data, jint sizeBytes, int dataType) + jint lod, jint compIdx, jbyteArray data, jint sizeBytes) { - RsAllocation *alloc = (RsAllocation *)_alloc; + jint len = _env->GetArrayLength(data); if (kLogApi) { - ALOGD("nAllocationElementRead, con(%p), alloc(%p), xoff(%i), yoff(%i), zoff(%i), comp(%i), " - "sizeBytes(%i)", (RsContext)con, alloc, xoff, yoff, zoff, compIdx, sizeBytes); + ALOGD("nAllocationElementRead, con(%p), alloc(%p), xoff(%i), yoff(%i), zoff(%i), comp(%i), len(%i), " + "sizeBytes(%i)", (RsContext)con, (RsAllocation)alloc, xoff, yoff, zoff, compIdx, len, + sizeBytes); } - PER_ARRAY_TYPE(0, rsAllocationElementRead, false, (RsContext)con, alloc, - xoff, yoff, zoff, lod, ptr, sizeBytes, compIdx); + jbyte *ptr = _env->GetByteArrayElements(data, nullptr); + rsAllocationElementRead((RsContext)con, (RsAllocation)alloc, + xoff, yoff, zoff, + lod, ptr, sizeBytes, compIdx); + _env->ReleaseByteArrayElements(data, ptr, JNI_ABORT); } // Copies from the Allocation pointed to by _alloc into the Java object data. static void nAllocationRead2D(JNIEnv *_env, jobject _this, jlong con, jlong _alloc, jint xoff, jint yoff, jint lod, jint _face, - jint w, jint h, jobject data, int sizeBytes, int dataType) + jint w, jint h, jobject data, jint sizeBytes, jint dataType, + jint mSize, jboolean usePadding) { RsAllocation *alloc = (RsAllocation *)_alloc; RsAllocationCubemapFace face = (RsAllocationCubemapFace)_face; @@ -1178,13 +1326,16 @@ nAllocationRead2D(JNIEnv *_env, jobject _this, jlong con, jlong _alloc, jint xof ALOGD("nAllocation2DRead, con(%p), adapter(%p), xoff(%i), yoff(%i), w(%i), h(%i), len(%i) " "type(%i)", (RsContext)con, alloc, xoff, yoff, w, h, sizeBytes, dataType); } - PER_ARRAY_TYPE(0, rsAllocation2DRead, false, (RsContext)con, alloc, xoff, yoff, lod, face, w, h, - ptr, sizeBytes, 0); + int count = w * h; + PER_ARRAY_TYPE(0, rsAllocation2DRead, false, + (RsContext)con, alloc, xoff, yoff, lod, face, w, h, ptr, sizeBytes, 0); } + // Copies from the Allocation pointed to by _alloc into the Java object data. static void nAllocationRead3D(JNIEnv *_env, jobject _this, jlong con, jlong _alloc, jint xoff, jint yoff, jint zoff, jint lod, - jint w, jint h, jint d, jobject data, int sizeBytes, int dataType) + jint w, jint h, jint d, jobject data, int sizeBytes, int dataType, + jint mSize, jboolean usePadding) { RsAllocation *alloc = (RsAllocation *)_alloc; if (kLogApi) { @@ -1192,8 +1343,9 @@ nAllocationRead3D(JNIEnv *_env, jobject _this, jlong con, jlong _alloc, jint xof " h(%i), d(%i), sizeBytes(%i)", (RsContext)con, (RsAllocation)alloc, xoff, yoff, zoff, lod, w, h, d, sizeBytes); } - PER_ARRAY_TYPE(0, rsAllocation3DRead, false, (RsContext)con, alloc, xoff, yoff, zoff, lod, w, h, d, - ptr, sizeBytes, 0); + int count = w * h * d; + PER_ARRAY_TYPE(nullptr, rsAllocation3DRead, false, + (RsContext)con, alloc, xoff, yoff, zoff, lod, w, h, d, ptr, sizeBytes, 0); } static jlong @@ -2214,17 +2366,17 @@ static JNINativeMethod methods[] = { {"rsnAllocationSetSurface", "(JJLandroid/view/Surface;)V", (void*)nAllocationSetSurface }, {"rsnAllocationIoSend", "(JJ)V", (void*)nAllocationIoSend }, {"rsnAllocationIoReceive", "(JJ)V", (void*)nAllocationIoReceive }, -{"rsnAllocationData1D", "(JJIIILjava/lang/Object;II)V", (void*)nAllocationData1D }, +{"rsnAllocationData1D", "(JJIIILjava/lang/Object;IIIZ)V", (void*)nAllocationData1D }, {"rsnAllocationElementData", "(JJIIIII[BI)V", (void*)nAllocationElementData }, -{"rsnAllocationData2D", "(JJIIIIIILjava/lang/Object;II)V", (void*)nAllocationData2D }, +{"rsnAllocationData2D", "(JJIIIIIILjava/lang/Object;IIIZ)V", (void*)nAllocationData2D }, {"rsnAllocationData2D", "(JJIIIIIIJIIII)V", (void*)nAllocationData2D_alloc }, -{"rsnAllocationData3D", "(JJIIIIIIILjava/lang/Object;II)V", (void*)nAllocationData3D }, +{"rsnAllocationData3D", "(JJIIIIIIILjava/lang/Object;IIIZ)V", (void*)nAllocationData3D }, {"rsnAllocationData3D", "(JJIIIIIIIJIIII)V", (void*)nAllocationData3D_alloc }, -{"rsnAllocationRead", "(JJLjava/lang/Object;I)V", (void*)nAllocationRead }, -{"rsnAllocationRead1D", "(JJIIILjava/lang/Object;II)V", (void*)nAllocationRead1D }, -{"rsnAllocationElementRead", "(JJIIIIILjava/lang/Object;II)V", (void*)nAllocationElementRead }, -{"rsnAllocationRead2D", "(JJIIIIIILjava/lang/Object;II)V", (void*)nAllocationRead2D }, -{"rsnAllocationRead3D", "(JJIIIIIIILjava/lang/Object;II)V", (void*)nAllocationRead3D }, +{"rsnAllocationRead", "(JJLjava/lang/Object;IIZ)V", (void*)nAllocationRead }, +{"rsnAllocationRead1D", "(JJIIILjava/lang/Object;IIIZ)V", (void*)nAllocationRead1D }, +{"rsnAllocationElementRead", "(JJIIIII[BI)V", (void*)nAllocationElementRead }, +{"rsnAllocationRead2D", "(JJIIIIIILjava/lang/Object;IIIZ)V", (void*)nAllocationRead2D }, +{"rsnAllocationRead3D", "(JJIIIIIIILjava/lang/Object;IIIZ)V", (void*)nAllocationRead3D }, {"rsnAllocationGetType", "(JJ)J", (void*)nAllocationGetType}, {"rsnAllocationResize1D", "(JJI)V", (void*)nAllocationResize1D }, {"rsnAllocationGenerateMipmaps", "(JJ)V", (void*)nAllocationGenerateMipmaps }, diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java index 94d400a76476..265103284452 100644 --- a/services/backup/java/com/android/server/backup/BackupManagerService.java +++ b/services/backup/java/com/android/server/backup/BackupManagerService.java @@ -601,7 +601,7 @@ public class BackupManagerService { return token; } - // High level policy: apps are ineligible for backup if certain conditions apply + // High level policy: apps are generally ineligible for backup if certain conditions apply public static boolean appIsEligibleForBackup(ApplicationInfo app) { // 1. their manifest states android:allowBackup="false" if ((app.flags&ApplicationInfo.FLAG_ALLOW_BACKUP) == 0) { @@ -628,7 +628,7 @@ public class BackupManagerService { return (pkg.applicationInfo.flags & ApplicationInfo.FLAG_FULL_BACKUP_ONLY) != 0; } - // No agent means we do full backups for it + // No agent or fullBackupOnly="true" means we do indeed perform full-data backups for it return true; } @@ -1266,7 +1266,23 @@ public class BackupManagerService { for (int i = 0; i < N; i++) { String pkgName = in.readUTF(); long lastBackup = in.readLong(); - schedule.add(new FullBackupEntry(pkgName, lastBackup)); + try { + PackageInfo pkg = mPackageManager.getPackageInfo(pkgName, 0); + if (appGetsFullBackup(pkg) + && appIsEligibleForBackup(pkg.applicationInfo)) { + schedule.add(new FullBackupEntry(pkgName, lastBackup)); + } else { + if (DEBUG) { + Slog.i(TAG, "Package " + pkgName + + " no longer eligible for full backup"); + } + } + } catch (NameNotFoundException e) { + if (DEBUG) { + Slog.i(TAG, "Package " + pkgName + + " not installed; dropping from full backup"); + } + } } Collections.sort(schedule); } catch (Exception e) { @@ -1289,7 +1305,7 @@ public class BackupManagerService { schedule = new ArrayList<FullBackupEntry>(N); for (int i = 0; i < N; i++) { PackageInfo info = apps.get(i); - if (appGetsFullBackup(info)) { + if (appGetsFullBackup(info) && appIsEligibleForBackup(info.applicationInfo)) { schedule.add(new FullBackupEntry(info.packageName, 0)); } } @@ -1761,11 +1777,11 @@ public class BackupManagerService { addPackageParticipantsLocked(pkgList); } // If they're full-backup candidates, add them there instead + final long now = System.currentTimeMillis(); for (String packageName : pkgList) { try { PackageInfo app = mPackageManager.getPackageInfo(packageName, 0); - long now = System.currentTimeMillis(); - if (appGetsFullBackup(app)) { + if (appGetsFullBackup(app) && appIsEligibleForBackup(app.applicationInfo)) { enqueueFullBackup(packageName, now); scheduleNextFullBackupJob(); } @@ -2462,7 +2478,7 @@ public class BackupManagerService { BackupRequest request = mQueue.get(0); mQueue.remove(0); - Slog.d(TAG, "starting agent for backup of " + request); + Slog.d(TAG, "starting key/value backup of " + request); addBackupTrace("launch agent for " + request.packageName); // Verify that the requested app exists; it might be something that @@ -2473,13 +2489,24 @@ public class BackupManagerService { try { mCurrentPackage = mPackageManager.getPackageInfo(request.packageName, PackageManager.GET_SIGNATURES); - if (mCurrentPackage.applicationInfo.backupAgentName == null) { + if (!appIsEligibleForBackup(mCurrentPackage.applicationInfo)) { // The manifest has changed but we had a stale backup request pending. // This won't happen again because the app won't be requesting further // backups. Slog.i(TAG, "Package " + request.packageName + " no longer supports backup; skipping"); - addBackupTrace("skipping - no agent, completion is noop"); + addBackupTrace("skipping - not eligible, completion is noop"); + executeNextState(BackupState.RUNNING_QUEUE); + return; + } + + if (appGetsFullBackup(mCurrentPackage)) { + // It's possible that this app *formerly* was enqueued for key/value backup, + // but has since been updated and now only supports the full-data path. + // Don't proceed with a key/value backup for it in this case. + Slog.i(TAG, "Package " + request.packageName + + " requests full-data rather than key/value; skipping"); + addBackupTrace("skipping - fullBackupOnly, completion is noop"); executeNextState(BackupState.RUNNING_QUEUE); return; } @@ -9161,6 +9188,8 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF // check whether there is data for it in the current dataset, falling back // to the ancestral dataset if not. long token = getAvailableRestoreToken(packageName); + if (DEBUG) Slog.v(TAG, "restorePackage pkg=" + packageName + + " token=" + Long.toHexString(token)); // If we didn't come up with a place to look -- no ancestral dataset and // the app has never been backed up from this device -- there's nothing diff --git a/services/core/java/com/android/server/AssetAtlasService.java b/services/core/java/com/android/server/AssetAtlasService.java index a2c87b97cc6a..e6dc1c732eb9 100644 --- a/services/core/java/com/android/server/AssetAtlasService.java +++ b/services/core/java/com/android/server/AssetAtlasService.java @@ -291,7 +291,7 @@ public class AssetAtlasService extends IAssetAtlas.Stub { } canvas.drawBitmap(bitmap, 0.0f, 0.0f, null); canvas.restore(); - atlasMap[mapIndex++] = bitmap.mNativeBitmap; + atlasMap[mapIndex++] = bitmap.getSkBitmap(); atlasMap[mapIndex++] = entry.x; atlasMap[mapIndex++] = entry.y; atlasMap[mapIndex++] = entry.rotated ? 1 : 0; diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index 059dde156260..fc95b007cc1e 100755 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -16,6 +16,8 @@ package com.android.server.am; +import static com.android.server.am.ActivityManagerDebugConfig.*; + import java.io.FileDescriptor; import java.io.IOException; import java.io.PrintWriter; @@ -33,6 +35,7 @@ import android.os.Looper; import android.os.SystemProperties; import android.util.ArrayMap; import android.util.ArraySet; + import com.android.internal.app.ProcessStats; import com.android.internal.os.BatteryStatsImpl; import com.android.internal.os.TransferPipe; @@ -67,14 +70,15 @@ import android.util.SparseArray; import android.util.TimeUtils; public final class ActiveServices { - static final boolean DEBUG_SERVICE = ActivityManagerService.DEBUG_SERVICE; - static final boolean DEBUG_SERVICE_EXECUTING = ActivityManagerService.DEBUG_SERVICE_EXECUTING; - static final boolean DEBUG_DELAYED_SERVICE = ActivityManagerService.DEBUG_SERVICE; - static final boolean DEBUG_DELAYED_STARTS = DEBUG_DELAYED_SERVICE; - static final boolean DEBUG_MU = ActivityManagerService.DEBUG_MU; - static final boolean LOG_SERVICE_START_STOP = false; - static final String TAG = ActivityManagerService.TAG; - static final String TAG_MU = ActivityManagerService.TAG_MU; + private static final String TAG = TAG_WITH_CLASS_NAME ? "ActiveServices" : TAG_AM; + private static final String TAG_MU = TAG + POSTFIX_MU; + private static final String TAG_SERVICE = TAG + POSTFIX_SERVICE; + private static final String TAG_SERVICE_EXECUTING = TAG + POSTFIX_SERVICE_EXECUTING; + + private static final boolean DEBUG_DELAYED_SERVICE = DEBUG_SERVICE; + private static final boolean DEBUG_DELAYED_STARTS = DEBUG_DELAYED_SERVICE; + + private static final boolean LOG_SERVICE_START_STOP = false; // How long we wait for a service to finish executing. static final int SERVICE_TIMEOUT = 20*1000; @@ -206,11 +210,12 @@ public final class ActiveServices { void ensureNotStartingBackground(ServiceRecord r) { if (mStartingBackground.remove(r)) { - if (DEBUG_DELAYED_STARTS) Slog.v(TAG, "No longer background starting: " + r); + if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, + "No longer background starting: " + r); rescheduleDelayedStarts(); } if (mDelayedStartList.remove(r)) { - if (DEBUG_DELAYED_STARTS) Slog.v(TAG, "No longer delaying start: " + r); + if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "No longer delaying start: " + r); } } @@ -229,16 +234,17 @@ public final class ActiveServices { while (mDelayedStartList.size() > 0 && mStartingBackground.size() < mMaxStartingBackground) { ServiceRecord r = mDelayedStartList.remove(0); - if (DEBUG_DELAYED_STARTS) Slog.v(TAG, "REM FR DELAY LIST (exec next): " + r); + if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, + "REM FR DELAY LIST (exec next): " + r); if (r.pendingStarts.size() <= 0) { Slog.w(TAG, "**** NO PENDING STARTS! " + r + " startReq=" + r.startRequested + " delayedStop=" + r.delayedStop); } if (DEBUG_DELAYED_SERVICE) { if (mDelayedStartList.size() > 0) { - Slog.v(TAG, "Remaining delayed list:"); + Slog.v(TAG_SERVICE, "Remaining delayed list:"); for (int i=0; i<mDelayedStartList.size(); i++) { - Slog.v(TAG, " #" + i + ": " + mDelayedStartList.get(i)); + Slog.v(TAG_SERVICE, " #" + i + ": " + mDelayedStartList.get(i)); } } } @@ -248,7 +254,7 @@ public final class ActiveServices { if (mStartingBackground.size() > 0) { ServiceRecord next = mStartingBackground.get(0); long when = next.startingBgTimeout > now ? next.startingBgTimeout : now; - if (DEBUG_DELAYED_SERVICE) Slog.v(TAG, "Top bg start is " + next + if (DEBUG_DELAYED_SERVICE) Slog.v(TAG_SERVICE, "Top bg start is " + next + ", can delay others up to " + when); Message msg = obtainMessage(MSG_BG_START_TIMEOUT); sendMessageAtTime(msg, when); @@ -298,7 +304,7 @@ public final class ActiveServices { ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType, int callingPid, int callingUid, int userId) { - if (DEBUG_DELAYED_STARTS) Slog.v(TAG, "startService: " + service + if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "startService: " + service + " type=" + resolvedType + " args=" + service.getExtras()); final boolean callerFg; @@ -337,7 +343,7 @@ public final class ActiveServices { NeededUriGrants neededGrants = mAm.checkGrantUriPermissionFromIntentLocked( callingUid, r.packageName, service, service.getFlags(), null, r.userId); if (unscheduleServiceRestartLocked(r, callingUid, false)) { - if (DEBUG_SERVICE) Slog.v(TAG, "START SERVICE WHILE RESTART PENDING: " + r); + if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "START SERVICE WHILE RESTART PENDING: " + r); } r.lastActivity = SystemClock.uptimeMillis(); r.startRequested = true; @@ -360,29 +366,30 @@ public final class ActiveServices { // service is started. This is especially the case for receivers, which // may start a service in onReceive() to do some additional work and have // initialized some global state as part of that. - if (DEBUG_DELAYED_SERVICE) Slog.v(TAG, "Potential start delay of " + r + " in " - + proc); + if (DEBUG_DELAYED_SERVICE) Slog.v(TAG_SERVICE, "Potential start delay of " + + r + " in " + proc); if (r.delayed) { // This service is already scheduled for a delayed start; just leave // it still waiting. - if (DEBUG_DELAYED_STARTS) Slog.v(TAG, "Continuing to delay: " + r); + if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "Continuing to delay: " + r); return r.name; } if (smap.mStartingBackground.size() >= mMaxStartingBackground) { // Something else is starting, delay! - Slog.i(TAG, "Delaying start of: " + r); + Slog.i(TAG_SERVICE, "Delaying start of: " + r); smap.mDelayedStartList.add(r); r.delayed = true; return r.name; } - if (DEBUG_DELAYED_STARTS) Slog.v(TAG, "Not delaying: " + r); + if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "Not delaying: " + r); addToStarting = true; } else if (proc.curProcState >= ActivityManager.PROCESS_STATE_SERVICE) { // We slightly loosen when we will enqueue this new service as a background // starting service we are waiting for, to also include processes that are // currently running other services or receivers. addToStarting = true; - if (DEBUG_DELAYED_STARTS) Slog.v(TAG, "Not delaying, but counting as bg: " + r); + if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, + "Not delaying, but counting as bg: " + r); } else if (DEBUG_DELAYED_STARTS) { StringBuilder sb = new StringBuilder(128); sb.append("Not potential delay (state=").append(proc.curProcState) @@ -394,16 +401,17 @@ public final class ActiveServices { } sb.append("): "); sb.append(r.toString()); - Slog.v(TAG, sb.toString()); + Slog.v(TAG_SERVICE, sb.toString()); } } else if (DEBUG_DELAYED_STARTS) { if (callerFg) { - Slog.v(TAG, "Not potential delay (callerFg=" + callerFg + " uid=" + Slog.v(TAG_SERVICE, "Not potential delay (callerFg=" + callerFg + " uid=" + callingUid + " pid=" + callingPid + "): " + r); } else if (r.app != null) { - Slog.v(TAG, "Not potential delay (cur app=" + r.app + "): " + r); + Slog.v(TAG_SERVICE, "Not potential delay (cur app=" + r.app + "): " + r); } else { - Slog.v(TAG, "Not potential delay (user " + r.userId + " not started): " + r); + Slog.v(TAG_SERVICE, + "Not potential delay (user " + r.userId + " not started): " + r); } } @@ -432,9 +440,9 @@ public final class ActiveServices { if (DEBUG_DELAYED_SERVICE) { RuntimeException here = new RuntimeException("here"); here.fillInStackTrace(); - Slog.v(TAG, "Starting background (first=" + first + "): " + r, here); + Slog.v(TAG_SERVICE, "Starting background (first=" + first + "): " + r, here); } else if (DEBUG_DELAYED_STARTS) { - Slog.v(TAG, "Starting background (first=" + first + "): " + r); + Slog.v(TAG_SERVICE, "Starting background (first=" + first + "): " + r); } if (first) { smap.rescheduleDelayedStarts(); @@ -451,7 +459,7 @@ public final class ActiveServices { // If service isn't actually running, but is is being held in the // delayed list, then we need to keep it started but note that it // should be stopped once no longer delayed. - if (DEBUG_DELAYED_STARTS) Slog.v(TAG, "Delaying stop of pending: " + service); + if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "Delaying stop of pending: " + service); service.delayedStop = true; return; } @@ -469,7 +477,7 @@ public final class ActiveServices { int stopServiceLocked(IApplicationThread caller, Intent service, String resolvedType, int userId) { - if (DEBUG_SERVICE) Slog.v(TAG, "stopService: " + service + if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "stopService: " + service + " type=" + resolvedType); final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller); @@ -525,7 +533,7 @@ public final class ActiveServices { boolean stopServiceTokenLocked(ComponentName className, IBinder token, int startId) { - if (DEBUG_SERVICE) Slog.v(TAG, "stopServiceToken: " + className + if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "stopServiceToken: " + className + " " + token + " startId=" + startId); ServiceRecord r = findServiceLocked(className, token, UserHandle.getCallingUserId()); if (r != null) { @@ -687,7 +695,7 @@ public final class ActiveServices { int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service, String resolvedType, IServiceConnection connection, int flags, int userId) { - if (DEBUG_SERVICE) Slog.v(TAG, "bindService: " + service + if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "bindService: " + service + " type=" + resolvedType + " conn=" + connection.asBinder() + " flags=0x" + Integer.toHexString(flags)); final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller); @@ -751,7 +759,7 @@ public final class ActiveServices { try { if (unscheduleServiceRestartLocked(s, callerApp.info.uid, false)) { - if (DEBUG_SERVICE) Slog.v(TAG, "BIND SERVICE WHILE RESTART PENDING: " + if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "BIND SERVICE WHILE RESTART PENDING: " + s); } @@ -819,7 +827,7 @@ public final class ActiveServices { mAm.updateOomAdjLocked(s.app); } - if (DEBUG_SERVICE) Slog.v(TAG, "Bind " + s + " with " + b + if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Bind " + s + " with " + b + ": received=" + b.intent.received + " apps=" + b.intent.apps.size() + " doRebind=" + b.intent.doRebind); @@ -857,7 +865,7 @@ public final class ActiveServices { void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) { final long origId = Binder.clearCallingIdentity(); try { - if (DEBUG_SERVICE) Slog.v(TAG, "PUBLISHING " + r + if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "PUBLISHING " + r + " " + intent + ": " + service); if (r != null) { Intent.FilterComparison filter @@ -873,14 +881,14 @@ public final class ActiveServices { ConnectionRecord c = clist.get(i); if (!filter.equals(c.binding.intent.intent)) { if (DEBUG_SERVICE) Slog.v( - TAG, "Not publishing to: " + c); + TAG_SERVICE, "Not publishing to: " + c); if (DEBUG_SERVICE) Slog.v( - TAG, "Bound intent: " + c.binding.intent.intent); + TAG_SERVICE, "Bound intent: " + c.binding.intent.intent); if (DEBUG_SERVICE) Slog.v( - TAG, "Published intent: " + intent); + TAG_SERVICE, "Published intent: " + intent); continue; } - if (DEBUG_SERVICE) Slog.v(TAG, "Publishing to: " + c); + if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Publishing to: " + c); try { c.conn.connected(r.name, service); } catch (Exception e) { @@ -901,7 +909,7 @@ public final class ActiveServices { boolean unbindServiceLocked(IServiceConnection connection) { IBinder binder = connection.asBinder(); - if (DEBUG_SERVICE) Slog.v(TAG, "unbindService: conn=" + binder); + if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "unbindService: conn=" + binder); ArrayList<ConnectionRecord> clist = mServiceConnections.get(binder); if (clist == null) { Slog.w(TAG, "Unbind failed: could not find connection for " @@ -945,7 +953,7 @@ public final class ActiveServices { Intent.FilterComparison filter = new Intent.FilterComparison(intent); IntentBindRecord b = r.bindings.get(filter); - if (DEBUG_SERVICE) Slog.v(TAG, "unbindFinished in " + r + if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "unbindFinished in " + r + " at " + b + ": apps=" + (b != null ? b.apps.size() : 0)); @@ -1012,7 +1020,7 @@ public final class ActiveServices { String resolvedType, int callingPid, int callingUid, int userId, boolean createIfNeeded, boolean callingFromFg) { ServiceRecord r = null; - if (DEBUG_SERVICE) Slog.v(TAG, "retrieveServiceLocked: " + service + if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "retrieveServiceLocked: " + service + " type=" + resolvedType + " callingUid=" + callingUid); userId = mAm.handleIncomingUser(callingPid, callingUid, userId, @@ -1036,7 +1044,7 @@ public final class ActiveServices { ServiceInfo sInfo = rInfo != null ? rInfo.serviceInfo : null; if (sInfo == null) { - Slog.w(TAG, "Unable to start service " + service + " U=" + userId + + Slog.w(TAG_SERVICE, "Unable to start service " + service + " U=" + userId + ": not found"); return null; } @@ -1110,9 +1118,9 @@ public final class ActiveServices { } private final void bumpServiceExecutingLocked(ServiceRecord r, boolean fg, String why) { - if (DEBUG_SERVICE) Slog.v(TAG, ">>> EXECUTING " + if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, ">>> EXECUTING " + why + " of " + r + " in app " + r.app); - else if (DEBUG_SERVICE_EXECUTING) Slog.v(TAG, ">>> EXECUTING " + else if (DEBUG_SERVICE_EXECUTING) Slog.v(TAG_SERVICE_EXECUTING, ">>> EXECUTING " + why + " of " + r.shortName); long now = SystemClock.uptimeMillis(); if (r.executeNesting == 0) { @@ -1155,7 +1163,7 @@ public final class ActiveServices { i.hasBound = true; i.doRebind = false; } catch (RemoteException e) { - if (DEBUG_SERVICE) Slog.v(TAG, "Crashed while binding " + r); + if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Crashed while binding " + r); return false; } } @@ -1336,7 +1344,7 @@ public final class ActiveServices { return null; } - if (DEBUG_SERVICE) Slog.v(TAG, "Bringing up " + r + " " + r.intent); + if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Bringing up " + r + " " + r.intent); // We are now bringing the service up, so no longer in the // restarting state. @@ -1347,7 +1355,7 @@ public final class ActiveServices { // Make sure this service is no longer considered delayed, we are starting it now. if (r.delayed) { - if (DEBUG_DELAYED_STARTS) Slog.v(TAG, "REM FR DELAY LIST (bring up): " + r); + if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "REM FR DELAY LIST (bring up): " + r); getServiceMap(r.userId).mDelayedStartList.remove(r); r.delayed = false; } @@ -1430,7 +1438,8 @@ public final class ActiveServices { // Oh and hey we've already been asked to stop! r.delayedStop = false; if (r.startRequested) { - if (DEBUG_DELAYED_STARTS) Slog.v(TAG, "Applying delayed stop (in bring up): " + r); + if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, + "Applying delayed stop (in bring up): " + r); stopServiceLocked(r); } } @@ -1509,7 +1518,7 @@ public final class ActiveServices { sendServiceArgsLocked(r, execInFg, true); if (r.delayed) { - if (DEBUG_DELAYED_STARTS) Slog.v(TAG, "REM FR DELAY LIST (new proc): " + r); + if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "REM FR DELAY LIST (new proc): " + r); getServiceMap(r.userId).mDelayedStartList.remove(r); r.delayed = false; } @@ -1518,7 +1527,8 @@ public final class ActiveServices { // Oh and hey we've already been asked to stop! r.delayedStop = false; if (r.startRequested) { - if (DEBUG_DELAYED_STARTS) Slog.v(TAG, "Applying delayed stop (from start): " + r); + if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, + "Applying delayed stop (from start): " + r); stopServiceLocked(r); } } @@ -1534,7 +1544,7 @@ public final class ActiveServices { while (r.pendingStarts.size() > 0) { try { ServiceRecord.StartItem si = r.pendingStarts.remove(0); - if (DEBUG_SERVICE) Slog.v(TAG, "Sending arguments to: " + if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Sending arguments to: " + r + " " + r.intent + " args=" + si.intent); if (si.intent == null && N > 1) { // If somehow we got a dummy null intent in the middle, @@ -1566,7 +1576,7 @@ public final class ActiveServices { } catch (RemoteException e) { // Remote process gone... we'll let the normal cleanup take // care of this. - if (DEBUG_SERVICE) Slog.v(TAG, "Crashed while scheduling start: " + r); + if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Crashed while scheduling start: " + r); break; } catch (Exception e) { Slog.w(TAG, "Unexpected exception", e); @@ -1636,7 +1646,7 @@ public final class ActiveServices { if (r.app != null && r.app.thread != null) { for (int i=r.bindings.size()-1; i>=0; i--) { IntentBindRecord ibr = r.bindings.valueAt(i); - if (DEBUG_SERVICE) Slog.v(TAG, "Bringing down binding " + ibr + if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Bringing down binding " + ibr + ": hasBound=" + ibr.hasBound); if (ibr.hasBound) { try { @@ -1654,7 +1664,7 @@ public final class ActiveServices { } } - if (DEBUG_SERVICE) Slog.v(TAG, "Bringing down " + r + " " + r.intent); + if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Bringing down " + r + " " + r.intent); r.destroyTime = SystemClock.uptimeMillis(); if (LOG_SERVICE_START_STOP) { EventLogTags.writeAmDestroyService( @@ -1671,7 +1681,7 @@ public final class ActiveServices { for (int i=mPendingServices.size()-1; i>=0; i--) { if (mPendingServices.get(i) == r) { mPendingServices.remove(i); - if (DEBUG_SERVICE) Slog.v(TAG, "Removed pending: " + r); + if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Removed pending: " + r); } } @@ -1704,11 +1714,11 @@ public final class ActiveServices { } } else { if (DEBUG_SERVICE) Slog.v( - TAG, "Removed service that has no process: " + r); + TAG_SERVICE, "Removed service that has no process: " + r); } } else { if (DEBUG_SERVICE) Slog.v( - TAG, "Removed service that is not running: " + r); + TAG_SERVICE, "Removed service that is not running: " + r); } if (r.bindings.size() > 0) { @@ -1775,7 +1785,7 @@ public final class ActiveServices { } if (!c.serviceDead) { - if (DEBUG_SERVICE) Slog.v(TAG, "Disconnecting binding " + b.intent + if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Disconnecting binding " + b.intent + ": shouldUnbind=" + b.intent.hasBound); if (s.app != null && s.app.thread != null && b.intent.apps.size() == 0 && b.intent.hasBound) { @@ -1902,19 +1912,20 @@ public final class ActiveServices { private void serviceDoneExecutingLocked(ServiceRecord r, boolean inDestroying, boolean finishing) { - if (DEBUG_SERVICE) Slog.v(TAG, "<<< DONE EXECUTING " + r + if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "<<< DONE EXECUTING " + r + ": nesting=" + r.executeNesting + ", inDestroying=" + inDestroying + ", app=" + r.app); - else if (DEBUG_SERVICE_EXECUTING) Slog.v(TAG, "<<< DONE EXECUTING " + r.shortName); + else if (DEBUG_SERVICE_EXECUTING) Slog.v(TAG_SERVICE_EXECUTING, + "<<< DONE EXECUTING " + r.shortName); r.executeNesting--; if (r.executeNesting <= 0) { if (r.app != null) { - if (DEBUG_SERVICE) Slog.v(TAG, + if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Nesting at 0 of " + r.shortName); r.app.execServicesFg = false; r.app.executingServices.remove(r); if (r.app.executingServices.size() == 0) { - if (DEBUG_SERVICE || DEBUG_SERVICE_EXECUTING) Slog.v(TAG, + if (DEBUG_SERVICE || DEBUG_SERVICE_EXECUTING) Slog.v(TAG_SERVICE_EXECUTING, "No more executingServices of " + r.shortName); mAm.mHandler.removeMessages(ActivityManagerService.SERVICE_TIMEOUT_MSG, r.app); } else if (r.executeFg) { @@ -1927,7 +1938,7 @@ public final class ActiveServices { } } if (inDestroying) { - if (DEBUG_SERVICE) Slog.v(TAG, + if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "doneExecuting remove destroying " + r); mDestroyingServices.remove(r); r.bindings.clear(); @@ -2141,13 +2152,13 @@ public final class ActiveServices { sr.executeNesting = 0; sr.forceClearTracker(); if (mDestroyingServices.remove(sr)) { - if (DEBUG_SERVICE) Slog.v(TAG, "killServices remove destroying " + sr); + if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "killServices remove destroying " + sr); } final int numClients = sr.bindings.size(); for (int bindingi=numClients-1; bindingi>=0; bindingi--) { IntentBindRecord b = sr.bindings.valueAt(bindingi); - if (DEBUG_SERVICE) Slog.v(TAG, "Killing binding " + b + if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Killing binding " + b + ": shouldUnbind=" + b.hasBound); b.binder = null; b.requested = b.received = b.hasBound = false; @@ -2281,7 +2292,7 @@ public final class ActiveServices { if (sr.app == app) { sr.forceClearTracker(); mDestroyingServices.remove(i); - if (DEBUG_SERVICE) Slog.v(TAG, "killServices remove destroying " + sr); + if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "killServices remove destroying " + sr); } } diff --git a/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java b/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java new file mode 100644 index 000000000000..03f253b4807e --- /dev/null +++ b/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.server.am; + +/** + * Common class for the various debug {@link android.util.Log} output configuration in the activity + * manager package. + */ +class ActivityManagerDebugConfig { + + // All output logs in the activity manager package use the {@link #TAG_AM} string for tagging + // their log output. This makes it easy to identify the origin of the log message when sifting + // through a large amount of log output from multiple sources. However, it also makes trying + // to figure-out the origin of a log message while debugging the activity manager a little + // painful. By setting this constant to true, log messages from the activity manager package + // will be tagged with their class names instead fot the generic tag. + static final boolean TAG_WITH_CLASS_NAME = false; + + // While debugging it is sometimes useful to have the category name of the log prepended to the + // base log tag to make sifting through logs with the same base tag easier. By setting this + // constant to true, the category name of the log point will be prepended to the log tag. + static final boolean PREPEND_CATEGORY_NAME = false; + + // Default log tag for the activity manager package. + static final String TAG_AM = "ActivityManager"; + + // Enable all debug log categories. + static final boolean DEBUG_ALL = false; + + // Available log categories in the activity manager package. + static final boolean DEBUG_BACKUP = DEBUG_ALL || false; + static final boolean DEBUG_BROADCAST = DEBUG_ALL || false; + static final boolean DEBUG_BROADCAST_BACKGROUND = DEBUG_BROADCAST || false; + static final boolean DEBUG_BROADCAST_LIGHT = DEBUG_BROADCAST || false; + static final boolean DEBUG_CLEANUP = DEBUG_ALL || false; + static final boolean DEBUG_CONFIGURATION = DEBUG_ALL || false; + static final boolean DEBUG_FOCUS = false; + static final boolean DEBUG_IMMERSIVE = DEBUG_ALL || false; + static final boolean DEBUG_LOCKSCREEN = DEBUG_ALL || false; + 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_POWER = DEBUG_ALL || false; + static final boolean DEBUG_POWER_QUICK = DEBUG_POWER || false; + static final boolean DEBUG_PROCESS_OBSERVERS = DEBUG_ALL || false; + static final boolean DEBUG_PROCESSES = DEBUG_ALL || false; + static final boolean DEBUG_PROVIDER = DEBUG_ALL || false; + static final boolean DEBUG_PSS = DEBUG_ALL || false; + static final boolean DEBUG_RECENTS = DEBUG_ALL || false; + static final boolean DEBUG_RESULTS = DEBUG_ALL || false; + 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_SWITCH = DEBUG_ALL || false; + static final boolean DEBUG_TASKS = DEBUG_ALL || false; + static final boolean DEBUG_THUMBNAILS = DEBUG_ALL || false; + static final boolean DEBUG_TRANSITION = 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_VISBILITY = DEBUG_ALL || false; + + static final String POSTFIX_BACKUP = (PREPEND_CATEGORY_NAME) ? "_Backup" : ""; + static final String POSTFIX_BROADCAST = (PREPEND_CATEGORY_NAME) ? "_Broadcast" : ""; + static final String POSTFIX_MU = "_MU"; + static final String POSTFIX_SERVICE = (PREPEND_CATEGORY_NAME) ? "_Service" : ""; + static final String POSTFIX_SERVICE_EXECUTING = + (PREPEND_CATEGORY_NAME) ? "_ServiceExecuting" : ""; + +} diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 61ff514a8f21..46f07cc527fe 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -30,6 +30,7 @@ import static com.android.server.Watchdog.NATIVE_STACKS_OF_INTEREST; import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT; import static org.xmlpull.v1.XmlPullParser.START_TAG; import static com.android.server.am.ActivityStackSupervisor.HOME_STACK_ID; +import static com.android.server.am.ActivityManagerDebugConfig.*; import static com.android.server.am.TaskRecord.INVALID_TASK_ID; import android.Manifest; @@ -55,11 +56,13 @@ import android.os.storage.StorageManager; import android.service.voice.IVoiceInteractionSession; import android.util.ArrayMap; import android.util.ArraySet; +import android.util.DebugUtils; import android.util.SparseIntArray; import android.view.Display; import com.android.internal.R; import com.android.internal.annotations.GuardedBy; +import com.android.internal.app.DumpHeapActivity; import com.android.internal.app.IAppOpsService; import com.android.internal.app.IVoiceInteractor; import com.android.internal.app.ProcessMap; @@ -245,10 +248,11 @@ public final class ActivityManagerService extends ActivityManagerNative // File that stores last updated system version and called preboot receivers static final String CALLED_PRE_BOOTS_FILENAME = "called_pre_boots.dat"; - static final String TAG = "ActivityManager"; - static final String TAG_MU = "ActivityManagerServiceMU"; - static final boolean DEBUG = false; - static final boolean localLOGV = DEBUG; + static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityManagerService" : TAG_AM; + private static final String TAG_MU = TAG + POSTFIX_MU; + + // TODO(ogunwale): Migrate all the constants below to use ActivityManagerDebugConfig class. + static final boolean localLOGV = DEBUG_ALL || false; static final boolean DEBUG_BACKUP = localLOGV || false; static final boolean DEBUG_BROADCAST = localLOGV || false; static final boolean DEBUG_BROADCAST_LIGHT = DEBUG_BROADCAST || false; @@ -1124,6 +1128,11 @@ public final class ActivityManagerService extends ActivityManagerNative boolean mAutoStopProfiler = false; int mProfileType = 0; String mOpenGlTraceApp = null; + final ArrayMap<String, Long> mMemWatchProcesses = new ArrayMap<>(); + String mMemWatchDumpProcName; + String mMemWatchDumpFile; + int mMemWatchDumpPid; + int mMemWatchDumpUid; final long[] mTmpLong = new long[1]; @@ -1266,6 +1275,8 @@ public final class ActivityManagerService extends ActivityManagerNative static final int DISMISS_DIALOG_MSG = 48; static final int NOTIFY_TASK_STACK_CHANGE_LISTENERS_MSG = 49; static final int NOTIFY_CLEARTEXT_NETWORK_MSG = 50; + static final int POST_DUMP_HEAP_NOTIFICATION_MSG = 51; + static final int DELETE_DUMPHEAP_MSG = 52; static final int FIRST_ACTIVITY_STACK_MSG = 100; static final int FIRST_BROADCAST_QUEUE_MSG = 200; @@ -1820,6 +1831,78 @@ public final class ActivityManagerService extends ActivityManagerNative } break; } + case POST_DUMP_HEAP_NOTIFICATION_MSG: { + final String procName; + final int uid; + final long memLimit; + synchronized (ActivityManagerService.this) { + procName = mMemWatchDumpProcName; + uid = mMemWatchDumpUid; + Long limit = mMemWatchProcesses.get(procName); + memLimit = limit != null ? limit : 0; + } + if (procName == null) { + return; + } + + if (DEBUG_PSS) Slog.d(TAG, "Showing dump heap notification from " + + procName + "/" + uid); + + INotificationManager inm = NotificationManager.getService(); + if (inm == null) { + return; + } + + String text = mContext.getString(R.string.dump_heap_notification, procName); + Notification notification = new Notification(); + notification.icon = com.android.internal.R.drawable.stat_sys_adb; + notification.when = 0; + notification.flags = Notification.FLAG_ONGOING_EVENT|Notification.FLAG_AUTO_CANCEL; + notification.tickerText = text; + notification.defaults = 0; // please be quiet + notification.sound = null; + notification.vibrate = null; + notification.color = mContext.getResources().getColor( + com.android.internal.R.color.system_notification_accent_color); + Intent deleteIntent = new Intent(); + deleteIntent.setAction(DumpHeapActivity.ACTION_DELETE_DUMPHEAP); + notification.deleteIntent = PendingIntent.getBroadcastAsUser(mContext, 0, + deleteIntent, 0, UserHandle.OWNER); + Intent intent = new Intent(); + intent.setClassName("android", DumpHeapActivity.class.getName()); + intent.putExtra(DumpHeapActivity.KEY_PROCESS, procName); + intent.putExtra(DumpHeapActivity.KEY_SIZE, memLimit); + int userId = UserHandle.getUserId(uid); + notification.setLatestEventInfo(mContext, text, + mContext.getText(R.string.dump_heap_notification_detail), + PendingIntent.getActivityAsUser(mContext, 0, intent, + PendingIntent.FLAG_CANCEL_CURRENT, null, + new UserHandle(userId))); + + try { + int[] outId = new int[1]; + inm.enqueueNotificationWithTag("android", "android", null, + R.string.dump_heap_notification, + notification, outId, userId); + } catch (RuntimeException e) { + Slog.w(ActivityManagerService.TAG, + "Error showing notification for dump heap", e); + } catch (RemoteException e) { + } + } break; + case DELETE_DUMPHEAP_MSG: { + revokeUriPermission(ActivityThread.currentActivityThread().getApplicationThread(), + DumpHeapActivity.JAVA_URI, + Intent.FLAG_GRANT_READ_URI_PERMISSION + | Intent.FLAG_GRANT_WRITE_URI_PERMISSION, + UserHandle.myUserId()); + synchronized (ActivityManagerService.this) { + mMemWatchDumpFile = null; + mMemWatchDumpProcName = null; + mMemWatchDumpPid = -1; + mMemWatchDumpUid = -1; + } + } break; } } }; @@ -1906,7 +1989,7 @@ public final class ActivityManagerService extends ActivityManagerNative if (pss != 0 && proc.thread != null && proc.setProcState == procState && proc.pid == pid && proc.lastPssTime == lastPssTime) { num++; - recordPssSample(proc, procState, pss, tmp[0], + recordPssSampleLocked(proc, procState, pss, tmp[0], SystemClock.uptimeMillis()); } } @@ -2318,7 +2401,7 @@ public final class ActivityManagerService extends ActivityManagerNative } ps.addCpuTimeLocked(st.rel_utime - otherUTime, st.rel_stime - otherSTime, cpuSpeedTimes); - pr.curCpuTime += (st.rel_utime+st.rel_stime) * 10; + pr.curCpuTime += st.rel_utime + st.rel_stime; } else { BatteryStatsImpl.Uid.Proc ps = st.batteryStats; if (ps == null || !ps.isActive()) { @@ -5704,7 +5787,7 @@ public final class ActivityManagerService extends ActivityManagerNative for (String pkg : pkgs) { synchronized (ActivityManagerService.this) { if (forceStopPackageLocked(pkg, -1, false, false, false, false, false, - 0, "finished booting")) { + 0, "query restart")) { setResultCode(Activity.RESULT_OK); return; } @@ -5714,6 +5797,19 @@ public final class ActivityManagerService extends ActivityManagerNative } }, pkgFilter); + IntentFilter dumpheapFilter = new IntentFilter(); + dumpheapFilter.addAction(DumpHeapActivity.ACTION_DELETE_DUMPHEAP); + mContext.registerReceiver(new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (intent.getBooleanExtra(DumpHeapActivity.EXTRA_DELAY_DELETE, false)) { + mHandler.sendEmptyMessageDelayed(POST_DUMP_HEAP_NOTIFICATION_MSG, 5*60*1000); + } else { + mHandler.sendEmptyMessage(POST_DUMP_HEAP_NOTIFICATION_MSG); + } + } + }, dumpheapFilter); + // Let system services know. mSystemServiceManager.startBootPhase(SystemService.PHASE_BOOT_COMPLETED); @@ -12739,6 +12835,22 @@ public final class ActivityManagerService extends ActivityManagerNative + " mOrigWaitForDebugger=" + mOrigWaitForDebugger); } } + if (mMemWatchProcesses.size() > 0) { + pw.println(" Mem watch processes:"); + for (int i=0; i<mMemWatchProcesses.size(); i++) { + if (needSep) { + pw.println(); + needSep = false; + } + pw.print(" "); pw.print(mMemWatchProcesses.keyAt(i)); + pw.print(": "); DebugUtils.printSizeValue(pw, mMemWatchProcesses.valueAt(i)); + pw.println(); + } + pw.print(" mMemWatchDumpProcName="); pw.println(mMemWatchDumpProcName); + pw.print(" mMemWatchDumpFile="); pw.println(mMemWatchDumpFile); + pw.print(" mMemWatchDumpPid="); pw.print(mMemWatchDumpPid); + pw.print(" mMemWatchDumpUid="); pw.println(mMemWatchDumpUid); + } if (mOpenGlTraceApp != null) { if (dumpPackage == null || dumpPackage.equals(mOpenGlTraceApp)) { if (needSep) { @@ -13421,8 +13533,9 @@ public final class ActivityManagerService extends ActivityManagerNative pw.print(" "); pw.print("state: cur="); pw.print(ProcessList.makeProcStateString(r.curProcState)); pw.print(" set="); pw.print(ProcessList.makeProcStateString(r.setProcState)); - pw.print(" lastPss="); pw.print(r.lastPss); - pw.print(" lastCachedPss="); pw.println(r.lastCachedPss); + pw.print(" lastPss="); DebugUtils.printSizeValue(pw, r.lastPss*1024); + pw.print(" lastCachedPss="); DebugUtils.printSizeValue(pw, r.lastCachedPss*1024); + pw.println(); pw.print(prefix); pw.print(" "); pw.print("cached="); pw.print(r.cached); @@ -17230,7 +17343,7 @@ public final class ActivityManagerService extends ActivityManagerNative /** * Record new PSS sample for a process. */ - void recordPssSample(ProcessRecord proc, int procState, long pss, long uss, long now) { + void recordPssSampleLocked(ProcessRecord proc, int procState, long pss, long uss, long now) { EventLogTags.writeAmPss(proc.pid, proc.uid, proc.processName, pss*1024, uss*1024); proc.lastPssTime = now; proc.baseProcessTracker.addPss(pss, uss, true, proc.pkgList); @@ -17244,6 +17357,67 @@ public final class ActivityManagerService extends ActivityManagerNative if (procState >= ActivityManager.PROCESS_STATE_HOME) { proc.lastCachedPss = pss; } + + Long check = mMemWatchProcesses.get(proc.processName); + if (check != null) { + if ((pss*1024) >= check && proc.thread != null && mMemWatchDumpProcName == null) { + boolean isDebuggable = "1".equals(SystemProperties.get(SYSTEM_DEBUGGABLE, "0")); + if (!isDebuggable) { + if ((proc.info.flags&ApplicationInfo.FLAG_DEBUGGABLE) != 0) { + isDebuggable = true; + } + } + if (isDebuggable) { + Slog.w(TAG, "Process " + proc + " exceeded pss limit " + check + "; reporting"); + final ProcessRecord myProc = proc; + final File heapdumpFile = DumpHeapProvider.getJavaFile(); + mMemWatchDumpProcName = proc.processName; + mMemWatchDumpFile = heapdumpFile.toString(); + mMemWatchDumpPid = proc.pid; + mMemWatchDumpUid = proc.uid; + BackgroundThread.getHandler().post(new Runnable() { + @Override + public void run() { + revokeUriPermission(ActivityThread.currentActivityThread() + .getApplicationThread(), + DumpHeapActivity.JAVA_URI, + Intent.FLAG_GRANT_READ_URI_PERMISSION + | Intent.FLAG_GRANT_WRITE_URI_PERMISSION, + UserHandle.myUserId()); + ParcelFileDescriptor fd = null; + try { + heapdumpFile.delete(); + fd = ParcelFileDescriptor.open(heapdumpFile, + ParcelFileDescriptor.MODE_CREATE | + ParcelFileDescriptor.MODE_TRUNCATE | + ParcelFileDescriptor.MODE_READ_WRITE); + IApplicationThread thread = myProc.thread; + if (thread != null) { + try { + if (DEBUG_PSS) Slog.d(TAG, "Requesting dump heap from " + + myProc + " to " + heapdumpFile); + thread.dumpHeap(true, heapdumpFile.toString(), fd); + } catch (RemoteException e) { + } + } + } catch (FileNotFoundException e) { + e.printStackTrace(); + } finally { + if (fd != null) { + try { + fd.close(); + } catch (IOException e) { + } + } + } + } + }); + } else { + Slog.w(TAG, "Process " + proc + " exceeded pss limit " + check + + ", but debugging not enabled"); + } + } + } } /** @@ -17602,7 +17776,7 @@ public final class ActivityManagerService extends ActivityManagerNative // states, which well tend to give noisy data. long start = SystemClock.uptimeMillis(); long pss = Debug.getPss(app.pid, mTmpLong, null); - recordPssSample(app, app.curProcState, pss, mTmpLong[0], now); + recordPssSampleLocked(app, app.curProcState, pss, mTmpLong[0], now); mPendingPssProcesses.remove(app); Slog.i(TAG, "Recorded pss for " + app + " state " + app.setProcState + " to " + app.curProcState + ": " @@ -18422,6 +18596,38 @@ public final class ActivityManagerService extends ActivityManagerNative } } + @Override + public void setDumpHeapDebugLimit(String processName, long maxMemSize) { + enforceCallingPermission(android.Manifest.permission.SET_DEBUG_APP, + "setDumpHeapDebugLimit()"); + synchronized (this) { + if (maxMemSize > 0) { + mMemWatchProcesses.put(processName, maxMemSize); + mHandler.sendEmptyMessage(POST_DUMP_HEAP_NOTIFICATION_MSG); + } else { + mMemWatchProcesses.remove(processName); + } + } + } + + @Override + public void dumpHeapFinished(String path) { + synchronized (this) { + if (Binder.getCallingPid() != mMemWatchDumpPid) { + Slog.w(TAG, "dumpHeapFinished: Calling pid " + Binder.getCallingPid() + + " does not match last pid " + mMemWatchDumpPid); + return; + } + if (mMemWatchDumpFile == null || !mMemWatchDumpFile.equals(path)) { + Slog.w(TAG, "dumpHeapFinished: Calling path " + path + + " does not match last path " + mMemWatchDumpFile); + return; + } + if (DEBUG_PSS) Slog.d(TAG, "Dump heap finished for " + path); + mHandler.sendEmptyMessage(POST_DUMP_HEAP_NOTIFICATION_MSG); + } + } + /** In this method we try to acquire our lock to make sure that we have not deadlocked */ public void monitor() { synchronized (this) { } diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java index b3d3d6a4ac9a..8b95ae87b936 100644 --- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java @@ -20,6 +20,7 @@ import static android.Manifest.permission.START_ANY_ACTIVITY; import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME; import static android.content.pm.PackageManager.PERMISSION_GRANTED; +import static com.android.server.am.ActivityManagerDebugConfig.*; import static com.android.server.am.ActivityManagerService.localLOGV; import static com.android.server.am.ActivityManagerService.DEBUG_CONFIGURATION; import static com.android.server.am.ActivityManagerService.DEBUG_FOCUS; @@ -116,7 +117,7 @@ import java.util.ArrayList; import java.util.List; public final class ActivityStackSupervisor implements DisplayListener { - static final boolean DEBUG = ActivityManagerService.DEBUG || false; + static final boolean DEBUG = DEBUG_ALL || false; static final boolean DEBUG_ADD_REMOVE = DEBUG || false; static final boolean DEBUG_APP = DEBUG || false; static final boolean DEBUG_CONTAINERS = DEBUG || false; diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java index 5083b1dcb896..8fe123811a04 100644 --- a/services/core/java/com/android/server/am/BroadcastQueue.java +++ b/services/core/java/com/android/server/am/BroadcastQueue.java @@ -41,6 +41,8 @@ import android.os.UserHandle; import android.util.EventLog; import android.util.Slog; +import static com.android.server.am.ActivityManagerDebugConfig.*; + /** * BROADCASTS * @@ -48,11 +50,9 @@ import android.util.Slog; * foreground priority, and one for normal (background-priority) broadcasts. */ public final class BroadcastQueue { - static final String TAG = "BroadcastQueue"; - static final String TAG_MU = ActivityManagerService.TAG_MU; - static final boolean DEBUG_BROADCAST = ActivityManagerService.DEBUG_BROADCAST; - static final boolean DEBUG_BROADCAST_LIGHT = ActivityManagerService.DEBUG_BROADCAST_LIGHT; - static final boolean DEBUG_MU = ActivityManagerService.DEBUG_MU; + private static final String TAG = TAG_WITH_CLASS_NAME ? "BroadcastQueue" : TAG_AM; + private static final String TAG_MU = TAG + POSTFIX_MU; + private static final String TAG_BROADCAST = TAG + POSTFIX_BROADCAST; static final int MAX_BROADCAST_HISTORY = ActivityManager.isLowRamDeviceStatic() ? 10 : 50; static final int MAX_BROADCAST_SUMMARY_HISTORY @@ -143,7 +143,7 @@ public final class BroadcastQueue { switch (msg.what) { case BROADCAST_INTENT_MSG: { if (DEBUG_BROADCAST) Slog.v( - TAG, "Received BROADCAST_INTENT_MSG"); + TAG_BROADCAST, "Received BROADCAST_INTENT_MSG"); processNextBroadcast(true); } break; case BROADCAST_TIMEOUT_MSG: { @@ -196,7 +196,7 @@ public final class BroadcastQueue { public final boolean replaceParallelBroadcastLocked(BroadcastRecord r) { for (int i=mParallelBroadcasts.size()-1; i>=0; i--) { if (r.intent.filterEquals(mParallelBroadcasts.get(i).intent)) { - if (DEBUG_BROADCAST) Slog.v(TAG, + if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "***** DROPPING PARALLEL [" + mQueueName + "]: " + r.intent); mParallelBroadcasts.set(i, r); @@ -209,7 +209,7 @@ public final class BroadcastQueue { public final boolean replaceOrderedBroadcastLocked(BroadcastRecord r) { for (int i=mOrderedBroadcasts.size()-1; i>0; i--) { if (r.intent.filterEquals(mOrderedBroadcasts.get(i).intent)) { - if (DEBUG_BROADCAST) Slog.v(TAG, + if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "***** DROPPING ORDERED [" + mQueueName + "]: " + r.intent); mOrderedBroadcasts.set(i, r); @@ -221,7 +221,7 @@ public final class BroadcastQueue { private final void processCurBroadcastLocked(BroadcastRecord r, ProcessRecord app) throws RemoteException { - if (DEBUG_BROADCAST) Slog.v(TAG, + if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Process cur broadcast " + r + " for app " + app); if (app.thread == null) { throw new RemoteException(); @@ -238,7 +238,7 @@ public final class BroadcastQueue { boolean started = false; try { - if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG, + if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Delivering to component " + r.curComponent + ": " + r); mService.ensurePackageDexOpt(r.intent.getComponent().getPackageName()); @@ -246,12 +246,12 @@ public final class BroadcastQueue { mService.compatibilityInfoForPackageLocked(r.curReceiver.applicationInfo), r.resultCode, r.resultData, r.resultExtras, r.ordered, r.userId, app.repProcState); - if (DEBUG_BROADCAST) Slog.v(TAG, + if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Process cur broadcast " + r + " DELIVERED for app " + app); started = true; } finally { if (!started) { - if (DEBUG_BROADCAST) Slog.v(TAG, + if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Process cur broadcast " + r + ": NOT STARTED!"); r.receiver = null; r.curApp = null; @@ -305,23 +305,22 @@ public final class BroadcastQueue { r.resultExtras, r.resultAbort, false); reschedule = true; } - - r = mPendingBroadcast; - if (r != null && r.curApp == app) { - if (DEBUG_BROADCAST) Slog.v(TAG, + if (r == null && mPendingBroadcast != null && mPendingBroadcast.curApp == app) { + if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "[" + mQueueName + "] skip & discard pending app " + r); + r = mPendingBroadcast; + } + + if (r != null) { logBroadcastReceiverDiscardLocked(r); finishReceiverLocked(r, r.resultCode, r.resultData, r.resultExtras, r.resultAbort, false); - reschedule = true; - } - if (reschedule) { scheduleBroadcastsLocked(); } } public void scheduleBroadcastsLocked() { - if (DEBUG_BROADCAST) Slog.v(TAG, "Schedule broadcasts [" + if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Schedule broadcasts [" + mQueueName + "]: current=" + mBroadcastsScheduled); @@ -391,8 +390,7 @@ public final class BroadcastQueue { // on. If there are background services currently starting, then we will go into a // special state where we hold off on continuing this broadcast until they are done. if (mService.mServices.hasBackgroundServices(r.userId)) { - Slog.i(ActivityManagerService.TAG, "Delay finish: " - + r.curComponent.flattenToShortString()); + Slog.i(TAG, "Delay finish: " + r.curComponent.flattenToShortString()); r.state = BroadcastRecord.WAITING_SERVICES; return false; } @@ -412,7 +410,7 @@ public final class BroadcastQueue { if (mOrderedBroadcasts.size() > 0) { BroadcastRecord br = mOrderedBroadcasts.get(0); if (br.userId == userId && br.state == BroadcastRecord.WAITING_SERVICES) { - Slog.i(ActivityManagerService.TAG, "Resuming delayed broadcast"); + Slog.i(TAG, "Resuming delayed broadcast"); br.curComponent = null; br.state = BroadcastRecord.IDLE; processNextBroadcast(false); @@ -475,7 +473,7 @@ public final class BroadcastQueue { int mode = mService.mAppOpsService.noteOperation(r.appOp, filter.receiverList.uid, filter.packageName); if (mode != AppOpsManager.MODE_ALLOWED) { - if (DEBUG_BROADCAST) Slog.v(TAG, + if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "App op " + r.appOp + " not allowed for broadcast to uid " + filter.receiverList.uid + " pkg " + filter.packageName); skip = true; @@ -513,10 +511,11 @@ public final class BroadcastQueue { } } try { - if (DEBUG_BROADCAST_LIGHT) Slog.i(TAG, "Delivering to " + filter + " : " + r); + if (DEBUG_BROADCAST_LIGHT) Slog.i(TAG_BROADCAST, + "Delivering to " + filter + " : " + r); performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver, - new Intent(r.intent), r.resultCode, r.resultData, - r.resultExtras, r.ordered, r.initialSticky, r.userId); + new Intent(r.intent), r.resultCode, r.resultData, + r.resultExtras, r.ordered, r.initialSticky, r.userId); if (ordered) { r.state = BroadcastRecord.CALL_DONE_RECEIVE; } @@ -538,7 +537,7 @@ public final class BroadcastQueue { synchronized(mService) { BroadcastRecord r; - if (DEBUG_BROADCAST) Slog.v(TAG, "processNextBroadcast [" + if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "processNextBroadcast [" + mQueueName + "]: " + mParallelBroadcasts.size() + " broadcasts, " + mOrderedBroadcasts.size() + " ordered broadcasts"); @@ -555,17 +554,17 @@ public final class BroadcastQueue { r.dispatchTime = SystemClock.uptimeMillis(); r.dispatchClockTime = System.currentTimeMillis(); final int N = r.receivers.size(); - if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG, "Processing parallel broadcast [" + if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Processing parallel broadcast [" + mQueueName + "] " + r); for (int i=0; i<N; i++) { Object target = r.receivers.get(i); - if (DEBUG_BROADCAST) Slog.v(TAG, + if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Delivering non-ordered on [" + mQueueName + "] to registered " + target + ": " + r); deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false); } addBroadcastToHistoryLocked(r); - if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG, "Done with parallel broadcast [" + if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Done with parallel broadcast [" + mQueueName + "] " + r); } @@ -575,11 +574,9 @@ public final class BroadcastQueue { // broadcast, then do nothing at this point. Just in case, we // check that the process we're waiting for still exists. if (mPendingBroadcast != null) { - if (DEBUG_BROADCAST_LIGHT) { - Slog.v(TAG, "processNextBroadcast [" - + mQueueName + "]: waiting for " - + mPendingBroadcast.curApp); - } + if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, + "processNextBroadcast [" + mQueueName + "]: waiting for " + + mPendingBroadcast.curApp); boolean isDead; synchronized (mService.mPidsSelfLocked) { @@ -645,7 +642,7 @@ public final class BroadcastQueue { } if (r.state != BroadcastRecord.IDLE) { - if (DEBUG_BROADCAST) Slog.d(TAG, + if (DEBUG_BROADCAST) Slog.d(TAG_BROADCAST, "processNextBroadcast(" + mQueueName + ") called when not idle (state=" + r.state + ")"); @@ -658,7 +655,7 @@ public final class BroadcastQueue { // result if requested... if (r.resultTo != null) { try { - if (DEBUG_BROADCAST) Slog.i(TAG, + if (DEBUG_BROADCAST) Slog.i(TAG_BROADCAST, "Finishing broadcast [" + mQueueName + "] " + r.intent.getAction() + " app=" + r.callerApp); performReceiveLocked(r.callerApp, r.resultTo, @@ -675,11 +672,11 @@ public final class BroadcastQueue { } } - if (DEBUG_BROADCAST) Slog.v(TAG, "Cancelling BROADCAST_TIMEOUT_MSG"); + if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Cancelling BROADCAST_TIMEOUT_MSG"); cancelBroadcastTimeoutLocked(); - if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG, "Finished with ordered broadcast " - + r); + if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, + "Finished with ordered broadcast " + r); // ... and on to the next... addBroadcastToHistoryLocked(r); @@ -699,12 +696,12 @@ public final class BroadcastQueue { if (recIdx == 0) { r.dispatchTime = r.receiverTime; r.dispatchClockTime = System.currentTimeMillis(); - if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG, "Processing ordered broadcast [" + if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Processing ordered broadcast [" + mQueueName + "] " + r); } if (! mPendingBroadcastTimeoutMessage) { long timeoutTime = r.receiverTime + mTimeoutPeriod; - if (DEBUG_BROADCAST) Slog.v(TAG, + if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Submitting BROADCAST_TIMEOUT_MSG [" + mQueueName + "] for " + r + " at " + timeoutTime); setBroadcastTimeoutLocked(timeoutTime); @@ -715,7 +712,7 @@ public final class BroadcastQueue { // Simple case: this is a registered receiver who gets // a direct call. BroadcastFilter filter = (BroadcastFilter)nextReceiver; - if (DEBUG_BROADCAST) Slog.v(TAG, + if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Delivering ordered [" + mQueueName + "] to registered " + filter + ": " + r); @@ -723,7 +720,7 @@ public final class BroadcastQueue { if (r.receiver == null || !r.ordered) { // The receiver has already finished, so schedule to // process the next one. - if (DEBUG_BROADCAST) Slog.v(TAG, "Quick finishing [" + if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Quick finishing [" + mQueueName + "]: ordered=" + r.ordered + " receiver=" + r.receiver); r.state = BroadcastRecord.IDLE; @@ -786,7 +783,7 @@ public final class BroadcastQueue { int mode = mService.mAppOpsService.noteOperation(r.appOp, info.activityInfo.applicationInfo.uid, info.activityInfo.packageName); if (mode != AppOpsManager.MODE_ALLOWED) { - if (DEBUG_BROADCAST) Slog.v(TAG, + if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "App op " + r.appOp + " not allowed for broadcast to uid " + info.activityInfo.applicationInfo.uid + " pkg " + info.activityInfo.packageName); @@ -835,19 +832,18 @@ public final class BroadcastQueue { + info.activityInfo.packageName, e); } if (!isAvailable) { - if (DEBUG_BROADCAST) { - Slog.v(TAG, "Skipping delivery to " + info.activityInfo.packageName - + " / " + info.activityInfo.applicationInfo.uid - + " : package no longer available"); - } + if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, + "Skipping delivery to " + info.activityInfo.packageName + " / " + + info.activityInfo.applicationInfo.uid + + " : package no longer available"); skip = true; } } if (skip) { - if (DEBUG_BROADCAST) Slog.v(TAG, - "Skipping delivery of ordered [" - + mQueueName + "] " + r + " for whatever reason"); + if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, + "Skipping delivery of ordered [" + mQueueName + "] " + + r + " for whatever reason"); r.receiver = null; r.curFilter = null; r.state = BroadcastRecord.IDLE; @@ -915,7 +911,7 @@ public final class BroadcastQueue { } // Not running -- get it started, to be executed when the app comes up. - if (DEBUG_BROADCAST) Slog.v(TAG, + if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Need to start app [" + mQueueName + "] " + targetProcess + " for broadcast " + r); if ((r.curApp=mService.startProcessLocked(targetProcess, @@ -990,7 +986,7 @@ public final class BroadcastQueue { // broadcast timeout message after each receiver finishes. Instead, we set up // an initial timeout then kick it down the road a little further as needed // when it expires. - if (DEBUG_BROADCAST) Slog.v(TAG, + if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Premature timeout [" + mQueueName + "] @ " + now + ": resetting BROADCAST_TIMEOUT_MSG for " + timeoutTime); @@ -1005,7 +1001,7 @@ public final class BroadcastQueue { // for started services to finish as well before going on. So if we have actually // waited long enough time timeout the broadcast, let's give up on the whole thing // and just move on to the next. - Slog.i(ActivityManagerService.TAG, "Waited long enough for: " + (br.curComponent != null + Slog.i(TAG, "Waited long enough for: " + (br.curComponent != null ? br.curComponent.flattenToShortString() : "(null)")); br.curComponent = null; br.state = BroadcastRecord.IDLE; diff --git a/services/core/java/com/android/server/am/DumpHeapProvider.java b/services/core/java/com/android/server/am/DumpHeapProvider.java new file mode 100644 index 000000000000..a8b639ecf8d4 --- /dev/null +++ b/services/core/java/com/android/server/am/DumpHeapProvider.java @@ -0,0 +1,89 @@ +/* + * 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.am; + +import android.content.ContentProvider; +import android.content.ContentValues; +import android.database.Cursor; +import android.net.Uri; +import android.os.Environment; +import android.os.ParcelFileDescriptor; + +import java.io.File; +import java.io.FileNotFoundException; + +public class DumpHeapProvider extends ContentProvider { + static final Object sLock = new Object(); + static File sHeapDumpJavaFile; + + static public File getJavaFile() { + synchronized (sLock) { + return sHeapDumpJavaFile; + } + } + + @Override + public boolean onCreate() { + synchronized (sLock) { + File dataDir = Environment.getDataDirectory(); + File systemDir = new File(dataDir, "system"); + File heapdumpDir = new File(systemDir, "heapdump"); + heapdumpDir.mkdir(); + sHeapDumpJavaFile = new File(heapdumpDir, "javaheap.bin"); + } + return true; + } + + @Override + public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { + return null; + } + + @Override + public String getType(Uri uri) { + return "application/octet-stream"; + } + + @Override + public Uri insert(Uri uri, ContentValues values) { + return null; + } + + @Override + public int delete(Uri uri, String selection, String[] selectionArgs) { + return 0; + } + + @Override + public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { + return 0; + } + + @Override + public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException { + synchronized (sLock) { + String path = uri.getEncodedPath(); + final String tag = Uri.decode(path); + if (tag.equals("/java")) { + return ParcelFileDescriptor.open(sHeapDumpJavaFile, + ParcelFileDescriptor.MODE_READ_ONLY); + } else { + throw new FileNotFoundException("Invalid path for " + uri); + } + } + } +} diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java index a6c616ae8de2..f374c86c7fa1 100644 --- a/services/core/java/com/android/server/am/ProcessRecord.java +++ b/services/core/java/com/android/server/am/ProcessRecord.java @@ -17,6 +17,7 @@ package com.android.server.am; import android.util.ArraySet; +import android.util.DebugUtils; import android.util.EventLog; import android.util.Slog; import com.android.internal.app.ProcessStats; @@ -248,8 +249,9 @@ final class ProcessRecord { pw.println(); pw.print(prefix); pw.print("adjSeq="); pw.print(adjSeq); pw.print(" lruSeq="); pw.print(lruSeq); - pw.print(" lastPss="); pw.print(lastPss); - pw.print(" lastCachedPss="); pw.println(lastCachedPss); + pw.print(" lastPss="); DebugUtils.printSizeValue(pw, lastPss*1024); + pw.print(" lastCachedPss="); DebugUtils.printSizeValue(pw, lastCachedPss*1024); + pw.println(); pw.print(prefix); pw.print("cached="); pw.print(cached); pw.print(" empty="); pw.println(empty); if (serviceb) { diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index 4b7f698ce32f..61a7263935de 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -3616,6 +3616,21 @@ public class AudioService extends IAudioService.Stub { final int index = (mIndexMap.valueAt(i) + 5) / 10; pw.print(index); } + pw.println(); + pw.print(" Devices: "); + final int devices = AudioSystem.getDevicesForStream(mStreamType); + int device, i = 0, n = 0; + // iterate all devices from 1 to DEVICE_OUT_DEFAULT exclusive + // (the default device is not returned by getDevicesForStream) + while ((device = 1 << i) != AudioSystem.DEVICE_OUT_DEFAULT) { + if ((devices & device) != 0) { + if (n++ > 0) { + pw.print(", "); + } + pw.print(AudioSystem.getOutputDeviceName(device)); + } + i++; + } } } diff --git a/services/core/java/com/android/server/pm/KeySetManagerService.java b/services/core/java/com/android/server/pm/KeySetManagerService.java index 773b1645a84e..aa6393276375 100644 --- a/services/core/java/com/android/server/pm/KeySetManagerService.java +++ b/services/core/java/com/android/server/pm/KeySetManagerService.java @@ -414,9 +414,9 @@ public class KeySetManagerService { // Get the package's known keys and KeySets ArraySet<Long> deletableKeySets = getOriginalKeySetsByPackageNameLPr(packageName); ArraySet<Long> deletableKeys = new ArraySet<Long>(); - ArraySet<Long> knownKeys = null; - for (Long ks : deletableKeySets) { - knownKeys = mKeySetMapping.get(ks); + final int origDksSize = deletableKeySets.size(); + for (int i = 0; i < origDksSize; i++) { + ArraySet<Long> knownKeys = mKeySetMapping.get(deletableKeySets.valueAt(i)); if (knownKeys != null) { deletableKeys.addAll(knownKeys); } @@ -429,9 +429,9 @@ public class KeySetManagerService { } ArraySet<Long> knownKeySets = getOriginalKeySetsByPackageNameLPr(pkgName); deletableKeySets.removeAll(knownKeySets); - knownKeys = new ArraySet<Long>(); - for (Long ks : knownKeySets) { - knownKeys = mKeySetMapping.get(ks); + final int kksSize = knownKeySets.size(); + for (int i = 0; i < kksSize; i++) { + ArraySet<Long> knownKeys = mKeySetMapping.get(knownKeySets.valueAt(i)); if (knownKeys != null) { deletableKeys.removeAll(knownKeys); } @@ -440,18 +440,22 @@ public class KeySetManagerService { // The remaining keys and KeySets are not relied on by any other // application and so can be safely deleted. - for (Long ks : deletableKeySets) { + final int dksSize = deletableKeySets.size(); + for (int i = 0; i < dksSize; i++) { + Long ks = deletableKeySets.valueAt(i); mKeySets.delete(ks); mKeySetMapping.delete(ks); } - for (Long keyId : deletableKeys) { - mPublicKeys.delete(keyId); + final int dkSize = deletableKeys.size(); + for (int i = 0; i < dkSize; i++) { + mPublicKeys.delete(deletableKeys.valueAt(i)); } // Now remove the deleted KeySets from each package's signingKeySets for (String pkgName : mPackages.keySet()) { PackageSetting p = mPackages.get(pkgName); - for (Long ks : deletableKeySets) { + for (int i = 0; i < dksSize; i++) { + Long ks = deletableKeySets.valueAt(i); p.keySetData.removeSigningKeySet(ks); } } diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index 27293925e8cb..e4f5e7d744ea 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -917,6 +917,7 @@ public class UserManagerService extends IUserManager.Stub { writeBoolean(serializer, restrictions, UserManager.DISALLOW_CREATE_WINDOWS); writeBoolean(serializer, restrictions, UserManager.DISALLOW_CROSS_PROFILE_COPY_PASTE); writeBoolean(serializer, restrictions, UserManager.DISALLOW_OUTGOING_BEAM); + writeBoolean(serializer, restrictions, UserManager.DISALLOW_WALLPAPER); serializer.endTag(null, TAG_RESTRICTIONS); } @@ -1063,6 +1064,7 @@ public class UserManagerService extends IUserManager.Stub { readBoolean(parser, restrictions, UserManager.DISALLOW_CREATE_WINDOWS); readBoolean(parser, restrictions, UserManager.DISALLOW_CROSS_PROFILE_COPY_PASTE); readBoolean(parser, restrictions, UserManager.DISALLOW_OUTGOING_BEAM); + readBoolean(parser, restrictions, UserManager.DISALLOW_WALLPAPER); } private void readBoolean(XmlPullParser parser, Bundle restrictions, diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index 1e64017ceaca..62e7af4f51be 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -539,6 +539,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { private boolean mAllowTheaterModeWakeFromLidSwitch; private boolean mAllowTheaterModeWakeFromWakeGesture; + // Whether to support long press from power button in non-interactive mode + private boolean mSupportLongPressPowerWhenNonInteractive; + // Whether to go to sleep entering theater mode from power button private boolean mGoToSleepOnButtonPressTheaterMode; @@ -885,12 +888,21 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } else { wakeUpFromPowerKey(event.getDownTime()); - final int maxCount = getMaxMultiPressPowerCount(); - if (maxCount <= 1) { - mPowerKeyHandled = true; - } else { + if (mSupportLongPressPowerWhenNonInteractive && hasLongPressOnPowerBehavior()) { + Message msg = mHandler.obtainMessage(MSG_POWER_LONG_PRESS); + msg.setAsynchronous(true); + mHandler.sendMessageDelayed(msg, + ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout()); mBeganFromNonInteractive = true; + } else { + final int maxCount = getMaxMultiPressPowerCount(); + + if (maxCount <= 1) { + mPowerKeyHandled = true; + } else { + mBeganFromNonInteractive = true; + } } } } @@ -1259,6 +1271,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { mGoToSleepOnButtonPressTheaterMode = mContext.getResources().getBoolean( com.android.internal.R.bool.config_goToSleepOnButtonPressTheaterMode); + mSupportLongPressPowerWhenNonInteractive = mContext.getResources().getBoolean( + com.android.internal.R.bool.config_supportLongPressPowerWhenNonInteractive); + mShortPressOnPowerBehavior = mContext.getResources().getInteger( com.android.internal.R.integer.config_shortPressOnPowerBehavior); mLongPressOnPowerBehavior = mContext.getResources().getInteger( diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java index c3fc195c2e3f..75c33af2a1e9 100644 --- a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java +++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java @@ -5,6 +5,7 @@ import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.content.pm.ActivityInfo; +import android.content.res.Resources; import android.graphics.PixelFormat; import android.os.Bundle; import android.os.IBinder; @@ -27,9 +28,6 @@ import com.android.internal.policy.IKeyguardShowCallback; * local or remote instances of keyguard. */ public class KeyguardServiceDelegate { - public static final String KEYGUARD_PACKAGE = "com.android.systemui"; - public static final String KEYGUARD_CLASS = "com.android.systemui.keyguard.KeyguardService"; - private static final String TAG = "KeyguardServiceDelegate"; private static final boolean DEBUG = true; @@ -111,10 +109,15 @@ public class KeyguardServiceDelegate { public void bindService(Context context) { Intent intent = new Intent(); - intent.setClassName(KEYGUARD_PACKAGE, KEYGUARD_CLASS); + final Resources resources = context.getApplicationContext().getResources(); + + final ComponentName keyguardComponent = ComponentName.unflattenFromString( + resources.getString(com.android.internal.R.string.config_keyguardComponent)); + intent.setComponent(keyguardComponent); + if (!context.bindServiceAsUser(intent, mKeyguardConnection, Context.BIND_AUTO_CREATE, UserHandle.OWNER)) { - Log.v(TAG, "*** Keyguard: can't bind to " + KEYGUARD_CLASS); + Log.v(TAG, "*** Keyguard: can't bind to " + keyguardComponent); mKeyguardState.showing = false; mKeyguardState.showingAndNotOccluded = false; mKeyguardState.secure = false; diff --git a/services/core/java/com/android/server/trust/TrustAgentWrapper.java b/services/core/java/com/android/server/trust/TrustAgentWrapper.java index 57b204d9a1b5..583cc6ba9d83 100644 --- a/services/core/java/com/android/server/trust/TrustAgentWrapper.java +++ b/services/core/java/com/android/server/trust/TrustAgentWrapper.java @@ -395,6 +395,7 @@ public class TrustAgentWrapper { } public void destroy() { + mContext.unregisterReceiver(mBroadcastReceiver); mHandler.removeMessages(MSG_RESTART_TIMEOUT); if (!mBound) { diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java index b48fadb278b2..99cf8df21509 100644 --- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java +++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java @@ -20,6 +20,7 @@ import static android.os.ParcelFileDescriptor.*; import android.app.ActivityManagerNative; import android.app.AppGlobals; +import android.app.AppOpsManager; import android.app.IUserSwitchObserver; import android.app.IWallpaperManager; import android.app.IWallpaperManagerCallback; @@ -164,6 +165,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { final IWindowManager mIWindowManager; final IPackageManager mIPackageManager; final MyPackageMonitor mMonitor; + final AppOpsManager mAppOpsManager; WallpaperData mLastWallpaper; /** @@ -478,6 +480,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { mIWindowManager = IWindowManager.Stub.asInterface( ServiceManager.getService(Context.WINDOW_SERVICE)); mIPackageManager = AppGlobals.getPackageManager(); + mAppOpsManager = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE); mMonitor = new MyPackageMonitor(); mMonitor.register(context, null, UserHandle.ALL, true); getWallpaperDir(UserHandle.USER_OWNER).mkdirs(); @@ -613,8 +616,12 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { } } - public void clearWallpaper() { + public void clearWallpaper(String callingPackage) { if (DEBUG) Slog.v(TAG, "clearWallpaper"); + checkPermission(android.Manifest.permission.SET_WALLPAPER); + if (!isWallpaperSupported(callingPackage)) { + return; + } synchronized (mLock) { clearWallpaperLocked(false, UserHandle.getCallingUserId(), null); } @@ -622,6 +629,9 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { void clearWallpaperLocked(boolean defaultFailed, int userId, IRemoteCallback reply) { WallpaperData wallpaper = mWallpaperMap.get(userId); + if (wallpaper == null) { + return; + } File f = new File(getWallpaperDir(userId), WALLPAPER); if (f.exists()) { f.delete(); @@ -668,6 +678,10 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { Binder.restoreCallingIdentity(ident); } for (UserInfo user: users) { + // ignore managed profiles + if (user.isManagedProfile()) { + continue; + } WallpaperData wd = mWallpaperMap.get(user.id); if (wd == null) { // User hasn't started yet, so load her settings to peek at the wallpaper @@ -690,8 +704,12 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { return p; } - public void setDimensionHints(int width, int height) throws RemoteException { + public void setDimensionHints(int width, int height, String callingPackage) + throws RemoteException { checkPermission(android.Manifest.permission.SET_WALLPAPER_HINTS); + if (!isWallpaperSupported(callingPackage)) { + return; + } synchronized (mLock) { int userId = UserHandle.getCallingUserId(); WallpaperData wallpaper = mWallpaperMap.get(userId); @@ -733,19 +751,30 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { public int getWidthHint() throws RemoteException { synchronized (mLock) { WallpaperData wallpaper = mWallpaperMap.get(UserHandle.getCallingUserId()); - return wallpaper.width; + if (wallpaper != null) { + return wallpaper.width; + } else { + return 0; + } } } public int getHeightHint() throws RemoteException { synchronized (mLock) { WallpaperData wallpaper = mWallpaperMap.get(UserHandle.getCallingUserId()); - return wallpaper.height; + if (wallpaper != null) { + return wallpaper.height; + } else { + return 0; + } } } - public void setDisplayPadding(Rect padding) { + public void setDisplayPadding(Rect padding, String callingPackage) { checkPermission(android.Manifest.permission.SET_WALLPAPER_HINTS); + if (!isWallpaperSupported(callingPackage)) { + return; + } synchronized (mLock) { int userId = UserHandle.getCallingUserId(); WallpaperData wallpaper = mWallpaperMap.get(userId); @@ -791,6 +820,9 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { wallpaperUserId = UserHandle.getUserId(callingUid); } WallpaperData wallpaper = mWallpaperMap.get(wallpaperUserId); + if (wallpaper == null) { + return null; + } try { if (outParams != null) { outParams.putInt("width", wallpaper.width); @@ -814,15 +846,18 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { int userId = UserHandle.getCallingUserId(); synchronized (mLock) { WallpaperData wallpaper = mWallpaperMap.get(userId); - if (wallpaper.connection != null) { + if (wallpaper != null && wallpaper.connection != null) { return wallpaper.connection.mInfo; } return null; } } - public ParcelFileDescriptor setWallpaper(String name) { + public ParcelFileDescriptor setWallpaper(String name, String callingPackage) { checkPermission(android.Manifest.permission.SET_WALLPAPER); + if (!isWallpaperSupported(callingPackage)) { + return null; + } synchronized (mLock) { if (DEBUG) Slog.v(TAG, "setWallpaper"); int userId = UserHandle.getCallingUserId(); @@ -868,6 +903,13 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { return null; } + public void setWallpaperComponentChecked(ComponentName name, String callingPackage) { + if (isWallpaperSupported(callingPackage)) { + setWallpaperComponent(name); + } + } + + // ToDo: Remove this version of the function public void setWallpaperComponent(ComponentName name) { checkPermission(android.Manifest.permission.SET_WALLPAPER_COMPONENT); synchronized (mLock) { @@ -1097,6 +1139,15 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { } } + /** + * Certain user types do not support wallpapers (e.g. managed profiles). The check is + * implemented through through the OP_WRITE_WALLPAPER AppOp. + */ + public boolean isWallpaperSupported(String callingPackage) { + return mAppOpsManager.checkOpNoThrow(AppOpsManager.OP_WRITE_WALLPAPER, Binder.getCallingUid(), + callingPackage) == AppOpsManager.MODE_ALLOWED; + } + private static JournaledFile makeJournaledFile(int userId) { final String base = new File(getWallpaperDir(userId), WALLPAPER_INFO).getAbsolutePath(); return new JournaledFile(new File(base), new File(base + ".tmp")); @@ -1174,7 +1225,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { private void loadSettingsLocked(int userId) { if (DEBUG) Slog.v(TAG, "loadSettingsLocked"); - + JournaledFile journal = makeJournaledFile(userId); FileInputStream stream = null; File file = journal.chooseForRead(); diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index fc9ff76c7b5d..00d7971ce959 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -51,6 +51,7 @@ import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; import android.content.pm.UserInfo; import android.database.ContentObserver; +import android.graphics.Bitmap; import android.hardware.usb.UsbManager; import android.media.AudioManager; import android.media.IAudioService; @@ -179,6 +180,14 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { DEVICE_OWNER_USER_RESTRICTIONS.add(UserManager.DISALLOW_SMS); } + // The following user restrictions cannot be changed by any active admin, including device + // owner and profile owner. + private static final Set<String> IMMUTABLE_USER_RESTRICTIONS; + static { + IMMUTABLE_USER_RESTRICTIONS = new HashSet(); + IMMUTABLE_USER_RESTRICTIONS.add(UserManager.DISALLOW_WALLPAPER); + } + private static final Set<String> SECURE_SETTINGS_WHITELIST; private static final Set<String> SECURE_SETTINGS_DEVICEOWNER_WHITELIST; private static final Set<String> GLOBAL_SETTINGS_WHITELIST; @@ -4952,6 +4961,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { && DEVICE_OWNER_USER_RESTRICTIONS.contains(key)) { throw new SecurityException("Profile owners cannot set user restriction " + key); } + if (IMMUTABLE_USER_RESTRICTIONS.contains(key)) { + throw new SecurityException("User restriction " + key + " cannot be changed"); + } boolean alreadyRestricted = mUserManager.hasUserRestriction(key, user); IAudioService iAudioService = null; @@ -5491,6 +5503,22 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } + @Override + public void setUserIcon(ComponentName who, Bitmap icon) { + synchronized (this) { + Preconditions.checkNotNull(who, "ComponentName is null"); + getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); + + int userId = UserHandle.getCallingUserId(); + long id = Binder.clearCallingIdentity(); + try { + mUserManager.setUserIcon(userId, icon); + } finally { + restoreCallingIdentity(id); + } + } + } + /** * We need to update the internal state of whether a user has completed setup once. After * that, we ignore any changes that reset the Settings.Secure.USER_SETUP_COMPLETE changes diff --git a/services/usb/java/com/android/server/usb/UsbMidiDevice.java b/services/usb/java/com/android/server/usb/UsbMidiDevice.java index a6e9677a90c4..51d61bbb4b38 100644 --- a/services/usb/java/com/android/server/usb/UsbMidiDevice.java +++ b/services/usb/java/com/android/server/usb/UsbMidiDevice.java @@ -21,7 +21,6 @@ import android.media.midi.MidiDeviceInfo; import android.media.midi.MidiDeviceServer; import android.media.midi.MidiDispatcher; import android.media.midi.MidiManager; -import android.media.midi.MidiPort; import android.media.midi.MidiReceiver; import android.media.midi.MidiSender; import android.os.Bundle; @@ -46,6 +45,8 @@ public final class UsbMidiDevice implements Closeable { private final MidiReceiver[] mInputPortReceivers; + private static final int BUFFER_SIZE = 512; + // for polling multiple FileDescriptors for MIDI events private final StructPollfd[] mPollFDs; // streams for reading from ALSA driver @@ -102,7 +103,7 @@ public final class UsbMidiDevice implements Closeable { final int portF = port; mInputPortReceivers[port] = new MidiReceiver() { @Override - public void post(byte[] data, int offset, int count, long timestamp) + public void receive(byte[] data, int offset, int count, long timestamp) throws IOException { // FIXME - timestamps are ignored, future posting not supported yet. mOutputStreams[portF].write(data, offset, count); @@ -130,7 +131,7 @@ public final class UsbMidiDevice implements Closeable { new Thread() { @Override public void run() { - byte[] buffer = new byte[MidiPort.MAX_PACKET_DATA_SIZE]; + byte[] buffer = new byte[BUFFER_SIZE]; try { boolean done = false; while (!done) { @@ -143,7 +144,7 @@ public final class UsbMidiDevice implements Closeable { int count = mInputStreams[index].read(buffer); long timestamp = System.nanoTime(); - outputReceivers[index].post(buffer, 0, count, timestamp); + outputReceivers[index].receive(buffer, 0, count, timestamp); } else if ((pfd.revents & (OsConstants.POLLERR | OsConstants.POLLHUP)) != 0) { done = true; diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 0a4b7877836d..f3b2d2e322ea 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -3716,6 +3716,34 @@ public class TelephonyManager { } /** + * Whether the device supports configuring the DTMF tone length. + * + * @return {@code true} if the DTMF tone length can be changed, and {@code false} otherwise. + */ + public boolean canChangeDtmfToneLength() { + try { + return getITelephony().canChangeDtmfToneLength(); + } catch (RemoteException e) { + Log.e(TAG, "Error calling ITelephony#canChangeDtmfToneLength", e); + } + return false; + } + + /** + * Whether the device is a world phone. + * + * @return {@code true} if the device is a world phone, and {@code false} otherwise. + */ + public boolean isWorldPhone() { + try { + return getITelephony().isWorldPhone(); + } catch (RemoteException e) { + Log.e(TAG, "Error calling ITelephony#isWorldPhone", e); + } + return false; + } + + /** * This function retrieves value for setting "name+subId", and if that is not found * retrieves value for setting "name", and if that is not found uses def as default * diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl index 62c8746f7ea9..3769deed233d 100644 --- a/telephony/java/com/android/internal/telephony/ITelephony.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl @@ -863,11 +863,25 @@ interface ITelephony { /** * Whether video calling has been enabled by the user. * - * @return {@code True} if the user has enabled video calling, {@code false} otherwise. + * @return {@code true} if the user has enabled video calling, {@code false} otherwise. */ boolean isVideoCallingEnabled(); /** + * Whether the DTMF tone length can be changed. + * + * @return {@code true} if the DTMF tone length can be changed. + */ + boolean canChangeDtmfToneLength(); + + /** + * Whether the device is a world phone. + * + * @return {@code true} if the devices is a world phone. + */ + boolean isWorldPhone(); + + /** * Get IMS Registration Status */ boolean isImsRegistered(); diff --git a/tools/aapt/Images.cpp b/tools/aapt/Images.cpp index 5ab177ba490a..063b4e6801a0 100644 --- a/tools/aapt/Images.cpp +++ b/tools/aapt/Images.cpp @@ -481,8 +481,9 @@ static void get_outline(image_info* image) // assuming the image is a round rect, compute the radius by marching // diagonally from the top left corner towards the center - image->outlineAlpha = max(max_alpha_over_row(image->rows[innerMidY], innerStartX, innerEndX), - max_alpha_over_col(image->rows, innerMidX, innerStartY, innerStartY)); + image->outlineAlpha = std::max( + max_alpha_over_row(image->rows[innerMidY], innerStartX, innerEndX), + max_alpha_over_col(image->rows, innerMidX, innerStartY, innerStartY)); int diagonalInset = 0; find_max_opacity(image->rows, innerStartX, innerStartY, innerMidX, innerMidY, 1, 1, diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp index 6fbc17cabda9..941a2884e2a6 100644 --- a/tools/aapt/ResourceTable.cpp +++ b/tools/aapt/ResourceTable.cpp @@ -1807,7 +1807,7 @@ status_t ResourceTable::addIncludedResources(Bundle* bundle, const sp<AaptAssets } const ResTable& featureTable = featureAssetManager.getResources(false); - mTypeIdOffset = max(mTypeIdOffset, + mTypeIdOffset = std::max(mTypeIdOffset, findLargestTypeIdForPackage(featureTable, mAssetsPackage)); } @@ -2703,20 +2703,16 @@ ResourceTable::validateLocalizations(void) const String8 defaultLocale; // For all strings... - for (map<String16, map<String8, SourcePos> >::iterator nameIter = mLocalizations.begin(); - nameIter != mLocalizations.end(); - nameIter++) { - const map<String8, SourcePos>& configSrcMap = nameIter->second; + for (const auto& nameIter : mLocalizations) { + const std::map<String8, SourcePos>& configSrcMap = nameIter.second; // Look for strings with no default localization if (configSrcMap.count(defaultLocale) == 0) { SourcePos().warning("string '%s' has no default translation.", - String8(nameIter->first).string()); + String8(nameIter.first).string()); if (mBundle->getVerbose()) { - for (map<String8, SourcePos>::const_iterator locales = configSrcMap.begin(); - locales != configSrcMap.end(); - locales++) { - locales->second.printf("locale %s found", locales->first.string()); + for (const auto& locale : configSrcMap) { + locale.second.printf("locale %s found", locale.first.string()); } } // !!! TODO: throw an error here in some circumstances @@ -2727,8 +2723,8 @@ ResourceTable::validateLocalizations(void) const char* allConfigs = mBundle->getConfigurations().string(); const char* start = allConfigs; const char* comma; - - set<String8> missingConfigs; + + std::set<String8> missingConfigs; AaptLocaleValue locale; do { String8 config; @@ -2762,13 +2758,11 @@ ResourceTable::validateLocalizations(void) if (!missingConfigs.empty()) { String8 configStr; - for (set<String8>::iterator iter = missingConfigs.begin(); - iter != missingConfigs.end(); - iter++) { - configStr.appendFormat(" %s", iter->string()); + for (const auto& iter : missingConfigs) { + configStr.appendFormat(" %s", iter.string()); } SourcePos().warning("string '%s' is missing %u required localizations:%s", - String8(nameIter->first).string(), + String8(nameIter.first).string(), (unsigned int)missingConfigs.size(), configStr.string()); } diff --git a/tools/aapt/ResourceTable.h b/tools/aapt/ResourceTable.h index eef0ae10e60d..96442248d296 100644 --- a/tools/aapt/ResourceTable.h +++ b/tools/aapt/ResourceTable.h @@ -17,8 +17,6 @@ #include "StringPool.h" #include "Symbol.h" -using namespace std; - class XMLNode; class ResourceTable; @@ -29,7 +27,7 @@ enum { XML_COMPILE_STRIP_WHITESPACE = 1<<3, XML_COMPILE_STRIP_RAW_VALUES = 1<<4, XML_COMPILE_UTF8 = 1<<5, - + XML_COMPILE_STANDARD_RESOURCE = XML_COMPILE_STRIP_COMMENTS | XML_COMPILE_ASSIGN_ATTRIBUTE_IDS | XML_COMPILE_STRIP_WHITESPACE | XML_COMPILE_STRIP_RAW_VALUES @@ -116,7 +114,7 @@ public: * and would mess up iteration order for the existing * resources. */ - queue<CompileResourceWorkItem>& getWorkQueue() { + std::queue<CompileResourceWorkItem>& getWorkQueue() { return mWorkQueue; } @@ -587,10 +585,10 @@ private: size_t mNumLocal; SourcePos mCurrentXmlPos; Bundle* mBundle; - + // key = string resource name, value = set of locales in which that name is defined - map<String16, map<String8, SourcePos> > mLocalizations; - queue<CompileResourceWorkItem> mWorkQueue; + std::map<String16, std::map<String8, SourcePos>> mLocalizations; + std::queue<CompileResourceWorkItem> mWorkQueue; }; #endif diff --git a/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java index 8d24d38711c2..970b9d042f60 100644 --- a/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java @@ -76,13 +76,6 @@ public final class Bitmap_Delegate { // ---- Public Helper methods ---- /** - * Returns the native delegate associated to a given {@link Bitmap_Delegate} object. - */ - public static Bitmap_Delegate getDelegate(Bitmap bitmap) { - return sManager.getDelegate(bitmap.mNativeBitmap); - } - - /** * Returns the native delegate associated to a given an int referencing a {@link Bitmap} object. */ public static Bitmap_Delegate getDelegate(long native_bitmap) { @@ -187,19 +180,6 @@ public final class Bitmap_Delegate { return createBitmap(delegate, createFlags, density.getDpiValue()); } - /** - * Returns the {@link BufferedImage} used by the delegate of the given {@link Bitmap}. - */ - public static BufferedImage getImage(Bitmap bitmap) { - // get the delegate from the native int. - Bitmap_Delegate delegate = sManager.getDelegate(bitmap.mNativeBitmap); - if (delegate == null) { - return null; - } - - return delegate.mImage; - } - public static int getBufferedImageType(int nativeBitmapConfig) { switch (Config.nativeToConfig(nativeBitmapConfig)) { case ALPHA_8: diff --git a/wifi/java/android/net/wifi/WifiActivityEnergyInfo.java b/wifi/java/android/net/wifi/WifiActivityEnergyInfo.java index 533b8bca10ac..626346304437 100644 --- a/wifi/java/android/net/wifi/WifiActivityEnergyInfo.java +++ b/wifi/java/android/net/wifi/WifiActivityEnergyInfo.java @@ -21,37 +21,37 @@ import android.os.Parcelable; /** * Record of energy and activity information from controller and - * underlying wifi stack state.Timestamp the record with system - * time + * underlying wifi stack state. Timestamp the record with elapsed + * real-time. * @hide */ public final class WifiActivityEnergyInfo implements Parcelable { + private final long mTimestamp; private final int mStackState; private final int mControllerTxTimeMs; private final int mControllerRxTimeMs; private final int mControllerIdleTimeMs; private final int mControllerEnergyUsed; - private final long timestamp; public static final int STACK_STATE_INVALID = 0; public static final int STACK_STATE_STATE_ACTIVE = 1; public static final int STACK_STATE_STATE_SCANNING = 2; public static final int STACK_STATE_STATE_IDLE = 3; - public WifiActivityEnergyInfo(int stackState, int txTime, int rxTime, - int idleTime, int energyUsed) { + public WifiActivityEnergyInfo(long timestamp, int stackState, + int txTime, int rxTime, int idleTime, int energyUsed) { + mTimestamp = timestamp; mStackState = stackState; mControllerTxTimeMs = txTime; mControllerRxTimeMs = rxTime; mControllerIdleTimeMs = idleTime; mControllerEnergyUsed = energyUsed; - timestamp = System.currentTimeMillis(); } @Override public String toString() { return "WifiActivityEnergyInfo{" - + " timestamp=" + timestamp + + " timestamp=" + mTimestamp + " mStackState=" + mStackState + " mControllerTxTimeMs=" + mControllerTxTimeMs + " mControllerRxTimeMs=" + mControllerRxTimeMs @@ -63,13 +63,14 @@ public final class WifiActivityEnergyInfo implements Parcelable { public static final Parcelable.Creator<WifiActivityEnergyInfo> CREATOR = new Parcelable.Creator<WifiActivityEnergyInfo>() { public WifiActivityEnergyInfo createFromParcel(Parcel in) { + long timestamp = in.readLong(); int stackState = in.readInt(); int txTime = in.readInt(); int rxTime = in.readInt(); int idleTime = in.readInt(); int energyUsed = in.readInt(); - return new WifiActivityEnergyInfo(stackState, txTime, rxTime, - idleTime, energyUsed); + return new WifiActivityEnergyInfo(timestamp, stackState, + txTime, rxTime, idleTime, energyUsed); } public WifiActivityEnergyInfo[] newArray(int size) { return new WifiActivityEnergyInfo[size]; @@ -77,6 +78,7 @@ public final class WifiActivityEnergyInfo implements Parcelable { }; public void writeToParcel(Parcel out, int flags) { + out.writeLong(mTimestamp); out.writeInt(mStackState); out.writeInt(mControllerTxTimeMs); out.writeInt(mControllerRxTimeMs); @@ -127,7 +129,7 @@ public final class WifiActivityEnergyInfo implements Parcelable { * @return timestamp(wall clock) of record creation */ public long getTimeStamp() { - return timestamp; + return mTimestamp; } /** |