diff options
350 files changed, 16692 insertions, 12440 deletions
@@ -26,7 +26,10 @@ LOCAL_PATH := $(call my-dir) # TODO: find a more appropriate way to do this. framework_res_source_path := APPS/framework-res_intermediates/src -# the library +# Build the master framework library. +# The framework contains too many method references (>64K) for poor old DEX. +# So we first build the framework as a monolithic static library then split it +# up into smaller pieces. # ============================================================ include $(CLEAR_VARS) @@ -39,14 +42,6 @@ LOCAL_SRC_FILES += \ core/java/android/speech/tts/EventLogTags.logtags \ core/java/android/webkit/EventLogTags.logtags \ -# The following filters out code we are temporarily not including at all. -# TODO: Move AWT and beans (and associated harmony code) back into libcore. -# TODO: Maybe remove javax.microedition entirely? -# TODO: Move SyncML (org.mobilecontrol.*) into its own library. -LOCAL_SRC_FILES := $(filter-out \ - org/mobilecontrol/% \ - ,$(LOCAL_SRC_FILES)) - ## READ ME: ######################################################## ## ## When updating this list of aidl files, consider if that aidl is @@ -159,13 +154,15 @@ LOCAL_SRC_FILES += \ core/java/android/os/IUserManager.aidl \ core/java/android/os/IVibratorService.aidl \ core/java/android/service/notification/INotificationListener.aidl \ + core/java/android/print/ILayoutResultCallback.aidl \ + core/java/android/print/IPrintDocumentAdapter.aidl \ core/java/android/print/IPrinterDiscoveryObserver.aidl \ - core/java/android/print/IPrintAdapter.aidl \ core/java/android/print/IPrintClient.aidl \ - core/java/android/print/IPrintResultCallback.aidl \ core/java/android/print/IPrintManager.aidl \ - core/java/android/print/IPrintSpoolerService.aidl \ - core/java/android/print/IPrintSpoolerServiceCallbacks.aidl \ + core/java/android/print/IPrintSpooler.aidl \ + core/java/android/print/IPrintSpoolerCallbacks.aidl \ + core/java/android/print/IPrintSpoolerClient.aidl \ + core/java/android/print/IWriteResultCallback.aidl \ core/java/android/printservice/IPrintService.aidl \ core/java/android/printservice/IPrintServiceClient.aidl \ core/java/android/service/dreams/IDreamManager.aidl \ @@ -256,8 +253,6 @@ LOCAL_SRC_FILES += \ telephony/java/com/android/internal/telephony/IWapPushManager.aidl \ wifi/java/android/net/wifi/IWifiManager.aidl \ wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl -# - # FRAMEWORKS_BASE_JAVA_SRC_DIRS comes from build/core/pathmap.mk LOCAL_AIDL_INCLUDES += $(FRAMEWORKS_BASE_JAVA_SRC_DIRS) @@ -270,32 +265,65 @@ LOCAL_INTERMEDIATE_SOURCES := \ LOCAL_NO_STANDARD_LIBRARIES := true LOCAL_JAVA_LIBRARIES := bouncycastle conscrypt core core-junit ext okhttp +LOCAL_MODULE := framework-base + +LOCAL_JAR_EXCLUDE_FILES := none + +include $(BUILD_STATIC_JAVA_LIBRARY) + +# Make sure that R.java and Manifest.java are built before we build +# the source for this library. +framework_res_R_stamp := \ + $(call intermediates-dir-for,APPS,framework-res,,COMMON)/src/R.stamp +$(full_classes_compiled_jar): $(framework_res_R_stamp) + +# Build part 1 of the framework library. +# ============================================================ +include $(CLEAR_VARS) + LOCAL_MODULE := framework LOCAL_MODULE_CLASS := JAVA_LIBRARIES +LOCAL_NO_STANDARD_LIBRARIES := true +LOCAL_STATIC_JAVA_LIBRARIES := framework-base +LOCAL_DX_FLAGS := --core-library + +# Packages to include, use \* wildcard to include descendants. +LOCAL_JAR_PACKAGES := android\* # List of classes and interfaces which should be loaded by the Zygote. LOCAL_JAVA_RESOURCE_FILES += $(LOCAL_PATH)/preloaded-classes -#LOCAL_JARJAR_RULES := $(LOCAL_PATH)/jarjar-rules.txt +include $(BUILD_JAVA_LIBRARY) +framework_module := $(LOCAL_INSTALLED_MODULE) +# Build part 2 of the framework library. +# ============================================================ +include $(CLEAR_VARS) + +LOCAL_MODULE := framework2 +LOCAL_MODULE_CLASS := JAVA_LIBRARIES +LOCAL_NO_STANDARD_LIBRARIES := true +LOCAL_STATIC_JAVA_LIBRARIES := framework-base LOCAL_DX_FLAGS := --core-library -include $(BUILD_JAVA_LIBRARY) +# Packages to include, use \* wildcard to include descendants. +LOCAL_JAR_PACKAGES := com\* javax\* -# Make sure that R.java and Manifest.java are built before we build -# the source for this library. -framework_res_R_stamp := \ - $(call intermediates-dir-for,APPS,framework-res,,COMMON)/src/R.stamp -$(full_classes_compiled_jar): $(framework_res_R_stamp) +include $(BUILD_JAVA_LIBRARY) +framework2_module := $(LOCAL_INSTALLED_MODULE) -# Make sure that framework-res is installed when framework is. -$(LOCAL_INSTALLED_MODULE): | $(dir $(LOCAL_INSTALLED_MODULE))framework-res.apk +# Make sure that all framework modules are installed when framework is. +# ============================================================ +$(framework_module): | $(dir $(framework_module))framework-res.apk +$(framework_module): | $(dir $(framework_module))framework2.jar -framework_built := $(call java-lib-deps,framework) +framework_built := $(call java-lib-deps,framework framework2) -# AIDL files to be preprocessed and included in the SDK, -# relative to the root of the build tree. +# Copy AIDL files to be preprocessed and included in the SDK, +# specified relative to the root of the build tree. # ============================================================ +include $(CLEAR_VARS) + aidl_files := \ frameworks/base/core/java/android/accounts/IAccountManager.aidl \ frameworks/base/core/java/android/accounts/IAccountManagerResponse.aidl \ @@ -441,6 +469,7 @@ framework_docs_LOCAL_API_CHECK_JAVA_LIBRARIES := \ okhttp \ ext \ framework \ + framework2 \ mms-common \ telephony-common \ voip-common @@ -477,7 +506,7 @@ framework_docs_LOCAL_DROIDDOC_OPTIONS := \ -overview $(LOCAL_PATH)/core/java/overview.html framework_docs_LOCAL_API_CHECK_ADDITIONAL_JAVA_DIR:= \ - $(call intermediates-dir-for,JAVA_LIBRARIES,framework,,COMMON) + $(call intermediates-dir-for,JAVA_LIBRARIES,framework-base,,COMMON) framework_docs_LOCAL_ADDITIONAL_JAVA_DIR:= \ $(framework_docs_LOCAL_API_CHECK_ADDITIONAL_JAVA_DIR) \ @@ -759,7 +788,7 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES:=$(framework_docs_LOCAL_SRC_FILES) LOCAL_INTERMEDIATE_SOURCES:=$(framework_docs_LOCAL_INTERMEDIATE_SOURCES) -LOCAL_JAVA_LIBRARIES:=$(framework_docs_LOCAL_JAVA_LIBRARIES) framework +LOCAL_JAVA_LIBRARIES:=$(framework_docs_LOCAL_JAVA_LIBRARIES) LOCAL_MODULE_CLASS:=$(framework_docs_LOCAL_MODULE_CLASS) LOCAL_DROIDDOC_SOURCE_PATH:=$(framework_docs_LOCAL_DROIDDOC_SOURCE_PATH) LOCAL_DROIDDOC_HTML_DIR:=$(framework_docs_LOCAL_DROIDDOC_HTML_DIR) diff --git a/CleanSpec.mk b/CleanSpec.mk index 893daf1..58de3f3 100644 --- a/CleanSpec.mk +++ b/CleanSpec.mk @@ -163,6 +163,7 @@ $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framew $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates) $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates) $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/framework-res_intermediates) +$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates) # ************************************************ # NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST # ************************************************ diff --git a/api/current.txt b/api/current.txt index 711c87c..5607eab 100644 --- a/api/current.txt +++ b/api/current.txt @@ -259,6 +259,7 @@ package android { field public static final int addPrintersActivity = 16843747; // 0x10103e3 field public static final int addStatesFromChildren = 16842992; // 0x10100f0 field public static final int adjustViewBounds = 16843038; // 0x101011e + field public static final int aid = 16843750; // 0x10103e6 field public static final int alertDialogIcon = 16843605; // 0x1010355 field public static final int alertDialogStyle = 16842845; // 0x101005d field public static final int alertDialogTheme = 16843529; // 0x1010309 @@ -793,6 +794,7 @@ package android { field public static final int path = 16842794; // 0x101002a field public static final int pathPattern = 16842796; // 0x101002c field public static final int pathPrefix = 16842795; // 0x101002b + field public static final int paymentService = 16843749; // 0x10103e5 field public static final int permission = 16842758; // 0x1010006 field public static final int permissionFlags = 16843719; // 0x10103c7 field public static final int permissionGroup = 16842762; // 0x101000a @@ -3052,17 +3054,19 @@ package android.app { public class AlarmManager { method public void cancel(android.app.PendingIntent); method public void set(int, long, android.app.PendingIntent); - method public void setInexactRepeating(int, long, long, android.app.PendingIntent); + method public void setExact(int, long, android.app.PendingIntent); + method public deprecated void setInexactRepeating(int, long, long, android.app.PendingIntent); method public void setRepeating(int, long, long, android.app.PendingIntent); method public void setTime(long); method public void setTimeZone(java.lang.String); + method public void setWindow(int, long, long, android.app.PendingIntent); field public static final int ELAPSED_REALTIME = 3; // 0x3 field public static final int ELAPSED_REALTIME_WAKEUP = 2; // 0x2 - field public static final long INTERVAL_DAY = 86400000L; // 0x5265c00L - field public static final long INTERVAL_FIFTEEN_MINUTES = 900000L; // 0xdbba0L - field public static final long INTERVAL_HALF_DAY = 43200000L; // 0x2932e00L - field public static final long INTERVAL_HALF_HOUR = 1800000L; // 0x1b7740L - field public static final long INTERVAL_HOUR = 3600000L; // 0x36ee80L + field public static final deprecated long INTERVAL_DAY = 86400000L; // 0x5265c00L + field public static final deprecated long INTERVAL_FIFTEEN_MINUTES = 900000L; // 0xdbba0L + field public static final deprecated long INTERVAL_HALF_DAY = 43200000L; // 0x2932e00L + field public static final deprecated long INTERVAL_HALF_HOUR = 1800000L; // 0x1b7740L + field public static final deprecated long INTERVAL_HOUR = 3600000L; // 0x36ee80L field public static final int RTC = 1; // 0x1 field public static final int RTC_WAKEUP = 0; // 0x0 } @@ -7114,6 +7118,7 @@ package android.content.pm { field public static final java.lang.String FEATURE_LOCATION_NETWORK = "android.hardware.location.network"; field public static final java.lang.String FEATURE_MICROPHONE = "android.hardware.microphone"; field public static final java.lang.String FEATURE_NFC = "android.hardware.nfc"; + field public static final java.lang.String FEATURE_NFC_HCE = "android.hardware.nfc.hce"; field public static final java.lang.String FEATURE_SCREEN_LANDSCAPE = "android.hardware.screen.landscape"; field public static final java.lang.String FEATURE_SCREEN_PORTRAIT = "android.hardware.screen.portrait"; field public static final java.lang.String FEATURE_SENSOR_ACCELEROMETER = "android.hardware.sensor.accelerometer"; @@ -8742,13 +8747,17 @@ package android.graphics { method public final boolean isPremultiplied(); method public final boolean isRecycled(); method public void prepareToDraw(); + method public void reconfigure(int, int, android.graphics.Bitmap.Config); method public void recycle(); method public boolean sameAs(android.graphics.Bitmap); + method public void setConfig(android.graphics.Bitmap.Config); method public void setDensity(int); method public void setHasAlpha(boolean); method public final void setHasMipMap(boolean); + method public void setHeight(int); method public void setPixel(int, int, int); method public void setPixels(int[], int, int, int, int, int, int); + method public void setWidth(int); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator CREATOR; field public static final int DENSITY_NONE = 0; // 0x0 @@ -11609,6 +11618,7 @@ package android.media { field public static final int FX_FOCUS_NAVIGATION_RIGHT = 4; // 0x4 field public static final int FX_FOCUS_NAVIGATION_UP = 1; // 0x1 field public static final int FX_KEYPRESS_DELETE = 7; // 0x7 + field public static final int FX_KEYPRESS_INVALID = 9; // 0x9 field public static final int FX_KEYPRESS_RETURN = 8; // 0x8 field public static final int FX_KEYPRESS_SPACEBAR = 6; // 0x6 field public static final int FX_KEYPRESS_STANDARD = 5; // 0x5 @@ -13462,6 +13472,7 @@ package android.net { public class LocalSocket implements java.io.Closeable { ctor public LocalSocket(); + ctor public LocalSocket(int); method public void bind(android.net.LocalSocketAddress) throws java.io.IOException; method public void close() throws java.io.IOException; method public void connect(android.net.LocalSocketAddress) throws java.io.IOException; @@ -13487,6 +13498,9 @@ package android.net { method public void setSoTimeout(int) throws java.io.IOException; method public void shutdownInput() throws java.io.IOException; method public void shutdownOutput() throws java.io.IOException; + field public static final int SOCKET_DGRAM = 1; // 0x1 + field public static final int SOCKET_SEQPACKET = 3; // 0x3 + field public static final int SOCKET_STREAM = 2; // 0x2 } public class LocalSocketAddress { @@ -14731,6 +14745,31 @@ package android.nfc { } +package android.nfc.cardemulation { + + public abstract class HostApduService extends android.app.Service { + ctor public HostApduService(); + method public final android.os.IBinder onBind(android.content.Intent); + method public abstract void onDeactivated(int); + method public abstract byte[] processCommandApdu(byte[], int); + method public final void sendResponseApdu(byte[]); + field public static final int DEACTIVATION_DESELECTED = 1; // 0x1 + field public static final int DEACTIVATION_LINK_LOSS = 0; // 0x0 + field public static final java.lang.String SERVICE_INTERFACE = "android.nfc.HostApduService"; + field public static final java.lang.String SERVICE_META_DATA = "android.nfc.HostApduService"; + } + + public abstract class SeApduService extends android.app.Service { + ctor public SeApduService(); + method public abstract void onAidSelected(byte[]); + method public final android.os.IBinder onBind(android.content.Intent); + method public abstract void onHciTransactionEvent(byte[], byte[]); + field public static final java.lang.String SERVICE_INTERFACE = "android.nfc.SeApduService"; + field public static final java.lang.String SERVICE_META_DATA = "android.nfc.SeApduService"; + } + +} + package android.nfc.tech { abstract class BasicTagTechnology implements android.nfc.tech.TagTechnology { @@ -18016,6 +18055,7 @@ package android.os { method public void setUserRestriction(java.lang.String, boolean); method public void setUserRestrictions(android.os.Bundle); method public void setUserRestrictions(android.os.Bundle, android.os.UserHandle); + field public static final java.lang.String DISALLOW_APP_RESTRICTIONS = "no_app_restrictions"; field public static final java.lang.String DISALLOW_CONFIG_BLUETOOTH = "no_config_bluetooth"; field public static final java.lang.String DISALLOW_CONFIG_CREDENTIALS = "no_config_credentials"; field public static final java.lang.String DISALLOW_CONFIG_WIFI = "no_config_wifi"; @@ -18448,36 +18488,6 @@ package android.print { field public static final android.os.Parcelable.Creator CREATOR; } - public abstract class PrintAdapter { - ctor public PrintAdapter(); - method public abstract android.print.PrintAdapterInfo getInfo(); - method public void onFinish(); - method public abstract void onPrint(java.util.List<android.print.PageRange>, java.io.FileDescriptor, android.os.CancellationSignal, android.print.PrintAdapter.PrintResultCallback); - method public boolean onPrintAttributesChanged(android.print.PrintAttributes); - method public void onStart(); - } - - public static abstract class PrintAdapter.PrintResultCallback { - method public void onPrintFailed(java.lang.CharSequence); - method public void onPrintFinished(java.util.List<android.print.PageRange>); - } - - public final class PrintAdapterInfo implements android.os.Parcelable { - method public int describeContents(); - method public int getFlags(); - method public int getPageCount(); - method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; - field public static final int PAGE_COUNT_UNKNOWN = -1; // 0xffffffff - } - - public static final class PrintAdapterInfo.Builder { - ctor public PrintAdapterInfo.Builder(); - method public android.print.PrintAdapterInfo create(); - method public android.print.PrintAdapterInfo.Builder setFlags(int); - method public android.print.PrintAdapterInfo.Builder setPageCount(int); - } - public final class PrintAttributes implements android.os.Parcelable { method public void clear(); method public int describeContents(); @@ -18528,64 +18538,103 @@ package android.print { } public static final class PrintAttributes.MediaSize { - ctor public PrintAttributes.MediaSize(java.lang.String, java.lang.String, int, int, int); + ctor public PrintAttributes.MediaSize(java.lang.String, java.lang.CharSequence, int, int); + method public static android.print.PrintAttributes.MediaSize createMediaSize(android.content.pm.PackageManager, int); method public int getHeightMils(); method public java.lang.String getId(); - method public java.lang.CharSequence getLabel(android.content.pm.PackageManager); + method public java.lang.CharSequence getLabel(); method public int getWidthMils(); - field public static final android.print.PrintAttributes.MediaSize ISO_A0; - field public static final android.print.PrintAttributes.MediaSize ISO_A1; - field public static final android.print.PrintAttributes.MediaSize ISO_A10; - field public static final android.print.PrintAttributes.MediaSize ISO_A2; - field public static final android.print.PrintAttributes.MediaSize ISO_A3; - field public static final android.print.PrintAttributes.MediaSize ISO_A4; - field public static final android.print.PrintAttributes.MediaSize ISO_A5; - field public static final android.print.PrintAttributes.MediaSize ISO_A6; - field public static final android.print.PrintAttributes.MediaSize ISO_A7; - field public static final android.print.PrintAttributes.MediaSize ISO_A8; - field public static final android.print.PrintAttributes.MediaSize ISO_A9; - field public static final android.print.PrintAttributes.MediaSize ISO_B0; - field public static final android.print.PrintAttributes.MediaSize ISO_B1; - field public static final android.print.PrintAttributes.MediaSize ISO_B10; - field public static final android.print.PrintAttributes.MediaSize ISO_B2; - field public static final android.print.PrintAttributes.MediaSize ISO_B3; - field public static final android.print.PrintAttributes.MediaSize ISO_B4; - field public static final android.print.PrintAttributes.MediaSize ISO_B5; - field public static final android.print.PrintAttributes.MediaSize ISO_B6; - field public static final android.print.PrintAttributes.MediaSize ISO_B7; - field public static final android.print.PrintAttributes.MediaSize ISO_B8; - field public static final android.print.PrintAttributes.MediaSize ISO_B9; - field public static final android.print.PrintAttributes.MediaSize ISO_C0; - field public static final android.print.PrintAttributes.MediaSize ISO_C1; - field public static final android.print.PrintAttributes.MediaSize ISO_C10; - field public static final android.print.PrintAttributes.MediaSize ISO_C2; - field public static final android.print.PrintAttributes.MediaSize ISO_C3; - field public static final android.print.PrintAttributes.MediaSize ISO_C4; - field public static final android.print.PrintAttributes.MediaSize ISO_C5; - field public static final android.print.PrintAttributes.MediaSize ISO_C6; - field public static final android.print.PrintAttributes.MediaSize ISO_C7; - field public static final android.print.PrintAttributes.MediaSize ISO_C8; - field public static final android.print.PrintAttributes.MediaSize ISO_C9; - field public static final android.print.PrintAttributes.MediaSize NA_GOVT_LETTER; - field public static final android.print.PrintAttributes.MediaSize NA_JUNIOR_LEGAL; - field public static final android.print.PrintAttributes.MediaSize NA_LEDGER; - field public static final android.print.PrintAttributes.MediaSize NA_LEGAL; - field public static final android.print.PrintAttributes.MediaSize NA_LETTER; - field public static final android.print.PrintAttributes.MediaSize NA_TBLOID; + field public static final int ISO_A0 = 1; // 0x1 + field public static final int ISO_A1 = 2; // 0x2 + field public static final int ISO_A10 = 11; // 0xb + field public static final int ISO_A2 = 3; // 0x3 + field public static final int ISO_A3 = 4; // 0x4 + field public static final int ISO_A4 = 5; // 0x5 + field public static final int ISO_A5 = 6; // 0x6 + field public static final int ISO_A6 = 7; // 0x7 + field public static final int ISO_A7 = 8; // 0x8 + field public static final int ISO_A8 = 9; // 0x9 + field public static final int ISO_A9 = 10; // 0xa + field public static final int ISO_B0 = 100; // 0x64 + field public static final int ISO_B1 = 101; // 0x65 + field public static final int ISO_B10 = 110; // 0x6e + field public static final int ISO_B2 = 102; // 0x66 + field public static final int ISO_B3 = 103; // 0x67 + field public static final int ISO_B4 = 104; // 0x68 + field public static final int ISO_B5 = 105; // 0x69 + field public static final int ISO_B6 = 106; // 0x6a + field public static final int ISO_B7 = 107; // 0x6b + field public static final int ISO_B8 = 108; // 0x6c + field public static final int ISO_B9 = 109; // 0x6d + field public static final int ISO_C0 = 200; // 0xc8 + field public static final int ISO_C1 = 201; // 0xc9 + field public static final int ISO_C10 = 210; // 0xd2 + field public static final int ISO_C2 = 202; // 0xca + field public static final int ISO_C3 = 203; // 0xcb + field public static final int ISO_C4 = 204; // 0xcc + field public static final int ISO_C5 = 205; // 0xcd + field public static final int ISO_C6 = 206; // 0xce + field public static final int ISO_C7 = 207; // 0xcf + field public static final int ISO_C8 = 208; // 0xd0 + field public static final int ISO_C9 = 209; // 0xd1 + field public static final int NA_GOVT_LETTER = 301; // 0x12d + field public static final int NA_JUNIOR_LEGAL = 303; // 0x12f + field public static final int NA_LEDGER = 304; // 0x130 + field public static final int NA_LEGAL = 302; // 0x12e + field public static final int NA_LETTER = 300; // 0x12c + field public static final int NA_TBLOID = 305; // 0x131 } public static final class PrintAttributes.Resolution { - ctor public PrintAttributes.Resolution(java.lang.String, java.lang.String, int, int, int); + ctor public PrintAttributes.Resolution(java.lang.String, java.lang.CharSequence, int, int); method public int getHorizontalDpi(); method public java.lang.String getId(); - method public java.lang.CharSequence getLabel(android.content.pm.PackageManager); + method public java.lang.CharSequence getLabel(); method public int getVerticalDpi(); } public static final class PrintAttributes.Tray { - ctor public PrintAttributes.Tray(java.lang.String, java.lang.String, int); + ctor public PrintAttributes.Tray(java.lang.String, java.lang.CharSequence); method public java.lang.String getId(); - method public java.lang.CharSequence getLabel(android.content.pm.PackageManager); + method public java.lang.CharSequence getLabel(); + } + + public abstract class PrintDocumentAdapter { + ctor public PrintDocumentAdapter(); + method public void onFinish(); + method public abstract void onLayout(android.print.PrintAttributes, android.print.PrintAttributes, android.os.CancellationSignal, android.print.PrintDocumentAdapter.LayoutResultCallback, android.os.Bundle); + method public void onStart(); + method public abstract void onWrite(java.util.List<android.print.PageRange>, java.io.FileDescriptor, android.os.CancellationSignal, android.print.PrintDocumentAdapter.WriteResultCallback); + field public static final java.lang.String METADATA_KEY_PRINT_PREVIEW = "KEY_METADATA_PRINT_PREVIEW"; + } + + public static abstract class PrintDocumentAdapter.LayoutResultCallback { + method public void onLayoutFailed(java.lang.CharSequence); + method public void onLayoutFinished(android.print.PrintDocumentInfo, boolean); + } + + public static abstract class PrintDocumentAdapter.WriteResultCallback { + method public void onWriteFailed(java.lang.CharSequence); + method public void onWriteFinished(java.util.List<android.print.PageRange>); + } + + public final class PrintDocumentInfo implements android.os.Parcelable { + method public int describeContents(); + method public int getContentType(); + method public int getPageCount(); + method public void writeToParcel(android.os.Parcel, int); + field public static final int CONTENT_TYPE_DOCUMENT = 0; // 0x0 + field public static final int CONTENT_TYPE_PHOTO = 1; // 0x1 + field public static final int CONTENT_TYPE_UNKNOWN = -1; // 0xffffffff + field public static final android.os.Parcelable.Creator CREATOR; + field public static final int PAGE_COUNT_UNKNOWN = -1; // 0xffffffff + } + + public static final class PrintDocumentInfo.Builder { + ctor public PrintDocumentInfo.Builder(); + method public android.print.PrintDocumentInfo create(); + method public android.print.PrintDocumentInfo.Builder setContentType(int); + method public android.print.PrintDocumentInfo.Builder setPageCount(int); } public final class PrintJob { @@ -18608,7 +18657,6 @@ package android.print { field public static final int PRINT_JOB_ID_UNDEFINED = -1; // 0xffffffff field public static final int STATE_CANCELED = 6; // 0x6 field public static final int STATE_COMPLETED = 4; // 0x4 - field public static final int STATE_CREATED = 1; // 0x1 field public static final int STATE_FAILED = 5; // 0x5 field public static final int STATE_QUEUED = 2; // 0x2 field public static final int STATE_STARTED = 3; // 0x3 @@ -18617,7 +18665,7 @@ package android.print { public final class PrintManager { method public java.util.List<android.print.PrintJob> getPrintJobs(); method public android.print.PrintJob print(java.lang.String, java.io.File, android.print.PrintAttributes); - method public android.print.PrintJob print(java.lang.String, android.print.PrintAdapter, android.print.PrintAttributes); + method public android.print.PrintJob print(java.lang.String, android.print.PrintDocumentAdapter, android.print.PrintAttributes); } public final class PrinterId implements android.os.Parcelable { @@ -18699,11 +18747,16 @@ package android.print.pdf { package android.printservice { + public final class PrintDocument { + method public java.io.FileDescriptor getData(); + method public android.print.PrintDocumentInfo getInfo(); + } + public final class PrintJob { method public boolean cancel(); method public boolean complete(); method public boolean fail(java.lang.CharSequence); - method public final java.io.FileDescriptor getData(); + method public android.printservice.PrintDocument getDocument(); method public int getId(); method public android.print.PrintJobInfo getInfo(); method public boolean isQueued(); @@ -24781,6 +24834,33 @@ package android.util { ctor public AndroidRuntimeException(java.lang.Exception); } + public final class ArrayMap implements java.util.Map { + ctor public ArrayMap(); + ctor public ArrayMap(int); + ctor public ArrayMap(android.util.ArrayMap); + method public void clear(); + method public boolean containsAll(java.util.Collection<?>); + method public boolean containsKey(java.lang.Object); + method public boolean containsValue(java.lang.Object); + method public void ensureCapacity(int); + method public java.util.Set<java.util.Map.Entry<K, V>> entrySet(); + method public V get(java.lang.Object); + method public boolean isEmpty(); + method public K keyAt(int); + method public java.util.Set<K> keySet(); + method public V put(K, V); + method public void putAll(android.util.ArrayMap<? extends K, ? extends V>); + method public void putAll(java.util.Map<? extends K, ? extends V>); + method public V remove(java.lang.Object); + method public boolean removeAll(java.util.Collection<?>); + method public V removeAt(int); + method public boolean retainAll(java.util.Collection<?>); + method public V setValueAt(int, V); + method public int size(); + method public V valueAt(int); + method public java.util.Collection<V> values(); + } + public class AtomicFile { ctor public AtomicFile(java.io.File); method public void delete(); @@ -25134,6 +25214,7 @@ package android.util { method public void put(int, E); method public void remove(int); method public void removeAt(int); + method public void removeAtRange(int, int); method public void setValueAt(int, E); method public int size(); method public E valueAt(int); @@ -25872,6 +25953,7 @@ package android.view { field public static final int KEYCODE_LEFT_BRACKET = 71; // 0x47 field public static final int KEYCODE_M = 41; // 0x29 field public static final int KEYCODE_MANNER_MODE = 205; // 0xcd + field public static final int KEYCODE_MEDIA_AUDIO_TRACK = 222; // 0xde field public static final int KEYCODE_MEDIA_CLOSE = 128; // 0x80 field public static final int KEYCODE_MEDIA_EJECT = 129; // 0x81 field public static final int KEYCODE_MEDIA_FAST_FORWARD = 90; // 0x5a @@ -26726,7 +26808,6 @@ package android.view { method public float getY(); method public boolean hasFocus(); method public boolean hasFocusable(); - method public boolean hasLayout(); method public boolean hasOnClickListeners(); method public boolean hasOverlappingRendering(); method public boolean hasTransientState(); @@ -26756,6 +26837,7 @@ package android.view { method public boolean isInEditMode(); method public boolean isInLayout(); method public boolean isInTouchMode(); + method public boolean isLaidOut(); method public boolean isLayoutDirectionResolved(); method public boolean isLayoutRequested(); method public boolean isLongClickable(); @@ -27033,6 +27115,7 @@ package android.view { field protected static final int[] PRESSED_FOCUSED_WINDOW_FOCUSED_STATE_SET; field protected static final int[] PRESSED_SELECTED_STATE_SET; field protected static final int[] PRESSED_SELECTED_WINDOW_FOCUSED_STATE_SET; + field protected static final int[] PRESSED_STATE_SET; field protected static final int[] PRESSED_WINDOW_FOCUSED_STATE_SET; field public static final android.util.Property ROTATION; field public static final android.util.Property ROTATION_X; diff --git a/cmds/input/src/com/android/commands/input/Input.java b/cmds/input/src/com/android/commands/input/Input.java index bb26443..473b60c 100644 --- a/cmds/input/src/com/android/commands/input/Input.java +++ b/cmds/input/src/com/android/commands/input/Input.java @@ -24,6 +24,9 @@ import android.view.KeyCharacterMap; import android.view.KeyEvent; import android.view.MotionEvent; +import java.util.HashMap; +import java.util.Map; + /** * Command that sends key events to the device, either by their keycode, or by * desired character output. @@ -31,6 +34,21 @@ import android.view.MotionEvent; public class Input { private static final String TAG = "Input"; + private static final String INVALID_ARGUMENTS = "Error: Invalid arguments for command: "; + + private static final Map<String, Integer> SOURCES = new HashMap<String, Integer>() {{ + put("keyboard", InputDevice.SOURCE_KEYBOARD); + put("dpad", InputDevice.SOURCE_DPAD); + put("gamepad", InputDevice.SOURCE_GAMEPAD); + put("touchscreen", InputDevice.SOURCE_TOUCHSCREEN); + put("mouse", InputDevice.SOURCE_MOUSE); + put("stylus", InputDevice.SOURCE_STYLUS); + put("trackball", InputDevice.SOURCE_TRACKBALL); + put("touchpad", InputDevice.SOURCE_TOUCHPAD); + put("touchnavigation", InputDevice.SOURCE_TOUCH_NAVIGATION); + put("joystick", InputDevice.SOURCE_JOYSTICK); + }}; + /** * Command-line entry point. @@ -47,86 +65,71 @@ public class Input { return; } - String command = args[0]; + int index = 0; + String command = args[index]; + int inputSource = InputDevice.SOURCE_UNKNOWN; + if (SOURCES.containsKey(command)) { + inputSource = SOURCES.get(command); + index++; + command = args[index]; + } + final int length = args.length - index; try { if (command.equals("text")) { - if (args.length == 2) { - sendText(args[1]); + if (length == 2) { + inputSource = getSource(inputSource, InputDevice.SOURCE_KEYBOARD); + sendText(inputSource, args[index+1]); return; } } else if (command.equals("keyevent")) { - if (args.length >= 2) { - final boolean longpress = "--longpress".equals(args[1]); - final int start = longpress ? 2 : 1; - if (args.length > start) { - for (int i = start; i < args.length; i++) { + if (length >= 2) { + final boolean longpress = "--longpress".equals(args[index + 1]); + final int start = longpress ? index + 2 : index + 1; + inputSource = getSource(inputSource, InputDevice.SOURCE_KEYBOARD); + if (length > start) { + for (int i = start; i < length; i++) { int keyCode = KeyEvent.keyCodeFromString(args[i]); if (keyCode == KeyEvent.KEYCODE_UNKNOWN) { keyCode = KeyEvent.keyCodeFromString("KEYCODE_" + args[i]); } - sendKeyEvent(keyCode, longpress); + sendKeyEvent(inputSource, keyCode, longpress); } return; } } } else if (command.equals("tap")) { - if (args.length == 3) { - sendTap(InputDevice.SOURCE_TOUCHSCREEN, Float.parseFloat(args[1]), Float.parseFloat(args[2])); + if (length == 3) { + inputSource = getSource(inputSource, InputDevice.SOURCE_TOUCHSCREEN); + sendTap(inputSource, Float.parseFloat(args[index+1]), + Float.parseFloat(args[index+2])); return; } } else if (command.equals("swipe")) { - if (args.length == 5) { - sendSwipe(InputDevice.SOURCE_TOUCHSCREEN, Float.parseFloat(args[1]), Float.parseFloat(args[2]), - Float.parseFloat(args[3]), Float.parseFloat(args[4]), -1); - return; - } - } else if (command.equals("touchscreen") || command.equals("touchpad") - || command.equals("touchnavigation")) { - // determine input source - int inputSource = InputDevice.SOURCE_TOUCHSCREEN; - if (command.equals("touchpad")) { - inputSource = InputDevice.SOURCE_TOUCHPAD; - } else if (command.equals("touchnavigation")) { - inputSource = InputDevice.SOURCE_TOUCH_NAVIGATION; + int duration = -1; + inputSource = getSource(inputSource, InputDevice.SOURCE_TOUCHSCREEN); + switch (length) { + case 6: + duration = Integer.parseInt(args[index+5]); + case 5: + sendSwipe(inputSource, + Float.parseFloat(args[index+1]), Float.parseFloat(args[index+2]), + Float.parseFloat(args[index+3]), Float.parseFloat(args[index+4]), + duration); + return; } - // determine subcommand - if (args.length > 1) { - String subcommand = args[1]; - if (subcommand.equals("tap")) { - if (args.length == 4) { - sendTap(inputSource, Float.parseFloat(args[2]), - Float.parseFloat(args[3])); - return; - } - } else if (subcommand.equals("swipe")) { - if (args.length == 6) { - sendSwipe(inputSource, Float.parseFloat(args[2]), - Float.parseFloat(args[3]), Float.parseFloat(args[4]), - Float.parseFloat(args[5]), -1); - return; - } else if (args.length == 7) { - sendSwipe(inputSource, Float.parseFloat(args[2]), - Float.parseFloat(args[3]), Float.parseFloat(args[4]), - Float.parseFloat(args[5]), Integer.parseInt(args[6])); - return; - } - } + } else if (command.equals("press")) { + inputSource = getSource(inputSource, InputDevice.SOURCE_TRACKBALL); + if (length == 1) { + sendTap(inputSource, 0.0f, 0.0f); + return; } - } else if (command.equals("trackball")) { - // determine subcommand - if (args.length > 1) { - String subcommand = args[1]; - if (subcommand.equals("press")) { - sendTap(InputDevice.SOURCE_TRACKBALL, 0.0f, 0.0f); - return; - } else if (subcommand.equals("roll")) { - if (args.length == 4) { - sendMove(InputDevice.SOURCE_TRACKBALL, Float.parseFloat(args[2]), - Float.parseFloat(args[3])); - return; - } - } + } else if (command.equals("roll")) { + inputSource = getSource(inputSource, InputDevice.SOURCE_TRACKBALL); + if (length == 3) { + sendMove(inputSource, Float.parseFloat(args[index+1]), + Float.parseFloat(args[index+2])); + return; } } else { System.err.println("Error: Unknown command: " + command); @@ -135,7 +138,7 @@ public class Input { } } catch (NumberFormatException ex) { } - System.err.println("Error: Invalid arguments for command: " + command); + System.err.println(INVALID_ARGUMENTS + command); showUsage(); } @@ -145,7 +148,7 @@ public class Input { * * @param text is a string of characters you want to input to the device. */ - private void sendText(String text) { + private void sendText(int source, String text) { StringBuffer buff = new StringBuffer(text); @@ -157,7 +160,7 @@ public class Input { buff.setCharAt(i, ' '); buff.deleteCharAt(--i); } - } + } if (buff.charAt(i) == '%') { escapeFlag = true; } @@ -168,21 +171,25 @@ public class Input { KeyCharacterMap kcm = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD); KeyEvent[] events = kcm.getEvents(chars); for(int i = 0; i < events.length; i++) { - injectKeyEvent(events[i]); + KeyEvent e = events[i]; + if (source != e.getSource()) { + e.setSource(source); + } + injectKeyEvent(e); } } - private void sendKeyEvent(int keyCode, boolean longpress) { + private void sendKeyEvent(int inputSource, int keyCode, boolean longpress) { long now = SystemClock.uptimeMillis(); injectKeyEvent(new KeyEvent(now, now, KeyEvent.ACTION_DOWN, keyCode, 0, 0, - KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 0, InputDevice.SOURCE_KEYBOARD)); + KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 0, inputSource)); if (longpress) { injectKeyEvent(new KeyEvent(now, now, KeyEvent.ACTION_DOWN, keyCode, 1, 0, KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_LONG_PRESS, - InputDevice.SOURCE_KEYBOARD)); + inputSource)); } injectKeyEvent(new KeyEvent(now, now, KeyEvent.ACTION_UP, keyCode, 0, 0, - KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 0, InputDevice.SOURCE_KEYBOARD)); + KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 0, inputSource)); } private void sendTap(int inputSource, float x, float y) { @@ -206,7 +213,7 @@ public class Input { lerp(y1, y2, alpha), 1.0f); now = SystemClock.uptimeMillis(); } - injectMotionEvent(inputSource, MotionEvent.ACTION_UP, now, x1, y1, 0.0f); + injectMotionEvent(inputSource, MotionEvent.ACTION_UP, now, x2, y2, 0.0f); } /** @@ -257,14 +264,26 @@ public class Input { return (b - a) * alpha + a; } + private static final int getSource(int inputSource, int defaultSource) { + return inputSource == -1 ? defaultSource : inputSource; + } + private void showUsage() { - System.err.println("usage: input ..."); - System.err.println(" input text <string>"); - System.err.println(" input keyevent [--longpress] <key code number or name> ..."); - System.err.println(" input [touchscreen|touchpad|touchnavigation] tap <x> <y>"); - System.err.println(" input [touchscreen|touchpad|touchnavigation] swipe " - + "<x1> <y1> <x2> <y2> [duration(ms)]"); - System.err.println(" input trackball press"); - System.err.println(" input trackball roll <dx> <dy>"); + System.err.println("Usage: input [<source>] <command> [<arg>...]"); + System.err.println(); + System.err.println("The sources are: "); + for (String src : SOURCES.keySet()) { + System.err.println(" " + src); + } + System.err.println(); + System.err.println("The commands and default sources are:"); + System.err.println(" text <string> (Default: touchscreen)"); + System.err.println(" keyevent [--longpress] <key code number or name> ..." + + " (Default: keyboard)"); + System.err.println(" tap <x> <y> (Default: touchscreen)"); + System.err.println(" swipe <x1> <y1> <x2> <y2> [duration(ms)]" + + " (Default: touchscreen)"); + System.err.println(" press (Default: trackball)"); + System.err.println(" roll <dx> <dy> (Default: trackball)"); } } diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index fa746ba..8f2f9ca 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -16,6 +16,7 @@ package android.app; +import android.util.ArrayMap; import com.android.internal.app.ActionBarImpl; import com.android.internal.policy.PolicyManager; @@ -700,7 +701,7 @@ public class Activity extends ContextThemeWrapper Object activity; HashMap<String, Object> children; ArrayList<Fragment> fragments; - HashMap<String, LoaderManagerImpl> loaders; + ArrayMap<String, LoaderManagerImpl> loaders; } /* package */ NonConfigurationInstances mLastNonConfigurationInstances; @@ -725,7 +726,7 @@ public class Activity extends ContextThemeWrapper } }; - HashMap<String, LoaderManagerImpl> mAllLoaderManagers; + ArrayMap<String, LoaderManagerImpl> mAllLoaderManagers; LoaderManagerImpl mLoaderManager; private static final class ManagedCursor { @@ -819,13 +820,13 @@ public class Activity extends ContextThemeWrapper return mLoaderManager; } mCheckedForLoaderManager = true; - mLoaderManager = getLoaderManager(null, mLoadersStarted, true); + mLoaderManager = getLoaderManager("(root)", mLoadersStarted, true); return mLoaderManager; } LoaderManagerImpl getLoaderManager(String who, boolean started, boolean create) { if (mAllLoaderManagers == null) { - mAllLoaderManagers = new HashMap<String, LoaderManagerImpl>(); + mAllLoaderManagers = new ArrayMap<String, LoaderManagerImpl>(); } LoaderManagerImpl lm = mAllLoaderManagers.get(who); if (lm == null) { @@ -1036,7 +1037,7 @@ public class Activity extends ContextThemeWrapper if (mLoaderManager != null) { mLoaderManager.doStart(); } else if (!mCheckedForLoaderManager) { - mLoaderManager = getLoaderManager(null, mLoadersStarted, false); + mLoaderManager = getLoaderManager("(root)", mLoadersStarted, false); } mCheckedForLoaderManager = true; } @@ -1648,17 +1649,18 @@ public class Activity extends ContextThemeWrapper if (mAllLoaderManagers != null) { // prune out any loader managers that were already stopped and so // have nothing useful to retain. - LoaderManagerImpl loaders[] = new LoaderManagerImpl[mAllLoaderManagers.size()]; - mAllLoaderManagers.values().toArray(loaders); - if (loaders != null) { - for (int i=0; i<loaders.length; i++) { - LoaderManagerImpl lm = loaders[i]; - if (lm.mRetaining) { - retainLoaders = true; - } else { - lm.doDestroy(); - mAllLoaderManagers.remove(lm.mWho); - } + final int N = mAllLoaderManagers.size(); + LoaderManagerImpl loaders[] = new LoaderManagerImpl[N]; + for (int i=N-1; i>=0; i--) { + loaders[i] = mAllLoaderManagers.valueAt(i); + } + for (int i=0; i<N; i++) { + LoaderManagerImpl lm = loaders[i]; + if (lm.mRetaining) { + retainLoaders = true; + } else { + lm.doDestroy(); + mAllLoaderManagers.remove(lm.mWho); } } } @@ -5236,14 +5238,15 @@ public class Activity extends ContextThemeWrapper } mFragments.dispatchStart(); if (mAllLoaderManagers != null) { - LoaderManagerImpl loaders[] = new LoaderManagerImpl[mAllLoaderManagers.size()]; - mAllLoaderManagers.values().toArray(loaders); - if (loaders != null) { - for (int i=0; i<loaders.length; i++) { - LoaderManagerImpl lm = loaders[i]; - lm.finishRetain(); - lm.doReportStart(); - } + final int N = mAllLoaderManagers.size(); + LoaderManagerImpl loaders[] = new LoaderManagerImpl[N]; + for (int i=N-1; i>=0; i--) { + loaders[i] = mAllLoaderManagers.valueAt(i); + } + for (int i=0; i<N; i++) { + LoaderManagerImpl lm = loaders[i]; + lm.finishRetain(); + lm.doReportStart(); } } } diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index c79768e..4e6c3dc 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -234,32 +234,49 @@ public class ActivityManager { /** @hide Process is a persistent system process and is doing UI. */ public static final int PROCESS_STATE_PERSISTENT_UI = 1; - /** @hide Process is hosting the current top activity. */ + /** @hide Process is hosting the current top activities. Note that this covers + * all activities that are visible to the user. */ public static final int PROCESS_STATE_TOP = 2; /** @hide Process is important to the user, and something they are aware of. */ - public static final int PROCESS_STATE_IMPORTANT_PERCEPTIBLE = 3; + public static final int PROCESS_STATE_IMPORTANT_FOREGROUND = 3; /** @hide Process is important to the user, but not something they are aware of. */ public static final int PROCESS_STATE_IMPORTANT_BACKGROUND = 4; - /** @hide Process is in the background running a receiver. */ - public static final int PROCESS_STATE_RECEIVER = 5; - /** @hide Process is in the background running a backup/restore operation. */ - public static final int PROCESS_STATE_BACKUP = 6; + public static final int PROCESS_STATE_BACKUP = 5; + + /** @hide Process is in the background, but it can't restore its state so we want + * to try to avoid killing it. */ + public static final int PROCESS_STATE_HEAVY_WEIGHT = 6; - /** @hide Process is in the background running a service. */ + /** @hide Process is in the background running a service. Unlike oom_adj, this level + * is used for both the normal running in background state and the executing + * operations state. */ public static final int PROCESS_STATE_SERVICE = 7; + /** @hide Process is in the background running a receiver. Note that from the + * perspective of oom_adj receivers run at a higher foreground level, but for our + * prioritization here that is not necessary and putting them below services means + * many fewer changes in some process states as they receive broadcasts. */ + public static final int PROCESS_STATE_RECEIVER = 8; + /** @hide Process is in the background but hosts the home activity. */ - public static final int PROCESS_STATE_HOME = 8; + public static final int PROCESS_STATE_HOME = 9; /** @hide Process is in the background but hosts the last shown activity. */ - public static final int PROCESS_STATE_LAST_ACTIVITY = 9; + public static final int PROCESS_STATE_LAST_ACTIVITY = 10; + + /** @hide Process is being cached for later use and contains activities. */ + public static final int PROCESS_STATE_CACHED_ACTIVITY = 11; + + /** @hide Process is being cached for later use and is a client of another cached + * process that contains activities. */ + public static final int PROCESS_STATE_CACHED_ACTIVITY_CLIENT = 12; - /** @hide Process is being cached for later use. */ - public static final int PROCESS_STATE_CACHED = 10; + /** @hide Process is being cached for later use and is empty. */ + public static final int PROCESS_STATE_CACHED_EMPTY = 13; /*package*/ ActivityManager(Context context, Handler handler) { mContext = context; diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 222ad69..d9f9d61 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -69,6 +69,7 @@ import android.os.SystemProperties; import android.os.Trace; import android.os.UserHandle; import android.util.AndroidRuntimeException; +import android.util.ArrayMap; import android.util.DisplayMetrics; import android.util.EventLog; import android.util.Log; @@ -103,8 +104,6 @@ import java.lang.ref.WeakReference; import java.net.InetAddress; import java.security.Security; import java.util.ArrayList; -import java.util.HashMap; -import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Map; @@ -164,15 +163,15 @@ public final class ActivityThread { final ApplicationThread mAppThread = new ApplicationThread(); final Looper mLooper = Looper.myLooper(); final H mH = new H(); - final HashMap<IBinder, ActivityClientRecord> mActivities - = new HashMap<IBinder, ActivityClientRecord>(); + final ArrayMap<IBinder, ActivityClientRecord> mActivities + = new ArrayMap<IBinder, ActivityClientRecord>(); // List of new activities (via ActivityRecord.nextIdle) that should // be reported when next we idle. ActivityClientRecord mNewActivities = null; // Number of activities that are currently visible on-screen. int mNumVisibleActivities = 0; - final HashMap<IBinder, Service> mServices - = new HashMap<IBinder, Service>(); + final ArrayMap<IBinder, Service> mServices + = new ArrayMap<IBinder, Service>(); AppBindData mBoundApplication; Profiler mProfiler; int mCurDefaultDisplayDpi; @@ -183,7 +182,7 @@ public final class ActivityThread { final ArrayList<Application> mAllApplications = new ArrayList<Application>(); // set of instantiated backup agents, keyed by package name - final HashMap<String, BackupAgent> mBackupAgents = new HashMap<String, BackupAgent>(); + final ArrayMap<String, BackupAgent> mBackupAgents = new ArrayMap<String, BackupAgent>(); /** Reference to singleton {@link ActivityThread} */ private static ActivityThread sCurrentActivityThread; Instrumentation mInstrumentation; @@ -203,10 +202,10 @@ public final class ActivityThread { // which means this lock gets held while the activity and window managers // holds their own lock. Thus you MUST NEVER call back into the activity manager // or window manager or anything that depends on them while holding this lock. - final HashMap<String, WeakReference<LoadedApk>> mPackages - = new HashMap<String, WeakReference<LoadedApk>>(); - final HashMap<String, WeakReference<LoadedApk>> mResourcePackages - = new HashMap<String, WeakReference<LoadedApk>>(); + final ArrayMap<String, WeakReference<LoadedApk>> mPackages + = new ArrayMap<String, WeakReference<LoadedApk>>(); + final ArrayMap<String, WeakReference<LoadedApk>> mResourcePackages + = new ArrayMap<String, WeakReference<LoadedApk>>(); final ArrayList<ActivityClientRecord> mRelaunchingActivities = new ArrayList<ActivityClientRecord>(); Configuration mPendingConfiguration = null; @@ -238,17 +237,17 @@ public final class ActivityThread { } // The lock of mProviderMap protects the following variables. - final HashMap<ProviderKey, ProviderClientRecord> mProviderMap - = new HashMap<ProviderKey, ProviderClientRecord>(); - final HashMap<IBinder, ProviderRefCount> mProviderRefCountMap - = new HashMap<IBinder, ProviderRefCount>(); - final HashMap<IBinder, ProviderClientRecord> mLocalProviders - = new HashMap<IBinder, ProviderClientRecord>(); - final HashMap<ComponentName, ProviderClientRecord> mLocalProvidersByName - = new HashMap<ComponentName, ProviderClientRecord>(); - - final HashMap<Activity, ArrayList<OnActivityPausedListener>> mOnPauseListeners - = new HashMap<Activity, ArrayList<OnActivityPausedListener>>(); + final ArrayMap<ProviderKey, ProviderClientRecord> mProviderMap + = new ArrayMap<ProviderKey, ProviderClientRecord>(); + final ArrayMap<IBinder, ProviderRefCount> mProviderRefCountMap + = new ArrayMap<IBinder, ProviderRefCount>(); + final ArrayMap<IBinder, ProviderClientRecord> mLocalProviders + = new ArrayMap<IBinder, ProviderClientRecord>(); + final ArrayMap<ComponentName, ProviderClientRecord> mLocalProvidersByName + = new ArrayMap<ComponentName, ProviderClientRecord>(); + + final ArrayMap<Activity, ArrayList<OnActivityPausedListener>> mOnPauseListeners + = new ArrayMap<Activity, ArrayList<OnActivityPausedListener>>(); final GcIdler mGcIdler = new GcIdler(); boolean mGcIdlerScheduled = false; @@ -3702,47 +3701,45 @@ public final class ActivityThread { = new ArrayList<ComponentCallbacks2>(); synchronized (mResourcesManager) { - final int N = mAllApplications.size(); - for (int i=0; i<N; i++) { + final int NAPP = mAllApplications.size(); + for (int i=0; i<NAPP; i++) { callbacks.add(mAllApplications.get(i)); } - if (mActivities.size() > 0) { - for (ActivityClientRecord ar : mActivities.values()) { - Activity a = ar.activity; - if (a != null) { - Configuration thisConfig = applyConfigCompatMainThread( - mCurDefaultDisplayDpi, newConfig, - ar.packageInfo.getCompatibilityInfo()); - if (!ar.activity.mFinished && (allActivities || !ar.paused)) { - // If the activity is currently resumed, its configuration - // needs to change right now. - callbacks.add(a); - } else if (thisConfig != null) { - // Otherwise, we will tell it about the change - // the next time it is resumed or shown. Note that - // the activity manager may, before then, decide the - // activity needs to be destroyed to handle its new - // configuration. - if (DEBUG_CONFIGURATION) { - Slog.v(TAG, "Setting activity " - + ar.activityInfo.name + " newConfig=" + thisConfig); - } - ar.newConfig = thisConfig; + final int NACT = mActivities.size(); + for (int i=0; i<NACT; i++) { + ActivityClientRecord ar = mActivities.valueAt(i); + Activity a = ar.activity; + if (a != null) { + Configuration thisConfig = applyConfigCompatMainThread( + mCurDefaultDisplayDpi, newConfig, + ar.packageInfo.getCompatibilityInfo()); + if (!ar.activity.mFinished && (allActivities || !ar.paused)) { + // If the activity is currently resumed, its configuration + // needs to change right now. + callbacks.add(a); + } else if (thisConfig != null) { + // Otherwise, we will tell it about the change + // the next time it is resumed or shown. Note that + // the activity manager may, before then, decide the + // activity needs to be destroyed to handle its new + // configuration. + if (DEBUG_CONFIGURATION) { + Slog.v(TAG, "Setting activity " + + ar.activityInfo.name + " newConfig=" + thisConfig); } + ar.newConfig = thisConfig; } } } - if (mServices.size() > 0) { - for (Service service : mServices.values()) { - callbacks.add(service); - } + final int NSVC = mServices.size(); + for (int i=0; i<NSVC; i++) { + callbacks.add(mServices.valueAt(i)); } } synchronized (mProviderMap) { - if (mLocalProviders.size() > 0) { - for (ProviderClientRecord providerClientRecord : mLocalProviders.values()) { - callbacks.add(providerClientRecord.mLocalProvider); - } + final int NPRV = mLocalProviders.size(); + for (int i=0; i<NPRV; i++) { + callbacks.add(mLocalProviders.valueAt(i).mLocalProvider); } } @@ -4575,12 +4572,11 @@ public final class ActivityThread { mProviderRefCountMap.remove(jBinder); } - Iterator<ProviderClientRecord> iter = mProviderMap.values().iterator(); - while (iter.hasNext()) { - ProviderClientRecord pr = iter.next(); + for (int i=mProviderMap.size()-1; i>=0; i--) { + ProviderClientRecord pr = mProviderMap.valueAt(i); IBinder myBinder = pr.mProvider.asBinder(); if (myBinder == jBinder) { - iter.remove(); + mProviderMap.removeAt(i); } } } diff --git a/core/java/android/app/AlarmManager.java b/core/java/android/app/AlarmManager.java index 2fe682d..d9c3775 100644 --- a/core/java/android/app/AlarmManager.java +++ b/core/java/android/app/AlarmManager.java @@ -16,7 +16,9 @@ package android.app; +import android.content.Context; import android.content.Intent; +import android.os.Build; import android.os.RemoteException; /** @@ -52,6 +54,8 @@ import android.os.RemoteException; */ public class AlarmManager { + private static final String TAG = "AlarmManager"; + /** * Alarm time in {@link System#currentTimeMillis System.currentTimeMillis()} * (wall clock time in UTC), which will wake up the device when @@ -80,17 +84,33 @@ public class AlarmManager */ public static final int ELAPSED_REALTIME = 3; + /** @hide */ + public static final long WINDOW_EXACT = 0; + /** @hide */ + public static final long WINDOW_HEURISTIC = -1; + private final IAlarmManager mService; + private final boolean mAlwaysExact; + /** * package private on purpose */ - AlarmManager(IAlarmManager service) { + AlarmManager(IAlarmManager service, Context ctx) { mService = service; + + final int sdkVersion = ctx.getApplicationInfo().targetSdkVersion; + mAlwaysExact = (sdkVersion < Build.VERSION_CODES.KEY_LIME_PIE); } - + + private long legacyExactLength() { + return (mAlwaysExact ? WINDOW_EXACT : WINDOW_HEURISTIC); + } + /** - * Schedule an alarm. <b>Note: for timing operations (ticks, timeouts, + * TBW: discussion of fuzzy nature of alarms in KLP+. + * + * <p>Schedule an alarm. <b>Note: for timing operations (ticks, timeouts, * etc) it is easier and much more efficient to use * {@link android.os.Handler}.</b> If there is already an alarm scheduled * for the same IntentSender, it will first be canceled. @@ -122,7 +142,9 @@ public class AlarmManager * IntentSender.getBroadcast()}. * * @see android.os.Handler + * @see #setExact * @see #setRepeating + * @see #setWindow * @see #cancel * @see android.content.Context#sendBroadcast * @see android.content.Context#registerReceiver @@ -133,10 +155,7 @@ public class AlarmManager * @see #RTC_WAKEUP */ public void set(int type, long triggerAtMillis, PendingIntent operation) { - try { - mService.set(type, triggerAtMillis, operation); - } catch (RemoteException ex) { - } + setImpl(type, triggerAtMillis, legacyExactLength(), 0, operation); } /** @@ -177,6 +196,8 @@ public class AlarmManager * * @see android.os.Handler * @see #set + * @see #setExact + * @see #setWindow * @see #cancel * @see android.content.Context#sendBroadcast * @see android.content.Context#registerReceiver @@ -188,22 +209,95 @@ public class AlarmManager */ public void setRepeating(int type, long triggerAtMillis, long intervalMillis, PendingIntent operation) { + setImpl(type, triggerAtMillis, legacyExactLength(), intervalMillis, operation); + } + + /** + * Schedule an alarm to be delivered within a given window of time. + * + * TBW: clean up these docs + * + * @param type One of ELAPSED_REALTIME, ELAPSED_REALTIME_WAKEUP, RTC or + * RTC_WAKEUP. + * @param windowStartMillis The earliest time, in milliseconds, that the alarm should + * be delivered, expressed in the appropriate clock's units (depending on the alarm + * type). + * @param windowLengthMillis The length of the requested delivery window, + * in milliseconds. The alarm will be delivered no later than this many + * milliseconds after the windowStartMillis time. Note that this parameter + * is a <i>duration,</i> not the timestamp of the end of the window. + * @param operation Action to perform when the alarm goes off; + * typically comes from {@link PendingIntent#getBroadcast + * IntentSender.getBroadcast()}. + * + * @see #set + * @see #setExact + * @see #setRepeating + * @see #cancel + * @see android.content.Context#sendBroadcast + * @see android.content.Context#registerReceiver + * @see android.content.Intent#filterEquals + * @see #ELAPSED_REALTIME + * @see #ELAPSED_REALTIME_WAKEUP + * @see #RTC + * @see #RTC_WAKEUP + */ + public void setWindow(int type, long windowStartMillis, long windowLengthMillis, + PendingIntent operation) { + setImpl(type, windowStartMillis, windowLengthMillis, 0, operation); + } + + /** + * TBW: new 'exact' alarm that must be delivered as nearly as possible + * to the precise time specified. + */ + public void setExact(int type, long triggerAtMillis, PendingIntent operation) { + setImpl(type, triggerAtMillis, WINDOW_EXACT, 0, operation); + } + + private void setImpl(int type, long triggerAtMillis, long windowMillis, long intervalMillis, + PendingIntent operation) { try { - mService.setRepeating(type, triggerAtMillis, intervalMillis, operation); + mService.set(type, triggerAtMillis, windowMillis, intervalMillis, operation); } catch (RemoteException ex) { } } /** - * Available inexact recurrence intervals recognized by - * {@link #setInexactRepeating(int, long, long, PendingIntent)} + * @deprecated setInexactRepeating() is deprecated; as of API 19 all + * repeating alarms are inexact. */ + @Deprecated public static final long INTERVAL_FIFTEEN_MINUTES = 15 * 60 * 1000; + + /** + * @deprecated setInexactRepeating() is deprecated; as of API 19 all + * repeating alarms are inexact. + */ + @Deprecated public static final long INTERVAL_HALF_HOUR = 2*INTERVAL_FIFTEEN_MINUTES; + + /** + * @deprecated setInexactRepeating() is deprecated; as of API 19 all + * repeating alarms are inexact. + */ + @Deprecated public static final long INTERVAL_HOUR = 2*INTERVAL_HALF_HOUR; + + /** + * @deprecated setInexactRepeating() is deprecated; as of API 19 all + * repeating alarms are inexact. + */ + @Deprecated public static final long INTERVAL_HALF_DAY = 12*INTERVAL_HOUR; + + /** + * @deprecated setInexactRepeating() is deprecated; as of API 19 all + * repeating alarms are inexact. + */ + @Deprecated public static final long INTERVAL_DAY = 2*INTERVAL_HALF_DAY; - + /** * Schedule a repeating alarm that has inexact trigger time requirements; * for example, an alarm that repeats every hour, but not necessarily at @@ -236,6 +330,8 @@ public class AlarmManager * typically comes from {@link PendingIntent#getBroadcast * IntentSender.getBroadcast()}. * + * @deprecated As of API 19, all repeating alarms are inexact. + * * @see android.os.Handler * @see #set * @see #cancel @@ -252,12 +348,10 @@ public class AlarmManager * @see #INTERVAL_HALF_DAY * @see #INTERVAL_DAY */ + @Deprecated public void setInexactRepeating(int type, long triggerAtMillis, long intervalMillis, PendingIntent operation) { - try { - mService.setInexactRepeating(type, triggerAtMillis, intervalMillis, operation); - } catch (RemoteException ex) { - } + setImpl(type, triggerAtMillis, WINDOW_HEURISTIC, intervalMillis, operation); } /** diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index de94bb7..8d47236 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -16,12 +16,13 @@ package android.app; -import android.Manifest; +import android.os.Binder; +import android.os.IBinder; +import android.util.ArrayMap; import com.android.internal.app.IAppOpsService; import com.android.internal.app.IAppOpsCallback; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; import android.content.Context; @@ -53,8 +54,10 @@ import android.os.RemoteException; public class AppOpsManager { final Context mContext; final IAppOpsService mService; - final HashMap<Callback, IAppOpsCallback> mModeWatchers - = new HashMap<Callback, IAppOpsCallback>(); + final ArrayMap<Callback, IAppOpsCallback> mModeWatchers + = new ArrayMap<Callback, IAppOpsCallback>(); + + static IBinder sToken; public static final int MODE_ALLOWED = 0; public static final int MODE_IGNORED = 1; @@ -641,6 +644,21 @@ public class AppOpsManager { return noteOp(op, Process.myUid(), mContext.getBasePackageName()); } + /** @hide */ + public static IBinder getToken(IAppOpsService service) { + synchronized (AppOpsManager.class) { + if (sToken != null) { + return sToken; + } + try { + sToken = service.getToken(new Binder()); + } catch (RemoteException e) { + // System is dead, whatevs. + } + return sToken; + } + } + /** * Report that an application has started executing a long-running operation. Note that you * must pass in both the uid and name of the application to be checked; this function will @@ -659,7 +677,7 @@ public class AppOpsManager { */ public int startOp(int op, int uid, String packageName) { try { - int mode = mService.startOperation(op, uid, packageName); + int mode = mService.startOperation(getToken(mService), op, uid, packageName); if (mode == MODE_ERRORED) { throw new SecurityException("Operation not allowed"); } @@ -675,7 +693,7 @@ public class AppOpsManager { */ public int startOpNoThrow(int op, int uid, String packageName) { try { - return mService.startOperation(op, uid, packageName); + return mService.startOperation(getToken(mService), op, uid, packageName); } catch (RemoteException e) { } return MODE_IGNORED; @@ -694,7 +712,7 @@ public class AppOpsManager { */ public void finishOp(int op, int uid, String packageName) { try { - mService.finishOperation(op, uid, packageName); + mService.finishOperation(getToken(mService), op, uid, packageName); } catch (RemoteException e) { } } diff --git a/core/java/android/app/ApplicationLoaders.java b/core/java/android/app/ApplicationLoaders.java index a26b88c..413c369 100644 --- a/core/java/android/app/ApplicationLoaders.java +++ b/core/java/android/app/ApplicationLoaders.java @@ -17,11 +17,9 @@ package android.app; import android.os.Trace; +import android.util.ArrayMap; import dalvik.system.PathClassLoader; -import java.util.HashMap; -import java.util.Map; - class ApplicationLoaders { public static ApplicationLoaders getDefault() @@ -71,7 +69,7 @@ class ApplicationLoaders } } - private final Map<String, ClassLoader> mLoaders = new HashMap<String, ClassLoader>(); + private final ArrayMap<String, ClassLoader> mLoaders = new ArrayMap<String, ClassLoader>(); private static final ApplicationLoaders gApplicationLoaders = new ApplicationLoaders(); diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java index 432e9b1..ab2739d 100644 --- a/core/java/android/app/ApplicationPackageManager.java +++ b/core/java/android/app/ApplicationPackageManager.java @@ -51,6 +51,7 @@ import android.net.Uri; import android.os.Process; import android.os.RemoteException; import android.os.UserHandle; +import android.util.ArrayMap; import android.util.Log; import android.view.Display; @@ -859,26 +860,20 @@ final class ApplicationPackageManager extends PackageManager { boolean needCleanup = false; for (String ssp : pkgList) { synchronized (sSync) { - if (sIconCache.size() > 0) { - Iterator<ResourceName> it = sIconCache.keySet().iterator(); - while (it.hasNext()) { - ResourceName nm = it.next(); - if (nm.packageName.equals(ssp)) { - //Log.i(TAG, "Removing cached drawable for " + nm); - it.remove(); - needCleanup = true; - } + for (int i=sIconCache.size()-1; i>=0; i--) { + ResourceName nm = sIconCache.keyAt(i); + if (nm.packageName.equals(ssp)) { + //Log.i(TAG, "Removing cached drawable for " + nm); + sIconCache.removeAt(i); + needCleanup = true; } } - if (sStringCache.size() > 0) { - Iterator<ResourceName> it = sStringCache.keySet().iterator(); - while (it.hasNext()) { - ResourceName nm = it.next(); - if (nm.packageName.equals(ssp)) { - //Log.i(TAG, "Removing cached string for " + nm); - it.remove(); - needCleanup = true; - } + for (int i=sStringCache.size()-1; i>=0; i--) { + ResourceName nm = sStringCache.keyAt(i); + if (nm.packageName.equals(ssp)) { + //Log.i(TAG, "Removing cached string for " + nm); + sStringCache.removeAt(i); + needCleanup = true; } } } @@ -1335,8 +1330,8 @@ final class ApplicationPackageManager extends PackageManager { private final IPackageManager mPM; private static final Object sSync = new Object(); - private static HashMap<ResourceName, WeakReference<Drawable.ConstantState>> sIconCache - = new HashMap<ResourceName, WeakReference<Drawable.ConstantState>>(); - private static HashMap<ResourceName, WeakReference<CharSequence>> sStringCache - = new HashMap<ResourceName, WeakReference<CharSequence>>(); + private static ArrayMap<ResourceName, WeakReference<Drawable.ConstantState>> sIconCache + = new ArrayMap<ResourceName, WeakReference<Drawable.ConstantState>>(); + private static ArrayMap<ResourceName, WeakReference<CharSequence>> sStringCache + = new ArrayMap<ResourceName, WeakReference<CharSequence>>(); } diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index 6a0fbd5..eeee57d 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -16,6 +16,7 @@ package android.app; +import android.os.Build; import com.android.internal.policy.PolicyManager; import com.android.internal.util.Preconditions; @@ -309,11 +310,11 @@ class ContextImpl extends Context { return new ActivityManager(ctx.getOuterContext(), ctx.mMainThread.getHandler()); }}); - registerService(ALARM_SERVICE, new StaticServiceFetcher() { - public Object createStaticService() { + registerService(ALARM_SERVICE, new ServiceFetcher() { + public Object createService(ContextImpl ctx) { IBinder b = ServiceManager.getService(ALARM_SERVICE); IAlarmManager service = IAlarmManager.Stub.asInterface(b); - return new AlarmManager(service); + return new AlarmManager(service, ctx); }}); registerService(AUDIO_SERVICE, new ServiceFetcher() { @@ -706,6 +707,16 @@ class ContextImpl extends Context { sSharedPrefs.put(packageName, packagePrefs); } + // At least one application in the world actually passes in a null + // name. This happened to work because when we generated the file name + // we would stringify it to "null.xml". Nice. + if (mPackageInfo.getApplicationInfo().targetSdkVersion < + Build.VERSION_CODES.KEY_LIME_PIE) { + if (name == null) { + name = "null"; + } + } + sp = packagePrefs.get(name); if (sp == null) { File prefsFile = getSharedPrefsFile(name); diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java index b6aeb84..6933a7a 100644 --- a/core/java/android/app/Fragment.java +++ b/core/java/android/app/Fragment.java @@ -26,6 +26,7 @@ import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; import android.util.AndroidRuntimeException; +import android.util.ArrayMap; import android.util.AttributeSet; import android.util.DebugUtils; import android.util.Log; @@ -43,7 +44,6 @@ import android.widget.AdapterView; import java.io.FileDescriptor; import java.io.PrintWriter; -import java.util.HashMap; final class FragmentState implements Parcelable { final String mClassName; @@ -342,8 +342,8 @@ final class FragmentState implements Parcelable { * the activity UI was in. */ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListener { - private static final HashMap<String, Class<?>> sClassMap = - new HashMap<String, Class<?>>(); + private static final ArrayMap<String, Class<?>> sClassMap = + new ArrayMap<String, Class<?>>(); static final int INVALID_STATE = -1; // Invalid state used as a null value. static final int INITIALIZING = 0; // Not yet created. diff --git a/core/java/android/app/IAlarmManager.aidl b/core/java/android/app/IAlarmManager.aidl index edb40ed..0a49ddf 100644 --- a/core/java/android/app/IAlarmManager.aidl +++ b/core/java/android/app/IAlarmManager.aidl @@ -24,9 +24,9 @@ import android.app.PendingIntent; * {@hide} */ interface IAlarmManager { - void set(int type, long triggerAtTime, in PendingIntent operation); - void setRepeating(int type, long triggerAtTime, long interval, in PendingIntent operation); - void setInexactRepeating(int type, long triggerAtTime, long interval, in PendingIntent operation); + /** windowLength == 0 means exact; windowLength < 0 means the let the OS decide */ + void set(int type, long triggerAtTime, long windowLength, + long interval, in PendingIntent operation); void setTime(long millis); void setTimeZone(String zone); void remove(in PendingIntent operation); diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java index 05d3a47..4239a5d 100644 --- a/core/java/android/app/LoadedApk.java +++ b/core/java/android/app/LoadedApk.java @@ -16,6 +16,7 @@ package android.app; +import android.util.ArrayMap; import com.android.internal.util.ArrayUtils; import android.content.BroadcastReceiver; @@ -49,8 +50,6 @@ import java.io.InputStream; import java.lang.ref.WeakReference; import java.net.URL; import java.util.Enumeration; -import java.util.HashMap; -import java.util.Iterator; final class IntentReceiverLeaked extends AndroidRuntimeException { public IntentReceiverLeaked(String msg) { @@ -89,14 +88,14 @@ public final class LoadedApk { private ClassLoader mClassLoader; private Application mApplication; - private final HashMap<Context, HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>> mReceivers - = new HashMap<Context, HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>>(); - private final HashMap<Context, HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>> mUnregisteredReceivers - = new HashMap<Context, HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>>(); - private final HashMap<Context, HashMap<ServiceConnection, LoadedApk.ServiceDispatcher>> mServices - = new HashMap<Context, HashMap<ServiceConnection, LoadedApk.ServiceDispatcher>>(); - private final HashMap<Context, HashMap<ServiceConnection, LoadedApk.ServiceDispatcher>> mUnboundServices - = new HashMap<Context, HashMap<ServiceConnection, LoadedApk.ServiceDispatcher>>(); + private final ArrayMap<Context, ArrayMap<BroadcastReceiver, ReceiverDispatcher>> mReceivers + = new ArrayMap<Context, ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>>(); + private final ArrayMap<Context, ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>> mUnregisteredReceivers + = new ArrayMap<Context, ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>>(); + private final ArrayMap<Context, ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>> mServices + = new ArrayMap<Context, ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>>(); + private final ArrayMap<Context, ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>> mUnboundServices + = new ArrayMap<Context, ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>>(); int mClientCount = 0; @@ -540,12 +539,11 @@ public final class LoadedApk { public void removeContextRegistrations(Context context, String who, String what) { final boolean reportRegistrationLeaks = StrictMode.vmRegistrationLeaksEnabled(); - HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> rmap = - mReceivers.remove(context); + ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> rmap = + mReceivers.remove(context); if (rmap != null) { - Iterator<LoadedApk.ReceiverDispatcher> it = rmap.values().iterator(); - while (it.hasNext()) { - LoadedApk.ReceiverDispatcher rd = it.next(); + for (int i=0; i<rmap.size(); i++) { + LoadedApk.ReceiverDispatcher rd = rmap.valueAt(i); IntentReceiverLeaked leak = new IntentReceiverLeaked( what + " " + who + " has leaked IntentReceiver " + rd.getIntentReceiver() + " that was " + @@ -566,12 +564,11 @@ public final class LoadedApk { } mUnregisteredReceivers.remove(context); //Slog.i(TAG, "Receiver registrations: " + mReceivers); - HashMap<ServiceConnection, LoadedApk.ServiceDispatcher> smap = + ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> smap = mServices.remove(context); if (smap != null) { - Iterator<LoadedApk.ServiceDispatcher> it = smap.values().iterator(); - while (it.hasNext()) { - LoadedApk.ServiceDispatcher sd = it.next(); + for (int i=0; i<smap.size(); i++) { + LoadedApk.ServiceDispatcher sd = smap.valueAt(i); ServiceConnectionLeaked leak = new ServiceConnectionLeaked( what + " " + who + " has leaked ServiceConnection " + sd.getServiceConnection() + " that was originally bound here"); @@ -598,7 +595,7 @@ public final class LoadedApk { Instrumentation instrumentation, boolean registered) { synchronized (mReceivers) { LoadedApk.ReceiverDispatcher rd = null; - HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> map = null; + ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> map = null; if (registered) { map = mReceivers.get(context); if (map != null) { @@ -610,7 +607,7 @@ public final class LoadedApk { instrumentation, registered); if (registered) { if (map == null) { - map = new HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>(); + map = new ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>(); mReceivers.put(context, map); } map.put(r, rd); @@ -626,7 +623,7 @@ public final class LoadedApk { public IIntentReceiver forgetReceiverDispatcher(Context context, BroadcastReceiver r) { synchronized (mReceivers) { - HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> map = mReceivers.get(context); + ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> map = mReceivers.get(context); LoadedApk.ReceiverDispatcher rd = null; if (map != null) { rd = map.get(r); @@ -636,10 +633,10 @@ public final class LoadedApk { mReceivers.remove(context); } if (r.getDebugUnregister()) { - HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> holder + ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> holder = mUnregisteredReceivers.get(context); if (holder == null) { - holder = new HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>(); + holder = new ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>(); mUnregisteredReceivers.put(context, holder); } RuntimeException ex = new IllegalArgumentException( @@ -652,7 +649,7 @@ public final class LoadedApk { return rd.getIIntentReceiver(); } } - HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> holder + ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> holder = mUnregisteredReceivers.get(context); if (holder != null) { rd = holder.get(r); @@ -868,14 +865,14 @@ public final class LoadedApk { Context context, Handler handler, int flags) { synchronized (mServices) { LoadedApk.ServiceDispatcher sd = null; - HashMap<ServiceConnection, LoadedApk.ServiceDispatcher> map = mServices.get(context); + ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> map = mServices.get(context); if (map != null) { sd = map.get(c); } if (sd == null) { sd = new ServiceDispatcher(c, context, handler, flags); if (map == null) { - map = new HashMap<ServiceConnection, LoadedApk.ServiceDispatcher>(); + map = new ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>(); mServices.put(context, map); } map.put(c, sd); @@ -889,7 +886,7 @@ public final class LoadedApk { public final IServiceConnection forgetServiceDispatcher(Context context, ServiceConnection c) { synchronized (mServices) { - HashMap<ServiceConnection, LoadedApk.ServiceDispatcher> map + ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> map = mServices.get(context); LoadedApk.ServiceDispatcher sd = null; if (map != null) { @@ -901,10 +898,10 @@ public final class LoadedApk { mServices.remove(context); } if ((sd.getFlags()&Context.BIND_DEBUG_UNBIND) != 0) { - HashMap<ServiceConnection, LoadedApk.ServiceDispatcher> holder + ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> holder = mUnboundServices.get(context); if (holder == null) { - holder = new HashMap<ServiceConnection, LoadedApk.ServiceDispatcher>(); + holder = new ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>(); mUnboundServices.put(context, holder); } RuntimeException ex = new IllegalArgumentException( @@ -916,7 +913,7 @@ public final class LoadedApk { return sd.getIServiceConnection(); } } - HashMap<ServiceConnection, LoadedApk.ServiceDispatcher> holder + ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> holder = mUnboundServices.get(context); if (holder != null) { sd = holder.get(c); @@ -969,8 +966,8 @@ public final class LoadedApk { } } - private final HashMap<ComponentName, ServiceDispatcher.ConnectionInfo> mActiveConnections - = new HashMap<ComponentName, ServiceDispatcher.ConnectionInfo>(); + private final ArrayMap<ComponentName, ServiceDispatcher.ConnectionInfo> mActiveConnections + = new ArrayMap<ComponentName, ServiceDispatcher.ConnectionInfo>(); ServiceDispatcher(ServiceConnection conn, Context context, Handler activityThread, int flags) { @@ -1000,9 +997,8 @@ public final class LoadedApk { void doForget() { synchronized(this) { - Iterator<ServiceDispatcher.ConnectionInfo> it = mActiveConnections.values().iterator(); - while (it.hasNext()) { - ServiceDispatcher.ConnectionInfo ci = it.next(); + for (int i=0; i<mActiveConnections.size(); i++) { + ServiceDispatcher.ConnectionInfo ci = mActiveConnections.valueAt(i); ci.binder.unlinkToDeath(ci.deathMonitor, 0); } mActiveConnections.clear(); diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java index e9693dd..f55dba4 100644 --- a/core/java/android/app/ResourcesManager.java +++ b/core/java/android/app/ResourcesManager.java @@ -18,7 +18,6 @@ package android.app; import static android.app.ActivityThread.DEBUG_CONFIGURATION; -import android.app.ApplicationPackageManager; import android.content.pm.ActivityInfo; import android.content.res.AssetManager; import android.content.res.CompatibilityInfo; @@ -34,10 +33,7 @@ import android.view.Display; import android.view.DisplayAdjustments; import java.lang.ref.WeakReference; -import java.util.HashMap; -import java.util.Iterator; import java.util.Locale; -import java.util.Map; /** @hide */ public class ResourcesManager { @@ -46,8 +42,8 @@ public class ResourcesManager { static final boolean DEBUG_STATS = true; private static ResourcesManager sResourcesManager; - final HashMap<ResourcesKey, WeakReference<Resources> > mActiveResources - = new HashMap<ResourcesKey, WeakReference<Resources> >(); + final ArrayMap<ResourcesKey, WeakReference<Resources> > mActiveResources + = new ArrayMap<ResourcesKey, WeakReference<Resources> >(); final ArrayMap<DisplayAdjustments, DisplayMetrics> mDefaultDisplayMetrics = new ArrayMap<DisplayAdjustments, DisplayMetrics>(); @@ -257,19 +253,16 @@ public class ResourcesManager { Configuration tmpConfig = null; - Iterator<Map.Entry<ResourcesKey, WeakReference<Resources>>> it = - mActiveResources.entrySet().iterator(); - while (it.hasNext()) { - Map.Entry<ResourcesKey, WeakReference<Resources>> entry = it.next(); - Resources r = entry.getValue().get(); + for (int i=mActiveResources.size()-1; i>=0; i--) { + ResourcesKey key = mActiveResources.keyAt(i); + Resources r = mActiveResources.valueAt(i).get(); if (r != null) { if (DEBUG_CONFIGURATION) Slog.v(TAG, "Changing resources " + r + " config to: " + config); - int displayId = entry.getKey().mDisplayId; + int displayId = key.mDisplayId; boolean isDefaultDisplay = (displayId == Display.DEFAULT_DISPLAY); DisplayMetrics dm = defaultDisplayMetrics; - ResourcesKey resourcesKey = entry.getKey(); - final boolean hasOverrideConfiguration = resourcesKey.hasOverrideConfiguration(); + final boolean hasOverrideConfiguration = key.hasOverrideConfiguration(); if (!isDefaultDisplay || hasOverrideConfiguration) { if (tmpConfig == null) { tmpConfig = new Configuration(); @@ -280,7 +273,7 @@ public class ResourcesManager { applyNonDefaultDisplayMetricsToConfigurationLocked(dm, tmpConfig); } if (hasOverrideConfiguration) { - tmpConfig.updateFrom(resourcesKey.mOverrideConfiguration); + tmpConfig.updateFrom(key.mOverrideConfiguration); } r.updateConfiguration(tmpConfig, dm, compat); } else { @@ -290,7 +283,7 @@ public class ResourcesManager { // + " " + r + ": " + r.getConfiguration()); } else { //Slog.i(TAG, "Removing old resources " + v.getKey()); - it.remove(); + mActiveResources.removeAt(i); } } diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index c3d1971..aa326ad 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -230,7 +230,15 @@ public abstract class Context { * tries to balance such requests from one app vs. the importantance of * keeping other apps around. */ - public static final int BIND_VISIBLE = 0x0100; + public static final int BIND_VISIBLE = 0x10000000; + + /** + * @hide + * Flag for {@link #bindService}: Consider this binding to be causing the target + * process to be showing UI, so it will be do a UI_HIDDEN memory trim when it goes + * away. + */ + public static final int BIND_SHOWING_UI = 0x20000000; /** * Flag for {@link #bindService}: Don't consider the bound service to be diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index 62c8d58..a954f59 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -16,6 +16,7 @@ package android.content; +import android.util.ArraySet; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; @@ -42,7 +43,6 @@ import java.io.IOException; import java.io.Serializable; import java.net.URISyntaxException; import java.util.ArrayList; -import java.util.HashSet; import java.util.Iterator; import java.util.Locale; import java.util.Set; @@ -3609,7 +3609,7 @@ public class Intent implements Parcelable, Cloneable { private String mPackage; private ComponentName mComponent; private int mFlags; - private HashSet<String> mCategories; + private ArraySet<String> mCategories; private Bundle mExtras; private Rect mSourceBounds; private Intent mSelector; @@ -3634,7 +3634,7 @@ public class Intent implements Parcelable, Cloneable { this.mComponent = o.mComponent; this.mFlags = o.mFlags; if (o.mCategories != null) { - this.mCategories = new HashSet<String>(o.mCategories); + this.mCategories = new ArraySet<String>(o.mCategories); } if (o.mExtras != null) { this.mExtras = new Bundle(o.mExtras); @@ -3662,7 +3662,7 @@ public class Intent implements Parcelable, Cloneable { this.mPackage = o.mPackage; this.mComponent = o.mComponent; if (o.mCategories != null) { - this.mCategories = new HashSet<String>(o.mCategories); + this.mCategories = new ArraySet<String>(o.mCategories); } } @@ -5226,7 +5226,7 @@ public class Intent implements Parcelable, Cloneable { */ public Intent addCategory(String category) { if (mCategories == null) { - mCategories = new HashSet<String>(); + mCategories = new ArraySet<String>(); } mCategories.add(category.intern()); return this; @@ -6370,7 +6370,7 @@ public class Intent implements Parcelable, Cloneable { if (other.mCategories != null && (mCategories == null || (flags&FILL_IN_CATEGORIES) != 0)) { if (other.mCategories != null) { - mCategories = new HashSet<String>(other.mCategories); + mCategories = new ArraySet<String>(other.mCategories); } changes |= FILL_IN_CATEGORIES; } @@ -6641,12 +6641,9 @@ public class Intent implements Parcelable, Cloneable { } first = false; b.append("cat=["); - Iterator<String> i = mCategories.iterator(); - boolean didone = false; - while (i.hasNext()) { - if (didone) b.append(","); - didone = true; - b.append(i.next()); + for (int i=0; i<mCategories.size(); i++) { + if (i > 0) b.append(','); + b.append(mCategories.valueAt(i)); } b.append("]"); } @@ -6804,8 +6801,8 @@ public class Intent implements Parcelable, Cloneable { uri.append("action=").append(Uri.encode(mAction)).append(';'); } if (mCategories != null) { - for (String category : mCategories) { - uri.append("category=").append(Uri.encode(category)).append(';'); + for (int i=0; i<mCategories.size(); i++) { + uri.append("category=").append(Uri.encode(mCategories.valueAt(i))).append(';'); } } if (mType != null) { @@ -6873,9 +6870,10 @@ public class Intent implements Parcelable, Cloneable { } if (mCategories != null) { - out.writeInt(mCategories.size()); - for (String category : mCategories) { - out.writeString(category); + final int N = mCategories.size(); + out.writeInt(N); + for (int i=0; i<N; i++) { + out.writeString(mCategories.valueAt(i)); } } else { out.writeInt(0); @@ -6927,7 +6925,7 @@ public class Intent implements Parcelable, Cloneable { int N = in.readInt(); if (N > 0) { - mCategories = new HashSet<String>(); + mCategories = new ArraySet<String>(); int i; for (i=0; i<N; i++) { mCategories.add(in.readString().intern()); diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 8a8751e..81f860e 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -955,6 +955,14 @@ public abstract class PackageManager { /** * Feature for {@link #getSystemAvailableFeatures} and + * {@link #hasSystemFeature}: The device supports host- + * based NFC card emulation. + */ + @SdkConstant(SdkConstantType.FEATURE) + public static final String FEATURE_NFC_HCE = "android.hardware.nfc.hce"; + + /** + * Feature for {@link #getSystemAvailableFeatures} and * {@link #hasSystemFeature}: The device includes an accelerometer. */ @SdkConstant(SdkConstantType.FEATURE) diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index 810a521..ce7addc 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -1554,10 +1554,15 @@ public class PackageParser { int type; PublicKey currentKey = null; + int currentKeyDepth = -1; Map<PublicKey, Set<String>> definedKeySets = new HashMap<PublicKey, Set<String>>(); while ((type = parser.next()) != XmlPullParser.END_DOCUMENT && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { if (type == XmlPullParser.END_TAG) { + if (parser.getDepth() == currentKeyDepth) { + currentKey = null; + currentKeyDepth = -1; + } continue; } String tagname = parser.getName(); @@ -1567,9 +1572,21 @@ public class PackageParser { final String encodedKey = sa.getNonResourceString( com.android.internal.R.styleable.PublicKey_value); currentKey = parsePublicKey(encodedKey); + if (currentKey == null) { + Slog.w(TAG, "No valid key in 'publicKey' tag at " + + parser.getPositionDescription()); + sa.recycle(); + continue; + } + currentKeyDepth = parser.getDepth(); definedKeySets.put(currentKey, new HashSet<String>()); sa.recycle(); } else if (tagname.equals("keyset")) { + if (currentKey == null) { + Slog.i(TAG, "'keyset' not in 'publicKey' tag at " + + parser.getPositionDescription()); + continue; + } final TypedArray sa = res.obtainAttributes(attrs, com.android.internal.R.styleable.KeySet); final String name = sa.getNonResourceString( diff --git a/core/java/android/hardware/photography/CameraMetadata.java b/core/java/android/hardware/photography/CameraMetadata.java index 4633b2f..c024c05 100644 --- a/core/java/android/hardware/photography/CameraMetadata.java +++ b/core/java/android/hardware/photography/CameraMetadata.java @@ -16,6 +16,10 @@ package android.hardware.photography; +import android.hardware.photography.impl.MetadataMarshalClass; +import android.hardware.photography.impl.MetadataMarshalRect; +import android.hardware.photography.impl.MetadataMarshalSize; +import android.hardware.photography.impl.MetadataMarshalString; import android.os.Parcelable; import android.os.Parcel; import android.util.Log; @@ -85,6 +89,11 @@ public class CameraMetadata implements Parcelable, AutoCloseable { public <T> void set(Key<T> key, T value) { int tag = key.getTag(); + if (value == null) { + writeValues(tag, null); + return; + } + int nativeType = getNativeType(tag); int size = packSingle(value, null, key.mType, nativeType, /* sizeOnly */true); @@ -265,6 +274,11 @@ public class CameraMetadata implements Parcelable, AutoCloseable { private static <T> int packClass(T value, ByteBuffer buffer, Class<T> type, int nativeType, boolean sizeOnly) { + MetadataMarshalClass<T> marshaler = getMarshaler(type, nativeType); + if (marshaler != null) { + return marshaler.marshal(value, buffer, nativeType, sizeOnly); + } + /** * FIXME: This doesn't actually work because getFields() returns fields in an unordered * manner. Although we could sort and get the data to come out correctly on the *java* side, @@ -558,6 +572,11 @@ public class CameraMetadata implements Parcelable, AutoCloseable { private static <T> T unpackClass(ByteBuffer buffer, Class<T> type, int nativeType) { + MetadataMarshalClass<T> marshaler = getMarshaler(type, nativeType); + if (marshaler != null) { + return marshaler.unmarshal(buffer, nativeType); + } + /** * FIXME: This doesn't actually work because getFields() returns fields in an unordered * manner. Although we could sort and get the data to come out correctly on the *java* side, @@ -611,14 +630,44 @@ public class CameraMetadata implements Parcelable, AutoCloseable { Class<?> componentType = type.getComponentType(); Object array; - int remaining = buffer.remaining(); - // FIXME: Assumes that the rest of the ByteBuffer is part of the array. - int arraySize = remaining / getTypeSize(nativeType); + int elementSize = getTypeSize(nativeType); + + MetadataMarshalClass<?> marshaler = getMarshaler(componentType, nativeType); + if (marshaler != null) { + elementSize = marshaler.getNativeSize(nativeType); + } + + if (elementSize != MetadataMarshalClass.NATIVE_SIZE_DYNAMIC) { + int remaining = buffer.remaining(); + int arraySize = remaining / elementSize; + + Log.v(TAG, + String.format( + "Attempting to unpack array (count = %d, element size = %d, bytes " + + "remaining = %d) for type %s", + arraySize, elementSize, remaining, type)); + + array = Array.newInstance(componentType, arraySize); + for (int i = 0; i < arraySize; ++i) { + Object elem = unpackSingle(buffer, componentType, nativeType); + Array.set(array, i, elem); + } + } else { + // Dynamic size, use an array list. + ArrayList<Object> arrayList = new ArrayList<Object>(); + + int primitiveSize = getTypeSize(nativeType); + while (buffer.remaining() >= primitiveSize) { + Object elem = unpackSingle(buffer, componentType, nativeType); + arrayList.add(elem); + } - array = Array.newInstance(componentType, arraySize); - for (int i = 0; i < arraySize; ++i) { - Object elem = unpackSingle(buffer, componentType, nativeType); - Array.set(array, i, elem); + array = arrayList.toArray((T[]) Array.newInstance(componentType, 0)); + } + + if (buffer.remaining() != 0) { + Log.e(TAG, "Trailing bytes (" + buffer.remaining() + ") left over after unpacking " + + type); } return (T) array; @@ -927,11 +976,39 @@ public class CameraMetadata implements Parcelable, AutoCloseable { return values[ordinal]; } + static HashMap<Class<?>, MetadataMarshalClass<?>> sMarshalerMap = new + HashMap<Class<?>, MetadataMarshalClass<?>>(); + + private static <T> void registerMarshaler(MetadataMarshalClass<T> marshaler) { + sMarshalerMap.put(marshaler.getMarshalingClass(), marshaler); + } + + @SuppressWarnings("unchecked") + private static <T> MetadataMarshalClass<T> getMarshaler(Class<T> type, int nativeType) { + MetadataMarshalClass<T> marshaler = (MetadataMarshalClass<T>) sMarshalerMap.get(type); + + if (marshaler != null && !marshaler.isNativeTypeSupported(nativeType)) { + throw new UnsupportedOperationException("Unsupported type " + nativeType + + " to be marshalled to/from a " + type); + } + + return marshaler; + } + /** * We use a class initializer to allow the native code to cache some field offsets */ static { System.loadLibrary("media_jni"); nativeClassInit(); + + Log.v(TAG, "Shall register metadata marshalers"); + + // load built-in marshallers + registerMarshaler(new MetadataMarshalRect()); + registerMarshaler(new MetadataMarshalSize()); + registerMarshaler(new MetadataMarshalString()); + + Log.v(TAG, "Registered metadata marshalers"); } } diff --git a/core/java/android/hardware/photography/CameraPropertiesKeys.java b/core/java/android/hardware/photography/CameraPropertiesKeys.java index 7e6380e..db8ab44 100644 --- a/core/java/android/hardware/photography/CameraPropertiesKeys.java +++ b/core/java/android/hardware/photography/CameraPropertiesKeys.java @@ -39,11 +39,8 @@ import static android.hardware.photography.CameraMetadata.Key; **/ public final class CameraPropertiesKeys { public static final class Control { - public static final Key<byte[]> AE_AVAILABLE_ANTIBANDING_MODES = new Key<byte[]>("android.control.aeAvailableAntibandingModes", byte[].class); - public static final Key<byte[]> AE_AVAILABLE_MODES = - new Key<byte[]>("android.control.aeAvailableModes", byte[].class); public static final Key<int[]> AE_AVAILABLE_TARGET_FPS_RANGES = new Key<int[]>("android.control.aeAvailableTargetFpsRanges", int[].class); public static final Key<int[]> AE_COMPENSATION_RANGE = @@ -62,40 +59,23 @@ public final class CameraPropertiesKeys { new Key<byte[]>("android.control.awbAvailableModes", byte[].class); public static final Key<Integer> MAX_REGIONS = new Key<Integer>("android.control.maxRegions", int.class); - public static final Key<byte[]> SCENE_MODE_OVERRIDES = - new Key<byte[]>("android.control.sceneModeOverrides", byte[].class); } + public static final class Flash { public static final class Info { public static final Key<Byte> AVAILABLE = new Key<Byte>("android.flash.info.available", byte.class); - public static final Key<Long> CHARGE_DURATION = - new Key<Long>("android.flash.info.chargeDuration", long.class); } - public static final Key<Byte> COLOR_TEMPERATURE = - new Key<Byte>("android.flash.colorTemperature", byte.class); - public static final Key<Byte> MAX_ENERGY = - new Key<Byte>("android.flash.maxEnergy", byte.class); - } - public static final class HotPixel { - public static final class Info { - public static final Key<int[]> MAP = - new Key<int[]>("android.hotPixel.info.map", int[].class); - } - - } public static final class Jpeg { - - public static final Key<int[]> AVAILABLE_THUMBNAIL_SIZES = - new Key<int[]>("android.jpeg.availableThumbnailSizes", int[].class); - public static final Key<Integer> MAX_SIZE = - new Key<Integer>("android.jpeg.maxSize", int.class); + public static final Key<android.hardware.photography.Size[]> AVAILABLE_THUMBNAIL_SIZES = + new Key<android.hardware.photography.Size[]>("android.jpeg.availableThumbnailSizes", android.hardware.photography.Size[].class); } + public static final class Lens { public static final class Info { public static final Key<float[]> AVAILABLE_APERTURES = @@ -106,21 +86,14 @@ public final class CameraPropertiesKeys { new Key<float[]>("android.lens.info.availableFocalLengths", float[].class); public static final Key<byte[]> AVAILABLE_OPTICAL_STABILIZATION = new Key<byte[]>("android.lens.info.availableOpticalStabilization", byte[].class); - public static final Key<float[]> GEOMETRIC_CORRECTION_MAP = - new Key<float[]>("android.lens.info.geometricCorrectionMap", float[].class); - public static final Key<int[]> GEOMETRIC_CORRECTION_MAP_SIZE = - new Key<int[]>("android.lens.info.geometricCorrectionMapSize", int[].class); public static final Key<Float> HYPERFOCAL_DISTANCE = new Key<Float>("android.lens.info.hyperfocalDistance", float.class); public static final Key<Float> MINIMUM_FOCUS_DISTANCE = new Key<Float>("android.lens.info.minimumFocusDistance", float.class); - public static final Key<float[]> SHADING_MAP = - new Key<float[]>("android.lens.info.shadingMap", float[].class); - public static final Key<int[]> SHADING_MAP_SIZE = - new Key<int[]>("android.lens.info.shadingMapSize", int[].class); + public static final Key<android.hardware.photography.Size> SHADING_MAP_SIZE = + new Key<android.hardware.photography.Size>("android.lens.info.shadingMapSize", android.hardware.photography.Size.class); } - public static final class FacingKey extends Key<Lens.FacingKey.Enum> { public enum Enum { FRONT, @@ -139,32 +112,16 @@ public final class CameraPropertiesKeys { public static final Key<Lens.FacingKey.Enum> FACING = new FacingKey("android.lens.facing"); - public static final Key<float[]> OPTICAL_AXIS_ANGLE = - new Key<float[]>("android.lens.opticalAxisAngle", float[].class); - public static final Key<float[]> POSITION = - new Key<float[]>("android.lens.position", float[].class); } - public static final class Quirks { - public static final Key<Byte> METERING_CROP_REGION = - new Key<Byte>("android.quirks.meteringCropRegion", byte.class); - public static final Key<Byte> TRIGGER_AF_WITH_AUTO = - new Key<Byte>("android.quirks.triggerAfWithAuto", byte.class); - public static final Key<Byte> USE_ZSL_FORMAT = - new Key<Byte>("android.quirks.useZslFormat", byte.class); - - } public static final class Request { - public static final Key<int[]> MAX_NUM_OUTPUT_STREAMS = new Key<int[]>("android.request.maxNumOutputStreams", int[].class); - public static final Key<int[]> MAX_NUM_REPROCESS_STREAMS = - new Key<int[]>("android.request.maxNumReprocessStreams", int[].class); } - public static final class Scaler { + public static final class Scaler { public static final class AvailableFormatsKey extends Key<Scaler.AvailableFormatsKey.Enum[]> { public enum Enum { @@ -204,192 +161,63 @@ public final class CameraPropertiesKeys { new AvailableFormatsKey("android.scaler.availableFormats"); public static final Key<long[]> AVAILABLE_JPEG_MIN_DURATIONS = new Key<long[]>("android.scaler.availableJpegMinDurations", long[].class); - public static final Key<int[]> AVAILABLE_JPEG_SIZES = - new Key<int[]>("android.scaler.availableJpegSizes", int[].class); + public static final Key<android.hardware.photography.Size[]> AVAILABLE_JPEG_SIZES = + new Key<android.hardware.photography.Size[]>("android.scaler.availableJpegSizes", android.hardware.photography.Size[].class); public static final Key<Float> AVAILABLE_MAX_DIGITAL_ZOOM = new Key<Float>("android.scaler.availableMaxDigitalZoom", float.class); public static final Key<long[]> AVAILABLE_PROCESSED_MIN_DURATIONS = new Key<long[]>("android.scaler.availableProcessedMinDurations", long[].class); - public static final Key<int[]> AVAILABLE_PROCESSED_SIZES = - new Key<int[]>("android.scaler.availableProcessedSizes", int[].class); - public static final Key<long[]> AVAILABLE_RAW_MIN_DURATIONS = - new Key<long[]>("android.scaler.availableRawMinDurations", long[].class); - public static final Key<int[]> AVAILABLE_RAW_SIZES = - new Key<int[]>("android.scaler.availableRawSizes", int[].class); + public static final Key<android.hardware.photography.Size[]> AVAILABLE_PROCESSED_SIZES = + new Key<android.hardware.photography.Size[]>("android.scaler.availableProcessedSizes", android.hardware.photography.Size[].class); } + public static final class Sensor { public static final class Info { - public static final Key<int[]> ACTIVE_ARRAY_SIZE = - new Key<int[]>("android.sensor.info.activeArraySize", int[].class); - public static final Key<int[]> AVAILABLE_SENSITIVITIES = - new Key<int[]>("android.sensor.info.availableSensitivities", int[].class); - - public static final class ColorFilterArrangementKey extends Key<Sensor.Info.ColorFilterArrangementKey.Enum> { - public enum Enum { - RGGB, - GRBG, - GBRG, - BGGR, - RGB; - } - - public static final Enum RGGB = Enum.RGGB; - public static final Enum GRBG = Enum.GRBG; - public static final Enum GBRG = Enum.GBRG; - public static final Enum BGGR = Enum.BGGR; - public static final Enum RGB = Enum.RGB; - - // TODO: remove requirement for constructor by making Key an interface - private ColorFilterArrangementKey(String name) { - super(name, Sensor.Info.ColorFilterArrangementKey.Enum.class); - } - - } - - public static final Key<Sensor.Info.ColorFilterArrangementKey.Enum> COLOR_FILTER_ARRANGEMENT = - new ColorFilterArrangementKey("android.sensor.info.colorFilterArrangement"); + public static final Key<android.graphics.Rect> ACTIVE_ARRAY_SIZE = + new Key<android.graphics.Rect>("android.sensor.info.activeArraySize", android.graphics.Rect.class); + public static final Key<int[]> SENSITIVITY_RANGE = + new Key<int[]>("android.sensor.info.sensitivityRange", int[].class); public static final Key<long[]> EXPOSURE_TIME_RANGE = new Key<long[]>("android.sensor.info.exposureTimeRange", long[].class); public static final Key<Long> MAX_FRAME_DURATION = new Key<Long>("android.sensor.info.maxFrameDuration", long.class); - public static final Key<float[]> PHYSICAL_SIZE = - new Key<float[]>("android.sensor.info.physicalSize", float[].class); - public static final Key<int[]> PIXEL_ARRAY_SIZE = - new Key<int[]>("android.sensor.info.pixelArraySize", int[].class); - public static final Key<Integer> WHITE_LEVEL = - new Key<Integer>("android.sensor.info.whiteLevel", int.class); + public static final Key<android.hardware.photography.Size> PHYSICAL_SIZE = + new Key<android.hardware.photography.Size>("android.sensor.info.physicalSize", android.hardware.photography.Size.class); } - public static final Key<Rational> BASE_GAIN_FACTOR = new Key<Rational>("android.sensor.baseGainFactor", Rational.class); - public static final Key<int[]> BLACK_LEVEL_PATTERN = - new Key<int[]>("android.sensor.blackLevelPattern", int[].class); - public static final Key<Rational[]> CALIBRATION_TRANSFORM1 = - new Key<Rational[]>("android.sensor.calibrationTransform1", Rational[].class); - public static final Key<Rational[]> CALIBRATION_TRANSFORM2 = - new Key<Rational[]>("android.sensor.calibrationTransform2", Rational[].class); - public static final Key<Rational[]> COLOR_TRANSFORM1 = - new Key<Rational[]>("android.sensor.colorTransform1", Rational[].class); - public static final Key<Rational[]> COLOR_TRANSFORM2 = - new Key<Rational[]>("android.sensor.colorTransform2", Rational[].class); - public static final Key<Rational[]> FORWARD_MATRIX1 = - new Key<Rational[]>("android.sensor.forwardMatrix1", Rational[].class); - public static final Key<Rational[]> FORWARD_MATRIX2 = - new Key<Rational[]>("android.sensor.forwardMatrix2", Rational[].class); public static final Key<Integer> MAX_ANALOG_SENSITIVITY = new Key<Integer>("android.sensor.maxAnalogSensitivity", int.class); - public static final Key<float[]> NOISE_MODEL_COEFFICIENTS = - new Key<float[]>("android.sensor.noiseModelCoefficients", float[].class); public static final Key<Integer> ORIENTATION = new Key<Integer>("android.sensor.orientation", int.class); - public static final class ReferenceIlluminant1Key extends Key<Sensor.ReferenceIlluminant1Key.Enum> { - public enum Enum { - DAYLIGHT, - FLUORESCENT, - TUNGSTEN, - FLASH, - FINE_WEATHER, - CLOUDY_WEATHER, - SHADE, - DAYLIGHT_FLUORESCENT, - DAY_WHITE_FLUORESCENT, - COOL_WHITE_FLUORESCENT, - WHITE_FLUORESCENT, - STANDARD_A, - STANDARD_B, - STANDARD_C, - D55, - D65, - D75, - D50, - ISO_STUDIO_TUNGSTEN; - } - - public static final Enum DAYLIGHT = Enum.DAYLIGHT; - public static final Enum FLUORESCENT = Enum.FLUORESCENT; - public static final Enum TUNGSTEN = Enum.TUNGSTEN; - public static final Enum FLASH = Enum.FLASH; - public static final Enum FINE_WEATHER = Enum.FINE_WEATHER; - public static final Enum CLOUDY_WEATHER = Enum.CLOUDY_WEATHER; - public static final Enum SHADE = Enum.SHADE; - public static final Enum DAYLIGHT_FLUORESCENT = Enum.DAYLIGHT_FLUORESCENT; - public static final Enum DAY_WHITE_FLUORESCENT = Enum.DAY_WHITE_FLUORESCENT; - public static final Enum COOL_WHITE_FLUORESCENT = Enum.COOL_WHITE_FLUORESCENT; - public static final Enum WHITE_FLUORESCENT = Enum.WHITE_FLUORESCENT; - public static final Enum STANDARD_A = Enum.STANDARD_A; - public static final Enum STANDARD_B = Enum.STANDARD_B; - public static final Enum STANDARD_C = Enum.STANDARD_C; - public static final Enum D55 = Enum.D55; - public static final Enum D65 = Enum.D65; - public static final Enum D75 = Enum.D75; - public static final Enum D50 = Enum.D50; - public static final Enum ISO_STUDIO_TUNGSTEN = Enum.ISO_STUDIO_TUNGSTEN; - - // TODO: remove requirement for constructor by making Key an interface - private ReferenceIlluminant1Key(String name) { - super(name, Sensor.ReferenceIlluminant1Key.Enum.class); - } - - static { - CameraMetadata.registerEnumValues(Sensor.ReferenceIlluminant1Key.Enum.class, new int[] { - 1, // DAYLIGHT - 2, // FLUORESCENT - 3, // TUNGSTEN - 4, // FLASH - 9, // FINE_WEATHER - 10, // CLOUDY_WEATHER - 11, // SHADE - 12, // DAYLIGHT_FLUORESCENT - 13, // DAY_WHITE_FLUORESCENT - 14, // COOL_WHITE_FLUORESCENT - 15, // WHITE_FLUORESCENT - 17, // STANDARD_A - 18, // STANDARD_B - 19, // STANDARD_C - 20, // D55 - 21, // D65 - 22, // D75 - 23, // D50 - 24 // ISO_STUDIO_TUNGSTEN - }); - } - } - - public static final Key<Sensor.ReferenceIlluminant1Key.Enum> REFERENCE_ILLUMINANT1 = - new ReferenceIlluminant1Key("android.sensor.referenceIlluminant1"); - public static final Key<Byte> REFERENCE_ILLUMINANT2 = - new Key<Byte>("android.sensor.referenceIlluminant2", byte.class); - } + public static final class Statistics { public static final class Info { public static final Key<byte[]> AVAILABLE_FACE_DETECT_MODES = new Key<byte[]>("android.statistics.info.availableFaceDetectModes", byte[].class); - public static final Key<Integer> HISTOGRAM_BUCKET_COUNT = - new Key<Integer>("android.statistics.info.histogramBucketCount", int.class); public static final Key<Integer> MAX_FACE_COUNT = new Key<Integer>("android.statistics.info.maxFaceCount", int.class); - public static final Key<Integer> MAX_HISTOGRAM_COUNT = - new Key<Integer>("android.statistics.info.maxHistogramCount", int.class); - public static final Key<Integer> MAX_SHARPNESS_MAP_VALUE = - new Key<Integer>("android.statistics.info.maxSharpnessMapValue", int.class); - public static final Key<int[]> SHARPNESS_MAP_SIZE = - new Key<int[]>("android.statistics.info.sharpnessMapSize", int[].class); } - } - public static final class Tonemap { + public static final class Tonemap { public static final Key<Integer> MAX_CURVE_POINTS = new Key<Integer>("android.tonemap.maxCurvePoints", int.class); } - public static final class Led { + /** + * @hide + */ + public static final class Led { + /** + * @hide + */ public static final class AvailableLedsKey extends Key<Led.AvailableLedsKey.Enum[]> { public enum Enum { TRANSMIT; @@ -404,12 +232,15 @@ public final class CameraPropertiesKeys { } + /** + * @hide + */ public static final Key<Led.AvailableLedsKey.Enum[]> AVAILABLE_LEDS = new AvailableLedsKey("android.led.availableLeds"); } - public static final class Info { + public static final class Info { public static final class SupportedHardwareLevelKey extends Key<Info.SupportedHardwareLevelKey.Enum> { public enum Enum { @@ -431,6 +262,7 @@ public final class CameraPropertiesKeys { new SupportedHardwareLevelKey("android.info.supportedHardwareLevel"); } + } diff --git a/core/java/android/hardware/photography/CaptureRequestKeys.java b/core/java/android/hardware/photography/CaptureRequestKeys.java index b8abe2b..ca6d487 100644 --- a/core/java/android/hardware/photography/CaptureRequestKeys.java +++ b/core/java/android/hardware/photography/CaptureRequestKeys.java @@ -40,7 +40,6 @@ import static android.hardware.photography.CameraMetadata.Key; public final class CaptureRequestKeys { public static final class ColorCorrection { - public static final class ModeKey extends Key<ColorCorrection.ModeKey.Enum> { public enum Enum { TRANSFORM_MATRIX, @@ -61,12 +60,14 @@ public final class CaptureRequestKeys { public static final Key<ColorCorrection.ModeKey.Enum> MODE = new ModeKey("android.colorCorrection.mode"); - public static final Key<float[]> TRANSFORM = - new Key<float[]>("android.colorCorrection.transform", float[].class); + public static final Key<Rational[]> TRANSFORM = + new Key<Rational[]>("android.colorCorrection.transform", Rational[].class); + public static final Key<float[]> GAINS = + new Key<float[]>("android.colorCorrection.gains", float[].class); } - public static final class Control { + public static final class Control { public static final class AeAntibandingModeKey extends Key<Control.AeAntibandingModeKey.Enum> { public enum Enum { @@ -92,25 +93,8 @@ public final class CaptureRequestKeys { new AeAntibandingModeKey("android.control.aeAntibandingMode"); public static final Key<Integer> AE_EXPOSURE_COMPENSATION = new Key<Integer>("android.control.aeExposureCompensation", int.class); - - public static final class AeLockKey extends Key<Control.AeLockKey.Enum> { - public enum Enum { - OFF, - ON; - } - - public static final Enum OFF = Enum.OFF; - public static final Enum ON = Enum.ON; - - // TODO: remove requirement for constructor by making Key an interface - private AeLockKey(String name) { - super(name, Control.AeLockKey.Enum.class); - } - - } - - public static final Key<Control.AeLockKey.Enum> AE_LOCK = - new AeLockKey("android.control.aeLock"); + public static final Key<Boolean> AE_LOCK = + new Key<Boolean>("android.control.aeLock", boolean.class); public static final class AeModeKey extends Key<Control.AeModeKey.Enum> { public enum Enum { @@ -209,25 +193,8 @@ public final class CaptureRequestKeys { public static final Key<Control.AfTriggerKey.Enum> AF_TRIGGER = new AfTriggerKey("android.control.afTrigger"); - - public static final class AwbLockKey extends Key<Control.AwbLockKey.Enum> { - public enum Enum { - OFF, - ON; - } - - public static final Enum OFF = Enum.OFF; - public static final Enum ON = Enum.ON; - - // TODO: remove requirement for constructor by making Key an interface - private AwbLockKey(String name) { - super(name, Control.AwbLockKey.Enum.class); - } - - } - - public static final Key<Control.AwbLockKey.Enum> AWB_LOCK = - new AwbLockKey("android.control.awbLock"); + public static final Key<Boolean> AWB_LOCK = + new Key<Boolean>("android.control.awbLock", boolean.class); public static final class AwbModeKey extends Key<Control.AwbModeKey.Enum> { public enum Enum { @@ -414,53 +381,13 @@ public final class CaptureRequestKeys { public static final Key<Control.SceneModeKey.Enum> SCENE_MODE = new SceneModeKey("android.control.sceneMode"); - - public static final class VideoStabilizationModeKey extends Key<Control.VideoStabilizationModeKey.Enum> { - public enum Enum { - OFF, - ON; - } - - public static final Enum OFF = Enum.OFF; - public static final Enum ON = Enum.ON; - - // TODO: remove requirement for constructor by making Key an interface - private VideoStabilizationModeKey(String name) { - super(name, Control.VideoStabilizationModeKey.Enum.class); - } - - } - - public static final Key<Control.VideoStabilizationModeKey.Enum> VIDEO_STABILIZATION_MODE = - new VideoStabilizationModeKey("android.control.videoStabilizationMode"); + public static final Key<Boolean> VIDEO_STABILIZATION_MODE = + new Key<Boolean>("android.control.videoStabilizationMode", boolean.class); } - public static final class Demosaic { - - - public static final class ModeKey extends Key<Demosaic.ModeKey.Enum> { - public enum Enum { - FAST, - HIGH_QUALITY; - } - public static final Enum FAST = Enum.FAST; - public static final Enum HIGH_QUALITY = Enum.HIGH_QUALITY; - - // TODO: remove requirement for constructor by making Key an interface - private ModeKey(String name) { - super(name, Demosaic.ModeKey.Enum.class); - } - - } - - public static final Key<Demosaic.ModeKey.Enum> MODE = - new ModeKey("android.demosaic.mode"); - - } public static final class Edge { - public static final class ModeKey extends Key<Edge.ModeKey.Enum> { public enum Enum { OFF, @@ -481,16 +408,10 @@ public final class CaptureRequestKeys { public static final Key<Edge.ModeKey.Enum> MODE = new ModeKey("android.edge.mode"); - public static final Key<Byte> STRENGTH = - new Key<Byte>("android.edge.strength", byte.class); } - public static final class Flash { - public static final Key<Byte> FIRING_POWER = - new Key<Byte>("android.flash.firingPower", byte.class); - public static final Key<Long> FIRING_TIME = - new Key<Long>("android.flash.firingTime", long.class); + public static final class Flash { public static final class ModeKey extends Key<Flash.ModeKey.Enum> { public enum Enum { @@ -514,64 +435,12 @@ public final class CaptureRequestKeys { new ModeKey("android.flash.mode"); } - public static final class Geometric { - - - public static final class ModeKey extends Key<Geometric.ModeKey.Enum> { - public enum Enum { - OFF, - FAST, - HIGH_QUALITY; - } - - public static final Enum OFF = Enum.OFF; - public static final Enum FAST = Enum.FAST; - public static final Enum HIGH_QUALITY = Enum.HIGH_QUALITY; - - // TODO: remove requirement for constructor by making Key an interface - private ModeKey(String name) { - super(name, Geometric.ModeKey.Enum.class); - } - - } - - public static final Key<Geometric.ModeKey.Enum> MODE = - new ModeKey("android.geometric.mode"); - public static final Key<Byte> STRENGTH = - new Key<Byte>("android.geometric.strength", byte.class); - - } - public static final class HotPixel { - - - public static final class ModeKey extends Key<HotPixel.ModeKey.Enum> { - public enum Enum { - OFF, - FAST, - HIGH_QUALITY; - } - - public static final Enum OFF = Enum.OFF; - public static final Enum FAST = Enum.FAST; - public static final Enum HIGH_QUALITY = Enum.HIGH_QUALITY; - - // TODO: remove requirement for constructor by making Key an interface - private ModeKey(String name) { - super(name, HotPixel.ModeKey.Enum.class); - } - - } - public static final Key<HotPixel.ModeKey.Enum> MODE = - new ModeKey("android.hotPixel.mode"); - - } public static final class Jpeg { - public static final Key<double[]> GPS_COORDINATES = new Key<double[]>("android.jpeg.gpsCoordinates", double[].class); - public static final Key<Byte> GPS_PROCESSING_METHOD = - new Key<Byte>("android.jpeg.gpsProcessingMethod", byte.class); + public static final Key<String> GPS_PROCESSING_METHOD = + new Key<String>("android.jpeg.gpsProcessingMethod", String.class); public static final Key<Long> GPS_TIMESTAMP = new Key<Long>("android.jpeg.gpsTimestamp", long.class); public static final Key<Integer> ORIENTATION = @@ -580,12 +449,12 @@ public final class CaptureRequestKeys { new Key<Byte>("android.jpeg.quality", byte.class); public static final Key<Byte> THUMBNAIL_QUALITY = new Key<Byte>("android.jpeg.thumbnailQuality", byte.class); - public static final Key<int[]> THUMBNAIL_SIZE = - new Key<int[]>("android.jpeg.thumbnailSize", int[].class); + public static final Key<android.hardware.photography.Size> THUMBNAIL_SIZE = + new Key<android.hardware.photography.Size>("android.jpeg.thumbnailSize", android.hardware.photography.Size.class); } - public static final class Lens { + public static final class Lens { public static final Key<Float> APERTURE = new Key<Float>("android.lens.aperture", float.class); public static final Key<Float> FILTER_DENSITY = @@ -615,8 +484,8 @@ public final class CaptureRequestKeys { new OpticalStabilizationModeKey("android.lens.opticalStabilizationMode"); } - public static final class NoiseReduction { + public static final class NoiseReduction { public static final class ModeKey extends Key<NoiseReduction.ModeKey.Enum> { public enum Enum { @@ -638,68 +507,28 @@ public final class CaptureRequestKeys { public static final Key<NoiseReduction.ModeKey.Enum> MODE = new ModeKey("android.noiseReduction.mode"); - public static final Key<Byte> STRENGTH = - new Key<Byte>("android.noiseReduction.strength", byte.class); } - public static final class Request { - public static final Key<Integer> FRAME_COUNT = - new Key<Integer>("android.request.frameCount", int.class); + /** + * @hide + */ + public static final class Request { + /** + * @hide + */ public static final Key<Integer> ID = new Key<Integer>("android.request.id", int.class); - public static final Key<Byte> INPUT_STREAMS = - new Key<Byte>("android.request.inputStreams", byte.class); - - public static final class MetadataModeKey extends Key<Request.MetadataModeKey.Enum> { - public enum Enum { - NONE, - FULL; - } - - public static final Enum NONE = Enum.NONE; - public static final Enum FULL = Enum.FULL; - - // TODO: remove requirement for constructor by making Key an interface - private MetadataModeKey(String name) { - super(name, Request.MetadataModeKey.Enum.class); - } - - } - - public static final Key<Request.MetadataModeKey.Enum> METADATA_MODE = - new MetadataModeKey("android.request.metadataMode"); - public static final Key<Byte> OUTPUT_STREAMS = - new Key<Byte>("android.request.outputStreams", byte.class); - - public static final class TypeKey extends Key<Request.TypeKey.Enum> { - public enum Enum { - CAPTURE, - REPROCESS; - } - - public static final Enum CAPTURE = Enum.CAPTURE; - public static final Enum REPROCESS = Enum.REPROCESS; - - // TODO: remove requirement for constructor by making Key an interface - private TypeKey(String name) { - super(name, Request.TypeKey.Enum.class); - } - - } - - public static final Key<Request.TypeKey.Enum> TYPE = - new TypeKey("android.request.type"); } - public static final class Scaler { - public static final Key<int[]> CROP_REGION = - new Key<int[]>("android.scaler.cropRegion", int[].class); + public static final class Scaler { + public static final Key<android.graphics.Rect> CROP_REGION = + new Key<android.graphics.Rect>("android.scaler.cropRegion", android.graphics.Rect.class); } - public static final class Sensor { + public static final class Sensor { public static final Key<Long> EXPOSURE_TIME = new Key<Long>("android.sensor.exposureTime", long.class); public static final Key<Long> FRAME_DURATION = @@ -708,36 +537,9 @@ public final class CaptureRequestKeys { new Key<Integer>("android.sensor.sensitivity", int.class); } - public static final class Shading { - - public static final class ModeKey extends Key<Shading.ModeKey.Enum> { - public enum Enum { - OFF, - FAST, - HIGH_QUALITY; - } - - public static final Enum OFF = Enum.OFF; - public static final Enum FAST = Enum.FAST; - public static final Enum HIGH_QUALITY = Enum.HIGH_QUALITY; - - // TODO: remove requirement for constructor by making Key an interface - private ModeKey(String name) { - super(name, Shading.ModeKey.Enum.class); - } - - } - - public static final Key<Shading.ModeKey.Enum> MODE = - new ModeKey("android.shading.mode"); - public static final Key<Byte> STRENGTH = - new Key<Byte>("android.shading.strength", byte.class); - - } public static final class Statistics { - public static final class FaceDetectModeKey extends Key<Statistics.FaceDetectModeKey.Enum> { public enum Enum { OFF, @@ -759,47 +561,9 @@ public final class CaptureRequestKeys { public static final Key<Statistics.FaceDetectModeKey.Enum> FACE_DETECT_MODE = new FaceDetectModeKey("android.statistics.faceDetectMode"); - public static final class HistogramModeKey extends Key<Statistics.HistogramModeKey.Enum> { - public enum Enum { - OFF, - ON; - } - - public static final Enum OFF = Enum.OFF; - public static final Enum ON = Enum.ON; - - // TODO: remove requirement for constructor by making Key an interface - private HistogramModeKey(String name) { - super(name, Statistics.HistogramModeKey.Enum.class); - } - - } - - public static final Key<Statistics.HistogramModeKey.Enum> HISTOGRAM_MODE = - new HistogramModeKey("android.statistics.histogramMode"); - - public static final class SharpnessMapModeKey extends Key<Statistics.SharpnessMapModeKey.Enum> { - public enum Enum { - OFF, - ON; - } - - public static final Enum OFF = Enum.OFF; - public static final Enum ON = Enum.ON; - - // TODO: remove requirement for constructor by making Key an interface - private SharpnessMapModeKey(String name) { - super(name, Statistics.SharpnessMapModeKey.Enum.class); - } - - } - - public static final Key<Statistics.SharpnessMapModeKey.Enum> SHARPNESS_MAP_MODE = - new SharpnessMapModeKey("android.statistics.sharpnessMapMode"); - } - public static final class Tonemap { + public static final class Tonemap { public static final Key<Float> CURVE_BLUE = new Key<Float>("android.tonemap.curveBlue", float.class); public static final Key<Float> CURVE_GREEN = @@ -829,29 +593,25 @@ public final class CaptureRequestKeys { new ModeKey("android.tonemap.mode"); } - public static final class Led { + /** + * @hide + */ + public static final class Led { + /** + * @hide + */ + public static final Key<Boolean> TRANSMIT = + new Key<Boolean>("android.led.transmit", boolean.class); - public static final class TransmitKey extends Key<Led.TransmitKey.Enum> { - public enum Enum { - OFF, - ON; - } - - public static final Enum OFF = Enum.OFF; - public static final Enum ON = Enum.ON; - - // TODO: remove requirement for constructor by making Key an interface - private TransmitKey(String name) { - super(name, Led.TransmitKey.Enum.class); - } - - } + } - public static final Key<Led.TransmitKey.Enum> TRANSMIT = - new TransmitKey("android.led.transmit"); + public static final class BlackLevel { + public static final Key<Boolean> LOCK = + new Key<Boolean>("android.blackLevel.lock", boolean.class); } + } diff --git a/core/java/android/hardware/photography/CaptureResultKeys.java b/core/java/android/hardware/photography/CaptureResultKeys.java index 5a638ed..4931564 100644 --- a/core/java/android/hardware/photography/CaptureResultKeys.java +++ b/core/java/android/hardware/photography/CaptureResultKeys.java @@ -39,32 +39,17 @@ import static android.hardware.photography.CameraMetadata.Key; **/ public final class CaptureResultKeys { public static final class ColorCorrection { - - - public static final class ModeKey extends Key<ColorCorrection.ModeKey.Enum> { - public enum Enum { - TRANSFORM_MATRIX, - FAST, - HIGH_QUALITY; - } - - public static final Enum TRANSFORM_MATRIX = Enum.TRANSFORM_MATRIX; - public static final Enum FAST = Enum.FAST; - public static final Enum HIGH_QUALITY = Enum.HIGH_QUALITY; - - // TODO: remove requirement for constructor by making Key an interface - private ModeKey(String name) { - super(name, ColorCorrection.ModeKey.Enum.class); - } - - } - - public static final Key<ColorCorrection.ModeKey.Enum> MODE = - new ModeKey("android.colorCorrection.mode"); + public static final Key<Rational[]> TRANSFORM = + new Key<Rational[]>("android.colorCorrection.transform", Rational[].class); + public static final Key<float[]> GAINS = + new Key<float[]>("android.colorCorrection.gains", float[].class); } - public static final class Control { + public static final class Control { + /** + * @hide + */ public static final Key<Integer> AE_PRECAPTURE_ID = new Key<Integer>("android.control.aePrecaptureId", int.class); public static final Key<int[]> AE_REGIONS = @@ -152,6 +137,9 @@ public final class CaptureResultKeys { public static final Key<Control.AfStateKey.Enum> AF_STATE = new AfStateKey("android.control.afState"); + /** + * @hide + */ public static final Key<Integer> AF_TRIGGER_ID = new Key<Integer>("android.control.afTriggerId", int.class); @@ -235,8 +223,8 @@ public final class CaptureResultKeys { new ModeKey("android.control.mode"); } - public static final class Edge { + public static final class Edge { public static final class ModeKey extends Key<Edge.ModeKey.Enum> { public enum Enum { @@ -260,12 +248,8 @@ public final class CaptureResultKeys { new ModeKey("android.edge.mode"); } - public static final class Flash { - public static final Key<Byte> FIRING_POWER = - new Key<Byte>("android.flash.firingPower", byte.class); - public static final Key<Long> FIRING_TIME = - new Key<Long>("android.flash.firingTime", long.class); + public static final class Flash { public static final class ModeKey extends Key<Flash.ModeKey.Enum> { public enum Enum { @@ -312,53 +296,26 @@ public final class CaptureResultKeys { new StateKey("android.flash.state"); } - public static final class HotPixel { - - - public static final class ModeKey extends Key<HotPixel.ModeKey.Enum> { - public enum Enum { - OFF, - FAST, - HIGH_QUALITY; - } - public static final Enum OFF = Enum.OFF; - public static final Enum FAST = Enum.FAST; - public static final Enum HIGH_QUALITY = Enum.HIGH_QUALITY; - - // TODO: remove requirement for constructor by making Key an interface - private ModeKey(String name) { - super(name, HotPixel.ModeKey.Enum.class); - } - - } - - public static final Key<HotPixel.ModeKey.Enum> MODE = - new ModeKey("android.hotPixel.mode"); - - } public static final class Jpeg { - public static final Key<double[]> GPS_COORDINATES = new Key<double[]>("android.jpeg.gpsCoordinates", double[].class); - public static final Key<Byte> GPS_PROCESSING_METHOD = - new Key<Byte>("android.jpeg.gpsProcessingMethod", byte.class); + public static final Key<String> GPS_PROCESSING_METHOD = + new Key<String>("android.jpeg.gpsProcessingMethod", String.class); public static final Key<Long> GPS_TIMESTAMP = new Key<Long>("android.jpeg.gpsTimestamp", long.class); public static final Key<Integer> ORIENTATION = new Key<Integer>("android.jpeg.orientation", int.class); public static final Key<Byte> QUALITY = new Key<Byte>("android.jpeg.quality", byte.class); - public static final Key<Integer> SIZE = - new Key<Integer>("android.jpeg.size", int.class); public static final Key<Byte> THUMBNAIL_QUALITY = new Key<Byte>("android.jpeg.thumbnailQuality", byte.class); - public static final Key<int[]> THUMBNAIL_SIZE = - new Key<int[]>("android.jpeg.thumbnailSize", int[].class); + public static final Key<android.hardware.photography.Size> THUMBNAIL_SIZE = + new Key<android.hardware.photography.Size>("android.jpeg.thumbnailSize", android.hardware.photography.Size.class); } - public static final class Lens { + public static final class Lens { public static final Key<Float> APERTURE = new Key<Float>("android.lens.aperture", float.class); public static final Key<Float> FILTER_DENSITY = @@ -407,8 +364,8 @@ public final class CaptureResultKeys { new StateKey("android.lens.state"); } - public static final class NoiseReduction { + public static final class NoiseReduction { public static final class ModeKey extends Key<NoiseReduction.ModeKey.Enum> { public enum Enum { @@ -432,43 +389,25 @@ public final class CaptureResultKeys { new ModeKey("android.noiseReduction.mode"); } - public static final class Request { + public static final class Request { public static final Key<Integer> FRAME_COUNT = new Key<Integer>("android.request.frameCount", int.class); + /** + * @hide + */ public static final Key<Integer> ID = new Key<Integer>("android.request.id", int.class); - public static final class MetadataModeKey extends Key<Request.MetadataModeKey.Enum> { - public enum Enum { - NONE, - FULL; - } - - public static final Enum NONE = Enum.NONE; - public static final Enum FULL = Enum.FULL; - - // TODO: remove requirement for constructor by making Key an interface - private MetadataModeKey(String name) { - super(name, Request.MetadataModeKey.Enum.class); - } - - } - - public static final Key<Request.MetadataModeKey.Enum> METADATA_MODE = - new MetadataModeKey("android.request.metadataMode"); - public static final Key<Byte> OUTPUT_STREAMS = - new Key<Byte>("android.request.outputStreams", byte.class); - } - public static final class Scaler { - public static final Key<int[]> CROP_REGION = - new Key<int[]>("android.scaler.cropRegion", int[].class); + public static final class Scaler { + public static final Key<android.graphics.Rect> CROP_REGION = + new Key<android.graphics.Rect>("android.scaler.cropRegion", android.graphics.Rect.class); } - public static final class Sensor { + public static final class Sensor { public static final Key<Long> EXPOSURE_TIME = new Key<Long>("android.sensor.exposureTime", long.class); public static final Key<Long> FRAME_DURATION = @@ -479,34 +418,9 @@ public final class CaptureResultKeys { new Key<Long>("android.sensor.timestamp", long.class); } - public static final class Shading { - - - public static final class ModeKey extends Key<Shading.ModeKey.Enum> { - public enum Enum { - OFF, - FAST, - HIGH_QUALITY; - } - - public static final Enum OFF = Enum.OFF; - public static final Enum FAST = Enum.FAST; - public static final Enum HIGH_QUALITY = Enum.HIGH_QUALITY; - // TODO: remove requirement for constructor by making Key an interface - private ModeKey(String name) { - super(name, Shading.ModeKey.Enum.class); - } - - } - - public static final Key<Shading.ModeKey.Enum> MODE = - new ModeKey("android.shading.mode"); - - } public static final class Statistics { - public static final class FaceDetectModeKey extends Key<Statistics.FaceDetectModeKey.Enum> { public enum Enum { OFF, @@ -531,56 +445,41 @@ public final class CaptureResultKeys { new Key<int[]>("android.statistics.faceIds", int[].class); public static final Key<int[]> FACE_LANDMARKS = new Key<int[]>("android.statistics.faceLandmarks", int[].class); - public static final Key<int[]> FACE_RECTANGLES = - new Key<int[]>("android.statistics.faceRectangles", int[].class); + public static final Key<android.graphics.Rect[]> FACE_RECTANGLES = + new Key<android.graphics.Rect[]>("android.statistics.faceRectangles", android.graphics.Rect[].class); public static final Key<byte[]> FACE_SCORES = new Key<byte[]>("android.statistics.faceScores", byte[].class); - public static final Key<int[]> HISTOGRAM = - new Key<int[]>("android.statistics.histogram", int[].class); - - public static final class HistogramModeKey extends Key<Statistics.HistogramModeKey.Enum> { - public enum Enum { - OFF, - ON; - } - - public static final Enum OFF = Enum.OFF; - public static final Enum ON = Enum.ON; - - // TODO: remove requirement for constructor by making Key an interface - private HistogramModeKey(String name) { - super(name, Statistics.HistogramModeKey.Enum.class); - } - - } - - public static final Key<Statistics.HistogramModeKey.Enum> HISTOGRAM_MODE = - new HistogramModeKey("android.statistics.histogramMode"); - public static final Key<int[]> SHARPNESS_MAP = - new Key<int[]>("android.statistics.sharpnessMap", int[].class); - - public static final class SharpnessMapModeKey extends Key<Statistics.SharpnessMapModeKey.Enum> { + public static final Key<float[]> LENS_SHADING_MAP = + new Key<float[]>("android.statistics.lensShadingMap", float[].class); + public static final Key<float[]> PREDICTED_COLOR_GAINS = + new Key<float[]>("android.statistics.predictedColorGains", float[].class); + public static final Key<Rational[]> PREDICTED_COLOR_TRANSFORM = + new Key<Rational[]>("android.statistics.predictedColorTransform", Rational[].class); + + public static final class SceneFlickerKey extends Key<Statistics.SceneFlickerKey.Enum> { public enum Enum { - OFF, - ON; + NONE, + _50HZ, + _60HZ; } - public static final Enum OFF = Enum.OFF; - public static final Enum ON = Enum.ON; + public static final Enum NONE = Enum.NONE; + public static final Enum _50HZ = Enum._50HZ; + public static final Enum _60HZ = Enum._60HZ; // TODO: remove requirement for constructor by making Key an interface - private SharpnessMapModeKey(String name) { - super(name, Statistics.SharpnessMapModeKey.Enum.class); + private SceneFlickerKey(String name) { + super(name, Statistics.SceneFlickerKey.Enum.class); } } - public static final Key<Statistics.SharpnessMapModeKey.Enum> SHARPNESS_MAP_MODE = - new SharpnessMapModeKey("android.statistics.sharpnessMapMode"); + public static final Key<Statistics.SceneFlickerKey.Enum> SCENE_FLICKER = + new SceneFlickerKey("android.statistics.sceneFlicker"); } - public static final class Tonemap { + public static final class Tonemap { public static final Key<Float> CURVE_BLUE = new Key<Float>("android.tonemap.curveBlue", float.class); public static final Key<Float> CURVE_GREEN = @@ -610,29 +509,25 @@ public final class CaptureResultKeys { new ModeKey("android.tonemap.mode"); } - public static final class Led { + /** + * @hide + */ + public static final class Led { + /** + * @hide + */ + public static final Key<Boolean> TRANSMIT = + new Key<Boolean>("android.led.transmit", boolean.class); - public static final class TransmitKey extends Key<Led.TransmitKey.Enum> { - public enum Enum { - OFF, - ON; - } - - public static final Enum OFF = Enum.OFF; - public static final Enum ON = Enum.ON; - - // TODO: remove requirement for constructor by making Key an interface - private TransmitKey(String name) { - super(name, Led.TransmitKey.Enum.class); - } - - } + } - public static final Key<Led.TransmitKey.Enum> TRANSMIT = - new TransmitKey("android.led.transmit"); + public static final class BlackLevel { + public static final Key<Boolean> LOCK = + new Key<Boolean>("android.blackLevel.lock", boolean.class); } + } diff --git a/core/java/android/hardware/photography/impl/MetadataMarshalClass.java b/core/java/android/hardware/photography/impl/MetadataMarshalClass.java new file mode 100644 index 0000000..a70784d --- /dev/null +++ b/core/java/android/hardware/photography/impl/MetadataMarshalClass.java @@ -0,0 +1,67 @@ +/* + * 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.hardware.photography.impl; + +import java.nio.ByteBuffer; + +public interface MetadataMarshalClass<T> { + + /** + * Marshal the specified object instance (value) into a byte buffer. + * + * @param value the value of type T that we wish to write into the byte buffer + * @param buffer the byte buffer into which the marshalled object will be written + * @param nativeType the native type, e.g. + * {@link android.hardware.photography.CameraMetadata#TYPE_BYTE TYPE_BYTE}. + * Guaranteed to be one for which isNativeTypeSupported returns true. + * @param sizeOnly if this is true, don't write to the byte buffer. calculate the size only. + * @return the size that needs to be written to the byte buffer + */ + int marshal(T value, ByteBuffer buffer, int nativeType, boolean sizeOnly); + + /** + * Unmarshal a new object instance from the byte buffer. + * @param buffer the byte buffer, from which we will read the object + * @param nativeType the native type, e.g. + * {@link android.hardware.photography.CameraMetadata#TYPE_BYTE TYPE_BYTE}. + * Guaranteed to be one for which isNativeTypeSupported returns true. + * @return a new instance of type T read from the byte buffer + */ + T unmarshal(ByteBuffer buffer, int nativeType); + + Class<T> getMarshalingClass(); + + /** + * Determines whether or not this marshaller supports this native type. Most marshallers + * will are likely to only support one type. + * + * @param nativeType the native type, e.g. + * {@link android.hardware.photography.CameraMetadata#TYPE_BYTE TYPE_BYTE} + * @return true if it supports, false otherwise + */ + boolean isNativeTypeSupported(int nativeType); + + public static int NATIVE_SIZE_DYNAMIC = -1; + + /** + * How many bytes T will take up if marshalled to/from nativeType + * @param nativeType the native type, e.g. + * {@link android.hardware.photography.CameraMetadata#TYPE_BYTE TYPE_BYTE} + * @return a size in bytes, or NATIVE_SIZE_DYNAMIC if the size is dynamic + */ + int getNativeSize(int nativeType); +} diff --git a/core/java/android/hardware/photography/impl/MetadataMarshalRect.java b/core/java/android/hardware/photography/impl/MetadataMarshalRect.java new file mode 100644 index 0000000..d6636ac --- /dev/null +++ b/core/java/android/hardware/photography/impl/MetadataMarshalRect.java @@ -0,0 +1,68 @@ +/* + * 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.hardware.photography.impl; + +import android.graphics.Rect; +import android.hardware.photography.CameraMetadata; + +import java.nio.ByteBuffer; + +public class MetadataMarshalRect implements MetadataMarshalClass<Rect> { + private static final int SIZE = 16; + + @Override + public int marshal(Rect value, ByteBuffer buffer, int nativeType, boolean sizeOnly) { + if (sizeOnly) { + return SIZE; + } + + buffer.putInt(value.left); + buffer.putInt(value.top); + buffer.putInt(value.width()); + buffer.putInt(value.height()); + + return SIZE; + } + + @Override + public Rect unmarshal(ByteBuffer buffer, int nativeType) { + + int left = buffer.getInt(); + int top = buffer.getInt(); + int width = buffer.getInt(); + int height = buffer.getInt(); + + int right = left + width; + int bottom = top + height; + + return new Rect(left, top, right, bottom); + } + + @Override + public Class<Rect> getMarshalingClass() { + return Rect.class; + } + + @Override + public boolean isNativeTypeSupported(int nativeType) { + return nativeType == CameraMetadata.TYPE_INT32; + } + + @Override + public int getNativeSize(int nativeType) { + return SIZE; + } +} diff --git a/core/java/android/hardware/photography/impl/MetadataMarshalSize.java b/core/java/android/hardware/photography/impl/MetadataMarshalSize.java new file mode 100644 index 0000000..430219c --- /dev/null +++ b/core/java/android/hardware/photography/impl/MetadataMarshalSize.java @@ -0,0 +1,61 @@ +/* + * 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.hardware.photography.impl; + +import android.hardware.photography.CameraMetadata; +import android.hardware.photography.Size; + +import java.nio.ByteBuffer; + +public class MetadataMarshalSize implements MetadataMarshalClass<Size> { + + private static final int SIZE = 8; + + @Override + public int marshal(Size value, ByteBuffer buffer, int nativeType, boolean sizeOnly) { + if (sizeOnly) { + return SIZE; + } + + buffer.putInt(value.getWidth()); + buffer.putInt(value.getHeight()); + + return SIZE; + } + + @Override + public Size unmarshal(ByteBuffer buffer, int nativeType) { + int width = buffer.getInt(); + int height = buffer.getInt(); + + return new Size(width, height); + } + + @Override + public Class<Size> getMarshalingClass() { + return Size.class; + } + + @Override + public boolean isNativeTypeSupported(int nativeType) { + return nativeType == CameraMetadata.TYPE_INT32; + } + + @Override + public int getNativeSize(int nativeType) { + return SIZE; + } +} diff --git a/core/java/android/hardware/photography/impl/MetadataMarshalString.java b/core/java/android/hardware/photography/impl/MetadataMarshalString.java new file mode 100644 index 0000000..81123ee --- /dev/null +++ b/core/java/android/hardware/photography/impl/MetadataMarshalString.java @@ -0,0 +1,81 @@ +/* + * 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.hardware.photography.impl; + +import android.hardware.photography.CameraMetadata; + +import java.nio.ByteBuffer; +import java.nio.charset.Charset; + +public class MetadataMarshalString implements MetadataMarshalClass<String> { + + private static final Charset UTF8_CHARSET = Charset.forName("UTF-8"); + + @Override + public int marshal(String value, ByteBuffer buffer, int nativeType, boolean sizeOnly) { + byte[] arr = value.getBytes(UTF8_CHARSET); + + if (!sizeOnly) { + buffer.put(arr); + buffer.put((byte)0); // metadata strings are NULL-terminated + } + + return arr.length + 1; + } + + @Override + public String unmarshal(ByteBuffer buffer, int nativeType) { + + buffer.mark(); // save the current position + + boolean foundNull = false; + int stringLength = 0; + while (buffer.hasRemaining()) { + if (buffer.get() == (byte)0) { + foundNull = true; + break; + } + + stringLength++; + } + if (!foundNull) { + throw new IllegalArgumentException("Strings must be null-terminated"); + } + + buffer.reset(); // go back to the previously marked position + + byte[] strBytes = new byte[stringLength + 1]; + buffer.get(strBytes, /*dstOffset*/0, stringLength + 1); // including null character + + // not including null character + return new String(strBytes, /*offset*/0, stringLength, UTF8_CHARSET); + } + + @Override + public Class<String> getMarshalingClass() { + return String.class; + } + + @Override + public boolean isNativeTypeSupported(int nativeType) { + return nativeType == CameraMetadata.TYPE_BYTE; + } + + @Override + public int getNativeSize(int nativeType) { + return NATIVE_SIZE_DYNAMIC; + } +} diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 04ab0a5..f920874 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -1373,4 +1373,16 @@ public class ConnectivityManager { } return timeOutMs; } + + /** + * Get the carrier provisioning url. + * {@hide} + */ + public String getMobileProvisioningUrl() { + try { + return mService.getMobileProvisioningUrl(); + } catch (RemoteException e) { + } + return null; + } } diff --git a/core/java/android/net/DhcpStateMachine.java b/core/java/android/net/DhcpStateMachine.java index 1ebf393..5151a04 100644 --- a/core/java/android/net/DhcpStateMachine.java +++ b/core/java/android/net/DhcpStateMachine.java @@ -374,7 +374,7 @@ public class DhcpStateMachine extends StateMachine { //Do it a bit earlier than half the lease duration time //to beat the native DHCP client and avoid extra packets //48% for one hour lease time = 29 minutes - mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, + mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + leaseDuration * 480, //in milliseconds mDhcpRenewalIntent); diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index 0a476eb..b0f7fc6 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -139,4 +139,6 @@ interface IConnectivityManager int findConnectionTypeForIface(in String iface); int checkMobileProvisioning(boolean sendNotification, int suggestedTimeOutMs, in ResultReceiver resultReceiver); + + String getMobileProvisioningUrl(); } diff --git a/core/java/android/net/LocalServerSocket.java b/core/java/android/net/LocalServerSocket.java index 2b93fc2..a36203b 100644 --- a/core/java/android/net/LocalServerSocket.java +++ b/core/java/android/net/LocalServerSocket.java @@ -46,7 +46,7 @@ public class LocalServerSocket { { impl = new LocalSocketImpl(); - impl.create(true); + impl.create(LocalSocket.SOCKET_STREAM); localAddress = new LocalSocketAddress(name); impl.bind(localAddress); @@ -93,7 +93,7 @@ public class LocalServerSocket { impl.accept (acceptedImpl); - return new LocalSocket(acceptedImpl); + return new LocalSocket(acceptedImpl, LocalSocket.SOCKET_UNKNOWN); } /** diff --git a/core/java/android/net/LocalSocket.java b/core/java/android/net/LocalSocket.java index 14a8094..31bc20b 100644 --- a/core/java/android/net/LocalSocket.java +++ b/core/java/android/net/LocalSocket.java @@ -34,21 +34,42 @@ public class LocalSocket implements Closeable { private LocalSocketAddress localAddress; private boolean isBound; private boolean isConnected; + private final int sockType; + + /** unknown socket type (used for constructor with existing file descriptor) */ + /* package */ static final int SOCKET_UNKNOWN = 0; + /** Datagram socket type */ + public static final int SOCKET_DGRAM = 1; + /** Stream socket type */ + public static final int SOCKET_STREAM = 2; + /** Sequential packet socket type */ + public static final int SOCKET_SEQPACKET = 3; /** * Creates a AF_LOCAL/UNIX domain stream socket. */ public LocalSocket() { - this(new LocalSocketImpl()); + this(SOCKET_STREAM); + } + + /** + * Creates a AF_LOCAL/UNIX domain stream socket with given socket type + * + * @param sockType either {@link #SOCKET_DGRAM}, {@link #SOCKET_STREAM} + * or {@link #SOCKET_SEQPACKET} + */ + public LocalSocket(int sockType) { + this(new LocalSocketImpl(), sockType); isBound = false; isConnected = false; } + /** * Creates a AF_LOCAL/UNIX domain stream socket with FileDescriptor. * @hide */ public LocalSocket(FileDescriptor fd) throws IOException { - this(new LocalSocketImpl(fd)); + this(new LocalSocketImpl(fd), SOCKET_UNKNOWN); isBound = true; isConnected = true; } @@ -57,8 +78,9 @@ public class LocalSocket implements Closeable { * for use with AndroidServerSocket * @param impl a SocketImpl */ - /*package*/ LocalSocket(LocalSocketImpl impl) { + /*package*/ LocalSocket(LocalSocketImpl impl, int sockType) { this.impl = impl; + this.sockType = sockType; this.isConnected = false; this.isBound = false; } @@ -81,7 +103,7 @@ public class LocalSocket implements Closeable { synchronized (this) { if (!implCreated) { try { - impl.create(true); + impl.create(sockType); } finally { implCreated = true; } diff --git a/core/java/android/net/LocalSocketImpl.java b/core/java/android/net/LocalSocketImpl.java index 3b43c36..fa3cf58 100644 --- a/core/java/android/net/LocalSocketImpl.java +++ b/core/java/android/net/LocalSocketImpl.java @@ -22,6 +22,10 @@ import java.io.InputStream; import java.io.FileDescriptor; import java.net.SocketOptions; +import libcore.io.ErrnoException; +import libcore.io.Libcore; +import libcore.io.OsConstants; + /** * Socket implementation used for android.net.LocalSocket and * android.net.LocalServerSocket. Supports only AF_LOCAL sockets. @@ -159,7 +163,6 @@ class LocalSocketImpl private native int pending_native(FileDescriptor fd) throws IOException; private native int available_native(FileDescriptor fd) throws IOException; - private native void close_native(FileDescriptor fd) throws IOException; private native int read_native(FileDescriptor fd) throws IOException; private native int readba_native(byte[] b, int off, int len, FileDescriptor fd) throws IOException; @@ -171,8 +174,6 @@ class LocalSocketImpl int namespace) throws IOException; private native void bindLocal(FileDescriptor fd, String name, int namespace) throws IOException; - private native FileDescriptor create_native(boolean stream) - throws IOException; private native void listen_native(FileDescriptor fd, int backlog) throws IOException; private native void shutdown(FileDescriptor fd, boolean shutdownInput); @@ -222,15 +223,33 @@ class LocalSocketImpl /** * Creates a socket in the underlying OS. * - * @param stream true if this should be a stream socket, false for - * datagram. + * @param sockType either {@link LocalSocket#SOCKET_DGRAM}, {@link LocalSocket#SOCKET_STREAM} + * or {@link LocalSocket#SOCKET_SEQPACKET} * @throws IOException */ - public void create (boolean stream) throws IOException { + public void create (int sockType) throws IOException { // no error if socket already created // need this for LocalServerSocket.accept() if (fd == null) { - fd = create_native(stream); + int osType; + switch (sockType) { + case LocalSocket.SOCKET_DGRAM: + osType = OsConstants.SOCK_DGRAM; + break; + case LocalSocket.SOCKET_STREAM: + osType = OsConstants.SOCK_STREAM; + break; + case LocalSocket.SOCKET_SEQPACKET: + osType = OsConstants.SOCK_SEQPACKET; + break; + default: + throw new IllegalStateException("unknown sockType"); + } + try { + fd = Libcore.os.socket(OsConstants.AF_UNIX, osType, 0); + } catch (ErrnoException e) { + e.rethrowAsIOException(); + } } } @@ -242,7 +261,11 @@ class LocalSocketImpl public void close() throws IOException { synchronized (LocalSocketImpl.this) { if (fd == null) return; - close_native(fd); + try { + Libcore.os.close(fd); + } catch (ErrnoException e) { + e.rethrowAsIOException(); + } fd = null; } } diff --git a/core/java/android/net/http/HttpResponseCache.java b/core/java/android/net/http/HttpResponseCache.java index bd50bcf..269dfb8 100644 --- a/core/java/android/net/http/HttpResponseCache.java +++ b/core/java/android/net/http/HttpResponseCache.java @@ -17,9 +17,9 @@ package android.net.http; import android.content.Context; +import com.android.okhttp.OkResponseCache; import com.android.okhttp.ResponseSource; import com.android.okhttp.internal.DiskLruCache; -import com.android.okhttp.internal.http.OkResponseCache; import java.io.Closeable; import java.io.File; import java.io.IOException; diff --git a/core/java/android/nfc/cardemulation/HostApduService.java b/core/java/android/nfc/cardemulation/HostApduService.java new file mode 100644 index 0000000..e52c0c3 --- /dev/null +++ b/core/java/android/nfc/cardemulation/HostApduService.java @@ -0,0 +1,222 @@ +package android.nfc.cardemulation; + +import android.annotation.SdkConstant; +import android.annotation.SdkConstant.SdkConstantType; +import android.app.Service; +import android.content.Intent; +import android.os.Bundle; +import android.os.Handler; +import android.os.IBinder; +import android.os.Message; +import android.os.Messenger; +import android.os.RemoteException; +import android.util.Log; + +/** + * <p>A convenience class that can be extended to implement + * a service that processes ISO7816-4 commands on top of + * the ISO14443-4 / IsoDep protocol (T=CL). + * + * <p>To tell the platform which ISO7816 application ID (AIDs) + * are implemented by this service, a {@link #SERVICE_META_DATA} + * entry must be included in the declaration of the service. An + * example of such a service declaration is shown below: + * <pre> <service android:name=".MyHostApduService"> + * <intent-filter> + * <action android:name="android.nfc.HostApduService"/> + * </intent-filter> + * <meta-data android:name="android.nfc.HostApduService" android:resource="@xml/apduservice.xml"/> + * </service></pre> + * <p>For more details refer to {@link #SERVICE_META_DATA}, + * <code><{@link android.R.styleable#ApduService apdu-service}></code> and + * <code><{@link android.R.styleable#AidFilter aid-filter}></code>. + * <p class="note">The Android platform currently only supports a single + * logical channel. + */ +public abstract class HostApduService extends Service { + /** + * The {@link Intent} that must be declared as handled by the service. + */ + @SdkConstant(SdkConstantType.SERVICE_ACTION) + public static final String SERVICE_INTERFACE = + "android.nfc.HostApduService"; + + /** + * The name of the meta-data element that contains + * more information about this service. + */ + public static final String SERVICE_META_DATA = "android.nfc.HostApduService"; + + /** + * Reason for {@link #onDeactivated(int)}. + * Indicates deactivation was due to the NFC link + * being lost. + */ + public static final int DEACTIVATION_LINK_LOSS = 0; + + /** + * Reason for {@link #onDeactivated(int)}. + * + * <p>Indicates deactivation was due to a different AID + * being selected (which implicitly deselects the AID + * currently active on the logical channel). + * + * <p>Note that this next AID may still be resolved to this + * service, in which case {@link #processCommandApdu(byte[], int)} + * will be called again. + */ + public static final int DEACTIVATION_DESELECTED = 1; + + static final String TAG = "ApduService"; + + /** + * MSG_COMMAND_APDU is sent by NfcService when + * a 7816-4 command APDU has been received. + * + * @hide + */ + public static final int MSG_COMMAND_APDU = 0; + + /** + * MSG_RESPONSE_APDU is sent to NfcService to send + * a response APDU back to the remote device. + * + * @hide + */ + public static final int MSG_RESPONSE_APDU = 1; + + /** + * MSG_DEACTIVATED is sent by NfcService when + * the current session is finished; either because + * another AID was selected that resolved to + * another service, or because the NFC link + * was deactivated. + * + * @hide + */ + public static final int MSG_DEACTIVATED = 2; + + /** + * @hide + */ + public static final String KEY_DATA = "data"; + + /** + * Messenger interface to NfcService for sending responses. + * Only accessed on main thread by the message handler. + */ + Messenger mNfcService = null; + + final Messenger mMessenger = new Messenger(new MsgHandler()); + + final class MsgHandler extends Handler { + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case MSG_COMMAND_APDU: + Bundle dataBundle = msg.getData(); + if (dataBundle == null) { + return; + } + if (mNfcService == null) mNfcService = msg.replyTo; + + byte[] apdu = dataBundle.getByteArray(KEY_DATA); + if (apdu != null) { + byte[] responseApdu = processCommandApdu(apdu, 0); + if (responseApdu != null) { + if (mNfcService == null) { + Log.e(TAG, "Response not sent; service was deactivated."); + return; + } + Message responseMsg = Message.obtain(null, MSG_RESPONSE_APDU); + Bundle responseBundle = new Bundle(); + responseBundle.putByteArray(KEY_DATA, responseApdu); + responseMsg.setData(responseBundle); + try { + mNfcService.send(responseMsg); + } catch (RemoteException e) { + Log.e("TAG", "Response not sent; RemoteException calling into " + + "NfcService."); + } + } + } else { + Log.e(TAG, "Received MSG_COMMAND_APDU without data."); + } + break; + case MSG_RESPONSE_APDU: + if (mNfcService == null) { + Log.e(TAG, "Response not sent; service was deactivated."); + return; + } + try { + mNfcService.send(msg); + } catch (RemoteException e) { + Log.e(TAG, "RemoteException calling into NfcService."); + } + break; + case MSG_DEACTIVATED: + // Make sure we won't call into NfcService again + mNfcService = null; + onDeactivated(msg.arg1); + break; + default: + super.handleMessage(msg); + } + } + } + + @Override + public final IBinder onBind(Intent intent) { + return mMessenger.getBinder(); + } + + /** + * Sends a response APDU back to the remote device. + * + * <p>Note: this method may be called from any thread and will not block. + * @param responseApdu A byte-array containing the reponse APDU. + */ + public final void sendResponseApdu(byte[] responseApdu) { + Message responseMsg = Message.obtain(null, MSG_RESPONSE_APDU); + Bundle dataBundle = new Bundle(); + dataBundle.putByteArray(KEY_DATA, responseApdu); + responseMsg.setData(dataBundle); + try { + mMessenger.send(responseMsg); + } catch (RemoteException e) { + Log.e("TAG", "Local messenger has died."); + } + } + + /** + * <p>This method will be called when a command APDU has been received + * from a remote device. A response APDU can be provided directly + * by returning a byte-array in this method. Note that in general + * response APDUs must be sent as quickly as possible, given the fact + * that the user is likely holding his device over an NFC reader + * when this method is called. + * + * <p class="note">If there are multiple services that have registered for the same + * AIDs in their meta-data entry, you will only get called if the user has + * explicitly selected your service, either as a default or just for the next tap. + * + * <p class="note">This method is running on the main thread of your application. + * If you cannot return a response APDU immediately, return null + * and use the {@link #sendResponseApdu(byte[])} method later. + * + * @param commandApdu + * @param flags + * @return a byte-array containing the response APDU, or null if no + * response APDU can be sent at this point. + */ + public abstract byte[] processCommandApdu(byte[] commandApdu, int flags); + + /** + * This method will be called in two possible scenarios: + * <li>The NFC link has been deactivated or lost + * <li>A different AID has been selected and was resolved to a different + * service component + * @param reason Either {@link #DEACTIVATION_LINK_LOSS} or {@link #DEACTIVATION_DESELECTED} + */ + public abstract void onDeactivated(int reason); +} diff --git a/core/java/android/nfc/cardemulation/SeApduService.java b/core/java/android/nfc/cardemulation/SeApduService.java new file mode 100644 index 0000000..78f8312 --- /dev/null +++ b/core/java/android/nfc/cardemulation/SeApduService.java @@ -0,0 +1,111 @@ +package android.nfc.cardemulation; + +import android.annotation.SdkConstant; +import android.annotation.SdkConstant.SdkConstantType; +import android.app.Service; +import android.content.Intent; +import android.os.Bundle; +import android.os.Handler; +import android.os.IBinder; +import android.os.Message; +import android.os.Messenger; + +/** + * <p>A convenience class that can be extended to implement + * a service that registers and deals with events for + * ISO7814-4 AIDs that reside on an embedded secure element + * or UICC. + * + * <p>To tell the platform which ISO7816 application ID (AIDs) + * are present on the Secure Element and handled by this service, + * a {@link #SERVICE_META_DATA} entry must be included in the declaration + * of the service. An example of such a service declaration is shown below: + * <pre> <service android:name=".MySeApduService"> + * <intent-filter> + * <action android:name="android.nfc.SeApduService"/> + * </intent-filter> + * <meta-data android:name="android.nfc.SeApduService" android:resource="@xml/apduservice.xml"/> + * </service></pre> + * <p>For more details refer to {@link #SERVICE_META_DATA}, + * <code><{@link android.R.styleable#ApduService apdu-service}></code> and + * <code><{@link android.R.styleable#AidFilter aid-filter}></code>. + */ +public abstract class SeApduService extends Service { + /** + * The {@link Intent} that must be declared as handled by the service. + */ + @SdkConstant(SdkConstantType.SERVICE_ACTION) + public static final String SERVICE_INTERFACE = + "android.nfc.SeApduService"; + + /** + * The name of the meta-data element that contains + * more information about this service. + */ + public static final String SERVICE_META_DATA = "android.nfc.SeApduService"; + + /** + * @hide + */ + public static final int MSG_AID_SELECTED = 0; + + /** + * @hide + */ + public static final int MSG_HCI_TRANSACTION_EVT = 1; + + /** + * @hide + */ + public static final String KEY_AID = "aid"; + + /** + * @hide + */ + public static final String KEY_PARAMETERS = "parameters"; + + final Messenger mMessenger = new Messenger(new MsgHandler()); + + final class MsgHandler extends Handler { + @Override + public void handleMessage(Message msg) { + switch (msg.what){ + case MSG_AID_SELECTED: { + Bundle dataBundle = msg.getData(); + byte[] aid = dataBundle.getByteArray(KEY_AID); + onAidSelected(aid); + break; + } + case MSG_HCI_TRANSACTION_EVT: { + Bundle dataBundle = msg.getData(); + byte[] aid = dataBundle.getByteArray(KEY_AID); + byte[] parameters = dataBundle.getByteArray(KEY_PARAMETERS); + onHciTransactionEvent(aid, parameters); + break; + } + } + } + }; + + @Override + public final IBinder onBind(Intent intent) { + return mMessenger.getBinder(); + } + + /** + * This method is called when an AID that has been registered + * in the manifest of this service has been selected on a + * eSE/UICC. + * @param aid The AID that has been selected + */ + public abstract void onAidSelected(byte[] aid); + + /** + * This method is called when a HCI transaction event has + * been received for an AID that has been registered + * in the manifest of this service. + * @param aid The AID of the application that generated the event + * @param parameters Parameters according to ETSI-TS 102 622 + */ + public abstract void onHciTransactionEvent(byte[] aid, byte[] parameters); +}
\ No newline at end of file diff --git a/core/java/android/os/Bundle.java b/core/java/android/os/Bundle.java index b8769b4..f474504 100644 --- a/core/java/android/os/Bundle.java +++ b/core/java/android/os/Bundle.java @@ -16,15 +16,12 @@ package android.os; +import android.util.ArrayMap; import android.util.Log; import android.util.SparseArray; import java.io.Serializable; import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; import java.util.Set; /** @@ -37,13 +34,13 @@ public final class Bundle implements Parcelable, Cloneable { static { EMPTY = new Bundle(); - EMPTY.mMap = Collections.unmodifiableMap(new HashMap<String, Object>()); + EMPTY.mMap = ArrayMap.EMPTY; } // Invariant - exactly one of mMap / mParcelledData will be null // (except inside a call to unparcel) - /* package */ Map<String, Object> mMap = null; + /* package */ ArrayMap<String, Object> mMap = null; /* * If mParcelledData is non-null, then mMap will be null and the @@ -65,7 +62,7 @@ public final class Bundle implements Parcelable, Cloneable { * Constructs a new, empty Bundle. */ public Bundle() { - mMap = new HashMap<String, Object>(); + mMap = new ArrayMap<String, Object>(); mClassLoader = getClass().getClassLoader(); } @@ -91,7 +88,7 @@ public final class Bundle implements Parcelable, Cloneable { * inside of the Bundle. */ public Bundle(ClassLoader loader) { - mMap = new HashMap<String, Object>(); + mMap = new ArrayMap<String, Object>(); mClassLoader = loader; } @@ -102,7 +99,7 @@ public final class Bundle implements Parcelable, Cloneable { * @param capacity the initial capacity of the Bundle */ public Bundle(int capacity) { - mMap = new HashMap<String, Object>(capacity); + mMap = new ArrayMap<String, Object>(capacity); mClassLoader = getClass().getClassLoader(); } @@ -122,7 +119,7 @@ public final class Bundle implements Parcelable, Cloneable { } if (b.mMap != null) { - mMap = new HashMap<String, Object>(b.mMap); + mMap = new ArrayMap<String, Object>(b.mMap); } else { mMap = null; } @@ -162,7 +159,7 @@ public final class Bundle implements Parcelable, Cloneable { if (size == 0) { return null; } - Object o = mMap.values().iterator().next(); + Object o = mMap.valueAt(0); try { return (String) o; } catch (ClassCastException e) { @@ -218,9 +215,12 @@ public final class Bundle implements Parcelable, Cloneable { return; } if (mMap == null) { - mMap = new HashMap<String, Object>(N); + mMap = new ArrayMap<String, Object>(N); + } else { + mMap.erase(); + mMap.ensureCapacity(N); } - mParcelledData.readMapInternal(mMap, N, mClassLoader); + mParcelledData.readArrayMapInternal(mMap, N, mClassLoader); mParcelledData.recycle(); mParcelledData = null; } @@ -331,9 +331,8 @@ public final class Bundle implements Parcelable, Cloneable { } } else { // It's been unparcelled, so we need to walk the map - Iterator<Map.Entry<String, Object>> iter = mMap.entrySet().iterator(); - while (!fdFound && iter.hasNext()) { - Object obj = iter.next().getValue(); + for (int i=mMap.size()-1; i>=0; i--) { + Object obj = mMap.valueAt(i); if (obj instanceof Parcelable) { if ((((Parcelable)obj).describeContents() & Parcelable.CONTENTS_FILE_DESCRIPTOR) != 0) { @@ -1643,7 +1642,7 @@ public final class Bundle implements Parcelable, Cloneable { parcel.writeInt(0x4C444E42); // 'B' 'N' 'D' 'L' int oldPos = parcel.dataPosition(); - parcel.writeMapInternal(mMap); + parcel.writeArrayMapInternal(mMap); int newPos = parcel.dataPosition(); // Backpatch length diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java index c5f473e..0a6db25 100644 --- a/core/java/android/os/Debug.java +++ b/core/java/android/os/Debug.java @@ -192,6 +192,14 @@ public final class Debug return dalvikPss + nativePss + otherPss; } + /** + * @hide Return total PSS memory usage in kB. + */ + public int getTotalUss() { + return dalvikPrivateClean + dalvikPrivateDirty + + nativePrivateClean + nativePrivateDirty + + otherPrivateClean + otherPrivateDirty; + } /** * Return total PSS memory usage in kB. @@ -1001,9 +1009,10 @@ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Lo /** * Retrieves the PSS memory used by the process as given by the - * smaps. @hide + * smaps. Optionally supply a long array of 1 entry to also + * receive the uss of the process. @hide */ - public static native long getPss(int pid); + public static native long getPss(int pid, long[] outUss); /** * Establish an object allocation limit in the current thread. diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl index 7589a5a..bd2d9ac 100644 --- a/core/java/android/os/IUserManager.aidl +++ b/core/java/android/os/IUserManager.aidl @@ -49,4 +49,5 @@ interface IUserManager { boolean changeRestrictionsPin(in String newPin); int checkRestrictionsPin(in String pin); boolean hasRestrictionsPin(); + void removeRestrictions(); } diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java index 0916ea9..12f7915 100644 --- a/core/java/android/os/Parcel.java +++ b/core/java/android/os/Parcel.java @@ -17,6 +17,7 @@ package android.os; import android.text.TextUtils; +import android.util.ArrayMap; import android.util.Log; import android.util.SparseArray; import android.util.SparseBooleanArray; @@ -572,7 +573,7 @@ public final class Parcel { * allows you to avoid mysterious type errors at the point of marshalling. */ public final void writeMap(Map val) { - writeMapInternal((Map<String,Object>) val); + writeMapInternal((Map<String, Object>) val); } /** @@ -593,6 +594,23 @@ public final class Parcel { } /** + * Flatten an ArrayMap into the parcel at the current dataPosition(), + * growing dataCapacity() if needed. The Map keys must be String objects. + */ + /* package */ void writeArrayMapInternal(ArrayMap<String,Object> val) { + if (val == null) { + writeInt(-1); + return; + } + final int N = val.size(); + writeInt(N); + for (int i=0; i<N; i++) { + writeValue(val.keyAt(i)); + writeValue(val.valueAt(i)); + } + } + + /** * Flatten a Bundle into the parcel at the current dataPosition(), * growing dataCapacity() if needed. */ @@ -2258,6 +2276,16 @@ public final class Parcel { } } + /* package */ void readArrayMapInternal(ArrayMap outVal, int N, + ClassLoader loader) { + while (N > 0) { + Object key = readValue(loader); + Object value = readValue(loader); + outVal.append(key, value); + N--; + } + } + private void readListInternal(List outVal, int N, ClassLoader loader) { while (N > 0) { diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java index 159d3eb..1d482dc 100644 --- a/core/java/android/os/Process.java +++ b/core/java/android/os/Process.java @@ -894,6 +894,19 @@ public class Process { public static final native boolean setOomAdj(int pid, int amt); /** + * Adjust the swappiness level for a process. + * + * @param pid The process identifier to set. + * @param is_increased Whether swappiness should be increased or default. + * + * @return Returns true if the underlying system supports this + * feature, else false. + * + * {@hide} + */ + public static final native boolean setSwappiness(int pid, boolean is_increased); + + /** * Change this process's argv[0] parameter. This can be useful to show * more descriptive information in things like the 'ps' command. * diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java index c33a28a..83426ae 100644 --- a/core/java/android/os/UserManager.java +++ b/core/java/android/os/UserManager.java @@ -140,6 +140,16 @@ public class UserManager { */ public static final String DISALLOW_REMOVE_USER = "no_remove_user"; + /** + * Key for user restrictions. Specifies if a user is disallowed from setting app restrictions + * via a restrictions PIN. The default is <code>false</code>. If app restrictions have already + * been set up, then this user restriction cannot be set to true. + * <p/> + * Type: Boolean + * @see #hasRestrictionsPin() + */ + public static final String DISALLOW_APP_RESTRICTIONS = "no_app_restrictions"; + /** @hide */ public static final int PIN_VERIFICATION_FAILED_INCORRECT = -3; /** @hide */ @@ -678,4 +688,13 @@ public class UserManager { } return false; } + + /** @hide */ + public void removeRestrictions() { + try { + mService.removeRestrictions(); + } catch (RemoteException re) { + Log.w(TAG, "Could not change restrictions pin"); + } + } } diff --git a/core/java/android/preference/PreferenceActivity.java b/core/java/android/preference/PreferenceActivity.java index a9ee96e..ec97efb 100644 --- a/core/java/android/preference/PreferenceActivity.java +++ b/core/java/android/preference/PreferenceActivity.java @@ -973,6 +973,9 @@ public abstract class PreferenceActivity extends ListActivity implements @Override protected void onListItemClick(ListView l, View v, int position, long id) { + if (!isResumed()) { + return; + } super.onListItemClick(l, v, position, id); if (mAdapter != null) { diff --git a/core/java/android/preference/VolumePreference.java b/core/java/android/preference/VolumePreference.java index caf55d7..dc683a6 100644 --- a/core/java/android/preference/VolumePreference.java +++ b/core/java/android/preference/VolumePreference.java @@ -25,11 +25,14 @@ import android.media.Ringtone; import android.media.RingtoneManager; import android.net.Uri; import android.os.Handler; +import android.os.HandlerThread; +import android.os.Message; import android.os.Parcel; import android.os.Parcelable; import android.provider.Settings; import android.provider.Settings.System; import android.util.AttributeSet; +import android.util.Log; import android.view.KeyEvent; import android.view.View; import android.widget.SeekBar; @@ -115,7 +118,7 @@ public class VolumePreference extends SeekBarDialogPreference implements public void onActivityStop() { if (mSeekBarVolumizer != null) { - mSeekBarVolumizer.stopSample(); + mSeekBarVolumizer.postStopSample(); } } @@ -220,10 +223,10 @@ public class VolumePreference extends SeekBarDialogPreference implements /** * Turns a {@link SeekBar} into a volume control. */ - public class SeekBarVolumizer implements OnSeekBarChangeListener, Runnable { + public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callback { private Context mContext; - private Handler mHandler = new Handler(); + private Handler mHandler; private AudioManager mAudioManager; private int mStreamType; @@ -234,6 +237,11 @@ public class VolumePreference extends SeekBarDialogPreference implements private SeekBar mSeekBar; private int mVolumeBeforeMute = -1; + private static final int MSG_SET_STREAM_VOLUME = 0; + private static final int MSG_START_SAMPLE = 1; + private static final int MSG_STOP_SAMPLE = 2; + private static final int CHECK_RINGTONE_PLAYBACK_DELAY_MS = 1000; + private ContentObserver mVolumeObserver = new ContentObserver(mHandler) { @Override public void onChange(boolean selfChange) { @@ -255,6 +263,10 @@ public class VolumePreference extends SeekBarDialogPreference implements mStreamType = streamType; mSeekBar = seekBar; + HandlerThread thread = new HandlerThread(TAG + ".CallbackHandler"); + thread.start(); + mHandler = new Handler(thread.getLooper(), this); + initSeekBar(seekBar, defaultUri); } @@ -285,8 +297,54 @@ public class VolumePreference extends SeekBarDialogPreference implements } } + @Override + public boolean handleMessage(Message msg) { + switch (msg.what) { + case MSG_SET_STREAM_VOLUME: + mAudioManager.setStreamVolume(mStreamType, mLastProgress, 0); + break; + case MSG_START_SAMPLE: + onStartSample(); + break; + case MSG_STOP_SAMPLE: + onStopSample(); + break; + default: + Log.e(TAG, "invalid SeekBarVolumizer message: "+msg.what); + } + return true; + } + + private void postStartSample() { + mHandler.removeMessages(MSG_START_SAMPLE); + mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_START_SAMPLE), + isSamplePlaying() ? CHECK_RINGTONE_PLAYBACK_DELAY_MS : 0); + } + + private void onStartSample() { + if (!isSamplePlaying()) { + onSampleStarting(this); + if (mRingtone != null) { + mRingtone.play(); + } + } + } + + private void postStopSample() { + // remove pending delayed start messages + mHandler.removeMessages(MSG_START_SAMPLE); + mHandler.removeMessages(MSG_STOP_SAMPLE); + mHandler.sendMessage(mHandler.obtainMessage(MSG_STOP_SAMPLE)); + } + + private void onStopSample() { + if (mRingtone != null) { + mRingtone.stop(); + } + } + public void stop() { - stopSample(); + postStopSample(); mContext.getContentResolver().unregisterContentObserver(mVolumeObserver); mSeekBar.setOnSeekBarChangeListener(null); } @@ -307,21 +365,15 @@ public class VolumePreference extends SeekBarDialogPreference implements void postSetVolume(int progress) { // Do the volume changing separately to give responsive UI mLastProgress = progress; - mHandler.removeCallbacks(this); - mHandler.post(this); + mHandler.removeMessages(MSG_SET_STREAM_VOLUME); + mHandler.sendMessage(mHandler.obtainMessage(MSG_SET_STREAM_VOLUME)); } public void onStartTrackingTouch(SeekBar seekBar) { } public void onStopTrackingTouch(SeekBar seekBar) { - if (!isSamplePlaying()) { - startSample(); - } - } - - public void run() { - mAudioManager.setStreamVolume(mStreamType, mLastProgress, 0); + postStartSample(); } public boolean isSamplePlaying() { @@ -329,16 +381,11 @@ public class VolumePreference extends SeekBarDialogPreference implements } public void startSample() { - onSampleStarting(this); - if (mRingtone != null) { - mRingtone.play(); - } + postStartSample(); } public void stopSample() { - if (mRingtone != null) { - mRingtone.stop(); - } + postStopSample(); } public SeekBar getSeekBar() { @@ -347,23 +394,21 @@ public class VolumePreference extends SeekBarDialogPreference implements public void changeVolumeBy(int amount) { mSeekBar.incrementProgressBy(amount); - if (!isSamplePlaying()) { - startSample(); - } postSetVolume(mSeekBar.getProgress()); + postStartSample(); mVolumeBeforeMute = -1; } public void muteVolume() { if (mVolumeBeforeMute != -1) { mSeekBar.setProgress(mVolumeBeforeMute); - startSample(); postSetVolume(mVolumeBeforeMute); + postStartSample(); mVolumeBeforeMute = -1; } else { mVolumeBeforeMute = mSeekBar.getProgress(); mSeekBar.setProgress(0); - stopSample(); + postStopSample(); postSetVolume(0); } } diff --git a/core/java/android/print/PrintFileAdapter.java b/core/java/android/print/FileDocumentAdapter.java index dab9648..c7011f4 100644 --- a/core/java/android/print/PrintFileAdapter.java +++ b/core/java/android/print/FileDocumentAdapter.java @@ -16,11 +16,15 @@ package android.print; +import android.content.Context; import android.os.AsyncTask; +import android.os.Bundle; import android.os.CancellationSignal; import android.os.CancellationSignal.OnCancelListener; import android.util.Log; +import com.android.internal.R; + import libcore.io.IoUtils; import java.io.File; @@ -36,53 +40,55 @@ import java.util.List; /** * Adapter for printing files. */ -class PrintFileAdapter extends PrintAdapter { +final class FileDocumentAdapter extends PrintDocumentAdapter { + + private static final String LOG_TAG = "FileDocumentAdapter"; - private static final String LOG_TAG = "PrintFileAdapter"; + private final Context mContext; private final File mFile; private WriteFileAsyncTask mWriteFileAsyncTask; - public PrintFileAdapter(File file) { + public FileDocumentAdapter(Context context, File file) { if (file == null) { throw new IllegalArgumentException("File cannot be null!"); } + mContext = context; mFile = file; } @Override - public void onPrint(List<PageRange> pages, FileDescriptor destination, - CancellationSignal cancellationSignal, PrintResultCallback callback) { - mWriteFileAsyncTask = new WriteFileAsyncTask(mFile, destination, cancellationSignal, - callback); - mWriteFileAsyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, - (Void[]) null); - + public void onLayout(PrintAttributes oldAttributes, PrintAttributes newAttributes, + CancellationSignal cancellationSignal, LayoutResultCallback callback, + Bundle metadata) { + // TODO: When we have a PDF rendering library we should query the page count. + PrintDocumentInfo info = new PrintDocumentInfo.Builder() + .setPageCount(PrintDocumentInfo.PAGE_COUNT_UNKNOWN).create(); + callback.onLayoutFinished(info, false); } @Override - public PrintAdapterInfo getInfo() { - // TODO: When we have PDF render library we should query the page count. - return new PrintAdapterInfo.Builder().create(); + public void onWrite(List<PageRange> pages, FileDescriptor destination, + CancellationSignal cancellationSignal, WriteResultCallback callback) { + mWriteFileAsyncTask = new WriteFileAsyncTask(destination, cancellationSignal, callback); + mWriteFileAsyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, + (Void[]) null); } - private static final class WriteFileAsyncTask extends AsyncTask<Void, Void, Void> { - - private final File mSource; + private final class WriteFileAsyncTask extends AsyncTask<Void, Void, Void> { private final FileDescriptor mDestination; - private final PrintResultCallback mResultCallback; + private final WriteResultCallback mResultCallback; private final CancellationSignal mCancellationSignal; - public WriteFileAsyncTask(File source, FileDescriptor destination, - CancellationSignal cancellationSignal, PrintResultCallback callback) { - mSource = source; + public WriteFileAsyncTask(FileDescriptor destination, + CancellationSignal cancellationSignal, WriteResultCallback callback) { mDestination = destination; mResultCallback = callback; - mCancellationSignal = cancellationSignal; + mCancellationSignal = cancellationSignal; mCancellationSignal.setOnCancelListener(new OnCancelListener() { @Override public void onCancel() { @@ -97,8 +103,11 @@ class PrintFileAdapter extends PrintAdapter { OutputStream out = new FileOutputStream(mDestination); final byte[] buffer = new byte[8192]; try { - in = new FileInputStream(mSource); + in = new FileInputStream(mFile); while (true) { + if (isCancelled()) { + break; + } final int readByteCount = in.read(buffer); if (readByteCount < 0) { break; @@ -106,20 +115,28 @@ class PrintFileAdapter extends PrintAdapter { out.write(buffer, 0, readByteCount); } } catch (IOException ioe) { - Log.e(LOG_TAG, "Error writing data!", ioe); + Log.e(LOG_TAG, "Error writing data!", ioe); + mResultCallback.onWriteFailed(mContext.getString( + R.string.write_fail_reason_cannot_write)); } finally { IoUtils.closeQuietly(in); IoUtils.closeQuietly(out); - if (!isCancelled()) { - List<PageRange> pages = new ArrayList<PageRange>(); - pages.add(PageRange.ALL_PAGES); - mResultCallback.onPrintFinished(pages); - } else { - mResultCallback.onPrintFailed("Cancelled"); - } } return null; } + + @Override + protected void onPostExecute(Void result) { + List<PageRange> pages = new ArrayList<PageRange>(); + pages.add(PageRange.ALL_PAGES); + mResultCallback.onWriteFinished(pages); + } + + @Override + protected void onCancelled(Void result) { + mResultCallback.onWriteFailed(mContext.getString( + R.string.write_fail_reason_cancelled)); + } } } diff --git a/core/java/android/print/ILayoutResultCallback.aidl b/core/java/android/print/ILayoutResultCallback.aidl new file mode 100644 index 0000000..e4d79f3 --- /dev/null +++ b/core/java/android/print/ILayoutResultCallback.aidl @@ -0,0 +1,31 @@ +/* + * 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.print; + +import android.os.ICancellationSignal; +import android.print.PrintDocumentInfo; + +/** + * Callback for observing the result of android.print.PrintAdapter#onLayout. + * + * @hide + */ +oneway interface ILayoutResultCallback { + void onLayoutStarted(ICancellationSignal cancellationSignal); + void onLayoutFinished(in PrintDocumentInfo info, boolean changed); + void onLayoutFailed(CharSequence error); +} diff --git a/core/java/android/print/IPrintAdapter.aidl b/core/java/android/print/IPrintDocumentAdapter.aidl index f3ff8c4..04da157 100644 --- a/core/java/android/print/IPrintAdapter.aidl +++ b/core/java/android/print/IPrintDocumentAdapter.aidl @@ -16,8 +16,10 @@ package android.print; +import android.os.Bundle; import android.os.ParcelFileDescriptor; -import android.print.IPrintResultCallback; +import android.print.ILayoutResultCallback; +import android.print.IWriteResultCallback; import android.print.PageRange; import android.print.PrintAttributes; @@ -26,10 +28,11 @@ import android.print.PrintAttributes; * * @hide */ -oneway interface IPrintAdapter { +oneway interface IPrintDocumentAdapter { void start(); - void printAttributesChanged(in PrintAttributes attributes); - void print(in List<PageRange> pages, in ParcelFileDescriptor fd, - IPrintResultCallback callback); + void layout(in PrintAttributes oldAttributes, in PrintAttributes newAttributes, + ILayoutResultCallback callback, in Bundle metadata); + void write(in List<PageRange> pages, in ParcelFileDescriptor fd, + IWriteResultCallback callback); void finish(); } diff --git a/core/java/android/print/IPrintManager.aidl b/core/java/android/print/IPrintManager.aidl index ff9877e..a466e74 100644 --- a/core/java/android/print/IPrintManager.aidl +++ b/core/java/android/print/IPrintManager.aidl @@ -16,11 +16,8 @@ package android.print; -import android.os.ICancellationSignal; -import android.print.IPrintAdapter; +import android.print.IPrintDocumentAdapter; import android.print.IPrintClient; -import android.print.IPrinterDiscoveryObserver; -import android.print.PrinterId; import android.print.PrintJobInfo; import android.print.PrintAttributes; @@ -30,12 +27,11 @@ import android.print.PrintAttributes; * @hide */ interface IPrintManager { - List<PrintJobInfo> getPrintJobs(int appId, int userId); - PrintJobInfo getPrintJob(int printJobId, int appId, int userId); - PrintJobInfo print(String printJobName, in IPrintClient client, in IPrintAdapter printAdapter, - in PrintAttributes attributes, int appId, int userId); + List<PrintJobInfo> getPrintJobInfos(int appId, int userId); + PrintJobInfo getPrintJobInfo(int printJobId, int appId, int userId); + PrintJobInfo print(String printJobName, in IPrintClient client, + in IPrintDocumentAdapter printAdapter, in PrintAttributes attributes, + int appId, int userId); void cancelPrintJob(int printJobId, int appId, int userId); - void onPrintJobQueued(in PrinterId printerId, in PrintJobInfo printJob); - void startDiscoverPrinters(IPrinterDiscoveryObserver observer); - void stopDiscoverPrinters(); + } diff --git a/core/java/android/print/IPrintSpoolerService.aidl b/core/java/android/print/IPrintSpooler.aidl index e84d592..c55205d 100644 --- a/core/java/android/print/IPrintSpoolerService.aidl +++ b/core/java/android/print/IPrintSpooler.aidl @@ -18,32 +18,35 @@ package android.print; import android.content.ComponentName; import android.os.ParcelFileDescriptor; -import android.print.IPrintAdapter; +import android.print.IPrintDocumentAdapter; import android.print.IPrintClient; -import android.print.IPrintSpoolerServiceCallbacks; +import android.print.IPrintSpoolerClient; +import android.print.IPrintSpoolerCallbacks; import android.print.PrinterInfo; import android.print.PrintAttributes; /** * Interface for communication with the print spooler service. * - * @see android.print.IPrintSpoolerServiceCallbacks + * @see android.print.IPrintSpoolerCallbacks * * @hide */ -oneway interface IPrintSpoolerService { - void getPrintJobs(IPrintSpoolerServiceCallbacks callback, in ComponentName componentName, +oneway interface IPrintSpooler { + void getPrintJobInfos(IPrintSpoolerCallbacks callback, in ComponentName componentName, int state, int appId, int sequence); - void getPrintJob(int printJobId, IPrintSpoolerServiceCallbacks callback, + void getPrintJobInfo(int printJobId, IPrintSpoolerCallbacks callback, int appId, int sequence); - void createPrintJob(String printJobName, in IPrintClient client, in IPrintAdapter printAdapter, - in PrintAttributes attributes, IPrintSpoolerServiceCallbacks callback, int appId, - int sequence); - void cancelPrintJob(int printJobId, IPrintSpoolerServiceCallbacks callback, + void createPrintJob(String printJobName, in IPrintClient client, + in IPrintDocumentAdapter printAdapter, in PrintAttributes attributes, + IPrintSpoolerCallbacks callback, int appId, int sequence); + void cancelPrintJob(int printJobId, IPrintSpoolerCallbacks callback, int appId, int sequence); - void setPrintJobState(int printJobId, int status, IPrintSpoolerServiceCallbacks callback, + void setPrintJobState(int printJobId, int status, IPrintSpoolerCallbacks callback, int sequence); - void setPrintJobTag(int printJobId, String tag, IPrintSpoolerServiceCallbacks callback, + void setPrintJobTag(int printJobId, String tag, IPrintSpoolerCallbacks callback, int sequence); void writePrintJobData(in ParcelFileDescriptor fd, int printJobId); -}
\ No newline at end of file + void setClient(IPrintSpoolerClient client); + void notifyClientForActivteJobs(); +} diff --git a/core/java/android/print/IPrintSpoolerServiceCallbacks.aidl b/core/java/android/print/IPrintSpoolerCallbacks.aidl index 0c51913..7912964 100644 --- a/core/java/android/print/IPrintSpoolerServiceCallbacks.aidl +++ b/core/java/android/print/IPrintSpoolerCallbacks.aidl @@ -26,8 +26,8 @@ import java.util.List; * * @hide */ -oneway interface IPrintSpoolerServiceCallbacks { - void onGetPrintJobsResult(in List<PrintJobInfo> printJob, int sequence); +oneway interface IPrintSpoolerCallbacks { + void onGetPrintJobInfosResult(in List<PrintJobInfo> printJob, int sequence); void onGetPrintJobInfoResult(in PrintJobInfo printJob, int sequence); void onCreatePrintJobResult(in PrintJobInfo printJob, int sequence); void onCancelPrintJobResult(boolean canceled, int sequence); diff --git a/core/java/android/print/IPrintSpoolerClient.aidl b/core/java/android/print/IPrintSpoolerClient.aidl new file mode 100644 index 0000000..47975e1 --- /dev/null +++ b/core/java/android/print/IPrintSpoolerClient.aidl @@ -0,0 +1,35 @@ +/* + * 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.print; + +import android.content.ComponentName; +import android.print.IPrinterDiscoveryObserver; +import android.print.PrintJobInfo; + + +/** + * Interface for receiving interesting state updates from the print spooler. + * + * @hide + */ +oneway interface IPrintSpoolerClient { + void onPrintJobQueued(in PrintJobInfo printJob); + void onStartPrinterDiscovery(IPrinterDiscoveryObserver observer); + void onStopPrinterDiscovery(); + void onAllPrintJobsForServiceHandled(in ComponentName printService); + void onAllPrintJobsHandled(); +} diff --git a/core/java/android/print/IPrintSpoolerObserver.aidl b/core/java/android/print/IPrintSpoolerObserver.aidl new file mode 100644 index 0000000..7b8f40e --- /dev/null +++ b/core/java/android/print/IPrintSpoolerObserver.aidl @@ -0,0 +1,31 @@ +/* + * 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.print; + +import android.print.PrinterId; +import android.print.PrinterInfo; + +/** + * Interface for observing the state of the print spooler. + * + * @hide + */ +oneway interface IPrinterDiscoveryObserver { + void onPrintJobQueued(in PrinterId printerId, in PrintJobInfo printJob); + void onAllPrintJobsHandled(in ComponentName printService); + void onAllPrintJobsHandled(); +} diff --git a/core/java/android/print/IPrintResultCallback.aidl b/core/java/android/print/IWriteResultCallback.aidl index 838377e..d5428b1 100644 --- a/core/java/android/print/IPrintResultCallback.aidl +++ b/core/java/android/print/IWriteResultCallback.aidl @@ -18,16 +18,14 @@ package android.print; import android.os.ICancellationSignal; import android.print.PageRange; -import android.print.PrintAdapterInfo; /** - * Callbacks for observing the print progress (writing of printed content) - * of a PrintAdapter. + * Callback for observing the result of android.print.DocuemntAdapter#onWrite. * * @hide */ -oneway interface IPrintResultCallback { - void onPrintStarted(in PrintAdapterInfo info, ICancellationSignal cancellationSignal); - void onPrintFinished(in List<PageRange> pages); - void onPrintFailed(CharSequence error); +oneway interface IWriteResultCallback { + void onWriteStarted(ICancellationSignal cancellationSignal); + void onWriteFinished(in List<PageRange> pages); + void onWriteFailed(CharSequence error); } diff --git a/core/java/android/print/PageRange.java b/core/java/android/print/PageRange.java index 60e6229..9257a04 100644 --- a/core/java/android/print/PageRange.java +++ b/core/java/android/print/PageRange.java @@ -42,8 +42,10 @@ public final class PageRange implements Parcelable { * @throws IllegalArgumentException If start is less than zero. * @throws IllegalArgumentException If end is less than zero. * @throws IllegalArgumentException If start greater than end. + * + * @hide */ - PageRange(int start, int end) { + public PageRange(int start, int end) { if (start < 0) { throw new IllegalArgumentException("start cannot be less than zero."); } diff --git a/core/java/android/print/PrintAdapter.java b/core/java/android/print/PrintAdapter.java deleted file mode 100644 index 6547c55..0000000 --- a/core/java/android/print/PrintAdapter.java +++ /dev/null @@ -1,164 +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.print; - -import android.os.CancellationSignal; - -import java.io.FileDescriptor; -import java.util.List; - -/** - * Base class that provides data to be printed. - * - * <h3>Lifecycle</h3> - * <p> - * <ul> - * <li> - * You will receive a call on {@link #onStart()} when printing starts. - * This callback can be used to allocate resources. - * </li> - * <li> - * Next you will get one or more calls to {@link #onPrintAttributesChanged( - * PrintAttributes) to informs you that the print attributes (page size, density, - * etc) changed giving you an opportunity to re-layout the content. - * </li> - * <li> - * After every {@link #onPrintAttributesChanged(PrintAttributes) you will receive - * one or more calls to {@link #onPrint(List, FileDescriptor, CancellationSignal, - * PrintResultCallback)} asking you to write a PDF file with the content for - * specific pages. - * </li> - * <li> - * Finally, you will receive a call on {@link #onFinish()} right after printing. - * You can use this callback to release resources. - * </li> - * <li> - * You can receive calls to {@link #getInfo()} at any point after a call to - * {@link #onPrintAttributesChanged(PrintAttributes)} which should return - * a {@link PrintAdapterInfo} describing your {@link PrintAdapter}. - * </li> - * </ul> - * </p> - * <p> - */ -public abstract class PrintAdapter { - - /** - * Called when printing started. You can use this callback to - * allocate resources. - * <p> - * <strong>Note:</strong> Invoked on the main thread. - * </p> - */ - public void onStart() { - /* do nothing - stub */ - } - - /** - * Called when the print job attributes (page size, density, etc) - * changed giving you a chance to re-layout the content such that - * it matches the new constraints. - * <p> - * <strong>Note:</strong> Invoked on the main thread. - * </p> - * - * @param attributes The print job attributes. - * @return Whether the content changed based on the provided attributes. - */ - public boolean onPrintAttributesChanged(PrintAttributes attributes) { - return false; - } - - /** - * Called when specific pages of the content have to be printed in the from of - * a PDF file to the given file descriptor. You should <strong>not</strong> - * close the file descriptor instead you have to invoke {@link PrintResultCallback - * #onPrintFinished()} or {@link PrintResultCallback#onPrintFailed(CharSequence)}. - * <p> - * <strong>Note:</strong> If the printed content is large, it is a good - * practice to schedule writing it on a dedicated thread and register a - * callback in the provided {@link CancellationSignal} upon invocation of - * which you should stop writing data. The cancellation callback will not - * be made on the main thread. - * </p> - * <p> - * <strong>Note:</strong> Invoked on the main thread. - * </p> - * - * @param pages The pages whose content to print. - * @param destination The destination file descriptor to which to start writing. - * @param cancellationSignal Signal for observing cancel print requests. - * @param progressListener Callback to inform the system with the write progress. - * - * @see CancellationSignal - */ - public abstract void onPrint(List<PageRange> pages, FileDescriptor destination, - CancellationSignal cancellationSignal, PrintResultCallback progressListener); - - /** - * Called when printing finished. You can use this callback to release - * resources. - * <p> - * <strong>Note:</strong> Invoked on the main thread. - * </p> - */ - public void onFinish() { - /* do nothing - stub */ - } - - /** - * Gets a {@link PrinterInfo} object that contains metadata about the - * printed content. - * <p> - * <strong>Note:</strong> Invoked on the main thread. - * </p> - * - * @return The info object for this {@link PrintAdapter}. - * - * @see PrintAdapterInfo - */ - public abstract PrintAdapterInfo getInfo(); - - /** - * Base class for implementing a listener for the print result - * of a {@link PrintAdapter}. - */ - public static abstract class PrintResultCallback { - - PrintResultCallback() { - /* do nothing - hide constructor */ - } - - /** - * Notifies that all the data was printed. - * - * @param pages The pages that were printed. - */ - public void onPrintFinished(List<PageRange> pages) { - /* do nothing - stub */ - } - - /** - * Notifies that an error occurred while printing the data. - * - * @param error Error message. May be null if error is unknown. - */ - public void onPrintFailed(CharSequence error) { - /* do nothing - stub */ - } - } -} diff --git a/core/java/android/print/PrintAdapterInfo.java b/core/java/android/print/PrintAdapterInfo.java deleted file mode 100644 index 06e6b10..0000000 --- a/core/java/android/print/PrintAdapterInfo.java +++ /dev/null @@ -1,136 +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.print; - -import android.os.Parcel; -import android.os.Parcelable; - -/** - * This class encapsulates information about a {@link PrintAdapter} object. - */ -public final class PrintAdapterInfo implements Parcelable { - - /** - * Constant for unknown page count. - */ - public static final int PAGE_COUNT_UNKNOWN = -1; - - private int mPageCount; - private int mFlags; - - /** - * Creates a new instance. - */ - private PrintAdapterInfo() { - /* do nothing */ - } - - /** - * Creates a new instance. - * - * @param parcel Data from which to initialize. - */ - private PrintAdapterInfo(Parcel parcel) { - mPageCount = parcel.readInt(); - mFlags = parcel.readInt(); - } - - /** - * Gets the total number of pages. - * - * @return The number of pages. - */ - public int getPageCount() { - return mPageCount; - } - - /** - * @return The flags of this printable info. - * - * @see #FLAG_NOTIFY_FOR_ATTRIBUTES_CHANGE - */ - public int getFlags() { - return mFlags; - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel parcel, int flags) { - parcel.writeInt(mPageCount); - parcel.writeInt(mFlags); - } - - /** - * Builder for creating an {@link PrintAdapterInfo}. - */ - public static final class Builder { - private final PrintAdapterInfo mPrintableInfo = new PrintAdapterInfo(); - - /** - * Sets the total number of pages. - * - * @param pageCount The number of pages. Must be - * greater than zero. - */ - public Builder setPageCount(int pageCount) { - if (pageCount < 0) { - throw new IllegalArgumentException("pageCount" - + " must be greater than or euqal to zero!"); - } - mPrintableInfo.mPageCount = pageCount; - return this; - } - - /** - * Sets the flags of this printable info. - * - * @param flags The flags. - * - * @see #FLAG_NOTIFY_FOR_ATTRIBUTES_CHANGE - */ - public Builder setFlags(int flags) { - mPrintableInfo.mFlags = flags; - return this; - } - - /** - * Creates a new {@link PrintAdapterInfo} instance. - * - * @return The new instance. - */ - public PrintAdapterInfo create() { - return mPrintableInfo; - } - } - - public static final Parcelable.Creator<PrintAdapterInfo> CREATOR = - new Creator<PrintAdapterInfo>() { - @Override - public PrintAdapterInfo createFromParcel(Parcel parcel) { - return new PrintAdapterInfo(parcel); - } - - @Override - public PrintAdapterInfo[] newArray(int size) { - return new PrintAdapterInfo[size]; - } - }; -} diff --git a/core/java/android/print/PrintAttributes.java b/core/java/android/print/PrintAttributes.java index 8511d0b..65f1330 100644 --- a/core/java/android/print/PrintAttributes.java +++ b/core/java/android/print/PrintAttributes.java @@ -18,11 +18,10 @@ package android.print; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; -import android.content.res.Resources.NotFoundException; +import android.content.res.Resources; import android.os.Parcel; import android.os.Parcelable; import android.text.TextUtils; -import android.util.Log; import com.android.internal.R; @@ -388,196 +387,476 @@ public final class PrintAttributes implements Parcelable { * This class specifies a supported media size. */ public static final class MediaSize { - private static final String LOG_TAG = "MediaSize"; // TODO: Verify media sizes and add more standard ones. // ISO sizes - /** ISO A0 media size: 841mm x 1189mm (33.11" x 46.81") */ - public static final MediaSize ISO_A0 = - new MediaSize("ISO_A0", "android", R.string.mediaSize_iso_a0, 33110, 46810); - /** ISO A1 media size: 594mm x 841mm (23.39" x 33.11") */ - public static final MediaSize ISO_A1 = - new MediaSize("ISO_A1", "android", R.string.mediaSize_iso_a1, 23390, 33110); - /** ISO A2 media size: 420mm x 594mm (16.54" x 23.39") */ - public static final MediaSize ISO_A2 = - new MediaSize("ISO_A2", "android", R.string.mediaSize_iso_a2, 16540, 23390); - /** ISO A3 media size: 297mm x 420mm (11.69" x 16.54") */ - public static final MediaSize ISO_A3 = - new MediaSize("ISO_A3", "android", R.string.mediaSize_iso_a3, 11690, 16540); - /** ISO A4 media size: 210mm x 297mm (8.27" x 11.69") */ - public static final MediaSize ISO_A4 = - new MediaSize("ISO_A4", "android", R.string.mediaSize_iso_a4, 8270, 11690); - /** ISO A5 media size: 148mm x 210mm (5.83" x 8.27") */ - public static final MediaSize ISO_A5 = - new MediaSize("ISO_A5", "android", R.string.mediaSize_iso_a5, 5830, 8270); - /** ISO A6 media size: 105mm x 148mm (4.13" x 5.83") */ - public static final MediaSize ISO_A6 = - new MediaSize("ISO_A6", "android", R.string.mediaSize_iso_a6, 4130, 5830); - /** ISO A7 media size: 74mm x 105mm (2.91" x 4.13") */ - public static final MediaSize ISO_A7 = - new MediaSize("ISO_A7", "android", R.string.mediaSize_iso_a7, 2910, 4130); - /** ISO A8 media size: 52mm x 74mm (2.05" x 2.91") */ - public static final MediaSize ISO_A8 = - new MediaSize("ISO_A8", "android", R.string.mediaSize_iso_a8, 2050, 2910); - /** ISO A9 media size: 37mm x 52mm (1.46" x 2.05") */ - public static final MediaSize ISO_A9 = - new MediaSize("ISO_A9", "android", R.string.mediaSize_iso_a9, 1460, 2050); - /** ISO A10 media size: 26mm x 37mm (1.02" x 1.46") */ - public static final MediaSize ISO_A10 = - new MediaSize("ISO_A10", "android", R.string.mediaSize_iso_a10, 1020, 1460); - - /** ISO B0 media size: 1000mm x 1414mm (39.37" x 55.67") */ - public static final MediaSize ISO_B0 = - new MediaSize("ISO_B0", "android", R.string.mediaSize_iso_b0, 39370, 55670); - /** ISO B1 media size: 707mm x 1000mm (27.83" x 39.37") */ - public static final MediaSize ISO_B1 = - new MediaSize("ISO_B1", "android", R.string.mediaSize_iso_b1, 27830, 39370); - /** ISO B2 media size: 500mm x 707mm (19.69" x 27.83") */ - public static final MediaSize ISO_B2 = - new MediaSize("ISO_B2", "android", R.string.mediaSize_iso_b2, 19690, 27830); - /** ISO B3 media size: 353mm x 500mm (13.90" x 19.69") */ - public static final MediaSize ISO_B3 = - new MediaSize("ISO_B3", "android", R.string.mediaSize_iso_b3, 13900, 19690); - /** ISO B4 media size: 250mm x 353mm (9.84" x 13.90") */ - public static final MediaSize ISO_B4 = - new MediaSize("ISO_B4", "android", R.string.mediaSize_iso_b4, 9840, 13900); - /** ISO B5 media size: 176mm x 250mm (6.93" x 9.84") */ - public static final MediaSize ISO_B5 = - new MediaSize("ISO_B5", "android", R.string.mediaSize_iso_b5, 6930, 9840); - /** ISO B6 media size: 125mm x 176mm (4.92" x 6.93") */ - public static final MediaSize ISO_B6 = - new MediaSize("ISO_B6", "android", R.string.mediaSize_iso_b6, 4920, 6930); - /** ISO B7 media size: 88mm x 125mm (3.46" x 4.92") */ - public static final MediaSize ISO_B7 = - new MediaSize("ISO_B7", "android", R.string.mediaSize_iso_b7, 3460, 4920); - /** ISO B8 media size: 62mm x 88mm (2.44" x 3.46") */ - public static final MediaSize ISO_B8 = - new MediaSize("ISO_B8", "android", R.string.mediaSize_iso_b8, 2440, 3460); - /** ISO B9 media size: 44mm x 62mm (1.73" x 2.44") */ - public static final MediaSize ISO_B9 = - new MediaSize("ISO_B9", "android", R.string.mediaSize_iso_b9, 1730, 2440); - /** ISO B10 media size: 31mm x 44mm (1.22" x 1.73") */ - public static final MediaSize ISO_B10 = - new MediaSize("ISO_B10", "android", R.string.mediaSize_iso_b10, 1220, 1730); - - /** ISO C0 media size: 917mm x 1297mm (36.10" x 51.06") */ - public static final MediaSize ISO_C0 = - new MediaSize("ISO_C0", "android", R.string.mediaSize_iso_c0, 36100, 51060); - /** ISO C1 media size: 648mm x 917mm (25.51" x 36.10") */ - public static final MediaSize ISO_C1 = - new MediaSize("ISO_C1", "android", R.string.mediaSize_iso_c1, 25510, 36100); - /** ISO C2 media size: 458mm x 648mm (18.03" x 25.51") */ - public static final MediaSize ISO_C2 = - new MediaSize("ISO_C2", "android", R.string.mediaSize_iso_c2, 18030, 25510); - /** ISO C3 media size: 324mm x 458mm (12.76" x 18.03") */ - public static final MediaSize ISO_C3 = - new MediaSize("ISO_C3", "android", R.string.mediaSize_iso_c3, 12760, 18030); - /** ISO C4 media size: 229mm x 324mm (9.02" x 12.76") */ - public static final MediaSize ISO_C4 = - new MediaSize("ISO_C4", "android", R.string.mediaSize_iso_c4, 9020, 12760); - /** ISO C5 media size: 162mm x 229mm (6.38" x 9.02") */ - public static final MediaSize ISO_C5 = - new MediaSize("ISO_C5", "android", R.string.mediaSize_iso_c5, 6380, 9020); - /** ISO C6 media size: 114mm x 162mm (4.49" x 6.38") */ - public static final MediaSize ISO_C6 = - new MediaSize("ISO_C6", "android", R.string.mediaSize_iso_c6, 4490, 6380); - /** ISO C7 media size: 81mm x 114mm (3.19" x 4.49") */ - public static final MediaSize ISO_C7 = - new MediaSize("ISO_C7", "android", R.string.mediaSize_iso_c7, 3190, 4490); - /** ISO C8 media size: 57mm x 81mm (2.24" x 3.19") */ - public static final MediaSize ISO_C8 = - new MediaSize("ISO_C8", "android", R.string.mediaSize_iso_c8, 2240, 3190); - /** ISO C9 media size: 40mm x 57mm (1.57" x 2.24") */ - public static final MediaSize ISO_C9 = - new MediaSize("ISO_C9", "android", R.string.mediaSize_iso_c9, 1570, 2240); - /** ISO C10 media size: 28mm x 40mm (1.10" x 1.57") */ - public static final MediaSize ISO_C10 = - new MediaSize("ISO_C10", "android", R.string.mediaSize_iso_c10, 1100, 1570); + /** + * ISO A0 media size: 841mm x 1189mm (33.11" x 46.81") + * + * @see #createMediaSize(PackageManager, int) + */ + public static final int ISO_A0 = 1; + + /** + * ISO A1 media size: 594mm x 841mm (23.39" x 33.11") + * + * @see #createMediaSize(PackageManager, int) + */ + public static final int ISO_A1 = 2; + + /** + * + *ISO A2 media size: 420mm x 594mm (16.54" x 23.39") + * + * @see #createMediaSize(PackageManager, int) + */ + public static final int ISO_A2 = 3; + + /** + * ISO A3 media size: 297mm x 420mm (11.69" x 16.54") + * + * @see #createMediaSize(PackageManager, int) + */ + public static final int ISO_A3 = 4; + + /** + * ISO A4 media size: 210mm x 297mm (8.27" x 11.69") + * + * @see #createMediaSize(PackageManager, int) + */ + public static final int ISO_A4 = 5; + + /** + * ISO A5 media size: 148mm x 210mm (5.83" x 8.27") + * + * @see #createMediaSize(PackageManager, int) + */ + public static final int ISO_A5 = 6; + + /** + * ISO A6 media size: 105mm x 148mm (4.13" x 5.83") + * + * @see #createMediaSize(PackageManager, int) + */ + public static final int ISO_A6 = 7; + + /** + * ISO A7 media size: 74mm x 105mm (2.91" x 4.13") + * + * @see #createMediaSize(PackageManager, int) + */ + public static final int ISO_A7 = 8; + + /** + * ISO A8 media size: 52mm x 74mm (2.05" x 2.91") + * + * @see #createMediaSize(PackageManager, int) + */ + public static final int ISO_A8 = 9; + + /** + * ISO A9 media size: 37mm x 52mm (1.46" x 2.05") + * + * @see #createMediaSize(PackageManager, int) + */ + public static final int ISO_A9 = 10; + + /** + * ISO A10 media size: 26mm x 37mm (1.02" x 1.46") + * + * @see #createMediaSize(PackageManager, int) + */ + public static final int ISO_A10 = 11; + + + /** + * ISO B0 media size: 1000mm x 1414mm (39.37" x 55.67") + * + * @see #createMediaSize(PackageManager, int) + */ + public static final int ISO_B0 = 100; + + /** + * ISO B1 media size: 707mm x 1000mm (27.83" x 39.37") + * + * @see #createMediaSize(PackageManager, int) + */ + public static final int ISO_B1 = 101; + + /** + * ISO B2 media size: 500mm x 707mm (19.69" x 27.83") + * + * @see #createMediaSize(PackageManager, int) + */ + public static final int ISO_B2 = 102; + + /** + * ISO B3 media size: 353mm x 500mm (13.90" x 19.69") + * + * @see #createMediaSize(PackageManager, int) + */ + public static final int ISO_B3 = 103; + + /** + * ISO B4 media size: 250mm x 353mm (9.84" x 13.90") + * + * @see #createMediaSize(PackageManager, int) + */ + public static final int ISO_B4 = 104; + + /** + * ISO B5 media size: 176mm x 250mm (6.93" x 9.84") + * + * @see #createMediaSize(PackageManager, int) + */ + public static final int ISO_B5 = 105; + + /** + * ISO B6 media size: 125mm x 176mm (4.92" x 6.93") + * + * @see #createMediaSize(PackageManager, int) + */ + public static final int ISO_B6 = 106; + + /** + * ISO B7 media size: 88mm x 125mm (3.46" x 4.92") + * + * @see #createMediaSize(PackageManager, int) + */ + public static final int ISO_B7 = 107; + + /** ISO B8 media size: 62mm x 88mm (2.44" x 3.46") + * + * @see #createMediaSize(PackageManager, int) + */ + public static final int ISO_B8 = 108; + + /** + * ISO B9 media size: 44mm x 62mm (1.73" x 2.44") + * + * @see #createMediaSize(PackageManager, int) + */ + public static final int ISO_B9 = 109; + + /** + * ISO B10 media size: 31mm x 44mm (1.22" x 1.73") + * + * @see #createMediaSize(PackageManager, int) + */ + public static final int ISO_B10 = 110; + + + /** + * ISO C0 media size: 917mm x 1297mm (36.10" x 51.06") + * + * @see #createMediaSize(PackageManager, int) + */ + public static final int ISO_C0 = 200; + + /** + * ISO C1 media size: 648mm x 917mm (25.51" x 36.10") + * + * @see #createMediaSize(PackageManager, int) + */ + + public static final int ISO_C1 = 201; + /** + * ISO C2 media size: 458mm x 648mm (18.03" x 25.51") + * + * @see #createMediaSize(PackageManager, int) + */ + public static final int ISO_C2 = 202; + + /** + * ISO C3 media size: 324mm x 458mm (12.76" x 18.03") + * + * @see #createMediaSize(PackageManager, int) + */ + public static final int ISO_C3 = 203; + + /** + * ISO C4 media size: 229mm x 324mm (9.02" x 12.76") + * + * @see #createMediaSize(PackageManager, int) + */ + public static final int ISO_C4 = 204; + + /** + * ISO C5 media size: 162mm x 229mm (6.38" x 9.02") + * + * @see #createMediaSize(PackageManager, int) + */ + public static final int ISO_C5 = 205; + + /** + * ISO C6 media size: 114mm x 162mm (4.49" x 6.38") + * + * @see #createMediaSize(PackageManager, int) + */ + public static final int ISO_C6 = 206; + + /** + * ISO C7 media size: 81mm x 114mm (3.19" x 4.49") + * + * @see #createMediaSize(PackageManager, int) + */ + public static final int ISO_C7 = 207; + + /** + * ISO C8 media size: 57mm x 81mm (2.24" x 3.19") + * + * @see #createMediaSize(PackageManager, int) + */ + public static final int ISO_C8 = 208; + + /** + * ISO C9 media size: 40mm x 57mm (1.57" x 2.24") + * + * @see #createMediaSize(PackageManager, int) + */ + public static final int ISO_C9 = 209; + + /** + * ISO C10 media size: 28mm x 40mm (1.10" x 1.57") + * + * @see #createMediaSize(PackageManager, int) + */ + public static final int ISO_C10 = 210; + // North America - /** North America Letter media size: 8.5" x 11" */ - public static final MediaSize NA_LETTER = - new MediaSize("NA_LETTER", "android", R.string.mediaSize_na_letter, 8500, 11000); - /** North America Government-Letter media size: 8.0" x 10.5" */ - public static final MediaSize NA_GOVT_LETTER = - new MediaSize("NA_GOVT_LETTER", "android", - R.string.mediaSize_na_gvrnmt_letter, 8000, 10500); - /** North America Legal media size: 8.5" x 14" */ - public static final MediaSize NA_LEGAL = - new MediaSize("NA_LEGAL", "android", R.string.mediaSize_na_legal, 8500, 14000); - /** North America Junior Legal media size: 8.0" x 5.0" */ - public static final MediaSize NA_JUNIOR_LEGAL = - new MediaSize("NA_JUNIOR_LEGAL", "android", - R.string.mediaSize_na_junior_legal, 8000, 5000); - /** North America Ledger media size: 17" x 11" */ - public static final MediaSize NA_LEDGER = - new MediaSize("NA_LEDGER", "android", R.string.mediaSize_na_ledger, 17000, 11000); - /** North America Tabloid media size: 11" x 17" */ - public static final MediaSize NA_TBLOID = - new MediaSize("NA_TABLOID", "android", - R.string.mediaSize_na_tabloid, 11000, 17000); + /** + * North America Letter media size: 8.5" x 11" + * + * @see #createMediaSize(PackageManager, int) + */ + public static final int NA_LETTER = 300; - private final String mId; - private final String mPackageName; - private final int mLabelResId; - private final int mWidthMils; - private final int mHeightMils; + /** + * North America Government-Letter media size: 8.0" x 10.5" + * + * @see #createMediaSize(PackageManager, int) + */ + public static final int NA_GOVT_LETTER = 301; /** - * Gets the unique media size id. + * North America Legal media size: 8.5" x 14" * - * @return The unique media size id. + * @see #createMediaSize(PackageManager, int) */ - public String getId() { - return mId; - } + public static final int NA_LEGAL = 302; /** - * Gets the human readable media size label. + * North America Junior Legal media size: 8.0" x 5.0" * - * @return The human readable label. + * @see #createMediaSize(PackageManager, int) */ - public CharSequence getLabel(PackageManager packageManager) { - try { - return packageManager.getResourcesForApplication( - mPackageName).getString(mLabelResId); - } catch (NotFoundException nfe) { - Log.w(LOG_TAG, "Could not load resouce" + mLabelResId - + " from package " + mPackageName); - } catch (NameNotFoundException nnfee) { - Log.w(LOG_TAG, "Could not load resouce" + mLabelResId - + " from package " + mPackageName); - } - return null; - } + public static final int NA_JUNIOR_LEGAL = 303; /** - * Gets the media width in mils (thousands of an inch). + * North America Ledger media size: 17" x 11" * - * @return The media width. + * @see #createMediaSize(PackageManager, int) */ - public int getWidthMils() { - return mWidthMils; - } + public static final int NA_LEDGER = 304; /** - * Gets the media height in mils (thousands of an inch). + * North America Tabloid media size: 11" x 17" * - * @return The media height. + * @see #createMediaSize(PackageManager, int) */ - public int getHeightMils() { - return mHeightMils; + public static final int NA_TBLOID = 305; + + /** + * Creates a standard media size with a localized label. + * + * @param pm Package manager used to load the label. + * @param mediaSize Media size constant. + * @return A {@link MediaSize} instance with a localized label. + */ + public static MediaSize createMediaSize(PackageManager pm, int mediaSize) { + final Resources resources; + try { + resources = pm.getResourcesForApplication("android"); + } catch (NameNotFoundException nnfe) { + return null; + } + switch (mediaSize) { + case ISO_A0: { + return new MediaSize("ISO_A0", resources + .getString(R.string.mediaSize_iso_a0), 33110, 46810); + } + case ISO_A1: { + return new MediaSize("ISO_A1", resources + .getString(R.string.mediaSize_iso_a1), 23390, 33110); + } + case ISO_A2: { + return new MediaSize("ISO_A2", resources + .getString(R.string.mediaSize_iso_a2), 16540, 23390); + } + case ISO_A3: { + return new MediaSize("ISO_A3", resources + .getString(R.string.mediaSize_iso_a3), 11690, 16540); + } + case ISO_A4: { + return new MediaSize("ISO_A4", resources + .getString(R.string.mediaSize_iso_a4), 8270, 11690); + } + case ISO_A5: { + return new MediaSize("ISO_A5", resources + .getString(R.string.mediaSize_iso_a5), 5830, 8270); + } + case ISO_A6: { + return new MediaSize("ISO_A6", resources + .getString(R.string.mediaSize_iso_a6), 4130, 5830); + } + case ISO_A7: { + return new MediaSize("ISO_A7", resources + .getString(R.string.mediaSize_iso_a7), 2910, 4130); + } + case ISO_A8: { + return new MediaSize("ISO_A8", resources + .getString(R.string.mediaSize_iso_a8), 2050, 2910); + } + case ISO_A9: { + return new MediaSize("ISO_A9", resources + .getString(R.string.mediaSize_iso_a9), 1460, 2050); + } + case ISO_A10: { + return new MediaSize("ISO_A10", resources + .getString(R.string.mediaSize_iso_a10), 1020, 1460); + } + case ISO_B0: { + return new MediaSize("ISO_B0", resources + .getString(R.string.mediaSize_iso_b0), 39370, 55670); + } + case ISO_B1: { + return new MediaSize("ISO_B1", resources + .getString(R.string.mediaSize_iso_b1), 27830, 39370); + } + case ISO_B2: { + return new MediaSize("ISO_B2", resources + .getString(R.string.mediaSize_iso_b2), 19690, 27830); + } + case ISO_B3: { + return new MediaSize("ISO_B3", resources + .getString(R.string.mediaSize_iso_b3), 13900, 19690); + } + case ISO_B4: { + return new MediaSize("ISO_B4", resources + .getString(R.string.mediaSize_iso_b4), 9840, 13900); + } + case ISO_B5: { + return new MediaSize("ISO_B5", resources + .getString(R.string.mediaSize_iso_b5), 6930, 9840); + } + case ISO_B6: { + return new MediaSize("ISO_B6", resources + .getString(R.string.mediaSize_iso_b6), 4920, 6930); + } + case ISO_B7: { + return new MediaSize("ISO_B7", resources + .getString(R.string.mediaSize_iso_b7), 3460, 4920); + } + case ISO_B8: { + return new MediaSize("ISO_B8", resources + .getString(R.string.mediaSize_iso_b8), 2440, 3460); + } + case ISO_B9: { + return new MediaSize("ISO_B9", resources + .getString(R.string.mediaSize_iso_b9), 1730, 2440); + } + case ISO_B10: { + return new MediaSize("ISO_B10", resources + .getString(R.string.mediaSize_iso_b10), 1220, 1730); + } + case ISO_C0: { + return new MediaSize("ISO_C0", resources + .getString(R.string.mediaSize_iso_c0), 36100, 51060); + } + case ISO_C1: { + return new MediaSize("ISO_C1", resources + .getString(R.string.mediaSize_iso_c1), 25510, 36100); + } + case ISO_C2: { + return new MediaSize("ISO_C2", resources + .getString(R.string.mediaSize_iso_c2), 18030, 25510); + } + case ISO_C3: { + return new MediaSize("ISO_C3", resources + .getString(R.string.mediaSize_iso_c3), 12760, 18030); + } + case ISO_C4: { + return new MediaSize("ISO_C4", resources + .getString(R.string.mediaSize_iso_c4), 9020, 12760); + } + case ISO_C5: { + return new MediaSize("ISO_C5", resources + .getString(R.string.mediaSize_iso_c5), 6380, 9020); + } + case ISO_C6: { + return new MediaSize("ISO_C6", resources + .getString(R.string.mediaSize_iso_c6), 4490, 6380); + } + case ISO_C7: { + return new MediaSize("ISO_C7", resources + .getString(R.string.mediaSize_iso_c7), 3190, 4490); + } + case ISO_C8: { + return new MediaSize("ISO_C8", resources + .getString(R.string.mediaSize_iso_c8), 2240, 3190); + } + case ISO_C9: { + return new MediaSize("ISO_C9", resources + .getString(R.string.mediaSize_iso_c9), 1570, 2240); + } + case ISO_C10: { + return new MediaSize("ISO_C10", resources + .getString(R.string.mediaSize_iso_c10), 1100, 1570); + } + case NA_LETTER: { + return new MediaSize("NA_LETTER", resources + .getString(R.string.mediaSize_na_letter), 8500, 11000); + } + case NA_GOVT_LETTER: { + return new MediaSize("NA_GOVT_LETTER", resources + .getString(R.string.mediaSize_na_gvrnmt_letter), 8000, 10500); + } + case NA_LEGAL: { + return new MediaSize("NA_LEGAL", resources + .getString(R.string.mediaSize_na_legal), 8500, 14000); + } + case NA_JUNIOR_LEGAL: { + return new MediaSize("NA_JUNIOR_LEGAL", resources + .getString(R.string.mediaSize_na_junior_legal), 8000, 5000); + } + case NA_LEDGER: { + return new MediaSize("NA_LEDGER", resources + .getString(R.string.mediaSize_na_ledger), 17000, 11000); + } + case NA_TBLOID: { + return new MediaSize("NA_TABLOID", resources + .getString(R.string.mediaSize_na_tabloid), 11000, 17000); + } + default: { + throw new IllegalArgumentException("Unknown media size."); + } + } } + private final String mId; + private final CharSequence mLabel; + private final int mWidthMils; + private final int mHeightMils; + /** * Creates a new instance. * * @param id The unique media size id. - * @param packageName The name of the creating package. - * @param labelResId The resource if of a human readable label. + * @param label The <strong>internationalized</strong> human readable label. * @param widthMils The width in mils (thousands of an inch). * @param heightMils The height in mils (thousands of an inch). * @@ -586,16 +865,12 @@ public final class PrintAttributes implements Parcelable { * @throws IllegalArgumentException If the widthMils is less than or equal to zero. * @throws IllegalArgumentException If the heightMils is less than or equal to zero. */ - public MediaSize(String id, String packageName, int labelResId, - int widthMils, int heightMils) { + public MediaSize(String id, CharSequence label, int widthMils, int heightMils) { if (TextUtils.isEmpty(id)) { throw new IllegalArgumentException("id cannot be empty."); } - if (TextUtils.isEmpty(packageName)) { - throw new IllegalArgumentException("packageName cannot be empty."); - } - if (labelResId <= 0) { - throw new IllegalArgumentException("labelResId must be greater than zero."); + if (TextUtils.isEmpty(label)) { + throw new IllegalArgumentException("label cannot be empty."); } if (widthMils <= 0) { throw new IllegalArgumentException("widthMils " @@ -605,17 +880,51 @@ public final class PrintAttributes implements Parcelable { throw new IllegalArgumentException("heightMils " + "cannot be less than or euqual to zero."); } - mPackageName = packageName; mId = id; - mLabelResId = labelResId; + mLabel = label; mWidthMils = widthMils; mHeightMils = heightMils; } + /** + * Gets the unique media size id. + * + * @return The unique media size id. + */ + public String getId() { + return mId; + } + + /** + * Gets the human readable media size label. + * + * @return The human readable label. + */ + public CharSequence getLabel() { + return mLabel; + } + + /** + * Gets the media width in mils (thousands of an inch). + * + * @return The media width. + */ + public int getWidthMils() { + return mWidthMils; + } + + /** + * Gets the media height in mils (thousands of an inch). + * + * @return The media height. + */ + public int getHeightMils() { + return mHeightMils; + } + void writeToParcel(Parcel parcel) { parcel.writeString(mId); - parcel.writeString(mPackageName); - parcel.writeInt(mLabelResId); + parcel.writeCharSequence(mLabel); parcel.writeInt(mWidthMils); parcel.writeInt(mHeightMils); } @@ -623,8 +932,7 @@ public final class PrintAttributes implements Parcelable { static MediaSize createFromParcel(Parcel parcel) { return new MediaSize( parcel.readString(), - parcel.readString(), - parcel.readInt(), + parcel.readCharSequence(), parcel.readInt(), parcel.readInt()); } @@ -634,8 +942,7 @@ public final class PrintAttributes implements Parcelable { StringBuilder builder = new StringBuilder(); builder.append("MediaSize{"); builder.append("id: ").append(mId); - builder.append(", packageName: ").append(mPackageName); - builder.append(", labelResId: ").append(mLabelResId); + builder.append(", label: ").append(mLabel); builder.append(", heightMils: ").append(mHeightMils); builder.append(", widthMils: ").append(mWidthMils); builder.append("}"); @@ -647,15 +954,46 @@ public final class PrintAttributes implements Parcelable { * This class specifies a supported resolution in dpi (dots per inch). */ public static final class Resolution { - private static final String LOG_TAG = "Resolution"; - private final String mId; - private final String mPackageName; - private final int mLabelResId; + private final CharSequence mLabel; private final int mHorizontalDpi; private final int mVerticalDpi; /** + * Creates a new instance. + * + * @param id The unique resolution id. + * @param label The <strong>internationalized</strong> human readable label. + * @param horizontalDpi The horizontal resolution in dpi. + * @param verticalDpi The vertical resolution in dpi. + * + * @throws IllegalArgumentException If the id is empty. + * @throws IllegalArgumentException If the label is empty. + * @throws IllegalArgumentException If the horizontalDpi is less than or equal to zero. + * @throws IllegalArgumentException If the verticalDpi is less than or equal to zero. + */ + public Resolution(String id, CharSequence label, int horizontalDpi, int verticalDpi) { + if (TextUtils.isEmpty(id)) { + throw new IllegalArgumentException("id cannot be empty."); + } + if (TextUtils.isEmpty(label)) { + throw new IllegalArgumentException("label cannot be empty."); + } + if (horizontalDpi <= 0) { + throw new IllegalArgumentException("horizontalDpi " + + "cannot be less than or equal to zero."); + } + if (verticalDpi <= 0) { + throw new IllegalArgumentException("verticalDpi" + + " cannot be less than or equal to zero."); + } + mId = id; + mLabel = label; + mHorizontalDpi = horizontalDpi; + mVerticalDpi = verticalDpi; + } + + /** * Gets the unique resolution id. * * @return The unique resolution id. @@ -669,18 +1007,8 @@ public final class PrintAttributes implements Parcelable { * * @return The human readable label. */ - public CharSequence getLabel(PackageManager packageManager) { - try { - return packageManager.getResourcesForApplication( - mPackageName).getString(mLabelResId); - } catch (NotFoundException nfe) { - Log.w(LOG_TAG, "Could not load resouce" + mLabelResId - + " from package " + mPackageName); - } catch (NameNotFoundException nnfee) { - Log.w(LOG_TAG, "Could not load resouce" + mLabelResId - + " from package " + mPackageName); - } - return null; + public CharSequence getLabel() { + return mLabel; } /** @@ -701,50 +1029,9 @@ public final class PrintAttributes implements Parcelable { return mVerticalDpi; } - /** - * Creates a new instance. - * - * @param id The unique resolution id. - * @param packageName The name of the creating package. - * @param labelResId The resource id of a human readable label. - * @param horizontalDpi The horizontal resolution in dpi. - * @param verticalDpi The vertical resolution in dpi. - * - * @throws IllegalArgumentException If the id is empty. - * @throws IllegalArgumentException If the label is empty. - * @throws IllegalArgumentException If the horizontalDpi is less than or equal to zero. - * @throws IllegalArgumentException If the verticalDpi is less than or equal to zero. - */ - public Resolution(String id, String packageName, int labelResId, - int horizontalDpi, int verticalDpi) { - if (TextUtils.isEmpty(id)) { - throw new IllegalArgumentException("id cannot be empty."); - } - if (TextUtils.isEmpty(packageName)) { - throw new IllegalArgumentException("packageName cannot be empty."); - } - if (labelResId <= 0) { - throw new IllegalArgumentException("labelResId must be greater than zero."); - } - if (horizontalDpi <= 0) { - throw new IllegalArgumentException("horizontalDpi " - + "cannot be less than or equal to zero."); - } - if (verticalDpi <= 0) { - throw new IllegalArgumentException("verticalDpi" - + " cannot be less than or equal to zero."); - } - mId = id; - mPackageName = packageName; - mLabelResId = labelResId; - mHorizontalDpi = horizontalDpi; - mVerticalDpi = verticalDpi; - } - void writeToParcel(Parcel parcel) { parcel.writeString(mId); - parcel.writeString(mPackageName); - parcel.writeInt(mLabelResId); + parcel.writeCharSequence(mLabel); parcel.writeInt(mHorizontalDpi); parcel.writeInt(mVerticalDpi); } @@ -752,8 +1039,7 @@ public final class PrintAttributes implements Parcelable { static Resolution createFromParcel(Parcel parcel) { return new Resolution( parcel.readString(), - parcel.readString(), - parcel.readInt(), + parcel.readCharSequence(), parcel.readInt(), parcel.readInt()); } @@ -763,8 +1049,7 @@ public final class PrintAttributes implements Parcelable { StringBuilder builder = new StringBuilder(); builder.append("Resolution{"); builder.append("id: ").append(mId); - builder.append(", packageName: ").append(mPackageName); - builder.append(", labelResId: ").append(mLabelResId); + builder.append(", label: ").append(mLabel); builder.append(", horizontalDpi: ").append(mHorizontalDpi); builder.append(", verticalDpi: ").append(mVerticalDpi); builder.append("}"); @@ -782,6 +1067,38 @@ public final class PrintAttributes implements Parcelable { private final int mBottomMils; /** + * Creates a new instance. + * + * @param leftMils The left margin in mils (thousands of an inch). + * @param topMils The top margin in mils (thousands of an inch). + * @param rightMils The right margin in mils (thousands of an inch). + * @param bottomMils The bottom margin in mils (thousands of an inch). + * + * @throws IllegalArgumentException If the leftMils is less than zero. + * @throws IllegalArgumentException If the topMils is less than zero. + * @throws IllegalArgumentException If the rightMils is less than zero. + * @throws IllegalArgumentException If the bottomMils is less than zero. + */ + public Margins(int leftMils, int topMils, int rightMils, int bottomMils) { + if (leftMils < 0) { + throw new IllegalArgumentException("leftMils cannot be less than zero."); + } + if (topMils < 0) { + throw new IllegalArgumentException("topMils cannot be less than zero."); + } + if (rightMils < 0) { + throw new IllegalArgumentException("rightMils cannot be less than zero."); + } + if (bottomMils < 0) { + throw new IllegalArgumentException("bottomMils cannot be less than zero."); + } + mTopMils = topMils; + mLeftMils = leftMils; + mRightMils = rightMils; + mBottomMils = bottomMils; + } + + /** * Gets the left margin in mils (thousands of an inch). * * @return The left margin. @@ -817,38 +1134,6 @@ public final class PrintAttributes implements Parcelable { return mBottomMils; } - /** - * Creates a new instance. - * - * @param leftMils The left margin in mils (thousands of an inch). - * @param topMils The top margin in mils (thousands of an inch). - * @param rightMils The right margin in mils (thousands of an inch). - * @param bottomMils The bottom margin in mils (thousands of an inch). - * - * @throws IllegalArgumentException If the leftMils is less than zero. - * @throws IllegalArgumentException If the topMils is less than zero. - * @throws IllegalArgumentException If the rightMils is less than zero. - * @throws IllegalArgumentException If the bottomMils is less than zero. - */ - public Margins(int leftMils, int topMils, int rightMils, int bottomMils) { - if (leftMils < 0) { - throw new IllegalArgumentException("leftMils cannot be less than zero."); - } - if (topMils < 0) { - throw new IllegalArgumentException("topMils cannot be less than zero."); - } - if (rightMils < 0) { - throw new IllegalArgumentException("rightMils cannot be less than zero."); - } - if (bottomMils < 0) { - throw new IllegalArgumentException("bottomMils cannot be less than zero."); - } - mTopMils = topMils; - mLeftMils = leftMils; - mRightMils = rightMils; - mBottomMils = bottomMils; - } - void writeToParcel(Parcel parcel) { parcel.writeInt(mLeftMils); parcel.writeInt(mTopMils); @@ -881,11 +1166,28 @@ public final class PrintAttributes implements Parcelable { * Represents a printer tray. */ public static final class Tray { - private static final String LOG_TAG = "Tray"; - private final String mId; - private final String mPackageName; - private final int mLabelResId; + private final CharSequence mLabel; + + /** + * Creates a new instance. + * + * @param id The unique tray id. + * @param label The <strong>internationalized</strong> human readable label. + * + * @throws IllegalArgumentException If the id is empty. + * @throws IllegalArgumentException If the label is empty. + */ + public Tray(String id, CharSequence label) { + if (TextUtils.isEmpty(id)) { + throw new IllegalArgumentException("id cannot be empty."); + } + if (TextUtils.isEmpty(label)) { + throw new IllegalArgumentException("label cannot be empty."); + } + mId = id; + mLabel = label; + } /** * Gets the unique tray id. @@ -901,56 +1203,19 @@ public final class PrintAttributes implements Parcelable { * * @return The human readable label. */ - public CharSequence getLabel(PackageManager packageManager) { - try { - return packageManager.getResourcesForApplication( - mPackageName).getString(mLabelResId); - } catch (NotFoundException nfe) { - Log.w(LOG_TAG, "Could not load resouce" + mLabelResId - + " from package " + mPackageName); - } catch (NameNotFoundException nnfee) { - Log.w(LOG_TAG, "Could not load resouce" + mLabelResId - + " from package " + mPackageName); - } - return null; - } - - /** - * Creates a new instance. - * - * @param id The unique tray id. - * @param packageName The name of the creating package. - * @param labelResId The resource id of a human readable label. - * - * @throws IllegalArgumentException If the id is empty. - * @throws IllegalArgumentException If the label is empty. - */ - public Tray(String id, String packageName, int labelResId) { - if (TextUtils.isEmpty(id)) { - throw new IllegalArgumentException("id cannot be empty."); - } - if (TextUtils.isEmpty(packageName)) { - throw new IllegalArgumentException("packageName cannot be empty."); - } - if (labelResId <= 0) { - throw new IllegalArgumentException("label must be greater than zero."); - } - mId = id; - mPackageName = packageName; - mLabelResId = labelResId; + public CharSequence getLabel() { + return mLabel; } void writeToParcel(Parcel parcel) { parcel.writeString(mId); - parcel.writeString(mPackageName); - parcel.writeInt(mLabelResId); + parcel.writeCharSequence(mLabel); } static Tray createFromParcel(Parcel parcel) { return new Tray( parcel.readString(), - parcel.readString(), - parcel.readInt()); + parcel.readCharSequence()); } @Override @@ -959,8 +1224,7 @@ public final class PrintAttributes implements Parcelable { builder.append("Tray{"); builder.append("id: ").append(mId); builder.append("id: ").append(mId); - builder.append(", packageName: ").append(mPackageName); - builder.append(", labelResId: ").append(mLabelResId); + builder.append(", label: ").append(mLabel); builder.append("}"); return builder.toString(); } diff --git a/core/java/android/print/PrintDocumentAdapter.java b/core/java/android/print/PrintDocumentAdapter.java new file mode 100644 index 0000000..1f83a45 --- /dev/null +++ b/core/java/android/print/PrintDocumentAdapter.java @@ -0,0 +1,232 @@ +/* + * 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.print; + +import android.os.Bundle; +import android.os.CancellationSignal; + +import java.io.FileDescriptor; +import java.util.List; + +/** + * Base class that provides the content of a document to be printed. + * + * <h3>Lifecycle</h3> + * <p> + * <ul> + * <li> + * Initially, you will receive a call to {@link #onStart()}. This callback + * can be used to allocate resources. + * </li> + * <li> + * Next, you will get one or more calls to {@link #onLayout(PrintAttributes, + * PrintAttributes, CancellationSignal, LayoutResultCallback, Bundle)} to + * inform you that the print attributes (page size, density, etc) changed + * giving you an opportunity to layout the content to match the new constraints. + * </li> + * <li> + * After every call to {@link #onLayout(PrintAttributes, PrintAttributes, + * CancellationSignal, LayoutResultCallback, Bundle)}, you may get a call to + * {@link #onWrite(List, FileDescriptor, CancellationSignal, WriteResultCallback)} + * asking you to write a PDF file with the content for specific pages. + * </li> + * <li> + * Finally, you will receive a call to {@link #onFinish()}. You can use this + * callback to release resources allocated in {@link #onStart()}. + * </li> + * </ul> + * </p> + * <h3>Implementation</h3> + * <p> + * The APIs defined in this class are designed to enable doing part or all + * of the work on an arbitrary thread. For example, if the printed content + * does not depend on the UI state, i.e. on what is shown on the screen, then + * you can off load the entire work on a dedicated thread, thus making your + * application interactive while the print work is being performed. + * </p> + * <p> + * You can also do work on different threads, for example if you print UI + * content, you can handle {@link #onStart()} and {@link #onLayout(PrintAttributes, + * PrintAttributes, CancellationSignal, LayoutResultCallback, Bundle)} on + * the UI thread (assuming onStart initializes resources needed for layout). + * This will ensure that the UI does not change while you are laying out the + * printed content. Then you can handle {@link #onWrite(List, FileDescriptor, + * CancellationSignal, WriteResultCallback)} and {@link #onFinish()} on another + * thread. This will ensure that the UI is frozen for the minimal amount of + * time. Also this assumes that you will generate the printed content in + * {@link #onLayout(PrintAttributes, PrintAttributes, CancellationSignal, + * LayoutResultCallback, Bundle)} which is not mandatory. If you use multiple + * threads, you are responsible for proper synchronization. + * </p> + */ +public abstract class PrintDocumentAdapter { + + /** + * Meta-data key: mapped to a boolean value that is <code>true</code> if + * the current layout is for a print preview, <code>false</code> otherwise. + */ + public static final String METADATA_KEY_PRINT_PREVIEW = "KEY_METADATA_PRINT_PREVIEW"; + + /** + * Called when printing starts. You can use this callback to allocate + * resources. This method is invoked on the main thread. + */ + public void onStart() { + /* do nothing - stub */ + } + + /** + * Called when the print attributes (page size, density, etc) changed + * giving you a chance to layout the content such that it matches the + * new constraints. This method is invoked on the main thread. + * <p> + * After you are done laying out, you <strong>must</strong> invoke: {@link + * LayoutResultCallback#onLayoutFinished(PrintDocumentInfo, boolean)} with + * the last argument <code>true</code> or <code>false</code> depending on + * whether the layout changed the content or not, respectively; and {@link + * LayoutResultCallback#onLayoutFailed(CharSequence)}, if an error occurred. + * </p> + * <p> + * <strong>Note:</strong> If the content is large and a layout will be + * performed, it is a good practice to schedule the work on a dedicated + * thread and register an observer in the provided {@link + * CancellationSignal} upon invocation of which you should stop the + * layout. The cancellation callback will not be made on the main + * thread. + * </p> + * + * @param oldAttributes The old print attributes. + * @param newAttributes The new print attributes. + * @param cancellationSignal Signal for observing cancel layout requests. + * @param callback Callback to inform the system for the layout result. + * @param metadata Additional information about how layout the content. + * + * @see LayoutResultCallback + * @see CancellationSignal + * @see #METADATA_KEY_PRINT_PREVIEW + */ + public abstract void onLayout(PrintAttributes oldAttributes, PrintAttributes newAttributes, + CancellationSignal cancellationSignal, LayoutResultCallback callback, + Bundle metadata); + + /** + * Called when specific pages of the content should be written in the + * from of a PDF file to the given file descriptor. This method is invoked + * on the main thread. + *<p> + * After you are done writing, you should <strong>not</strong> close the + * file descriptor, rather you must invoke: {@link WriteResultCallback + * #onWriteFinished(List)}, if writing completed successfully; or {@link + * WriteResultCallback#onWriteFailed(CharSequence)}, if an error occurred. + * </p> + * <p> + * <strong>Note:</strong> If the printed content is large, it is a good + * practice to schedule writing it on a dedicated thread and register an + * observer in the provided {@link CancellationSignal} upon invocation of + * which you should stop writing. The cancellation callback will not be + * made on the main thread. + * </p> + * + * @param pages The pages whose content to print. + * @param destination The destination file descriptor to which to write. + * @param cancellationSignal Signal for observing cancel writing requests. + * @param callback Callback to inform the system for the write result. + * + * @see WriteResultCallback + * @see CancellationSignal + */ + public abstract void onWrite(List<PageRange> pages, FileDescriptor destination, + CancellationSignal cancellationSignal, WriteResultCallback callback); + + /** + * Called when printing finishes. You can use this callback to release + * resources acquired in {@link #onStart()}. This method is invoked on + * the main thread. + */ + public void onFinish() { + /* do nothing - stub */ + } + + /** + * Base class for implementing a callback for the result of {@link + * PrintDocumentAdapter#onWrite(List, FileDescriptor, CancellationSignal, + * WriteResultCallback)}. + */ + public static abstract class WriteResultCallback { + + /** + * @hide + */ + public WriteResultCallback() { + /* do nothing - hide constructor */ + } + + /** + * Notifies that all the data was written. + * + * @param pages The pages that were written. + */ + public void onWriteFinished(List<PageRange> pages) { + /* do nothing - stub */ + } + + /** + * Notifies that an error occurred while writing the data. + * + * @param error Error message. May be null if error is unknown. + */ + public void onWriteFailed(CharSequence error) { + /* do nothing - stub */ + } + } + + /** + * Base class for implementing a callback for the result of {@link + * PrintDocumentAdapter#onLayout(PrintAttributes, PrintAttributes, + * CancellationSignal, LayoutResultCallback, Bundle)}. + */ + public static abstract class LayoutResultCallback { + + /** + * @hide + */ + public LayoutResultCallback() { + /* do nothing - hide constructor */ + } + + /** + * Notifies that the layout finished and whether the content changed. + * + * @param info An info object describing the document. + * @param changed Whether the layout changed. + * + * @see PrintDocumentInfo + */ + public void onLayoutFinished(PrintDocumentInfo info, boolean changed) { + /* do nothing - stub */ + } + + /** + * Notifies that an error occurred while laying out the document. + * + * @param error Error message. May be null if error is unknown. + */ + public void onLayoutFailed(CharSequence error) { + /* do nothing - stub */ + } + } +} diff --git a/core/java/android/print/PrintAdapterInfo.aidl b/core/java/android/print/PrintDocumentInfo.aidl index 27bf717..831dcb7 100644 --- a/core/java/android/print/PrintAdapterInfo.aidl +++ b/core/java/android/print/PrintDocumentInfo.aidl @@ -16,4 +16,4 @@ package android.print; -parcelable PrintAdapterInfo; +parcelable PrintDocumentInfo; diff --git a/core/java/android/print/PrintDocumentInfo.java b/core/java/android/print/PrintDocumentInfo.java new file mode 100644 index 0000000..7d42b3a --- /dev/null +++ b/core/java/android/print/PrintDocumentInfo.java @@ -0,0 +1,181 @@ +/* + * 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.print; + +import android.os.Parcel; +import android.os.Parcelable; + +/** + * This class encapsulates information about a printed document. + */ +public final class PrintDocumentInfo implements Parcelable { + + /** + * Constant for unknown page count (default). + */ + public static final int PAGE_COUNT_UNKNOWN = -1; + + /** + * Content type: unknown (default). + */ + public static final int CONTENT_TYPE_UNKNOWN = -1; + + /** + * Content type: document. + */ + public static final int CONTENT_TYPE_DOCUMENT = 0; + + /** + * Content type: photo. + */ + public static final int CONTENT_TYPE_PHOTO = 1; + + private int mPageCount; + private int mContentType; + + /** + * Creates a new instance. + */ + private PrintDocumentInfo() { + mPageCount = PAGE_COUNT_UNKNOWN; + mContentType = CONTENT_TYPE_UNKNOWN; + } + + /** + * Creates a new instance. + * + * @param Prototype from which to clone. + */ + private PrintDocumentInfo(PrintDocumentInfo prototype) { + mPageCount = prototype.mPageCount; + mContentType = prototype.mContentType; + } + + /** + * Creates a new instance. + * + * @param parcel Data from which to initialize. + */ + private PrintDocumentInfo(Parcel parcel) { + mPageCount = parcel.readInt(); + mContentType = parcel.readInt(); + } + + /** + * Gets the total number of pages. + * + * @return The number of pages. + * + * @see #PAGE_COUNT_UNKNOWN + */ + public int getPageCount() { + return mPageCount; + } + + /** + * Gets the content type. + * + * @return The content type. + * + * @see #CONTENT_TYPE_UNKNOWN + * @see #CONTENT_TYPE_DOCUMENT + * @see #CONTENT_TYPE_PHOTO + */ + public int getContentType() { + return mContentType; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel parcel, int flags) { + parcel.writeInt(mPageCount); + parcel.writeInt(mContentType); + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("PrintDocumentInfo{"); + builder.append("pageCount: ").append(mPageCount); + builder.append(", contentType: ").append(mContentType); + builder.append("}"); + return builder.toString(); + } + + /** + * Builder for creating an {@link PrintDocumentInfo}. + */ + public static final class Builder { + private final PrintDocumentInfo mPrototype = new PrintDocumentInfo(); + + /** + * Sets the total number of pages. + * + * @param pageCount The number of pages. Must be greater than + * or equal to zero or {@link PrintDocumentInfo#PAGE_COUNT_UNKNOWN}. + */ + public Builder setPageCount(int pageCount) { + if (pageCount < 0 && pageCount != PAGE_COUNT_UNKNOWN) { + throw new IllegalArgumentException("pageCount" + + " must be greater than or euqal to zero or" + + " DocumentInfo#PAGE_COUNT_UNKNOWN"); + } + mPrototype.mPageCount = pageCount; + return this; + } + + /** + * Sets the content type. + * + * @param type The content type. + * + * @see #CONTENT_TYPE_UNKNOWN + * @see #CONTENT_TYPE_DOCUMENT + * @see #CONTENT_TYPE_PHOTO + */ + public Builder setContentType(int type) { + mPrototype.mContentType = type; + return this; + } + + /** + * Creates a new {@link PrintDocumentInfo} instance. + * + * @return The new instance. + */ + public PrintDocumentInfo create() { + return new PrintDocumentInfo(mPrototype); + } + } + + public static final Parcelable.Creator<PrintDocumentInfo> CREATOR = + new Creator<PrintDocumentInfo>() { + @Override + public PrintDocumentInfo createFromParcel(Parcel parcel) { + return new PrintDocumentInfo(parcel); + } + + @Override + public PrintDocumentInfo[] newArray(int size) { + return new PrintDocumentInfo[size]; + } + }; +} diff --git a/core/java/android/print/PrintJob.java b/core/java/android/print/PrintJob.java index f7cca87..a5e0b79 100644 --- a/core/java/android/print/PrintJob.java +++ b/core/java/android/print/PrintJob.java @@ -55,7 +55,7 @@ public final class PrintJob { * @return The print job info. */ public PrintJobInfo getInfo() { - PrintJobInfo info = mPrintManager.getPrintJob(mId); + PrintJobInfo info = mPrintManager.getPrintJobInfo(mId); if (info != null) { mCachedInfo = info; } diff --git a/core/java/android/print/PrintJobInfo.java b/core/java/android/print/PrintJobInfo.java index 72d6057..97384d9 100644 --- a/core/java/android/print/PrintJobInfo.java +++ b/core/java/android/print/PrintJobInfo.java @@ -35,11 +35,20 @@ public final class PrintJobInfo implements Parcelable { public static final int STATE_ANY = -1; /** + * Constant for matching any print job state. + * + * @hide + */ + public static final int STATE_ANY_VISIBLE_TO_CLIENTS = -2; + + /** * Print job state: The print job is being created but not yet * ready to be printed. * <p> * Next valid states: {@link #STATE_QUEUED} * </p> + * + * @hide */ public static final int STATE_CREATED = 1; @@ -116,6 +125,46 @@ public final class PrintJobInfo implements Parcelable { /** The print job attributes size. */ private PrintAttributes mAttributes; + /** Information about the printed document. */ + private PrintDocumentInfo mDocumentInfo; + + /** @hide*/ + public PrintJobInfo() { + /* do nothing */ + } + + /** @hide */ + public PrintJobInfo(PrintJobInfo other) { + mId = other.mId; + mLabel = other.mLabel; + mPrinterId = other.mPrinterId; + mState = other.mState; + mAppId = other.mAppId; + mUserId = other.mUserId; + mTag = other.mTag; + mAttributes = other.mAttributes; + mDocumentInfo = other.mDocumentInfo; + } + + private PrintJobInfo(Parcel parcel) { + mId = parcel.readInt(); + mLabel = parcel.readCharSequence(); + mPrinterId = parcel.readParcelable(null); + mState = parcel.readInt(); + mAppId = parcel.readInt(); + mUserId = parcel.readInt(); + mTag = parcel.readString(); + if (parcel.readInt() == 1) { + mPageRanges = (PageRange[]) parcel.readParcelableArray(null); + } + if (parcel.readInt() == 1) { + mAttributes = PrintAttributes.CREATOR.createFromParcel(parcel); + } + if (parcel.readInt() == 1) { + mDocumentInfo = PrintDocumentInfo.CREATOR.createFromParcel(parcel); + } + } + /** * Gets the unique print job id. * @@ -300,35 +349,26 @@ public final class PrintJobInfo implements Parcelable { mAttributes = attributes; } - /** @hide*/ - public PrintJobInfo() { - /* do nothing */ - } - - /** @hide */ - public PrintJobInfo(PrintJobInfo other) { - mId = other.mId; - mLabel = other.mLabel; - mPrinterId = other.mPrinterId; - mState = other.mState; - mAppId = other.mAppId; - mUserId = other.mUserId; - mAttributes = other.mAttributes; + /** + * Gets the info describing the printed document. + * + * @return The document info. + * + * @hide + */ + public PrintDocumentInfo getDocumentInfo() { + return mDocumentInfo; } - private PrintJobInfo(Parcel parcel) { - mId = parcel.readInt(); - mLabel = parcel.readCharSequence(); - mPrinterId = parcel.readParcelable(null); - mState = parcel.readInt(); - mAppId = parcel.readInt(); - mUserId = parcel.readInt(); - if (parcel.readInt() == 1) { - mPageRanges = (PageRange[]) parcel.readParcelableArray(null); - } - if (parcel.readInt() == 1) { - mAttributes = PrintAttributes.CREATOR.createFromParcel(parcel); - } + /** + * Sets the info describing the printed document. + * + * @param info The document info. + * + * @hide + */ + public void setDocumentInfo(PrintDocumentInfo info) { + mDocumentInfo = info; } @Override @@ -344,6 +384,7 @@ public final class PrintJobInfo implements Parcelable { parcel.writeInt(mState); parcel.writeInt(mAppId); parcel.writeInt(mUserId); + parcel.writeString(mTag); if (mPageRanges != null) { parcel.writeInt(1); parcel.writeParcelableArray(mPageRanges, flags); @@ -356,6 +397,12 @@ public final class PrintJobInfo implements Parcelable { } else { parcel.writeInt(0); } + if (mDocumentInfo != null) { + parcel.writeInt(1); + mDocumentInfo.writeToParcel(parcel, flags); + } else { + parcel.writeInt(0); + } } @Override @@ -366,7 +413,10 @@ public final class PrintJobInfo implements Parcelable { builder.append(", id: ").append(mId); builder.append(", status: ").append(stateToString(mState)); builder.append(", printer: " + mPrinterId); - builder.append(", attributes: " + (mAttributes != null ? mAttributes.toString() : null)); + builder.append(", attributes: " + (mAttributes != null + ? mAttributes.toString() : null)); + builder.append(", documentInfo: " + (mDocumentInfo != null + ? mDocumentInfo.toString() : null)); builder.append("}"); return builder.toString(); } diff --git a/core/java/android/print/PrintManager.java b/core/java/android/print/PrintManager.java index be9b596..f9f53f6 100644 --- a/core/java/android/print/PrintManager.java +++ b/core/java/android/print/PrintManager.java @@ -19,6 +19,7 @@ package android.print; import android.content.Context; import android.content.IntentSender; import android.content.IntentSender.SendIntentException; +import android.os.Bundle; import android.os.CancellationSignal; import android.os.Handler; import android.os.ICancellationSignal; @@ -26,7 +27,9 @@ import android.os.Looper; import android.os.Message; import android.os.ParcelFileDescriptor; import android.os.RemoteException; -import android.print.PrintAdapter.PrintResultCallback; +import android.print.PrintDocumentAdapter.LayoutResultCallback; +import android.print.PrintDocumentAdapter.WriteResultCallback; +import android.text.TextUtils; import android.util.Log; import com.android.internal.os.SomeArgs; @@ -103,7 +106,7 @@ public final class PrintManager { * Creates an instance that can access all print jobs. * * @param userId The user id for which to get all print jobs. - * @return An instance of the caller has the permission to access + * @return An instance if the caller has the permission to access * all print jobs, null otherwise. * * @hide @@ -112,11 +115,11 @@ public final class PrintManager { return new PrintManager(mContext, mService, userId, APP_ID_ANY); } - PrintJobInfo getPrintJob(int printJobId) { + PrintJobInfo getPrintJobInfo(int printJobId) { try { - return mService.getPrintJob(printJobId, mAppId, mUserId); + return mService.getPrintJobInfo(printJobId, mAppId, mUserId); } catch (RemoteException re) { - Log.e(LOG_TAG, "Error getting print job:" + printJobId, re); + Log.e(LOG_TAG, "Error getting a print job info:" + printJobId, re); } return null; } @@ -130,7 +133,7 @@ public final class PrintManager { */ public List<PrintJob> getPrintJobs() { try { - List<PrintJobInfo> printJobInfos = mService.getPrintJobs(mAppId, mUserId); + List<PrintJobInfo> printJobInfos = mService.getPrintJobInfos(mAppId, mUserId); if (printJobInfos == null) { return Collections.emptyList(); } @@ -141,18 +144,17 @@ public final class PrintManager { } return printJobs; } catch (RemoteException re) { - Log.e(LOG_TAG, "Error getting print jobs!", re); + Log.e(LOG_TAG, "Error getting print jobs", re); } return Collections.emptyList(); } - ICancellationSignal cancelPrintJob(int printJobId) { + void cancelPrintJob(int printJobId) { try { mService.cancelPrintJob(printJobId, mAppId, mUserId); } catch (RemoteException re) { - Log.e(LOG_TAG, "Error cancleing a print job:" + printJobId, re); + Log.e(LOG_TAG, "Error cancleing a print job: " + printJobId, re); } - return null; } /** @@ -166,24 +168,27 @@ public final class PrintManager { * @see PrintJob */ public PrintJob print(String printJobName, File pdfFile, PrintAttributes attributes) { - PrintFileAdapter printable = new PrintFileAdapter(pdfFile); - return print(printJobName, printable, attributes); + FileDocumentAdapter documentAdapter = new FileDocumentAdapter(mContext, pdfFile); + return print(printJobName, documentAdapter, attributes); } /** - * Creates a print job for printing a {@link PrintAdapter} with default print + * Creates a print job for printing a {@link PrintDocumentAdapter} with default print * attributes. * * @param printJobName A name for the new print job. - * @param printAdapter The printable adapter to print. + * @param documentAdapter An adapter that emits the document to print. * @param attributes The default print job attributes. * @return The created print job. * * @see PrintJob */ - public PrintJob print(String printJobName, PrintAdapter printAdapter, + public PrintJob print(String printJobName, PrintDocumentAdapter documentAdapter, PrintAttributes attributes) { - PrintAdapterDelegate delegate = new PrintAdapterDelegate(printAdapter, + if (TextUtils.isEmpty(printJobName)) { + throw new IllegalArgumentException("priintJobName cannot be empty"); + } + PrintDocumentAdapterDelegate delegate = new PrintDocumentAdapterDelegate(documentAdapter, mContext.getMainLooper()); try { PrintJobInfo printJob = mService.print(printJobName, mPrintClient, delegate, @@ -217,145 +222,120 @@ public final class PrintManager { } } - private static final class PrintAdapterDelegate extends IPrintAdapter.Stub { - private final Object mLock = new Object(); - - private PrintAdapter mPrintAdapter; + private static final class PrintDocumentAdapterDelegate extends IPrintDocumentAdapter.Stub { + private PrintDocumentAdapter mDocumentAdapter; // Strong reference OK - cleared in finish() - private Handler mHandler; + private Handler mHandler; // Strong reference OK - cleared in finish() - public PrintAdapterDelegate(PrintAdapter printAdapter, Looper looper) { - mPrintAdapter = printAdapter; + public PrintDocumentAdapterDelegate(PrintDocumentAdapter documentAdapter, Looper looper) { + mDocumentAdapter = documentAdapter; mHandler = new MyHandler(looper); } @Override public void start() { - synchronized (mLock) { - if (isFinishedLocked()) { - return; - } - mHandler.obtainMessage(MyHandler.MESSAGE_START, - mPrintAdapter).sendToTarget(); - } + mHandler.sendEmptyMessage(MyHandler.MSG_START); } @Override - public void printAttributesChanged(PrintAttributes attributes) { - synchronized (mLock) { - if (isFinishedLocked()) { - return; - } - SomeArgs args = SomeArgs.obtain(); - args.arg1 = mPrintAdapter; - args.arg2 = attributes; - mHandler.obtainMessage(MyHandler.MESSAGE_PRINT_ATTRIBUTES_CHANGED, - args).sendToTarget(); - } + public void layout(PrintAttributes oldAttributes, PrintAttributes newAttributes, + ILayoutResultCallback callback, Bundle metadata) { + SomeArgs args = SomeArgs.obtain(); + args.arg1 = oldAttributes; + args.arg2 = newAttributes; + args.arg3 = callback; + args.arg4 = metadata; + mHandler.obtainMessage(MyHandler.MSG_LAYOUT, args).sendToTarget(); } @Override - public void print(List<PageRange> pages, ParcelFileDescriptor fd, - IPrintResultCallback callback) { - synchronized (mLock) { - if (isFinishedLocked()) { - return; - } - SomeArgs args = SomeArgs.obtain(); - args.arg1 = mPrintAdapter; - args.arg2 = pages; - args.arg3 = fd.getFileDescriptor(); - args.arg4 = callback; - mHandler.obtainMessage(MyHandler.MESSAGE_PRINT, args).sendToTarget(); - } + public void write(List<PageRange> pages, ParcelFileDescriptor fd, + IWriteResultCallback callback) { + SomeArgs args = SomeArgs.obtain(); + args.arg1 = pages; + args.arg2 = fd.getFileDescriptor(); + args.arg3 = callback; + mHandler.obtainMessage(MyHandler.MSG_WRITE, args).sendToTarget(); } @Override public void finish() { - synchronized (mLock) { - if (isFinishedLocked()) { - return; - } - mHandler.obtainMessage(MyHandler.MESSAGE_FINIS, - mPrintAdapter).sendToTarget(); - } + mHandler.sendEmptyMessage(MyHandler.MSG_FINISH); } - private boolean isFinishedLocked() { - return mPrintAdapter == null; + private boolean isFinished() { + return mDocumentAdapter == null; } - private void finishLocked() { - mPrintAdapter = null; + private void doFinish() { + mDocumentAdapter = null; mHandler = null; } private final class MyHandler extends Handler { - public static final int MESSAGE_START = 1; - public static final int MESSAGE_PRINT_ATTRIBUTES_CHANGED = 2; - public static final int MESSAGE_PRINT = 3; - public static final int MESSAGE_FINIS = 4; + public static final int MSG_START = 1; + public static final int MSG_LAYOUT = 2; + public static final int MSG_WRITE = 3; + public static final int MSG_FINISH = 4; public MyHandler(Looper looper) { super(looper, null, true); } @Override + @SuppressWarnings("unchecked") public void handleMessage(Message message) { + if (isFinished()) { + return; + } switch (message.what) { - case MESSAGE_START: { - PrintAdapter adapter = (PrintAdapter) message.obj; - adapter.onStart(); + case MSG_START: { + mDocumentAdapter.onStart(); } break; - case MESSAGE_PRINT_ATTRIBUTES_CHANGED: { + case MSG_LAYOUT: { SomeArgs args = (SomeArgs) message.obj; - PrintAdapter adapter = (PrintAdapter) args.arg1; - PrintAttributes attributes = (PrintAttributes) args.arg2; + PrintAttributes oldAttributes = (PrintAttributes) args.arg1; + PrintAttributes newAttributes = (PrintAttributes) args.arg2; + ILayoutResultCallback callback = (ILayoutResultCallback) args.arg3; + Bundle metadata = (Bundle) args.arg4; args.recycle(); - adapter.onPrintAttributesChanged(attributes); + + try { + ICancellationSignal remoteSignal = CancellationSignal.createTransport(); + callback.onLayoutStarted(remoteSignal); + + mDocumentAdapter.onLayout(oldAttributes, newAttributes, + CancellationSignal.fromTransport(remoteSignal), + new LayoutResultCallbackWrapper(callback), metadata); + } catch (RemoteException re) { + Log.e(LOG_TAG, "Error printing", re); + } } break; - case MESSAGE_PRINT: { + case MSG_WRITE: { SomeArgs args = (SomeArgs) message.obj; - PrintAdapter adapter = (PrintAdapter) args.arg1; - @SuppressWarnings("unchecked") - List<PageRange> pages = (List<PageRange>) args.arg2; - final FileDescriptor fd = (FileDescriptor) args.arg3; - IPrintResultCallback callback = (IPrintResultCallback) args.arg4; + List<PageRange> pages = (List<PageRange>) args.arg1; + FileDescriptor fd = (FileDescriptor) args.arg2; + IWriteResultCallback callback = (IWriteResultCallback) args.arg3; args.recycle(); + try { ICancellationSignal remoteSignal = CancellationSignal.createTransport(); - callback.onPrintStarted(adapter.getInfo(), remoteSignal); - - CancellationSignal localSignal = CancellationSignal.fromTransport( - remoteSignal); - adapter.onPrint(pages, fd, localSignal, - new PrintResultCallbackWrapper(callback) { - @Override - public void onPrintFinished(List<PageRange> pages) { - IoUtils.closeQuietly(fd); - super.onPrintFinished(pages); - } - - @Override - public void onPrintFailed(CharSequence error) { - IoUtils.closeQuietly(fd); - super.onPrintFailed(error); - } - }); + callback.onWriteStarted(remoteSignal); + + mDocumentAdapter.onWrite(pages, fd, + CancellationSignal.fromTransport(remoteSignal), + new WriteResultCallbackWrapper(callback, fd)); } catch (RemoteException re) { Log.e(LOG_TAG, "Error printing", re); IoUtils.closeQuietly(fd); } } break; - case MESSAGE_FINIS: { - PrintAdapter adapter = (PrintAdapter) message.obj; - adapter.onFinish(); - synchronized (mLock) { - finishLocked(); - } + case MSG_FINISH: { + mDocumentAdapter.onFinish(); + doFinish(); } break; default: { @@ -367,29 +347,65 @@ public final class PrintManager { } } - private static abstract class PrintResultCallbackWrapper extends PrintResultCallback { + private static final class WriteResultCallbackWrapper extends WriteResultCallback { + + private final IWriteResultCallback mWrappedCallback; + private final FileDescriptor mFd; + + public WriteResultCallbackWrapper(IWriteResultCallback callback, + FileDescriptor fd) { + mWrappedCallback = callback; + mFd = fd; + } + + @Override + public void onWriteFinished(List<PageRange> pages) { + try { + // Close before notifying the other end. We want + // to be ready by the time we announce it. + IoUtils.closeQuietly(mFd); + mWrappedCallback.onWriteFinished(pages); + } catch (RemoteException re) { + Log.e(LOG_TAG, "Error calling onWriteFinished", re); + } + } + + @Override + public void onWriteFailed(CharSequence error) { + try { + // Close before notifying the other end. We want + // to be ready by the time we announce it. + IoUtils.closeQuietly(mFd); + mWrappedCallback.onWriteFailed(error); + } catch (RemoteException re) { + Log.e(LOG_TAG, "Error calling onWriteFailed", re); + } + } + } + + private static final class LayoutResultCallbackWrapper extends LayoutResultCallback { - private final IPrintResultCallback mWrappedCallback; + private final ILayoutResultCallback mWrappedCallback; - public PrintResultCallbackWrapper(IPrintResultCallback callback) { + public LayoutResultCallbackWrapper(ILayoutResultCallback callback) { mWrappedCallback = callback; } @Override - public void onPrintFinished(List<PageRange> pages) { + public void onLayoutFinished(PrintDocumentInfo info, boolean changed) { try { - mWrappedCallback.onPrintFinished(pages); + mWrappedCallback.onLayoutFinished(info, changed); } catch (RemoteException re) { - Log.e(LOG_TAG, "Error calling onPrintFinished", re); + Log.e(LOG_TAG, "Error calling onLayoutFinished", re); } } @Override - public void onPrintFailed(CharSequence error) { + public void onLayoutFailed(CharSequence error) { try { - mWrappedCallback.onPrintFailed(error); + mWrappedCallback.onLayoutFailed(error); } catch (RemoteException re) { - Log.e(LOG_TAG, "Error calling onPrintFailed", re); + Log.e(LOG_TAG, "Error calling onLayoutFailed", re); } } } diff --git a/core/java/android/print/PrinterId.java b/core/java/android/print/PrinterId.java index b853eb0..e884026 100644 --- a/core/java/android/print/PrinterId.java +++ b/core/java/android/print/PrinterId.java @@ -54,7 +54,7 @@ public final class PrinterId implements Parcelable { * * @hide */ - public ComponentName getServiceComponentName() { + public ComponentName getService() { return mServiceComponentName; } @@ -125,26 +125,6 @@ public final class PrinterId implements Parcelable { return builder.toString(); } - /** - * @hide - */ - public String flattenToString() { - return mServiceComponentName.flattenToString() + ":" + mLocalId; - } - - /** - * @hide - */ - public static PrinterId unflattenFromString(String string) { - String[] split = string.split(":"); - if (split.length != 2) { - throw new IllegalArgumentException("Not well-formed printer id:" + string); - } - ComponentName component = ComponentName.unflattenFromString(split[0]); - String localId = String.valueOf(split[1]); - return new PrinterId(component, localId); - } - public static final Parcelable.Creator<PrinterId> CREATOR = new Creator<PrinterId>() { @Override diff --git a/core/java/android/print/PrinterInfo.java b/core/java/android/print/PrinterInfo.java index 9283472..da3b6bc 100644 --- a/core/java/android/print/PrinterInfo.java +++ b/core/java/android/print/PrinterInfo.java @@ -86,6 +86,31 @@ public final class PrinterInfo implements Parcelable { mDefaults.put(PROPERTY_ORIENTATION, DEFAULT_UNDEFINED); } + private PrinterInfo(PrinterInfo prototype) { + mId = prototype.mId; + mLabel = prototype.mLabel; + mStatus = prototype.mStatus; + + mMinMargins = prototype.mMinMargins; + mMediaSizes.addAll(prototype.mMediaSizes); + mResolutions.addAll(prototype.mResolutions); + mInputTrays = (prototype.mInputTrays != null) + ? new ArrayList<Tray>(prototype.mInputTrays) : null; + mOutputTrays = (prototype.mOutputTrays != null) + ? new ArrayList<Tray>(prototype.mOutputTrays) : null; + + mDuplexModes = prototype.mDuplexModes; + mColorModes = prototype.mColorModes; + mFittingModes = prototype.mFittingModes; + mOrientations = prototype.mOrientations; + + final int defaultCount = prototype.mDefaults.size(); + for (int i = 0; i < defaultCount; i++) { + mDefaults.put(prototype.mDefaults.keyAt(i), prototype.mDefaults.valueAt(i)); + } + mDefaultMargins = prototype.mDefaultMargins; + } + /** * Get the globally unique printer id. * @@ -437,7 +462,7 @@ public final class PrinterInfo implements Parcelable { * </p> */ public static final class Builder { - private final PrinterInfo mPrinterInfo; + private final PrinterInfo mPrototype; /** * Creates a new instance. @@ -455,9 +480,9 @@ public final class PrinterInfo implements Parcelable { if (TextUtils.isEmpty(label)) { throw new IllegalArgumentException("label cannot be empty."); } - mPrinterInfo = new PrinterInfo(); - mPrinterInfo.mLabel = label; - mPrinterInfo.mId = printerId; + mPrototype = new PrinterInfo(); + mPrototype.mLabel = label; + mPrototype.mId = printerId; } /** @@ -470,7 +495,7 @@ public final class PrinterInfo implements Parcelable { * @return This builder. */ public Builder setStatus(int status) { - mPrinterInfo.mStatus = status; + mPrototype.mStatus = status; return this; } @@ -489,11 +514,11 @@ public final class PrinterInfo implements Parcelable { * @see PrintAttributes.MediaSize */ public Builder addMediaSize(MediaSize mediaSize, boolean isDefault) { - final int insertionIndex = mPrinterInfo.mMediaSizes.size(); - mPrinterInfo.mMediaSizes.add(mediaSize); + final int insertionIndex = mPrototype.mMediaSizes.size(); + mPrototype.mMediaSizes.add(mediaSize); if (isDefault) { throwIfDefaultAlreadySpecified(PROPERTY_MEDIA_SIZE); - mPrinterInfo.mDefaults.put(PROPERTY_MEDIA_SIZE, insertionIndex); + mPrototype.mDefaults.put(PROPERTY_MEDIA_SIZE, insertionIndex); } return this; } @@ -514,11 +539,11 @@ public final class PrinterInfo implements Parcelable { * @see PrintAttributes.Resolution */ public Builder addResolution(Resolution resolution, boolean isDefault) { - final int insertionIndex = mPrinterInfo.mResolutions.size(); - mPrinterInfo.mResolutions.add(resolution); + final int insertionIndex = mPrototype.mResolutions.size(); + mPrototype.mResolutions.add(resolution); if (isDefault) { throwIfDefaultAlreadySpecified(PROPERTY_RESOLUTION); - mPrinterInfo.mDefaults.put(PROPERTY_RESOLUTION, insertionIndex); + mPrototype.mDefaults.put(PROPERTY_RESOLUTION, insertionIndex); } return this; } @@ -543,8 +568,8 @@ public final class PrinterInfo implements Parcelable { throw new IllegalArgumentException("Default margins" + " cannot be outside of the min margins."); } - mPrinterInfo.mMinMargins = margins; - mPrinterInfo.mDefaultMargins = defaultMargins; + mPrototype.mMinMargins = margins; + mPrototype.mDefaultMargins = defaultMargins; return this; } @@ -564,14 +589,14 @@ public final class PrinterInfo implements Parcelable { * @see PrintAttributes.Tray */ public Builder addInputTray(Tray inputTray, boolean isDefault) { - if (mPrinterInfo.mInputTrays == null) { - mPrinterInfo.mInputTrays = new ArrayList<Tray>(); + if (mPrototype.mInputTrays == null) { + mPrototype.mInputTrays = new ArrayList<Tray>(); } - final int insertionIndex = mPrinterInfo.mInputTrays.size(); - mPrinterInfo.mInputTrays.add(inputTray); + final int insertionIndex = mPrototype.mInputTrays.size(); + mPrototype.mInputTrays.add(inputTray); if (isDefault) { throwIfDefaultAlreadySpecified(PROPERTY_INPUT_TRAY); - mPrinterInfo.mDefaults.put(PROPERTY_INPUT_TRAY, insertionIndex); + mPrototype.mDefaults.put(PROPERTY_INPUT_TRAY, insertionIndex); } return this; } @@ -592,14 +617,14 @@ public final class PrinterInfo implements Parcelable { * @see PrintAttributes.Tray */ public Builder addOutputTray(Tray outputTray, boolean isDefault) { - if (mPrinterInfo.mOutputTrays == null) { - mPrinterInfo.mOutputTrays = new ArrayList<Tray>(); + if (mPrototype.mOutputTrays == null) { + mPrototype.mOutputTrays = new ArrayList<Tray>(); } - final int insertionIndex = mPrinterInfo.mOutputTrays.size(); - mPrinterInfo.mOutputTrays.add(outputTray); + final int insertionIndex = mPrototype.mOutputTrays.size(); + mPrototype.mOutputTrays.add(outputTray); if (isDefault) { throwIfDefaultAlreadySpecified(PROPERTY_OUTPUT_TRAY); - mPrinterInfo.mDefaults.put(PROPERTY_OUTPUT_TRAY, insertionIndex); + mPrototype.mDefaults.put(PROPERTY_OUTPUT_TRAY, insertionIndex); } return this; } @@ -631,8 +656,8 @@ public final class PrinterInfo implements Parcelable { throw new IllegalArgumentException("Default color mode not in color modes."); } PrintAttributes.enforceValidColorMode(colorModes); - mPrinterInfo.mColorModes = colorModes; - mPrinterInfo.mDefaults.put(PROPERTY_COLOR_MODE, defaultColorMode); + mPrototype.mColorModes = colorModes; + mPrototype.mDefaults.put(PROPERTY_COLOR_MODE, defaultColorMode); return this; } @@ -664,8 +689,8 @@ public final class PrinterInfo implements Parcelable { throw new IllegalArgumentException("Default duplex mode not in duplex modes."); } PrintAttributes.enforceValidDuplexMode(defaultDuplexMode); - mPrinterInfo.mDuplexModes = duplexModes; - mPrinterInfo.mDefaults.put(PROPERTY_DUPLEX_MODE, defaultDuplexMode); + mPrototype.mDuplexModes = duplexModes; + mPrototype.mDefaults.put(PROPERTY_DUPLEX_MODE, defaultDuplexMode); return this; } @@ -696,8 +721,8 @@ public final class PrinterInfo implements Parcelable { throw new IllegalArgumentException("Default fitting mode not in fiting modes."); } PrintAttributes.enfoceValidFittingMode(defaultFittingMode); - mPrinterInfo.mFittingModes = fittingModes; - mPrinterInfo.mDefaults.put(PROPERTY_FITTING_MODE, defaultFittingMode); + mPrototype.mFittingModes = fittingModes; + mPrototype.mDefaults.put(PROPERTY_FITTING_MODE, defaultFittingMode); return this; } @@ -728,8 +753,8 @@ public final class PrinterInfo implements Parcelable { throw new IllegalArgumentException("Default orientation not in orientations."); } PrintAttributes.enforceValidOrientation(defaultOrientation); - mPrinterInfo.mOrientations = orientations; - mPrinterInfo.mDefaults.put(PROPERTY_ORIENTATION, defaultOrientation); + mPrototype.mOrientations = orientations; + mPrototype.mDefaults.put(PROPERTY_ORIENTATION, defaultOrientation); return this; } @@ -743,41 +768,41 @@ public final class PrinterInfo implements Parcelable { * @throws IllegalStateException If a required attribute was not specified. */ public PrinterInfo create() { - if (mPrinterInfo.mMediaSizes == null || mPrinterInfo.mMediaSizes.isEmpty()) { + if (mPrototype.mMediaSizes == null || mPrototype.mMediaSizes.isEmpty()) { throw new IllegalStateException("No media size specified."); } - if (mPrinterInfo.mDefaults.valueAt(PROPERTY_MEDIA_SIZE) == DEFAULT_UNDEFINED) { + if (mPrototype.mDefaults.valueAt(PROPERTY_MEDIA_SIZE) == DEFAULT_UNDEFINED) { throw new IllegalStateException("No default media size specified."); } - if (mPrinterInfo.mResolutions == null || mPrinterInfo.mResolutions.isEmpty()) { + if (mPrototype.mResolutions == null || mPrototype.mResolutions.isEmpty()) { throw new IllegalStateException("No resolution specified."); } - if (mPrinterInfo.mDefaults.valueAt(PROPERTY_RESOLUTION) == DEFAULT_UNDEFINED) { + if (mPrototype.mDefaults.valueAt(PROPERTY_RESOLUTION) == DEFAULT_UNDEFINED) { throw new IllegalStateException("No default resolution specified."); } - if (mPrinterInfo.mColorModes == 0) { + if (mPrototype.mColorModes == 0) { throw new IllegalStateException("No color mode specified."); } - if (mPrinterInfo.mDefaults.valueAt(PROPERTY_COLOR_MODE) == DEFAULT_UNDEFINED) { + if (mPrototype.mDefaults.valueAt(PROPERTY_COLOR_MODE) == DEFAULT_UNDEFINED) { throw new IllegalStateException("No default color mode specified."); } - if (mPrinterInfo.mOrientations == 0) { + if (mPrototype.mOrientations == 0) { throw new IllegalStateException("No oprientation specified."); } - if (mPrinterInfo.mDefaults.valueAt(PROPERTY_ORIENTATION) == DEFAULT_UNDEFINED) { + if (mPrototype.mDefaults.valueAt(PROPERTY_ORIENTATION) == DEFAULT_UNDEFINED) { throw new IllegalStateException("No default orientation specified."); } - if (mPrinterInfo.mMinMargins == null) { - mPrinterInfo.mMinMargins = new Margins(0, 0, 0, 0); + if (mPrototype.mMinMargins == null) { + mPrototype.mMinMargins = new Margins(0, 0, 0, 0); } - if (mPrinterInfo.mDefaultMargins == null) { - mPrinterInfo.mDefaultMargins = mPrinterInfo.mMinMargins; + if (mPrototype.mDefaultMargins == null) { + mPrototype.mDefaultMargins = mPrototype.mMinMargins; } - return mPrinterInfo; + return new PrinterInfo(mPrototype); } private void throwIfDefaultAlreadySpecified(int propertyIndex) { - if (mPrinterInfo.mDefaults.get(propertyIndex) != DEFAULT_UNDEFINED) { + if (mPrototype.mDefaults.get(propertyIndex) != DEFAULT_UNDEFINED) { throw new IllegalArgumentException("Default already specified."); } } diff --git a/core/java/android/print/pdf/PdfDocument.java b/core/java/android/print/pdf/PdfDocument.java index 7ce036d..cfeb975 100644 --- a/core/java/android/print/pdf/PdfDocument.java +++ b/core/java/android/print/pdf/PdfDocument.java @@ -56,7 +56,7 @@ import java.util.List; * // finish the page * document.finishPage(page); * . . . - * add more pages + * // add more pages * . . . * // write the document content * document.writeTo(getOutputStream()); diff --git a/core/java/android/printservice/IPrintService.aidl b/core/java/android/printservice/IPrintService.aidl index eabd96d..c72385a 100644 --- a/core/java/android/printservice/IPrintService.aidl +++ b/core/java/android/printservice/IPrintService.aidl @@ -17,6 +17,7 @@ package android.printservice; import android.os.ICancellationSignal; +import android.print.IPrinterDiscoveryObserver; import android.print.PrintJobInfo; import android.print.PrinterId; import android.printservice.IPrintServiceClient; @@ -28,8 +29,8 @@ import android.printservice.IPrintServiceClient; */ oneway interface IPrintService { void setClient(IPrintServiceClient client); - void requestCancelPrintJob(in PrintJobInfo printJob); - void onPrintJobQueued(in PrintJobInfo printJob); - void startPrinterDiscovery(); + void requestCancelPrintJob(in PrintJobInfo printJobInfo); + void onPrintJobQueued(in PrintJobInfo printJobInfo); + void startPrinterDiscovery(IPrinterDiscoveryObserver observer); void stopPrinterDiscovery(); } diff --git a/core/java/android/printservice/IPrintServiceClient.aidl b/core/java/android/printservice/IPrintServiceClient.aidl index cff8c02..cdde4d8 100644 --- a/core/java/android/printservice/IPrintServiceClient.aidl +++ b/core/java/android/printservice/IPrintServiceClient.aidl @@ -27,11 +27,9 @@ import android.print.PrinterInfo; * @hide */ interface IPrintServiceClient { - List<PrintJobInfo> getPrintJobs(); - PrintJobInfo getPrintJob(int printJobId); + List<PrintJobInfo> getPrintJobInfos(); + PrintJobInfo getPrintJobInfo(int printJobId); boolean setPrintJobState(int printJobId, int status); boolean setPrintJobTag(int printJobId, String tag); oneway void writePrintJobData(in ParcelFileDescriptor fd, int printJobId); - oneway void addDiscoveredPrinters(in List<PrinterInfo> printers); - oneway void removeDiscoveredPrinters(in List<PrinterId> printers); } diff --git a/core/java/android/printservice/PrintDocument.java b/core/java/android/printservice/PrintDocument.java new file mode 100644 index 0000000..2a1581a --- /dev/null +++ b/core/java/android/printservice/PrintDocument.java @@ -0,0 +1,91 @@ +/* + * 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.printservice; + +import android.os.ParcelFileDescriptor; +import android.os.RemoteException; +import android.print.PrintDocumentInfo; +import android.util.Log; + +import java.io.FileDescriptor; +import java.io.IOException; + +/** + * This class represents a printed document from the perspective of a print + * service. It exposes APIs to query the document and obtain its data. + */ +public final class PrintDocument { + + private static final String LOG_TAG = "PrintDocument"; + + private final int mPrintJobId; + + private final IPrintServiceClient mPrintServiceClient; + + private final PrintDocumentInfo mInfo; + + PrintDocument(int printJobId, IPrintServiceClient printServiceClient, + PrintDocumentInfo info) { + mPrintJobId = printJobId; + mPrintServiceClient = printServiceClient; + mInfo = info; + } + + /** + * Gets the {@link PrintDocumentInfo} that describes this document. + * + * @return The document info. + */ + public PrintDocumentInfo getInfo() { + return mInfo; + } + + /** + * Gets the data associated with this document. It is a responsibility of the + * client to open a stream to the returned file descriptor and fully read the + * data. + * <p> + * <strong>Note:</strong> It is your responsibility to close the file descriptor. + * </p> + * + * @return A file descriptor for reading the data or <code>null</code>. + */ + public FileDescriptor getData() { + ParcelFileDescriptor source = null; + ParcelFileDescriptor sink = null; + try { + ParcelFileDescriptor[] fds = ParcelFileDescriptor.createPipe(); + source = fds[0]; + sink = fds[1]; + mPrintServiceClient.writePrintJobData(sink, mPrintJobId); + return source.getFileDescriptor(); + } catch (IOException ioe) { + Log.e(LOG_TAG, "Error calling getting print job data!", ioe); + } catch (RemoteException re) { + Log.e(LOG_TAG, "Error calling getting print job data!", re); + } finally { + if (sink != null) { + try { + sink.close(); + } catch (IOException ioe) { + /* ignore */ + } + } + } + return null; + } +} diff --git a/core/java/android/printservice/PrintJob.java b/core/java/android/printservice/PrintJob.java index f490f91..80530a7 100644 --- a/core/java/android/printservice/PrintJob.java +++ b/core/java/android/printservice/PrintJob.java @@ -16,10 +16,6 @@ package android.printservice; -import java.io.FileDescriptor; -import java.io.IOException; - -import android.os.ParcelFileDescriptor; import android.os.RemoteException; import android.print.PrintJobInfo; import android.util.Log; @@ -33,19 +29,16 @@ public final class PrintJob { private static final String LOG_TAG = "PrintJob"; - private final int mId; - private final IPrintServiceClient mPrintServiceClient; + private final PrintDocument mDocument; + private PrintJobInfo mCachedInfo; - PrintJob(PrintJobInfo info, IPrintServiceClient client) { - if (client == null) { - throw new IllegalStateException("Print serivice not connected!"); - } - mCachedInfo = info; - mId = info.getId(); + PrintJob(PrintJobInfo jobInfo, IPrintServiceClient client) { + mCachedInfo = jobInfo; mPrintServiceClient = client; + mDocument = new PrintDocument(mCachedInfo.getId(), client, jobInfo.getDocumentInfo()); } /** @@ -54,7 +47,7 @@ public final class PrintJob { * @return The id. */ public int getId() { - return mId; + return mCachedInfo.getId(); } /** @@ -70,9 +63,9 @@ public final class PrintJob { public PrintJobInfo getInfo() { PrintJobInfo info = null; try { - info = mPrintServiceClient.getPrintJob(mId); + info = mPrintServiceClient.getPrintJobInfo(mCachedInfo.getId()); } catch (RemoteException re) { - Log.e(LOG_TAG, "Couldn't get info for job: " + mId, re); + Log.e(LOG_TAG, "Couldn't get info for job: " + mCachedInfo.getId(), re); } if (info != null) { mCachedInfo = info; @@ -81,6 +74,15 @@ public final class PrintJob { } /** + * Gets the document of this print job. + * + * @return The document. + */ + public PrintDocument getDocument() { + return mDocument; + } + + /** * Gets whether this print job is queued. Such a print job is * ready to be printed and can be started. * @@ -103,7 +105,7 @@ public final class PrintJob { * @see #fail(CharSequence) */ public boolean isStarted() { - return getInfo().getState() == PrintJobInfo.STATE_STARTED; + return getInfo().getState() == PrintJobInfo.STATE_STARTED; } /** @@ -181,48 +183,13 @@ public final class PrintJob { */ public boolean setTag(String tag) { try { - return mPrintServiceClient.setPrintJobTag(mId, tag); + return mPrintServiceClient.setPrintJobTag(mCachedInfo.getId(), tag); } catch (RemoteException re) { - Log.e(LOG_TAG, "Error setting tag for job:" + mId, re); + Log.e(LOG_TAG, "Error setting tag for job: " + mCachedInfo.getId(), re); } return false; } - /** - * Gets the data associated with this print job. It is a responsibility of - * the print service to open a stream to the returned file descriptor - * and fully read the content. - * <p> - * <strong>Note:</strong> It is your responsibility to close the file descriptor. - * </p> - * - * @return A file descriptor for reading the data or <code>null</code>. - */ - public final FileDescriptor getData() { - ParcelFileDescriptor source = null; - ParcelFileDescriptor sink = null; - try { - ParcelFileDescriptor[] fds = ParcelFileDescriptor.createPipe(); - source = fds[0]; - sink = fds[1]; - mPrintServiceClient.writePrintJobData(sink, mId); - return source.getFileDescriptor(); - } catch (IOException ioe) { - Log.e(LOG_TAG, "Error calling getting print job data!", ioe); - } catch (RemoteException re) { - Log.e(LOG_TAG, "Error calling getting print job data!", re); - } finally { - if (sink != null) { - try { - sink.close(); - } catch (IOException ioe) { - /* ignore */ - } - } - } - return null; - } - @Override public boolean equals(Object obj) { if (this == obj) { @@ -235,23 +202,25 @@ public final class PrintJob { return false; } PrintJob other = (PrintJob) obj; - return (mId == other.mId); + return (mCachedInfo.getId() == other.mCachedInfo.getId()); } @Override public int hashCode() { - return mId; + return mCachedInfo.getId(); } private boolean setState(int state) { - // Best effort - update the state of the cached info since - // we may not be able to re-fetch it later if the job gets - // removed from the spooler. - mCachedInfo.setState(state); try { - return mPrintServiceClient.setPrintJobState(mId, state); + if (mPrintServiceClient.setPrintJobState(mCachedInfo.getId(), state)) { + // Best effort - update the state of the cached info since + // we may not be able to re-fetch it later if the job gets + // removed from the spooler as a result of the state change. + mCachedInfo.setState(state); + return true; + } } catch (RemoteException re) { - Log.e(LOG_TAG, "Error setting the state of job:" + mId, re); + Log.e(LOG_TAG, "Error setting the state of job: " + mCachedInfo.getId(), re); } return false; } diff --git a/core/java/android/printservice/PrintService.java b/core/java/android/printservice/PrintService.java index 9256966..dde31d2 100644 --- a/core/java/android/printservice/PrintService.java +++ b/core/java/android/printservice/PrintService.java @@ -25,6 +25,7 @@ import android.os.IBinder; import android.os.Looper; import android.os.Message; import android.os.RemoteException; +import android.print.IPrinterDiscoveryObserver; import android.print.PrintJobInfo; import android.print.PrinterId; import android.print.PrinterInfo; @@ -47,7 +48,7 @@ import java.util.List; * {@link #onStartPrinterDiscovery()} and ends with a call to * {@link #onStopPrinterDiscovery()}. During a printer discovery * period the print service reports newly discovered printers by - * calling {@link #addDiscoveredPrinters(List)} and added printers + * calling {@link #addDiscoveredPrinters(List)} and reports added printers * that disappeared by calling {@link #removeDiscoveredPrinters(List)}. * Calls to {@link #addDiscoveredPrinters(List)} and * {@link #removeDiscoveredPrinters(List)} before a call to @@ -67,26 +68,30 @@ import java.util.List; * a call to {@link #onPrintJobQueued(PrintJob)} is made and the print * service may handle it immediately or schedule that for an appropriate * time in the future. The list of all print jobs for this service - * are be available by calling {@link #getPrintJobs()}. A queued print - * job is one whose {@link PrintJob#isQueued()} return true. + * are be available by calling {@link #getPrintJobs()}. * </p> * <p> * A print service is responsible for setting the print job state as * appropriate while processing it. Initially, a print job is in a * {@link PrintJobInfo#STATE_QUEUED} state which means that the data to * be printed is spooled by the system and the print service can obtain - * that data by calling {@link PrintJob#getData()}. After the print - * service starts printing the data it should set the print job state - * to {@link PrintJobInfo#STATE_STARTED}. Upon successful completion, the - * print job state has to be set to {@link PrintJobInfo#STATE_COMPLETED}. - * In a case of a failure, the print job state should be set to - * {@link PrintJobInfo#STATE_FAILED}. If a print job is in a - * {@link PrintJobInfo#STATE_STARTED} state and the user requests to - * cancel it, the print service will receive a call to - * {@link #onRequestCancelPrintJob(PrintJob)} which requests from the - * service to do a best effort in canceling the job. In case the job - * is successfully canceled, its state has to be set to - * {@link PrintJobInfo#STATE_CANCELED}. + * that data by calling {@link PrintJob#getDocument()}. A queued print + * job's {@link PrintJob#isQueued()} method returns true. + * </p> + * <p> + * After the print service starts printing the data it should set the + * print job state to {@link PrintJobInfo#STATE_STARTED} by calling + * {@link PrintJob#start()}. Upon successful completion, the print job + * state has to be set to {@link PrintJobInfo#STATE_COMPLETED} by calling + * {@link PrintJob#complete()}. In case of a failure, the print job + * state should be set to {@link PrintJobInfo#STATE_FAILED} by calling + * {@link PrintJob#fail(CharSequence)}. If a print job is in a + * {@link PrintJobInfo#STATE_STARTED} state, i.e. {@link PrintJob#isStarted()} + * return true, and the user requests to cancel it, the print service will + * receive a call to {@link #onRequestCancelPrintJob(PrintJob)} which + * requests from the service to do a best effort in canceling the job. In + * case the job is successfully canceled, its state has to be set to + * {@link PrintJobInfo#STATE_CANCELED}. by calling {@link PrintJob#cancel()}. * </p> * <h3>Lifecycle</h3> * <p> @@ -124,9 +129,9 @@ import java.util.List; * <p> * A print service can be configured by specifying an optional settings * activity which exposes service specific options, an optional add - * prints activity which is used for manual addition of printers, etc. - * It is a responsibility of the system to launch the settings and add - * printers activities when appropriate. + * prints activity which is used for manual addition of printers, vendor + * name ,etc. It is a responsibility of the system to launch the settings + * and add printers activities when appropriate. * </p> * <p> * A print service is configured by providing a @@ -148,7 +153,7 @@ import java.util.List; */ public abstract class PrintService extends Service { - private static final String LOG_TAG = PrintService.class.getSimpleName(); + private static final String LOG_TAG = "PrintService"; /** * The {@link Intent} action that must be declared as handled by a service @@ -162,6 +167,7 @@ public abstract class PrintService extends Service { * <code><{@link android.R.styleable#PrintService print-service}></code> * tag. This is a a sample XML file configuring a print service: * <pre> <print-service + * android:vendor="SomeVendor" * android:settingsActivity="foo.bar.MySettingsActivity" * andorid:addPrintersActivity="foo.bar.MyAddPrintersActivity." * . . . @@ -175,7 +181,7 @@ public abstract class PrintService extends Service { private IPrintServiceClient mClient; - private boolean mDiscoveringPrinters; + private IPrinterDiscoveryObserver mDiscoveryObserver; @Override protected void attachBaseContext(Context base) { @@ -230,29 +236,26 @@ public abstract class PrintService extends Service { * printers have to be added. You can call this method as many times as * necessary during the discovery period but should not pass in already * added printers. If a printer is already added in the same printer - * discovery period, it will be ignored. + * discovery period, it will be ignored. If you want to update an already + * added printer, you should removed it and then re-add it. * </p> * * @param printers A list with discovered printers. * - * @throws IllegalStateException If this service is not connected. - * * @see #removeDiscoveredPrinters(List) * @see #onStartPrinterDiscovery() * @see #onStopPrinterDiscovery() */ public final void addDiscoveredPrinters(List<PrinterInfo> printers) { + final IPrinterDiscoveryObserver observer; synchronized (mLock) { - if (mClient == null) { - throw new IllegalStateException("Print serivice not connected!"); - } - if (mDiscoveringPrinters) { - try { - // Calling with a lock into the system is fine. - mClient.addDiscoveredPrinters(printers); - } catch (RemoteException re) { - Log.e(LOG_TAG, "Error adding discovered printers!", re); - } + observer = mDiscoveryObserver; + } + if (observer != null) { + try { + observer.addDiscoveredPrinters(printers); + } catch (RemoteException re) { + Log.e(LOG_TAG, "Error adding discovered printers", re); } } } @@ -269,37 +272,35 @@ public abstract class PrintService extends Service { * this method as many times as necessary during the discovery period * but should not pass in already removed printer ids. If a printer with * a given id is already removed in the same discovery period, it will - * be ignored. + * be ignored. If you want to update an already added printer, you should + * removed it and then re-add it. * </p> * * @param printerIds A list with disappeared printer ids. * - * @throws IllegalStateException If this service is not connected. - * * @see #addDiscoveredPrinters(List) * @see #onStartPrinterDiscovery() * @see #onStopPrinterDiscovery() */ public final void removeDiscoveredPrinters(List<PrinterId> printerIds) { + final IPrinterDiscoveryObserver observer; synchronized (mLock) { - if (mClient == null) { - throw new IllegalStateException("Print serivice not connected!"); - } - if (mDiscoveringPrinters) { - try { - // Calling with a lock into the system is fine. - mClient.removeDiscoveredPrinters(printerIds); - } catch (RemoteException re) { - Log.e(LOG_TAG, "Error removing discovered printers!", re); - } + observer = mDiscoveryObserver; + } + if (observer != null) { + try { + observer.removeDiscoveredPrinters(printerIds); + } catch (RemoteException re) { + Log.e(LOG_TAG, "Error removing discovered printers", re); } } } /** * Called when canceling of a print job is requested. The service - * should do best effort to fulfill the request. After the print - * job is canceled by calling {@link PrintJob#cancel()}. + * should do best effort to fulfill the request. After the cancellation + * is performed, the print job should be set to a cancelled state by + * calling {@link PrintJob#cancel()}. * * @param printJob The print job to be canceled. */ @@ -310,11 +311,12 @@ public abstract class PrintService extends Service { * Called when there is a queued print job for one of the printers * managed by this print service. A queued print job is ready for * processing by a print service which can get the data to be printed - * by calling {@link PrintJob#getData()}. This service may start + * by calling {@link PrintJob#getDocument()}. This service may start * processing the passed in print job or schedule handling of queued * print jobs at a convenient time. The service can get the print * jobs by a call to {@link #getPrintJobs()} and examine their state - * to find the ones with state {@link PrintJobInfo#STATE_QUEUED}. + * to find the ones with state {@link PrintJobInfo#STATE_QUEUED} by + * calling {@link PrintJob#isQueued()}. * * @param printJob The new queued print job. * @@ -326,32 +328,32 @@ public abstract class PrintService extends Service { * Gets the print jobs for the printers managed by this service. * * @return The print jobs. - * - * @throws IllegalStateException If this service is not connected. */ public final List<PrintJob> getPrintJobs() { + final IPrintServiceClient client; synchronized (mLock) { - if (mClient == null) { - throw new IllegalStateException("Print serivice not connected!"); - } - try { - List<PrintJob> printJobs = null; - List<PrintJobInfo> printJobInfos = mClient.getPrintJobs(); - if (printJobInfos != null) { - final int printJobInfoCount = printJobInfos.size(); - printJobs = new ArrayList<PrintJob>(printJobInfoCount); - for (int i = 0; i < printJobInfoCount; i++) { - printJobs.add(new PrintJob(printJobInfos.get(i), mClient)); - } - } - if (printJobs != null) { - return printJobs; + client = mClient; + } + if (client == null) { + return Collections.emptyList(); + } + try { + List<PrintJob> printJobs = null; + List<PrintJobInfo> printJobInfos = client.getPrintJobInfos(); + if (printJobInfos != null) { + final int printJobInfoCount = printJobInfos.size(); + printJobs = new ArrayList<PrintJob>(printJobInfoCount); + for (int i = 0; i < printJobInfoCount; i++) { + printJobs.add(new PrintJob(printJobInfos.get(i), client)); } - } catch (RemoteException re) { - Log.e(LOG_TAG, "Error calling getPrintJobs()", re); } - return Collections.emptyList(); + if (printJobs != null) { + return printJobs; + } + } catch (RemoteException re) { + Log.e(LOG_TAG, "Error calling getPrintJobs()", re); } + return Collections.emptyList(); } /** @@ -375,8 +377,9 @@ public abstract class PrintService extends Service { } @Override - public void startPrinterDiscovery() { - mHandler.sendEmptyMessage(MyHandler.MESSAGE_START_PRINTER_DISCOVERY); + public void startPrinterDiscovery(IPrinterDiscoveryObserver observer) { + mHandler.obtainMessage(MyHandler.MESSAGE_START_PRINTER_DISCOVERY, + observer).sendToTarget(); } @Override @@ -385,14 +388,15 @@ public abstract class PrintService extends Service { } @Override - public void requestCancelPrintJob(PrintJobInfo printJob) { - mHandler.obtainMessage(MyHandler.MESSAGE_CANCEL_PRINTJOB, printJob).sendToTarget(); + public void requestCancelPrintJob(PrintJobInfo printJobInfo) { + mHandler.obtainMessage(MyHandler.MESSAGE_CANCEL_PRINTJOB, + printJobInfo).sendToTarget(); } @Override - public void onPrintJobQueued(PrintJobInfo printJob) { + public void onPrintJobQueued(PrintJobInfo printJobInfo) { mHandler.obtainMessage(MyHandler.MESSAGE_ON_PRINTJOB_QUEUED, - printJob).sendToTarget(); + printJobInfo).sendToTarget(); } }; } @@ -414,26 +418,26 @@ public abstract class PrintService extends Service { switch (action) { case MESSAGE_START_PRINTER_DISCOVERY: { synchronized (mLock) { - mDiscoveringPrinters = true; + mDiscoveryObserver = (IPrinterDiscoveryObserver) message.obj; } onStartPrinterDiscovery(); } break; case MESSAGE_STOP_PRINTER_DISCOVERY: { synchronized (mLock) { - mDiscoveringPrinters = false; + mDiscoveryObserver = null; } onStopPrinterDiscovery(); } break; case MESSAGE_CANCEL_PRINTJOB: { - PrintJobInfo printJob = (PrintJobInfo) message.obj; - onRequestCancelPrintJob(new PrintJob(printJob, mClient)); + PrintJobInfo printJobInfo = (PrintJobInfo) message.obj; + onRequestCancelPrintJob(new PrintJob(printJobInfo, mClient)); } break; case MESSAGE_ON_PRINTJOB_QUEUED: { - PrintJobInfo printJob = (PrintJobInfo) message.obj; - onPrintJobQueued(new PrintJob(printJob, mClient)); + PrintJobInfo printJobInfo = (PrintJobInfo) message.obj; + onPrintJobQueued(new PrintJob(printJobInfo, mClient)); } break; case MESSAGE_SET_CLEINT: { @@ -441,13 +445,12 @@ public abstract class PrintService extends Service { synchronized (mLock) { mClient = client; if (client == null) { - mDiscoveringPrinters = false; + mDiscoveryObserver = null; } } if (client != null) { onConnected(); } else { - onStopPrinterDiscovery(); onDisconnected(); } } break; diff --git a/core/java/android/printservice/PrintServiceInfo.java b/core/java/android/printservice/PrintServiceInfo.java index 0370a25..43dd1b6 100644 --- a/core/java/android/printservice/PrintServiceInfo.java +++ b/core/java/android/printservice/PrintServiceInfo.java @@ -48,8 +48,6 @@ import java.io.IOException; */ public final class PrintServiceInfo implements Parcelable { - private static final boolean DEBUG = false; - private static final String LOG_TAG = PrintServiceInfo.class.getSimpleName(); private static final String TAG_PRINT_SERVICE = "print-service"; @@ -97,7 +95,6 @@ public final class PrintServiceInfo implements Parcelable { * @param context Context for accessing resources. * @throws XmlPullParserException If a XML parsing error occurs. * @throws IOException If a I/O error occurs. - * @hide */ public static PrintServiceInfo create(ResolveInfo resolveInfo, Context context) { String settingsActivityName = null; @@ -117,7 +114,7 @@ public final class PrintServiceInfo implements Parcelable { String nodeName = parser.getName(); if (!TAG_PRINT_SERVICE.equals(nodeName)) { throw new XmlPullParserException( - "Meta-data does not start with" + TAG_PRINT_SERVICE + " tag"); + "Meta-data does not start with " + TAG_PRINT_SERVICE + " tag"); } Resources resources = packageManager.getResourcesForApplication( @@ -213,7 +210,7 @@ public final class PrintServiceInfo implements Parcelable { @Override public int hashCode() { - return 31 * 1 + ((mId == null) ? 0 : mId.hashCode()); + return 31 + ((mId == null) ? 0 : mId.hashCode()); } @Override @@ -244,12 +241,8 @@ public final class PrintServiceInfo implements Parcelable { builder.append("PrintServiceInfo{"); builder.append("id:").append(mId).append(", "); builder.append("resolveInfo:").append(mResolveInfo).append(", "); - if (DEBUG) { - builder.append("settingsActivityName:").append(mSettingsActivityName); - builder.append("addPrintersActivityName:").append(mAddPrintersActivityName); - } else if (mSettingsActivityName != null || mAddPrintersActivityName != null) { - builder.append("<has meta-data>"); - } + builder.append("settingsActivityName:").append(mSettingsActivityName); + builder.append("addPrintersActivityName:").append(mAddPrintersActivityName); builder.append("}"); return builder.toString(); } diff --git a/core/java/android/provider/CalendarContract.java b/core/java/android/provider/CalendarContract.java index 25af209..d743484 100644 --- a/core/java/android/provider/CalendarContract.java +++ b/core/java/android/provider/CalendarContract.java @@ -2393,7 +2393,7 @@ public final class CalendarContract { intent.setData(ContentUris.withAppendedId(CalendarContract.CONTENT_URI, alarmTime)); intent.putExtra(ALARM_TIME, alarmTime); PendingIntent pi = PendingIntent.getBroadcast(context, 0, intent, 0); - manager.set(AlarmManager.RTC_WAKEUP, alarmTime, pi); + manager.setExact(AlarmManager.RTC_WAKEUP, alarmTime, pi); } /** diff --git a/core/java/android/util/ArrayMap.java b/core/java/android/util/ArrayMap.java index 18534c6..22f62d7 100644 --- a/core/java/android/util/ArrayMap.java +++ b/core/java/android/util/ArrayMap.java @@ -44,8 +44,6 @@ import java.util.Set; * you have no control over this shrinking -- if you set a capacity and then remove an * item, it may reduce the capacity to better match the current size. In the future an * explicit call to set the capacity should turn off this aggressive shrinking behavior.</p> - * - * @hide */ public final class ArrayMap<K, V> implements Map<K, V> { private static final boolean DEBUG = false; @@ -63,6 +61,11 @@ public final class ArrayMap<K, V> implements Map<K, V> { private static final int CACHE_SIZE = 10; /** + * @hide Special immutable empty ArrayMap. + */ + public static final ArrayMap EMPTY = new ArrayMap(true); + + /** * Caches of small array objects to avoid spamming garbage. The cache * Object[] variable is a pointer to a linked list of array objects. * The first entry in the array is a pointer to the next array in the @@ -73,6 +76,11 @@ public final class ArrayMap<K, V> implements Map<K, V> { static Object[] mTwiceBaseCache; static int mTwiceBaseCacheSize; + /** + * Special hash array value that indicates the container is immutable. + */ + static final int[] EMPTY_IMMUTABLE_INTS = new int[0]; + int[] mHashes; Object[] mArray; int mSize; @@ -86,7 +94,7 @@ public final class ArrayMap<K, V> implements Map<K, V> { return ~0; } - int index = SparseArray.binarySearch(mHashes, N, hash); + int index = ContainerHelpers.binarySearch(mHashes, N, hash); // If the hash code wasn't found, then we have no entry for this key. if (index < 0) { @@ -117,6 +125,9 @@ public final class ArrayMap<K, V> implements Map<K, V> { } private void allocArrays(final int size) { + if (mHashes == EMPTY_IMMUTABLE_INTS) { + throw new UnsupportedOperationException("ArrayMap is immutable"); + } if (size == (BASE_SIZE*2)) { synchronized (ArrayMap.class) { if (mTwiceBaseCache != null) { @@ -188,8 +199,8 @@ public final class ArrayMap<K, V> implements Map<K, V> { * will grow once items are added to it. */ public ArrayMap() { - mHashes = SparseArray.EMPTY_INTS; - mArray = SparseArray.EMPTY_OBJECTS; + mHashes = ContainerHelpers.EMPTY_INTS; + mArray = ContainerHelpers.EMPTY_OBJECTS; mSize = 0; } @@ -198,14 +209,20 @@ public final class ArrayMap<K, V> implements Map<K, V> { */ public ArrayMap(int capacity) { if (capacity == 0) { - mHashes = SparseArray.EMPTY_INTS; - mArray = SparseArray.EMPTY_OBJECTS; + mHashes = ContainerHelpers.EMPTY_INTS; + mArray = ContainerHelpers.EMPTY_OBJECTS; } else { allocArrays(capacity); } mSize = 0; } + private ArrayMap(boolean immutable) { + mHashes = EMPTY_IMMUTABLE_INTS; + mArray = ContainerHelpers.EMPTY_OBJECTS; + mSize = 0; + } + /** * Create a new ArrayMap with the mappings from the given ArrayMap. */ @@ -221,15 +238,29 @@ public final class ArrayMap<K, V> implements Map<K, V> { */ @Override public void clear() { - if (mSize != 0) { + if (mSize > 0) { freeArrays(mHashes, mArray, mSize); - mHashes = SparseArray.EMPTY_INTS; - mArray = SparseArray.EMPTY_OBJECTS; + mHashes = ContainerHelpers.EMPTY_INTS; + mArray = ContainerHelpers.EMPTY_OBJECTS; mSize = 0; } } /** + * @hide + * Like {@link #clear}, but doesn't reduce the capacity of the ArrayMap. + */ + public void erase() { + if (mSize > 0) { + final int N = mSize<<1; + final Object[] array = mArray; + for (int i=0; i<N; i++) { + array[i] = null; + } + } + } + + /** * Ensure the array map can hold at least <var>minimumCapacity</var> * items. */ @@ -393,6 +424,33 @@ public final class ArrayMap<K, V> implements Map<K, V> { } /** + * Special fast path for appending items to the end of the array without validation. + * The array must already be large enough to contain the item. + * @hide + */ + public void append(K key, V value) { + int index = mSize; + final int hash = key.hashCode(); + if (index >= mHashes.length) { + throw new IllegalStateException("Array is full"); + } + if (index > 0 && mHashes[index-1] > hash) { + RuntimeException e = new RuntimeException("here"); + e.fillInStackTrace(); + Log.w(TAG, "New hash " + hash + + " is before end of array hash " + mHashes[index-1] + + " at index " + index + " key " + key, e); + put(key, value); + return; + } + mSize = index+1; + mHashes[index] = hash; + index <<= 1; + mArray[index] = key; + mArray[index+1] = value; + } + + /** * Perform a {@link #put(Object, Object)} of all key/value pairs in <var>array</var> * @param array The array whose contents are to be retrieved. */ @@ -439,8 +497,8 @@ public final class ArrayMap<K, V> implements Map<K, V> { // Now empty. if (DEBUG) Log.d(TAG, "remove: shrink from " + mHashes.length + " to 0"); freeArrays(mHashes, mArray, mSize); - mHashes = SparseArray.EMPTY_INTS; - mArray = SparseArray.EMPTY_OBJECTS; + mHashes = ContainerHelpers.EMPTY_INTS; + mArray = ContainerHelpers.EMPTY_OBJECTS; mSize = 0; } else { if (mHashes.length > (BASE_SIZE*2) && mSize < mHashes.length/3) { diff --git a/core/java/android/util/ArraySet.java b/core/java/android/util/ArraySet.java index 4e1d32c..1648ec9 100644 --- a/core/java/android/util/ArraySet.java +++ b/core/java/android/util/ArraySet.java @@ -85,7 +85,7 @@ public final class ArraySet<E> implements Collection<E>, Set<E> { return ~0; } - int index = SparseArray.binarySearch(mHashes, N, hash); + int index = ContainerHelpers.binarySearch(mHashes, N, hash); // If the hash code wasn't found, then we have no entry for this key. if (index < 0) { @@ -187,8 +187,8 @@ public final class ArraySet<E> implements Collection<E>, Set<E> { * will grow once items are added to it. */ public ArraySet() { - mHashes = SparseArray.EMPTY_INTS; - mArray = SparseArray.EMPTY_OBJECTS; + mHashes = ContainerHelpers.EMPTY_INTS; + mArray = ContainerHelpers.EMPTY_OBJECTS; mSize = 0; } @@ -197,8 +197,8 @@ public final class ArraySet<E> implements Collection<E>, Set<E> { */ public ArraySet(int capacity) { if (capacity == 0) { - mHashes = SparseArray.EMPTY_INTS; - mArray = SparseArray.EMPTY_OBJECTS; + mHashes = ContainerHelpers.EMPTY_INTS; + mArray = ContainerHelpers.EMPTY_OBJECTS; } else { allocArrays(capacity); } @@ -223,8 +223,8 @@ public final class ArraySet<E> implements Collection<E>, Set<E> { public void clear() { if (mSize != 0) { freeArrays(mHashes, mArray, mSize); - mHashes = SparseArray.EMPTY_INTS; - mArray = SparseArray.EMPTY_OBJECTS; + mHashes = ContainerHelpers.EMPTY_INTS; + mArray = ContainerHelpers.EMPTY_OBJECTS; mSize = 0; } } @@ -371,8 +371,8 @@ public final class ArraySet<E> implements Collection<E>, Set<E> { // Now empty. if (DEBUG) Log.d(TAG, "remove: shrink from " + mHashes.length + " to 0"); freeArrays(mHashes, mArray, mSize); - mHashes = SparseArray.EMPTY_INTS; - mArray = SparseArray.EMPTY_OBJECTS; + mHashes = ContainerHelpers.EMPTY_INTS; + mArray = ContainerHelpers.EMPTY_OBJECTS; mSize = 0; } else { if (mHashes.length > (BASE_SIZE*2) && mSize < mHashes.length/3) { diff --git a/core/java/android/util/ContainerHelpers.java b/core/java/android/util/ContainerHelpers.java new file mode 100644 index 0000000..624c4bd --- /dev/null +++ b/core/java/android/util/ContainerHelpers.java @@ -0,0 +1,63 @@ +/* + * 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.util; + +class ContainerHelpers { + static final boolean[] EMPTY_BOOLEANS = new boolean[0]; + static final int[] EMPTY_INTS = new int[0]; + static final long[] EMPTY_LONGS = new long[0]; + static final Object[] EMPTY_OBJECTS = new Object[0]; + + // This is Arrays.binarySearch(), but doesn't do any argument validation. + static int binarySearch(int[] array, int size, int value) { + int lo = 0; + int hi = size - 1; + + while (lo <= hi) { + final int mid = (lo + hi) >>> 1; + final int midVal = array[mid]; + + if (midVal < value) { + lo = mid + 1; + } else if (midVal > value) { + hi = mid - 1; + } else { + return mid; // value found + } + } + return ~lo; // value not present + } + + static int binarySearch(long[] array, int size, long value) { + int lo = 0; + int hi = size - 1; + + while (lo <= hi) { + final int mid = (lo + hi) >>> 1; + final long midVal = array[mid]; + + if (midVal < value) { + lo = mid + 1; + } else if (midVal > value) { + hi = mid - 1; + } else { + return mid; // value found + } + } + return ~lo; // value not present + } +} diff --git a/core/java/android/util/LongSparseArray.java b/core/java/android/util/LongSparseArray.java index 77dfcf4..63e8c25 100644 --- a/core/java/android/util/LongSparseArray.java +++ b/core/java/android/util/LongSparseArray.java @@ -64,8 +64,8 @@ public class LongSparseArray<E> implements Cloneable { */ public LongSparseArray(int initialCapacity) { if (initialCapacity == 0) { - mKeys = SparseLongArray.EMPTY_LONGS; - mValues = SparseArray.EMPTY_OBJECTS; + mKeys = ContainerHelpers.EMPTY_LONGS; + mValues = ContainerHelpers.EMPTY_OBJECTS; } else { initialCapacity = ArrayUtils.idealLongArraySize(initialCapacity); mKeys = new long[initialCapacity]; @@ -102,7 +102,7 @@ public class LongSparseArray<E> implements Cloneable { */ @SuppressWarnings("unchecked") public E get(long key, E valueIfKeyNotFound) { - int i = binarySearch(mKeys, 0, mSize, key); + int i = ContainerHelpers.binarySearch(mKeys, mSize, key); if (i < 0 || mValues[i] == DELETED) { return valueIfKeyNotFound; @@ -115,7 +115,7 @@ public class LongSparseArray<E> implements Cloneable { * Removes the mapping from the specified key, if there was any. */ public void delete(long key) { - int i = binarySearch(mKeys, 0, mSize, key); + int i = ContainerHelpers.binarySearch(mKeys, mSize, key); if (i >= 0) { if (mValues[i] != DELETED) { @@ -176,7 +176,7 @@ public class LongSparseArray<E> implements Cloneable { * was one. */ public void put(long key, E value) { - int i = binarySearch(mKeys, 0, mSize, key); + int i = ContainerHelpers.binarySearch(mKeys, mSize, key); if (i >= 0) { mValues[i] = value; @@ -193,7 +193,7 @@ public class LongSparseArray<E> implements Cloneable { gc(); // Search again because indices may have changed. - i = ~binarySearch(mKeys, 0, mSize, key); + i = ~ContainerHelpers.binarySearch(mKeys, mSize, key); } if (mSize >= mKeys.length) { @@ -284,7 +284,7 @@ public class LongSparseArray<E> implements Cloneable { gc(); } - return binarySearch(mKeys, 0, mSize, key); + return ContainerHelpers.binarySearch(mKeys, mSize, key); } /** @@ -356,23 +356,36 @@ public class LongSparseArray<E> implements Cloneable { mSize = pos + 1; } - private static int binarySearch(long[] a, int start, int len, long key) { - int high = start + len, low = start - 1, guess; - - while (high - low > 1) { - guess = (high + low) / 2; - - if (a[guess] < key) - low = guess; - else - high = guess; + /** + * {@inheritDoc} + * + * <p>This implementation composes a string by iterating over its mappings. If + * this map contains itself as a value, the string "(this Map)" + * will appear in its place. + */ + @Override + public String toString() { + if (size() <= 0) { + return "{}"; } - if (high == start + len) - return ~(start + len); - else if (a[high] == key) - return high; - else - return ~high; + StringBuilder buffer = new StringBuilder(mSize * 28); + buffer.append('{'); + for (int i=0; i<mSize; i++) { + if (i > 0) { + buffer.append(", "); + } + long key = keyAt(i); + buffer.append(key); + buffer.append('='); + Object value = valueAt(i); + if (value != this) { + buffer.append(value); + } else { + buffer.append("(this Map)"); + } + } + buffer.append('}'); + return buffer.toString(); } } diff --git a/core/java/android/util/LongSparseLongArray.java b/core/java/android/util/LongSparseLongArray.java index d795308..133e415 100644 --- a/core/java/android/util/LongSparseLongArray.java +++ b/core/java/android/util/LongSparseLongArray.java @@ -58,8 +58,8 @@ public class LongSparseLongArray implements Cloneable { */ public LongSparseLongArray(int initialCapacity) { if (initialCapacity == 0) { - mKeys = SparseLongArray.EMPTY_LONGS; - mValues = SparseLongArray.EMPTY_LONGS; + mKeys = ContainerHelpers.EMPTY_LONGS; + mValues = ContainerHelpers.EMPTY_LONGS; } else { initialCapacity = ArrayUtils.idealLongArraySize(initialCapacity); mKeys = new long[initialCapacity]; @@ -94,7 +94,7 @@ public class LongSparseLongArray implements Cloneable { * if no such mapping has been made. */ public long get(long key, long valueIfKeyNotFound) { - int i = Arrays.binarySearch(mKeys, 0, mSize, key); + int i = ContainerHelpers.binarySearch(mKeys, mSize, key); if (i < 0) { return valueIfKeyNotFound; @@ -107,7 +107,7 @@ public class LongSparseLongArray implements Cloneable { * Removes the mapping from the specified key, if there was any. */ public void delete(long key) { - int i = Arrays.binarySearch(mKeys, 0, mSize, key); + int i = ContainerHelpers.binarySearch(mKeys, mSize, key); if (i >= 0) { removeAt(i); @@ -129,7 +129,7 @@ public class LongSparseLongArray implements Cloneable { * was one. */ public void put(long key, long value) { - int i = Arrays.binarySearch(mKeys, 0, mSize, key); + int i = ContainerHelpers.binarySearch(mKeys, mSize, key); if (i >= 0) { mValues[i] = value; @@ -183,7 +183,7 @@ public class LongSparseLongArray implements Cloneable { * key is not mapped. */ public int indexOfKey(long key) { - return Arrays.binarySearch(mKeys, 0, mSize, key); + return ContainerHelpers.binarySearch(mKeys, mSize, key); } /** @@ -241,4 +241,31 @@ public class LongSparseLongArray implements Cloneable { mKeys = nkeys; mValues = nvalues; } + + /** + * {@inheritDoc} + * + * <p>This implementation composes a string by iterating over its mappings. + */ + @Override + public String toString() { + if (size() <= 0) { + return "{}"; + } + + StringBuilder buffer = new StringBuilder(mSize * 28); + buffer.append('{'); + for (int i=0; i<mSize; i++) { + if (i > 0) { + buffer.append(", "); + } + long key = keyAt(i); + buffer.append(key); + buffer.append('='); + long value = valueAt(i); + buffer.append(value); + } + buffer.append('}'); + return buffer.toString(); + } } diff --git a/core/java/android/util/SparseArray.java b/core/java/android/util/SparseArray.java index 0e013c3..6e66090 100644 --- a/core/java/android/util/SparseArray.java +++ b/core/java/android/util/SparseArray.java @@ -42,8 +42,6 @@ import com.android.internal.util.ArrayUtils; */ public class SparseArray<E> implements Cloneable { private static final Object DELETED = new Object(); - static final int[] EMPTY_INTS = new int[0]; - static final Object[] EMPTY_OBJECTS = new Object[0]; private boolean mGarbage = false; private int[] mKeys; @@ -66,8 +64,8 @@ public class SparseArray<E> implements Cloneable { */ public SparseArray(int initialCapacity) { if (initialCapacity == 0) { - mKeys = EMPTY_INTS; - mValues = EMPTY_OBJECTS; + mKeys = ContainerHelpers.EMPTY_INTS; + mValues = ContainerHelpers.EMPTY_OBJECTS; } else { initialCapacity = ArrayUtils.idealIntArraySize(initialCapacity); mKeys = new int[initialCapacity]; @@ -104,7 +102,7 @@ public class SparseArray<E> implements Cloneable { */ @SuppressWarnings("unchecked") public E get(int key, E valueIfKeyNotFound) { - int i = binarySearch(mKeys, mSize, key); + int i = ContainerHelpers.binarySearch(mKeys, mSize, key); if (i < 0 || mValues[i] == DELETED) { return valueIfKeyNotFound; @@ -117,7 +115,7 @@ public class SparseArray<E> implements Cloneable { * Removes the mapping from the specified key, if there was any. */ public void delete(int key) { - int i = binarySearch(mKeys, mSize, key); + int i = ContainerHelpers.binarySearch(mKeys, mSize, key); if (i >= 0) { if (mValues[i] != DELETED) { @@ -144,6 +142,19 @@ public class SparseArray<E> implements Cloneable { } } + /** + * Remove a range of mappings as a batch. + * + * @param index Index to begin at + * @param size Number of mappings to remove + */ + public void removeAtRange(int index, int size) { + final int end = Math.min(mSize, index + size); + for (int i = index; i < end; i++) { + removeAt(i); + } + } + private void gc() { // Log.e("SparseArray", "gc start with " + mSize); @@ -178,7 +189,7 @@ public class SparseArray<E> implements Cloneable { * was one. */ public void put(int key, E value) { - int i = binarySearch(mKeys, mSize, key); + int i = ContainerHelpers.binarySearch(mKeys, mSize, key); if (i >= 0) { mValues[i] = value; @@ -195,7 +206,7 @@ public class SparseArray<E> implements Cloneable { gc(); // Search again because indices may have changed. - i = ~binarySearch(mKeys, mSize, key); + i = ~ContainerHelpers.binarySearch(mKeys, mSize, key); } if (mSize >= mKeys.length) { @@ -286,7 +297,7 @@ public class SparseArray<E> implements Cloneable { gc(); } - return binarySearch(mKeys, mSize, key); + return ContainerHelpers.binarySearch(mKeys, mSize, key); } /** @@ -360,23 +371,36 @@ public class SparseArray<E> implements Cloneable { mSize = pos + 1; } - // This is Arrays.binarySearch(), but doesn't do any argument validation. - static int binarySearch(int[] array, int size, int value) { - int lo = 0; - int hi = size - 1; - - while (lo <= hi) { - int mid = (lo + hi) >>> 1; - int midVal = array[mid]; + /** + * {@inheritDoc} + * + * <p>This implementation composes a string by iterating over its mappings. If + * this map contains itself as a value, the string "(this Map)" + * will appear in its place. + */ + @Override + public String toString() { + if (size() <= 0) { + return "{}"; + } - if (midVal < value) { - lo = mid + 1; - } else if (midVal > value) { - hi = mid - 1; + StringBuilder buffer = new StringBuilder(mSize * 28); + buffer.append('{'); + for (int i=0; i<mSize; i++) { + if (i > 0) { + buffer.append(", "); + } + int key = keyAt(i); + buffer.append(key); + buffer.append('='); + Object value = valueAt(i); + if (value != this) { + buffer.append(value); } else { - return mid; // value found + buffer.append("(this Map)"); } } - return ~lo; // value not present + buffer.append('}'); + return buffer.toString(); } } diff --git a/core/java/android/util/SparseBooleanArray.java b/core/java/android/util/SparseBooleanArray.java index 430755a..da196d7 100644 --- a/core/java/android/util/SparseBooleanArray.java +++ b/core/java/android/util/SparseBooleanArray.java @@ -35,8 +35,6 @@ import com.android.internal.util.ArrayUtils; * the performance difference is not significant, less than 50%.</p> */ public class SparseBooleanArray implements Cloneable { - static final boolean[] EMPTY_BOOLEANS = new boolean[0]; - /** * Creates a new SparseBooleanArray containing no mappings. */ @@ -53,8 +51,8 @@ public class SparseBooleanArray implements Cloneable { */ public SparseBooleanArray(int initialCapacity) { if (initialCapacity == 0) { - mKeys = SparseArray.EMPTY_INTS; - mValues = EMPTY_BOOLEANS; + mKeys = ContainerHelpers.EMPTY_INTS; + mValues = ContainerHelpers.EMPTY_BOOLEANS; } else { initialCapacity = ArrayUtils.idealIntArraySize(initialCapacity); mKeys = new int[initialCapacity]; @@ -89,7 +87,7 @@ public class SparseBooleanArray implements Cloneable { * if no such mapping has been made. */ public boolean get(int key, boolean valueIfKeyNotFound) { - int i = SparseArray.binarySearch(mKeys, mSize, key); + int i = ContainerHelpers.binarySearch(mKeys, mSize, key); if (i < 0) { return valueIfKeyNotFound; @@ -102,7 +100,7 @@ public class SparseBooleanArray implements Cloneable { * Removes the mapping from the specified key, if there was any. */ public void delete(int key) { - int i = SparseArray.binarySearch(mKeys, mSize, key); + int i = ContainerHelpers.binarySearch(mKeys, mSize, key); if (i >= 0) { System.arraycopy(mKeys, i + 1, mKeys, i, mSize - (i + 1)); @@ -117,7 +115,7 @@ public class SparseBooleanArray implements Cloneable { * was one. */ public void put(int key, boolean value) { - int i = SparseArray.binarySearch(mKeys, mSize, key); + int i = ContainerHelpers.binarySearch(mKeys, mSize, key); if (i >= 0) { mValues[i] = value; @@ -182,7 +180,7 @@ public class SparseBooleanArray implements Cloneable { * key is not mapped. */ public int indexOfKey(int key) { - return SparseArray.binarySearch(mKeys, mSize, key); + return ContainerHelpers.binarySearch(mKeys, mSize, key); } /** @@ -237,7 +235,34 @@ public class SparseBooleanArray implements Cloneable { mValues[pos] = value; mSize = pos + 1; } - + + /** + * {@inheritDoc} + * + * <p>This implementation composes a string by iterating over its mappings. + */ + @Override + public String toString() { + if (size() <= 0) { + return "{}"; + } + + StringBuilder buffer = new StringBuilder(mSize * 28); + buffer.append('{'); + for (int i=0; i<mSize; i++) { + if (i > 0) { + buffer.append(", "); + } + int key = keyAt(i); + buffer.append(key); + buffer.append('='); + boolean value = valueAt(i); + buffer.append(value); + } + buffer.append('}'); + return buffer.toString(); + } + private int[] mKeys; private boolean[] mValues; private int mSize; diff --git a/core/java/android/util/SparseIntArray.java b/core/java/android/util/SparseIntArray.java index b6fb295..c2bacb0 100644 --- a/core/java/android/util/SparseIntArray.java +++ b/core/java/android/util/SparseIntArray.java @@ -54,8 +54,8 @@ public class SparseIntArray implements Cloneable { */ public SparseIntArray(int initialCapacity) { if (initialCapacity == 0) { - mKeys = SparseArray.EMPTY_INTS; - mValues = SparseArray.EMPTY_INTS; + mKeys = ContainerHelpers.EMPTY_INTS; + mValues = ContainerHelpers.EMPTY_INTS; } else { initialCapacity = ArrayUtils.idealIntArraySize(initialCapacity); mKeys = new int[initialCapacity]; @@ -90,7 +90,7 @@ public class SparseIntArray implements Cloneable { * if no such mapping has been made. */ public int get(int key, int valueIfKeyNotFound) { - int i = SparseArray.binarySearch(mKeys, mSize, key); + int i = ContainerHelpers.binarySearch(mKeys, mSize, key); if (i < 0) { return valueIfKeyNotFound; @@ -103,7 +103,7 @@ public class SparseIntArray implements Cloneable { * Removes the mapping from the specified key, if there was any. */ public void delete(int key) { - int i = SparseArray.binarySearch(mKeys, mSize, key); + int i = ContainerHelpers.binarySearch(mKeys, mSize, key); if (i >= 0) { removeAt(i); @@ -125,7 +125,7 @@ public class SparseIntArray implements Cloneable { * was one. */ public void put(int key, int value) { - int i = SparseArray.binarySearch(mKeys, mSize, key); + int i = ContainerHelpers.binarySearch(mKeys, mSize, key); if (i >= 0) { mValues[i] = value; @@ -190,7 +190,7 @@ public class SparseIntArray implements Cloneable { * key is not mapped. */ public int indexOfKey(int key) { - return SparseArray.binarySearch(mKeys, mSize, key); + return ContainerHelpers.binarySearch(mKeys, mSize, key); } /** @@ -245,4 +245,31 @@ public class SparseIntArray implements Cloneable { mValues[pos] = value; mSize = pos + 1; } + + /** + * {@inheritDoc} + * + * <p>This implementation composes a string by iterating over its mappings. + */ + @Override + public String toString() { + if (size() <= 0) { + return "{}"; + } + + StringBuilder buffer = new StringBuilder(mSize * 28); + buffer.append('{'); + for (int i=0; i<mSize; i++) { + if (i > 0) { + buffer.append(", "); + } + int key = keyAt(i); + buffer.append(key); + buffer.append('='); + int value = valueAt(i); + buffer.append(value); + } + buffer.append('}'); + return buffer.toString(); + } } diff --git a/core/java/android/util/SparseLongArray.java b/core/java/android/util/SparseLongArray.java index 55cb3a2..182fd35 100644 --- a/core/java/android/util/SparseLongArray.java +++ b/core/java/android/util/SparseLongArray.java @@ -34,8 +34,6 @@ import com.android.internal.util.ArrayUtils; * the performance difference is not significant, less than 50%.</p> */ public class SparseLongArray implements Cloneable { - static final long[] EMPTY_LONGS = new long[0]; - private int[] mKeys; private long[] mValues; private int mSize; @@ -56,8 +54,8 @@ public class SparseLongArray implements Cloneable { */ public SparseLongArray(int initialCapacity) { if (initialCapacity == 0) { - mKeys = SparseArray.EMPTY_INTS; - mValues = EMPTY_LONGS; + mKeys = ContainerHelpers.EMPTY_INTS; + mValues = ContainerHelpers.EMPTY_LONGS; } else { initialCapacity = ArrayUtils.idealLongArraySize(initialCapacity); mKeys = new int[initialCapacity]; @@ -92,7 +90,7 @@ public class SparseLongArray implements Cloneable { * if no such mapping has been made. */ public long get(int key, long valueIfKeyNotFound) { - int i = SparseArray.binarySearch(mKeys, mSize, key); + int i = ContainerHelpers.binarySearch(mKeys, mSize, key); if (i < 0) { return valueIfKeyNotFound; @@ -105,7 +103,7 @@ public class SparseLongArray implements Cloneable { * Removes the mapping from the specified key, if there was any. */ public void delete(int key) { - int i = SparseArray.binarySearch(mKeys, mSize, key); + int i = ContainerHelpers.binarySearch(mKeys, mSize, key); if (i >= 0) { removeAt(i); @@ -127,7 +125,7 @@ public class SparseLongArray implements Cloneable { * was one. */ public void put(int key, long value) { - int i = SparseArray.binarySearch(mKeys, mSize, key); + int i = ContainerHelpers.binarySearch(mKeys, mSize, key); if (i >= 0) { mValues[i] = value; @@ -181,7 +179,7 @@ public class SparseLongArray implements Cloneable { * key is not mapped. */ public int indexOfKey(int key) { - return SparseArray.binarySearch(mKeys, mSize, key); + return ContainerHelpers.binarySearch(mKeys, mSize, key); } /** @@ -239,4 +237,31 @@ public class SparseLongArray implements Cloneable { mKeys = nkeys; mValues = nvalues; } + + /** + * {@inheritDoc} + * + * <p>This implementation composes a string by iterating over its mappings. + */ + @Override + public String toString() { + if (size() <= 0) { + return "{}"; + } + + StringBuilder buffer = new StringBuilder(mSize * 28); + buffer.append('{'); + for (int i=0; i<mSize; i++) { + if (i > 0) { + buffer.append(", "); + } + int key = keyAt(i); + buffer.append(key); + buffer.append('='); + long value = valueAt(i); + buffer.append(value); + } + buffer.append('}'); + return buffer.toString(); + } } diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java index 4adee14..d2d1f1b 100644 --- a/core/java/android/view/GLES20Canvas.java +++ b/core/java/android/view/GLES20Canvas.java @@ -621,7 +621,7 @@ class GLES20Canvas extends HardwareCanvas { @Override public void concat(Matrix matrix) { - nConcatMatrix(mRenderer, matrix.native_instance); + if (matrix != null) nConcatMatrix(mRenderer, matrix.native_instance); } private static native void nConcatMatrix(int renderer, int matrix); diff --git a/core/java/android/view/GLES20TextureLayer.java b/core/java/android/view/GLES20TextureLayer.java index a4cc630..bb5a6eb 100644 --- a/core/java/android/view/GLES20TextureLayer.java +++ b/core/java/android/view/GLES20TextureLayer.java @@ -73,7 +73,7 @@ class GLES20TextureLayer extends GLES20Layer { SurfaceTexture getSurfaceTexture() { if (mSurface == null) { - mSurface = new SurfaceTexture(mTexture, false); + mSurface = new SurfaceTexture(mTexture); } return mSurface; } diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl index 0289407..aea2799 100644 --- a/core/java/android/view/IWindowManager.aidl +++ b/core/java/android/view/IWindowManager.aidl @@ -78,7 +78,7 @@ interface IWindowManager void addWindowToken(IBinder token, int type); void removeWindowToken(IBinder token); void addAppToken(int addPos, IApplicationToken token, int groupId, int stackId, - int requestedOrientation, boolean fullscreen, boolean showWhenLocked); + int requestedOrientation, boolean fullscreen, boolean showWhenLocked, int userId); void setAppGroupId(IBinder token, int groupId); void setAppOrientation(IApplicationToken token, int requestedOrientation); int getAppOrientation(IApplicationToken token); diff --git a/core/java/android/view/InputDevice.java b/core/java/android/view/InputDevice.java index 2a761c1..34fa73d 100644 --- a/core/java/android/view/InputDevice.java +++ b/core/java/android/view/InputDevice.java @@ -51,6 +51,7 @@ public final class InputDevice implements Parcelable { private final int mKeyboardType; private final KeyCharacterMap mKeyCharacterMap; private final boolean mHasVibrator; + private final boolean mHasButtonUnderPad; private final ArrayList<MotionRange> mMotionRanges = new ArrayList<MotionRange>(); private Vibrator mVibrator; // guarded by mMotionRanges during initialization @@ -343,7 +344,8 @@ public final class InputDevice implements Parcelable { // Called by native code. private InputDevice(int id, int generation, String name, String descriptor, boolean isExternal, int sources, - int keyboardType, KeyCharacterMap keyCharacterMap, boolean hasVibrator) { + int keyboardType, KeyCharacterMap keyCharacterMap, + boolean hasVibrator, boolean hasButtonUnderPad) { mId = id; mGeneration = generation; mName = name; @@ -353,6 +355,7 @@ public final class InputDevice implements Parcelable { mKeyboardType = keyboardType; mKeyCharacterMap = keyCharacterMap; mHasVibrator = hasVibrator; + mHasButtonUnderPad = hasButtonUnderPad; } private InputDevice(Parcel in) { @@ -365,6 +368,7 @@ public final class InputDevice implements Parcelable { mKeyboardType = in.readInt(); mKeyCharacterMap = KeyCharacterMap.CREATOR.createFromParcel(in); mHasVibrator = in.readInt() != 0; + mHasButtonUnderPad = in.readInt() != 0; for (;;) { int axis = in.readInt(); @@ -612,6 +616,15 @@ public final class InputDevice implements Parcelable { } /** + * Reports whether the device has a button under its touchpad + * @return Whether the device has a button under its touchpad + * @hide + */ + public boolean hasButtonUnderPad() { + return mHasButtonUnderPad; + } + + /** * Provides information about the range of values for a particular {@link MotionEvent} axis. * * @see InputDevice#getMotionRange(int) @@ -733,6 +746,7 @@ public final class InputDevice implements Parcelable { out.writeInt(mKeyboardType); mKeyCharacterMap.writeToParcel(out, flags); out.writeInt(mHasVibrator ? 1 : 0); + out.writeInt(mHasButtonUnderPad ? 1 : 0); final int numRanges = mMotionRanges.size(); for (int i = 0; i < numRanges; i++) { diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java index 5db3909..5a5fc10 100644 --- a/core/java/android/view/KeyEvent.java +++ b/core/java/android/view/KeyEvent.java @@ -629,8 +629,11 @@ public class KeyEvent extends InputEvent implements Parcelable { /** Key code constant: Brightness Up key. * Adjusts the screen brightness up. */ public static final int KEYCODE_BRIGHTNESS_UP = 221; + /** Key code constant: Audio Track key + * Switches the audio tracks. */ + public static final int KEYCODE_MEDIA_AUDIO_TRACK = 222; - private static final int LAST_KEYCODE = KEYCODE_BRIGHTNESS_UP; + private static final int LAST_KEYCODE = KEYCODE_MEDIA_AUDIO_TRACK; // NOTE: If you add a new keycode here you must also add it to: // isSystem() @@ -874,6 +877,7 @@ public class KeyEvent extends InputEvent implements Parcelable { names.append(KEYCODE_ASSIST, "KEYCODE_ASSIST"); names.append(KEYCODE_BRIGHTNESS_DOWN, "KEYCODE_BRIGHTNESS_DOWN"); names.append(KEYCODE_BRIGHTNESS_UP, "KEYCODE_BRIGHTNESS_UP"); + names.append(KEYCODE_MEDIA_AUDIO_TRACK, "KEYCODE_MEDIA_AUDIO_TRACK"); }; // Symbolic names of all metakeys in bit order from least significant to most significant. @@ -1833,6 +1837,19 @@ public class KeyEvent extends InputEvent implements Parcelable { } } + /** Whether key will, by default, trigger a click on the focused view. + * @hide + */ + public static final boolean isConfirmKey(int keyCode) { + switch (keyCode) { + case KeyEvent.KEYCODE_DPAD_CENTER: + case KeyEvent.KEYCODE_ENTER: + return true; + default: + return false; + } + } + /** {@inheritDoc} */ @Override public final int getDeviceId() { diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 7447d1b..188ddf2 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -52,6 +52,7 @@ import android.text.TextUtils; import android.util.AttributeSet; import android.util.FloatProperty; import android.util.Log; +import android.util.LongSparseLongArray; import android.util.Pools.SynchronizedPool; import android.util.Property; import android.util.SparseArray; @@ -1122,7 +1123,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * * @see android.graphics.drawable.Drawable * @see #getDrawableState() - * @hide */ protected static final int[] PRESSED_STATE_SET; /** @@ -2198,7 +2198,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * Flag indicating that the view has been through at least one layout since it * was last attached to a window. */ - static final int PFLAG3_HAS_LAYOUT = 0x4; + static final int PFLAG3_IS_LAID_OUT = 0x4; + + /** + * Flag indicating that a call to measure() was skipped and should be done + * instead when layout() is invoked. + */ + static final int PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT = 0x8; /* End of masks for mPrivateFlags3 */ @@ -2980,6 +2986,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, */ int mOldHeightMeasureSpec = Integer.MIN_VALUE; + private LongSparseLongArray mMeasureCache; + @ViewDebug.ExportedProperty(deepExport = true, prefix = "bg_") private Drawable mBackground; @@ -6152,8 +6160,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * Returns true if this view has been through at least one layout since it * was last attached to or detached from a window. */ - public boolean hasLayout() { - return (mPrivateFlags3 & PFLAG3_HAS_LAYOUT) == PFLAG3_HAS_LAYOUT; + public boolean isLaidOut() { + return (mPrivateFlags3 & PFLAG3_IS_LAID_OUT) == PFLAG3_IS_LAID_OUT; } /** @@ -7937,21 +7945,17 @@ public class View implements Drawable.Callback, KeyEvent.Callback, public boolean onKeyDown(int keyCode, KeyEvent event) { boolean result = false; - switch (keyCode) { - case KeyEvent.KEYCODE_DPAD_CENTER: - case KeyEvent.KEYCODE_ENTER: { - if ((mViewFlags & ENABLED_MASK) == DISABLED) { - return true; - } - // Long clickable items don't necessarily have to be clickable - if (((mViewFlags & CLICKABLE) == CLICKABLE || - (mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE) && - (event.getRepeatCount() == 0)) { - setPressed(true); - checkForLongClick(0); - return true; - } - break; + if (KeyEvent.isConfirmKey(event.getKeyCode())) { + if ((mViewFlags & ENABLED_MASK) == DISABLED) { + return true; + } + // Long clickable items don't necessarily have to be clickable + if (((mViewFlags & CLICKABLE) == CLICKABLE || + (mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE) && + (event.getRepeatCount() == 0)) { + setPressed(true); + checkForLongClick(0); + return true; } } return result; @@ -11805,7 +11809,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, mPrivateFlags &= ~PFLAG_AWAKEN_SCROLL_BARS_ON_ATTACH; } - mPrivateFlags3 &= ~PFLAG3_HAS_LAYOUT; + mPrivateFlags3 &= ~PFLAG3_IS_LAID_OUT; jumpDrawablesToCurrentState(); @@ -12104,7 +12108,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, */ protected void onDetachedFromWindow() { mPrivateFlags &= ~PFLAG_CANCEL_NEXT_UP_EVENT; - mPrivateFlags3 &= ~PFLAG3_HAS_LAYOUT; + mPrivateFlags3 &= ~PFLAG3_IS_LAID_OUT; removeUnsetPressCallback(); removeLongPressCallback(); @@ -14402,12 +14406,19 @@ public class View implements Drawable.Callback, KeyEvent.Callback, */ @SuppressWarnings({"unchecked"}) public void layout(int l, int t, int r, int b) { + if ((mPrivateFlags3 & PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT) != 0) { + onMeasure(mOldWidthMeasureSpec, mOldHeightMeasureSpec); + mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT; + } + int oldL = mLeft; int oldT = mTop; int oldB = mBottom; int oldR = mRight; + boolean changed = isLayoutModeOptical(mParent) ? setOpticalFrame(l, t, r, b) : setFrame(l, t, r, b); + if (changed || (mPrivateFlags & PFLAG_LAYOUT_REQUIRED) == PFLAG_LAYOUT_REQUIRED) { onLayout(changed, l, t, r, b); mPrivateFlags &= ~PFLAG_LAYOUT_REQUIRED; @@ -14422,8 +14433,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } } } + mPrivateFlags &= ~PFLAG_FORCE_LAYOUT; - mPrivateFlags3 |= PFLAG3_HAS_LAYOUT; + mPrivateFlags3 |= PFLAG3_IS_LAID_OUT; } /** @@ -15899,6 +15911,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * handle possible request-during-layout errors correctly.</p> */ public void requestLayout() { + if (mMeasureCache != null) mMeasureCache.clear(); + if (mAttachInfo != null && mAttachInfo.mViewRequestingLayout == null) { // Only trigger request-during-layout logic if this is the view requesting it, // not the views in its parent hierarchy @@ -15928,6 +15942,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * on the parent. */ public void forceLayout() { + if (mMeasureCache != null) mMeasureCache.clear(); + mPrivateFlags |= PFLAG_FORCE_LAYOUT; mPrivateFlags |= PFLAG_INVALIDATED; } @@ -15961,6 +15977,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback, widthMeasureSpec = MeasureSpec.adjust(widthMeasureSpec, optical ? -oWidth : oWidth); heightMeasureSpec = MeasureSpec.adjust(heightMeasureSpec, optical ? -oHeight : oHeight); } + + // Suppress sign extension for the low bytes + long key = (long) widthMeasureSpec << 32 | (long) heightMeasureSpec & 0xffffffffL; + if (mMeasureCache == null) mMeasureCache = new LongSparseLongArray(2); + if ((mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT || widthMeasureSpec != mOldWidthMeasureSpec || heightMeasureSpec != mOldHeightMeasureSpec) { @@ -15970,8 +15991,17 @@ public class View implements Drawable.Callback, KeyEvent.Callback, resolveRtlPropertiesIfNeeded(); - // measure ourselves, this should set the measured dimension flag back - onMeasure(widthMeasureSpec, heightMeasureSpec); + int cacheIndex = mMeasureCache.indexOfKey(key); + if (cacheIndex < 0) { + // measure ourselves, this should set the measured dimension flag back + onMeasure(widthMeasureSpec, heightMeasureSpec); + mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT; + } else { + long value = mMeasureCache.valueAt(cacheIndex); + // Casting a long to int drops the high 32 bits, no mask needed + setMeasuredDimension((int) (value >> 32), (int) value); + mPrivateFlags3 |= PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT; + } // flag not set, setMeasuredDimension() was not invoked, we raise // an exception to warn the developer @@ -15986,6 +16016,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback, mOldWidthMeasureSpec = widthMeasureSpec; mOldHeightMeasureSpec = heightMeasureSpec; + + mMeasureCache.put(key, ((long) mMeasuredWidth) << 32 | + (long) mMeasuredHeight & 0xffffffffL); // suppress sign extension } /** diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 93c6d6e..075719c 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -228,6 +228,7 @@ public final class ViewRootImpl implements ViewParent, InputStage mFirstInputStage; InputStage mFirstPostImeInputStage; + SyntheticInputStage mSyntheticInputStage; boolean mWindowAttributesChanged = false; int mWindowAttributesChangesFlag = 0; @@ -589,8 +590,8 @@ public final class ViewRootImpl implements ViewParent, // Set up the input pipeline. CharSequence counterSuffix = attrs.getTitle(); - InputStage syntheticStage = new SyntheticInputStage(); - InputStage viewPostImeStage = new ViewPostImeInputStage(syntheticStage); + mSyntheticInputStage = new SyntheticInputStage(); + InputStage viewPostImeStage = new ViewPostImeInputStage(mSyntheticInputStage); InputStage nativePostImeStage = new NativePostImeInputStage(viewPostImeStage, "aq:native-post-ime:" + counterSuffix); InputStage earlyPostImeStage = new EarlyPostImeInputStage(nativePostImeStage); @@ -3773,6 +3774,9 @@ public final class ViewRootImpl implements ViewParent, private int processKeyEvent(QueuedInputEvent q) { final KeyEvent event = (KeyEvent)q.mEvent; + // The synthetic stage occasionally needs to know about keys in order to debounce taps + mSyntheticInputStage.notifyKeyEvent(event); + // Deliver the key to the view hierarchy. if (mView.dispatchKeyEvent(event)) { return FINISH_HANDLED; @@ -3945,6 +3949,10 @@ public final class ViewRootImpl implements ViewParent, } super.onDeliverToNext(q); } + + public void notifyKeyEvent(KeyEvent e) { + mTouchNavigation.notifyKeyEvent(e); + } } /** @@ -4375,6 +4383,9 @@ public final class ViewRootImpl implements ViewParent, // Tap timeout in milliseconds. private static final int TAP_TIMEOUT = 250; + // Debounce timeout for touch nav devices with a button under their pad, in milliseconds + private static final int DEBOUNCE_TIME = 250; + // The maximum distance traveled for a gesture to be considered a tap in millimeters. private static final int TAP_SLOP_MILLIMETERS = 5; @@ -4409,6 +4420,9 @@ public final class ViewRootImpl implements ViewParent, private int mConfigTapTimeout; private float mConfigTapSlop; + // Amount of time to wait between button presses and tap generation for debouncing + private int mConfigDebounceTime; + // The scaled tick distance. A movement of this amount should generally translate // into a single dpad event in a given direction. private float mConfigTickDistance; @@ -4454,6 +4468,11 @@ public final class ViewRootImpl implements ViewParent, private boolean mFlinging; private float mFlingVelocity; + // The last time a confirm key was pressed on the touch nav device + private long mLastConfirmKeyTime = Long.MAX_VALUE; + + private boolean mHasButtonUnderPad; + public SyntheticTouchNavigationHandler() { super(true); } @@ -4497,6 +4516,8 @@ public final class ViewRootImpl implements ViewParent, MIN_FLING_VELOCITY_TICKS_PER_SECOND * mConfigTickDistance; mConfigMaxFlingVelocity = MAX_FLING_VELOCITY_TICKS_PER_SECOND * mConfigTickDistance; + mConfigDebounceTime = DEBOUNCE_TIME; + mHasButtonUnderPad = device.hasButtonUnderPad(); if (LOCAL_DEBUG) { Log.d(LOCAL_TAG, "Configured device " + mCurrentDeviceId @@ -4567,10 +4588,13 @@ public final class ViewRootImpl implements ViewParent, if (!mConsumedMovement && Math.hypot(mLastX - mStartX, mLastY - mStartY) < mConfigTapSlop && time <= mStartTime + mConfigTapTimeout) { - // It's a tap! - finishKeys(time); - sendKeyDownOrRepeat(time, KeyEvent.KEYCODE_DPAD_CENTER, metaState); - sendKeyUp(time); + if (!mHasButtonUnderPad || + time >= mLastConfirmKeyTime + mConfigDebounceTime) { + // It's a tap! + finishKeys(time); + sendKeyDownOrRepeat(time, KeyEvent.KEYCODE_DPAD_CENTER, metaState); + sendKeyUp(time); + } } else if (mConsumedMovement && mPendingKeyCode != KeyEvent.KEYCODE_UNKNOWN) { // It might be a fling. @@ -4603,6 +4627,13 @@ public final class ViewRootImpl implements ViewParent, } } + public void notifyKeyEvent(KeyEvent e) { + final int keyCode = e.getKeyCode(); + if (KeyEvent.isConfirmKey(e.getKeyCode())) { + mLastConfirmKeyTime = e.getDownTime(); + } + } + private void finishKeys(long time) { cancelFling(); sendKeyUp(time); @@ -6435,11 +6466,17 @@ public final class ViewRootImpl implements ViewParent, public long mLastEventTimeMillis; public void run() { - mLastEventTimeMillis = SystemClock.uptimeMillis(); - AccessibilityEvent event = AccessibilityEvent.obtain(); - event.setEventType(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED); - event.setContentChangeType(AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE); - mSource.sendAccessibilityEventUnchecked(event); + // The accessibility may be turned off while we were waiting so check again. + if (AccessibilityManager.getInstance(mContext).isEnabled()) { + mLastEventTimeMillis = SystemClock.uptimeMillis(); + AccessibilityEvent event = AccessibilityEvent.obtain(); + event.setEventType(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED); + event.setContentChangeType(AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE); + mSource.sendAccessibilityEventUnchecked(event); + } else { + mLastEventTimeMillis = 0; + } + // In any case reset to initial state. mSource.resetSubtreeAccessibilityStateChanged(); mSource = null; } diff --git a/core/java/android/view/VolumePanel.java b/core/java/android/view/VolumePanel.java index 9c00b7f..f0e6677 100644 --- a/core/java/android/view/VolumePanel.java +++ b/core/java/android/view/VolumePanel.java @@ -32,6 +32,7 @@ import android.media.AudioService; import android.media.AudioSystem; import android.media.RingtoneManager; import android.media.ToneGenerator; +import android.media.VolumeController; import android.net.Uri; import android.os.Handler; import android.os.Message; @@ -55,7 +56,8 @@ import java.util.HashMap; * * @hide */ -public class VolumePanel extends Handler implements OnSeekBarChangeListener, View.OnClickListener +public class VolumePanel extends Handler implements OnSeekBarChangeListener, View.OnClickListener, + VolumeController { private static final String TAG = "VolumePanel"; private static boolean LOGD = false; diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfoCache.java b/core/java/android/view/accessibility/AccessibilityNodeInfoCache.java index dded74c..1fde2fa 100644 --- a/core/java/android/view/accessibility/AccessibilityNodeInfoCache.java +++ b/core/java/android/view/accessibility/AccessibilityNodeInfoCache.java @@ -39,7 +39,7 @@ public class AccessibilityNodeInfoCache { private static final boolean ENABLED = true; - private static final boolean DEBUG = true; + private static final boolean DEBUG = false; private static final boolean CHECK_INTEGRITY_IF_DEBUGGABLE_BUILD = true; @@ -108,7 +108,7 @@ public class AccessibilityNodeInfoCache { private void refreshCachedNode(long sourceId) { if (DEBUG) { - Log.i(LOG_TAG, "Refresing cached node."); + Log.i(LOG_TAG, "Refreshing cached node."); } synchronized (mLock) { AccessibilityNodeInfo cachedInfo = mCacheImpl.get(sourceId); @@ -117,7 +117,7 @@ public class AccessibilityNodeInfoCache { return; } // The node changed so we will just refresh it right now. - if (cachedInfo.refresh(false)) { + if (cachedInfo.refresh(true)) { return; } // Weird, we could not refresh. Just evict the entire sub-tree. @@ -141,7 +141,7 @@ public class AccessibilityNodeInfoCache { info = AccessibilityNodeInfo.obtain(info); } if (DEBUG) { -// Log.i(LOG_TAG, "get(" + accessibilityNodeId + ") = " + info); + Log.i(LOG_TAG, "get(" + accessibilityNodeId + ") = " + info); } return info; } @@ -159,7 +159,7 @@ public class AccessibilityNodeInfoCache { if (ENABLED) { synchronized(mLock) { if (DEBUG) { -// Log.i(LOG_TAG, "add(" + info + ")"); + Log.i(LOG_TAG, "add(" + info + ")"); } final long sourceId = info.getSourceNodeId(); @@ -319,8 +319,6 @@ public class AccessibilityNodeInfoCache { Log.e(LOG_TAG, "Node from: " + info.getWindowId() + " not from:" + windowId + " " + info); } - mCacheImpl.removeAt(i); - i--; } } } diff --git a/core/java/android/view/transition/Fade.java b/core/java/android/view/transition/Fade.java index c2aa90b..4fd60c1 100644 --- a/core/java/android/view/transition/Fade.java +++ b/core/java/android/view/transition/Fade.java @@ -32,6 +32,8 @@ import android.view.ViewGroup; */ public class Fade extends Visibility { + private static boolean DBG = Transition.DBG && false; + private static final String LOG_TAG = "Fade"; private static final String PROPNAME_SCREEN_X = "android:fade:screenX"; private static final String PROPNAME_SCREEN_Y = "android:fade:screenY"; @@ -121,7 +123,7 @@ public class Fade extends Visibility { View view; View startView = (startValues != null) ? startValues.view : null; View endView = (endValues != null) ? endValues.view : null; - if (Transition.DBG) { + if (DBG) { Log.d(LOG_TAG, "Fade.predisappear: startView, startVis, endView, endVis = " + startView + ", " + startVisibility + ", " + endView + ", " + endVisibility); } diff --git a/core/java/android/view/transition/Transition.java b/core/java/android/view/transition/Transition.java index 6d5e61a..f99ddc0 100644 --- a/core/java/android/view/transition/Transition.java +++ b/core/java/android/view/transition/Transition.java @@ -20,6 +20,7 @@ import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.TimeInterpolator; import android.util.ArrayMap; +import android.util.Log; import android.util.LongSparseArray; import android.util.Pair; import android.util.SparseArray; @@ -84,11 +85,14 @@ public abstract class Transition implements Cloneable { int mNumInstances = 0; - /** - * The set of listeners to be sent transition lifecycle events. - */ + + // The set of listeners to be sent transition lifecycle events. ArrayList<TransitionListener> mListeners = null; + // The set of animators collected from calls to play(), to be run in runAnimations() + ArrayMap<Pair<TransitionValues, TransitionValues>, Animator> mAnimatorMap = + new ArrayMap<Pair<TransitionValues, TransitionValues>, Animator>(); + /** * Constructs a Transition object with no target objects. A transition with * no targets defaults to running on all target objects in the scene hierarchy @@ -203,6 +207,9 @@ public abstract class Transition implements Cloneable { */ protected void play(ViewGroup sceneRoot, TransitionValuesMaps startValues, TransitionValuesMaps endValues) { + if (DBG) { + Log.d(LOG_TAG, "play() for " + this); + } mPlayStartValuesList.clear(); mPlayEndValuesList.clear(); ArrayMap<View, TransitionValues> endCopy = @@ -312,20 +319,45 @@ public abstract class Transition implements Cloneable { for (int i = 0; i < startValuesList.size(); ++i) { TransitionValues start = startValuesList.get(i); TransitionValues end = endValuesList.get(i); - // TODO: what to do about targetIds and itemIds? - Animator animator = play(sceneRoot, start, end); - if (animator != null) { - mAnimatorMap.put(new Pair(start, end), animator); - // Note: we've already done the check against targetIDs in these lists - mPlayStartValuesList.add(start); - mPlayEndValuesList.add(end); + // Only bother trying to animate with values that differ between start/end + if (start != null || end != null) { + if (start == null || !start.equals(end)) { + if (DBG) { + View view = (end != null) ? end.view : start.view; + Log.d(LOG_TAG, " differing start/end values for view " + + view); + if (start == null || end == null) { + if (start == null) { + Log.d(LOG_TAG, " " + ((start == null) ? + "start null, end non-null" : "start non-null, end null")); + } + } else { + for (String key : start.values.keySet()) { + Object startValue = start.values.get(key); + Object endValue = end.values.get(key); + if (startValue != endValue && !startValue.equals(endValue)) { + Log.d(LOG_TAG, " " + key + ": start(" + startValue + + "), end(" + endValue +")"); + } + } + } + } + // TODO: what to do about targetIds and itemIds? + Animator animator = play(sceneRoot, start, end); + if (animator != null) { + mAnimatorMap.put(new Pair(start, end), animator); + // Note: we've already done the check against targetIDs in these lists + mPlayStartValuesList.add(start); + mPlayEndValuesList.add(end); + } + } else if (DBG) { + View view = (end != null) ? end.view : start.view; + Log.d(LOG_TAG, " No change for view " + view); + } } } } - ArrayMap<Pair<TransitionValues, TransitionValues>, Animator> mAnimatorMap = - new ArrayMap<Pair<TransitionValues, TransitionValues>, Animator>(); - /** * Internal utility method for checking whether a given view/id * is valid for this transition, where "valid" means that either @@ -364,14 +396,20 @@ public abstract class Transition implements Cloneable { * @hide */ protected void runAnimations() { - + if (DBG && mPlayStartValuesList.size() > 0) { + Log.d(LOG_TAG, "runAnimations (" + mPlayStartValuesList.size() + ") on " + this); + } startTransition(); // Now walk the list of TransitionValues, calling play for each pair for (int i = 0; i < mPlayStartValuesList.size(); ++i) { TransitionValues start = mPlayStartValuesList.get(i); TransitionValues end = mPlayEndValuesList.get(i); + Animator anim = mAnimatorMap.get(new Pair(start, end)); + if (DBG) { + Log.d(LOG_TAG, " anim: " + anim); + } startTransition(); - runAnimator(mAnimatorMap.get(new Pair(start, end))); + runAnimator(anim); } mPlayStartValuesList.clear(); mPlayEndValuesList.clear(); @@ -871,27 +909,35 @@ public abstract class Transition implements Cloneable { String toString(String indent) { String result = indent + getClass().getSimpleName() + "@" + Integer.toHexString(hashCode()) + ": "; - result += "dur(" + mDuration + ") "; - result += "dly(" + mStartDelay + ") "; - result += "interp(" + mInterpolator + ") "; - result += "tgts("; - if (mTargetIds != null) { - for (int i = 0; i < mTargetIds.length; ++i) { - if (i > 0) { - result += ", "; + if (mDuration != -1) { + result += "dur(" + mDuration + ") "; + } + if (mStartDelay != -1) { + result += "dly(" + mStartDelay + ") "; + } + if (mInterpolator != null) { + result += "interp(" + mInterpolator + ") "; + } + if (mTargetIds != null || mTargets != null) { + result += "tgts("; + if (mTargetIds != null) { + for (int i = 0; i < mTargetIds.length; ++i) { + if (i > 0) { + result += ", "; + } + result += mTargetIds[i]; } - result += mTargetIds[i]; } - } - if (mTargets != null) { - for (int i = 0; i < mTargets.length; ++i) { - if (i > 0) { - result += ", "; + if (mTargets != null) { + for (int i = 0; i < mTargets.length; ++i) { + if (i > 0) { + result += ", "; + } + result += mTargets[i]; } - result += mTargets[i]; } + result += ")"; } - result += ")"; return result; } diff --git a/core/java/android/view/transition/TransitionManager.java b/core/java/android/view/transition/TransitionManager.java index b200a6d..7836268 100644 --- a/core/java/android/view/transition/TransitionManager.java +++ b/core/java/android/view/transition/TransitionManager.java @@ -17,6 +17,7 @@ package android.view.transition; import android.util.ArrayMap; +import android.util.Log; import android.view.ViewGroup; import android.view.ViewTreeObserver; @@ -36,6 +37,8 @@ import java.util.ArrayList; public class TransitionManager { // TODO: how to handle enter/exit? + private static String LOG_TAG = "TransitionManager"; + private static final Transition sDefaultTransition = new AutoTransition(); private Transition mDefaultTransition = new AutoTransition(); @@ -164,6 +167,7 @@ public class TransitionManager { observer.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { public boolean onPreDraw() { sceneRoot.getViewTreeObserver().removeOnPreDrawListener(this); + sPendingTransitions.remove(sceneRoot); // Add to running list, handle end to remove it sRunningTransitions.put(sceneRoot, transition); transition.addListener(new Transition.TransitionListenerAdapter() { @@ -316,8 +320,11 @@ public class TransitionManager { * value of null causes the TransitionManager to use the default transition. */ public static void beginDelayedTransition(final ViewGroup sceneRoot, Transition transition) { - - if (!sPendingTransitions.contains(sceneRoot)) { + if (!sPendingTransitions.contains(sceneRoot) && sceneRoot.isLaidOut()) { + if (Transition.DBG) { + Log.d(LOG_TAG, "beginDelayedTransition: root, transition = " + + sceneRoot + ", " + transition); + } sPendingTransitions.add(sceneRoot); if (transition == null) { transition = sDefaultTransition; @@ -325,13 +332,7 @@ public class TransitionManager { final Transition finalTransition = transition.clone(); sceneChangeSetup(sceneRoot, transition); sceneRoot.setCurrentScene(null); - sceneRoot.postOnAnimation(new Runnable() { - @Override - public void run() { - sPendingTransitions.remove(sceneRoot); - sceneChangeRunTransition(sceneRoot, finalTransition); - } - }); + sceneChangeRunTransition(sceneRoot, finalTransition); } } } diff --git a/core/java/android/view/transition/TransitionValues.java b/core/java/android/view/transition/TransitionValues.java index f361666..6e5d3d3 100644 --- a/core/java/android/view/transition/TransitionValues.java +++ b/core/java/android/view/transition/TransitionValues.java @@ -53,6 +53,23 @@ public class TransitionValues { public final Map<String, Object> values = new ArrayMap<String, Object>(); @Override + public boolean equals(Object other) { + if (other instanceof TransitionValues) { + if (view == ((TransitionValues) other).view) { + if (values.equals(((TransitionValues) other).values)) { + return true; + } + } + } + return false; + } + + @Override + public int hashCode() { + return 31*view.hashCode() + values.hashCode(); + } + + @Override public String toString() { String returnValue = "TransitionValues@" + Integer.toHexString(hashCode()) + ":\n"; returnValue += " view = " + view + "\n"; diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java index 0149f03..7146d0d 100644 --- a/core/java/android/webkit/WebView.java +++ b/core/java/android/webkit/WebView.java @@ -850,6 +850,23 @@ public class WebView extends AbsoluteLayout } /** + * Asynchronously evaluates JavaScript in the context of the currently displayed page. + * If non-null, |resultCallback| will be invoked with any result returned from that + * execution. This method must be called on the UI thread and the callback will + * be made on the UI thread. + * + * @param script the JavaScript to execute. + * @param resultCallback A callback to be invoked when the script execution + * completes with the result of the execution (if any). + * May be null if no notificaion of the result is required. + * @hide pending API council approval and CTS test coverage. + */ + public void evaluateJavascript(String script, ValueCallback<String> resultCallback) { + checkThread(); + mProvider.evaluateJavaScript(script, resultCallback); + } + + /** * Saves the current view as a web archive. * * @param filename the filename where the archive should be placed diff --git a/core/java/android/webkit/WebViewClassic.java b/core/java/android/webkit/WebViewClassic.java index 5a9e6c9..b930276 100644 --- a/core/java/android/webkit/WebViewClassic.java +++ b/core/java/android/webkit/WebViewClassic.java @@ -2656,6 +2656,12 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc clearHelpers(); } + @Override + public void evaluateJavaScript(String script, ValueCallback<String> resultCallback) { + // K-only API not implemented in WebViewClassic. + throw new IllegalStateException("This API not supported in Classic WebView."); + } + /** * See {@link WebView#saveWebArchive(String)} */ diff --git a/core/java/android/webkit/WebViewProvider.java b/core/java/android/webkit/WebViewProvider.java index 41d6333..8c5c4ce 100644 --- a/core/java/android/webkit/WebViewProvider.java +++ b/core/java/android/webkit/WebViewProvider.java @@ -114,6 +114,8 @@ public interface WebViewProvider { public void loadDataWithBaseURL(String baseUrl, String data, String mimeType, String encoding, String historyUrl); + public void evaluateJavaScript(String script, ValueCallback<String> resultCallback); + public void saveWebArchive(String filename); public void saveWebArchive(String basename, boolean autoname, ValueCallback<String> callback); diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java index 8b51bf3..f5c3b37 100644 --- a/core/java/android/widget/AbsListView.java +++ b/core/java/android/widget/AbsListView.java @@ -1207,15 +1207,13 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te */ public void setFastScrollEnabled(boolean enabled) { mFastScrollEnabled = enabled; - if (enabled) { - if (mFastScroller == null) { - mFastScroller = new FastScroller(getContext(), this); - } - } else { - if (mFastScroller != null) { - mFastScroller.stop(); - mFastScroller = null; - } + + if (enabled && mFastScroller == null) { + mFastScroller = new FastScroller(getContext(), this); + } + + if (mFastScroller != null) { + mFastScroller.setEnabled(enabled); } } @@ -2927,9 +2925,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te @Override public boolean onKeyUp(int keyCode, KeyEvent event) { - switch (keyCode) { - case KeyEvent.KEYCODE_DPAD_CENTER: - case KeyEvent.KEYCODE_ENTER: + if (KeyEvent.isConfirmKey(keyCode)) { if (!isEnabled()) { return true; } @@ -2945,7 +2941,6 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te setPressed(false); return true; } - break; } return super.onKeyUp(keyCode, event); } @@ -6502,58 +6497,67 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te } /** - * Put a view into the ScrapViews list. These views are unordered. + * Puts a view into the list of scrap views. + * <p> + * If the list data hasn't changed or the adapter has stable IDs, views + * with transient state will be preserved for later retrieval. * * @param scrap The view to add + * @param position The view's position within its parent */ void addScrapView(View scrap, int position) { - AbsListView.LayoutParams lp = (AbsListView.LayoutParams) scrap.getLayoutParams(); + final AbsListView.LayoutParams lp = (AbsListView.LayoutParams) scrap.getLayoutParams(); if (lp == null) { return; } lp.scrappedFromPosition = position; - // Don't put header or footer views or views that should be ignored - // into the scrap heap - int viewType = lp.viewType; + // Don't scrap header or footer views, or views that should + // otherwise not be recycled. + final int viewType = lp.viewType; + if (!shouldRecycleViewType(viewType)) { + return; + } + + scrap.dispatchStartTemporaryDetach(); + + // Don't scrap views that have transient state. final boolean scrapHasTransientState = scrap.hasTransientState(); - if (!shouldRecycleViewType(viewType) || scrapHasTransientState) { - if (viewType != ITEM_VIEW_TYPE_HEADER_OR_FOOTER && scrapHasTransientState) { + if (scrapHasTransientState) { + if (mAdapter != null && mAdapterHasStableIds) { + // If the adapter has stable IDs, we can reuse the view for + // the same data. + if (mTransientStateViewsById == null) { + mTransientStateViewsById = new LongSparseArray<View>(); + } + mTransientStateViewsById.put(lp.itemId, scrap); + } else if (!mDataChanged) { + // If the data hasn't changed, we can reuse the views at + // their old positions. + if (mTransientStateViews == null) { + mTransientStateViews = new SparseArray<View>(); + } + mTransientStateViews.put(position, scrap); + } else { + // Otherwise, we'll have to remove the view and start over. if (mSkippedScrap == null) { mSkippedScrap = new ArrayList<View>(); } mSkippedScrap.add(scrap); } - if (scrapHasTransientState) { - scrap.dispatchStartTemporaryDetach(); - if (mAdapter != null && mAdapterHasStableIds) { - if (mTransientStateViewsById == null) { - mTransientStateViewsById = new LongSparseArray<View>(); - } - mTransientStateViewsById.put(lp.itemId, scrap); - } else if (!mDataChanged) { - // avoid putting views on transient state list during a data change; - // the layout positions may be out of sync with the adapter positions - if (mTransientStateViews == null) { - mTransientStateViews = new SparseArray<View>(); - } - mTransientStateViews.put(position, scrap); - } + } else { + if (mViewTypeCount == 1) { + mCurrentScrap.add(scrap); + } else { + mScrapViews[viewType].add(scrap); } - return; - } - scrap.dispatchStartTemporaryDetach(); - if (mViewTypeCount == 1) { - mCurrentScrap.add(scrap); - } else { - mScrapViews[viewType].add(scrap); - } + scrap.setAccessibilityDelegate(null); - scrap.setAccessibilityDelegate(null); - if (mRecyclerListener != null) { - mRecyclerListener.onMovedToScrapHeap(scrap); + if (mRecyclerListener != null) { + mRecyclerListener.onMovedToScrapHeap(scrap); + } } } diff --git a/core/java/android/widget/CheckedTextView.java b/core/java/android/widget/CheckedTextView.java index f1c3139..40747f0 100644 --- a/core/java/android/widget/CheckedTextView.java +++ b/core/java/android/widget/CheckedTextView.java @@ -242,7 +242,7 @@ public class CheckedTextView extends TextView implements Checkable { right = width - mBasePadding; left = right - mCheckMarkWidth; } - checkMarkDrawable.setBounds( left, top, right, bottom); + checkMarkDrawable.setBounds(mScrollX + left, top, mScrollX + right, bottom); checkMarkDrawable.draw(canvas); } } diff --git a/core/java/android/widget/FastScroller.java b/core/java/android/widget/FastScroller.java index 594b130..f3c0687 100644 --- a/core/java/android/widget/FastScroller.java +++ b/core/java/android/widget/FastScroller.java @@ -175,6 +175,9 @@ class FastScroller { /** Whether decorations should be laid out from right to left. */ private boolean mLayoutFromRight; + /** Whether the fast scroller is enabled. */ + private boolean mEnabled; + /** Whether the scrollbar and decorations should always be shown. */ private boolean mAlwaysShow; @@ -302,6 +305,39 @@ class FastScroller { } /** + * Removes this FastScroller overlay from the host view. + */ + public void remove() { + mOverlay.remove(mTrackImage); + mOverlay.remove(mThumbImage); + mOverlay.remove(mPreviewImage); + mOverlay.remove(mPrimaryText); + mOverlay.remove(mSecondaryText); + } + + /** + * @param enabled Whether the fast scroll thumb is enabled. + */ + public void setEnabled(boolean enabled) { + mEnabled = enabled; + + if (enabled) { + if (mAlwaysShow) { + setState(STATE_VISIBLE); + } + } else { + stop(); + } + } + + /** + * @return Whether the fast scroll thumb is enabled. + */ + public boolean isEnabled() { + return mEnabled; + } + + /** * @param alwaysShow Whether the fast scroll thumb should always be shown */ public void setAlwaysShow(boolean alwaysShow) { @@ -329,18 +365,6 @@ class FastScroller { setState(STATE_NONE); } - /** - * @return Whether the fast scroll thumb should be shown. - */ - public boolean shouldShow() { - // Don't show if the list is as tall as or shorter than the thumbnail. - if (mList.getHeight() <= mThumbImage.getHeight()) { - return false; - } - - return true; - } - public void setScrollbarPosition(int position) { if (position == View.SCROLLBAR_POSITION_DEFAULT) { position = mList.isLayoutRtl() ? @@ -696,7 +720,7 @@ class FastScroller { } public void onScroll(int firstVisibleItem, int visibleItemCount, int totalItemCount) { - if (!mAlwaysShow && !isLongList(visibleItemCount, totalItemCount)) { + if (!mEnabled || !mAlwaysShow && !isLongList(visibleItemCount, totalItemCount)) { setState(STATE_NONE); return; } @@ -1106,6 +1130,10 @@ class FastScroller { } public boolean onInterceptTouchEvent(MotionEvent ev) { + if (!mEnabled) { + return false; + } + switch (ev.getActionMasked()) { case MotionEvent.ACTION_DOWN: if (isPointInside(ev.getX(), ev.getY())) { @@ -1134,6 +1162,10 @@ class FastScroller { } public boolean onTouchEvent(MotionEvent me) { + if (!mEnabled) { + return false; + } + switch (me.getActionMasked()) { case MotionEvent.ACTION_DOWN: { if (isPointInside(me.getX(), me.getY())) { diff --git a/core/java/android/widget/Gallery.java b/core/java/android/widget/Gallery.java index c4ef11c..78ba6e0 100644 --- a/core/java/android/widget/Gallery.java +++ b/core/java/android/widget/Gallery.java @@ -1228,13 +1228,9 @@ public class Gallery extends AbsSpinner implements GestureDetector.OnGestureList @Override public boolean onKeyUp(int keyCode, KeyEvent event) { - switch (keyCode) { - case KeyEvent.KEYCODE_DPAD_CENTER: - case KeyEvent.KEYCODE_ENTER: { - + if (KeyEvent.isConfirmKey(keyCode)) { if (mReceivedInvokeKeyDown) { if (mItemCount > 0) { - dispatchPress(mSelectedChild); postDelayed(new Runnable() { @Override @@ -1242,20 +1238,17 @@ public class Gallery extends AbsSpinner implements GestureDetector.OnGestureList dispatchUnpress(); } }, ViewConfiguration.getPressedStateDuration()); - + int selectedIndex = mSelectedPosition - mFirstPosition; performItemClick(getChildAt(selectedIndex), mSelectedPosition, mAdapter .getItemId(mSelectedPosition)); } } - + // Clear the flag mReceivedInvokeKeyDown = false; - return true; } - } - return super.onKeyUp(keyCode, event); } diff --git a/core/java/android/widget/HorizontalScrollView.java b/core/java/android/widget/HorizontalScrollView.java index d114b76..dab0962 100644 --- a/core/java/android/widget/HorizontalScrollView.java +++ b/core/java/android/widget/HorizontalScrollView.java @@ -1480,7 +1480,7 @@ public class HorizontalScrollView extends FrameLayout { } mChildToScrollTo = null; - if (!hasLayout()) { + if (!isLaidOut()) { final int scrollRange = Math.max(0, childWidth - (r - l - mPaddingLeft - mPaddingRight)); if (mSavedState != null) { diff --git a/core/java/android/widget/ListPopupWindow.java b/core/java/android/widget/ListPopupWindow.java index 3d6b69e..414c318 100644 --- a/core/java/android/widget/ListPopupWindow.java +++ b/core/java/android/widget/ListPopupWindow.java @@ -821,8 +821,7 @@ public class ListPopupWindow { // to select one of its items if (keyCode != KeyEvent.KEYCODE_SPACE && (mDropDownList.getSelectedItemPosition() >= 0 - || (keyCode != KeyEvent.KEYCODE_ENTER - && keyCode != KeyEvent.KEYCODE_DPAD_CENTER))) { + || !KeyEvent.isConfirmKey(keyCode))) { int curIndex = mDropDownList.getSelectedItemPosition(); boolean consumed; @@ -910,16 +909,10 @@ public class ListPopupWindow { public boolean onKeyUp(int keyCode, KeyEvent event) { if (isShowing() && mDropDownList.getSelectedItemPosition() >= 0) { boolean consumed = mDropDownList.onKeyUp(keyCode, event); - if (consumed) { - switch (keyCode) { - // if the list accepts the key events and the key event - // was a click, the text view gets the selected item - // from the drop down as its content - case KeyEvent.KEYCODE_ENTER: - case KeyEvent.KEYCODE_DPAD_CENTER: - dismiss(); - break; - } + if (consumed && KeyEvent.isConfirmKey(keyCode)) { + // if the list accepts the key events and the key event was a click, the text view + // gets the selected item from the drop down as its content + dismiss(); } return consumed; } diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java index c44ac32..2f42ae3 100644 --- a/core/java/android/widget/ListView.java +++ b/core/java/android/widget/ListView.java @@ -1478,12 +1478,12 @@ public class ListView extends AbsListView { @Override protected void layoutChildren() { final boolean blockLayoutRequests = mBlockLayoutRequests; - if (!blockLayoutRequests) { - mBlockLayoutRequests = true; - } else { + if (blockLayoutRequests) { return; } + mBlockLayoutRequests = true; + try { super.layoutChildren(); @@ -1495,10 +1495,10 @@ public class ListView extends AbsListView { return; } - int childrenTop = mListPadding.top; - int childrenBottom = mBottom - mTop - mListPadding.bottom; + final int childrenTop = mListPadding.top; + final int childrenBottom = mBottom - mTop - mListPadding.bottom; + final int childCount = getChildCount(); - int childCount = getChildCount(); int index = 0; int delta = 0; @@ -1507,8 +1507,6 @@ public class ListView extends AbsListView { View oldFirst = null; View newSel = null; - View focusLayoutRestoreView = null; - AccessibilityNodeInfo accessibilityFocusLayoutRestoreNode = null; View accessibilityFocusLayoutRestoreView = null; int accessibilityFocusPosition = INVALID_POSITION; @@ -1570,6 +1568,7 @@ public class ListView extends AbsListView { // Remember which child, if any, had accessibility focus. This must // occur before recycling any views, since that will clear // accessibility focus. + // TODO: This should rely on transient state. final ViewRootImpl viewRootImpl = getViewRootImpl(); if (viewRootImpl != null) { final View accessFocusedView = viewRootImpl.getAccessibilityFocusedHost(); @@ -1593,16 +1592,18 @@ public class ListView extends AbsListView { } } + // Ensure the child containing focus, if any, has transient state. + // If the list data hasn't changed, or if the adapter has stable + // IDs, this will maintain focus. + final View focusedChild = getFocusedChild(); + if (focusedChild != null) { + focusedChild.setHasTransientState(true); + } + // Pull all children into the RecycleBin. // These views will be reused if possible final int firstPosition = mFirstPosition; final RecycleBin recycleBin = mRecycler; - - // reset the focus restoration - View focusLayoutRestoreDirectChild = null; - - // Don't put header or footer views into the Recycler. Those are - // already cached in mHeaderViews; if (dataChanged) { for (int i = 0; i < childCount; i++) { recycleBin.addScrapView(getChildAt(i), firstPosition+i); @@ -1611,28 +1612,6 @@ public class ListView extends AbsListView { recycleBin.fillActiveViews(childCount, firstPosition); } - // take focus back to us temporarily to avoid the eventual - // call to clear focus when removing the focused child below - // from messing things up when ViewAncestor assigns focus back - // to someone else - final View focusedChild = getFocusedChild(); - if (focusedChild != null) { - // TODO: in some cases focusedChild.getParent() == null - - // we can remember the focused view to restore after relayout if the - // data hasn't changed, or if the focused position is a header or footer - if (!dataChanged || isDirectChildHeaderOrFooter(focusedChild)) { - focusLayoutRestoreDirectChild = focusedChild; - // remember the specific view that had focus - focusLayoutRestoreView = findFocus(); - if (focusLayoutRestoreView != null) { - // tell it we are going to mess with it - focusLayoutRestoreView.onStartTemporaryDetach(); - } - } - requestFocus(); - } - // Clear out old views detachAllViewsFromParent(); recycleBin.removeSkippedScrap(); @@ -1692,43 +1671,37 @@ public class ListView extends AbsListView { recycleBin.scrapActiveViews(); if (sel != null) { - // the current selected item should get focus if items - // are focusable - if (mItemsCanFocus && hasFocus() && !sel.hasFocus()) { - final boolean focusWasTaken = (sel == focusLayoutRestoreDirectChild && - focusLayoutRestoreView != null && - focusLayoutRestoreView.requestFocus()) || sel.requestFocus(); - if (!focusWasTaken) { - // selected item didn't take focus, fine, but still want - // to make sure something else outside of the selected view - // has focus + final boolean shouldPlaceFocus = mItemsCanFocus && hasFocus(); + final boolean maintainedFocus = focusedChild != null && focusedChild.hasFocus(); + if (shouldPlaceFocus && !maintainedFocus && !sel.hasFocus()) { + if (sel.requestFocus()) { + // Successfully placed focus, clear selection. + sel.setSelected(false); + mSelectorRect.setEmpty(); + } else { + // Failed to place focus, clear current (invalid) focus. final View focused = getFocusedChild(); if (focused != null) { focused.clearFocus(); } positionSelector(INVALID_POSITION, sel); - } else { - sel.setSelected(false); - mSelectorRect.setEmpty(); } } else { positionSelector(INVALID_POSITION, sel); } mSelectedTop = sel.getTop(); } else { - if (mTouchMode > TOUCH_MODE_DOWN && mTouchMode < TOUCH_MODE_SCROLL) { - View child = getChildAt(mMotionPosition - mFirstPosition); - if (child != null) positionSelector(mMotionPosition, child); + // If the user's finger is down, select the motion position. + // Otherwise, clear selection. + if (mTouchMode == TOUCH_MODE_TAP || mTouchMode == TOUCH_MODE_DONE_WAITING) { + final View child = getChildAt(mMotionPosition - mFirstPosition); + if (child != null) { + positionSelector(mMotionPosition, child); + } } else { mSelectedTop = 0; mSelectorRect.setEmpty(); } - - // even if there is not selected position, we may need to restore - // focus (i.e. something focusable in touch mode) - if (hasFocus() && focusLayoutRestoreView != null) { - focusLayoutRestoreView.requestFocus(); - } } // Attempt to restore accessibility focus. @@ -1753,11 +1726,8 @@ public class ListView extends AbsListView { } } - // tell focus view we are done mucking with it, if it is still in - // our view hierarchy. - if (focusLayoutRestoreView != null - && focusLayoutRestoreView.getWindowToken() != null) { - focusLayoutRestoreView.onFinishTemporaryDetach(); + if (focusedChild != null) { + focusedChild.setHasTransientState(false); } mLayoutMode = LAYOUT_NORMAL; diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java index 07e66b7..75e1f32 100644 --- a/core/java/android/widget/RemoteViews.java +++ b/core/java/android/widget/RemoteViews.java @@ -37,6 +37,7 @@ import android.os.Parcelable; import android.os.StrictMode; import android.os.UserHandle; import android.text.TextUtils; +import android.util.ArrayMap; import android.util.Log; import android.view.LayoutInflater; import android.view.LayoutInflater.Filter; @@ -45,6 +46,7 @@ import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; import android.widget.AdapterView.OnItemClickListener; +import libcore.util.Objects; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; @@ -136,6 +138,49 @@ public class RemoteViews implements Parcelable, Filter { private static final OnClickHandler DEFAULT_ON_CLICK_HANDLER = new OnClickHandler(); + private static final Object[] sMethodsLock = new Object[0]; + private static final ArrayMap<Class<? extends View>, ArrayMap<MutablePair<String, Class<?>>, Method>> sMethods = + new ArrayMap<Class<? extends View>, ArrayMap<MutablePair<String, Class<?>>, Method>>(); + private static final ThreadLocal<Object[]> sInvokeArgsTls = new ThreadLocal<Object[]>() { + @Override + protected Object[] initialValue() { + return new Object[1]; + } + }; + + /** + * Handle with care! + */ + static class MutablePair<F, S> { + F first; + S second; + + MutablePair(F first, S second) { + this.first = first; + this.second = second; + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof MutablePair)) { + return false; + } + MutablePair<?, ?> p = (MutablePair<?, ?>) o; + return Objects.equal(p.first, first) && Objects.equal(p.second, second); + } + + @Override + public int hashCode() { + return (first == null ? 0 : first.hashCode()) ^ (second == null ? 0 : second.hashCode()); + } + } + + /** + * This pair is used to perform lookups in sMethods without causing allocations. + */ + private final MutablePair<String, Class<?>> mPair = + new MutablePair<String, Class<?>>(null, null); + /** * This annotation indicates that a subclass of View is alllowed to be used * with the {@link RemoteViews} mechanism. @@ -206,9 +251,8 @@ public class RemoteViews implements Parcelable, Filter { * Overridden by each class to report on it's own memory usage */ public void updateMemoryUsageEstimate(MemoryUsageCounter counter) { - // We currently only calculate Bitmap memory usage, so by default, don't do anything - // here - return; + // We currently only calculate Bitmap memory usage, so by default, + // don't do anything here } public void setBitmapCache(BitmapCache bitmapCache) { @@ -346,7 +390,7 @@ public class RemoteViews implements Parcelable, Filter { } if (target == root) { target.setTagInternal(com.android.internal.R.id.fillInIntent, fillInIntent); - } else if (target != null && fillInIntent != null) { + } else if (fillInIntent != null) { OnClickListener listener = new OnClickListener() { public void onClick(View v) { // Insure that this view is a child of an AdapterView @@ -372,16 +416,7 @@ public class RemoteViews implements Parcelable, Filter { PendingIntent pendingIntent = (PendingIntent) parent.getTag(); - final float appScale = v.getContext().getResources() - .getCompatibilityInfo().applicationScale; - final int[] pos = new int[2]; - v.getLocationOnScreen(pos); - - final Rect rect = new Rect(); - rect.left = (int) (pos[0] * appScale + 0.5f); - rect.top = (int) (pos[1] * appScale + 0.5f); - rect.right = (int) ((pos[0] + v.getWidth()) * appScale + 0.5f); - rect.bottom = (int) ((pos[1] + v.getHeight()) * appScale + 0.5f); + final Rect rect = getSourceBounds(v); fillInIntent.setSourceBounds(rect); handler.onClickHandler(v, pendingIntent, fillInIntent); @@ -452,16 +487,7 @@ public class RemoteViews implements Parcelable, Filter { } if (fillInIntent == null) return; - final float appScale = view.getContext().getResources() - .getCompatibilityInfo().applicationScale; - final int[] pos = new int[2]; - view.getLocationOnScreen(pos); - - final Rect rect = new Rect(); - rect.left = (int) (pos[0] * appScale + 0.5f); - rect.top = (int) (pos[1] * appScale + 0.5f); - rect.right = (int) ((pos[0] + view.getWidth()) * appScale + 0.5f); - rect.bottom = (int) ((pos[1] + view.getHeight()) * appScale + 0.5f); + final Rect rect = getSourceBounds(view); final Intent intent = new Intent(); intent.setSourceBounds(rect); @@ -679,33 +705,22 @@ public class RemoteViews implements Parcelable, Filter { } } - if (target != null) { - // If the pendingIntent is null, we clear the onClickListener - OnClickListener listener = null; - if (pendingIntent != null) { - listener = new OnClickListener() { - public void onClick(View v) { - // Find target view location in screen coordinates and - // fill into PendingIntent before sending. - final float appScale = v.getContext().getResources() - .getCompatibilityInfo().applicationScale; - final int[] pos = new int[2]; - v.getLocationOnScreen(pos); - - final Rect rect = new Rect(); - rect.left = (int) (pos[0] * appScale + 0.5f); - rect.top = (int) (pos[1] * appScale + 0.5f); - rect.right = (int) ((pos[0] + v.getWidth()) * appScale + 0.5f); - rect.bottom = (int) ((pos[1] + v.getHeight()) * appScale + 0.5f); + // If the pendingIntent is null, we clear the onClickListener + OnClickListener listener = null; + if (pendingIntent != null) { + listener = new OnClickListener() { + public void onClick(View v) { + // Find target view location in screen coordinates and + // fill into PendingIntent before sending. + final Rect rect = getSourceBounds(v); - final Intent intent = new Intent(); - intent.setSourceBounds(rect); - handler.onClickHandler(v, pendingIntent, intent); - } - }; - } - target.setOnClickListener(listener); + final Intent intent = new Intent(); + intent.setSourceBounds(rect); + handler.onClickHandler(v, pendingIntent, intent); + } + }; } + target.setOnClickListener(listener); } public String getActionName() { @@ -717,6 +732,67 @@ public class RemoteViews implements Parcelable, Filter { public final static int TAG = 1; } + private static Rect getSourceBounds(View v) { + final float appScale = v.getContext().getResources() + .getCompatibilityInfo().applicationScale; + final int[] pos = new int[2]; + v.getLocationOnScreen(pos); + + final Rect rect = new Rect(); + rect.left = (int) (pos[0] * appScale + 0.5f); + rect.top = (int) (pos[1] * appScale + 0.5f); + rect.right = (int) ((pos[0] + v.getWidth()) * appScale + 0.5f); + rect.bottom = (int) ((pos[1] + v.getHeight()) * appScale + 0.5f); + return rect; + } + + private Method getMethod(View view, String methodName, Class<?> paramType) { + Method method; + Class<? extends View> klass = view.getClass(); + + synchronized (sMethodsLock) { + ArrayMap<MutablePair<String, Class<?>>, Method> methods = sMethods.get(klass); + if (methods == null) { + methods = new ArrayMap<MutablePair<String, Class<?>>, Method>(); + sMethods.put(klass, methods); + } + + mPair.first = methodName; + mPair.second = paramType; + + method = methods.get(mPair); + if (method == null) { + try { + method = klass.getMethod(methodName, paramType); + } catch (NoSuchMethodException ex) { + throw new ActionException("view: " + klass.getName() + " doesn't have method: " + + methodName + getParameters(paramType)); + } + + if (!method.isAnnotationPresent(RemotableViewMethod.class)) { + throw new ActionException("view: " + klass.getName() + + " can't use method with RemoteViews: " + + methodName + getParameters(paramType)); + } + + methods.put(new MutablePair<String, Class<?>>(methodName, paramType), method); + } + } + + return method; + } + + private static String getParameters(Class<?> paramType) { + if (paramType == null) return "()"; + return "(" + paramType + ")"; + } + + private static Object[] wrapArg(Object value) { + Object[] args = sInvokeArgsTls.get(); + args[0] = value; + return args; + } + /** * Equivalent to calling a combination of {@link Drawable#setAlpha(int)}, * {@link Drawable#setColorFilter(int, android.graphics.PorterDuff.Mode)}, @@ -810,8 +886,8 @@ public class RemoteViews implements Parcelable, Filter { public final static int TAG = 3; } - private class ReflectionActionWithoutParams extends Action { - String methodName; + private final class ReflectionActionWithoutParams extends Action { + final String methodName; public final static int TAG = 5; @@ -836,28 +912,10 @@ public class RemoteViews implements Parcelable, Filter { final View view = root.findViewById(viewId); if (view == null) return; - Class klass = view.getClass(); - Method method; try { - method = klass.getMethod(this.methodName); - } catch (NoSuchMethodException ex) { - throw new ActionException("view: " + klass.getName() + " doesn't have method: " - + this.methodName + "()"); - } - - if (!method.isAnnotationPresent(RemotableViewMethod.class)) { - throw new ActionException("view: " + klass.getName() - + " can't use method with RemoteViews: " - + this.methodName + "()"); - } - - try { - //noinspection ConstantIfStatement - if (false) { - Log.d(LOG_TAG, "view: " + klass.getName() + " calling method: " - + this.methodName + "()"); - } - method.invoke(view); + getMethod(view, this.methodName, null).invoke(view); + } catch (ActionException e) { + throw e; } catch (Exception ex) { throw new ActionException(ex); } @@ -990,7 +1048,7 @@ public class RemoteViews implements Parcelable, Filter { /** * Base class for the reflection actions. */ - private class ReflectionAction extends Action { + private final class ReflectionAction extends Action { static final int TAG = 2; static final int BOOLEAN = 1; @@ -1157,7 +1215,7 @@ public class RemoteViews implements Parcelable, Filter { } } - private Class getParameterType() { + private Class<?> getParameterType() { switch (this.type) { case BOOLEAN: return boolean.class; @@ -1197,37 +1255,16 @@ public class RemoteViews implements Parcelable, Filter { final View view = root.findViewById(viewId); if (view == null) return; - Class param = getParameterType(); + Class<?> param = getParameterType(); if (param == null) { throw new ActionException("bad type: " + this.type); } - Class klass = view.getClass(); - Method method; try { - method = klass.getMethod(this.methodName, getParameterType()); - } - catch (NoSuchMethodException ex) { - throw new ActionException("view: " + klass.getName() + " doesn't have method: " - + this.methodName + "(" + param.getName() + ")"); - } - - if (!method.isAnnotationPresent(RemotableViewMethod.class)) { - throw new ActionException("view: " + klass.getName() - + " can't use method with RemoteViews: " - + this.methodName + "(" + param.getName() + ")"); - } - - try { - //noinspection ConstantIfStatement - if (false) { - Log.d(LOG_TAG, "view: " + klass.getName() + " calling method: " - + this.methodName + "(" + param.getName() + ") with " - + (this.value == null ? "null" : this.value.getClass().getName())); - } - method.invoke(view, this.value); - } - catch (Exception ex) { + getMethod(view, this.methodName, param).invoke(view, wrapArg(this.value)); + } catch (ActionException e) { + throw e; + } catch (Exception ex) { throw new ActionException(ex); } } @@ -1323,7 +1360,7 @@ public class RemoteViews implements Parcelable, Filter { } public String getActionName() { - return "ViewGroupAction" + this.nestedViews == null ? "Remove" : "Add"; + return "ViewGroupAction" + (nestedViews == null ? "Remove" : "Add"); } public int mergeBehavior() { @@ -1370,7 +1407,6 @@ public class RemoteViews implements Parcelable, Filter { @Override public void apply(View root, ViewGroup rootParent, OnClickHandler handler) { - final Context context = root.getContext(); final TextView target = (TextView) root.findViewById(viewId); if (target == null) return; if (isRelative) { @@ -1415,7 +1451,6 @@ public class RemoteViews implements Parcelable, Filter { @Override public void apply(View root, ViewGroup rootParent, OnClickHandler handler) { - final Context context = root.getContext(); final TextView target = (TextView) root.findViewById(viewId); if (target == null) return; target.setTextSize(units, size); @@ -1462,7 +1497,6 @@ public class RemoteViews implements Parcelable, Filter { @Override public void apply(View root, ViewGroup rootParent, OnClickHandler handler) { - final Context context = root.getContext(); final View target = root.findViewById(viewId); if (target == null) return; target.setPadding(left, top, right, bottom); @@ -1494,6 +1528,7 @@ public class RemoteViews implements Parcelable, Filter { return mMemoryUsage; } + @SuppressWarnings("deprecation") public void addBitmapMemory(Bitmap b) { final Bitmap.Config c = b.getConfig(); // If we don't know, be pessimistic and assume 4 @@ -1597,7 +1632,7 @@ public class RemoteViews implements Parcelable, Filter { if (mode == MODE_NORMAL) { mPackage = parcel.readString(); mLayoutId = parcel.readInt(); - mIsWidgetCollectionChild = parcel.readInt() == 1 ? true : false; + mIsWidgetCollectionChild = parcel.readInt() == 1; int count = parcel.readInt(); if (count > 0) { diff --git a/core/java/android/widget/ScrollView.java b/core/java/android/widget/ScrollView.java index 3d361f1..6680393 100644 --- a/core/java/android/widget/ScrollView.java +++ b/core/java/android/widget/ScrollView.java @@ -1473,7 +1473,7 @@ public class ScrollView extends FrameLayout { } mChildToScrollTo = null; - if (!hasLayout()) { + if (!isLaidOut()) { if (mSavedState != null) { mScrollY = mSavedState.scrollPosition; mSavedState = null; diff --git a/core/java/com/android/internal/app/IAppOpsService.aidl b/core/java/com/android/internal/app/IAppOpsService.aidl index a9da863..2dc822e 100644 --- a/core/java/com/android/internal/app/IAppOpsService.aidl +++ b/core/java/com/android/internal/app/IAppOpsService.aidl @@ -24,10 +24,11 @@ interface IAppOpsService { // be kept in sync with frameworks/native/include/binder/IAppOpsService.h int checkOperation(int code, int uid, String packageName); int noteOperation(int code, int uid, String packageName); - int startOperation(int code, int uid, String packageName); - void finishOperation(int code, int uid, String packageName); + int startOperation(IBinder token, int code, int uid, String packageName); + void finishOperation(IBinder token, int code, int uid, String packageName); void startWatchingMode(int op, String packageName, IAppOpsCallback callback); void stopWatchingMode(IAppOpsCallback callback); + IBinder getToken(IBinder clientToken); // Remaining methods are only used in Java. List<AppOpsManager.PackageOps> getPackagesForOps(in int[] ops); diff --git a/core/java/com/android/internal/app/RestrictionsPinActivity.java b/core/java/com/android/internal/app/RestrictionsPinActivity.java index 57436f7..f8ce108 100644 --- a/core/java/com/android/internal/app/RestrictionsPinActivity.java +++ b/core/java/com/android/internal/app/RestrictionsPinActivity.java @@ -26,6 +26,7 @@ import android.text.TextWatcher; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.View; +import android.view.WindowManager; import android.widget.EditText; import android.widget.TextView; import android.widget.TextView.OnEditorActionListener; @@ -39,17 +40,24 @@ import com.android.internal.R; public class RestrictionsPinActivity extends AlertActivity implements DialogInterface.OnClickListener, TextWatcher, OnEditorActionListener { - private UserManager mUserManager; + protected UserManager mUserManager; + protected boolean mHasRestrictionsPin; - private EditText mPin1Text; - private EditText mPin2Text; - private TextView mPinErrorMessage; - private TextView mPinMessage; + protected EditText mPinText; + protected TextView mPinErrorMessage; + protected TextView mPinMessage; @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); + mUserManager = (UserManager) getSystemService(Context.USER_SERVICE); + mHasRestrictionsPin = mUserManager.hasRestrictionsPin(); + initUi(); + setupAlert(); + } + + protected void initUi() { AlertController.AlertParams ap = mAlertParams; ap.mTitle = getString(R.string.restr_pin_enter_pin); ap.mPositiveButtonText = getString(R.string.ok); @@ -58,18 +66,12 @@ public class RestrictionsPinActivity extends AlertActivity ap.mNegativeButtonListener = this; LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE); - ap.mView = inflater.inflate(R.layout.pin_challenge, null); + ap.mView = inflater.inflate(R.layout.restrictions_pin_challenge, null); mPinMessage = (TextView) ap.mView.findViewById(R.id.pin_message); - mPin1Text = (EditText) ap.mView.findViewById(R.id.pin1_text); - mPin2Text = (EditText) ap.mView.findViewById(R.id.pin2_text); + mPinText = (EditText) ap.mView.findViewById(R.id.pin_text); mPinErrorMessage = (TextView) ap.mView.findViewById(R.id.pin_error_message); - mPin1Text.addTextChangedListener(this); - mPin2Text.addTextChangedListener(this); - - mUserManager = (UserManager) getSystemService(Context.USER_SERVICE); - - setupAlert(); + mPinText.addTextChangedListener(this); } protected boolean verifyingPin() { @@ -81,19 +83,12 @@ public class RestrictionsPinActivity extends AlertActivity setPositiveButtonState(false); boolean hasPin = mUserManager.hasRestrictionsPin(); - if (verifyingPin()) { - if (hasPin) { - mPinMessage.setVisibility(View.GONE); - mPinErrorMessage.setVisibility(View.GONE); - mPin2Text.setVisibility(View.GONE); - mPin1Text.setOnEditorActionListener(this); - updatePinTimer(-1); - } else { - setResult(RESULT_OK); - finish(); - } - } else if (hasPin) { - // Shouldn't really be in this state, exit + if (hasPin) { + mPinMessage.setVisibility(View.GONE); + mPinErrorMessage.setVisibility(View.GONE); + mPinText.setOnEditorActionListener(this); + updatePinTimer(-1); + } else if (verifyingPin()) { setResult(RESULT_OK); finish(); } @@ -114,14 +109,14 @@ public class RestrictionsPinActivity extends AlertActivity seconds); mPinErrorMessage.setText(String.format(formatString, seconds)); mPinErrorMessage.setVisibility(View.VISIBLE); - mPin1Text.setEnabled(false); - mPin1Text.setText(""); + mPinText.setEnabled(false); + mPinText.setText(""); setPositiveButtonState(false); - mPin1Text.postDelayed(mCountdownRunnable, Math.min(1000, pinTimerMs)); + mPinText.postDelayed(mCountdownRunnable, Math.min(1000, pinTimerMs)); } else { mPinErrorMessage.setVisibility(View.INVISIBLE); - mPin1Text.setEnabled(true); - mPin1Text.setText(""); + mPinText.setEnabled(true); + mPinText.setText(""); } } @@ -134,20 +129,13 @@ public class RestrictionsPinActivity extends AlertActivity } } - private void performPositiveButtonAction() { - if (verifyingPin()) { - int result = mUserManager.checkRestrictionsPin(mPin1Text.getText().toString()); - if (result == UserManager.PIN_VERIFICATION_SUCCESS) { - setResult(RESULT_OK); - finish(); - } else if (result >= 0) { - updatePinTimer(result); - } - } else { - if (mUserManager.changeRestrictionsPin(mPin1Text.getText().toString())) { - setResult(RESULT_OK); - finish(); - } + protected void performPositiveButtonAction() { + int result = mUserManager.checkRestrictionsPin(mPinText.getText().toString()); + if (result == UserManager.PIN_VERIFICATION_SUCCESS) { + setResult(RESULT_OK); + finish(); + } else if (result >= 0) { + updatePinTimer(result); } } @@ -157,16 +145,8 @@ public class RestrictionsPinActivity extends AlertActivity @Override public void onTextChanged(CharSequence s, int start, int before, int count) { - CharSequence pin1 = mPin1Text.getText(); - if (!verifyingPin()) { - CharSequence pin2 = mPin2Text.getText(); - boolean match = pin1 != null && pin2 != null && pin1.length() >= 4 - && pin1.toString().equals(pin2.toString()); - setPositiveButtonState(match); - mPinErrorMessage.setVisibility(match ? View.INVISIBLE : View.VISIBLE); - } else { - setPositiveButtonState(pin1 != null && pin1.length() >= 4); - } + CharSequence pin = mPinText.getText(); + setPositiveButtonState(pin != null && pin.length() >= 4); } @Override diff --git a/core/java/com/android/internal/app/RestrictionsPinSetupActivity.java b/core/java/com/android/internal/app/RestrictionsPinSetupActivity.java index 35f2967..1d09292 100644 --- a/core/java/com/android/internal/app/RestrictionsPinSetupActivity.java +++ b/core/java/com/android/internal/app/RestrictionsPinSetupActivity.java @@ -16,13 +16,115 @@ package com.android.internal.app; +import android.app.AlertDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.os.UserManager; +import android.text.Editable; +import android.text.TextUtils; +import android.view.KeyEvent; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.EditText; +import android.widget.TextView; + +import com.android.internal.R; + /** * This activity is launched by Settings and other apps to either create a new PIN or - * challenge for an existing PIN. The PIN is maintained by UserManager. + * change an existing PIN. The PIN is maintained by UserManager. */ public class RestrictionsPinSetupActivity extends RestrictionsPinActivity { + private EditText mNewPinText; + private EditText mConfirmPinText; + + protected void initUi() { + AlertController.AlertParams ap = mAlertParams; + ap.mTitle = getString(R.string.restr_pin_enter_pin); + ap.mPositiveButtonText = getString(R.string.ok); + ap.mNegativeButtonText = getString(R.string.cancel); + ap.mPositiveButtonListener = this; + ap.mNegativeButtonListener = this; + LayoutInflater inflater = + (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE); + ap.mView = inflater.inflate(R.layout.restrictions_pin_setup, null); + + mPinText = (EditText) ap.mView.findViewById(R.id.pin_text); + mPinMessage = (TextView) ap.mView.findViewById(R.id.pin_message); + mNewPinText = (EditText) ap.mView.findViewById(R.id.pin_new_text); + mConfirmPinText = (EditText) ap.mView.findViewById(R.id.pin_confirm_text); + mPinErrorMessage = (TextView) ap.mView.findViewById(R.id.pin_error_message); + mNewPinText.addTextChangedListener(this); + mConfirmPinText.addTextChangedListener(this); + + if (!mHasRestrictionsPin) { + mPinText.setVisibility(View.GONE); + } + } + + public void onResume() { + super.onResume(); + setPositiveButtonState(false); + } + protected boolean verifyingPin() { return false; } + + private void setPositiveButtonState(boolean enabled) { + mAlert.getButton(DialogInterface.BUTTON_POSITIVE).setEnabled(enabled); + } + + public void onClick(DialogInterface dialog, int which) { + setResult(RESULT_CANCELED); + if (which == AlertDialog.BUTTON_POSITIVE) { + performPositiveButtonAction(); + } else if (which == AlertDialog.BUTTON_NEGATIVE) { + finish(); + } + } + + protected void performPositiveButtonAction() { + if (mHasRestrictionsPin) { + int result = mUserManager.checkRestrictionsPin(mPinText.getText().toString()); + if (result != UserManager.PIN_VERIFICATION_SUCCESS) { + // TODO: Set message that existing pin doesn't match + return; + } + } + if (mUserManager.changeRestrictionsPin(mNewPinText.getText().toString())) { + // TODO: Send message to PIN recovery agent about the recovery email address + setResult(RESULT_OK); + finish(); + } + } + + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + CharSequence pin = mPinText.getText(); + CharSequence pin1 = mNewPinText.getText(); + CharSequence pin2 = mConfirmPinText.getText(); + boolean match = pin1 != null && pin2 != null && pin1.length() >= 4 + && pin1.toString().equals(pin2.toString()) + && (!mHasRestrictionsPin || (pin != null && pin.length() >= 4)); + boolean showError = !TextUtils.isEmpty(pin1) && !TextUtils.isEmpty(pin2); + // TODO: Check recovery email address as well + setPositiveButtonState(match); + mPinErrorMessage.setVisibility((match || !showError) ? View.INVISIBLE : View.VISIBLE); + } + + @Override + public void afterTextChanged(Editable s) { + } + + @Override + public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { + performPositiveButtonAction(); + return true; + } } diff --git a/core/java/com/android/internal/util/XmlUtils.java b/core/java/com/android/internal/util/XmlUtils.java index fa35308..f40f48c 100644 --- a/core/java/com/android/internal/util/XmlUtils.java +++ b/core/java/com/android/internal/util/XmlUtils.java @@ -796,16 +796,8 @@ public class XmlUtils { } throw new XmlPullParserException( "Unexpected end of document in <string>"); - } else if (tagName.equals("int")) { - res = Integer.parseInt(parser.getAttributeValue(null, "value")); - } else if (tagName.equals("long")) { - res = Long.valueOf(parser.getAttributeValue(null, "value")); - } else if (tagName.equals("float")) { - res = new Float(parser.getAttributeValue(null, "value")); - } else if (tagName.equals("double")) { - res = new Double(parser.getAttributeValue(null, "value")); - } else if (tagName.equals("boolean")) { - res = Boolean.valueOf(parser.getAttributeValue(null, "value")); + } else if ((res = readThisPrimitiveValueXml(parser, tagName)) != null) { + // all work already done by readThisPrimitiveValueXml } else if (tagName.equals("int-array")) { parser.next(); res = readThisIntArrayXml(parser, "int-array", name); @@ -858,6 +850,31 @@ public class XmlUtils { "Unexpected end of document in <" + tagName + ">"); } + private static final Object readThisPrimitiveValueXml(XmlPullParser parser, String tagName) + throws XmlPullParserException, java.io.IOException + { + try { + if (tagName.equals("int")) { + return Integer.parseInt(parser.getAttributeValue(null, "value")); + } else if (tagName.equals("long")) { + return Long.valueOf(parser.getAttributeValue(null, "value")); + } else if (tagName.equals("float")) { + return new Float(parser.getAttributeValue(null, "value")); + } else if (tagName.equals("double")) { + return new Double(parser.getAttributeValue(null, "value")); + } else if (tagName.equals("boolean")) { + return Boolean.valueOf(parser.getAttributeValue(null, "value")); + } else { + return null; + } + } catch (NullPointerException e) { + throw new XmlPullParserException("Need value attribute in <" + tagName + ">"); + } catch (NumberFormatException e) { + throw new XmlPullParserException( + "Not a number in value attribute in <" + tagName + ">"); + } + } + public static final void beginDocument(XmlPullParser parser, String firstElementName) throws XmlPullParserException, IOException { int type; diff --git a/core/java/com/android/internal/view/menu/ListMenuItemView.java b/core/java/com/android/internal/view/menu/ListMenuItemView.java index 35b76dd..df579c6 100644 --- a/core/java/com/android/internal/view/menu/ListMenuItemView.java +++ b/core/java/com/android/internal/view/menu/ListMenuItemView.java @@ -26,41 +26,48 @@ import android.view.ViewGroup; import android.widget.CheckBox; import android.widget.CompoundButton; import android.widget.ImageView; +import android.widget.LinearLayout; import android.widget.RadioButton; -import android.widget.RelativeLayout; import android.widget.TextView; /** * The item view for each item in the ListView-based MenuViews. */ -public class ListMenuItemView extends RelativeLayout implements MenuView.ItemView { - private final Drawable mBackground; - private final int mTextAppearance; - - private MenuItemImpl mItemData; - +public class ListMenuItemView extends LinearLayout implements MenuView.ItemView { + private static final String TAG = "ListMenuItemView"; + private MenuItemImpl mItemData; + private ImageView mIconView; private RadioButton mRadioButton; private TextView mTitleView; private CheckBox mCheckBox; private TextView mShortcutView; - + + private Drawable mBackground; + private int mTextAppearance; + private Context mTextAppearanceContext; + private boolean mPreserveIconSpacing; + + private int mMenuType; + private LayoutInflater mInflater; - private boolean mPreserveIconSpacing; private boolean mForceShowIcon; public ListMenuItemView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs); - - final TypedArray a = context.obtainStyledAttributes( + + TypedArray a = + context.obtainStyledAttributes( attrs, com.android.internal.R.styleable.MenuView, defStyle, 0); + mBackground = a.getDrawable(com.android.internal.R.styleable.MenuView_itemBackground); - mTextAppearance = a.getResourceId( - com.android.internal.R.styleable.MenuView_itemTextAppearance, 0); + mTextAppearance = a.getResourceId(com.android.internal.R.styleable. + MenuView_itemTextAppearance, -1); mPreserveIconSpacing = a.getBoolean( com.android.internal.R.styleable.MenuView_preserveIconSpacing, false); - + mTextAppearanceContext = context; + a.recycle(); } @@ -71,22 +78,24 @@ public class ListMenuItemView extends RelativeLayout implements MenuView.ItemVie @Override protected void onFinishInflate() { super.onFinishInflate(); - - setBackground(mBackground); - + + setBackgroundDrawable(mBackground); + mTitleView = (TextView) findViewById(com.android.internal.R.id.title); - if (mTextAppearance != 0) { - mTitleView.setTextAppearance(mContext, mTextAppearance); + if (mTextAppearance != -1) { + mTitleView.setTextAppearance(mTextAppearanceContext, + mTextAppearance); } - + mShortcutView = (TextView) findViewById(com.android.internal.R.id.shortcut); } - @Override public void initialize(MenuItemImpl itemData, int menuType) { mItemData = itemData; + mMenuType = menuType; setVisibility(itemData.isVisible() ? View.VISIBLE : View.GONE); + setTitle(itemData.getTitleForItemView(this)); setCheckable(itemData.isCheckable()); setShortcut(itemData.shouldShowShortcut(), itemData.getShortcut()); @@ -98,36 +107,29 @@ public class ListMenuItemView extends RelativeLayout implements MenuView.ItemVie mPreserveIconSpacing = mForceShowIcon = forceShow; } - @Override public void setTitle(CharSequence title) { if (title != null) { mTitleView.setText(title); - - if (mTitleView.getVisibility() != VISIBLE) { - mTitleView.setVisibility(VISIBLE); - } + + if (mTitleView.getVisibility() != VISIBLE) mTitleView.setVisibility(VISIBLE); } else { - if (mTitleView.getVisibility() != GONE) { - mTitleView.setVisibility(GONE); - } + if (mTitleView.getVisibility() != GONE) mTitleView.setVisibility(GONE); } } - - @Override + public MenuItemImpl getItemData() { return mItemData; } - @Override public void setCheckable(boolean checkable) { if (!checkable && mRadioButton == null && mCheckBox == null) { return; } - + // Depending on whether its exclusive check or not, the checkbox or // radio button will be the one in use (and the other will be otherCompoundButton) final CompoundButton compoundButton; - final CompoundButton otherCompoundButton; + final CompoundButton otherCompoundButton; if (mItemData.isExclusiveCheckable()) { if (mRadioButton == null) { @@ -142,36 +144,28 @@ public class ListMenuItemView extends RelativeLayout implements MenuView.ItemVie compoundButton = mCheckBox; otherCompoundButton = mRadioButton; } - + if (checkable) { compoundButton.setChecked(mItemData.isChecked()); - + final int newVisibility = checkable ? VISIBLE : GONE; if (compoundButton.getVisibility() != newVisibility) { compoundButton.setVisibility(newVisibility); } - - // Align text to the start of the visible compound button. - alignTextToStartOf(compoundButton); - + // Make sure the other compound button isn't visible if (otherCompoundButton != null && otherCompoundButton.getVisibility() != GONE) { otherCompoundButton.setVisibility(GONE); } } else { - if (mCheckBox != null) { - mCheckBox.setVisibility(GONE); - } - if (mRadioButton != null) { - mRadioButton.setVisibility(GONE); - } + if (mCheckBox != null) mCheckBox.setVisibility(GONE); + if (mRadioButton != null) mRadioButton.setVisibility(GONE); } } - - @Override + public void setChecked(boolean checked) { CompoundButton compoundButton; - + if (mItemData.isExclusiveCheckable()) { if (mRadioButton == null) { insertRadioButton(); @@ -183,13 +177,13 @@ public class ListMenuItemView extends RelativeLayout implements MenuView.ItemVie } compoundButton = mCheckBox; } - + compoundButton.setChecked(checked); } - @Override public void setShortcut(boolean showShortcut, char shortcutKey) { - final int newVisibility = (showShortcut && mItemData.shouldShowShortcut()) ? VISIBLE : GONE; + final int newVisibility = (showShortcut && mItemData.shouldShowShortcut()) + ? VISIBLE : GONE; if (newVisibility == VISIBLE) { mShortcutView.setText(mItemData.getShortcutLabel()); @@ -199,22 +193,21 @@ public class ListMenuItemView extends RelativeLayout implements MenuView.ItemVie mShortcutView.setVisibility(newVisibility); } } - - @Override + public void setIcon(Drawable icon) { final boolean showIcon = mItemData.shouldShowIcon() || mForceShowIcon; if (!showIcon && !mPreserveIconSpacing) { return; } - + if (mIconView == null && icon == null && !mPreserveIconSpacing) { return; } - + if (mIconView == null) { insertIconView(); } - + if (icon != null || mPreserveIconSpacing) { mIconView.setImageDrawable(showIcon ? icon : null); @@ -225,55 +218,51 @@ public class ListMenuItemView extends RelativeLayout implements MenuView.ItemVie mIconView.setVisibility(GONE); } } - + @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { if (mIconView != null && mPreserveIconSpacing) { // Enforce minimum icon spacing - final ViewGroup.LayoutParams lp = getLayoutParams(); - final LayoutParams iconLp = (LayoutParams) mIconView.getLayoutParams(); + ViewGroup.LayoutParams lp = getLayoutParams(); + LayoutParams iconLp = (LayoutParams) mIconView.getLayoutParams(); if (lp.height > 0 && iconLp.width <= 0) { iconLp.width = lp.height; } } - super.onMeasure(widthMeasureSpec, heightMeasureSpec); } private void insertIconView() { - mIconView = (ImageView) getInflater() - .inflate(com.android.internal.R.layout.list_menu_item_icon, this, false); - addView(mIconView); + LayoutInflater inflater = getInflater(); + mIconView = (ImageView) inflater.inflate(com.android.internal.R.layout.list_menu_item_icon, + this, false); + addView(mIconView, 0); } - + private void insertRadioButton() { - mRadioButton = (RadioButton) getInflater() - .inflate(com.android.internal.R.layout.list_menu_item_radio, this, false); + LayoutInflater inflater = getInflater(); + mRadioButton = + (RadioButton) inflater.inflate(com.android.internal.R.layout.list_menu_item_radio, + this, false); addView(mRadioButton); } - + private void insertCheckBox() { - mCheckBox = (CheckBox) getInflater() - .inflate(com.android.internal.R.layout.list_menu_item_checkbox, this, false); + LayoutInflater inflater = getInflater(); + mCheckBox = + (CheckBox) inflater.inflate(com.android.internal.R.layout.list_menu_item_checkbox, + this, false); addView(mCheckBox); } - private void alignTextToStartOf(View v) { - final LayoutParams params = (LayoutParams) mTitleView.getLayoutParams(); - params.addRule(RelativeLayout.START_OF, v.getId()); - mTitleView.setLayoutParams(params); - } - - @Override public boolean prefersCondensedTitle() { return false; } - @Override public boolean showsIcon() { return mForceShowIcon; } - + private LayoutInflater getInflater() { if (mInflater == null) { mInflater = LayoutInflater.from(mContext); diff --git a/core/java/com/android/internal/view/menu/MenuItemImpl.java b/core/java/com/android/internal/view/menu/MenuItemImpl.java index 3d6b116..4d0a326 100644 --- a/core/java/com/android/internal/view/menu/MenuItemImpl.java +++ b/core/java/com/android/internal/view/menu/MenuItemImpl.java @@ -616,7 +616,7 @@ public final class MenuItemImpl implements MenuItem { @Override public boolean expandActionView() { - if (hasCollapsibleActionView()) { + if (!hasCollapsibleActionView()) { return false; } diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp index 63683b4..b03d12a 100644 --- a/core/jni/android/graphics/Bitmap.cpp +++ b/core/jni/android/graphics/Bitmap.cpp @@ -271,6 +271,26 @@ static jboolean Bitmap_recycle(JNIEnv* env, jobject, SkBitmap* bitmap) { return true;
}
+static void Bitmap_reconfigure(JNIEnv* env, jobject clazz, jint bitmapInt,
+ int width, int height, SkBitmap::Config config, int allocSize) {
+ if (width * height * SkBitmap::ComputeBytesPerPixel(config) > allocSize) {
+ // done in native as there's no way to get BytesPerPixel in Java
+ doThrowIAE(env, "Bitmap not large enough to support new configuration");
+ return;
+ }
+ SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapInt);
+ SkPixelRef* ref = bitmap->pixelRef();
+ SkSafeRef(ref);
+ bitmap->setConfig(config, width, height);
+ bitmap->setPixelRef(ref);
+
+ // notifyPixelsChanged will increment the generation ID even though the actual pixel data
+ // hasn't been touched. This signals the renderer that the bitmap (including width, height,
+ // and config) has changed.
+ ref->notifyPixelsChanged();
+ SkSafeUnref(ref);
+}
+
// These must match the int values in Bitmap.java
enum JavaEncodeFormat {
kJPEG_JavaEncodeFormat = 0,
@@ -666,6 +686,7 @@ static JNINativeMethod gBitmapMethods[] = { (void*)Bitmap_copy },
{ "nativeDestructor", "(I)V", (void*)Bitmap_destructor },
{ "nativeRecycle", "(I)Z", (void*)Bitmap_recycle },
+ { "nativeReconfigure", "(IIIII)V", (void*)Bitmap_reconfigure },
{ "nativeCompress", "(IIILjava/io/OutputStream;[B)Z",
(void*)Bitmap_compress },
{ "nativeErase", "(II)V", (void*)Bitmap_erase },
diff --git a/core/jni/android/graphics/SurfaceTexture.cpp b/core/jni/android/graphics/SurfaceTexture.cpp index 753f5dc..bf9177b 100644 --- a/core/jni/android/graphics/SurfaceTexture.cpp +++ b/core/jni/android/graphics/SurfaceTexture.cpp @@ -197,10 +197,10 @@ static void SurfaceTexture_classInit(JNIEnv* env, jclass clazz) } } -static void SurfaceTexture_init(JNIEnv* env, jobject thiz, jint texName, - jobject weakThiz, jboolean allowSynchronous) +static void SurfaceTexture_init(JNIEnv* env, jobject thiz, jint texName, jobject weakThiz) { - sp<GLConsumer> surfaceTexture(new GLConsumer(texName, allowSynchronous)); + sp<BufferQueue> bq = new BufferQueue(); + sp<GLConsumer> surfaceTexture(new GLConsumer(bq, texName, GL_TEXTURE_EXTERNAL_OES, true, true)); if (surfaceTexture == 0) { jniThrowException(env, OutOfResourcesException, "Unable to create native SurfaceTexture"); @@ -285,7 +285,7 @@ static void SurfaceTexture_release(JNIEnv* env, jobject thiz) static JNINativeMethod gSurfaceTextureMethods[] = { {"nativeClassInit", "()V", (void*)SurfaceTexture_classInit }, - {"nativeInit", "(ILjava/lang/Object;Z)V", (void*)SurfaceTexture_init }, + {"nativeInit", "(ILjava/lang/Object;)V", (void*)SurfaceTexture_init }, {"nativeFinalize", "()V", (void*)SurfaceTexture_finalize }, {"nativeSetDefaultBufferSize", "(II)V", (void*)SurfaceTexture_setDefaultBufferSize }, {"nativeUpdateTexImage", "()V", (void*)SurfaceTexture_updateTexImage }, diff --git a/core/jni/android_hardware_photography_CameraMetadata.cpp b/core/jni/android_hardware_photography_CameraMetadata.cpp index 5070d2c..5190a37 100644 --- a/core/jni/android_hardware_photography_CameraMetadata.cpp +++ b/core/jni/android_hardware_photography_CameraMetadata.cpp @@ -267,7 +267,13 @@ static void CameraMetadata_writeValues(JNIEnv *env, jobject thiz, jint tag, jbyt if (src == NULL) { // If array is NULL, delete the entry - res = metadata->erase(tag); + if (metadata->exists(tag)) { + res = metadata->erase(tag); + ALOGV("%s: Erase values (res = %d)", __FUNCTION__, res); + } else { + res = OK; + ALOGV("%s: Don't need to erase", __FUNCTION__); + } } else { // Copy from java array into native array ScopedByteArrayRO arrayReader(env, src); @@ -275,6 +281,8 @@ static void CameraMetadata_writeValues(JNIEnv *env, jobject thiz, jint tag, jbyt res = Helpers::updateAny(metadata, static_cast<uint32_t>(tag), tagType, arrayReader.get(), arrayReader.size()); + + ALOGV("%s: Update values (res = %d)", __FUNCTION__, res); } if (res == OK) { diff --git a/core/jni/android_media_AudioRecord.cpp b/core/jni/android_media_AudioRecord.cpp index 197d240..44e43e7 100644 --- a/core/jni/android_media_AudioRecord.cpp +++ b/core/jni/android_media_AudioRecord.cpp @@ -18,22 +18,12 @@ #define LOG_TAG "AudioRecord-JNI" -#include <stdio.h> -#include <unistd.h> -#include <fcntl.h> -#include <math.h> - #include <jni.h> #include <JNIHelp.h> #include <android_runtime/AndroidRuntime.h> #include <utils/Log.h> -#include <utils/SortedVector.h> -#include <utils/threads.h> #include <media/AudioRecord.h> -#include <media/mediarecorder.h> - -#include <cutils/bitops.h> #include <system/audio.h> @@ -402,10 +392,13 @@ static jint android_media_AudioRecord_readInShortArray(JNIEnv *env, jobject thi jshortArray javaAudioData, jint offsetInShorts, jint sizeInShorts) { - return (android_media_AudioRecord_readInByteArray(env, thiz, + jint read = android_media_AudioRecord_readInByteArray(env, thiz, (jbyteArray) javaAudioData, - offsetInShorts*2, sizeInShorts*2) - / 2); + offsetInShorts*2, sizeInShorts*2); + if (read > 0) { + read /= 2; + } + return read; } // ---------------------------------------------------------------------------- diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp index 67c2cfd..d6c5e4f 100644 --- a/core/jni/android_media_AudioSystem.cpp +++ b/core/jni/android_media_AudioSystem.cpp @@ -18,11 +18,6 @@ #define LOG_TAG "AudioSystem" #include <utils/Log.h> -#include <stdio.h> -#include <unistd.h> -#include <fcntl.h> -#include <math.h> - #include <jni.h> #include <JNIHelp.h> #include <android_runtime/AndroidRuntime.h> @@ -117,10 +112,36 @@ android_media_AudioSystem_getParameters(JNIEnv *env, jobject thiz, jstring keys) return env->NewStringUTF(AudioSystem::getParameters(0, c_keys8).string()); } +static JNIEnv* AudioSystem_getJNIEnv(bool* needsDetach) { + *needsDetach = false; + JNIEnv* env = AndroidRuntime::getJNIEnv(); + if (env == NULL) { + JavaVMAttachArgs args = {JNI_VERSION_1_4, NULL, NULL}; + JavaVM* vm = AndroidRuntime::getJavaVM(); + int result = vm->AttachCurrentThread(&env, (void*) &args); + if (result != JNI_OK) { + ALOGE("thread attach failed: %#x", result); + return NULL; + } + *needsDetach = true; + } + return env; +} + +static void AudioSystem_detachJNI() { + JavaVM* vm = AndroidRuntime::getJavaVM(); + int result = vm->DetachCurrentThread(); + if (result != JNI_OK) { + ALOGE("thread detach failed: %#x", result); + } +} + static void android_media_AudioSystem_error_callback(status_t err) { - JNIEnv *env = AndroidRuntime::getJNIEnv(); + bool needsDetach = false; + JNIEnv *env = AudioSystem_getJNIEnv(&needsDetach); + if (env == NULL) { return; } @@ -142,6 +163,10 @@ android_media_AudioSystem_error_callback(status_t err) } env->CallStaticVoidMethod(clazz, env->GetStaticMethodID(clazz, "errorCallbackFromNative","(I)V"), error); + + if (needsDetach) { + AudioSystem_detachJNI(); + } } static int @@ -282,6 +307,12 @@ android_media_AudioSystem_getOutputLatency(JNIEnv *env, jobject clazz, jint stre return (jint) afLatency; } +static jint +android_media_AudioSystem_setLowRamDevice(JNIEnv *env, jobject clazz, jboolean isLowRamDevice) +{ + return (jint) AudioSystem::setLowRamDevice((bool) isLowRamDevice); +} + // ---------------------------------------------------------------------------- static JNINativeMethod gMethods[] = { @@ -308,6 +339,7 @@ static JNINativeMethod gMethods[] = { {"getPrimaryOutputSamplingRate", "()I", (void *)android_media_AudioSystem_getPrimaryOutputSamplingRate}, {"getPrimaryOutputFrameCount", "()I", (void *)android_media_AudioSystem_getPrimaryOutputFrameCount}, {"getOutputLatency", "(I)I", (void *)android_media_AudioSystem_getOutputLatency}, + {"setLowRamDevice", "(Z)I", (void *)android_media_AudioSystem_setLowRamDevice}, }; int register_android_media_AudioSystem(JNIEnv *env) diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp index 1a73f42..f2da865 100644 --- a/core/jni/android_media_AudioTrack.cpp +++ b/core/jni/android_media_AudioTrack.cpp @@ -17,11 +17,6 @@ #define LOG_TAG "AudioTrack-JNI" -#include <stdio.h> -#include <unistd.h> -#include <fcntl.h> -#include <math.h> - #include <jni.h> #include <JNIHelp.h> #include <android_runtime/AndroidRuntime.h> @@ -33,8 +28,6 @@ #include <binder/MemoryHeapBase.h> #include <binder/MemoryBase.h> -#include <cutils/bitops.h> - #include <system/audio.h> // ---------------------------------------------------------------------------- @@ -47,8 +40,6 @@ static const char* const kClassPathName = "android/media/AudioTrack"; struct fields_t { // these fields provide access from C++ to the... jmethodID postNativeEventInJava; //... event post callback method - int PCM16; //... format constants - int PCM8; //... format constants jfieldID nativeTrackInJavaObj; // stores in Java the native AudioTrack object jfieldID jniData; // stores in Java additional resources used by the native AudioTrack }; @@ -64,6 +55,9 @@ struct audiotrack_callback_cookie { // keep these values in sync with AudioTrack.java #define MODE_STATIC 0 #define MODE_STREAM 1 +// keep these values in sync with AudioFormat.java +#define ENCODING_PCM_16BIT 2 +#define ENCODING_PCM_8BIT 3 // ---------------------------------------------------------------------------- class AudioTrackJniStorage { @@ -251,7 +245,8 @@ android_media_AudioTrack_native_setup(JNIEnv *env, jobject thiz, jobject weak_th // check the format. // This function was called from Java, so we compare the format against the Java constants - if ((audioFormat != javaAudioTrackFields.PCM16) && (audioFormat != javaAudioTrackFields.PCM8)) { + if ((audioFormat != ENCODING_PCM_16BIT) && (audioFormat != ENCODING_PCM_8BIT)) { + ALOGE("Error creating AudioTrack: unsupported audio format."); return AUDIOTRACK_ERROR_SETUP_INVALIDFORMAT; } @@ -259,19 +254,19 @@ android_media_AudioTrack_native_setup(JNIEnv *env, jobject thiz, jobject weak_th // for the moment 8bitPCM in MODE_STATIC is not supported natively in the AudioTrack C++ class // so we declare everything as 16bitPCM, the 8->16bit conversion for MODE_STATIC will be handled // in android_media_AudioTrack_native_write_byte() - if ((audioFormat == javaAudioTrackFields.PCM8) + if ((audioFormat == ENCODING_PCM_8BIT) && (memoryMode == MODE_STATIC)) { ALOGV("android_media_AudioTrack_native_setup(): requesting MODE_STATIC for 8bit \ buff size of %dbytes, switching to 16bit, buff size of %dbytes", buffSizeInBytes, 2*buffSizeInBytes); - audioFormat = javaAudioTrackFields.PCM16; + audioFormat = ENCODING_PCM_16BIT; // we will need twice the memory to store the data buffSizeInBytes *= 2; } // compute the frame count - int bytesPerSample = audioFormat == javaAudioTrackFields.PCM16 ? 2 : 1; - audio_format_t format = audioFormat == javaAudioTrackFields.PCM16 ? + int bytesPerSample = audioFormat == ENCODING_PCM_16BIT ? 2 : 1; + audio_format_t format = audioFormat == ENCODING_PCM_16BIT ? AUDIO_FORMAT_PCM_16_BIT : AUDIO_FORMAT_PCM_8_BIT; int frameCount = buffSizeInBytes / (nbChannels * bytesPerSample); @@ -520,15 +515,19 @@ jint writeToTrack(const sp<AudioTrack>& track, jint audioFormat, jbyte* data, // regular write() or copy the data to the AudioTrack's shared memory? if (track->sharedBuffer() == 0) { written = track->write(data + offsetInBytes, sizeInBytes); + // for compatibility with earlier behavior of write(), return 0 in this case + if (written == (ssize_t) WOULD_BLOCK) { + written = 0; + } } else { - if (audioFormat == javaAudioTrackFields.PCM16) { + if (audioFormat == ENCODING_PCM_16BIT) { // writing to shared memory, check for capacity if ((size_t)sizeInBytes > track->sharedBuffer()->size()) { sizeInBytes = track->sharedBuffer()->size(); } memcpy(track->sharedBuffer()->pointer(), data + offsetInBytes, sizeInBytes); written = sizeInBytes; - } else if (audioFormat == javaAudioTrackFields.PCM8) { + } else if (audioFormat == ENCODING_PCM_8BIT) { // data contains 8bit data we need to expand to 16bit before copying // to the shared memory // writing to shared memory, check for capacity, @@ -812,7 +811,7 @@ static jint android_media_AudioTrack_get_min_buff_size(JNIEnv *env, jobject thi sampleRateInHertz) != NO_ERROR) { return -1; } - return frameCount * nbChannels * (audioFormat == javaAudioTrackFields.PCM16 ? 2 : 1); + return frameCount * nbChannels * (audioFormat == ENCODING_PCM_16BIT ? 2 : 1); } // ---------------------------------------------------------------------------- @@ -886,8 +885,6 @@ static JNINativeMethod gMethods[] = { // field names found in android/media/AudioTrack.java #define JAVA_POSTEVENT_CALLBACK_NAME "postEventFromNative" -#define JAVA_CONST_PCM16_NAME "ENCODING_PCM_16BIT" -#define JAVA_CONST_PCM8_NAME "ENCODING_PCM_8BIT" #define JAVA_CONST_BUFFER_COUNT_NAME "BUFFER_COUNT" #define JAVA_CONST_STREAM_VOICE_CALL_NAME "STREAM_VOICE_CALL" #define JAVA_CONST_STREAM_SYSTEM_NAME "STREAM_SYSTEM" @@ -967,15 +964,6 @@ int register_android_media_AudioTrack(JNIEnv *env) ALOGE("Can't find %s", JAVA_AUDIOFORMAT_CLASS_NAME); return -1; } - if ( !android_media_getIntConstantFromClass(env, audioFormatClass, - JAVA_AUDIOFORMAT_CLASS_NAME, - JAVA_CONST_PCM16_NAME, &(javaAudioTrackFields.PCM16)) - || !android_media_getIntConstantFromClass(env, audioFormatClass, - JAVA_AUDIOFORMAT_CLASS_NAME, - JAVA_CONST_PCM8_NAME, &(javaAudioTrackFields.PCM8)) ) { - // error log performed in android_media_getIntConstantFromClass() - return -1; - } return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods)); } diff --git a/core/jni/android_net_LocalSocketImpl.cpp b/core/jni/android_net_LocalSocketImpl.cpp index f2b69c6..b9ed28e 100644 --- a/core/jni/android_net_LocalSocketImpl.cpp +++ b/core/jni/android_net_LocalSocketImpl.cpp @@ -44,26 +44,6 @@ static jclass class_Credentials; static jclass class_FileDescriptor; static jmethodID method_CredentialsInit; -/* - * private native FileDescriptor - * create_native(boolean stream) - * throws IOException; - */ -static jobject -socket_create (JNIEnv *env, jobject object, jboolean stream) -{ - int ret; - - ret = socket(PF_LOCAL, stream ? SOCK_STREAM : SOCK_DGRAM, 0); - - if (ret < 0) { - jniThrowIOException(env, errno); - return NULL; - } - - return jniCreateFileDescriptor(env,ret); -} - /* private native void connectLocal(FileDescriptor fd, * String name, int namespace) throws IOException */ @@ -445,32 +425,6 @@ static jint socket_available (JNIEnv *env, jobject object, #endif } -static void socket_close (JNIEnv *env, jobject object, jobject fileDescriptor) -{ - int fd; - int err; - - if (fileDescriptor == NULL) { - jniThrowNullPointerException(env, NULL); - return; - } - - fd = jniGetFDFromFileDescriptor(env, fileDescriptor); - - if (env->ExceptionOccurred() != NULL) { - return; - } - - do { - err = close(fd); - } while (err < 0 && errno == EINTR); - - if (err < 0) { - jniThrowIOException(env, errno); - return; - } -} - /** * Processes ancillary data, handling only * SCM_RIGHTS. Creates appropriate objects and sets appropriate @@ -909,7 +863,6 @@ static JNINativeMethod gMethods[] = { /* name, signature, funcPtr */ {"getOption_native", "(Ljava/io/FileDescriptor;I)I", (void*)socket_getOption}, {"setOption_native", "(Ljava/io/FileDescriptor;III)V", (void*)socket_setOption}, - {"create_native", "(Z)Ljava/io/FileDescriptor;", (void*)socket_create}, {"connectLocal", "(Ljava/io/FileDescriptor;Ljava/lang/String;I)V", (void*)socket_connect_local}, {"bindLocal", "(Ljava/io/FileDescriptor;Ljava/lang/String;I)V", (void*)socket_bind_local}, @@ -918,7 +871,6 @@ static JNINativeMethod gMethods[] = { {"shutdown", "(Ljava/io/FileDescriptor;Z)V", (void*)socket_shutdown}, {"available_native", "(Ljava/io/FileDescriptor;)I", (void*) socket_available}, {"pending_native", "(Ljava/io/FileDescriptor;)I", (void*) socket_pending}, - {"close_native", "(Ljava/io/FileDescriptor;)V", (void*) socket_close}, {"read_native", "(Ljava/io/FileDescriptor;)I", (void*) socket_read}, {"readba_native", "([BIILjava/io/FileDescriptor;)I", (void*) socket_readba}, {"writeba_native", "([BIILjava/io/FileDescriptor;)V", (void*) socket_writeba}, diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp index 8b7f3dd..61ace4a 100644 --- a/core/jni/android_os_Debug.cpp +++ b/core/jni/android_os_Debug.cpp @@ -380,10 +380,11 @@ static void android_os_Debug_getDirtyPages(JNIEnv *env, jobject clazz, jobject o android_os_Debug_getDirtyPagesPid(env, clazz, getpid(), object); } -static jlong android_os_Debug_getPssPid(JNIEnv *env, jobject clazz, jint pid) +static jlong android_os_Debug_getPssPid(JNIEnv *env, jobject clazz, jint pid, jlongArray outUss) { char line[1024]; jlong pss = 0; + jlong uss = 0; unsigned temp; char tmp[128]; @@ -398,23 +399,42 @@ static jlong android_os_Debug_getPssPid(JNIEnv *env, jobject clazz, jint pid) break; } - if (strncmp(line, "Pss: ", 5) == 0) { - char* c = line + 5; - while (*c != 0 && (*c < '0' || *c > '9')) { - c++; + if (line[0] == 'P') { + if (strncmp(line, "Pss:", 4) == 0) { + char* c = line + 4; + while (*c != 0 && (*c < '0' || *c > '9')) { + c++; + } + pss += atoi(c); + } else if (strncmp(line, "Private_Clean:", 14) + || strncmp(line, "Private_Dirty:", 14)) { + char* c = line + 14; + while (*c != 0 && (*c < '0' || *c > '9')) { + c++; + } + uss += atoi(c); } - pss += atoi(c); } } fclose(fp); + if (outUss != NULL) { + if (env->GetArrayLength(outUss) >= 1) { + jlong* outUssArray = env->GetLongArrayElements(outUss, 0); + if (outUssArray != NULL) { + outUssArray[0] = uss; + } + env->ReleaseLongArrayElements(outUss, outUssArray, 0); + } + } + return pss; } static jlong android_os_Debug_getPss(JNIEnv *env, jobject clazz) { - return android_os_Debug_getPssPid(env, clazz, getpid()); + return android_os_Debug_getPssPid(env, clazz, getpid(), NULL); } static jint read_binder_stat(const char* stat) @@ -689,7 +709,7 @@ static JNINativeMethod gMethods[] = { (void*) android_os_Debug_getDirtyPagesPid }, { "getPss", "()J", (void*) android_os_Debug_getPss }, - { "getPss", "(I)J", + { "getPss", "(I[J)J", (void*) android_os_Debug_getPssPid }, { "dumpNativeHeap", "(Ljava/io/FileDescriptor;)V", (void*) android_os_Debug_dumpNativeHeap }, diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp index 33ded03..6d97d01 100644 --- a/core/jni/android_util_Process.cpp +++ b/core/jni/android_util_Process.cpp @@ -33,6 +33,7 @@ #include <sys/errno.h> #include <sys/resource.h> #include <sys/types.h> +#include <sys/stat.h> #include <dirent.h> #include <fcntl.h> #include <grp.h> @@ -381,6 +382,32 @@ jboolean android_os_Process_setOomAdj(JNIEnv* env, jobject clazz, return false; } +jboolean android_os_Process_setSwappiness(JNIEnv *env, jobject clazz, + jint pid, jboolean is_increased) +{ + char text[64]; + + if (is_increased) { + strcpy(text, "/sys/fs/cgroup/memory/sw/tasks"); + } else { + strcpy(text, "/sys/fs/cgroup/memory/tasks"); + } + + struct stat st; + if (stat(text, &st) || !S_ISREG(st.st_mode)) { + return false; + } + + int fd = open(text, O_WRONLY); + if (fd >= 0) { + sprintf(text, "%d", pid); + write(fd, text, strlen(text)); + close(fd); + } + + return true; +} + void android_os_Process_setArgV0(JNIEnv* env, jobject clazz, jstring name) { if (name == NULL) { @@ -1022,6 +1049,7 @@ static const JNINativeMethod methods[] = { {"setProcessGroup", "(II)V", (void*)android_os_Process_setProcessGroup}, {"getProcessGroup", "(I)I", (void*)android_os_Process_getProcessGroup}, {"setOomAdj", "(II)Z", (void*)android_os_Process_setOomAdj}, + {"setSwappiness", "(IZ)Z", (void*)android_os_Process_setSwappiness}, {"setArgV0", "(Ljava/lang/String;)V", (void*)android_os_Process_setArgV0}, {"setUid", "(I)I", (void*)android_os_Process_setUid}, {"setGid", "(I)I", (void*)android_os_Process_setGid}, diff --git a/core/jni/android_view_InputDevice.cpp b/core/jni/android_view_InputDevice.cpp index 8ef5d0b..e5e3db0 100644 --- a/core/jni/android_view_InputDevice.cpp +++ b/core/jni/android_view_InputDevice.cpp @@ -57,7 +57,7 @@ jobject android_view_InputDevice_create(JNIEnv* env, const InputDeviceInfo& devi gInputDeviceClassInfo.ctor, deviceInfo.getId(), deviceInfo.getGeneration(), nameObj.get(), descriptorObj.get(), deviceInfo.isExternal(), deviceInfo.getSources(), deviceInfo.getKeyboardType(), - kcmObj.get(), deviceInfo.hasVibrator())); + kcmObj.get(), deviceInfo.hasVibrator(), deviceInfo.hasButtonUnderPad())); const Vector<InputDeviceInfo::MotionRange>& ranges = deviceInfo.getMotionRanges(); for (size_t i = 0; i < ranges.size(); i++) { @@ -86,8 +86,8 @@ int register_android_view_InputDevice(JNIEnv* env) FIND_CLASS(gInputDeviceClassInfo.clazz, "android/view/InputDevice"); gInputDeviceClassInfo.clazz = jclass(env->NewGlobalRef(gInputDeviceClassInfo.clazz)); - GET_METHOD_ID(gInputDeviceClassInfo.ctor, gInputDeviceClassInfo.clazz, - "<init>", "(IILjava/lang/String;Ljava/lang/String;ZIILandroid/view/KeyCharacterMap;Z)V"); + GET_METHOD_ID(gInputDeviceClassInfo.ctor, gInputDeviceClassInfo.clazz, "<init>", + "(IILjava/lang/String;Ljava/lang/String;ZIILandroid/view/KeyCharacterMap;ZZ)V"); GET_METHOD_ID(gInputDeviceClassInfo.addMotionRange, gInputDeviceClassInfo.clazz, "addMotionRange", "(IIFFFFF)V"); diff --git a/core/jni/android_view_MotionEvent.cpp b/core/jni/android_view_MotionEvent.cpp index 73c0683..ad6c0f2 100644 --- a/core/jni/android_view_MotionEvent.cpp +++ b/core/jni/android_view_MotionEvent.cpp @@ -18,6 +18,7 @@ #include "JNIHelp.h" +#include <SkMatrix.h> #include <android_runtime/AndroidRuntime.h> #include <utils/Log.h> #include <input/Input.h> @@ -26,9 +27,6 @@ #include "android_util_Binder.h" #include "android/graphics/Matrix.h" -#include "SkMatrix.h" - - namespace android { // ---------------------------------------------------------------------------- @@ -680,7 +678,18 @@ static void android_view_MotionEvent_nativeTransform(JNIEnv* env, jclass clazz, jint nativePtr, jobject matrixObj) { SkMatrix* matrix = android_graphics_Matrix_getSkMatrix(env, matrixObj); MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr); - event->transform(matrix); + + float m[9]; + m[0] = SkScalarToFloat(matrix->get(SkMatrix::kMScaleX)); + m[1] = SkScalarToFloat(matrix->get(SkMatrix::kMSkewX)); + m[2] = SkScalarToFloat(matrix->get(SkMatrix::kMTransX)); + m[3] = SkScalarToFloat(matrix->get(SkMatrix::kMSkewY)); + m[4] = SkScalarToFloat(matrix->get(SkMatrix::kMScaleY)); + m[5] = SkScalarToFloat(matrix->get(SkMatrix::kMTransY)); + m[6] = SkScalarToFloat(matrix->get(SkMatrix::kMPersp0)); + m[7] = SkScalarToFloat(matrix->get(SkMatrix::kMPersp1)); + m[8] = SkScalarToFloat(matrix->get(SkMatrix::kMPersp2)); + event->transform(m); } static jint android_view_MotionEvent_nativeReadFromParcel(JNIEnv* env, jclass clazz, diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp index 842a7f7..bf6753d 100644 --- a/core/jni/android_view_Surface.cpp +++ b/core/jni/android_view_Surface.cpp @@ -107,7 +107,7 @@ jobject android_view_Surface_createFromIGraphicBufferProducer(JNIEnv* env, return NULL; } - sp<Surface> surface(new Surface(bufferProducer)); + sp<Surface> surface(new Surface(bufferProducer, true)); if (surface == NULL) { return NULL; } @@ -143,7 +143,7 @@ static jint nativeCreateFromSurfaceTexture(JNIEnv* env, jclass clazz, } sp<IGraphicBufferProducer> bq = st->getBufferQueue(); - sp<Surface> surface(new Surface(bq)); + sp<Surface> surface(new Surface(bq, true)); if (surface == NULL) { jniThrowException(env, OutOfResourcesException, NULL); return 0; @@ -319,7 +319,7 @@ static jint nativeReadFromParcel(JNIEnv* env, jclass clazz, sp<IGraphicBufferProducer> gbp(interface_cast<IGraphicBufferProducer>(binder)); if (gbp != NULL) { // we have a new IGraphicBufferProducer, create a new Surface for it - sur = new Surface(gbp); + sur = new Surface(gbp, true); // and keep a reference before passing to java sur->incStrong(&sRefBaseOwner); } diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index bfd7560..fb8359b 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -2513,6 +2513,12 @@ </intent-filter> </receiver> + <receiver android:name="com.android.server.updates.CarrierProvisioningUrlsInstallReceiver" > + <intent-filter> + <action android:name="android.intent.action.UPDATE_CARRIER_PROVISIONING_URLS" /> + </intent-filter> + </receiver> + <receiver android:name="com.android.server.updates.TZInfoInstallReceiver" > <intent-filter> <action android:name="android.intent.action.UPDATE_TZINFO" /> diff --git a/core/res/res/layout/list_menu_item_checkbox.xml b/core/res/res/layout/list_menu_item_checkbox.xml index 02febc4..dc02a1e 100644 --- a/core/res/res/layout/list_menu_item_checkbox.xml +++ b/core/res/res/layout/list_menu_item_checkbox.xml @@ -4,9 +4,9 @@ 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. @@ -18,8 +18,9 @@ android:id="@+id/checkbox" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_alignParentEnd="true" - android:layout_centerVertical="true" + android:layout_gravity="center_vertical" android:focusable="false" android:clickable="false" android:duplicateParentState="true" /> + + diff --git a/core/res/res/layout/list_menu_item_icon.xml b/core/res/res/layout/list_menu_item_icon.xml index 89b6b09..a30be6a 100644 --- a/core/res/res/layout/list_menu_item_icon.xml +++ b/core/res/res/layout/list_menu_item_icon.xml @@ -4,9 +4,9 @@ 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. @@ -18,12 +18,11 @@ android:id="@+id/icon" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_centerVertical="true" - android:layout_alignParentStart="true" + android:layout_gravity="center_vertical" android:layout_marginStart="8dip" android:layout_marginEnd="-8dip" android:layout_marginTop="8dip" android:layout_marginBottom="8dip" android:scaleType="centerInside" - android:duplicateParentState="true" - android:contentDescription="@null" /> + android:duplicateParentState="true" /> + diff --git a/core/res/res/layout/list_menu_item_layout.xml b/core/res/res/layout/list_menu_item_layout.xml index 3130215..e8d4983 100644 --- a/core/res/res/layout/list_menu_item_layout.xml +++ b/core/res/res/layout/list_menu_item_layout.xml @@ -4,9 +4,9 @@ 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. @@ -16,38 +16,46 @@ <com.android.internal.view.menu.ListMenuItemView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" - android:layout_height="?android:attr/listPreferredItemHeightSmall" - android:gravity="start|center_vertical"> - + android:layout_height="?android:attr/listPreferredItemHeightSmall"> + <!-- Icon will be inserted here. --> - - <TextView - android:id="@+id/title" - android:layout_width="wrap_content" + + <!-- The title and summary have some gap between them, and this 'group' should be centered vertically. --> + <RelativeLayout + android:layout_width="0dip" + android:layout_weight="1" android:layout_height="wrap_content" - android:layout_alignWithParentIfMissing="true" + android:layout_gravity="center_vertical" android:layout_marginStart="?android:attr/listPreferredItemPaddingStart" android:layout_marginEnd="?android:attr/listPreferredItemPaddingEnd" - android:layout_toEndOf="@id/icon" - android:textAppearance="?android:attr/textAppearanceListItemSmall" - android:singleLine="true" - android:duplicateParentState="true" - android:ellipsize="marquee" - android:fadingEdge="horizontal" - android:textAlignment="viewStart" /> - - <TextView - android:id="@+id/shortcut" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_below="@id/title" - android:layout_alignStart="@id/title" - android:layout_alignWithParentIfMissing="true" - android:textAppearance="?android:attr/textAppearanceSmall" - android:singleLine="true" - android:duplicateParentState="true" - android:textAlignment="viewStart" /> + android:duplicateParentState="true"> + + <TextView + android:id="@+id/title" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_alignParentTop="true" + android:layout_alignParentStart="true" + android:textAppearance="?android:attr/textAppearanceListItemSmall" + android:singleLine="true" + android:duplicateParentState="true" + android:ellipsize="marquee" + android:fadingEdge="horizontal" + android:textAlignment="viewStart" /> + + <TextView + android:id="@+id/shortcut" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_below="@id/title" + android:layout_alignParentStart="true" + android:textAppearance="?android:attr/textAppearanceSmall" + android:singleLine="true" + android:duplicateParentState="true" + android:textAlignment="viewStart" /> + + </RelativeLayout> <!-- Checkbox, and/or radio button will be inserted here. --> - + </com.android.internal.view.menu.ListMenuItemView> diff --git a/core/res/res/layout/list_menu_item_radio.xml b/core/res/res/layout/list_menu_item_radio.xml index 74564ad..ac4459e 100644 --- a/core/res/res/layout/list_menu_item_radio.xml +++ b/core/res/res/layout/list_menu_item_radio.xml @@ -4,9 +4,9 @@ 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. @@ -18,8 +18,7 @@ android:id="@+id/radio" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_alignParentEnd="true" - android:layout_centerVertical="true" + android:layout_gravity="center_vertical" android:focusable="false" android:clickable="false" android:duplicateParentState="true" /> diff --git a/core/res/res/layout/popup_menu_item_layout.xml b/core/res/res/layout/popup_menu_item_layout.xml index aff3779..452f85d 100644 --- a/core/res/res/layout/popup_menu_item_layout.xml +++ b/core/res/res/layout/popup_menu_item_layout.xml @@ -4,9 +4,9 @@ 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. @@ -18,37 +18,45 @@ android:layout_width="match_parent" android:layout_height="?android:attr/dropdownListPreferredItemHeight" android:minWidth="196dip" - android:paddingEnd="16dip" - android:gravity="start|center_vertical"> - + android:paddingEnd="16dip"> + <!-- Icon will be inserted here. --> - - <TextView - android:id="@+id/title" - android:layout_width="wrap_content" + + <!-- The title and summary have some gap between them, and this 'group' should be centered vertically. --> + <RelativeLayout + android:layout_width="0dip" + android:layout_weight="1" android:layout_height="wrap_content" - android:layout_alignWithParentIfMissing="true" + android:layout_gravity="center_vertical" android:layout_marginStart="16dip" - android:layout_toEndOf="@id/icon" - android:textAppearance="?android:attr/textAppearanceLargePopupMenu" - android:singleLine="true" - android:duplicateParentState="true" - android:ellipsize="marquee" - android:fadingEdge="horizontal" - android:textAlignment="viewStart" /> - - <TextView - android:id="@+id/shortcut" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_below="@id/title" - android:layout_alignStart="@id/title" - android:layout_alignWithParentIfMissing="true" - android:textAppearance="?android:attr/textAppearanceSmallPopupMenu" - android:singleLine="true" - android:duplicateParentState="true" - android:textAlignment="viewStart" /> + android:duplicateParentState="true"> + + <TextView + android:id="@+id/title" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_alignParentTop="true" + android:layout_alignParentStart="true" + android:textAppearance="?android:attr/textAppearanceLargePopupMenu" + android:singleLine="true" + android:duplicateParentState="true" + android:ellipsize="marquee" + android:fadingEdge="horizontal" + android:textAlignment="viewStart" /> + + <TextView + android:id="@+id/shortcut" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_below="@id/title" + android:layout_alignParentStart="true" + android:textAppearance="?android:attr/textAppearanceSmallPopupMenu" + android:singleLine="true" + android:duplicateParentState="true" + android:textAlignment="viewStart" /> + + </RelativeLayout> <!-- Checkbox, and/or radio button will be inserted here. --> - + </com.android.internal.view.menu.ListMenuItemView> diff --git a/core/res/res/layout/restrictions_pin_challenge.xml b/core/res/res/layout/restrictions_pin_challenge.xml new file mode 100644 index 0000000..954af92 --- /dev/null +++ b/core/res/res/layout/restrictions_pin_challenge.xml @@ -0,0 +1,59 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<!-- Layout used as the dialog's content View for EditTextPreference. --> +<ScrollView xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:layout_marginTop="48dp" + android:layout_marginBottom="48dp" + android:overScrollMode="ifContentScrolls"> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:padding="8dip" + android:orientation="vertical"> + + <TextView android:id="@+id/pin_message" + style="?android:attr/textAppearanceMedium" + android:layout_marginTop="16dp" + android:layout_marginBottom="16dp" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="@string/restr_pin_create_pin" + android:textColor="?android:attr/textColorSecondary" /> + + <EditText android:id="@+id/pin_text" + style="?android:attr/textAppearanceMedium" + android:layout_marginBottom="16dp" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:hint="@string/restr_pin_enter_pin" + android:inputType="numberPassword" + android:textColor="?android:attr/textColorPrimary" /> + + <TextView android:id="@+id/pin_error_message" + style="?android:attr/textAppearanceSmall" + android:layout_marginBottom="16dp" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="@string/restr_pin_error_doesnt_match" + android:textColor="#FFFF0000" /> + + </LinearLayout> + +</ScrollView> diff --git a/core/res/res/layout/pin_challenge.xml b/core/res/res/layout/restrictions_pin_setup.xml index 2cb14b4..03ed696 100644 --- a/core/res/res/layout/pin_challenge.xml +++ b/core/res/res/layout/restrictions_pin_setup.xml @@ -37,38 +37,31 @@ android:text="@string/restr_pin_create_pin" android:textColor="?android:attr/textColorSecondary" /> - <!-- TextView android:id="@+id/pin1_label" - style="?android:attr/textAppearanceSmall" - android:layout_marginBottom="16dp" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:text="@string/restr_pin_enter_pin" - android:textColor="?android:attr/textColorSecondary" /--> - - <EditText android:id="@+id/pin1_text" + <EditText android:id="@+id/pin_text" style="?android:attr/textAppearanceMedium" android:layout_marginBottom="16dp" android:layout_width="match_parent" android:layout_height="wrap_content" - android:hint="@string/restr_pin_enter_pin" - android:inputType="textPassword" + android:hint="@string/restr_pin_enter_old_pin" + android:inputType="numberPassword" android:textColor="?android:attr/textColorPrimary" /> - <!-- TextView android:id="@+id/pin2_label" - style="?android:attr/textAppearanceSmall" + <EditText android:id="@+id/pin_new_text" + style="?android:attr/textAppearanceMedium" android:layout_marginBottom="16dp" android:layout_width="match_parent" android:layout_height="wrap_content" - android:text="@string/restr_pin_confirm_pin" - android:textColor="?android:attr/textColorSecondary" /--> + android:hint="@string/restr_pin_enter_new_pin" + android:inputType="numberPassword" + android:textColor="?android:attr/textColorPrimary" /> - <EditText android:id="@+id/pin2_text" + <EditText android:id="@+id/pin_confirm_text" style="?android:attr/textAppearanceMedium" android:layout_marginBottom="16dp" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="@string/restr_pin_confirm_pin" - android:inputType="textPassword" + android:inputType="numberPassword" android:textColor="?android:attr/textColorPrimary" /> <TextView android:id="@+id/pin_error_message" diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml index 06a5e67..3c36cba 100644 --- a/core/res/res/values-af/strings.xml +++ b/core/res/res/values-af/strings.xml @@ -279,10 +279,8 @@ <string name="permdesc_reorderTasks" msgid="7734217754877439351">"Laat die program toe om take na die voorgrond of agtergrond te skuif. Die program kan dit moontlik sonder jou insette doen."</string> <string name="permlab_removeTasks" msgid="6821513401870377403">"stop lopende programme"</string> <string name="permdesc_removeTasks" msgid="1394714352062635493">"Laat die program toe om take te verwyder en hul programme te dood. Kwaadwillige programme kan die gedrag van ander programme ontwrig."</string> - <!-- no translation found for permlab_manageActivityStacks (7391191384027303065) --> - <skip /> - <!-- no translation found for permdesc_manageActivityStacks (1615881933034084440) --> - <skip /> + <string name="permlab_manageActivityStacks" msgid="7391191384027303065">"bestuur aktiwiteitstapels"</string> + <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"Laat die program toe om by te voeg by die aktiwiteitstapels waarbinne ander programme loop, of dit te verwyder of te wysig. Kwaadwillige programme kan dalk die gedrag van ander programme ontwrig."</string> <string name="permlab_startAnyActivity" msgid="2918768238045206456">"begin enige aktiwiteit"</string> <string name="permdesc_startAnyActivity" msgid="997823695343584001">"Laat die program toe om \'n aktiwiteit te begin, ongeag toestemming-beskerming of uitgevoerde status."</string> <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"stel skermversoenbaarheid"</string> @@ -360,14 +358,10 @@ <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Dit laat die houer toe om aan die topvlak-koppelvlak van \'n invoermetode te bind. Dit moet nooit vir normale programme nodig wees nie."</string> <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"verbind aan \'n toeganklikheidsdiens"</string> <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Dit laat die houer toe om aan die top-koppelvlak van \'n toeganklikheidsdiens te verbind. Behoort nooit vir gewone programme nodig te wees nie."</string> - <!-- no translation found for permlab_bindPrintService (8462815179572748761) --> - <skip /> - <!-- no translation found for permdesc_bindPrintService (7960067623209111135) --> - <skip /> - <!-- no translation found for permlab_accessAllPrintJobs (1120792468465711159) --> - <skip /> - <!-- no translation found for permdesc_accessAllPrintJobs (2978185311041864762) --> - <skip /> + <string name="permlab_bindPrintService" msgid="8462815179572748761">"verbind aan \'n drukdiens"</string> + <string name="permdesc_bindPrintService" msgid="7960067623209111135">"Laat die houer toe om aan die top-koppelvlak van \'n drukdiens te verbind. Behoort nooit vir gewone programme nodig te wees nie."</string> + <string name="permlab_accessAllPrintJobs" msgid="1120792468465711159">"kry toegang tot alle druktake"</string> + <string name="permdesc_accessAllPrintJobs" msgid="2978185311041864762">"Gee die houer toegang tot druktake wat deur \'n ander program geskep is. Behoort nooit vir normale programme nodig te wees nie."</string> <string name="permlab_bindTextService" msgid="7358378401915287938">"bind aan \'n teksdiens"</string> <string name="permdesc_bindTextService" msgid="8151968910973998670">"Dit laat die houer toe om aan die topvlak-koppelvlak van \'n teksdiens (bv SpellCheckerService) te bind. Dit moet nooit vir normale programme nodig wees nie."</string> <string name="permlab_bindVpnService" msgid="4708596021161473255">"bind aan \'n VPN-diens"</string> @@ -470,6 +464,8 @@ <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Laat die program toe om SurfaceFlinger se laevlak-kenmerke te gebruik."</string> <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"lees raambuffer"</string> <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Laat die program toe om die inhoud van die raambuffer te lees."</string> + <string name="permlab_accessInputFlinger" msgid="5348635270689553857">"kry toegang tot InputFlinger"</string> + <string name="permdesc_accessInputFlinger" msgid="2104864941201226616">"Laat die program toe om InputFlinger se laevlak-kenmerke te gebruik."</string> <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"stel Wi-Fi-skerms op"</string> <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Laat die program toe om Wi-Fi-skerms op te stel en daaraan te koppel."</string> <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"beheer Wi-Fi-skerms"</string> @@ -639,10 +635,14 @@ <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Laat die program toe om netwerkbeleide te bestuur en program-spesifieke reëls te definieer."</string> <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"verander verrekening van netwerkgebruik"</string> <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Laat die program toe om te verander hoe netwerkgebruik teenoor programme gemeet word. Nie vir gebruik deur normale programme nie."</string> + <string name="permlab_markNetworkSocket" msgid="3658527214914959749">"wysig sokmerke"</string> + <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"Laat die program toe om sokmerke vir roetering te wysig"</string> <string name="permlab_accessNotifications" msgid="7673416487873432268">"kry toegang tot kennisgewings"</string> <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_invokeCarrierSetup" msgid="3699600833975117478">"roep die opstellingprogram op wat deur die draer voorsien is"</string> + <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Laat die houer toe om die opstellingsprogram wat deur die draer voorsien is, op te roep. Behoort nooit vir gewone programme nodig te wees nie."</string> <string name="policylab_limitPassword" msgid="4497420728857585791">"Stel wagwoordreëls"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"Beheer lengte en watter karakters wat in die skermontsluit-wagwoorde gebruik word."</string> <string name="policylab_watchLogin" msgid="914130646942199503">"Monitor pogings om skerm te ontsluit"</string> @@ -752,8 +752,7 @@ <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string> <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string> <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string> - <!-- no translation found for imProtocolGoogleTalk (493902321140277304) --> - <skip /> + <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangouts"</string> <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string> <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string> <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string> @@ -1515,94 +1514,56 @@ <string name="app_no_restricted_accounts" msgid="5739463249673727736">"Hierdie program werk nie met rekeninge vir beperkte profiele nie"</string> <string name="app_not_found" msgid="3429141853498927379">"Geen program gevind om hierdie handeling te hanteer nie"</string> <string name="revoke" msgid="5404479185228271586">"Herroep"</string> - <!-- no translation found for mediaSize_iso_a0 (7875427489420821793) --> - <skip /> - <!-- no translation found for mediaSize_iso_a1 (3760734499050875356) --> - <skip /> - <!-- no translation found for mediaSize_iso_a2 (5973266378020144382) --> - <skip /> - <!-- no translation found for mediaSize_iso_a3 (1373407105687300884) --> - <skip /> - <!-- no translation found for mediaSize_iso_a4 (6689772807982597254) --> - <skip /> - <!-- no translation found for mediaSize_iso_a5 (5353549652015741040) --> - <skip /> - <!-- no translation found for mediaSize_iso_a6 (8585038048674911907) --> - <skip /> - <!-- no translation found for mediaSize_iso_a7 (6641836716963839119) --> - <skip /> - <!-- no translation found for mediaSize_iso_a8 (7571139437465693355) --> - <skip /> - <!-- no translation found for mediaSize_iso_a9 (1378455891957115079) --> - <skip /> - <!-- no translation found for mediaSize_iso_a10 (2480747457429475344) --> - <skip /> - <!-- no translation found for mediaSize_iso_b0 (3965935097661108039) --> - <skip /> - <!-- no translation found for mediaSize_iso_b1 (2505753285010115437) --> - <skip /> - <!-- no translation found for mediaSize_iso_b2 (8763874709859458453) --> - <skip /> - <!-- no translation found for mediaSize_iso_b3 (4210506688191764076) --> - <skip /> - <!-- no translation found for mediaSize_iso_b4 (5749404165888526034) --> - <skip /> - <!-- no translation found for mediaSize_iso_b5 (7640627414621904733) --> - <skip /> - <!-- no translation found for mediaSize_iso_b6 (7342988864712748544) --> - <skip /> - <!-- no translation found for mediaSize_iso_b7 (5069844065235382429) --> - <skip /> - <!-- no translation found for mediaSize_iso_b8 (7316818922278779774) --> - <skip /> - <!-- no translation found for mediaSize_iso_b9 (5414727094026532341) --> - <skip /> - <!-- no translation found for mediaSize_iso_b10 (5251253731832048185) --> - <skip /> - <!-- no translation found for mediaSize_iso_c0 (4003138342671964217) --> - <skip /> - <!-- no translation found for mediaSize_iso_c1 (1935188063393553008) --> - <skip /> - <!-- no translation found for mediaSize_iso_c2 (3197307969712069904) --> - <skip /> - <!-- no translation found for mediaSize_iso_c3 (4335826087321913508) --> - <skip /> - <!-- no translation found for mediaSize_iso_c4 (3745639598281015005) --> - <skip /> - <!-- no translation found for mediaSize_iso_c5 (8269457765822791013) --> - <skip /> - <!-- no translation found for mediaSize_iso_c6 (566666105260346930) --> - <skip /> - <!-- no translation found for mediaSize_iso_c7 (8678413180782608498) --> - <skip /> - <!-- no translation found for mediaSize_iso_c8 (8392376206627041730) --> - <skip /> - <!-- no translation found for mediaSize_iso_c9 (9191613372324845405) --> - <skip /> - <!-- no translation found for mediaSize_iso_c10 (7327709699184920822) --> - <skip /> - <!-- no translation found for mediaSize_na_letter (4191805615829472953) --> - <skip /> - <!-- no translation found for mediaSize_na_gvrnmt_letter (7853382192649405507) --> - <skip /> - <!-- no translation found for mediaSize_na_legal (6697982988283823150) --> - <skip /> - <!-- no translation found for mediaSize_na_junior_legal (3727743969902758948) --> - <skip /> - <!-- no translation found for mediaSize_na_ledger (281871464896601236) --> - <skip /> - <!-- no translation found for mediaSize_na_tabloid (5775966416333578127) --> - <skip /> - <!-- no translation found for restr_pin_create_pin (8017600000263450337) --> - <skip /> - <!-- no translation found for restr_pin_enter_pin (3395953421368476103) --> - <skip /> - <!-- no translation found for restr_pin_confirm_pin (2891475237150965991) --> - <skip /> - <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) --> - <skip /> - <!-- no translation found for restr_pin_error_too_short (8173982756265777792) --> - <skip /> - <!-- no translation found for restr_pin_countdown:one (4835639969503729874) --> - <!-- no translation found for restr_pin_countdown:other (8030607343223287654) --> + <string name="mediaSize_iso_a0" msgid="7875427489420821793">"ISO A0"</string> + <string name="mediaSize_iso_a1" msgid="3760734499050875356">"ISO A1"</string> + <string name="mediaSize_iso_a2" msgid="5973266378020144382">"ISO A2"</string> + <string name="mediaSize_iso_a3" msgid="1373407105687300884">"ISO A3"</string> + <string name="mediaSize_iso_a4" msgid="6689772807982597254">"ISO A4"</string> + <string name="mediaSize_iso_a5" msgid="5353549652015741040">"ISO A5"</string> + <string name="mediaSize_iso_a6" msgid="8585038048674911907">"ISO A6"</string> + <string name="mediaSize_iso_a7" msgid="6641836716963839119">"ISO A7"</string> + <string name="mediaSize_iso_a8" msgid="7571139437465693355">"ISO A8"</string> + <string name="mediaSize_iso_a9" msgid="1378455891957115079">"ISO A9"</string> + <string name="mediaSize_iso_a10" msgid="2480747457429475344">"ISO A10"</string> + <string name="mediaSize_iso_b0" msgid="3965935097661108039">"ISO B0"</string> + <string name="mediaSize_iso_b1" msgid="2505753285010115437">"ISO B1"</string> + <string name="mediaSize_iso_b2" msgid="8763874709859458453">"ISO B2"</string> + <string name="mediaSize_iso_b3" msgid="4210506688191764076">"ISO B3"</string> + <string name="mediaSize_iso_b4" msgid="5749404165888526034">"ISO B4"</string> + <string name="mediaSize_iso_b5" msgid="7640627414621904733">"ISO B5"</string> + <string name="mediaSize_iso_b6" msgid="7342988864712748544">"ISO B6"</string> + <string name="mediaSize_iso_b7" msgid="5069844065235382429">"ISO B7"</string> + <string name="mediaSize_iso_b8" msgid="7316818922278779774">"ISO B8"</string> + <string name="mediaSize_iso_b9" msgid="5414727094026532341">"ISO B9"</string> + <string name="mediaSize_iso_b10" msgid="5251253731832048185">"ISO B10"</string> + <string name="mediaSize_iso_c0" msgid="4003138342671964217">"ISO C0"</string> + <string name="mediaSize_iso_c1" msgid="1935188063393553008">"ISO C1"</string> + <string name="mediaSize_iso_c2" msgid="3197307969712069904">"ISO C2"</string> + <string name="mediaSize_iso_c3" msgid="4335826087321913508">"ISO C3"</string> + <string name="mediaSize_iso_c4" msgid="3745639598281015005">"ISO C4"</string> + <string name="mediaSize_iso_c5" msgid="8269457765822791013">"ISO C5"</string> + <string name="mediaSize_iso_c6" msgid="566666105260346930">"ISO C6"</string> + <string name="mediaSize_iso_c7" msgid="8678413180782608498">"ISO C7"</string> + <string name="mediaSize_iso_c8" msgid="8392376206627041730">"ISO C8"</string> + <string name="mediaSize_iso_c9" msgid="9191613372324845405">"ISO C9"</string> + <string name="mediaSize_iso_c10" msgid="7327709699184920822">"ISO C10"</string> + <string name="mediaSize_na_letter" msgid="4191805615829472953">"Letter"</string> + <string name="mediaSize_na_gvrnmt_letter" msgid="7853382192649405507">"Government Letter"</string> + <string name="mediaSize_na_legal" msgid="6697982988283823150">"Legal"</string> + <string name="mediaSize_na_junior_legal" msgid="3727743969902758948">"Junior Legal"</string> + <string name="mediaSize_na_ledger" msgid="281871464896601236">"Ledger"</string> + <string name="mediaSize_na_tabloid" msgid="5775966416333578127">"Tabloid"</string> + <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"Gekanselleer"</string> + <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"Kon nie inhoud skryf nie"</string> + <string name="restr_pin_enter_pin" msgid="3395953421368476103">"Voer PIN in"</string> + <string name="restr_pin_enter_old_pin" msgid="1462206225512910757">"Huidige PIN"</string> + <string name="restr_pin_enter_new_pin" msgid="5959606691619959184">"Nuwe PIN"</string> + <string name="restr_pin_confirm_pin" msgid="8501523829633146239">"Bevestig nuwe PIN"</string> + <string name="restr_pin_create_pin" msgid="8017600000263450337">"Skep \'n PIN vir wysigingbeperkings"</string> + <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PIN\'e kom nie ooreen nie. Probeer weer."</string> + <string name="restr_pin_error_too_short" msgid="8173982756265777792">"PIN is te kort. Moet ten minste 4 syfers wees."</string> + <plurals name="restr_pin_countdown"> + <item quantity="one" msgid="4835639969503729874">"Verkeerde PIN. Probeer weer na 1 sekonde."</item> + <item quantity="other" msgid="8030607343223287654">"Verkeerde PIN. Probeer weer na <xliff:g id="COUNT">%d</xliff:g> sekondes."</item> + </plurals> </resources> diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml index 3796f73..f3c3401 100644 --- a/core/res/res/values-am/strings.xml +++ b/core/res/res/values-am/strings.xml @@ -279,10 +279,8 @@ <string name="permdesc_reorderTasks" msgid="7734217754877439351">"መተግበሪያው ተግባሮችን ወደ ቅድመ ገጹ እና ወደ ዳራው እንዲያንቀሳቅስ ይፈቅድለታል። መተግበሪያው ይህንን ያላንተ ግብዓት ሊያደርግ ይችላል።"</string> <string name="permlab_removeTasks" msgid="6821513401870377403">"የአሂድ ትግበራዎች አቁም"</string> <string name="permdesc_removeTasks" msgid="1394714352062635493">"ተግባሮችን ለማስወገድ እና መተግበሪያዎቻቸውን ለመግደል ለመተግበሪያ ይፈቅዳል። ጎጂ የሆኑ መተግበሪያዎች የሌሎችን መተግበሪያዎችን ባህሪ ሊያውኩ ይችላሉ።"</string> - <!-- no translation found for permlab_manageActivityStacks (7391191384027303065) --> - <skip /> - <!-- no translation found for permdesc_manageActivityStacks (1615881933034084440) --> - <skip /> + <string name="permlab_manageActivityStacks" msgid="7391191384027303065">"የእንቅስቃሴ ቁልሎችን ማቀናበር"</string> + <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"መተግበሪያው ሌሎች መተግበሪያዎች በሚያሄዱበት የእንቅስቃሴዎች ቁልሎችን እንዲያክል፣ እንዲያስወግድ እና እንዲቀይር ያስችለዋል። ተንኮል-አዘል መተግበሪያዎች የሌሎች መተግበሪያዎች ባህሪን ሊበጠብጡ ይችላሉ።"</string> <string name="permlab_startAnyActivity" msgid="2918768238045206456">"ማንኛውም እንቅስቃሴ ጀምር"</string> <string name="permdesc_startAnyActivity" msgid="997823695343584001">"መተግበሪያው ማንኛውም እንቅስቃሴ፣ የፍቃድ ጥበቃም ሆነ ወደ ውጭ የተላከበት ሁኔታ ሳይታይ፣ እንዲጀምር ይፈቅድለታል።"</string> <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"የማያ ገጽ ተኳኋኝነት መድብ"</string> @@ -360,14 +358,10 @@ <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"ያዡ ግቤት ስልቱን ወደ ከፍተኛ-ደረጃ በይነገጽ ለመጠረዝ ይፈቅዳሉ። ለመደበኛ ትግበራዎች በፍፁም አያስፈልግም።"</string> <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"ከአንድ የተደራሽነት አገልግሎት ጋር እሰር"</string> <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"ያዢው ወደ የአንድ ተደራሽነት አገልግሎት ከፍተኛ-ደረጃ በይነገጽ እንዲያስር ይፈቅድለታል። ለመደበኛ መተግበሪያዎች መቼም ቢሆን ሊያስፈልግ አይገባም።"</string> - <!-- no translation found for permlab_bindPrintService (8462815179572748761) --> - <skip /> - <!-- no translation found for permdesc_bindPrintService (7960067623209111135) --> - <skip /> - <!-- no translation found for permlab_accessAllPrintJobs (1120792468465711159) --> - <skip /> - <!-- no translation found for permdesc_accessAllPrintJobs (2978185311041864762) --> - <skip /> + <string name="permlab_bindPrintService" msgid="8462815179572748761">"ከአንድ የህትመት አገልግሎት ጋር ማያያዝ"</string> + <string name="permdesc_bindPrintService" msgid="7960067623209111135">"ያዢው የህትመት አገልግሎቱን ወደ ከፍተኛ-ደረጃ በይነገጽ እንዲጠርዝ ይፈቅድለታል። ለመደበኛ መተግበሪያዎች በጭራሽ አያስፈልግም።"</string> + <string name="permlab_accessAllPrintJobs" msgid="1120792468465711159">"ሁሉንም የህትመት ስራዎችን መድረስ"</string> + <string name="permdesc_accessAllPrintJobs" msgid="2978185311041864762">"ያዢው በሌላ መተግበሪያ የተፈጠሩ የህትመት ስራዎች እንዲደርስባቸው ያስችለዋል። ለመደበኛ መተግበሪያዎች በጭራሽ አያስፈልግም።"</string> <string name="permlab_bindTextService" msgid="7358378401915287938">"ለፅሁፍ አገልግሎት አሰረ"</string> <string name="permdesc_bindTextService" msgid="8151968910973998670">"ያዡ ግቤት ለከፍተኛ-ደረጃ የፅሁፍ አገልግሎት ገፅታ ለመጠረዝ ይፈቅዳል። ለመደበኛ ትግበራዎች በፍፁም አያስፈልግም።"</string> <string name="permlab_bindVpnService" msgid="4708596021161473255">"ለVPN አገልግሎት ተገዛ"</string> @@ -470,6 +464,8 @@ <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"መተግበሪያውን የSurfaceFlinger ዝቅተኛ ደረጃ ባህሪያትን ለመጠቀም ይፈቅዳል።"</string> <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"የንዑስ ክፈፍ ቋት አንብብ"</string> <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"የክፈፍ ቋት ይዘት ለማንበብ ለመተግበሪያው ይፈቅዳሉ።"</string> + <string name="permlab_accessInputFlinger" msgid="5348635270689553857">"InputFlinger ን መድረስ"</string> + <string name="permdesc_accessInputFlinger" msgid="2104864941201226616">"መተግበሪያው ባለአነስተኛ የInputFlinger ባህሪያት እንዲጠቀም ይፈቅድለታል።"</string> <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"የWifi ማሳያዎችን አዋቅር"</string> <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"መተግበሪያው የWifi ማሳያዎችን እንዲያዋቅርና ከእነሱ ጋር እንዲገናኝ ይፈቅድለታል።"</string> <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"የWifi ማሳያዎችን ተቆጣጠር"</string> @@ -639,10 +635,14 @@ <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"የአውታረመረብ ቋሚ መመሪያዎችን እና ትግበራ ተኮር ደንቦችን ለማደራጀት ለመተግበሪያው ይፈቅዳሉ፡፡"</string> <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"የአውታረ መረብ አጠቃቀም"</string> <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"ከመተግበሪያዎች በተለየ መልኩ እንዴት የአውታረ መረብ አጠቃቀም እንደተመዘገበ ለመቀየር ለመተግበሪያው ይፈቅዳሉ።ለመደበኛ መተግበሪያዎች አገልግሎት አይውልም።"</string> + <string name="permlab_markNetworkSocket" msgid="3658527214914959749">"የሶኬት ምልክቶችን መቀየር"</string> + <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"መተግበሪያው መንገድ እንዲፈልግ የሶኬት ምልክቶቹን እንዲቀይር ያስችለዋል"</string> <string name="permlab_accessNotifications" msgid="7673416487873432268">"ማሳወቂያዎችን ይድረሱ"</string> <string name="permdesc_accessNotifications" msgid="458457742683431387">"መተግበሪያው ማሳወቂያዎችን እንዲያስመጣ፣ እንዲመረምር እና እንዲያጸዳ ያስችለዋል፣ በሌሎች መተግበሪያዎች የተለጠፉትንም ጨምሮ።"</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"ከአንድ የማሳወቂያ አዳማጭ አገልግሎት ጋር ይሰሩ"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"ያዢው የማሳወቂያ አዳማጭ አገልግሎቱን ከከፍተኛ-ደረጃ በይነገጹ ጋር እንዲያስር ያስችለዋል። ለመደበኛ መተግበሪያዎች በጭራሽ አያስፈልግም።"</string> + <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"በድምጸ-ተያያዥ ሞደም የቀረበው የውቅር መተግበሪያውን መጥራት"</string> + <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"ያዢው በድምጸ-ተያያዥ ሞደም የቀረበው የውቅር መተግበሪያውን እንዲጠራው ያስችለዋል። ለመደበኛ መተግበሪያዎች በጭራሽ አያስፈልግም።"</string> <string name="policylab_limitPassword" msgid="4497420728857585791">"የይለፍ ቃል ድንቦች አዘጋጅ"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"በማያ-መክፈት የተፈቀዱ የይለፍ ቃል ርዝመት እና ቁምፊዎች ተቆጣጠር።"</string> <string name="policylab_watchLogin" msgid="914130646942199503">"የማሳያ-ክፈት ሙከራዎችን አሳይ"</string> @@ -752,8 +752,7 @@ <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string> <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string> <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string> - <!-- no translation found for imProtocolGoogleTalk (493902321140277304) --> - <skip /> + <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangouts"</string> <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string> <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string> <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string> @@ -1515,94 +1514,59 @@ <string name="app_no_restricted_accounts" msgid="5739463249673727736">"ይህ መተግበሪያ የተገደቡ መገለጫዎች መለያዎችን አይደግፍም"</string> <string name="app_not_found" msgid="3429141853498927379">"ይህን እርምጃ የሚያከናውን ምንም መተግበሪያ አልተገኘም"</string> <string name="revoke" msgid="5404479185228271586">"ሻር"</string> - <!-- no translation found for mediaSize_iso_a0 (7875427489420821793) --> - <skip /> - <!-- no translation found for mediaSize_iso_a1 (3760734499050875356) --> - <skip /> - <!-- no translation found for mediaSize_iso_a2 (5973266378020144382) --> - <skip /> - <!-- no translation found for mediaSize_iso_a3 (1373407105687300884) --> - <skip /> - <!-- no translation found for mediaSize_iso_a4 (6689772807982597254) --> - <skip /> - <!-- no translation found for mediaSize_iso_a5 (5353549652015741040) --> - <skip /> - <!-- no translation found for mediaSize_iso_a6 (8585038048674911907) --> - <skip /> - <!-- no translation found for mediaSize_iso_a7 (6641836716963839119) --> - <skip /> - <!-- no translation found for mediaSize_iso_a8 (7571139437465693355) --> - <skip /> - <!-- no translation found for mediaSize_iso_a9 (1378455891957115079) --> - <skip /> - <!-- no translation found for mediaSize_iso_a10 (2480747457429475344) --> - <skip /> - <!-- no translation found for mediaSize_iso_b0 (3965935097661108039) --> - <skip /> - <!-- no translation found for mediaSize_iso_b1 (2505753285010115437) --> - <skip /> - <!-- no translation found for mediaSize_iso_b2 (8763874709859458453) --> - <skip /> - <!-- no translation found for mediaSize_iso_b3 (4210506688191764076) --> - <skip /> - <!-- no translation found for mediaSize_iso_b4 (5749404165888526034) --> - <skip /> - <!-- no translation found for mediaSize_iso_b5 (7640627414621904733) --> - <skip /> - <!-- no translation found for mediaSize_iso_b6 (7342988864712748544) --> - <skip /> - <!-- no translation found for mediaSize_iso_b7 (5069844065235382429) --> + <string name="mediaSize_iso_a0" msgid="7875427489420821793">"አይ ኤስ ኦ ኤ0"</string> + <string name="mediaSize_iso_a1" msgid="3760734499050875356">"አይ ኤስ ኦ ኤ1"</string> + <string name="mediaSize_iso_a2" msgid="5973266378020144382">"አይ ኤስ ኦ ኤ2"</string> + <string name="mediaSize_iso_a3" msgid="1373407105687300884">"አይ ኤስ ኦ ኤ3"</string> + <string name="mediaSize_iso_a4" msgid="6689772807982597254">"አይ ኤስ ኦ ኤ4"</string> + <string name="mediaSize_iso_a5" msgid="5353549652015741040">"አይ ኤስ ኦ ኤ5"</string> + <string name="mediaSize_iso_a6" msgid="8585038048674911907">"አይ ኤስ ኦ ኤ6"</string> + <string name="mediaSize_iso_a7" msgid="6641836716963839119">"አይ ኤስ ኦ ኤ7"</string> + <string name="mediaSize_iso_a8" msgid="7571139437465693355">"አይ ኤስ ኦ ኤ8"</string> + <string name="mediaSize_iso_a9" msgid="1378455891957115079">"አይ ኤስ ኦ ኤ9"</string> + <string name="mediaSize_iso_a10" msgid="2480747457429475344">"አይ ኤስ ኦ ኤ10"</string> + <string name="mediaSize_iso_b0" msgid="3965935097661108039">"አይ ኤስ ኦ ቢ0"</string> + <string name="mediaSize_iso_b1" msgid="2505753285010115437">"አይ ኤስ ኦ ቢ1"</string> + <string name="mediaSize_iso_b2" msgid="8763874709859458453">"አይ ኤስ ኦ ቢ2"</string> + <string name="mediaSize_iso_b3" msgid="4210506688191764076">"አይ ኤስ ኦ ቢ3"</string> + <string name="mediaSize_iso_b4" msgid="5749404165888526034">"አይ ኤስ ኦ ቢ4"</string> + <string name="mediaSize_iso_b5" msgid="7640627414621904733">"አይ ኤስ ኦ ቢ5"</string> + <string name="mediaSize_iso_b6" msgid="7342988864712748544">"አይ ኤስ ኦ ቢ6"</string> + <string name="mediaSize_iso_b7" msgid="5069844065235382429">"አይ ኤስ ኦ ቢ7"</string> + <string name="mediaSize_iso_b8" msgid="7316818922278779774">"አይ ኤስ ኦ ቢ8"</string> + <string name="mediaSize_iso_b9" msgid="5414727094026532341">"አይ ኤስ ኦ ቢ9"</string> + <string name="mediaSize_iso_b10" msgid="5251253731832048185">"አይ ኤስ ኦ ቢ10"</string> + <string name="mediaSize_iso_c0" msgid="4003138342671964217">"አይ ኤስ ኦ ሲ0"</string> + <string name="mediaSize_iso_c1" msgid="1935188063393553008">"አይ ኤስ ኦ ሲ1"</string> + <string name="mediaSize_iso_c2" msgid="3197307969712069904">"አይ ኤስ ኦ ሲ2"</string> + <string name="mediaSize_iso_c3" msgid="4335826087321913508">"አይ ኤስ ኦ ሲ3"</string> + <string name="mediaSize_iso_c4" msgid="3745639598281015005">"አይ ኤስ ኦ ሲ4"</string> + <string name="mediaSize_iso_c5" msgid="8269457765822791013">"አይ ኤስ ኦ ሲ5"</string> + <string name="mediaSize_iso_c6" msgid="566666105260346930">"አይ ኤስ ኦ ሲ6"</string> + <string name="mediaSize_iso_c7" msgid="8678413180782608498">"አይ ኤስ ኦ ሲ7"</string> + <string name="mediaSize_iso_c8" msgid="8392376206627041730">"አይ ኤስ ኦ ሲ8"</string> + <string name="mediaSize_iso_c9" msgid="9191613372324845405">"አይ ኤስ ኦ ሲ9"</string> + <string name="mediaSize_iso_c10" msgid="7327709699184920822">"አይ ኤስ ኦ ሲ10"</string> + <string name="mediaSize_na_letter" msgid="4191805615829472953">"ደብዳቤ"</string> + <string name="mediaSize_na_gvrnmt_letter" msgid="7853382192649405507">"የመንግስት ደብዳቤ"</string> + <string name="mediaSize_na_legal" msgid="6697982988283823150">"ሕግ"</string> + <string name="mediaSize_na_junior_legal" msgid="3727743969902758948">"ጁኒየር ህጋዊ"</string> + <string name="mediaSize_na_ledger" msgid="281871464896601236">"የሒሳብ መዝገብ"</string> + <string name="mediaSize_na_tabloid" msgid="5775966416333578127">"ታብሎይድ"</string> + <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"ተትቷል"</string> + <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"ይዘት መጻፍ ላይ ስህተት"</string> + <string name="restr_pin_enter_pin" msgid="3395953421368476103">"ፒን ያስገቡ"</string> + <!-- no translation found for restr_pin_enter_old_pin (1462206225512910757) --> <skip /> - <!-- no translation found for mediaSize_iso_b8 (7316818922278779774) --> + <!-- no translation found for restr_pin_enter_new_pin (5959606691619959184) --> <skip /> - <!-- no translation found for mediaSize_iso_b9 (5414727094026532341) --> + <!-- no translation found for restr_pin_confirm_pin (8501523829633146239) --> <skip /> - <!-- no translation found for mediaSize_iso_b10 (5251253731832048185) --> - <skip /> - <!-- no translation found for mediaSize_iso_c0 (4003138342671964217) --> - <skip /> - <!-- no translation found for mediaSize_iso_c1 (1935188063393553008) --> - <skip /> - <!-- no translation found for mediaSize_iso_c2 (3197307969712069904) --> - <skip /> - <!-- no translation found for mediaSize_iso_c3 (4335826087321913508) --> - <skip /> - <!-- no translation found for mediaSize_iso_c4 (3745639598281015005) --> - <skip /> - <!-- no translation found for mediaSize_iso_c5 (8269457765822791013) --> - <skip /> - <!-- no translation found for mediaSize_iso_c6 (566666105260346930) --> - <skip /> - <!-- no translation found for mediaSize_iso_c7 (8678413180782608498) --> - <skip /> - <!-- no translation found for mediaSize_iso_c8 (8392376206627041730) --> - <skip /> - <!-- no translation found for mediaSize_iso_c9 (9191613372324845405) --> - <skip /> - <!-- no translation found for mediaSize_iso_c10 (7327709699184920822) --> - <skip /> - <!-- no translation found for mediaSize_na_letter (4191805615829472953) --> - <skip /> - <!-- no translation found for mediaSize_na_gvrnmt_letter (7853382192649405507) --> - <skip /> - <!-- no translation found for mediaSize_na_legal (6697982988283823150) --> - <skip /> - <!-- no translation found for mediaSize_na_junior_legal (3727743969902758948) --> - <skip /> - <!-- no translation found for mediaSize_na_ledger (281871464896601236) --> - <skip /> - <!-- no translation found for mediaSize_na_tabloid (5775966416333578127) --> - <skip /> - <!-- no translation found for restr_pin_create_pin (8017600000263450337) --> - <skip /> - <!-- no translation found for restr_pin_enter_pin (3395953421368476103) --> - <skip /> - <!-- no translation found for restr_pin_confirm_pin (2891475237150965991) --> - <skip /> - <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) --> - <skip /> - <!-- no translation found for restr_pin_error_too_short (8173982756265777792) --> - <skip /> - <!-- no translation found for restr_pin_countdown:one (4835639969503729874) --> - <!-- no translation found for restr_pin_countdown:other (8030607343223287654) --> + <string name="restr_pin_create_pin" msgid="8017600000263450337">"ገደቦችን ለመቀየር ፒን ይፍጠሩ"</string> + <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"ፒኖች አይዛመዱም። እንደገና ይሞክሩ።"</string> + <string name="restr_pin_error_too_short" msgid="8173982756265777792">"ፒን በጣም አጭር ነው። ቢያንስ 4 አኃዝ መሆን አለበት።"</string> + <plurals name="restr_pin_countdown"> + <item quantity="one" msgid="4835639969503729874">"ትክክል ያልሆነ ፒን። በ1 ሰከንድ ውስጥ እንደገና ይሞክሩ።"</item> + <item quantity="other" msgid="8030607343223287654">"ትክክል ያልሆነ ፒን። በ<xliff:g id="COUNT">%d</xliff:g> ሰከንዶች ውስጥ እንደገና ይሞክሩ።"</item> + </plurals> </resources> diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml index 1820689..2df723a 100644 --- a/core/res/res/values-ar/strings.xml +++ b/core/res/res/values-ar/strings.xml @@ -279,10 +279,8 @@ <string name="permdesc_reorderTasks" msgid="7734217754877439351">"للسماح للتطبيق بنقل المهام إلى المقدمة والخلفية. وقد يجري التطبيق ذلك بدون إذنك."</string> <string name="permlab_removeTasks" msgid="6821513401870377403">"إيقاف التطبيقات التي قيد التشغيل"</string> <string name="permdesc_removeTasks" msgid="1394714352062635493">"للسماح للتطبيق بإزالة المهام وإنهاء تطبيقاتها. قد تعطل التطبيقات الضارة عمل التطبيقات الأخرى."</string> - <!-- no translation found for permlab_manageActivityStacks (7391191384027303065) --> - <skip /> - <!-- no translation found for permdesc_manageActivityStacks (1615881933034084440) --> - <skip /> + <string name="permlab_manageActivityStacks" msgid="7391191384027303065">"إدارة حزم الأنشطة"</string> + <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"للسماح للتطبيق بإضافة حزم الأنشطة التي تعمل بها التطبيقات الأخرى وإزالتها وتعديلها. فقد تعطل التطبيقات الضارة سلوك عمل التطبيقات الأخرى."</string> <string name="permlab_startAnyActivity" msgid="2918768238045206456">"بدء أي نشاط"</string> <string name="permdesc_startAnyActivity" msgid="997823695343584001">"للسماح للتطبيق ببدء أي نشاط، بغض النظر عن حماية الإذن أو حالة التصدير."</string> <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"تعيين توافق الشاشة"</string> @@ -360,14 +358,10 @@ <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"للسماح للمالك بالالتزام بواجهة المستوى العلوي لأسلوب الإدخال. لن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string> <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"الالتزام بخدمة إمكانية الدخول"</string> <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"للسماح للمالك بالالتزام بواجهة المستوى العلوي لخدمة إمكانية الدخول. لن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string> - <!-- no translation found for permlab_bindPrintService (8462815179572748761) --> - <skip /> - <!-- no translation found for permdesc_bindPrintService (7960067623209111135) --> - <skip /> - <!-- no translation found for permlab_accessAllPrintJobs (1120792468465711159) --> - <skip /> - <!-- no translation found for permdesc_accessAllPrintJobs (2978185311041864762) --> - <skip /> + <string name="permlab_bindPrintService" msgid="8462815179572748761">"الالتزام بخدمة طباعة"</string> + <string name="permdesc_bindPrintService" msgid="7960067623209111135">"للسماح للمالك بالالتزام بواجهة المستوى العلوي لخدمة الطباعة. لن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string> + <string name="permlab_accessAllPrintJobs" msgid="1120792468465711159">"الدخول إلى جميع وظائف الطباعة"</string> + <string name="permdesc_accessAllPrintJobs" msgid="2978185311041864762">"للسماح للمالك بالدخول إلى وظائف الطباعة التي أنشأها تطبيق آخر. لن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string> <string name="permlab_bindTextService" msgid="7358378401915287938">"الالتزام بخدمة إدخال النصوص"</string> <string name="permdesc_bindTextService" msgid="8151968910973998670">"للسماح للمالك بالالتزام بواجهة المستوى العلوي لخدمة إدخال النصوص (على سبيل المثال، SpellCheckerService). لن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string> <string name="permlab_bindVpnService" msgid="4708596021161473255">"الالتزام بخدمة VPN"</string> @@ -470,6 +464,8 @@ <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"للسماح للتطبيق باستخدام ميزات SurfaceFlinger ذات المستوى المنخفض."</string> <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"قراءة المخزن المؤقت للإطارات"</string> <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"للسماح للتطبيق بقراءة محتوى المخزن المؤقت للإطارات."</string> + <string name="permlab_accessInputFlinger" msgid="5348635270689553857">"الدخول إلى InputFlinger"</string> + <string name="permdesc_accessInputFlinger" msgid="2104864941201226616">"للسماح للتطبيق باستخدام ميزات InputFlinger ذات المستوى المنخفض."</string> <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"تهيئة شاشات Wi-Fi"</string> <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"للسماح للتطبيق بتهيئة شاشات Wi-Fi والاتصال بها."</string> <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"التحكم في شاشات Wi-Fi"</string> @@ -639,10 +635,14 @@ <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"للسماح لتطبيق بإدارة سياسات الشبكة وتحديد قواعد متعلقة بالتطبيق."</string> <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"تعديل حساب استخدام الشبكة"</string> <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"للسماح للتطبيق بتعديل كيفية حساب استخدام الشبكة في التطبيقات. ليس للاستخدام بواسطة التطبيقات العادية."</string> + <string name="permlab_markNetworkSocket" msgid="3658527214914959749">"تعديل علامات المقابس"</string> + <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"للسماح للتطبيق بتعديل علامات المقابس لإعادة التوجيه."</string> <string name="permlab_accessNotifications" msgid="7673416487873432268">"إشعارات الدخول"</string> <string name="permdesc_accessNotifications" msgid="458457742683431387">"يتيح للتطبيق استرجاع الإشعارات وفحصها ومسحها، بما في ذلك تلك التي نشرتها تطبيقات أخرى."</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"الربط بخدمة تلقّي الإشعارات الصوتية"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"يتيح للمالك الربط بواجهة المستوى العلوي لخدمة تلقّي الإشعارات الصوتية. ولن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string> + <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"استدعاء تطبيق التهيئة الذي يوفره مشغل شبكة الجوال"</string> + <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"للسماح للمالك باستدعاء تطبيق التهيئة الذي يوفره مشغل شبكة الجوال. لن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string> <string name="policylab_limitPassword" msgid="4497420728857585791">"تعيين قواعد كلمة المرور"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"يمكنك التحكم في الطول والأحرف المسموح بها في كلمات مرور إلغاء تأمين الشاشة."</string> <string name="policylab_watchLogin" msgid="914130646942199503">"مراقبة محاولات إلغاء قفل الشاشة"</string> @@ -752,8 +752,7 @@ <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string> <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string> <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string> - <!-- no translation found for imProtocolGoogleTalk (493902321140277304) --> - <skip /> + <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangouts"</string> <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string> <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string> <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string> @@ -1515,94 +1514,59 @@ <string name="app_no_restricted_accounts" msgid="5739463249673727736">"لا يتوافق هذا التطبيق مع حسابات الملفات الشخصية المقيدة"</string> <string name="app_not_found" msgid="3429141853498927379">"لم يتم العثور على تطبيق يمكنه التعامل مع هذا الإجراء."</string> <string name="revoke" msgid="5404479185228271586">"إلغاء"</string> - <!-- no translation found for mediaSize_iso_a0 (7875427489420821793) --> - <skip /> - <!-- no translation found for mediaSize_iso_a1 (3760734499050875356) --> - <skip /> - <!-- no translation found for mediaSize_iso_a2 (5973266378020144382) --> - <skip /> - <!-- no translation found for mediaSize_iso_a3 (1373407105687300884) --> - <skip /> - <!-- no translation found for mediaSize_iso_a4 (6689772807982597254) --> - <skip /> - <!-- no translation found for mediaSize_iso_a5 (5353549652015741040) --> - <skip /> - <!-- no translation found for mediaSize_iso_a6 (8585038048674911907) --> - <skip /> - <!-- no translation found for mediaSize_iso_a7 (6641836716963839119) --> - <skip /> - <!-- no translation found for mediaSize_iso_a8 (7571139437465693355) --> - <skip /> - <!-- no translation found for mediaSize_iso_a9 (1378455891957115079) --> - <skip /> - <!-- no translation found for mediaSize_iso_a10 (2480747457429475344) --> - <skip /> - <!-- no translation found for mediaSize_iso_b0 (3965935097661108039) --> - <skip /> - <!-- no translation found for mediaSize_iso_b1 (2505753285010115437) --> - <skip /> - <!-- no translation found for mediaSize_iso_b2 (8763874709859458453) --> - <skip /> - <!-- no translation found for mediaSize_iso_b3 (4210506688191764076) --> - <skip /> - <!-- no translation found for mediaSize_iso_b4 (5749404165888526034) --> - <skip /> - <!-- no translation found for mediaSize_iso_b5 (7640627414621904733) --> - <skip /> - <!-- no translation found for mediaSize_iso_b6 (7342988864712748544) --> - <skip /> - <!-- no translation found for mediaSize_iso_b7 (5069844065235382429) --> + <string name="mediaSize_iso_a0" msgid="7875427489420821793">"ISO A0"</string> + <string name="mediaSize_iso_a1" msgid="3760734499050875356">"ISO A1"</string> + <string name="mediaSize_iso_a2" msgid="5973266378020144382">"ISO A2"</string> + <string name="mediaSize_iso_a3" msgid="1373407105687300884">"ISO A3"</string> + <string name="mediaSize_iso_a4" msgid="6689772807982597254">"ISO A4"</string> + <string name="mediaSize_iso_a5" msgid="5353549652015741040">"ISO A5"</string> + <string name="mediaSize_iso_a6" msgid="8585038048674911907">"ISO A6"</string> + <string name="mediaSize_iso_a7" msgid="6641836716963839119">"ISO A7"</string> + <string name="mediaSize_iso_a8" msgid="7571139437465693355">"ISO A8"</string> + <string name="mediaSize_iso_a9" msgid="1378455891957115079">"ISO A9"</string> + <string name="mediaSize_iso_a10" msgid="2480747457429475344">"ISO A10"</string> + <string name="mediaSize_iso_b0" msgid="3965935097661108039">"ISO B0"</string> + <string name="mediaSize_iso_b1" msgid="2505753285010115437">"ISO B1"</string> + <string name="mediaSize_iso_b2" msgid="8763874709859458453">"ISO B2"</string> + <string name="mediaSize_iso_b3" msgid="4210506688191764076">"ISO B3"</string> + <string name="mediaSize_iso_b4" msgid="5749404165888526034">"ISO B4"</string> + <string name="mediaSize_iso_b5" msgid="7640627414621904733">"ISO B5"</string> + <string name="mediaSize_iso_b6" msgid="7342988864712748544">"ISO B6"</string> + <string name="mediaSize_iso_b7" msgid="5069844065235382429">"ISO B7"</string> + <string name="mediaSize_iso_b8" msgid="7316818922278779774">"ISO B8"</string> + <string name="mediaSize_iso_b9" msgid="5414727094026532341">"ISO B9"</string> + <string name="mediaSize_iso_b10" msgid="5251253731832048185">"ISO B10"</string> + <string name="mediaSize_iso_c0" msgid="4003138342671964217">"ISO C0"</string> + <string name="mediaSize_iso_c1" msgid="1935188063393553008">"ISO C1"</string> + <string name="mediaSize_iso_c2" msgid="3197307969712069904">"ISO C2"</string> + <string name="mediaSize_iso_c3" msgid="4335826087321913508">"ISO C3"</string> + <string name="mediaSize_iso_c4" msgid="3745639598281015005">"ISO C4"</string> + <string name="mediaSize_iso_c5" msgid="8269457765822791013">"ISO C5"</string> + <string name="mediaSize_iso_c6" msgid="566666105260346930">"ISO C6"</string> + <string name="mediaSize_iso_c7" msgid="8678413180782608498">"ISO C7"</string> + <string name="mediaSize_iso_c8" msgid="8392376206627041730">"ISO C8"</string> + <string name="mediaSize_iso_c9" msgid="9191613372324845405">"ISO C9"</string> + <string name="mediaSize_iso_c10" msgid="7327709699184920822">"ISO C10"</string> + <string name="mediaSize_na_letter" msgid="4191805615829472953">"Letter"</string> + <string name="mediaSize_na_gvrnmt_letter" msgid="7853382192649405507">"Government Letter"</string> + <string name="mediaSize_na_legal" msgid="6697982988283823150">"Legal"</string> + <string name="mediaSize_na_junior_legal" msgid="3727743969902758948">"Junior Legal"</string> + <string name="mediaSize_na_ledger" msgid="281871464896601236">"Ledger"</string> + <string name="mediaSize_na_tabloid" msgid="5775966416333578127">"Tabloid"</string> + <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"ملغاة"</string> + <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"حدث خطأ أثناء كتابة المحتوى"</string> + <string name="restr_pin_enter_pin" msgid="3395953421368476103">"إدخال رقم التعريف الشخصي"</string> + <!-- no translation found for restr_pin_enter_old_pin (1462206225512910757) --> <skip /> - <!-- no translation found for mediaSize_iso_b8 (7316818922278779774) --> + <!-- no translation found for restr_pin_enter_new_pin (5959606691619959184) --> <skip /> - <!-- no translation found for mediaSize_iso_b9 (5414727094026532341) --> + <!-- no translation found for restr_pin_confirm_pin (8501523829633146239) --> <skip /> - <!-- no translation found for mediaSize_iso_b10 (5251253731832048185) --> - <skip /> - <!-- no translation found for mediaSize_iso_c0 (4003138342671964217) --> - <skip /> - <!-- no translation found for mediaSize_iso_c1 (1935188063393553008) --> - <skip /> - <!-- no translation found for mediaSize_iso_c2 (3197307969712069904) --> - <skip /> - <!-- no translation found for mediaSize_iso_c3 (4335826087321913508) --> - <skip /> - <!-- no translation found for mediaSize_iso_c4 (3745639598281015005) --> - <skip /> - <!-- no translation found for mediaSize_iso_c5 (8269457765822791013) --> - <skip /> - <!-- no translation found for mediaSize_iso_c6 (566666105260346930) --> - <skip /> - <!-- no translation found for mediaSize_iso_c7 (8678413180782608498) --> - <skip /> - <!-- no translation found for mediaSize_iso_c8 (8392376206627041730) --> - <skip /> - <!-- no translation found for mediaSize_iso_c9 (9191613372324845405) --> - <skip /> - <!-- no translation found for mediaSize_iso_c10 (7327709699184920822) --> - <skip /> - <!-- no translation found for mediaSize_na_letter (4191805615829472953) --> - <skip /> - <!-- no translation found for mediaSize_na_gvrnmt_letter (7853382192649405507) --> - <skip /> - <!-- no translation found for mediaSize_na_legal (6697982988283823150) --> - <skip /> - <!-- no translation found for mediaSize_na_junior_legal (3727743969902758948) --> - <skip /> - <!-- no translation found for mediaSize_na_ledger (281871464896601236) --> - <skip /> - <!-- no translation found for mediaSize_na_tabloid (5775966416333578127) --> - <skip /> - <!-- no translation found for restr_pin_create_pin (8017600000263450337) --> - <skip /> - <!-- no translation found for restr_pin_enter_pin (3395953421368476103) --> - <skip /> - <!-- no translation found for restr_pin_confirm_pin (2891475237150965991) --> - <skip /> - <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) --> - <skip /> - <!-- no translation found for restr_pin_error_too_short (8173982756265777792) --> - <skip /> - <!-- no translation found for restr_pin_countdown:one (4835639969503729874) --> - <!-- no translation found for restr_pin_countdown:other (8030607343223287654) --> + <string name="restr_pin_create_pin" msgid="8017600000263450337">"إنشاء رقم تعريف شخصي لتعديل القيود"</string> + <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"أرقام التعريف الشخصية لا تتطابق، أعد المحاولة."</string> + <string name="restr_pin_error_too_short" msgid="8173982756265777792">"رقم التعريف الشخصي أقصر مما يلزم، يجب ألا يقل عن 4 أرقام. "</string> + <plurals name="restr_pin_countdown"> + <item quantity="one" msgid="4835639969503729874">"رقم التعريف الشخصي غير صحيح، الرجاء إعادة المحاولة بعد ثانية واحدة."</item> + <item quantity="other" msgid="8030607343223287654">"رقم التعريف الشخصي غير صحيح، الرجاء إعادة المحاولة بعد <xliff:g id="COUNT">%d</xliff:g> من الثواني."</item> + </plurals> </resources> diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml index becac6c..c2ffeb3 100644 --- a/core/res/res/values-be/strings.xml +++ b/core/res/res/values-be/strings.xml @@ -470,6 +470,10 @@ <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Дазваляе прыкладанням выкарыстоўваць нізкаўзроўневыя функцыі SurfaceFlinger."</string> <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"чытаць буфер кадраў"</string> <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Дазваляе прыкладанням счытваць змесціва буферу кадра."</string> + <!-- no translation found for permlab_accessInputFlinger (5348635270689553857) --> + <skip /> + <!-- no translation found for permdesc_accessInputFlinger (2104864941201226616) --> + <skip /> <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"налада дысплеяў Wi-Fi"</string> <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Дазволiць прыкладанню наладжвацца i падключацца да дысплеяў Wi-Fi."</string> <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"кіраванне дысплеямi Wi-Fi"</string> @@ -639,10 +643,18 @@ <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Дазваляе прыкладаннм кіраваць сеткавымі палітыкамі і вызначаць правілы пэўных прыкладанняў."</string> <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"змяніць улік выкарыстання сеткі"</string> <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Дазваляе прыкладанням змяняць метад уліку выкарыстання сеткі прыкладаннямі. Не для выкарыстання звычайнымі прыкладаннямі."</string> + <!-- no translation found for permlab_markNetworkSocket (3658527214914959749) --> + <skip /> + <!-- no translation found for permdesc_markNetworkSocket (7655568433696356578) --> + <skip /> <string name="permlab_accessNotifications" msgid="7673416487873432268">"доступ да паведамленняў"</string> <string name="permdesc_accessNotifications" msgid="458457742683431387">"Дазваляе прыкладанню атрымлiваць, правяраць i выдаляць апавяшчэннi, у тым лiку апублiкаваныя iншымi прыкладаннямi."</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"прывязка да службы апавяшчэння слухача"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Дазваляе ўладальніку прывязвацца да верхняга ўзроўню інтэрфейсу службы апавяшчэння слухачоў. Ніколі не патрэбнае для звычайных прыкладанняў."</string> + <!-- no translation found for permlab_invokeCarrierSetup (3699600833975117478) --> + <skip /> + <!-- no translation found for permdesc_invokeCarrierSetup (4159549152529111920) --> + <skip /> <string name="policylab_limitPassword" msgid="4497420728857585791">"Устанавіць правілы паролю"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"Кіраванне даўжынёй і колькасцю знакаў у паролі разблакоўкі экрана."</string> <string name="policylab_watchLogin" msgid="914130646942199503">"Сачыць за спробамі разблакоўкі экрана"</string> @@ -1594,11 +1606,19 @@ <skip /> <!-- no translation found for mediaSize_na_tabloid (5775966416333578127) --> <skip /> - <!-- no translation found for restr_pin_create_pin (8017600000263450337) --> + <!-- no translation found for write_fail_reason_cancelled (7091258378121627624) --> + <skip /> + <!-- no translation found for write_fail_reason_cannot_write (8132505417935337724) --> <skip /> <!-- no translation found for restr_pin_enter_pin (3395953421368476103) --> <skip /> - <!-- no translation found for restr_pin_confirm_pin (2891475237150965991) --> + <!-- no translation found for restr_pin_enter_old_pin (1462206225512910757) --> + <skip /> + <!-- no translation found for restr_pin_enter_new_pin (5959606691619959184) --> + <skip /> + <!-- no translation found for restr_pin_confirm_pin (8501523829633146239) --> + <skip /> + <!-- no translation found for restr_pin_create_pin (8017600000263450337) --> <skip /> <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) --> <skip /> diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml index a4fa7f0..15ecdc2 100644 --- a/core/res/res/values-bg/strings.xml +++ b/core/res/res/values-bg/strings.xml @@ -470,6 +470,10 @@ <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Разрешава на приложението да използва функциите на SurfaceFlinger от ниско ниво."</string> <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"четене на кадровия буфер"</string> <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Разрешава на приложението да чете съдържанието на кадровия буфер."</string> + <!-- no translation found for permlab_accessInputFlinger (5348635270689553857) --> + <skip /> + <!-- no translation found for permdesc_accessInputFlinger (2104864941201226616) --> + <skip /> <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"конфигуриране на дисплеите през WiFi"</string> <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Разрешава на приложението да конфигурира и да се свързва с дисплеите през WiFi."</string> <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"контролиране на дисплеите през WiFi"</string> @@ -639,10 +643,18 @@ <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Разрешава на приложението да управлява правилата на мрежата и да определя такива за конкретно приложение."</string> <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"промяна на отчетността на употребата на мрежа"</string> <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Разрешава на приложението да променя това как употребата на мрежа се отчита спрямо приложенията. Не е предназначено за нормални приложения."</string> + <!-- no translation found for permlab_markNetworkSocket (3658527214914959749) --> + <skip /> + <!-- no translation found for permdesc_markNetworkSocket (7655568433696356578) --> + <skip /> <string name="permlab_accessNotifications" msgid="7673416487873432268">"достъп до известията"</string> <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_invokeCarrierSetup (3699600833975117478) --> + <skip /> + <!-- no translation found for permdesc_invokeCarrierSetup (4159549152529111920) --> + <skip /> <string name="policylab_limitPassword" msgid="4497420728857585791">"Задаване на правила за паролата"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"Контролирайте дължината и разрешените знаци за паролите за отключване на екрана."</string> <string name="policylab_watchLogin" msgid="914130646942199503">"Наблюдаване на опитите за отключване на екрана"</string> @@ -1593,11 +1605,19 @@ <skip /> <!-- no translation found for mediaSize_na_tabloid (5775966416333578127) --> <skip /> - <!-- no translation found for restr_pin_create_pin (8017600000263450337) --> + <!-- no translation found for write_fail_reason_cancelled (7091258378121627624) --> + <skip /> + <!-- no translation found for write_fail_reason_cannot_write (8132505417935337724) --> <skip /> <!-- no translation found for restr_pin_enter_pin (3395953421368476103) --> <skip /> - <!-- no translation found for restr_pin_confirm_pin (2891475237150965991) --> + <!-- no translation found for restr_pin_enter_old_pin (1462206225512910757) --> + <skip /> + <!-- no translation found for restr_pin_enter_new_pin (5959606691619959184) --> + <skip /> + <!-- no translation found for restr_pin_confirm_pin (8501523829633146239) --> + <skip /> + <!-- no translation found for restr_pin_create_pin (8017600000263450337) --> <skip /> <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) --> <skip /> diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml index 05965b3..494457c 100644 --- a/core/res/res/values-ca/strings.xml +++ b/core/res/res/values-ca/strings.xml @@ -279,10 +279,8 @@ <string name="permdesc_reorderTasks" msgid="7734217754877439351">"Permet que l\'aplicació desplaci tasques en primer o segon pla. L\'aplicació pot fer-ho sense que tu ho indiquis."</string> <string name="permlab_removeTasks" msgid="6821513401870377403">"atura les aplicacions que s\'estan executant"</string> <string name="permdesc_removeTasks" msgid="1394714352062635493">"Permet que l\'aplicació elimini tasques i finalitzi les seves aplicacions. Les aplicacions malicioses poden alterar el comportament d\'altres aplicacions."</string> - <!-- no translation found for permlab_manageActivityStacks (7391191384027303065) --> - <skip /> - <!-- no translation found for permdesc_manageActivityStacks (1615881933034084440) --> - <skip /> + <string name="permlab_manageActivityStacks" msgid="7391191384027303065">"gestiona les piles d\'activitats"</string> + <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"Permet que l\'aplicació, afegeixi, suprimeixi i modifiqui les piles d\'activitats on s\'executen altres aplicacions. És possible que les aplicacions malicioses interrompin el comportament d\'altres aplicacions."</string> <string name="permlab_startAnyActivity" msgid="2918768238045206456">"iniciar qualsevol activitat"</string> <string name="permdesc_startAnyActivity" msgid="997823695343584001">"Permet que l\'aplicació iniciï qualsevol activitat, amb independència de la protecció del permís o de l\'estat exportat."</string> <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"definició de la compatibilitat de pantalla"</string> @@ -360,14 +358,10 @@ <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Permet que el titular vinculi a la interfície de nivell superior d\'un mètode d\'entrada. No s\'hauria de necessitar mai per a les aplicacions normals."</string> <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"vincular amb un servei d\'accessibilitat"</string> <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Permet vincular amb la interfície de nivell superior d\'un servei d\'accessibilitat. Les aplicacions normals no haurien de necessitar-ho."</string> - <!-- no translation found for permlab_bindPrintService (8462815179572748761) --> - <skip /> - <!-- no translation found for permdesc_bindPrintService (7960067623209111135) --> - <skip /> - <!-- no translation found for permlab_accessAllPrintJobs (1120792468465711159) --> - <skip /> - <!-- no translation found for permdesc_accessAllPrintJobs (2978185311041864762) --> - <skip /> + <string name="permlab_bindPrintService" msgid="8462815179572748761">"vincula amb un servei d\'impressió"</string> + <string name="permdesc_bindPrintService" msgid="7960067623209111135">"Permet que el titular vinculi a la interfície de nivell superior d\'un servei d\'impressió. No s\'hauria de necessitar mai per a les aplicacions normals."</string> + <string name="permlab_accessAllPrintJobs" msgid="1120792468465711159">"accedeix a totes les tasques d\'impressió"</string> + <string name="permdesc_accessAllPrintJobs" msgid="2978185311041864762">"Permet que el propietari accedeixi a les tasques d\'impressió creades per una altra aplicació. Les aplicacions normals no l\'haurien de necessitar mai."</string> <string name="permlab_bindTextService" msgid="7358378401915287938">"vincula a un servei de text"</string> <string name="permdesc_bindTextService" msgid="8151968910973998670">"Permet al titular vincular amb la interfície de nivell superior d\'un servei de text (per exemple, SpellCheckerService). Les aplicacions normals mai no ho haurien de necessitar."</string> <string name="permlab_bindVpnService" msgid="4708596021161473255">"vincula a un servei de VPN"</string> @@ -470,6 +464,8 @@ <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Permet que l\'aplicació utilitzi funcions SurfaceFlinger de baix nivell."</string> <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"llegir la memòria intermèdia de marcs"</string> <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Permet que l\'aplicació llegeixi el contingut de la memòria intermèdia de marcs."</string> + <string name="permlab_accessInputFlinger" msgid="5348635270689553857">"accedeix a InputFlinger"</string> + <string name="permdesc_accessInputFlinger" msgid="2104864941201226616">"Permet que l\'aplicació utilitzi funcions InputFlinger de baix nivell."</string> <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"configuració de les pantalles Wi-Fi"</string> <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Permet a l\'aplicació configurar-se i connectar-se a les pantalles Wi-Fi."</string> <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"control de les pantalles Wi-Fi"</string> @@ -639,10 +635,14 @@ <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Permet que l\'aplicació gestioni les polítiques de la xarxa i que defineixi les regles específiques d\'aplicació."</string> <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"modificació del càlcul d\'ús de la xarxa"</string> <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Permet que l\'aplicació modifiqui la manera com es calcula l\'ús de la xarxa per part de les aplicacions. No indicat per a les aplicacions normals."</string> + <string name="permlab_markNetworkSocket" msgid="3658527214914959749">"modifica les marques dels sòcols"</string> + <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"Permet que l\'aplicació modifiqui les marques de sòcols per a l\'encaminament"</string> <string name="permlab_accessNotifications" msgid="7673416487873432268">"accedeix a les notificacions"</string> <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 de processament de notificacions"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Permet que el titular vinculi la interfície de nivell superior d\'un servei de processament de notificacions. No s\'hauria de necessitar mai per a les aplicacions normals."</string> + <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"invoca l\'aplicació de configuració proporcionada per l\'operador"</string> + <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Permet que el titular invoqui l\'aplicació de configuració proporcionada per l\'operador. No s\'hauria de necessitar mai per a les aplicacions normals."</string> <string name="policylab_limitPassword" msgid="4497420728857585791">"Defineix les normes de contrasenya"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"Controla la longitud i els caràcters permesos a les contrasenyes de desbloqueig de pantalla."</string> <string name="policylab_watchLogin" msgid="914130646942199503">"Control d\'intents de desbloqueig de pantalla"</string> @@ -752,8 +752,7 @@ <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string> <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string> <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string> - <!-- no translation found for imProtocolGoogleTalk (493902321140277304) --> - <skip /> + <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangouts"</string> <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string> <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string> <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string> @@ -1515,94 +1514,59 @@ <string name="app_no_restricted_accounts" msgid="5739463249673727736">"L\'aplicació no és compatible amb comptes de perfils restringits"</string> <string name="app_not_found" msgid="3429141853498927379">"No s\'ha trobat cap aplicació per processar aquesta acció"</string> <string name="revoke" msgid="5404479185228271586">"Revoca"</string> - <!-- no translation found for mediaSize_iso_a0 (7875427489420821793) --> - <skip /> - <!-- no translation found for mediaSize_iso_a1 (3760734499050875356) --> - <skip /> - <!-- no translation found for mediaSize_iso_a2 (5973266378020144382) --> - <skip /> - <!-- no translation found for mediaSize_iso_a3 (1373407105687300884) --> - <skip /> - <!-- no translation found for mediaSize_iso_a4 (6689772807982597254) --> - <skip /> - <!-- no translation found for mediaSize_iso_a5 (5353549652015741040) --> - <skip /> - <!-- no translation found for mediaSize_iso_a6 (8585038048674911907) --> - <skip /> - <!-- no translation found for mediaSize_iso_a7 (6641836716963839119) --> - <skip /> - <!-- no translation found for mediaSize_iso_a8 (7571139437465693355) --> - <skip /> - <!-- no translation found for mediaSize_iso_a9 (1378455891957115079) --> - <skip /> - <!-- no translation found for mediaSize_iso_a10 (2480747457429475344) --> - <skip /> - <!-- no translation found for mediaSize_iso_b0 (3965935097661108039) --> - <skip /> - <!-- no translation found for mediaSize_iso_b1 (2505753285010115437) --> - <skip /> - <!-- no translation found for mediaSize_iso_b2 (8763874709859458453) --> - <skip /> - <!-- no translation found for mediaSize_iso_b3 (4210506688191764076) --> - <skip /> - <!-- no translation found for mediaSize_iso_b4 (5749404165888526034) --> - <skip /> - <!-- no translation found for mediaSize_iso_b5 (7640627414621904733) --> - <skip /> - <!-- no translation found for mediaSize_iso_b6 (7342988864712748544) --> - <skip /> - <!-- no translation found for mediaSize_iso_b7 (5069844065235382429) --> + <string name="mediaSize_iso_a0" msgid="7875427489420821793">"ISO A0"</string> + <string name="mediaSize_iso_a1" msgid="3760734499050875356">"ISO A1"</string> + <string name="mediaSize_iso_a2" msgid="5973266378020144382">"ISO A2"</string> + <string name="mediaSize_iso_a3" msgid="1373407105687300884">"ISO A3"</string> + <string name="mediaSize_iso_a4" msgid="6689772807982597254">"ISO A4"</string> + <string name="mediaSize_iso_a5" msgid="5353549652015741040">"ISO A5"</string> + <string name="mediaSize_iso_a6" msgid="8585038048674911907">"ISO A6"</string> + <string name="mediaSize_iso_a7" msgid="6641836716963839119">"ISO A7"</string> + <string name="mediaSize_iso_a8" msgid="7571139437465693355">"ISO A8"</string> + <string name="mediaSize_iso_a9" msgid="1378455891957115079">"ISO A9"</string> + <string name="mediaSize_iso_a10" msgid="2480747457429475344">"ISO A10"</string> + <string name="mediaSize_iso_b0" msgid="3965935097661108039">"ISO B0"</string> + <string name="mediaSize_iso_b1" msgid="2505753285010115437">"ISO B1"</string> + <string name="mediaSize_iso_b2" msgid="8763874709859458453">"ISO B2"</string> + <string name="mediaSize_iso_b3" msgid="4210506688191764076">"ISO B3"</string> + <string name="mediaSize_iso_b4" msgid="5749404165888526034">"ISO B4"</string> + <string name="mediaSize_iso_b5" msgid="7640627414621904733">"ISO B5"</string> + <string name="mediaSize_iso_b6" msgid="7342988864712748544">"ISO B6"</string> + <string name="mediaSize_iso_b7" msgid="5069844065235382429">"ISO B7"</string> + <string name="mediaSize_iso_b8" msgid="7316818922278779774">"ISO B8"</string> + <string name="mediaSize_iso_b9" msgid="5414727094026532341">"ISO B9"</string> + <string name="mediaSize_iso_b10" msgid="5251253731832048185">"ISO B10"</string> + <string name="mediaSize_iso_c0" msgid="4003138342671964217">"ISO C0"</string> + <string name="mediaSize_iso_c1" msgid="1935188063393553008">"ISO C1"</string> + <string name="mediaSize_iso_c2" msgid="3197307969712069904">"ISO C2"</string> + <string name="mediaSize_iso_c3" msgid="4335826087321913508">"ISO C3"</string> + <string name="mediaSize_iso_c4" msgid="3745639598281015005">"ISO C4"</string> + <string name="mediaSize_iso_c5" msgid="8269457765822791013">"ISO C5"</string> + <string name="mediaSize_iso_c6" msgid="566666105260346930">"ISO C6"</string> + <string name="mediaSize_iso_c7" msgid="8678413180782608498">"ISO C7"</string> + <string name="mediaSize_iso_c8" msgid="8392376206627041730">"ISO C8"</string> + <string name="mediaSize_iso_c9" msgid="9191613372324845405">"ISO C9"</string> + <string name="mediaSize_iso_c10" msgid="7327709699184920822">"ISO C10"</string> + <string name="mediaSize_na_letter" msgid="4191805615829472953">"Carta"</string> + <string name="mediaSize_na_gvrnmt_letter" msgid="7853382192649405507">"Carta governamental"</string> + <string name="mediaSize_na_legal" msgid="6697982988283823150">"Legal"</string> + <string name="mediaSize_na_junior_legal" msgid="3727743969902758948">"Legal Junior"</string> + <string name="mediaSize_na_ledger" msgid="281871464896601236">"Llibre major"</string> + <string name="mediaSize_na_tabloid" msgid="5775966416333578127">"Tabloide"</string> + <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"Cancel·lada"</string> + <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"Error en escriure el contingut"</string> + <string name="restr_pin_enter_pin" msgid="3395953421368476103">"Introdueix el PIN"</string> + <!-- no translation found for restr_pin_enter_old_pin (1462206225512910757) --> <skip /> - <!-- no translation found for mediaSize_iso_b8 (7316818922278779774) --> + <!-- no translation found for restr_pin_enter_new_pin (5959606691619959184) --> <skip /> - <!-- no translation found for mediaSize_iso_b9 (5414727094026532341) --> + <!-- no translation found for restr_pin_confirm_pin (8501523829633146239) --> <skip /> - <!-- no translation found for mediaSize_iso_b10 (5251253731832048185) --> - <skip /> - <!-- no translation found for mediaSize_iso_c0 (4003138342671964217) --> - <skip /> - <!-- no translation found for mediaSize_iso_c1 (1935188063393553008) --> - <skip /> - <!-- no translation found for mediaSize_iso_c2 (3197307969712069904) --> - <skip /> - <!-- no translation found for mediaSize_iso_c3 (4335826087321913508) --> - <skip /> - <!-- no translation found for mediaSize_iso_c4 (3745639598281015005) --> - <skip /> - <!-- no translation found for mediaSize_iso_c5 (8269457765822791013) --> - <skip /> - <!-- no translation found for mediaSize_iso_c6 (566666105260346930) --> - <skip /> - <!-- no translation found for mediaSize_iso_c7 (8678413180782608498) --> - <skip /> - <!-- no translation found for mediaSize_iso_c8 (8392376206627041730) --> - <skip /> - <!-- no translation found for mediaSize_iso_c9 (9191613372324845405) --> - <skip /> - <!-- no translation found for mediaSize_iso_c10 (7327709699184920822) --> - <skip /> - <!-- no translation found for mediaSize_na_letter (4191805615829472953) --> - <skip /> - <!-- no translation found for mediaSize_na_gvrnmt_letter (7853382192649405507) --> - <skip /> - <!-- no translation found for mediaSize_na_legal (6697982988283823150) --> - <skip /> - <!-- no translation found for mediaSize_na_junior_legal (3727743969902758948) --> - <skip /> - <!-- no translation found for mediaSize_na_ledger (281871464896601236) --> - <skip /> - <!-- no translation found for mediaSize_na_tabloid (5775966416333578127) --> - <skip /> - <!-- no translation found for restr_pin_create_pin (8017600000263450337) --> - <skip /> - <!-- no translation found for restr_pin_enter_pin (3395953421368476103) --> - <skip /> - <!-- no translation found for restr_pin_confirm_pin (2891475237150965991) --> - <skip /> - <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) --> - <skip /> - <!-- no translation found for restr_pin_error_too_short (8173982756265777792) --> - <skip /> - <!-- no translation found for restr_pin_countdown:one (4835639969503729874) --> - <!-- no translation found for restr_pin_countdown:other (8030607343223287654) --> + <string name="restr_pin_create_pin" msgid="8017600000263450337">"Crea un pin per modificar les restriccions"</string> + <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"Els PIN no coincideixen. Torna-ho a provar."</string> + <string name="restr_pin_error_too_short" msgid="8173982756265777792">"El PIN és massa curt. Ha de tenir quatre dígits com a mínim."</string> + <plurals name="restr_pin_countdown"> + <item quantity="one" msgid="4835639969503729874">"PIN incorrecte. Torna-ho a provar d\'aquí a 1 segon."</item> + <item quantity="other" msgid="8030607343223287654">"PIN incorrecte. Torna-ho a provar d\'aquí a <xliff:g id="COUNT">%d</xliff:g> segons."</item> + </plurals> </resources> diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml index 9f3a090..7f7700a 100644 --- a/core/res/res/values-cs/strings.xml +++ b/core/res/res/values-cs/strings.xml @@ -279,10 +279,8 @@ <string name="permdesc_reorderTasks" msgid="7734217754877439351">"Umožňuje aplikaci přesunout úlohy na popředí nebo pozadí. Aplikace tak může činit bez vašeho zásahu."</string> <string name="permlab_removeTasks" msgid="6821513401870377403">"zastavení činnosti aplikací"</string> <string name="permdesc_removeTasks" msgid="1394714352062635493">"Umožňuje aplikaci odstranit úlohy a ukončit jejich aplikace. Škodlivé aplikace mohou narušit chování ostatních aplikací."</string> - <!-- no translation found for permlab_manageActivityStacks (7391191384027303065) --> - <skip /> - <!-- no translation found for permdesc_manageActivityStacks (1615881933034084440) --> - <skip /> + <string name="permlab_manageActivityStacks" msgid="7391191384027303065">"spravovat zásobníky aktivit"</string> + <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"Umožňuje aplikaci přidat, odstranit nebo upravit zásobníky aktivit jiných aplikací. Škodlivé aplikace mohou narušit chování ostatních aplikací."</string> <string name="permlab_startAnyActivity" msgid="2918768238045206456">"zahájení libovolné činnosti"</string> <string name="permdesc_startAnyActivity" msgid="997823695343584001">"Umožňuje aplikaci zahájit libovolnou aktivitu bez ohledu na ochranu pomocí oprávnění či exportovaný stav."</string> <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"nastavit kompatibilitu obrazovky"</string> @@ -360,14 +358,10 @@ <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Umožňuje držiteli vázat se na nejvyšší úroveň rozhraní pro zadávání dat. Běžné aplikace by toto oprávnění neměly nikdy požadovat."</string> <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"navázat se na službu usnadnění přístupu"</string> <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Umožňuje držiteli navázat se na nejvyšší úroveň rozhraní služby usnadnění přístupu. Běžné aplikace by toto oprávnění neměly nikdy požadovat."</string> - <!-- no translation found for permlab_bindPrintService (8462815179572748761) --> - <skip /> - <!-- no translation found for permdesc_bindPrintService (7960067623209111135) --> - <skip /> - <!-- no translation found for permlab_accessAllPrintJobs (1120792468465711159) --> - <skip /> - <!-- no translation found for permdesc_accessAllPrintJobs (2978185311041864762) --> - <skip /> + <string name="permlab_bindPrintService" msgid="8462815179572748761">"navázat se na tiskovou službu"</string> + <string name="permdesc_bindPrintService" msgid="7960067623209111135">"Umožňuje navázání na nejvyšší úroveň tiskové služby. Běžné aplikace by toto oprávnění neměly nikdy požadovat."</string> + <string name="permlab_accessAllPrintJobs" msgid="1120792468465711159">"přístup ke všem tiskovým úlohám"</string> + <string name="permdesc_accessAllPrintJobs" msgid="2978185311041864762">"Umožňuje přístup k tiskovým úlohám vytvořeným jinou aplikací. Běžné aplikace by toto oprávnění neměly nikdy požadovat."</string> <string name="permlab_bindTextService" msgid="7358378401915287938">"navázat se na textovou službu"</string> <string name="permdesc_bindTextService" msgid="8151968910973998670">"Umožňuje držiteli připojit se k nejvyšší úrovni rozhraní textové služby (např. SpellCheckerService). Běžné aplikace by toto oprávnění neměly nikdy požadovat."</string> <string name="permlab_bindVpnService" msgid="4708596021161473255">"navázat se na službu VPN"</string> @@ -470,6 +464,8 @@ <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Umožňuje aplikaci používat nízkoúrovňové funkce SurfaceFlinger."</string> <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"čtení vyrovnávací paměti snímků"</string> <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Umožňuje aplikaci číst obsah vyrovnávací paměti snímků."</string> + <string name="permlab_accessInputFlinger" msgid="5348635270689553857">"přístup k funkci InputFlinger"</string> + <string name="permdesc_accessInputFlinger" msgid="2104864941201226616">"Umožňuje aplikaci používat nízkoúrovňové funkce InputFlinger."</string> <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"konfigurovat displeje přes Wi-Fi"</string> <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Povoluje aplikaci připojit a konfigurovat displeje přes Wi-Fi."</string> <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"ovládat displeje přes Wi-Fi"</string> @@ -639,10 +635,14 @@ <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Umožňuje aplikaci spravovat zásady sítě a definovat pravidla pro konkrétní aplikace."</string> <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"upravit kontrolu používání sítě"</string> <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Umožňuje aplikaci upravit způsob výpočtu využití sítě aplikacemi. Toto oprávnění není určeno pro běžné aplikace."</string> + <string name="permlab_markNetworkSocket" msgid="3658527214914959749">"upravit značky soketů"</string> + <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"Umožňuje aplikaci upravit značky soketů pro směrování"</string> <string name="permlab_accessNotifications" msgid="7673416487873432268">"přístup k oznámením"</string> <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_invokeCarrierSetup" msgid="3699600833975117478">"vyvolat konfigurační aplikaci poskytnutou operátorem"</string> + <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Umožňuje vyvolání konfigurační aplikace poskytnuté operátorem. Běžné aplikace by toto oprávnění neměly nikdy požadovat."</string> <string name="policylab_limitPassword" msgid="4497420728857585791">"Nastavit pravidla pro heslo"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"Řídit délku hesel pro odemčení obrazovky a povolené znaky."</string> <string name="policylab_watchLogin" msgid="914130646942199503">"Sledovat pokusy o odemčení obrazovky"</string> @@ -752,8 +752,7 @@ <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string> <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string> <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string> - <!-- no translation found for imProtocolGoogleTalk (493902321140277304) --> - <skip /> + <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangouts"</string> <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string> <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string> <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string> @@ -1515,94 +1514,59 @@ <string name="app_no_restricted_accounts" msgid="5739463249673727736">"Tato aplikace nepodporuje účty pro omezené profily"</string> <string name="app_not_found" msgid="3429141853498927379">"Aplikace potřebná k provedení této akce nebyla nalezena"</string> <string name="revoke" msgid="5404479185228271586">"Zrušit"</string> - <!-- no translation found for mediaSize_iso_a0 (7875427489420821793) --> - <skip /> - <!-- no translation found for mediaSize_iso_a1 (3760734499050875356) --> - <skip /> - <!-- no translation found for mediaSize_iso_a2 (5973266378020144382) --> - <skip /> - <!-- no translation found for mediaSize_iso_a3 (1373407105687300884) --> - <skip /> - <!-- no translation found for mediaSize_iso_a4 (6689772807982597254) --> - <skip /> - <!-- no translation found for mediaSize_iso_a5 (5353549652015741040) --> - <skip /> - <!-- no translation found for mediaSize_iso_a6 (8585038048674911907) --> - <skip /> - <!-- no translation found for mediaSize_iso_a7 (6641836716963839119) --> - <skip /> - <!-- no translation found for mediaSize_iso_a8 (7571139437465693355) --> - <skip /> - <!-- no translation found for mediaSize_iso_a9 (1378455891957115079) --> - <skip /> - <!-- no translation found for mediaSize_iso_a10 (2480747457429475344) --> - <skip /> - <!-- no translation found for mediaSize_iso_b0 (3965935097661108039) --> - <skip /> - <!-- no translation found for mediaSize_iso_b1 (2505753285010115437) --> - <skip /> - <!-- no translation found for mediaSize_iso_b2 (8763874709859458453) --> - <skip /> - <!-- no translation found for mediaSize_iso_b3 (4210506688191764076) --> - <skip /> - <!-- no translation found for mediaSize_iso_b4 (5749404165888526034) --> - <skip /> - <!-- no translation found for mediaSize_iso_b5 (7640627414621904733) --> - <skip /> - <!-- no translation found for mediaSize_iso_b6 (7342988864712748544) --> - <skip /> - <!-- no translation found for mediaSize_iso_b7 (5069844065235382429) --> + <string name="mediaSize_iso_a0" msgid="7875427489420821793">"ISO A0"</string> + <string name="mediaSize_iso_a1" msgid="3760734499050875356">"ISO A1"</string> + <string name="mediaSize_iso_a2" msgid="5973266378020144382">"ISO A2"</string> + <string name="mediaSize_iso_a3" msgid="1373407105687300884">"ISO A3"</string> + <string name="mediaSize_iso_a4" msgid="6689772807982597254">"ISO A4"</string> + <string name="mediaSize_iso_a5" msgid="5353549652015741040">"ISO A5"</string> + <string name="mediaSize_iso_a6" msgid="8585038048674911907">"ISO A6"</string> + <string name="mediaSize_iso_a7" msgid="6641836716963839119">"ISO A7"</string> + <string name="mediaSize_iso_a8" msgid="7571139437465693355">"ISO A8"</string> + <string name="mediaSize_iso_a9" msgid="1378455891957115079">"ISO A9"</string> + <string name="mediaSize_iso_a10" msgid="2480747457429475344">"ISO A10"</string> + <string name="mediaSize_iso_b0" msgid="3965935097661108039">"ISO B0"</string> + <string name="mediaSize_iso_b1" msgid="2505753285010115437">"ISO B1"</string> + <string name="mediaSize_iso_b2" msgid="8763874709859458453">"ISO B2"</string> + <string name="mediaSize_iso_b3" msgid="4210506688191764076">"ISO B3"</string> + <string name="mediaSize_iso_b4" msgid="5749404165888526034">"ISO B4"</string> + <string name="mediaSize_iso_b5" msgid="7640627414621904733">"ISO B5"</string> + <string name="mediaSize_iso_b6" msgid="7342988864712748544">"ISO B6"</string> + <string name="mediaSize_iso_b7" msgid="5069844065235382429">"ISO B7"</string> + <string name="mediaSize_iso_b8" msgid="7316818922278779774">"ISO B8"</string> + <string name="mediaSize_iso_b9" msgid="5414727094026532341">"ISO B9"</string> + <string name="mediaSize_iso_b10" msgid="5251253731832048185">"ISO B10"</string> + <string name="mediaSize_iso_c0" msgid="4003138342671964217">"ISO C0"</string> + <string name="mediaSize_iso_c1" msgid="1935188063393553008">"ISO C1"</string> + <string name="mediaSize_iso_c2" msgid="3197307969712069904">"ISO C2"</string> + <string name="mediaSize_iso_c3" msgid="4335826087321913508">"ISO C3"</string> + <string name="mediaSize_iso_c4" msgid="3745639598281015005">"ISO C4"</string> + <string name="mediaSize_iso_c5" msgid="8269457765822791013">"ISO C5"</string> + <string name="mediaSize_iso_c6" msgid="566666105260346930">"ISO C6"</string> + <string name="mediaSize_iso_c7" msgid="8678413180782608498">"ISO C7"</string> + <string name="mediaSize_iso_c8" msgid="8392376206627041730">"ISO C8"</string> + <string name="mediaSize_iso_c9" msgid="9191613372324845405">"ISO C9"</string> + <string name="mediaSize_iso_c10" msgid="7327709699184920822">"ISO C10"</string> + <string name="mediaSize_na_letter" msgid="4191805615829472953">"Letter"</string> + <string name="mediaSize_na_gvrnmt_letter" msgid="7853382192649405507">"Government Letter"</string> + <string name="mediaSize_na_legal" msgid="6697982988283823150">"Legal"</string> + <string name="mediaSize_na_junior_legal" msgid="3727743969902758948">"Junior Legal"</string> + <string name="mediaSize_na_ledger" msgid="281871464896601236">"Ledger"</string> + <string name="mediaSize_na_tabloid" msgid="5775966416333578127">"Tabloid"</string> + <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"Zrušeno"</string> + <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"Při zápisu obsahu došlo k chybě"</string> + <string name="restr_pin_enter_pin" msgid="3395953421368476103">"Zadejte kód PIN"</string> + <!-- no translation found for restr_pin_enter_old_pin (1462206225512910757) --> <skip /> - <!-- no translation found for mediaSize_iso_b8 (7316818922278779774) --> + <!-- no translation found for restr_pin_enter_new_pin (5959606691619959184) --> <skip /> - <!-- no translation found for mediaSize_iso_b9 (5414727094026532341) --> + <!-- no translation found for restr_pin_confirm_pin (8501523829633146239) --> <skip /> - <!-- no translation found for mediaSize_iso_b10 (5251253731832048185) --> - <skip /> - <!-- no translation found for mediaSize_iso_c0 (4003138342671964217) --> - <skip /> - <!-- no translation found for mediaSize_iso_c1 (1935188063393553008) --> - <skip /> - <!-- no translation found for mediaSize_iso_c2 (3197307969712069904) --> - <skip /> - <!-- no translation found for mediaSize_iso_c3 (4335826087321913508) --> - <skip /> - <!-- no translation found for mediaSize_iso_c4 (3745639598281015005) --> - <skip /> - <!-- no translation found for mediaSize_iso_c5 (8269457765822791013) --> - <skip /> - <!-- no translation found for mediaSize_iso_c6 (566666105260346930) --> - <skip /> - <!-- no translation found for mediaSize_iso_c7 (8678413180782608498) --> - <skip /> - <!-- no translation found for mediaSize_iso_c8 (8392376206627041730) --> - <skip /> - <!-- no translation found for mediaSize_iso_c9 (9191613372324845405) --> - <skip /> - <!-- no translation found for mediaSize_iso_c10 (7327709699184920822) --> - <skip /> - <!-- no translation found for mediaSize_na_letter (4191805615829472953) --> - <skip /> - <!-- no translation found for mediaSize_na_gvrnmt_letter (7853382192649405507) --> - <skip /> - <!-- no translation found for mediaSize_na_legal (6697982988283823150) --> - <skip /> - <!-- no translation found for mediaSize_na_junior_legal (3727743969902758948) --> - <skip /> - <!-- no translation found for mediaSize_na_ledger (281871464896601236) --> - <skip /> - <!-- no translation found for mediaSize_na_tabloid (5775966416333578127) --> - <skip /> - <!-- no translation found for restr_pin_create_pin (8017600000263450337) --> - <skip /> - <!-- no translation found for restr_pin_enter_pin (3395953421368476103) --> - <skip /> - <!-- no translation found for restr_pin_confirm_pin (2891475237150965991) --> - <skip /> - <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) --> - <skip /> - <!-- no translation found for restr_pin_error_too_short (8173982756265777792) --> - <skip /> - <!-- no translation found for restr_pin_countdown:one (4835639969503729874) --> - <!-- no translation found for restr_pin_countdown:other (8030607343223287654) --> + <string name="restr_pin_create_pin" msgid="8017600000263450337">"Vytvořit kód PIN pro úpravy omezení"</string> + <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"Kódy PIN se neshodují. Zkuste to znovu."</string> + <string name="restr_pin_error_too_short" msgid="8173982756265777792">"Kód PIN je příliš krátký. Musí mít alespoň čtyři číslice."</string> + <plurals name="restr_pin_countdown"> + <item quantity="one" msgid="4835639969503729874">"Nesprávný kód PIN. Zkuste to znovu za jednu sekundu."</item> + <item quantity="other" msgid="8030607343223287654">"Nesprávný kód PIN. Zkuste to znovu za <xliff:g id="COUNT">%d</xliff:g> s."</item> + </plurals> </resources> diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml index 80e14c8..cc796b6 100644 --- a/core/res/res/values-da/strings.xml +++ b/core/res/res/values-da/strings.xml @@ -279,10 +279,8 @@ <string name="permdesc_reorderTasks" msgid="7734217754877439351">"Tillader, at appen kan flytte opgaver til forgrunden og baggrunden. Appen kan gøre dette uden din bekræftelse."</string> <string name="permlab_removeTasks" msgid="6821513401870377403">"stoppe kørsel af apps"</string> <string name="permdesc_removeTasks" msgid="1394714352062635493">"Tillader, at en app kan fjerne opgaver og lukke deres apps. Ondsindede apps kan forstyrre adfærden for andre apps."</string> - <!-- no translation found for permlab_manageActivityStacks (7391191384027303065) --> - <skip /> - <!-- no translation found for permdesc_manageActivityStacks (1615881933034084440) --> - <skip /> + <string name="permlab_manageActivityStacks" msgid="7391191384027303065">"administrere aktivitetsstakke"</string> + <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"Tillader, at appen tilføjer, fjerner og ændrer aktivitetsstakkene, hvori andre apps kører. Skadelige apps kan forstyrre adfærden for andre apps."</string> <string name="permlab_startAnyActivity" msgid="2918768238045206456">"starte en aktivitet"</string> <string name="permdesc_startAnyActivity" msgid="997823695343584001">"Tillader, at appen starter en hvilken som helst aktivitet, uanset tilladelsesbeskyttelse eller eksporteret tilstand."</string> <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"indstil skærmens kompatibilitet"</string> @@ -360,14 +358,10 @@ <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Tillader, at brugeren kan forpligter sig til en inputmetodes grænseflade på øverste niveau. Bør aldrig være nødvendigt til almindelige apps."</string> <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"bind dig til en tilgængelighedstjeneste"</string> <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Tillader, at brugeren binder sig til en grænseflade for en tilgængelighedstjeneste på øverste niveau. Bør aldrig være nødvendigt til almindelige apps."</string> - <!-- no translation found for permlab_bindPrintService (8462815179572748761) --> - <skip /> - <!-- no translation found for permdesc_bindPrintService (7960067623209111135) --> - <skip /> - <!-- no translation found for permlab_accessAllPrintJobs (1120792468465711159) --> - <skip /> - <!-- no translation found for permdesc_accessAllPrintJobs (2978185311041864762) --> - <skip /> + <string name="permlab_bindPrintService" msgid="8462815179572748761">"forbinde til en udskriftstjeneste"</string> + <string name="permdesc_bindPrintService" msgid="7960067623209111135">"Tillader, at brugeren forbinder til grænsefladen for en udskriftstjeneste på øverste niveau. Dette bør aldrig være nødvendigt for almindelige apps."</string> + <string name="permlab_accessAllPrintJobs" msgid="1120792468465711159">"få adgang til alle udskriftsjob"</string> + <string name="permdesc_accessAllPrintJobs" msgid="2978185311041864762">"Tillader, at brugeren får adgang til udskriftsjob, der er oprettet af en anden app. Dette bør aldrig være nødvendigt for almindelige apps."</string> <string name="permlab_bindTextService" msgid="7358378401915287938">"forpligte sig til en sms-tjeneste"</string> <string name="permdesc_bindTextService" msgid="8151968910973998670">"Tillader, at ejeren kan binde en teksttjenestes grænseflade (f. eks. SpellCheckerService) på øverste niveau. Dette bør aldrig være nødvendigt til normale apps."</string> <string name="permlab_bindVpnService" msgid="4708596021161473255">"bind til en VPN-tjeneste"</string> @@ -470,6 +464,8 @@ <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Tillader, at appen kan bruge SurfaceFlinger-funktioner på lavt niveau."</string> <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"læs rammebuffer"</string> <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Tillader, at appen kan læse indholdet fra rammebufferen."</string> + <string name="permlab_accessInputFlinger" msgid="5348635270689553857">"få adgang til InputFlinger"</string> + <string name="permdesc_accessInputFlinger" msgid="2104864941201226616">"Giver appen tilladelse til at bruge SurfaceFlinger-funktioner på lavt niveau."</string> <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"konfigurer Wi-Fi-skærme"</string> <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Tillader, at appen konfigurerer og opretter forbindelse til Wi-Fi-skærme."</string> <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"kontrollér Wi-Fi-skærme"</string> @@ -639,10 +635,14 @@ <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Tillader, at appen kan administrere netværkspolitikker og definere appspecifikke regler."</string> <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"skift afregning af netværksbrug"</string> <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Tillader, at appen kan ændre den måde, som netværksforbrug udregnes på i forhold til apps. Anvendes ikke af normale apps."</string> + <string name="permlab_markNetworkSocket" msgid="3658527214914959749">"ændre socketmærker"</string> + <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"Tillader, at appen ændrer socketmærker ved omdirigering"</string> <string name="permlab_accessNotifications" msgid="7673416487873432268">"adgang til underretninger"</string> <string name="permdesc_accessNotifications" msgid="458457742683431387">"Tillader, at appen kan hente, undersøge og rydde underretninger, herunder 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_invokeCarrierSetup" msgid="3699600833975117478">"aktivere konfigurationsappen, der leveres af mobilselskabet"</string> + <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Tillader, at brugeren aktiverer konfigurationsappen, der er ydet af mobilselskabet. Dette bør aldrig være nødvendigt for almindelige apps."</string> <string name="policylab_limitPassword" msgid="4497420728857585791">"Indstil regler for adgangskode"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"Kontroller længden samt tilladte tegn i adgangskoder til oplåsning af skærmen."</string> <string name="policylab_watchLogin" msgid="914130646942199503">"Overvåg forsøg på oplåsning af skærm"</string> @@ -752,8 +752,7 @@ <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string> <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string> <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string> - <!-- no translation found for imProtocolGoogleTalk (493902321140277304) --> - <skip /> + <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangouts"</string> <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string> <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string> <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string> @@ -1515,94 +1514,59 @@ <string name="app_no_restricted_accounts" msgid="5739463249673727736">"Denne applikation understøtter ikke konti for begrænsede profiler"</string> <string name="app_not_found" msgid="3429141853498927379">"Der blev ikke fundet nogen applikation, der kan håndtere denne handling"</string> <string name="revoke" msgid="5404479185228271586">"Tilbagekald"</string> - <!-- no translation found for mediaSize_iso_a0 (7875427489420821793) --> - <skip /> - <!-- no translation found for mediaSize_iso_a1 (3760734499050875356) --> - <skip /> - <!-- no translation found for mediaSize_iso_a2 (5973266378020144382) --> - <skip /> - <!-- no translation found for mediaSize_iso_a3 (1373407105687300884) --> - <skip /> - <!-- no translation found for mediaSize_iso_a4 (6689772807982597254) --> - <skip /> - <!-- no translation found for mediaSize_iso_a5 (5353549652015741040) --> - <skip /> - <!-- no translation found for mediaSize_iso_a6 (8585038048674911907) --> - <skip /> - <!-- no translation found for mediaSize_iso_a7 (6641836716963839119) --> - <skip /> - <!-- no translation found for mediaSize_iso_a8 (7571139437465693355) --> - <skip /> - <!-- no translation found for mediaSize_iso_a9 (1378455891957115079) --> - <skip /> - <!-- no translation found for mediaSize_iso_a10 (2480747457429475344) --> - <skip /> - <!-- no translation found for mediaSize_iso_b0 (3965935097661108039) --> - <skip /> - <!-- no translation found for mediaSize_iso_b1 (2505753285010115437) --> - <skip /> - <!-- no translation found for mediaSize_iso_b2 (8763874709859458453) --> - <skip /> - <!-- no translation found for mediaSize_iso_b3 (4210506688191764076) --> - <skip /> - <!-- no translation found for mediaSize_iso_b4 (5749404165888526034) --> - <skip /> - <!-- no translation found for mediaSize_iso_b5 (7640627414621904733) --> - <skip /> - <!-- no translation found for mediaSize_iso_b6 (7342988864712748544) --> - <skip /> - <!-- no translation found for mediaSize_iso_b7 (5069844065235382429) --> + <string name="mediaSize_iso_a0" msgid="7875427489420821793">"ISO A0"</string> + <string name="mediaSize_iso_a1" msgid="3760734499050875356">"ISO A1"</string> + <string name="mediaSize_iso_a2" msgid="5973266378020144382">"ISO A2"</string> + <string name="mediaSize_iso_a3" msgid="1373407105687300884">"ISO A3"</string> + <string name="mediaSize_iso_a4" msgid="6689772807982597254">"ISO A4"</string> + <string name="mediaSize_iso_a5" msgid="5353549652015741040">"ISO A5"</string> + <string name="mediaSize_iso_a6" msgid="8585038048674911907">"ISO A6"</string> + <string name="mediaSize_iso_a7" msgid="6641836716963839119">"ISO A7"</string> + <string name="mediaSize_iso_a8" msgid="7571139437465693355">"ISO A8"</string> + <string name="mediaSize_iso_a9" msgid="1378455891957115079">"ISO A9"</string> + <string name="mediaSize_iso_a10" msgid="2480747457429475344">"ISO A10"</string> + <string name="mediaSize_iso_b0" msgid="3965935097661108039">"ISO B0"</string> + <string name="mediaSize_iso_b1" msgid="2505753285010115437">"ISO B1"</string> + <string name="mediaSize_iso_b2" msgid="8763874709859458453">"ISO B2"</string> + <string name="mediaSize_iso_b3" msgid="4210506688191764076">"ISO B3"</string> + <string name="mediaSize_iso_b4" msgid="5749404165888526034">"ISO B4"</string> + <string name="mediaSize_iso_b5" msgid="7640627414621904733">"ISO B5"</string> + <string name="mediaSize_iso_b6" msgid="7342988864712748544">"ISO B6"</string> + <string name="mediaSize_iso_b7" msgid="5069844065235382429">"ISO B7"</string> + <string name="mediaSize_iso_b8" msgid="7316818922278779774">"ISO B8"</string> + <string name="mediaSize_iso_b9" msgid="5414727094026532341">"ISO B9"</string> + <string name="mediaSize_iso_b10" msgid="5251253731832048185">"ISO B10"</string> + <string name="mediaSize_iso_c0" msgid="4003138342671964217">"ISO C0"</string> + <string name="mediaSize_iso_c1" msgid="1935188063393553008">"ISO C1"</string> + <string name="mediaSize_iso_c2" msgid="3197307969712069904">"ISO C2"</string> + <string name="mediaSize_iso_c3" msgid="4335826087321913508">"ISO C3"</string> + <string name="mediaSize_iso_c4" msgid="3745639598281015005">"ISO C4"</string> + <string name="mediaSize_iso_c5" msgid="8269457765822791013">"ISO C5"</string> + <string name="mediaSize_iso_c6" msgid="566666105260346930">"ISO C6"</string> + <string name="mediaSize_iso_c7" msgid="8678413180782608498">"ISO C7"</string> + <string name="mediaSize_iso_c8" msgid="8392376206627041730">"ISO C8"</string> + <string name="mediaSize_iso_c9" msgid="9191613372324845405">"ISO C9"</string> + <string name="mediaSize_iso_c10" msgid="7327709699184920822">"ISO C10"</string> + <string name="mediaSize_na_letter" msgid="4191805615829472953">"Amerikansk \"Letter\""</string> + <string name="mediaSize_na_gvrnmt_letter" msgid="7853382192649405507">"Amerikansk \"Government Letter\""</string> + <string name="mediaSize_na_legal" msgid="6697982988283823150">"Amerikansk \"Legal\""</string> + <string name="mediaSize_na_junior_legal" msgid="3727743969902758948">"Amerikansk \"Junior Legal\""</string> + <string name="mediaSize_na_ledger" msgid="281871464896601236">"Amerikansk \"Ledger\""</string> + <string name="mediaSize_na_tabloid" msgid="5775966416333578127">"Amerikansk \"Tabloid\""</string> + <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"Annulleret"</string> + <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"Fejl ved skrivning af indhold"</string> + <string name="restr_pin_enter_pin" msgid="3395953421368476103">"Indtast pinkode"</string> + <!-- no translation found for restr_pin_enter_old_pin (1462206225512910757) --> <skip /> - <!-- no translation found for mediaSize_iso_b8 (7316818922278779774) --> + <!-- no translation found for restr_pin_enter_new_pin (5959606691619959184) --> <skip /> - <!-- no translation found for mediaSize_iso_b9 (5414727094026532341) --> + <!-- no translation found for restr_pin_confirm_pin (8501523829633146239) --> <skip /> - <!-- no translation found for mediaSize_iso_b10 (5251253731832048185) --> - <skip /> - <!-- no translation found for mediaSize_iso_c0 (4003138342671964217) --> - <skip /> - <!-- no translation found for mediaSize_iso_c1 (1935188063393553008) --> - <skip /> - <!-- no translation found for mediaSize_iso_c2 (3197307969712069904) --> - <skip /> - <!-- no translation found for mediaSize_iso_c3 (4335826087321913508) --> - <skip /> - <!-- no translation found for mediaSize_iso_c4 (3745639598281015005) --> - <skip /> - <!-- no translation found for mediaSize_iso_c5 (8269457765822791013) --> - <skip /> - <!-- no translation found for mediaSize_iso_c6 (566666105260346930) --> - <skip /> - <!-- no translation found for mediaSize_iso_c7 (8678413180782608498) --> - <skip /> - <!-- no translation found for mediaSize_iso_c8 (8392376206627041730) --> - <skip /> - <!-- no translation found for mediaSize_iso_c9 (9191613372324845405) --> - <skip /> - <!-- no translation found for mediaSize_iso_c10 (7327709699184920822) --> - <skip /> - <!-- no translation found for mediaSize_na_letter (4191805615829472953) --> - <skip /> - <!-- no translation found for mediaSize_na_gvrnmt_letter (7853382192649405507) --> - <skip /> - <!-- no translation found for mediaSize_na_legal (6697982988283823150) --> - <skip /> - <!-- no translation found for mediaSize_na_junior_legal (3727743969902758948) --> - <skip /> - <!-- no translation found for mediaSize_na_ledger (281871464896601236) --> - <skip /> - <!-- no translation found for mediaSize_na_tabloid (5775966416333578127) --> - <skip /> - <!-- no translation found for restr_pin_create_pin (8017600000263450337) --> - <skip /> - <!-- no translation found for restr_pin_enter_pin (3395953421368476103) --> - <skip /> - <!-- no translation found for restr_pin_confirm_pin (2891475237150965991) --> - <skip /> - <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) --> - <skip /> - <!-- no translation found for restr_pin_error_too_short (8173982756265777792) --> - <skip /> - <!-- no translation found for restr_pin_countdown:one (4835639969503729874) --> - <!-- no translation found for restr_pin_countdown:other (8030607343223287654) --> + <string name="restr_pin_create_pin" msgid="8017600000263450337">"Opret en pinkode til ændring af begrænsninger"</string> + <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"Pinkoderne stemmer ikke overens. Prøv igen."</string> + <string name="restr_pin_error_too_short" msgid="8173982756265777792">"Pinkoden er for kort. Den skal være på mindst 4 tal."</string> + <plurals name="restr_pin_countdown"> + <item quantity="one" msgid="4835639969503729874">"Forkert pinkode. Prøv igen om 1 sekund."</item> + <item quantity="other" msgid="8030607343223287654">"Forkert pinkode. Prøv igen om <xliff:g id="COUNT">%d</xliff:g> sekunder."</item> + </plurals> </resources> diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml index be81e63..729ce6c 100644 --- a/core/res/res/values-de/strings.xml +++ b/core/res/res/values-de/strings.xml @@ -279,10 +279,8 @@ <string name="permdesc_reorderTasks" msgid="7734217754877439351">"Ermöglicht der App, Aufgaben in den Vorder- und Hintergrund zu verschieben, ohne dass dazu ein Eingreifen Ihrerseits notwendig ist."</string> <string name="permlab_removeTasks" msgid="6821513401870377403">"Aktive Apps beenden"</string> <string name="permdesc_removeTasks" msgid="1394714352062635493">"Ermöglicht der App, Aufgaben zu entfernen und die entsprechenden Apps zu beenden. Schädliche Apps können das Verhalten anderer Apps stören."</string> - <!-- no translation found for permlab_manageActivityStacks (7391191384027303065) --> - <skip /> - <!-- no translation found for permdesc_manageActivityStacks (1615881933034084440) --> - <skip /> + <string name="permlab_manageActivityStacks" msgid="7391191384027303065">"Aktivitätsstapel verwalten"</string> + <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"Ermöglicht der App das Hinzufügen, Entfernen und Ändern der Aktivitätsstapel, in denen andere Apps ausgeführt werden. Schädliche Apps können das Verhalten anderer Apps beeinträchtigen."</string> <string name="permlab_startAnyActivity" msgid="2918768238045206456">"Beliebige Aktivität starten"</string> <string name="permdesc_startAnyActivity" msgid="997823695343584001">"Ermöglicht der App, ungeachtet der Berechtigungen oder des Exportstatus beliebige Aktivitäten zu starten"</string> <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"Bildschirmkompatibilität festlegen"</string> @@ -360,14 +358,10 @@ <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Ermöglicht dem Halter, sich an die Oberfläche einer Eingabemethode auf oberster Ebene zu binden. Sollte nie für normale Apps benötigt werden."</string> <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"An eine Bedienungshilfe binden"</string> <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Ermöglicht dem Halter, sich an die Oberfläche einer Bedienungshilfe auf oberster Ebene zu binden. Sollte nie für normale Apps benötigt werden."</string> - <!-- no translation found for permlab_bindPrintService (8462815179572748761) --> - <skip /> - <!-- no translation found for permdesc_bindPrintService (7960067623209111135) --> - <skip /> - <!-- no translation found for permlab_accessAllPrintJobs (1120792468465711159) --> - <skip /> - <!-- no translation found for permdesc_accessAllPrintJobs (2978185311041864762) --> - <skip /> + <string name="permlab_bindPrintService" msgid="8462815179572748761">"An einen Druckdienst binden"</string> + <string name="permdesc_bindPrintService" msgid="7960067623209111135">"Ermöglicht dem Inhaber, sich an die Oberfläche eines Druckdienstes auf oberster Ebene zu binden. Sollte für normale Apps nie benötigt werden."</string> + <string name="permlab_accessAllPrintJobs" msgid="1120792468465711159">"Auf alle Druckaufträge zugreifen"</string> + <string name="permdesc_accessAllPrintJobs" msgid="2978185311041864762">"Ermöglicht dem Inhaber den Zugriff auf von einer anderen App erstellte Druckaufträge. Sollte für normale Apps nie benötigt werden."</string> <string name="permlab_bindTextService" msgid="7358378401915287938">"An einen Textdienst binden"</string> <string name="permdesc_bindTextService" msgid="8151968910973998670">"Ermöglicht dem Halter, sich an die Oberfläche eines Textdienstes auf oberster Ebene zu binden, z. B. eines Rechtschreibprüfungsdienstes. Sollte nie für normale Apps benötigt werden."</string> <string name="permlab_bindVpnService" msgid="4708596021161473255">"An einen VPN-Dienst binden"</string> @@ -470,6 +464,8 @@ <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Ermöglicht der App, die systemnahen SurfaceFlinger-Funktionen zu verwenden"</string> <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"Frame-Puffer lesen"</string> <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Ermöglicht der App, den Inhalt des Frame-Puffers zu lesen"</string> + <string name="permlab_accessInputFlinger" msgid="5348635270689553857">"Auf InputFlinger zugreifen"</string> + <string name="permdesc_accessInputFlinger" msgid="2104864941201226616">"Ermöglicht der App, die systemnahen InputFlinger-Funktionen zu verwenden"</string> <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"WLAN-Anzeigen konfigurieren"</string> <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Erlaubt der App, WLAN-Anzeigen zu konfigurieren und eine Verbindung zu diesen herzustellen"</string> <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"WLAN-Anzeigen steuern"</string> @@ -639,10 +635,14 @@ <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Ermöglicht der App, Netzwerkrichtlinien zu verwalten und anwendungsspezifische Regeln festzulegen"</string> <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"Zuordnung für Netzwerknutzung ändern"</string> <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Ermöglicht der App, die Art und Weise zu ändern, wie der Netzwerkverbrauch im Hinblick auf Apps berechnet wird. Nicht für normale Apps vorgesehen."</string> + <string name="permlab_markNetworkSocket" msgid="3658527214914959749">"Socket-Markierungen ändern"</string> + <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"Ermöglicht der App das Ändern von Socket-Markierungen für das Routing"</string> <string name="permlab_accessNotifications" msgid="7673416487873432268">"Auf Benachrichtigungen zugreifen"</string> <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_invokeCarrierSetup" msgid="3699600833975117478">"Vom Mobilfunkanbieter bereitgestellte Konfigurations-App aufrufen"</string> + <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Ermöglicht dem Inhaber, die vom Mobilfunkanbieter bereitgestellte Konfigurations-App aufzurufen. Sollte für normale Apps nie benötigt werden."</string> <string name="policylab_limitPassword" msgid="4497420728857585791">"Passwortregeln festlegen"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"Zulässige Länge und Zeichen für Passwörter zum Entsperren des Bildschirms festlegen"</string> <string name="policylab_watchLogin" msgid="914130646942199503">"Versuche zum Entsperren des Displays überwachen"</string> @@ -752,8 +752,7 @@ <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo!"</string> <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string> <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string> - <!-- no translation found for imProtocolGoogleTalk (493902321140277304) --> - <skip /> + <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangouts"</string> <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string> <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string> <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string> @@ -1515,94 +1514,59 @@ <string name="app_no_restricted_accounts" msgid="5739463249673727736">"Diese App unterstützt keine Konten für eingeschränkte Profile."</string> <string name="app_not_found" msgid="3429141853498927379">"Für diese Aktion wurde keine App gefunden."</string> <string name="revoke" msgid="5404479185228271586">"Aufheben"</string> - <!-- no translation found for mediaSize_iso_a0 (7875427489420821793) --> - <skip /> - <!-- no translation found for mediaSize_iso_a1 (3760734499050875356) --> - <skip /> - <!-- no translation found for mediaSize_iso_a2 (5973266378020144382) --> - <skip /> - <!-- no translation found for mediaSize_iso_a3 (1373407105687300884) --> - <skip /> - <!-- no translation found for mediaSize_iso_a4 (6689772807982597254) --> - <skip /> - <!-- no translation found for mediaSize_iso_a5 (5353549652015741040) --> - <skip /> - <!-- no translation found for mediaSize_iso_a6 (8585038048674911907) --> - <skip /> - <!-- no translation found for mediaSize_iso_a7 (6641836716963839119) --> - <skip /> - <!-- no translation found for mediaSize_iso_a8 (7571139437465693355) --> - <skip /> - <!-- no translation found for mediaSize_iso_a9 (1378455891957115079) --> - <skip /> - <!-- no translation found for mediaSize_iso_a10 (2480747457429475344) --> - <skip /> - <!-- no translation found for mediaSize_iso_b0 (3965935097661108039) --> - <skip /> - <!-- no translation found for mediaSize_iso_b1 (2505753285010115437) --> - <skip /> - <!-- no translation found for mediaSize_iso_b2 (8763874709859458453) --> - <skip /> - <!-- no translation found for mediaSize_iso_b3 (4210506688191764076) --> - <skip /> - <!-- no translation found for mediaSize_iso_b4 (5749404165888526034) --> - <skip /> - <!-- no translation found for mediaSize_iso_b5 (7640627414621904733) --> - <skip /> - <!-- no translation found for mediaSize_iso_b6 (7342988864712748544) --> - <skip /> - <!-- no translation found for mediaSize_iso_b7 (5069844065235382429) --> + <string name="mediaSize_iso_a0" msgid="7875427489420821793">"ISO A0"</string> + <string name="mediaSize_iso_a1" msgid="3760734499050875356">"ISO A1"</string> + <string name="mediaSize_iso_a2" msgid="5973266378020144382">"ISO A2"</string> + <string name="mediaSize_iso_a3" msgid="1373407105687300884">"ISO A3"</string> + <string name="mediaSize_iso_a4" msgid="6689772807982597254">"ISO A4"</string> + <string name="mediaSize_iso_a5" msgid="5353549652015741040">"ISO A5"</string> + <string name="mediaSize_iso_a6" msgid="8585038048674911907">"ISO A6"</string> + <string name="mediaSize_iso_a7" msgid="6641836716963839119">"ISO A7"</string> + <string name="mediaSize_iso_a8" msgid="7571139437465693355">"ISO A8"</string> + <string name="mediaSize_iso_a9" msgid="1378455891957115079">"ISO A9"</string> + <string name="mediaSize_iso_a10" msgid="2480747457429475344">"ISO A10"</string> + <string name="mediaSize_iso_b0" msgid="3965935097661108039">"ISO B0"</string> + <string name="mediaSize_iso_b1" msgid="2505753285010115437">"ISO B1"</string> + <string name="mediaSize_iso_b2" msgid="8763874709859458453">"ISO B2"</string> + <string name="mediaSize_iso_b3" msgid="4210506688191764076">"ISO B3"</string> + <string name="mediaSize_iso_b4" msgid="5749404165888526034">"ISO B4"</string> + <string name="mediaSize_iso_b5" msgid="7640627414621904733">"ISO B5"</string> + <string name="mediaSize_iso_b6" msgid="7342988864712748544">"ISO B6"</string> + <string name="mediaSize_iso_b7" msgid="5069844065235382429">"ISO B7"</string> + <string name="mediaSize_iso_b8" msgid="7316818922278779774">"ISO B8"</string> + <string name="mediaSize_iso_b9" msgid="5414727094026532341">"ISO B9"</string> + <string name="mediaSize_iso_b10" msgid="5251253731832048185">"ISO B10"</string> + <string name="mediaSize_iso_c0" msgid="4003138342671964217">"ISO C0"</string> + <string name="mediaSize_iso_c1" msgid="1935188063393553008">"ISO C1"</string> + <string name="mediaSize_iso_c2" msgid="3197307969712069904">"ISO C2"</string> + <string name="mediaSize_iso_c3" msgid="4335826087321913508">"ISO C3"</string> + <string name="mediaSize_iso_c4" msgid="3745639598281015005">"ISO C4"</string> + <string name="mediaSize_iso_c5" msgid="8269457765822791013">"ISO C5"</string> + <string name="mediaSize_iso_c6" msgid="566666105260346930">"ISO C6"</string> + <string name="mediaSize_iso_c7" msgid="8678413180782608498">"ISO C7"</string> + <string name="mediaSize_iso_c8" msgid="8392376206627041730">"ISO C8"</string> + <string name="mediaSize_iso_c9" msgid="9191613372324845405">"ISO C9"</string> + <string name="mediaSize_iso_c10" msgid="7327709699184920822">"ISO C10"</string> + <string name="mediaSize_na_letter" msgid="4191805615829472953">"Letter"</string> + <string name="mediaSize_na_gvrnmt_letter" msgid="7853382192649405507">"Government Letter"</string> + <string name="mediaSize_na_legal" msgid="6697982988283823150">"Legal"</string> + <string name="mediaSize_na_junior_legal" msgid="3727743969902758948">"Junior Legal"</string> + <string name="mediaSize_na_ledger" msgid="281871464896601236">"Ledger"</string> + <string name="mediaSize_na_tabloid" msgid="5775966416333578127">"Tabloid"</string> + <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"Abgebrochen"</string> + <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"Fehler beim Schreiben von Inhalten"</string> + <string name="restr_pin_enter_pin" msgid="3395953421368476103">"PIN eingeben"</string> + <!-- no translation found for restr_pin_enter_old_pin (1462206225512910757) --> <skip /> - <!-- no translation found for mediaSize_iso_b8 (7316818922278779774) --> + <!-- no translation found for restr_pin_enter_new_pin (5959606691619959184) --> <skip /> - <!-- no translation found for mediaSize_iso_b9 (5414727094026532341) --> + <!-- no translation found for restr_pin_confirm_pin (8501523829633146239) --> <skip /> - <!-- no translation found for mediaSize_iso_b10 (5251253731832048185) --> - <skip /> - <!-- no translation found for mediaSize_iso_c0 (4003138342671964217) --> - <skip /> - <!-- no translation found for mediaSize_iso_c1 (1935188063393553008) --> - <skip /> - <!-- no translation found for mediaSize_iso_c2 (3197307969712069904) --> - <skip /> - <!-- no translation found for mediaSize_iso_c3 (4335826087321913508) --> - <skip /> - <!-- no translation found for mediaSize_iso_c4 (3745639598281015005) --> - <skip /> - <!-- no translation found for mediaSize_iso_c5 (8269457765822791013) --> - <skip /> - <!-- no translation found for mediaSize_iso_c6 (566666105260346930) --> - <skip /> - <!-- no translation found for mediaSize_iso_c7 (8678413180782608498) --> - <skip /> - <!-- no translation found for mediaSize_iso_c8 (8392376206627041730) --> - <skip /> - <!-- no translation found for mediaSize_iso_c9 (9191613372324845405) --> - <skip /> - <!-- no translation found for mediaSize_iso_c10 (7327709699184920822) --> - <skip /> - <!-- no translation found for mediaSize_na_letter (4191805615829472953) --> - <skip /> - <!-- no translation found for mediaSize_na_gvrnmt_letter (7853382192649405507) --> - <skip /> - <!-- no translation found for mediaSize_na_legal (6697982988283823150) --> - <skip /> - <!-- no translation found for mediaSize_na_junior_legal (3727743969902758948) --> - <skip /> - <!-- no translation found for mediaSize_na_ledger (281871464896601236) --> - <skip /> - <!-- no translation found for mediaSize_na_tabloid (5775966416333578127) --> - <skip /> - <!-- no translation found for restr_pin_create_pin (8017600000263450337) --> - <skip /> - <!-- no translation found for restr_pin_enter_pin (3395953421368476103) --> - <skip /> - <!-- no translation found for restr_pin_confirm_pin (2891475237150965991) --> - <skip /> - <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) --> - <skip /> - <!-- no translation found for restr_pin_error_too_short (8173982756265777792) --> - <skip /> - <!-- no translation found for restr_pin_countdown:one (4835639969503729874) --> - <!-- no translation found for restr_pin_countdown:other (8030607343223287654) --> + <string name="restr_pin_create_pin" msgid="8017600000263450337">"PIN für das Ändern von Einschränkungen erstellen"</string> + <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"Die PINs stimmen nicht überein. Bitte versuchen Sie es erneut."</string> + <string name="restr_pin_error_too_short" msgid="8173982756265777792">"Die PIN ist zu kurz. Sie muss mindestens vier Ziffern umfassen."</string> + <plurals name="restr_pin_countdown"> + <item quantity="one" msgid="4835639969503729874">"Falsche PIN. In 1 Sek. erneut versuchen."</item> + <item quantity="other" msgid="8030607343223287654">"Falsche PIN. In <xliff:g id="COUNT">%d</xliff:g> Sek. erneut versuchen."</item> + </plurals> </resources> diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml index 961e15e..6c05796 100644 --- a/core/res/res/values-el/strings.xml +++ b/core/res/res/values-el/strings.xml @@ -279,10 +279,8 @@ <string name="permdesc_reorderTasks" msgid="7734217754877439351">"Επιτρέπει στην εφαρμογή τη μετακίνηση εργασιών στο προσκήνιο και το παρασκήνιο. Η εφαρμογή μπορεί να το κάνει αυτό χωρίς να καταχωρίσετε δεδομένα εισόδου."</string> <string name="permlab_removeTasks" msgid="6821513401870377403">"διακοπή εκτέλεσης εφαρμογών"</string> <string name="permdesc_removeTasks" msgid="1394714352062635493">"Επιτρέπει στην εφαρμογή την κατάργηση ενεργειών και την απομάκρυνση των εφαρμογών τους. Τυχόν κακόβουλες εφαρμογές ενδέχεται να διαταράξουν τη λειτουργία άλλων εφαρμογών."</string> - <!-- no translation found for permlab_manageActivityStacks (7391191384027303065) --> - <skip /> - <!-- no translation found for permdesc_manageActivityStacks (1615881933034084440) --> - <skip /> + <string name="permlab_manageActivityStacks" msgid="7391191384027303065">"διαχείριση στοιβών δραστηριότητας"</string> + <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"Επιτρέπει στην εφαρμογή την προσθήκη, την κατάργηση και την τροποποίηση των στοιβών δραστηριότητας στις οποίες εκτελούνται άλλες εφαρμογές. Οι κακόβουλες εφαρμογές ενδέχεται να προκαλέσουν προβλήματα στη συμπεριφορά άλλων συσκευών."</string> <string name="permlab_startAnyActivity" msgid="2918768238045206456">"έναρξη οποιασδήποτε δραστηριότητας"</string> <string name="permdesc_startAnyActivity" msgid="997823695343584001">"Επιτρέπει στην εφαρμογή την έναρξη οποιασδήποτε δραστηριότητας, ανεξάρτητα από την προστασία αδειών ή την κατάσταση εξαγωγής."</string> <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"ρύθμιση συμβατότητας οθόνης"</string> @@ -360,14 +358,10 @@ <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Επιτρέπει στον κάτοχο τη δέσμευση στη διεπαφή ανωτάτου επιπέδου μιας μεθόδου εισόδου. Δεν απαιτείται για συνήθεις εφαρμογές."</string> <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"δέσμευση σε υπηρεσία προσβασιμότητας"</string> <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Επιτρέπει στον κάτοχο τη δέσμευση στη διεπαφή ανώτατου επιπέδου μιας υπηρεσίας προσβασιμότητας. Δεν απαιτείται σε κανονικές εφαρμογές."</string> - <!-- no translation found for permlab_bindPrintService (8462815179572748761) --> - <skip /> - <!-- no translation found for permdesc_bindPrintService (7960067623209111135) --> - <skip /> - <!-- no translation found for permlab_accessAllPrintJobs (1120792468465711159) --> - <skip /> - <!-- no translation found for permdesc_accessAllPrintJobs (2978185311041864762) --> - <skip /> + <string name="permlab_bindPrintService" msgid="8462815179572748761">"δέσμευση σε υπηρεσία εκτύπωσης"</string> + <string name="permdesc_bindPrintService" msgid="7960067623209111135">"Επιτρέπει στον κάτοχο τη δέσμευση στη διεπαφή ανωτάτου επιπέδου μιας υπηρεσίας εκτύπωσης. Δεν απαιτείται για κανονικές εφαρμογές."</string> + <string name="permlab_accessAllPrintJobs" msgid="1120792468465711159">"πρόσβαση σε όλες τις εργασίες εκτύπωσης"</string> + <string name="permdesc_accessAllPrintJobs" msgid="2978185311041864762">"Επιτρέπει στον κάτοχο να αποκτά πρόσβαση σε εργασίες εκτύπωσης από άλλες εφαρμογές. Δεν απαιτείται για κανονικές εφαρμογές."</string> <string name="permlab_bindTextService" msgid="7358378401915287938">"δέσμευση σε υπηρεσία ανταλλαγής μηνυμάτων"</string> <string name="permdesc_bindTextService" msgid="8151968910973998670">"Επιτρέπει στον κάτοχο τη σύνδεση με τη διεπαφή ανωτέρου επιπέδου μιας υπηρεσίας ανταλλαγής μηνυμάτων (π.χ. SpellCheckerService). Δεν είναι απαραίτητο για κανονικές εφαρμογές."</string> <string name="permlab_bindVpnService" msgid="4708596021161473255">"δέσμευση σε υπηρεσία VPN"</string> @@ -470,6 +464,8 @@ <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Επιτρέπει σε μια εφαρμογή να χρησιμοποιεί λειτουργίες SurfaceFlinger χαμηλού επιπέδου."</string> <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"ανάγνωση προσωρινής μνήμης πλαισίου"</string> <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Επιτρέπει στην εφαρμογή την ανάγνωση του περιεχομένου της προσωρινής μνήμης πλαισίου."</string> + <string name="permlab_accessInputFlinger" msgid="5348635270689553857">"πρόσβαση στο InputFlinger"</string> + <string name="permdesc_accessInputFlinger" msgid="2104864941201226616">"Επιτρέπει σε μια εφαρμογή να χρησιμοποιεί λειτουργίες InputFlinger χαμηλού επιπέδου."</string> <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"διαμόρφωση οθονών Wifi"</string> <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Επιτρέπει τη διαμόρφωση της εφαρμογής και τη σύνδεσης σε οθόνες Wifi."</string> <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"έλεγχος οθονών Wifi"</string> @@ -639,10 +635,14 @@ <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Επιτρέπει στην εφαρμογή τη διαχείριση των πολιτικών δικτύου και τον ορισμό κανόνων για ορισμένες εφαρμογές."</string> <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"τροποποίηση υπολογισμού χρήσης δικτύου"</string> <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Επιτρέπει στην εφαρμογή την τροποποίηση του τρόπου υπολογισμού της χρήσης δικτύου έναντι των εφαρμογών. Δεν προορίζεται για χρήση από συνήθεις εφαρμογές."</string> + <string name="permlab_markNetworkSocket" msgid="3658527214914959749">"τροποποίηση σημείων υποδοχής"</string> + <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"Επιτρέπει στην εφαρμογή την τροποποίηση σημείων υποδοχής για δρομολόγηση"</string> <string name="permlab_accessNotifications" msgid="7673416487873432268">"πρόσβαση στις ειδοποιήσεις"</string> <string name="permdesc_accessNotifications" msgid="458457742683431387">"Επιτρέπει στην εφαρμογή να ανακτά, να εξετάζει και να απαλείφει ειδοποιήσεις, συμπεριλαμβανομένων εκείνων που δημοσιεύονται από άλλες εφαρμογές."</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"δέσμευση σε υπηρεσία ακρόασης ειδοποίησης"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Επιτρέπει στον κάτοχο τη δέσμευση στη διεπαφή ανωτάτου επιπέδου μιας υπηρεσίας ακρόασης ειδοποιήσεων. Δεν απαιτείται σε κανονικές εφαρμογές."</string> + <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"κλήση της εφαρμογής διαμόρφωσης που παρέχεται από την εταιρεία κινητής τηλεφωνίας"</string> + <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Επιτρέπει στον κάτοχο την κλήση της εφαρμογής διαμόρφωσης που παρέχεται από την εταιρεία κινητής τηλεφωνίας. Δεν απαιτείται για κανονικές εφαρμογές."</string> <string name="policylab_limitPassword" msgid="4497420728857585791">"Ορισμός κανόνων κωδικού πρόσβασης"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"Έλεγχος του μεγέθους και των χαρακτήρων που επιτρέπονται στους κωδικούς πρόσβασης ξεκλειδώματος οθόνης."</string> <string name="policylab_watchLogin" msgid="914130646942199503">"Παρακολούθηση προσπαθειών ξεκλειδώματος οθόνης"</string> @@ -752,8 +752,7 @@ <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string> <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string> <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string> - <!-- no translation found for imProtocolGoogleTalk (493902321140277304) --> - <skip /> + <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangouts"</string> <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string> <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string> <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string> @@ -1515,94 +1514,59 @@ <string name="app_no_restricted_accounts" msgid="5739463249673727736">"Αυτή η εφαρμογή δεν υποστηρίζει λογαριασμούς για περιορισμένα προφίλ"</string> <string name="app_not_found" msgid="3429141853498927379">"Δεν υπάρχει εφαρμογή για τη διαχείριση αυτής της ενέργειας"</string> <string name="revoke" msgid="5404479185228271586">"Ανάκληση"</string> - <!-- no translation found for mediaSize_iso_a0 (7875427489420821793) --> - <skip /> - <!-- no translation found for mediaSize_iso_a1 (3760734499050875356) --> - <skip /> - <!-- no translation found for mediaSize_iso_a2 (5973266378020144382) --> - <skip /> - <!-- no translation found for mediaSize_iso_a3 (1373407105687300884) --> - <skip /> - <!-- no translation found for mediaSize_iso_a4 (6689772807982597254) --> - <skip /> - <!-- no translation found for mediaSize_iso_a5 (5353549652015741040) --> - <skip /> - <!-- no translation found for mediaSize_iso_a6 (8585038048674911907) --> - <skip /> - <!-- no translation found for mediaSize_iso_a7 (6641836716963839119) --> - <skip /> - <!-- no translation found for mediaSize_iso_a8 (7571139437465693355) --> - <skip /> - <!-- no translation found for mediaSize_iso_a9 (1378455891957115079) --> - <skip /> - <!-- no translation found for mediaSize_iso_a10 (2480747457429475344) --> - <skip /> - <!-- no translation found for mediaSize_iso_b0 (3965935097661108039) --> - <skip /> - <!-- no translation found for mediaSize_iso_b1 (2505753285010115437) --> - <skip /> - <!-- no translation found for mediaSize_iso_b2 (8763874709859458453) --> - <skip /> - <!-- no translation found for mediaSize_iso_b3 (4210506688191764076) --> - <skip /> - <!-- no translation found for mediaSize_iso_b4 (5749404165888526034) --> - <skip /> - <!-- no translation found for mediaSize_iso_b5 (7640627414621904733) --> - <skip /> - <!-- no translation found for mediaSize_iso_b6 (7342988864712748544) --> - <skip /> - <!-- no translation found for mediaSize_iso_b7 (5069844065235382429) --> + <string name="mediaSize_iso_a0" msgid="7875427489420821793">"ISO A0"</string> + <string name="mediaSize_iso_a1" msgid="3760734499050875356">"ISO A1"</string> + <string name="mediaSize_iso_a2" msgid="5973266378020144382">"ISO A2"</string> + <string name="mediaSize_iso_a3" msgid="1373407105687300884">"ISO A3"</string> + <string name="mediaSize_iso_a4" msgid="6689772807982597254">"ISO A4"</string> + <string name="mediaSize_iso_a5" msgid="5353549652015741040">"ISO A5"</string> + <string name="mediaSize_iso_a6" msgid="8585038048674911907">"ISO A6"</string> + <string name="mediaSize_iso_a7" msgid="6641836716963839119">"ISO A7"</string> + <string name="mediaSize_iso_a8" msgid="7571139437465693355">"ISO A8"</string> + <string name="mediaSize_iso_a9" msgid="1378455891957115079">"ISO A9"</string> + <string name="mediaSize_iso_a10" msgid="2480747457429475344">"ISO A10"</string> + <string name="mediaSize_iso_b0" msgid="3965935097661108039">"ISO B0"</string> + <string name="mediaSize_iso_b1" msgid="2505753285010115437">"ISO B1"</string> + <string name="mediaSize_iso_b2" msgid="8763874709859458453">"ISO B2"</string> + <string name="mediaSize_iso_b3" msgid="4210506688191764076">"ISO B3"</string> + <string name="mediaSize_iso_b4" msgid="5749404165888526034">"ISO B4"</string> + <string name="mediaSize_iso_b5" msgid="7640627414621904733">"ISO B5"</string> + <string name="mediaSize_iso_b6" msgid="7342988864712748544">"ISO B6"</string> + <string name="mediaSize_iso_b7" msgid="5069844065235382429">"ISO B7"</string> + <string name="mediaSize_iso_b8" msgid="7316818922278779774">"ISO B8"</string> + <string name="mediaSize_iso_b9" msgid="5414727094026532341">"ISO B9"</string> + <string name="mediaSize_iso_b10" msgid="5251253731832048185">"ISO B10"</string> + <string name="mediaSize_iso_c0" msgid="4003138342671964217">"ISO C0"</string> + <string name="mediaSize_iso_c1" msgid="1935188063393553008">"ISO C1"</string> + <string name="mediaSize_iso_c2" msgid="3197307969712069904">"ISO C2"</string> + <string name="mediaSize_iso_c3" msgid="4335826087321913508">"ISO C3"</string> + <string name="mediaSize_iso_c4" msgid="3745639598281015005">"ISO C4"</string> + <string name="mediaSize_iso_c5" msgid="8269457765822791013">"ISO C5"</string> + <string name="mediaSize_iso_c6" msgid="566666105260346930">"ISO C6"</string> + <string name="mediaSize_iso_c7" msgid="8678413180782608498">"ISO C7"</string> + <string name="mediaSize_iso_c8" msgid="8392376206627041730">"ISO C8"</string> + <string name="mediaSize_iso_c9" msgid="9191613372324845405">"ISO C9"</string> + <string name="mediaSize_iso_c10" msgid="7327709699184920822">"ISO C10"</string> + <string name="mediaSize_na_letter" msgid="4191805615829472953">"Επιστολή"</string> + <string name="mediaSize_na_gvrnmt_letter" msgid="7853382192649405507">"Κρατική επιστολή"</string> + <string name="mediaSize_na_legal" msgid="6697982988283823150">"Νομικό"</string> + <string name="mediaSize_na_junior_legal" msgid="3727743969902758948">"Junior Legal"</string> + <string name="mediaSize_na_ledger" msgid="281871464896601236">"Λογιστικό"</string> + <string name="mediaSize_na_tabloid" msgid="5775966416333578127">"Tabloid"</string> + <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"Ακυρώθηκε"</string> + <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"Σφάλμα κατά την εγγραφή περιεχομένου"</string> + <string name="restr_pin_enter_pin" msgid="3395953421368476103">"Εισαγωγή PIN"</string> + <!-- no translation found for restr_pin_enter_old_pin (1462206225512910757) --> <skip /> - <!-- no translation found for mediaSize_iso_b8 (7316818922278779774) --> + <!-- no translation found for restr_pin_enter_new_pin (5959606691619959184) --> <skip /> - <!-- no translation found for mediaSize_iso_b9 (5414727094026532341) --> + <!-- no translation found for restr_pin_confirm_pin (8501523829633146239) --> <skip /> - <!-- no translation found for mediaSize_iso_b10 (5251253731832048185) --> - <skip /> - <!-- no translation found for mediaSize_iso_c0 (4003138342671964217) --> - <skip /> - <!-- no translation found for mediaSize_iso_c1 (1935188063393553008) --> - <skip /> - <!-- no translation found for mediaSize_iso_c2 (3197307969712069904) --> - <skip /> - <!-- no translation found for mediaSize_iso_c3 (4335826087321913508) --> - <skip /> - <!-- no translation found for mediaSize_iso_c4 (3745639598281015005) --> - <skip /> - <!-- no translation found for mediaSize_iso_c5 (8269457765822791013) --> - <skip /> - <!-- no translation found for mediaSize_iso_c6 (566666105260346930) --> - <skip /> - <!-- no translation found for mediaSize_iso_c7 (8678413180782608498) --> - <skip /> - <!-- no translation found for mediaSize_iso_c8 (8392376206627041730) --> - <skip /> - <!-- no translation found for mediaSize_iso_c9 (9191613372324845405) --> - <skip /> - <!-- no translation found for mediaSize_iso_c10 (7327709699184920822) --> - <skip /> - <!-- no translation found for mediaSize_na_letter (4191805615829472953) --> - <skip /> - <!-- no translation found for mediaSize_na_gvrnmt_letter (7853382192649405507) --> - <skip /> - <!-- no translation found for mediaSize_na_legal (6697982988283823150) --> - <skip /> - <!-- no translation found for mediaSize_na_junior_legal (3727743969902758948) --> - <skip /> - <!-- no translation found for mediaSize_na_ledger (281871464896601236) --> - <skip /> - <!-- no translation found for mediaSize_na_tabloid (5775966416333578127) --> - <skip /> - <!-- no translation found for restr_pin_create_pin (8017600000263450337) --> - <skip /> - <!-- no translation found for restr_pin_enter_pin (3395953421368476103) --> - <skip /> - <!-- no translation found for restr_pin_confirm_pin (2891475237150965991) --> - <skip /> - <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) --> - <skip /> - <!-- no translation found for restr_pin_error_too_short (8173982756265777792) --> - <skip /> - <!-- no translation found for restr_pin_countdown:one (4835639969503729874) --> - <!-- no translation found for restr_pin_countdown:other (8030607343223287654) --> + <string name="restr_pin_create_pin" msgid="8017600000263450337">"Δημιουργία PIN για τροποποίηση περιορισμών"</string> + <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"Τα PIN δεν συμφωνούν. Προσπαθήστε ξανά."</string> + <string name="restr_pin_error_too_short" msgid="8173982756265777792">"Το PIN είναι υπερβολικά μικρό. Πρέπει να έχει μέγεθος τουλάχιστον 4 χαρακτήρων."</string> + <plurals name="restr_pin_countdown"> + <item quantity="one" msgid="4835639969503729874">"Εσφαλμένο PIN. Προσπαθήστε ξανά σε 1 δευτερόλεπτο."</item> + <item quantity="other" msgid="8030607343223287654">"Εσφαλμένο PIN. Προσπαθήστε ξανά σε <xliff:g id="COUNT">%d</xliff:g> δευτερόλεπτα."</item> + </plurals> </resources> diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml index 4825085..acb4b35 100644 --- a/core/res/res/values-en-rGB/strings.xml +++ b/core/res/res/values-en-rGB/strings.xml @@ -279,10 +279,8 @@ <string name="permdesc_reorderTasks" msgid="7734217754877439351">"Allows the app to move tasks to the foreground and background. The app may do this without your input."</string> <string name="permlab_removeTasks" msgid="6821513401870377403">"stop running apps"</string> <string name="permdesc_removeTasks" msgid="1394714352062635493">"Allows the app to remove tasks and kill their apps. Malicious apps may disrupt the behaviour of other apps."</string> - <!-- no translation found for permlab_manageActivityStacks (7391191384027303065) --> - <skip /> - <!-- no translation found for permdesc_manageActivityStacks (1615881933034084440) --> - <skip /> + <string name="permlab_manageActivityStacks" msgid="7391191384027303065">"manage activity stacks"</string> + <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"Allows the app to add, remove and modify the activity stacks in which other apps run. Malicious apps may disrupt the behaviour of other apps."</string> <string name="permlab_startAnyActivity" msgid="2918768238045206456">"start any activity"</string> <string name="permdesc_startAnyActivity" msgid="997823695343584001">"Allows the app to start any activity, regardless of permission protection or exported state."</string> <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"set screen compatibility"</string> @@ -360,14 +358,10 @@ <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Allows the holder to bind to the top-level interface of an input method. Should never be needed for normal apps."</string> <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"bind to an accessibility service"</string> <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Allows the holder to bind to the top-level interface of an accessibility service. Should never be needed for normal apps."</string> - <!-- no translation found for permlab_bindPrintService (8462815179572748761) --> - <skip /> - <!-- no translation found for permdesc_bindPrintService (7960067623209111135) --> - <skip /> - <!-- no translation found for permlab_accessAllPrintJobs (1120792468465711159) --> - <skip /> - <!-- no translation found for permdesc_accessAllPrintJobs (2978185311041864762) --> - <skip /> + <string name="permlab_bindPrintService" msgid="8462815179572748761">"bind to a print service"</string> + <string name="permdesc_bindPrintService" msgid="7960067623209111135">"Allows the holder to bind to the top-level interface of a print service. Should never be needed for normal apps."</string> + <string name="permlab_accessAllPrintJobs" msgid="1120792468465711159">"access all print jobs"</string> + <string name="permdesc_accessAllPrintJobs" msgid="2978185311041864762">"Allows the holder to access print jobs created by another app. Should never be needed for normal apps."</string> <string name="permlab_bindTextService" msgid="7358378401915287938">"bind to a text service"</string> <string name="permdesc_bindTextService" msgid="8151968910973998670">"Allows the holder to bind to the top-level interface of a text service (e.g. SpellCheckerService). Should never be needed for normal applications."</string> <string name="permlab_bindVpnService" msgid="4708596021161473255">"bind to a VPN service"</string> @@ -470,6 +464,8 @@ <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Allows the app to use SurfaceFlinger low-level features."</string> <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"read frame buffer"</string> <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Allows the app to read the content of the frame buffer."</string> + <string name="permlab_accessInputFlinger" msgid="5348635270689553857">"access InputFlinger"</string> + <string name="permdesc_accessInputFlinger" msgid="2104864941201226616">"Allows the app to use InputFlinger low-level features."</string> <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"configure Wi-Fi displays"</string> <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Allows the app to configure and connect to Wi-Fi displays."</string> <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"control Wi-Fi displays"</string> @@ -639,10 +635,14 @@ <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Allows the app to manage network policies and define app-specific rules."</string> <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"modify network usage accounting"</string> <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Allows the app to modify how network usage is accounted against apps. Not for use by normal apps."</string> + <string name="permlab_markNetworkSocket" msgid="3658527214914959749">"modify socket marks"</string> + <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"Allows the app to modify socket marks for routing"</string> <string name="permlab_accessNotifications" msgid="7673416487873432268">"access notifications"</string> <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_invokeCarrierSetup" msgid="3699600833975117478">"invoke the carrier-provided configuration app"</string> + <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Allows the holder to invoke the carrier-provided configuration app. Should never be needed for normal apps."</string> <string name="policylab_limitPassword" msgid="4497420728857585791">"Set password rules"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"Control the length and the characters allowed in screen-unlock passwords."</string> <string name="policylab_watchLogin" msgid="914130646942199503">"Monitor screen-unlock attempts"</string> @@ -752,8 +752,7 @@ <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string> <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string> <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string> - <!-- no translation found for imProtocolGoogleTalk (493902321140277304) --> - <skip /> + <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangouts"</string> <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string> <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string> <string name="imProtocolNetMeeting" msgid="8287625655986827971">"Net Meeting"</string> @@ -1515,94 +1514,56 @@ <string name="app_no_restricted_accounts" msgid="5739463249673727736">"This app doesn\'t support accounts for restricted profiles"</string> <string name="app_not_found" msgid="3429141853498927379">"No application found to handle this action"</string> <string name="revoke" msgid="5404479185228271586">"Revoke"</string> - <!-- no translation found for mediaSize_iso_a0 (7875427489420821793) --> - <skip /> - <!-- no translation found for mediaSize_iso_a1 (3760734499050875356) --> - <skip /> - <!-- no translation found for mediaSize_iso_a2 (5973266378020144382) --> - <skip /> - <!-- no translation found for mediaSize_iso_a3 (1373407105687300884) --> - <skip /> - <!-- no translation found for mediaSize_iso_a4 (6689772807982597254) --> - <skip /> - <!-- no translation found for mediaSize_iso_a5 (5353549652015741040) --> - <skip /> - <!-- no translation found for mediaSize_iso_a6 (8585038048674911907) --> - <skip /> - <!-- no translation found for mediaSize_iso_a7 (6641836716963839119) --> - <skip /> - <!-- no translation found for mediaSize_iso_a8 (7571139437465693355) --> - <skip /> - <!-- no translation found for mediaSize_iso_a9 (1378455891957115079) --> - <skip /> - <!-- no translation found for mediaSize_iso_a10 (2480747457429475344) --> - <skip /> - <!-- no translation found for mediaSize_iso_b0 (3965935097661108039) --> - <skip /> - <!-- no translation found for mediaSize_iso_b1 (2505753285010115437) --> - <skip /> - <!-- no translation found for mediaSize_iso_b2 (8763874709859458453) --> - <skip /> - <!-- no translation found for mediaSize_iso_b3 (4210506688191764076) --> - <skip /> - <!-- no translation found for mediaSize_iso_b4 (5749404165888526034) --> - <skip /> - <!-- no translation found for mediaSize_iso_b5 (7640627414621904733) --> - <skip /> - <!-- no translation found for mediaSize_iso_b6 (7342988864712748544) --> - <skip /> - <!-- no translation found for mediaSize_iso_b7 (5069844065235382429) --> - <skip /> - <!-- no translation found for mediaSize_iso_b8 (7316818922278779774) --> - <skip /> - <!-- no translation found for mediaSize_iso_b9 (5414727094026532341) --> - <skip /> - <!-- no translation found for mediaSize_iso_b10 (5251253731832048185) --> - <skip /> - <!-- no translation found for mediaSize_iso_c0 (4003138342671964217) --> - <skip /> - <!-- no translation found for mediaSize_iso_c1 (1935188063393553008) --> - <skip /> - <!-- no translation found for mediaSize_iso_c2 (3197307969712069904) --> - <skip /> - <!-- no translation found for mediaSize_iso_c3 (4335826087321913508) --> - <skip /> - <!-- no translation found for mediaSize_iso_c4 (3745639598281015005) --> - <skip /> - <!-- no translation found for mediaSize_iso_c5 (8269457765822791013) --> - <skip /> - <!-- no translation found for mediaSize_iso_c6 (566666105260346930) --> - <skip /> - <!-- no translation found for mediaSize_iso_c7 (8678413180782608498) --> - <skip /> - <!-- no translation found for mediaSize_iso_c8 (8392376206627041730) --> - <skip /> - <!-- no translation found for mediaSize_iso_c9 (9191613372324845405) --> - <skip /> - <!-- no translation found for mediaSize_iso_c10 (7327709699184920822) --> - <skip /> - <!-- no translation found for mediaSize_na_letter (4191805615829472953) --> - <skip /> - <!-- no translation found for mediaSize_na_gvrnmt_letter (7853382192649405507) --> - <skip /> - <!-- no translation found for mediaSize_na_legal (6697982988283823150) --> - <skip /> - <!-- no translation found for mediaSize_na_junior_legal (3727743969902758948) --> - <skip /> - <!-- no translation found for mediaSize_na_ledger (281871464896601236) --> - <skip /> - <!-- no translation found for mediaSize_na_tabloid (5775966416333578127) --> - <skip /> - <!-- no translation found for restr_pin_create_pin (8017600000263450337) --> - <skip /> - <!-- no translation found for restr_pin_enter_pin (3395953421368476103) --> - <skip /> - <!-- no translation found for restr_pin_confirm_pin (2891475237150965991) --> - <skip /> - <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) --> - <skip /> - <!-- no translation found for restr_pin_error_too_short (8173982756265777792) --> - <skip /> - <!-- no translation found for restr_pin_countdown:one (4835639969503729874) --> - <!-- no translation found for restr_pin_countdown:other (8030607343223287654) --> + <string name="mediaSize_iso_a0" msgid="7875427489420821793">"ISO A0"</string> + <string name="mediaSize_iso_a1" msgid="3760734499050875356">"ISO A1"</string> + <string name="mediaSize_iso_a2" msgid="5973266378020144382">"ISO A2"</string> + <string name="mediaSize_iso_a3" msgid="1373407105687300884">"ISO A3"</string> + <string name="mediaSize_iso_a4" msgid="6689772807982597254">"ISO A4"</string> + <string name="mediaSize_iso_a5" msgid="5353549652015741040">"ISO A5"</string> + <string name="mediaSize_iso_a6" msgid="8585038048674911907">"ISO A6"</string> + <string name="mediaSize_iso_a7" msgid="6641836716963839119">"ISO A7"</string> + <string name="mediaSize_iso_a8" msgid="7571139437465693355">"ISO A8"</string> + <string name="mediaSize_iso_a9" msgid="1378455891957115079">"ISO A9"</string> + <string name="mediaSize_iso_a10" msgid="2480747457429475344">"ISO A10"</string> + <string name="mediaSize_iso_b0" msgid="3965935097661108039">"ISO B0"</string> + <string name="mediaSize_iso_b1" msgid="2505753285010115437">"ISO B1"</string> + <string name="mediaSize_iso_b2" msgid="8763874709859458453">"ISO B2"</string> + <string name="mediaSize_iso_b3" msgid="4210506688191764076">"ISO B3"</string> + <string name="mediaSize_iso_b4" msgid="5749404165888526034">"ISO B4"</string> + <string name="mediaSize_iso_b5" msgid="7640627414621904733">"ISO B5"</string> + <string name="mediaSize_iso_b6" msgid="7342988864712748544">"ISO B6"</string> + <string name="mediaSize_iso_b7" msgid="5069844065235382429">"ISO B7"</string> + <string name="mediaSize_iso_b8" msgid="7316818922278779774">"ISO B8"</string> + <string name="mediaSize_iso_b9" msgid="5414727094026532341">"ISO B9"</string> + <string name="mediaSize_iso_b10" msgid="5251253731832048185">"ISO B10"</string> + <string name="mediaSize_iso_c0" msgid="4003138342671964217">"ISO C0"</string> + <string name="mediaSize_iso_c1" msgid="1935188063393553008">"ISO C1"</string> + <string name="mediaSize_iso_c2" msgid="3197307969712069904">"ISO C2"</string> + <string name="mediaSize_iso_c3" msgid="4335826087321913508">"ISO C3"</string> + <string name="mediaSize_iso_c4" msgid="3745639598281015005">"ISO C4"</string> + <string name="mediaSize_iso_c5" msgid="8269457765822791013">"ISO C5"</string> + <string name="mediaSize_iso_c6" msgid="566666105260346930">"ISO C6"</string> + <string name="mediaSize_iso_c7" msgid="8678413180782608498">"ISO C7"</string> + <string name="mediaSize_iso_c8" msgid="8392376206627041730">"ISO C8"</string> + <string name="mediaSize_iso_c9" msgid="9191613372324845405">"ISO C9"</string> + <string name="mediaSize_iso_c10" msgid="7327709699184920822">"ISO C10"</string> + <string name="mediaSize_na_letter" msgid="4191805615829472953">"Letter"</string> + <string name="mediaSize_na_gvrnmt_letter" msgid="7853382192649405507">"Government Letter"</string> + <string name="mediaSize_na_legal" msgid="6697982988283823150">"Legal"</string> + <string name="mediaSize_na_junior_legal" msgid="3727743969902758948">"Junior Legal"</string> + <string name="mediaSize_na_ledger" msgid="281871464896601236">"Ledger"</string> + <string name="mediaSize_na_tabloid" msgid="5775966416333578127">"Tabloid"</string> + <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"Cancelled"</string> + <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"Error writing content"</string> + <string name="restr_pin_enter_pin" msgid="3395953421368476103">"Enter PIN"</string> + <string name="restr_pin_enter_old_pin" msgid="1462206225512910757">"Current PIN:"</string> + <string name="restr_pin_enter_new_pin" msgid="5959606691619959184">"New PIN"</string> + <string name="restr_pin_confirm_pin" msgid="8501523829633146239">"Confirm new PIN"</string> + <string name="restr_pin_create_pin" msgid="8017600000263450337">"Create a PIN for modifying restrictions"</string> + <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PINs don\'t match. Try again."</string> + <string name="restr_pin_error_too_short" msgid="8173982756265777792">"PIN is too short. Must be at least 4 digits."</string> + <plurals name="restr_pin_countdown"> + <item quantity="one" msgid="4835639969503729874">"Incorrect PIN. Try again in 1 second."</item> + <item quantity="other" msgid="8030607343223287654">"Incorrect PIN. Try again in <xliff:g id="COUNT">%d</xliff:g> seconds."</item> + </plurals> </resources> diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml index 615fcbe..9fd6637 100644 --- a/core/res/res/values-es-rUS/strings.xml +++ b/core/res/res/values-es-rUS/strings.xml @@ -279,10 +279,8 @@ <string name="permdesc_reorderTasks" msgid="7734217754877439351">"Permite que la aplicación mueva tareas a segundo o a primer plano. La aplicación puede utilizar este permiso para realizar estos movimientos sin indicártelo."</string> <string name="permlab_removeTasks" msgid="6821513401870377403">"detener las aplicaciones en ejecución"</string> <string name="permdesc_removeTasks" msgid="1394714352062635493">"Permite que la aplicación elimine tareas y cierre sus aplicaciones. Las aplicaciones malintencionadas pueden usar este permiso para interferir en el comportamiento de otras aplicaciones."</string> - <!-- no translation found for permlab_manageActivityStacks (7391191384027303065) --> - <skip /> - <!-- no translation found for permdesc_manageActivityStacks (1615881933034084440) --> - <skip /> + <string name="permlab_manageActivityStacks" msgid="7391191384027303065">"administrar pilas de actividad"</string> + <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"Permite que la aplicación agregue, elimine y modifique las pilas de actividad en las que se ejecutan otras aplicaciones. Las aplicaciones maliciosas pueden interrumpir el comportamiento de otras aplicaciones."</string> <string name="permlab_startAnyActivity" msgid="2918768238045206456">"Iniciar cualquier actividad"</string> <string name="permdesc_startAnyActivity" msgid="997823695343584001">"Permite a la aplicación iniciar una actividad, sin importar si fue exportada ni si se encuentra protegida por permisos."</string> <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"Definir compatibilidad de pantalla"</string> @@ -360,14 +358,10 @@ <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Permite al propietario vincularse a la interfaz de nivel superior de un método de entrada. Las aplicaciones normales no deberían necesitar este permiso."</string> <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"vincular a un servicio de accesibilidad"</string> <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Permite al propietario vincularse a la interfaz de nivel superior de un servicio de accesibilidad. Las aplicaciones normales no deberían necesitar este permiso."</string> - <!-- no translation found for permlab_bindPrintService (8462815179572748761) --> - <skip /> - <!-- no translation found for permdesc_bindPrintService (7960067623209111135) --> - <skip /> - <!-- no translation found for permlab_accessAllPrintJobs (1120792468465711159) --> - <skip /> - <!-- no translation found for permdesc_accessAllPrintJobs (2978185311041864762) --> - <skip /> + <string name="permlab_bindPrintService" msgid="8462815179572748761">"vincular a un servicio de impresión"</string> + <string name="permdesc_bindPrintService" msgid="7960067623209111135">"Permite al propietario vincularse a la interfaz de nivel superior de un servicio de impresión. Las aplicaciones normales no deberían necesitar este permiso."</string> + <string name="permlab_accessAllPrintJobs" msgid="1120792468465711159">"acceder a todos los trabajos de impresión"</string> + <string name="permdesc_accessAllPrintJobs" msgid="2978185311041864762">"Permite al propietario acceder a trabajos de impresión creados con otra aplicación. Las aplicaciones normales no deberían necesitar este permiso."</string> <string name="permlab_bindTextService" msgid="7358378401915287938">"vincular a un servicio de texto"</string> <string name="permdesc_bindTextService" msgid="8151968910973998670">"Permite al titular vincularse a la interfaz de nivel superior de un servicio de texto (p. ej., SpellCheckerService). Las aplicaciones normales no deberían necesitar este permiso."</string> <string name="permlab_bindVpnService" msgid="4708596021161473255">"vincular con un servicio de VPN"</string> @@ -470,6 +464,8 @@ <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Permite que la aplicación utilice funciones de SurfaceFlinger de bajo nivel."</string> <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"leer el búfer de tramas"</string> <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Permite que la aplicación lea el contenido del búfer de tramas."</string> + <string name="permlab_accessInputFlinger" msgid="5348635270689553857">"acceder a InputFlinger"</string> + <string name="permdesc_accessInputFlinger" msgid="2104864941201226616">"Permite que la aplicación utilice funciones de InputFlinger de bajo nivel."</string> <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"configurar pantallas Wi-Fi"</string> <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Permite que la aplicación configure y se conecte a pantallas Wi-Fi."</string> <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"controlar pantallas Wi-Fi"</string> @@ -639,10 +635,14 @@ <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Permite que la aplicación administre las políticas de red y defina reglas específicas de la aplicación."</string> <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"Modificar la administración del uso de redes"</string> <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Permite que la aplicación modifique cómo se registra el uso de red en relación con las aplicaciones. Las aplicaciones normales no deben usar este permiso."</string> + <string name="permlab_markNetworkSocket" msgid="3658527214914959749">"modificar marcas de socket"</string> + <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"Permite que la aplicación modifique marcas de socket para enrutamiento."</string> <string name="permlab_accessNotifications" msgid="7673416487873432268">"acceder a las notificaciones"</string> <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_invokeCarrierSetup" msgid="3699600833975117478">"ejecutar la aplicación de configuración proporcionada por el proveedor"</string> + <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Permite al propietario ejecutar la aplicación de configuración proporcionada por el proveedor. Las aplicaciones normales no deberían necesitar este permiso."</string> <string name="policylab_limitPassword" msgid="4497420728857585791">"Establecer reglas de contraseña"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"Controlar la longitud y los caracteres permitidos en las contraseñas para desbloquear la pantalla"</string> <string name="policylab_watchLogin" msgid="914130646942199503">"Supervisa los intentos para desbloquear la pantalla"</string> @@ -752,8 +752,7 @@ <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string> <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string> <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string> - <!-- no translation found for imProtocolGoogleTalk (493902321140277304) --> - <skip /> + <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangouts"</string> <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string> <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string> <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string> @@ -1515,94 +1514,59 @@ <string name="app_no_restricted_accounts" msgid="5739463249673727736">"Esta aplicación no admite cuentas de perfiles restringidos."</string> <string name="app_not_found" msgid="3429141853498927379">"No se encontró una aplicación para manejar esta acción."</string> <string name="revoke" msgid="5404479185228271586">"Revocar"</string> - <!-- no translation found for mediaSize_iso_a0 (7875427489420821793) --> - <skip /> - <!-- no translation found for mediaSize_iso_a1 (3760734499050875356) --> - <skip /> - <!-- no translation found for mediaSize_iso_a2 (5973266378020144382) --> - <skip /> - <!-- no translation found for mediaSize_iso_a3 (1373407105687300884) --> - <skip /> - <!-- no translation found for mediaSize_iso_a4 (6689772807982597254) --> - <skip /> - <!-- no translation found for mediaSize_iso_a5 (5353549652015741040) --> - <skip /> - <!-- no translation found for mediaSize_iso_a6 (8585038048674911907) --> - <skip /> - <!-- no translation found for mediaSize_iso_a7 (6641836716963839119) --> - <skip /> - <!-- no translation found for mediaSize_iso_a8 (7571139437465693355) --> - <skip /> - <!-- no translation found for mediaSize_iso_a9 (1378455891957115079) --> - <skip /> - <!-- no translation found for mediaSize_iso_a10 (2480747457429475344) --> - <skip /> - <!-- no translation found for mediaSize_iso_b0 (3965935097661108039) --> - <skip /> - <!-- no translation found for mediaSize_iso_b1 (2505753285010115437) --> - <skip /> - <!-- no translation found for mediaSize_iso_b2 (8763874709859458453) --> - <skip /> - <!-- no translation found for mediaSize_iso_b3 (4210506688191764076) --> - <skip /> - <!-- no translation found for mediaSize_iso_b4 (5749404165888526034) --> - <skip /> - <!-- no translation found for mediaSize_iso_b5 (7640627414621904733) --> - <skip /> - <!-- no translation found for mediaSize_iso_b6 (7342988864712748544) --> - <skip /> - <!-- no translation found for mediaSize_iso_b7 (5069844065235382429) --> + <string name="mediaSize_iso_a0" msgid="7875427489420821793">"ISO A0"</string> + <string name="mediaSize_iso_a1" msgid="3760734499050875356">"ISO A1"</string> + <string name="mediaSize_iso_a2" msgid="5973266378020144382">"ISO A2"</string> + <string name="mediaSize_iso_a3" msgid="1373407105687300884">"ISO A3"</string> + <string name="mediaSize_iso_a4" msgid="6689772807982597254">"ISO A4"</string> + <string name="mediaSize_iso_a5" msgid="5353549652015741040">"ISO A5"</string> + <string name="mediaSize_iso_a6" msgid="8585038048674911907">"ISO A6"</string> + <string name="mediaSize_iso_a7" msgid="6641836716963839119">"ISO A7"</string> + <string name="mediaSize_iso_a8" msgid="7571139437465693355">"ISO A8"</string> + <string name="mediaSize_iso_a9" msgid="1378455891957115079">"ISO A9"</string> + <string name="mediaSize_iso_a10" msgid="2480747457429475344">"ISO A10"</string> + <string name="mediaSize_iso_b0" msgid="3965935097661108039">"ISO B0"</string> + <string name="mediaSize_iso_b1" msgid="2505753285010115437">"ISO B1"</string> + <string name="mediaSize_iso_b2" msgid="8763874709859458453">"ISO B2"</string> + <string name="mediaSize_iso_b3" msgid="4210506688191764076">"ISO B3"</string> + <string name="mediaSize_iso_b4" msgid="5749404165888526034">"ISO B4"</string> + <string name="mediaSize_iso_b5" msgid="7640627414621904733">"ISO B5"</string> + <string name="mediaSize_iso_b6" msgid="7342988864712748544">"ISO B6"</string> + <string name="mediaSize_iso_b7" msgid="5069844065235382429">"ISO B7"</string> + <string name="mediaSize_iso_b8" msgid="7316818922278779774">"ISO B8"</string> + <string name="mediaSize_iso_b9" msgid="5414727094026532341">"ISO B9"</string> + <string name="mediaSize_iso_b10" msgid="5251253731832048185">"ISO B10"</string> + <string name="mediaSize_iso_c0" msgid="4003138342671964217">"ISO C0"</string> + <string name="mediaSize_iso_c1" msgid="1935188063393553008">"ISO C1"</string> + <string name="mediaSize_iso_c2" msgid="3197307969712069904">"ISO C2"</string> + <string name="mediaSize_iso_c3" msgid="4335826087321913508">"ISO C3"</string> + <string name="mediaSize_iso_c4" msgid="3745639598281015005">"ISO C4"</string> + <string name="mediaSize_iso_c5" msgid="8269457765822791013">"ISO C5"</string> + <string name="mediaSize_iso_c6" msgid="566666105260346930">"ISO C6"</string> + <string name="mediaSize_iso_c7" msgid="8678413180782608498">"ISO C7"</string> + <string name="mediaSize_iso_c8" msgid="8392376206627041730">"ISO C8"</string> + <string name="mediaSize_iso_c9" msgid="9191613372324845405">"ISO C9"</string> + <string name="mediaSize_iso_c10" msgid="7327709699184920822">"ISO C10"</string> + <string name="mediaSize_na_letter" msgid="4191805615829472953">"Letter"</string> + <string name="mediaSize_na_gvrnmt_letter" msgid="7853382192649405507">"Government Letter"</string> + <string name="mediaSize_na_legal" msgid="6697982988283823150">"Legal"</string> + <string name="mediaSize_na_junior_legal" msgid="3727743969902758948">"Junior Legal"</string> + <string name="mediaSize_na_ledger" msgid="281871464896601236">"Ledger"</string> + <string name="mediaSize_na_tabloid" msgid="5775966416333578127">"Tabloid"</string> + <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"Cancelada"</string> + <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"Error al escribir contenido"</string> + <string name="restr_pin_enter_pin" msgid="3395953421368476103">"Ingresar PIN"</string> + <!-- no translation found for restr_pin_enter_old_pin (1462206225512910757) --> <skip /> - <!-- no translation found for mediaSize_iso_b8 (7316818922278779774) --> + <!-- no translation found for restr_pin_enter_new_pin (5959606691619959184) --> <skip /> - <!-- no translation found for mediaSize_iso_b9 (5414727094026532341) --> + <!-- no translation found for restr_pin_confirm_pin (8501523829633146239) --> <skip /> - <!-- no translation found for mediaSize_iso_b10 (5251253731832048185) --> - <skip /> - <!-- no translation found for mediaSize_iso_c0 (4003138342671964217) --> - <skip /> - <!-- no translation found for mediaSize_iso_c1 (1935188063393553008) --> - <skip /> - <!-- no translation found for mediaSize_iso_c2 (3197307969712069904) --> - <skip /> - <!-- no translation found for mediaSize_iso_c3 (4335826087321913508) --> - <skip /> - <!-- no translation found for mediaSize_iso_c4 (3745639598281015005) --> - <skip /> - <!-- no translation found for mediaSize_iso_c5 (8269457765822791013) --> - <skip /> - <!-- no translation found for mediaSize_iso_c6 (566666105260346930) --> - <skip /> - <!-- no translation found for mediaSize_iso_c7 (8678413180782608498) --> - <skip /> - <!-- no translation found for mediaSize_iso_c8 (8392376206627041730) --> - <skip /> - <!-- no translation found for mediaSize_iso_c9 (9191613372324845405) --> - <skip /> - <!-- no translation found for mediaSize_iso_c10 (7327709699184920822) --> - <skip /> - <!-- no translation found for mediaSize_na_letter (4191805615829472953) --> - <skip /> - <!-- no translation found for mediaSize_na_gvrnmt_letter (7853382192649405507) --> - <skip /> - <!-- no translation found for mediaSize_na_legal (6697982988283823150) --> - <skip /> - <!-- no translation found for mediaSize_na_junior_legal (3727743969902758948) --> - <skip /> - <!-- no translation found for mediaSize_na_ledger (281871464896601236) --> - <skip /> - <!-- no translation found for mediaSize_na_tabloid (5775966416333578127) --> - <skip /> - <!-- no translation found for restr_pin_create_pin (8017600000263450337) --> - <skip /> - <!-- no translation found for restr_pin_enter_pin (3395953421368476103) --> - <skip /> - <!-- no translation found for restr_pin_confirm_pin (2891475237150965991) --> - <skip /> - <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) --> - <skip /> - <!-- no translation found for restr_pin_error_too_short (8173982756265777792) --> - <skip /> - <!-- no translation found for restr_pin_countdown:one (4835639969503729874) --> - <!-- no translation found for restr_pin_countdown:other (8030607343223287654) --> + <string name="restr_pin_create_pin" msgid="8017600000263450337">"Crear PIN para modificar restricciones"</string> + <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"Los PIN no coinciden. Vuelve a intentarlo."</string> + <string name="restr_pin_error_too_short" msgid="8173982756265777792">"El PIN es demasiado corto. Debe tener al menos 4 dígitos."</string> + <plurals name="restr_pin_countdown"> + <item quantity="one" msgid="4835639969503729874">"Reintentar en 1 s"</item> + <item quantity="other" msgid="8030607343223287654">"Reintentar en <xliff:g id="COUNT">%d</xliff:g> s"</item> + </plurals> </resources> diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml index 2dbe795..165c9b6 100644 --- a/core/res/res/values-es/strings.xml +++ b/core/res/res/values-es/strings.xml @@ -279,10 +279,8 @@ <string name="permdesc_reorderTasks" msgid="7734217754877439351">"Permite que la aplicación mueva tareas a segundo o a primer plano. La aplicación puede utilizar este permiso para realizar estos movimientos sin que se lo indique el usuario."</string> <string name="permlab_removeTasks" msgid="6821513401870377403">"detener aplicaciones en ejecución"</string> <string name="permdesc_removeTasks" msgid="1394714352062635493">"Permite que la aplicación termine tareas y cierre sus aplicaciones. Las aplicaciones malintencionadas pueden usar este permiso para interferir en el comportamiento de otras aplicaciones."</string> - <!-- no translation found for permlab_manageActivityStacks (7391191384027303065) --> - <skip /> - <!-- no translation found for permdesc_manageActivityStacks (1615881933034084440) --> - <skip /> + <string name="permlab_manageActivityStacks" msgid="7391191384027303065">"administrar pilas de actividad"</string> + <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"Permite que la aplicación añada, elimine y modifique las pilas de actividad en las que se ejecutan otras aplicaciones. Las aplicaciones maliciosas pueden interrumpir el comportamiento de otras aplicaciones."</string> <string name="permlab_startAnyActivity" msgid="2918768238045206456">"iniciar una actividad"</string> <string name="permdesc_startAnyActivity" msgid="997823695343584001">"Permite que la aplicación inicie una actividad, independientemente de la protección de permisos o de si está exportada."</string> <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"establecer compatibilidad de pantalla"</string> @@ -360,14 +358,10 @@ <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Permite que se enlace con la interfaz de nivel superior de un método de introducción de texto. Las aplicaciones normales no deberían necesitar este permiso."</string> <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"enlazar con un servicio de accesibilidad"</string> <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Permite enlazar con la interfaz de nivel superior de un servicio de accesibilidad. Las aplicaciones normales no deberían necesitar este permiso."</string> - <!-- no translation found for permlab_bindPrintService (8462815179572748761) --> - <skip /> - <!-- no translation found for permdesc_bindPrintService (7960067623209111135) --> - <skip /> - <!-- no translation found for permlab_accessAllPrintJobs (1120792468465711159) --> - <skip /> - <!-- no translation found for permdesc_accessAllPrintJobs (2978185311041864762) --> - <skip /> + <string name="permlab_bindPrintService" msgid="8462815179572748761">"enlazar con un servicio de impresión"</string> + <string name="permdesc_bindPrintService" msgid="7960067623209111135">"Permite enlazar con la interfaz de nivel superior de un servicio de impresión. No debe ser necesario para las aplicaciones normales."</string> + <string name="permlab_accessAllPrintJobs" msgid="1120792468465711159">"acceder a todos los trabajos de impresión"</string> + <string name="permdesc_accessAllPrintJobs" msgid="2978185311041864762">"Permite acceder a trabajos de impresión creados con otra aplicación. No debe ser necesario para aplicaciones normales."</string> <string name="permlab_bindTextService" msgid="7358378401915287938">"enlazar con un servicio de texto"</string> <string name="permdesc_bindTextService" msgid="8151968910973998670">"Permite enlazar con la interfaz de nivel superior de un servicio de texto (por ejemplo, SpellCheckerService). Las aplicaciones normales no deberían necesitar este permiso."</string> <string name="permlab_bindVpnService" msgid="4708596021161473255">"enlazar con un servicio VPN"</string> @@ -470,6 +464,8 @@ <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Permite que la aplicación use funciones de SurfaceFlinger de nivel inferior."</string> <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"leer memoria de almacenamiento intermedio"</string> <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Permite que la aplicación lea el contenido de la memoria de almacenamiento intermedio."</string> + <string name="permlab_accessInputFlinger" msgid="5348635270689553857">"acceder a InputFlinger"</string> + <string name="permdesc_accessInputFlinger" msgid="2104864941201226616">"Permite que la aplicación utilice funciones de bajo nivel de SurfaceFlinger."</string> <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"configurar pantallas Wi-Fi"</string> <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Permite que la aplicación configure pantallas Wi-Fi y se conecte a ellas."</string> <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"controlar pantallas Wi-Fi"</string> @@ -639,10 +635,14 @@ <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Permite que la aplicación administre políticas de red y defina reglas específicas de la aplicación."</string> <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"modificar cálculo de uso de red"</string> <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Permite que la aplicación modifique cómo se registra el uso de red en relación con las aplicaciones. Las aplicaciones normales no deben usar este permiso."</string> + <string name="permlab_markNetworkSocket" msgid="3658527214914959749">"modificar marcas de socket"</string> + <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"Permite que la aplicación modifique marcas de socket para enrutamiento"</string> <string name="permlab_accessNotifications" msgid="7673416487873432268">"acceder a las notificaciones"</string> <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_invokeCarrierSetup" msgid="3699600833975117478">"ejecutar la aplicación de configuración proporcionada por el operador"</string> + <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Permite ejecutar la aplicación de configuración proporcionada por el operador. No debe ser necesario para aplicaciones normales."</string> <string name="policylab_limitPassword" msgid="4497420728857585791">"Establecimiento de reglas de contraseña"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"Controlar la longitud y los caracteres permitidos en las contraseñas de bloqueo de pantalla"</string> <string name="policylab_watchLogin" msgid="914130646942199503">"Control de intentos de bloqueo de pantalla"</string> @@ -752,8 +752,7 @@ <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo!"</string> <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string> <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string> - <!-- no translation found for imProtocolGoogleTalk (493902321140277304) --> - <skip /> + <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Conversaciones"</string> <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string> <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string> <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string> @@ -1515,94 +1514,59 @@ <string name="app_no_restricted_accounts" msgid="5739463249673727736">"Esta aplicación no admite cuentas de perfiles restringidos"</string> <string name="app_not_found" msgid="3429141853498927379">"No se ha encontrado ninguna aplicación que pueda realizar esta acción."</string> <string name="revoke" msgid="5404479185228271586">"Revocar"</string> - <!-- no translation found for mediaSize_iso_a0 (7875427489420821793) --> - <skip /> - <!-- no translation found for mediaSize_iso_a1 (3760734499050875356) --> - <skip /> - <!-- no translation found for mediaSize_iso_a2 (5973266378020144382) --> - <skip /> - <!-- no translation found for mediaSize_iso_a3 (1373407105687300884) --> - <skip /> - <!-- no translation found for mediaSize_iso_a4 (6689772807982597254) --> - <skip /> - <!-- no translation found for mediaSize_iso_a5 (5353549652015741040) --> - <skip /> - <!-- no translation found for mediaSize_iso_a6 (8585038048674911907) --> - <skip /> - <!-- no translation found for mediaSize_iso_a7 (6641836716963839119) --> - <skip /> - <!-- no translation found for mediaSize_iso_a8 (7571139437465693355) --> - <skip /> - <!-- no translation found for mediaSize_iso_a9 (1378455891957115079) --> - <skip /> - <!-- no translation found for mediaSize_iso_a10 (2480747457429475344) --> - <skip /> - <!-- no translation found for mediaSize_iso_b0 (3965935097661108039) --> - <skip /> - <!-- no translation found for mediaSize_iso_b1 (2505753285010115437) --> - <skip /> - <!-- no translation found for mediaSize_iso_b2 (8763874709859458453) --> - <skip /> - <!-- no translation found for mediaSize_iso_b3 (4210506688191764076) --> - <skip /> - <!-- no translation found for mediaSize_iso_b4 (5749404165888526034) --> - <skip /> - <!-- no translation found for mediaSize_iso_b5 (7640627414621904733) --> - <skip /> - <!-- no translation found for mediaSize_iso_b6 (7342988864712748544) --> - <skip /> - <!-- no translation found for mediaSize_iso_b7 (5069844065235382429) --> + <string name="mediaSize_iso_a0" msgid="7875427489420821793">"ISO A0"</string> + <string name="mediaSize_iso_a1" msgid="3760734499050875356">"ISO A1"</string> + <string name="mediaSize_iso_a2" msgid="5973266378020144382">"ISO A2"</string> + <string name="mediaSize_iso_a3" msgid="1373407105687300884">"ISO A3"</string> + <string name="mediaSize_iso_a4" msgid="6689772807982597254">"ISO A4"</string> + <string name="mediaSize_iso_a5" msgid="5353549652015741040">"ISO A5"</string> + <string name="mediaSize_iso_a6" msgid="8585038048674911907">"ISO A6"</string> + <string name="mediaSize_iso_a7" msgid="6641836716963839119">"ISO A7"</string> + <string name="mediaSize_iso_a8" msgid="7571139437465693355">"ISO A8"</string> + <string name="mediaSize_iso_a9" msgid="1378455891957115079">"ISO A9"</string> + <string name="mediaSize_iso_a10" msgid="2480747457429475344">"ISO A10"</string> + <string name="mediaSize_iso_b0" msgid="3965935097661108039">"ISO B0"</string> + <string name="mediaSize_iso_b1" msgid="2505753285010115437">"ISO B1"</string> + <string name="mediaSize_iso_b2" msgid="8763874709859458453">"ISO B2"</string> + <string name="mediaSize_iso_b3" msgid="4210506688191764076">"ISO B3"</string> + <string name="mediaSize_iso_b4" msgid="5749404165888526034">"ISO B4"</string> + <string name="mediaSize_iso_b5" msgid="7640627414621904733">"ISO B5"</string> + <string name="mediaSize_iso_b6" msgid="7342988864712748544">"ISO B6"</string> + <string name="mediaSize_iso_b7" msgid="5069844065235382429">"ISO B7"</string> + <string name="mediaSize_iso_b8" msgid="7316818922278779774">"ISO B8"</string> + <string name="mediaSize_iso_b9" msgid="5414727094026532341">"ISO B9"</string> + <string name="mediaSize_iso_b10" msgid="5251253731832048185">"ISO B10"</string> + <string name="mediaSize_iso_c0" msgid="4003138342671964217">"ISO C0"</string> + <string name="mediaSize_iso_c1" msgid="1935188063393553008">"ISO C1"</string> + <string name="mediaSize_iso_c2" msgid="3197307969712069904">"ISO C2"</string> + <string name="mediaSize_iso_c3" msgid="4335826087321913508">"ISO C3"</string> + <string name="mediaSize_iso_c4" msgid="3745639598281015005">"ISO C4"</string> + <string name="mediaSize_iso_c5" msgid="8269457765822791013">"ISO C5"</string> + <string name="mediaSize_iso_c6" msgid="566666105260346930">"ISO C6"</string> + <string name="mediaSize_iso_c7" msgid="8678413180782608498">"ISO C7"</string> + <string name="mediaSize_iso_c8" msgid="8392376206627041730">"ISO C8"</string> + <string name="mediaSize_iso_c9" msgid="9191613372324845405">"ISO C9"</string> + <string name="mediaSize_iso_c10" msgid="7327709699184920822">"ISO C10"</string> + <string name="mediaSize_na_letter" msgid="4191805615829472953">"Carta"</string> + <string name="mediaSize_na_gvrnmt_letter" msgid="7853382192649405507">"Carta del gobierno"</string> + <string name="mediaSize_na_legal" msgid="6697982988283823150">"Legal"</string> + <string name="mediaSize_na_junior_legal" msgid="3727743969902758948">"Junior legal"</string> + <string name="mediaSize_na_ledger" msgid="281871464896601236">"Doble carta"</string> + <string name="mediaSize_na_tabloid" msgid="5775966416333578127">"Tabloide"</string> + <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"Cancelado"</string> + <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"Error al escribir contenido"</string> + <string name="restr_pin_enter_pin" msgid="3395953421368476103">"Introducir PIN"</string> + <!-- no translation found for restr_pin_enter_old_pin (1462206225512910757) --> <skip /> - <!-- no translation found for mediaSize_iso_b8 (7316818922278779774) --> + <!-- no translation found for restr_pin_enter_new_pin (5959606691619959184) --> <skip /> - <!-- no translation found for mediaSize_iso_b9 (5414727094026532341) --> + <!-- no translation found for restr_pin_confirm_pin (8501523829633146239) --> <skip /> - <!-- no translation found for mediaSize_iso_b10 (5251253731832048185) --> - <skip /> - <!-- no translation found for mediaSize_iso_c0 (4003138342671964217) --> - <skip /> - <!-- no translation found for mediaSize_iso_c1 (1935188063393553008) --> - <skip /> - <!-- no translation found for mediaSize_iso_c2 (3197307969712069904) --> - <skip /> - <!-- no translation found for mediaSize_iso_c3 (4335826087321913508) --> - <skip /> - <!-- no translation found for mediaSize_iso_c4 (3745639598281015005) --> - <skip /> - <!-- no translation found for mediaSize_iso_c5 (8269457765822791013) --> - <skip /> - <!-- no translation found for mediaSize_iso_c6 (566666105260346930) --> - <skip /> - <!-- no translation found for mediaSize_iso_c7 (8678413180782608498) --> - <skip /> - <!-- no translation found for mediaSize_iso_c8 (8392376206627041730) --> - <skip /> - <!-- no translation found for mediaSize_iso_c9 (9191613372324845405) --> - <skip /> - <!-- no translation found for mediaSize_iso_c10 (7327709699184920822) --> - <skip /> - <!-- no translation found for mediaSize_na_letter (4191805615829472953) --> - <skip /> - <!-- no translation found for mediaSize_na_gvrnmt_letter (7853382192649405507) --> - <skip /> - <!-- no translation found for mediaSize_na_legal (6697982988283823150) --> - <skip /> - <!-- no translation found for mediaSize_na_junior_legal (3727743969902758948) --> - <skip /> - <!-- no translation found for mediaSize_na_ledger (281871464896601236) --> - <skip /> - <!-- no translation found for mediaSize_na_tabloid (5775966416333578127) --> - <skip /> - <!-- no translation found for restr_pin_create_pin (8017600000263450337) --> - <skip /> - <!-- no translation found for restr_pin_enter_pin (3395953421368476103) --> - <skip /> - <!-- no translation found for restr_pin_confirm_pin (2891475237150965991) --> - <skip /> - <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) --> - <skip /> - <!-- no translation found for restr_pin_error_too_short (8173982756265777792) --> - <skip /> - <!-- no translation found for restr_pin_countdown:one (4835639969503729874) --> - <!-- no translation found for restr_pin_countdown:other (8030607343223287654) --> + <string name="restr_pin_create_pin" msgid="8017600000263450337">"Crear PIN para modificar restricciones"</string> + <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"Los números PIN no coinciden. Inténtalo de nuevo."</string> + <string name="restr_pin_error_too_short" msgid="8173982756265777792">"El PIN es demasiado corto. Debe tener al menos 4 dígitos."</string> + <plurals name="restr_pin_countdown"> + <item quantity="one" msgid="4835639969503729874">"PIN incorrecto. Inténtalo de nuevo dentro de 1 segundo."</item> + <item quantity="other" msgid="8030607343223287654">"PIN incorrecto. Inténtalo de nuevo dentro de <xliff:g id="COUNT">%d</xliff:g> segundos."</item> + </plurals> </resources> diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml index cd3d97c..82ea4a2 100644 --- a/core/res/res/values-et/strings.xml +++ b/core/res/res/values-et/strings.xml @@ -470,6 +470,10 @@ <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Võimaldab rakendusel kasutada SurfaceFlingeri madalatasemelisi funktsioone."</string> <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"loe kaadripuhvrit"</string> <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Võimaldab rakendusel kaadripuhvri sisu lugeda."</string> + <!-- no translation found for permlab_accessInputFlinger (5348635270689553857) --> + <skip /> + <!-- no translation found for permdesc_accessInputFlinger (2104864941201226616) --> + <skip /> <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"WiFi-ekraanide seadistamine"</string> <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Lubab rakendusel seadistada WiFi-ekraane ja nendega ühendus luua."</string> <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"WiFi-ekraanide juhtimine"</string> @@ -639,10 +643,18 @@ <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Võimaldab rakendusel hallata võrgueeskirju ja määratleda rakendusespetsiifilisi reegleid."</string> <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"võrgukasutuse arvestamise muutmine"</string> <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Võimaldab rakendusel muuta võrgukasutuse loendamist rakenduste suhtes. Mitte kasutada tavarakenduste puhul."</string> + <!-- no translation found for permlab_markNetworkSocket (3658527214914959749) --> + <skip /> + <!-- no translation found for permdesc_markNetworkSocket (7655568433696356578) --> + <skip /> <string name="permlab_accessNotifications" msgid="7673416487873432268">"juurdepääsu märguanded"</string> <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> + <!-- no translation found for permlab_invokeCarrierSetup (3699600833975117478) --> + <skip /> + <!-- no translation found for permdesc_invokeCarrierSetup (4159549152529111920) --> + <skip /> <string name="policylab_limitPassword" msgid="4497420728857585791">"Parooli reeglite määramine"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"Kontrollige ekraaniluku avamise paroolide pikkust ja tähemärke."</string> <string name="policylab_watchLogin" msgid="914130646942199503">"Ekraani avamiskatsed"</string> @@ -1593,11 +1605,19 @@ <skip /> <!-- no translation found for mediaSize_na_tabloid (5775966416333578127) --> <skip /> - <!-- no translation found for restr_pin_create_pin (8017600000263450337) --> + <!-- no translation found for write_fail_reason_cancelled (7091258378121627624) --> + <skip /> + <!-- no translation found for write_fail_reason_cannot_write (8132505417935337724) --> <skip /> <!-- no translation found for restr_pin_enter_pin (3395953421368476103) --> <skip /> - <!-- no translation found for restr_pin_confirm_pin (2891475237150965991) --> + <!-- no translation found for restr_pin_enter_old_pin (1462206225512910757) --> + <skip /> + <!-- no translation found for restr_pin_enter_new_pin (5959606691619959184) --> + <skip /> + <!-- no translation found for restr_pin_confirm_pin (8501523829633146239) --> + <skip /> + <!-- no translation found for restr_pin_create_pin (8017600000263450337) --> <skip /> <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) --> <skip /> diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml index d4b1cb7..38bd3d6 100644 --- a/core/res/res/values-fa/strings.xml +++ b/core/res/res/values-fa/strings.xml @@ -470,6 +470,10 @@ <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"اجازه میدهد برنامه از ویژگیهای سطح پایین SurfaceFlinger استفاده کند."</string> <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"خواندن بافر قاب"</string> <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"به برنامه اجازه میدهد تا محتوای بافر کادر را بخواند."</string> + <!-- no translation found for permlab_accessInputFlinger (5348635270689553857) --> + <skip /> + <!-- no translation found for permdesc_accessInputFlinger (2104864941201226616) --> + <skip /> <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"پیکربندی صفحه نمایشهای Wi‑Fi"</string> <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"به برنامه اجازه میدهد تا اتصال به صفحات نمایش Wi‑Fi را پیکربندی کند."</string> <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"کنترل صفحه نمایشهای Wi‑Fi"</string> @@ -639,10 +643,18 @@ <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"به برنامه اجازه میدهد تا خط مشیهای شبکه را مدیریت کند و قوانین خاص برنامه را تعیین کند."</string> <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"اصلاح محاسبه استفاده از شبکه"</string> <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"به برنامه اجازه میدهد تا نحوه محاسبه کاربرد شبکه در برنامه را تغییر دهد. برای استفاده برنامههای عادی نیست."</string> + <!-- no translation found for permlab_markNetworkSocket (3658527214914959749) --> + <skip /> + <!-- no translation found for permdesc_markNetworkSocket (7655568433696356578) --> + <skip /> <string name="permlab_accessNotifications" msgid="7673416487873432268">"اعلانهای دسترسی"</string> <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_invokeCarrierSetup (3699600833975117478) --> + <skip /> + <!-- no translation found for permdesc_invokeCarrierSetup (4159549152529111920) --> + <skip /> <string name="policylab_limitPassword" msgid="4497420728857585791">"تنظیم قوانین رمز ورود"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"طول و نویسههای مجاز در گذرواژههای بازکردن قفل صفحه را کنترل کنید."</string> <string name="policylab_watchLogin" msgid="914130646942199503">"نمایش تلاشهای قفل گشایی صفحه"</string> @@ -1593,11 +1605,19 @@ <skip /> <!-- no translation found for mediaSize_na_tabloid (5775966416333578127) --> <skip /> - <!-- no translation found for restr_pin_create_pin (8017600000263450337) --> + <!-- no translation found for write_fail_reason_cancelled (7091258378121627624) --> + <skip /> + <!-- no translation found for write_fail_reason_cannot_write (8132505417935337724) --> <skip /> <!-- no translation found for restr_pin_enter_pin (3395953421368476103) --> <skip /> - <!-- no translation found for restr_pin_confirm_pin (2891475237150965991) --> + <!-- no translation found for restr_pin_enter_old_pin (1462206225512910757) --> + <skip /> + <!-- no translation found for restr_pin_enter_new_pin (5959606691619959184) --> + <skip /> + <!-- no translation found for restr_pin_confirm_pin (8501523829633146239) --> + <skip /> + <!-- no translation found for restr_pin_create_pin (8017600000263450337) --> <skip /> <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) --> <skip /> diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml index bded5cc..dccf2ec 100644 --- a/core/res/res/values-fi/strings.xml +++ b/core/res/res/values-fi/strings.xml @@ -470,6 +470,10 @@ <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Antaa sovelluksen käyttää SurfaceFlingerin matalan tason ominaisuuksia."</string> <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"lue kehyspuskuria"</string> <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Antaa sovelluksen lukea kehyspuskurin sisältöä."</string> + <!-- no translation found for permlab_accessInputFlinger (5348635270689553857) --> + <skip /> + <!-- no translation found for permdesc_accessInputFlinger (2104864941201226616) --> + <skip /> <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"määritä wifi-näyttöjen asetukset"</string> <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Antaa sovelluksen määrittää wifi-näyttöjä ja muodostaa yhteyden niihin."</string> <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"hallitse wifi-näyttöjä"</string> @@ -639,10 +643,18 @@ <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Sallii sovelluksen hallinnoida verkkokäytäntöjä ja määritellä sovelluskohtaisia sääntöjä."</string> <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"verkon käytön seurannan muokkaaminen"</string> <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Antaa sovelluksen muokata, miten sovellusten verkonkäyttöä lasketaan. Ei tavallisten sovellusten käyttöön."</string> + <!-- no translation found for permlab_markNetworkSocket (3658527214914959749) --> + <skip /> + <!-- no translation found for permdesc_markNetworkSocket (7655568433696356578) --> + <skip /> <string name="permlab_accessNotifications" msgid="7673416487873432268">"käytä ilmoituksia"</string> <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> + <!-- no translation found for permlab_invokeCarrierSetup (3699600833975117478) --> + <skip /> + <!-- no translation found for permdesc_invokeCarrierSetup (4159549152529111920) --> + <skip /> <string name="policylab_limitPassword" msgid="4497420728857585791">"Aseta salasanasäännöt"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"Hallinnoi ruudun lukituksenpoistosalasanoissa sallittuja merkkejä ja salasanan pituutta."</string> <string name="policylab_watchLogin" msgid="914130646942199503">"Tarkkaile ruudun lukituksen poistoyrityksiä"</string> @@ -1593,11 +1605,19 @@ <skip /> <!-- no translation found for mediaSize_na_tabloid (5775966416333578127) --> <skip /> - <!-- no translation found for restr_pin_create_pin (8017600000263450337) --> + <!-- no translation found for write_fail_reason_cancelled (7091258378121627624) --> + <skip /> + <!-- no translation found for write_fail_reason_cannot_write (8132505417935337724) --> <skip /> <!-- no translation found for restr_pin_enter_pin (3395953421368476103) --> <skip /> - <!-- no translation found for restr_pin_confirm_pin (2891475237150965991) --> + <!-- no translation found for restr_pin_enter_old_pin (1462206225512910757) --> + <skip /> + <!-- no translation found for restr_pin_enter_new_pin (5959606691619959184) --> + <skip /> + <!-- no translation found for restr_pin_confirm_pin (8501523829633146239) --> + <skip /> + <!-- no translation found for restr_pin_create_pin (8017600000263450337) --> <skip /> <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) --> <skip /> diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml index 549c4ae..86d0920 100644 --- a/core/res/res/values-fr/strings.xml +++ b/core/res/res/values-fr/strings.xml @@ -470,6 +470,10 @@ <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Permet à l\'application d\'utiliser les fonctionnalités de bas niveau de SurfaceFlinger."</string> <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"Lecture de la mémoire tampon graphique"</string> <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Permet à l\'application de lire le contenu de la mémoire tampon graphique."</string> + <!-- no translation found for permlab_accessInputFlinger (5348635270689553857) --> + <skip /> + <!-- no translation found for permdesc_accessInputFlinger (2104864941201226616) --> + <skip /> <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"configurer les écrans Wi-Fi"</string> <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Permet à l\'application de configurer des écrans Wi-Fi et de s\'y connecter."</string> <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"contrôler les écrans Wi-Fi"</string> @@ -639,10 +643,18 @@ <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Permet à l\'application de gérer les stratégies du réseau et de définir celles qui sont spécifiques à l\'application."</string> <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"modifier le système de comptabilisation de l\'utilisation du réseau"</string> <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Permet à l\'application de modifier l\'utilisation du réseau par les autres applications. Les applications standards ne doivent pas utiliser cette fonctionnalité."</string> + <!-- no translation found for permlab_markNetworkSocket (3658527214914959749) --> + <skip /> + <!-- no translation found for permdesc_markNetworkSocket (7655568433696356578) --> + <skip /> <string name="permlab_accessNotifications" msgid="7673416487873432268">"accéder aux notifications"</string> <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> + <!-- no translation found for permlab_invokeCarrierSetup (3699600833975117478) --> + <skip /> + <!-- no translation found for permdesc_invokeCarrierSetup (4159549152529111920) --> + <skip /> <string name="policylab_limitPassword" msgid="4497420728857585791">"Définir les règles du mot de passe"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"Choisir le nombre et le type de caractères autorisés dans les mots de passe de déverrouillage de l\'écran"</string> <string name="policylab_watchLogin" msgid="914130646942199503">"Gérer les tentatives de déverrouillage de l\'écran"</string> @@ -1593,11 +1605,19 @@ <skip /> <!-- no translation found for mediaSize_na_tabloid (5775966416333578127) --> <skip /> - <!-- no translation found for restr_pin_create_pin (8017600000263450337) --> + <!-- no translation found for write_fail_reason_cancelled (7091258378121627624) --> + <skip /> + <!-- no translation found for write_fail_reason_cannot_write (8132505417935337724) --> <skip /> <!-- no translation found for restr_pin_enter_pin (3395953421368476103) --> <skip /> - <!-- no translation found for restr_pin_confirm_pin (2891475237150965991) --> + <!-- no translation found for restr_pin_enter_old_pin (1462206225512910757) --> + <skip /> + <!-- no translation found for restr_pin_enter_new_pin (5959606691619959184) --> + <skip /> + <!-- no translation found for restr_pin_confirm_pin (8501523829633146239) --> + <skip /> + <!-- no translation found for restr_pin_create_pin (8017600000263450337) --> <skip /> <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) --> <skip /> diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml index 768dbd1..55c448a 100644 --- a/core/res/res/values-hi/strings.xml +++ b/core/res/res/values-hi/strings.xml @@ -279,10 +279,8 @@ <string name="permdesc_reorderTasks" msgid="7734217754877439351">"एप्लिकेशन को कार्यों को अग्रभूमि और पृष्ठभूमि पर ले जाने देता है. एप्लिकेशन आपके इनपुट के बिना यह कर सकता है."</string> <string name="permlab_removeTasks" msgid="6821513401870377403">"चलने वाले एप्लिकेशन रोकें"</string> <string name="permdesc_removeTasks" msgid="1394714352062635493">"किसी एप्लिकेशन को कार्यों को निकालने और उनके एप्लिकेशन समाप्त करने देता है. दुर्भावनापूर्ण एप्लिकेशन अन्य एप्लिकेशन का व्यवहार बाधित कर सकते हैं."</string> - <!-- no translation found for permlab_manageActivityStacks (7391191384027303065) --> - <skip /> - <!-- no translation found for permdesc_manageActivityStacks (1615881933034084440) --> - <skip /> + <string name="permlab_manageActivityStacks" msgid="7391191384027303065">"गतिविधि स्टैक प्रबंधित करें"</string> + <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"एप्लिकेशन को ऐसे गतिविधि स्टैक जोड़ने, निकालने, और बदलने देता है जिनमें अन्य एप्लिकेशन चलते हों. दुर्भावनापूर्ण एप्लिकेशन अन्य एप्लिकेशन के व्यवहार में बाधा डाल सकते हैं."</string> <string name="permlab_startAnyActivity" msgid="2918768238045206456">"कोई गतिविधि प्रारंभ करें"</string> <string name="permdesc_startAnyActivity" msgid="997823695343584001">"अनुमति सुरक्षा या निर्यात की स्थिति पर ध्यान दिए बिना, एप्लिकेशन को कोई गतिविधि प्रारंभ करने देता है."</string> <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"स्क्रीन संगतता सेट करें"</string> @@ -360,14 +358,10 @@ <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"धारक को किसी इनपुट विधि के शीर्ष-स्तर इंटरफ़ेस से आबद्ध होने देता है. सामान्य एप्लिकेशन के लिए कभी भी आवश्यक नहीं होना चाहिए."</string> <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"पहुंच-योग्यता सेवा से आबद्ध करें"</string> <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"धारक को किसी पहुंच-योग्यता सेवा के शीर्ष-स्तर इंटरफ़ेस से आबद्ध होने देता है. सामान्य एप्लिकेशन के लिए कभी भी आवश्यक नहीं होना चाहिए."</string> - <!-- no translation found for permlab_bindPrintService (8462815179572748761) --> - <skip /> - <!-- no translation found for permdesc_bindPrintService (7960067623209111135) --> - <skip /> - <!-- no translation found for permlab_accessAllPrintJobs (1120792468465711159) --> - <skip /> - <!-- no translation found for permdesc_accessAllPrintJobs (2978185311041864762) --> - <skip /> + <string name="permlab_bindPrintService" msgid="8462815179572748761">"प्रिंट सेवा से आबद्ध करें"</string> + <string name="permdesc_bindPrintService" msgid="7960067623209111135">"धारक को किसी प्रिंट सेवा के शीर्ष-स्तर इंटरफ़ेस से आबद्ध होने देता है. सामान्य एप्लिकेशन के लिए कभी भी आवश्यक नहीं होना चाहिए."</string> + <string name="permlab_accessAllPrintJobs" msgid="1120792468465711159">"सभी प्रिंट कार्य एक्सेस करें"</string> + <string name="permdesc_accessAllPrintJobs" msgid="2978185311041864762">"धारक को अन्य एप्लिकेशन के द्वारा बनाए गए प्रिंट कार्य एक्सेस करने देता है. सामान्य एप्लिकेशन के लिए कभी भी आवश्यक नहीं होना चाहिए."</string> <string name="permlab_bindTextService" msgid="7358378401915287938">"किसी पाठ सेवा पर बने रहें"</string> <string name="permdesc_bindTextService" msgid="8151968910973998670">"धारक को किसी पाठ सेवा (उदा. SpellCheckerService) के शीर्ष-स्तर इंटरफ़ेस पर आबद्ध होने देता है. सामान्य एप्लिकेशन के लिए कभी भी आवश्यक नहीं होना चाहिए."</string> <string name="permlab_bindVpnService" msgid="4708596021161473255">"किसी VPN सेवा से आबद्ध करें"</string> @@ -470,6 +464,8 @@ <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"एप्लिकेशन को SurfaceFlinger निम्न-स्तर सुविधाएं उपयोग करने देता है."</string> <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"फ़्रेम बफ़र पढ़ें"</string> <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"एप्लिकेशन को फ़्रेम बफ़र की सामग्री पढ़ने देता है."</string> + <string name="permlab_accessInputFlinger" msgid="5348635270689553857">"InputFlinger एक्सेस करें"</string> + <string name="permdesc_accessInputFlinger" msgid="2104864941201226616">"एप्लिकेशन को InputFlinger निम्न-स्तर सुविधाओं का उपयोग करने देता है."</string> <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"Wifi डिस्प्ले को कॉन्फ़िगर करें"</string> <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"एप्लिकेशन को कॉन्फ़िगर करने देता है और Wifi डिस्प्ले से कनेक्ट करता है."</string> <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"Wifi डिस्प्ले को नियंत्रित करें"</string> @@ -639,10 +635,14 @@ <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"एप्लिकेशन को नेटवर्क नीतियां प्रबंधित करने और एप्लिकेशन-विशिष्ट नियमों को परिभाषित करने देता है."</string> <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"नेटवर्क उपयोग हिसाब बदलें"</string> <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"एप्लिकेशन को यह संशोधित करने देता है कि एप्लिकेशन की तुलना में नेटवर्क उपयोग का मूल्यांकन कैसे किया जाता है. सामान्य एप्लिकेशन द्वारा उपयोग करने के लिए नहीं."</string> + <string name="permlab_markNetworkSocket" msgid="3658527214914959749">"सॉकेट मार्क बदलें"</string> + <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"एप्लिकेशन को रूटिंग के लिए सॉकेट मार्क बदलने देता है"</string> <string name="permlab_accessNotifications" msgid="7673416487873432268">"सूचनाओं तक पहुंचें"</string> <string name="permdesc_accessNotifications" msgid="458457742683431387">"एप्लिकेशन को सूचनाओं को प्राप्त करने, जांच करने, और साफ़ करने देता है, जिनमें अन्य एप्लिकेशन के द्वारा पोस्ट की गई सूचनाएं भी शामिल हैं."</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"सूचना श्रवणकर्ता सेवा से जुड़ें"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"धारक को सूचना श्रवणकर्ता सेवा के शीर्ष स्तरीय इंटरफ़ेस से जुड़ने देती है. सामान्य एप्लिकेशन के लिए कभी भी आवश्यक नहीं होनी चाहिए."</string> + <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"वाहक के द्वारा उपलब्ध कराया गया कॉन्फ़िगरेशन एप्लिकेशन प्रारंभ करें"</string> + <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"धारक को वाहक के द्वारा उपलब्ध कराया गया कॉन्फ़िगरेशन एप्लिकेशन प्रारंभ करने देता है. सामान्य एप्लिकेशन के लिए कभी भी आवश्यक नहीं होना चाहिए."</string> <string name="policylab_limitPassword" msgid="4497420728857585791">"पासवर्ड नियम सेट करें"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"स्क्रीन-अनलॉक पासवर्ड में अनुमति प्राप्त लंबाई और वर्णों को नियंत्रित करें."</string> <string name="policylab_watchLogin" msgid="914130646942199503">"स्क्रीन-अनलॉक के प्रयासों पर निगरानी रखें"</string> @@ -752,8 +752,7 @@ <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string> <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string> <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string> - <!-- no translation found for imProtocolGoogleTalk (493902321140277304) --> - <skip /> + <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangouts"</string> <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string> <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string> <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string> @@ -1515,94 +1514,59 @@ <string name="app_no_restricted_accounts" msgid="5739463249673727736">"यह एप्लिकेशन प्रतिबंधित प्रोफ़ाइल के खातों का समर्थन नहीं करता है"</string> <string name="app_not_found" msgid="3429141853498927379">"इस कार्यवाही को प्रबंधित करने के लिए कोई एप्लिकेशन नहीं मिला"</string> <string name="revoke" msgid="5404479185228271586">"निरस्त करें"</string> - <!-- no translation found for mediaSize_iso_a0 (7875427489420821793) --> - <skip /> - <!-- no translation found for mediaSize_iso_a1 (3760734499050875356) --> - <skip /> - <!-- no translation found for mediaSize_iso_a2 (5973266378020144382) --> - <skip /> - <!-- no translation found for mediaSize_iso_a3 (1373407105687300884) --> - <skip /> - <!-- no translation found for mediaSize_iso_a4 (6689772807982597254) --> - <skip /> - <!-- no translation found for mediaSize_iso_a5 (5353549652015741040) --> - <skip /> - <!-- no translation found for mediaSize_iso_a6 (8585038048674911907) --> - <skip /> - <!-- no translation found for mediaSize_iso_a7 (6641836716963839119) --> - <skip /> - <!-- no translation found for mediaSize_iso_a8 (7571139437465693355) --> - <skip /> - <!-- no translation found for mediaSize_iso_a9 (1378455891957115079) --> - <skip /> - <!-- no translation found for mediaSize_iso_a10 (2480747457429475344) --> - <skip /> - <!-- no translation found for mediaSize_iso_b0 (3965935097661108039) --> - <skip /> - <!-- no translation found for mediaSize_iso_b1 (2505753285010115437) --> - <skip /> - <!-- no translation found for mediaSize_iso_b2 (8763874709859458453) --> - <skip /> - <!-- no translation found for mediaSize_iso_b3 (4210506688191764076) --> - <skip /> - <!-- no translation found for mediaSize_iso_b4 (5749404165888526034) --> - <skip /> - <!-- no translation found for mediaSize_iso_b5 (7640627414621904733) --> - <skip /> - <!-- no translation found for mediaSize_iso_b6 (7342988864712748544) --> - <skip /> - <!-- no translation found for mediaSize_iso_b7 (5069844065235382429) --> + <string name="mediaSize_iso_a0" msgid="7875427489420821793">"ISO A0"</string> + <string name="mediaSize_iso_a1" msgid="3760734499050875356">"ISO A1"</string> + <string name="mediaSize_iso_a2" msgid="5973266378020144382">"ISO A2"</string> + <string name="mediaSize_iso_a3" msgid="1373407105687300884">"ISO A3"</string> + <string name="mediaSize_iso_a4" msgid="6689772807982597254">"ISO A4"</string> + <string name="mediaSize_iso_a5" msgid="5353549652015741040">"ISO A5"</string> + <string name="mediaSize_iso_a6" msgid="8585038048674911907">"ISO A6"</string> + <string name="mediaSize_iso_a7" msgid="6641836716963839119">"ISO A7"</string> + <string name="mediaSize_iso_a8" msgid="7571139437465693355">"ISO A8"</string> + <string name="mediaSize_iso_a9" msgid="1378455891957115079">"ISO A9"</string> + <string name="mediaSize_iso_a10" msgid="2480747457429475344">"ISO A10"</string> + <string name="mediaSize_iso_b0" msgid="3965935097661108039">"ISO B0"</string> + <string name="mediaSize_iso_b1" msgid="2505753285010115437">"ISO B1"</string> + <string name="mediaSize_iso_b2" msgid="8763874709859458453">"ISO B2"</string> + <string name="mediaSize_iso_b3" msgid="4210506688191764076">"ISO B3"</string> + <string name="mediaSize_iso_b4" msgid="5749404165888526034">"ISO B4"</string> + <string name="mediaSize_iso_b5" msgid="7640627414621904733">"ISO B5"</string> + <string name="mediaSize_iso_b6" msgid="7342988864712748544">"ISO B6"</string> + <string name="mediaSize_iso_b7" msgid="5069844065235382429">"ISO B7"</string> + <string name="mediaSize_iso_b8" msgid="7316818922278779774">"ISO B8"</string> + <string name="mediaSize_iso_b9" msgid="5414727094026532341">"ISO B9"</string> + <string name="mediaSize_iso_b10" msgid="5251253731832048185">"ISO B10"</string> + <string name="mediaSize_iso_c0" msgid="4003138342671964217">"ISO C0"</string> + <string name="mediaSize_iso_c1" msgid="1935188063393553008">"ISO C1"</string> + <string name="mediaSize_iso_c2" msgid="3197307969712069904">"ISO C2"</string> + <string name="mediaSize_iso_c3" msgid="4335826087321913508">"ISO C3"</string> + <string name="mediaSize_iso_c4" msgid="3745639598281015005">"ISO C4"</string> + <string name="mediaSize_iso_c5" msgid="8269457765822791013">"ISO C5"</string> + <string name="mediaSize_iso_c6" msgid="566666105260346930">"ISO C6"</string> + <string name="mediaSize_iso_c7" msgid="8678413180782608498">"ISO C7"</string> + <string name="mediaSize_iso_c8" msgid="8392376206627041730">"ISO C8"</string> + <string name="mediaSize_iso_c9" msgid="9191613372324845405">"ISO C9"</string> + <string name="mediaSize_iso_c10" msgid="7327709699184920822">"ISO C10"</string> + <string name="mediaSize_na_letter" msgid="4191805615829472953">"लेटर"</string> + <string name="mediaSize_na_gvrnmt_letter" msgid="7853382192649405507">"गवर्नमेंट लेटर"</string> + <string name="mediaSize_na_legal" msgid="6697982988283823150">"लीगल"</string> + <string name="mediaSize_na_junior_legal" msgid="3727743969902758948">"जूनियर लीगल"</string> + <string name="mediaSize_na_ledger" msgid="281871464896601236">"लेजर"</string> + <string name="mediaSize_na_tabloid" msgid="5775966416333578127">"टेबलॉइड"</string> + <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"रद्द कर दी गई"</string> + <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"सामग्री लिखने में त्रुटि"</string> + <string name="restr_pin_enter_pin" msgid="3395953421368476103">"PIN डालें"</string> + <!-- no translation found for restr_pin_enter_old_pin (1462206225512910757) --> <skip /> - <!-- no translation found for mediaSize_iso_b8 (7316818922278779774) --> + <!-- no translation found for restr_pin_enter_new_pin (5959606691619959184) --> <skip /> - <!-- no translation found for mediaSize_iso_b9 (5414727094026532341) --> + <!-- no translation found for restr_pin_confirm_pin (8501523829633146239) --> <skip /> - <!-- no translation found for mediaSize_iso_b10 (5251253731832048185) --> - <skip /> - <!-- no translation found for mediaSize_iso_c0 (4003138342671964217) --> - <skip /> - <!-- no translation found for mediaSize_iso_c1 (1935188063393553008) --> - <skip /> - <!-- no translation found for mediaSize_iso_c2 (3197307969712069904) --> - <skip /> - <!-- no translation found for mediaSize_iso_c3 (4335826087321913508) --> - <skip /> - <!-- no translation found for mediaSize_iso_c4 (3745639598281015005) --> - <skip /> - <!-- no translation found for mediaSize_iso_c5 (8269457765822791013) --> - <skip /> - <!-- no translation found for mediaSize_iso_c6 (566666105260346930) --> - <skip /> - <!-- no translation found for mediaSize_iso_c7 (8678413180782608498) --> - <skip /> - <!-- no translation found for mediaSize_iso_c8 (8392376206627041730) --> - <skip /> - <!-- no translation found for mediaSize_iso_c9 (9191613372324845405) --> - <skip /> - <!-- no translation found for mediaSize_iso_c10 (7327709699184920822) --> - <skip /> - <!-- no translation found for mediaSize_na_letter (4191805615829472953) --> - <skip /> - <!-- no translation found for mediaSize_na_gvrnmt_letter (7853382192649405507) --> - <skip /> - <!-- no translation found for mediaSize_na_legal (6697982988283823150) --> - <skip /> - <!-- no translation found for mediaSize_na_junior_legal (3727743969902758948) --> - <skip /> - <!-- no translation found for mediaSize_na_ledger (281871464896601236) --> - <skip /> - <!-- no translation found for mediaSize_na_tabloid (5775966416333578127) --> - <skip /> - <!-- no translation found for restr_pin_create_pin (8017600000263450337) --> - <skip /> - <!-- no translation found for restr_pin_enter_pin (3395953421368476103) --> - <skip /> - <!-- no translation found for restr_pin_confirm_pin (2891475237150965991) --> - <skip /> - <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) --> - <skip /> - <!-- no translation found for restr_pin_error_too_short (8173982756265777792) --> - <skip /> - <!-- no translation found for restr_pin_countdown:one (4835639969503729874) --> - <!-- no translation found for restr_pin_countdown:other (8030607343223287654) --> + <string name="restr_pin_create_pin" msgid="8017600000263450337">"प्रतिबंधों को बदलने के लिए PIN बनाएं"</string> + <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PIN मिलान नहीं करते हैं. पुनः प्रयास करें."</string> + <string name="restr_pin_error_too_short" msgid="8173982756265777792">"PIN बहुत छोटा है. कम से कम 4 अंकों का होना चाहिए."</string> + <plurals name="restr_pin_countdown"> + <item quantity="one" msgid="4835639969503729874">"गलत PIN. 1 सेकंड में पुनः प्रयास करें."</item> + <item quantity="other" msgid="8030607343223287654">"गलत PIN. <xliff:g id="COUNT">%d</xliff:g> सेकंड में पुनः प्रयास करें."</item> + </plurals> </resources> diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml index 730fb21..50289a4 100644 --- a/core/res/res/values-hr/strings.xml +++ b/core/res/res/values-hr/strings.xml @@ -279,10 +279,8 @@ <string name="permdesc_reorderTasks" msgid="7734217754877439351">"Aplikaciji omogućuje premještanje zadataka u prednji plan ili pozadinu. Aplikacija to može napraviti bez vašeg naloga."</string> <string name="permlab_removeTasks" msgid="6821513401870377403">"zaustavljanje pokrenutih aplikacija"</string> <string name="permdesc_removeTasks" msgid="1394714352062635493">"Omogućuje aplikaciji uklanjanje zadataka i uklanjanje njihovih aplikacija. Zlonamjerne aplikacije mogu poremetiti rad drugih aplikacija."</string> - <!-- no translation found for permlab_manageActivityStacks (7391191384027303065) --> - <skip /> - <!-- no translation found for permdesc_manageActivityStacks (1615881933034084440) --> - <skip /> + <string name="permlab_manageActivityStacks" msgid="7391191384027303065">"upravljaj snopovima aktivnosti"</string> + <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"Dopušta aplikaciji dodavanje, uklanjanje i izmjenu snopova aktivnosti u kojima se druge aplikacije izvršavaju. Zlonamjerne aplikacije mogu poremetiti ponašanje ostalih aplikacija."</string> <string name="permlab_startAnyActivity" msgid="2918768238045206456">"započni bilo kakvu aktivnost"</string> <string name="permdesc_startAnyActivity" msgid="997823695343584001">"Omogućuje aplikaciji da započne bilo koju aktivnost, bez obzira na zaštitu pomoću dozvola ili stanje izvoza."</string> <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"postavljanje kompatibilnosti sa zaslonom"</string> @@ -360,14 +358,10 @@ <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Nositelju omogućuje povezivanje sučelja najviše razine načina unosa. Ne bi smjelo biti potrebno za normalne aplikacije."</string> <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"vezivanje uz uslugu dostupnosti"</string> <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Nositelju omogućuje vezanje uz sučelje najviše razine usluge dostupnosti. Ne bi smjelo biti potrebno za normalne aplikacije."</string> - <!-- no translation found for permlab_bindPrintService (8462815179572748761) --> - <skip /> - <!-- no translation found for permdesc_bindPrintService (7960067623209111135) --> - <skip /> - <!-- no translation found for permlab_accessAllPrintJobs (1120792468465711159) --> - <skip /> - <!-- no translation found for permdesc_accessAllPrintJobs (2978185311041864762) --> - <skip /> + <string name="permlab_bindPrintService" msgid="8462815179572748761">"veži se uz uslugu ispisa"</string> + <string name="permdesc_bindPrintService" msgid="7960067623209111135">"Dopušta nositelju vezanje uza sučelje usluge ispisa najviše razine. Ne bi smjelo biti potrebno za uobičajene aplikacije."</string> + <string name="permlab_accessAllPrintJobs" msgid="1120792468465711159">"pristupi svim zadacima ispisa"</string> + <string name="permdesc_accessAllPrintJobs" msgid="2978185311041864762">"Dopušta nositelju pristup zadacima ispisa koje je izradila neka druga aplikacija. Ne bi smjelo biti potrebno za uobičajene aplikacije."</string> <string name="permlab_bindTextService" msgid="7358378401915287938">"vezanje na tekstualnu uslugu"</string> <string name="permdesc_bindTextService" msgid="8151968910973998670">"Omogućuje korisniku povezivanje s najvišom razinom sučelja tekstualne usluge (npr. SpellCheckerService). Ne bi smjelo biti potrebno za normalne aplikacije."</string> <string name="permlab_bindVpnService" msgid="4708596021161473255">"vezanje na VPN uslugu"</string> @@ -470,6 +464,8 @@ <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Aplikaciji omogućuje upotrebu značajki niske razine SurfaceFlinger."</string> <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"čitanje međuspremnika okvira"</string> <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Aplikaciji omogućuje čitanje sadržaja međuspremnika okvira."</string> + <string name="permlab_accessInputFlinger" msgid="5348635270689553857">"pristupi InputFlingeru"</string> + <string name="permdesc_accessInputFlinger" msgid="2104864941201226616">"Dopušta aplikaciji upotrebu značajki niske razine InputFlingera."</string> <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"konfiguriraj Wifi zaslone"</string> <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Omogućuje aplikaciji konfiguriranje i povezivanje s Wi-Fi zaslonima."</string> <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"upravljaj Wifi zaslonima"</string> @@ -639,10 +635,14 @@ <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Aplikaciji omogućuje upravljanje mrežnim pravilima i određivanje pravila za aplikacije."</string> <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"izmjena evidencije mrežne upotrebe"</string> <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Omogućuje aplikaciji izmjenu načina upotrebe mreže u odnosu na aplikacije. Nije namijenjeno uobičajenim aplikacijama."</string> + <string name="permlab_markNetworkSocket" msgid="3658527214914959749">"izmijeni oznake utičnica"</string> + <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"Dopušta aplikaciji izmjenu oznaka utičnica za usmjeravanje"</string> <string name="permlab_accessNotifications" msgid="7673416487873432268">"pristup obavijestima"</string> <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_invokeCarrierSetup" msgid="3699600833975117478">"dozovi operaterovu aplikaciju za konfiguraciju"</string> + <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Dopušta nositelju dozivanje operaterove aplikacije za konfiguraciju. Ne bi smjelo biti potrebno za uobičajene aplikacije."</string> <string name="policylab_limitPassword" msgid="4497420728857585791">"Postavi pravila zaporke"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"Upravljajte duljinom zaporki za otključavanje zaslona i dopuštenim znakovima u tim zaporkama."</string> <string name="policylab_watchLogin" msgid="914130646942199503">"Nadgledaj pokušaje otključavanja zaslona"</string> @@ -752,8 +752,7 @@ <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string> <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string> <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string> - <!-- no translation found for imProtocolGoogleTalk (493902321140277304) --> - <skip /> + <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangouts"</string> <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string> <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string> <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string> @@ -1515,94 +1514,59 @@ <string name="app_no_restricted_accounts" msgid="5739463249673727736">"Aplikacija ne podržava račune za ograničene profile"</string> <string name="app_not_found" msgid="3429141853498927379">"Nije pronađena aplikacija za upravljanje ovom radnjom"</string> <string name="revoke" msgid="5404479185228271586">"Opozovi"</string> - <!-- no translation found for mediaSize_iso_a0 (7875427489420821793) --> - <skip /> - <!-- no translation found for mediaSize_iso_a1 (3760734499050875356) --> - <skip /> - <!-- no translation found for mediaSize_iso_a2 (5973266378020144382) --> - <skip /> - <!-- no translation found for mediaSize_iso_a3 (1373407105687300884) --> - <skip /> - <!-- no translation found for mediaSize_iso_a4 (6689772807982597254) --> - <skip /> - <!-- no translation found for mediaSize_iso_a5 (5353549652015741040) --> - <skip /> - <!-- no translation found for mediaSize_iso_a6 (8585038048674911907) --> - <skip /> - <!-- no translation found for mediaSize_iso_a7 (6641836716963839119) --> - <skip /> - <!-- no translation found for mediaSize_iso_a8 (7571139437465693355) --> - <skip /> - <!-- no translation found for mediaSize_iso_a9 (1378455891957115079) --> - <skip /> - <!-- no translation found for mediaSize_iso_a10 (2480747457429475344) --> - <skip /> - <!-- no translation found for mediaSize_iso_b0 (3965935097661108039) --> - <skip /> - <!-- no translation found for mediaSize_iso_b1 (2505753285010115437) --> - <skip /> - <!-- no translation found for mediaSize_iso_b2 (8763874709859458453) --> - <skip /> - <!-- no translation found for mediaSize_iso_b3 (4210506688191764076) --> - <skip /> - <!-- no translation found for mediaSize_iso_b4 (5749404165888526034) --> - <skip /> - <!-- no translation found for mediaSize_iso_b5 (7640627414621904733) --> - <skip /> - <!-- no translation found for mediaSize_iso_b6 (7342988864712748544) --> - <skip /> - <!-- no translation found for mediaSize_iso_b7 (5069844065235382429) --> + <string name="mediaSize_iso_a0" msgid="7875427489420821793">"ISO A0"</string> + <string name="mediaSize_iso_a1" msgid="3760734499050875356">"ISO A1"</string> + <string name="mediaSize_iso_a2" msgid="5973266378020144382">"ISO A2"</string> + <string name="mediaSize_iso_a3" msgid="1373407105687300884">"ISO A3"</string> + <string name="mediaSize_iso_a4" msgid="6689772807982597254">"ISO A4"</string> + <string name="mediaSize_iso_a5" msgid="5353549652015741040">"ISO A5"</string> + <string name="mediaSize_iso_a6" msgid="8585038048674911907">"ISO A6"</string> + <string name="mediaSize_iso_a7" msgid="6641836716963839119">"ISO A7"</string> + <string name="mediaSize_iso_a8" msgid="7571139437465693355">"ISO A8"</string> + <string name="mediaSize_iso_a9" msgid="1378455891957115079">"ISO A9"</string> + <string name="mediaSize_iso_a10" msgid="2480747457429475344">"ISO A10"</string> + <string name="mediaSize_iso_b0" msgid="3965935097661108039">"ISO B0"</string> + <string name="mediaSize_iso_b1" msgid="2505753285010115437">"ISO B1"</string> + <string name="mediaSize_iso_b2" msgid="8763874709859458453">"ISO B2"</string> + <string name="mediaSize_iso_b3" msgid="4210506688191764076">"ISO B3"</string> + <string name="mediaSize_iso_b4" msgid="5749404165888526034">"ISO B4"</string> + <string name="mediaSize_iso_b5" msgid="7640627414621904733">"ISO B5"</string> + <string name="mediaSize_iso_b6" msgid="7342988864712748544">"ISO B6"</string> + <string name="mediaSize_iso_b7" msgid="5069844065235382429">"ISO B7"</string> + <string name="mediaSize_iso_b8" msgid="7316818922278779774">"ISO B8"</string> + <string name="mediaSize_iso_b9" msgid="5414727094026532341">"ISO B9"</string> + <string name="mediaSize_iso_b10" msgid="5251253731832048185">"ISO B10"</string> + <string name="mediaSize_iso_c0" msgid="4003138342671964217">"ISO C0"</string> + <string name="mediaSize_iso_c1" msgid="1935188063393553008">"ISO C1"</string> + <string name="mediaSize_iso_c2" msgid="3197307969712069904">"ISO C2"</string> + <string name="mediaSize_iso_c3" msgid="4335826087321913508">"ISO C3"</string> + <string name="mediaSize_iso_c4" msgid="3745639598281015005">"ISO C4"</string> + <string name="mediaSize_iso_c5" msgid="8269457765822791013">"ISO C5"</string> + <string name="mediaSize_iso_c6" msgid="566666105260346930">"ISO C6"</string> + <string name="mediaSize_iso_c7" msgid="8678413180782608498">"ISO C7"</string> + <string name="mediaSize_iso_c8" msgid="8392376206627041730">"ISO C8"</string> + <string name="mediaSize_iso_c9" msgid="9191613372324845405">"ISO C9"</string> + <string name="mediaSize_iso_c10" msgid="7327709699184920822">"ISO C10"</string> + <string name="mediaSize_na_letter" msgid="4191805615829472953">"Letter"</string> + <string name="mediaSize_na_gvrnmt_letter" msgid="7853382192649405507">"Government Letter"</string> + <string name="mediaSize_na_legal" msgid="6697982988283823150">"Legal"</string> + <string name="mediaSize_na_junior_legal" msgid="3727743969902758948">"Junior Legal"</string> + <string name="mediaSize_na_ledger" msgid="281871464896601236">"Ledger"</string> + <string name="mediaSize_na_tabloid" msgid="5775966416333578127">"Tabloid"</string> + <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"Otkazano"</string> + <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"Pogreška prilikom pisanja sadržaja"</string> + <string name="restr_pin_enter_pin" msgid="3395953421368476103">"Unesite PIN"</string> + <!-- no translation found for restr_pin_enter_old_pin (1462206225512910757) --> <skip /> - <!-- no translation found for mediaSize_iso_b8 (7316818922278779774) --> + <!-- no translation found for restr_pin_enter_new_pin (5959606691619959184) --> <skip /> - <!-- no translation found for mediaSize_iso_b9 (5414727094026532341) --> + <!-- no translation found for restr_pin_confirm_pin (8501523829633146239) --> <skip /> - <!-- no translation found for mediaSize_iso_b10 (5251253731832048185) --> - <skip /> - <!-- no translation found for mediaSize_iso_c0 (4003138342671964217) --> - <skip /> - <!-- no translation found for mediaSize_iso_c1 (1935188063393553008) --> - <skip /> - <!-- no translation found for mediaSize_iso_c2 (3197307969712069904) --> - <skip /> - <!-- no translation found for mediaSize_iso_c3 (4335826087321913508) --> - <skip /> - <!-- no translation found for mediaSize_iso_c4 (3745639598281015005) --> - <skip /> - <!-- no translation found for mediaSize_iso_c5 (8269457765822791013) --> - <skip /> - <!-- no translation found for mediaSize_iso_c6 (566666105260346930) --> - <skip /> - <!-- no translation found for mediaSize_iso_c7 (8678413180782608498) --> - <skip /> - <!-- no translation found for mediaSize_iso_c8 (8392376206627041730) --> - <skip /> - <!-- no translation found for mediaSize_iso_c9 (9191613372324845405) --> - <skip /> - <!-- no translation found for mediaSize_iso_c10 (7327709699184920822) --> - <skip /> - <!-- no translation found for mediaSize_na_letter (4191805615829472953) --> - <skip /> - <!-- no translation found for mediaSize_na_gvrnmt_letter (7853382192649405507) --> - <skip /> - <!-- no translation found for mediaSize_na_legal (6697982988283823150) --> - <skip /> - <!-- no translation found for mediaSize_na_junior_legal (3727743969902758948) --> - <skip /> - <!-- no translation found for mediaSize_na_ledger (281871464896601236) --> - <skip /> - <!-- no translation found for mediaSize_na_tabloid (5775966416333578127) --> - <skip /> - <!-- no translation found for restr_pin_create_pin (8017600000263450337) --> - <skip /> - <!-- no translation found for restr_pin_enter_pin (3395953421368476103) --> - <skip /> - <!-- no translation found for restr_pin_confirm_pin (2891475237150965991) --> - <skip /> - <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) --> - <skip /> - <!-- no translation found for restr_pin_error_too_short (8173982756265777792) --> - <skip /> - <!-- no translation found for restr_pin_countdown:one (4835639969503729874) --> - <!-- no translation found for restr_pin_countdown:other (8030607343223287654) --> + <string name="restr_pin_create_pin" msgid="8017600000263450337">"Izradite PIN za izmjenu ograničenja"</string> + <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PIN-ovi se ne podudaraju. Pokušajte ponovo."</string> + <string name="restr_pin_error_too_short" msgid="8173982756265777792">"PIN je prekratak. Mora imati barem 4 znamenke."</string> + <plurals name="restr_pin_countdown"> + <item quantity="one" msgid="4835639969503729874">"PIN nije točan. Ponovite za 1 s."</item> + <item quantity="other" msgid="8030607343223287654">"PIN nije točan. Ponovite za <xliff:g id="COUNT">%d</xliff:g> s."</item> + </plurals> </resources> diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml index 23f8e74..73d7341 100644 --- a/core/res/res/values-hu/strings.xml +++ b/core/res/res/values-hu/strings.xml @@ -470,6 +470,10 @@ <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Lehetővé teszi az alkalmazás számára a SurfaceFlinger alacsony szintű funkciók használatát."</string> <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"keretpuffer olvasása"</string> <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Lehetővé teszi az alkalmazás számára a keretpuffer tartalmának olvasását."</string> + <!-- no translation found for permlab_accessInputFlinger (5348635270689553857) --> + <skip /> + <!-- no translation found for permdesc_accessInputFlinger (2104864941201226616) --> + <skip /> <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"Wi-Fi kijelzők konfigurálása"</string> <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Lehetővé teszi, hogy az alkalmazás Wi-Fi kijelzőket konfiguráljon, és csatlakozzon hozzájuk."</string> <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"Wi-Fi kijelzők irányítása"</string> @@ -639,10 +643,18 @@ <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Lehetővé teszi az alkalmazás számára, hogy kezelje a hálózati irányelveket és meghatározza az alkalmazásspecifikus szabályokat."</string> <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"hálózathasználat elszámolásának módosítása"</string> <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Lehetővé teszi az alkalmazás számára annak módosítását, hogy a hálózathasználatot hogyan számolják el az alkalmazások esetében. Normál alkalmazások nem használhatják."</string> + <!-- no translation found for permlab_markNetworkSocket (3658527214914959749) --> + <skip /> + <!-- no translation found for permdesc_markNetworkSocket (7655568433696356578) --> + <skip /> <string name="permlab_accessNotifications" msgid="7673416487873432268">"hozzáférési értesítések"</string> <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> + <!-- no translation found for permlab_invokeCarrierSetup (3699600833975117478) --> + <skip /> + <!-- no translation found for permdesc_invokeCarrierSetup (4159549152529111920) --> + <skip /> <string name="policylab_limitPassword" msgid="4497420728857585791">"Jelszavakkal kapcsolatos szabályok beállítása"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"A képernyőzár-feloldási jelszavakban engedélyezett karakterek és hosszúság vezérlése."</string> <string name="policylab_watchLogin" msgid="914130646942199503">"Képernyőzár-feloldási kísérletek figyelése"</string> @@ -1593,11 +1605,19 @@ <skip /> <!-- no translation found for mediaSize_na_tabloid (5775966416333578127) --> <skip /> - <!-- no translation found for restr_pin_create_pin (8017600000263450337) --> + <!-- no translation found for write_fail_reason_cancelled (7091258378121627624) --> + <skip /> + <!-- no translation found for write_fail_reason_cannot_write (8132505417935337724) --> <skip /> <!-- no translation found for restr_pin_enter_pin (3395953421368476103) --> <skip /> - <!-- no translation found for restr_pin_confirm_pin (2891475237150965991) --> + <!-- no translation found for restr_pin_enter_old_pin (1462206225512910757) --> + <skip /> + <!-- no translation found for restr_pin_enter_new_pin (5959606691619959184) --> + <skip /> + <!-- no translation found for restr_pin_confirm_pin (8501523829633146239) --> + <skip /> + <!-- no translation found for restr_pin_create_pin (8017600000263450337) --> <skip /> <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) --> <skip /> diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml index ee652c5..67e1854 100644 --- a/core/res/res/values-in/strings.xml +++ b/core/res/res/values-in/strings.xml @@ -470,6 +470,10 @@ <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Mengizinkan apl menggunakan fitur tingkat rendah SurfaceFlinger."</string> <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"baca buffer frame"</string> <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Mengizinkan apl membaca konten penyangga frame."</string> + <!-- no translation found for permlab_accessInputFlinger (5348635270689553857) --> + <skip /> + <!-- no translation found for permdesc_accessInputFlinger (2104864941201226616) --> + <skip /> <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"mengonfigurasi tampilan Wi-Fi"</string> <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Izinkan aplikasi mengonfigurasi dan terhubung ke tampilan Wi-Fi."</string> <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"mengontrol tampilan Wi-Fi"</string> @@ -639,10 +643,18 @@ <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Mengizinkan apl mengelola kebijakan jaringan dan menentukan peraturan khusus apl."</string> <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"mengubah penghitungan penggunaan jaringan"</string> <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Mengizinkan apl memodifikasi cara penggunaan jaringan diperhitungkan terhadap apl. Tidak untuk digunakan oleh apl normal."</string> + <!-- no translation found for permlab_markNetworkSocket (3658527214914959749) --> + <skip /> + <!-- no translation found for permdesc_markNetworkSocket (7655568433696356578) --> + <skip /> <string name="permlab_accessNotifications" msgid="7673416487873432268">"mengakses pemberitahuan"</string> <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> + <!-- no translation found for permlab_invokeCarrierSetup (3699600833975117478) --> + <skip /> + <!-- no translation found for permdesc_invokeCarrierSetup (4159549152529111920) --> + <skip /> <string name="policylab_limitPassword" msgid="4497420728857585791">"Setel aturan sandi"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"Kontrol panjang dan karakter yang diizinkan dalam sandi pembuka layar."</string> <string name="policylab_watchLogin" msgid="914130646942199503">"Upaya pembukaan kunci layar monitor"</string> @@ -1593,11 +1605,19 @@ <skip /> <!-- no translation found for mediaSize_na_tabloid (5775966416333578127) --> <skip /> - <!-- no translation found for restr_pin_create_pin (8017600000263450337) --> + <!-- no translation found for write_fail_reason_cancelled (7091258378121627624) --> + <skip /> + <!-- no translation found for write_fail_reason_cannot_write (8132505417935337724) --> <skip /> <!-- no translation found for restr_pin_enter_pin (3395953421368476103) --> <skip /> - <!-- no translation found for restr_pin_confirm_pin (2891475237150965991) --> + <!-- no translation found for restr_pin_enter_old_pin (1462206225512910757) --> + <skip /> + <!-- no translation found for restr_pin_enter_new_pin (5959606691619959184) --> + <skip /> + <!-- no translation found for restr_pin_confirm_pin (8501523829633146239) --> + <skip /> + <!-- no translation found for restr_pin_create_pin (8017600000263450337) --> <skip /> <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) --> <skip /> diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml index 4059ad5..7e106d8 100644 --- a/core/res/res/values-it/strings.xml +++ b/core/res/res/values-it/strings.xml @@ -279,10 +279,8 @@ <string name="permdesc_reorderTasks" msgid="7734217754877439351">"Consente all\'applicazione di spostare attività in primo piano e in background. L\'applicazione potrebbe farlo senza un tuo comando."</string> <string name="permlab_removeTasks" msgid="6821513401870377403">"interruzione applicazioni in esecuzione"</string> <string name="permdesc_removeTasks" msgid="1394714352062635493">"Consente all\'applicazione di rimuovere le attività e terminare le loro applicazioni. Le applicazioni dannose potrebbero interferire con il comportamento di altre applicazioni."</string> - <!-- no translation found for permlab_manageActivityStacks (7391191384027303065) --> - <skip /> - <!-- no translation found for permdesc_manageActivityStacks (1615881933034084440) --> - <skip /> + <string name="permlab_manageActivityStacks" msgid="7391191384027303065">"gestione di stack attività"</string> + <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"Consente all\'app di aggiungere, rimuovere e modificare stack attività in cui vengono eseguite altre app. Le app dannose possono alterare il funzionamento delle altre app."</string> <string name="permlab_startAnyActivity" msgid="2918768238045206456">"inizio di un\'attività"</string> <string name="permdesc_startAnyActivity" msgid="997823695343584001">"Consente all\'applicazione di iniziare un\'attività, indipendentemente dalla protezione delle autorizzazioni o dallo stato esportato."</string> <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"impostazione compatibilità schermo"</string> @@ -360,14 +358,10 @@ <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Consente l\'associazione di un metodo di inserimento all\'interfaccia principale. Non dovrebbe mai essere necessaria per le normali applicazioni."</string> <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"collegamento a un servizio di accessibilità"</string> <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Consente al titolare di collegarsi all\'interfaccia di primo livello di un servizio di accessibilità. Non dovrebbe essere mai necessaria per le normali applicazioni."</string> - <!-- no translation found for permlab_bindPrintService (8462815179572748761) --> - <skip /> - <!-- no translation found for permdesc_bindPrintService (7960067623209111135) --> - <skip /> - <!-- no translation found for permlab_accessAllPrintJobs (1120792468465711159) --> - <skip /> - <!-- no translation found for permdesc_accessAllPrintJobs (2978185311041864762) --> - <skip /> + <string name="permlab_bindPrintService" msgid="8462815179572748761">"collegamento a un servizio di stampa"</string> + <string name="permdesc_bindPrintService" msgid="7960067623209111135">"Consente al titolare di collegarsi all\'interfaccia di primo livello di un servizio di stampa. Non dovrebbe essere mai necessaria per le normali applicazioni."</string> + <string name="permlab_accessAllPrintJobs" msgid="1120792468465711159">"accesso a tutti i processi di stampa"</string> + <string name="permdesc_accessAllPrintJobs" msgid="2978185311041864762">"Consente al titolare di accedere ai processi di stampa creati da un\'altra app. Non dovrebbe essere mai necessaria per le normali applicazioni."</string> <string name="permlab_bindTextService" msgid="7358378401915287938">"associazione a un servizio di testo"</string> <string name="permdesc_bindTextService" msgid="8151968910973998670">"Consente al titolare di collegarsi all\'interfaccia di primo livello di un servizio di testo (ad esempio SpellCheckerService). Non dovrebbe essere mai necessaria per le normali applicazioni."</string> <string name="permlab_bindVpnService" msgid="4708596021161473255">"associazione a un servizio VPN"</string> @@ -470,6 +464,8 @@ <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Consente all\'applicazione l\'utilizzo di funzioni di basso livello SurfaceFlinger."</string> <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"lettura buffer di frame"</string> <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Consente all\'applicazione di leggere i contenuti del buffer di frame."</string> + <string name="permlab_accessInputFlinger" msgid="5348635270689553857">"accesso a InputFlinger"</string> + <string name="permdesc_accessInputFlinger" msgid="2104864941201226616">"Consente all\'applicazione di utilizzare funzioni di basso livello InputFlinger."</string> <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"configurazione di schermi Wi-Fi"</string> <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Consente all\'applicazione di configurare schermi Wi-Fi e di collegarsi a essi."</string> <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"controllo di schermi Wi-Fi"</string> @@ -639,10 +635,14 @@ <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Consente all\'applicazione di gestire le norme di rete e definire le regole specifiche delle applicazioni."</string> <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"modifica calcolo dell\'utilizzo della rete"</string> <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Consente all\'applicazione di modificare il calcolo dell\'utilizzo della rete tra le applicazioni. Da non usare per normali applicazioni."</string> + <string name="permlab_markNetworkSocket" msgid="3658527214914959749">"modifica di contrassegni socket"</string> + <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"Consente all\'app di modificare i contrassegni socket per il routing"</string> <string name="permlab_accessNotifications" msgid="7673416487873432268">"accesso a notifiche"</string> <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_invokeCarrierSetup" msgid="3699600833975117478">"richiamo dell\'app di configurazione operatore-provider"</string> + <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Consente al titolare di richiamare l\'app di configurazione dell\'operatore-provider. Non dovrebbe essere mai necessaria per le normali applicazioni."</string> <string name="policylab_limitPassword" msgid="4497420728857585791">"Imposta regole password"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"Controlla la lunghezza e i caratteri ammessi nelle password di sblocco dello schermo."</string> <string name="policylab_watchLogin" msgid="914130646942199503">"Monitora tentativi di sblocco dello schermo"</string> @@ -752,8 +752,7 @@ <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string> <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string> <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string> - <!-- no translation found for imProtocolGoogleTalk (493902321140277304) --> - <skip /> + <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangout"</string> <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string> <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string> <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string> @@ -1515,94 +1514,59 @@ <string name="app_no_restricted_accounts" msgid="5739463249673727736">"Questa app non supporta account relativi a profili con limitazioni"</string> <string name="app_not_found" msgid="3429141853498927379">"Nessuna applicazione trovata in grado di gestire questa azione"</string> <string name="revoke" msgid="5404479185228271586">"Revoca"</string> - <!-- no translation found for mediaSize_iso_a0 (7875427489420821793) --> - <skip /> - <!-- no translation found for mediaSize_iso_a1 (3760734499050875356) --> - <skip /> - <!-- no translation found for mediaSize_iso_a2 (5973266378020144382) --> - <skip /> - <!-- no translation found for mediaSize_iso_a3 (1373407105687300884) --> - <skip /> - <!-- no translation found for mediaSize_iso_a4 (6689772807982597254) --> - <skip /> - <!-- no translation found for mediaSize_iso_a5 (5353549652015741040) --> - <skip /> - <!-- no translation found for mediaSize_iso_a6 (8585038048674911907) --> - <skip /> - <!-- no translation found for mediaSize_iso_a7 (6641836716963839119) --> - <skip /> - <!-- no translation found for mediaSize_iso_a8 (7571139437465693355) --> - <skip /> - <!-- no translation found for mediaSize_iso_a9 (1378455891957115079) --> - <skip /> - <!-- no translation found for mediaSize_iso_a10 (2480747457429475344) --> - <skip /> - <!-- no translation found for mediaSize_iso_b0 (3965935097661108039) --> - <skip /> - <!-- no translation found for mediaSize_iso_b1 (2505753285010115437) --> - <skip /> - <!-- no translation found for mediaSize_iso_b2 (8763874709859458453) --> - <skip /> - <!-- no translation found for mediaSize_iso_b3 (4210506688191764076) --> - <skip /> - <!-- no translation found for mediaSize_iso_b4 (5749404165888526034) --> - <skip /> - <!-- no translation found for mediaSize_iso_b5 (7640627414621904733) --> - <skip /> - <!-- no translation found for mediaSize_iso_b6 (7342988864712748544) --> - <skip /> - <!-- no translation found for mediaSize_iso_b7 (5069844065235382429) --> + <string name="mediaSize_iso_a0" msgid="7875427489420821793">"ISO A0"</string> + <string name="mediaSize_iso_a1" msgid="3760734499050875356">"ISO A1"</string> + <string name="mediaSize_iso_a2" msgid="5973266378020144382">"ISO A2"</string> + <string name="mediaSize_iso_a3" msgid="1373407105687300884">"ISO A3"</string> + <string name="mediaSize_iso_a4" msgid="6689772807982597254">"ISO A4"</string> + <string name="mediaSize_iso_a5" msgid="5353549652015741040">"ISO A5"</string> + <string name="mediaSize_iso_a6" msgid="8585038048674911907">"ISO A6"</string> + <string name="mediaSize_iso_a7" msgid="6641836716963839119">"ISO A7"</string> + <string name="mediaSize_iso_a8" msgid="7571139437465693355">"ISO A8"</string> + <string name="mediaSize_iso_a9" msgid="1378455891957115079">"ISO A9"</string> + <string name="mediaSize_iso_a10" msgid="2480747457429475344">"ISO A10"</string> + <string name="mediaSize_iso_b0" msgid="3965935097661108039">"ISO B0"</string> + <string name="mediaSize_iso_b1" msgid="2505753285010115437">"ISO B1"</string> + <string name="mediaSize_iso_b2" msgid="8763874709859458453">"ISO B2"</string> + <string name="mediaSize_iso_b3" msgid="4210506688191764076">"ISO B3"</string> + <string name="mediaSize_iso_b4" msgid="5749404165888526034">"ISO B4"</string> + <string name="mediaSize_iso_b5" msgid="7640627414621904733">"ISO B5"</string> + <string name="mediaSize_iso_b6" msgid="7342988864712748544">"ISO B6"</string> + <string name="mediaSize_iso_b7" msgid="5069844065235382429">"ISO B7"</string> + <string name="mediaSize_iso_b8" msgid="7316818922278779774">"ISO B8"</string> + <string name="mediaSize_iso_b9" msgid="5414727094026532341">"ISO B9"</string> + <string name="mediaSize_iso_b10" msgid="5251253731832048185">"ISO B10"</string> + <string name="mediaSize_iso_c0" msgid="4003138342671964217">"ISO C0"</string> + <string name="mediaSize_iso_c1" msgid="1935188063393553008">"ISO C1"</string> + <string name="mediaSize_iso_c2" msgid="3197307969712069904">"ISO C2"</string> + <string name="mediaSize_iso_c3" msgid="4335826087321913508">"ISO C3"</string> + <string name="mediaSize_iso_c4" msgid="3745639598281015005">"ISO C4"</string> + <string name="mediaSize_iso_c5" msgid="8269457765822791013">"ISO C5"</string> + <string name="mediaSize_iso_c6" msgid="566666105260346930">"ISO C6"</string> + <string name="mediaSize_iso_c7" msgid="8678413180782608498">"ISO C7"</string> + <string name="mediaSize_iso_c8" msgid="8392376206627041730">"ISO C8"</string> + <string name="mediaSize_iso_c9" msgid="9191613372324845405">"ISO C9"</string> + <string name="mediaSize_iso_c10" msgid="7327709699184920822">"ISO C10"</string> + <string name="mediaSize_na_letter" msgid="4191805615829472953">"Lettera"</string> + <string name="mediaSize_na_gvrnmt_letter" msgid="7853382192649405507">"Government letter"</string> + <string name="mediaSize_na_legal" msgid="6697982988283823150">"Legale"</string> + <string name="mediaSize_na_junior_legal" msgid="3727743969902758948">"Legale \"junior\""</string> + <string name="mediaSize_na_ledger" msgid="281871464896601236">"Ledger"</string> + <string name="mediaSize_na_tabloid" msgid="5775966416333578127">"Tabloid"</string> + <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"Annullato"</string> + <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"Errore nella scrittura dei contenuti"</string> + <string name="restr_pin_enter_pin" msgid="3395953421368476103">"Inserisci PIN"</string> + <!-- no translation found for restr_pin_enter_old_pin (1462206225512910757) --> <skip /> - <!-- no translation found for mediaSize_iso_b8 (7316818922278779774) --> + <!-- no translation found for restr_pin_enter_new_pin (5959606691619959184) --> <skip /> - <!-- no translation found for mediaSize_iso_b9 (5414727094026532341) --> + <!-- no translation found for restr_pin_confirm_pin (8501523829633146239) --> <skip /> - <!-- no translation found for mediaSize_iso_b10 (5251253731832048185) --> - <skip /> - <!-- no translation found for mediaSize_iso_c0 (4003138342671964217) --> - <skip /> - <!-- no translation found for mediaSize_iso_c1 (1935188063393553008) --> - <skip /> - <!-- no translation found for mediaSize_iso_c2 (3197307969712069904) --> - <skip /> - <!-- no translation found for mediaSize_iso_c3 (4335826087321913508) --> - <skip /> - <!-- no translation found for mediaSize_iso_c4 (3745639598281015005) --> - <skip /> - <!-- no translation found for mediaSize_iso_c5 (8269457765822791013) --> - <skip /> - <!-- no translation found for mediaSize_iso_c6 (566666105260346930) --> - <skip /> - <!-- no translation found for mediaSize_iso_c7 (8678413180782608498) --> - <skip /> - <!-- no translation found for mediaSize_iso_c8 (8392376206627041730) --> - <skip /> - <!-- no translation found for mediaSize_iso_c9 (9191613372324845405) --> - <skip /> - <!-- no translation found for mediaSize_iso_c10 (7327709699184920822) --> - <skip /> - <!-- no translation found for mediaSize_na_letter (4191805615829472953) --> - <skip /> - <!-- no translation found for mediaSize_na_gvrnmt_letter (7853382192649405507) --> - <skip /> - <!-- no translation found for mediaSize_na_legal (6697982988283823150) --> - <skip /> - <!-- no translation found for mediaSize_na_junior_legal (3727743969902758948) --> - <skip /> - <!-- no translation found for mediaSize_na_ledger (281871464896601236) --> - <skip /> - <!-- no translation found for mediaSize_na_tabloid (5775966416333578127) --> - <skip /> - <!-- no translation found for restr_pin_create_pin (8017600000263450337) --> - <skip /> - <!-- no translation found for restr_pin_enter_pin (3395953421368476103) --> - <skip /> - <!-- no translation found for restr_pin_confirm_pin (2891475237150965991) --> - <skip /> - <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) --> - <skip /> - <!-- no translation found for restr_pin_error_too_short (8173982756265777792) --> - <skip /> - <!-- no translation found for restr_pin_countdown:one (4835639969503729874) --> - <!-- no translation found for restr_pin_countdown:other (8030607343223287654) --> + <string name="restr_pin_create_pin" msgid="8017600000263450337">"Crea un PIN per la modifica delle limitazioni"</string> + <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"I PIN non corrispondono. Riprova."</string> + <string name="restr_pin_error_too_short" msgid="8173982756265777792">"Il PIN è troppo corto. Deve avere almeno quattro cifre."</string> + <plurals name="restr_pin_countdown"> + <item quantity="one" msgid="4835639969503729874">"PIN errato. Riprova tra 1 s."</item> + <item quantity="other" msgid="8030607343223287654">"PIN errato. Riprova tra <xliff:g id="COUNT">%d</xliff:g> s."</item> + </plurals> </resources> diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml index 6168fdf..66a62e7 100644 --- a/core/res/res/values-iw/strings.xml +++ b/core/res/res/values-iw/strings.xml @@ -279,10 +279,8 @@ <string name="permdesc_reorderTasks" msgid="7734217754877439351">"מאפשר ליישום להעביר משימות לחזית ולרקע. היישום עשוי לעשות זאת ללא התערבותך."</string> <string name="permlab_removeTasks" msgid="6821513401870377403">"עצירת יישומים פעילים"</string> <string name="permdesc_removeTasks" msgid="1394714352062635493">"הרשאה זו מאפשרת ליישום להסיר משימות ולסגור את היישומים שבהם הן פועלות. יישומים זדוניים עלולים לשבש את פעולתם של יישומים אחרים."</string> - <!-- no translation found for permlab_manageActivityStacks (7391191384027303065) --> - <skip /> - <!-- no translation found for permdesc_manageActivityStacks (1615881933034084440) --> - <skip /> + <string name="permlab_manageActivityStacks" msgid="7391191384027303065">"ניהול של ערימות פעילות"</string> + <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"ההרשאה הזו מאפשרת לאפליקציה להוסיף, להסיר ולשנות את ערימות הפעילות שבהן רצות אפליקציות אחרות. אפליקציות זדוניות עלולת להפריע להתנהגות של אפליקציות אחרות."</string> <string name="permlab_startAnyActivity" msgid="2918768238045206456">"התחלת פעילות מכל סוג שהוא"</string> <string name="permdesc_startAnyActivity" msgid="997823695343584001">"מאפשר ליישום להתחיל בפעילות מכל סוג שהוא, ללא התחשבות בהגנת הרשאות או במצב מיוצא."</string> <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"הגדרת תאימות מסך"</string> @@ -360,14 +358,10 @@ <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"מאפשר למשתמש לבצע איגוד לממשק ברמה עליונה של שיטת קלט. הרשאה זו לעולם אינה נחוצה ליישומים רגילים."</string> <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"הכפפה לשירות נגישות"</string> <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"מתיר לבעלים להכפיף לממשק ברמה העליונה של שירות זמינות. הרשאה זו אף פעם אינה אמורה להיות נחוצה ליישומים רגילים."</string> - <!-- no translation found for permlab_bindPrintService (8462815179572748761) --> - <skip /> - <!-- no translation found for permdesc_bindPrintService (7960067623209111135) --> - <skip /> - <!-- no translation found for permlab_accessAllPrintJobs (1120792468465711159) --> - <skip /> - <!-- no translation found for permdesc_accessAllPrintJobs (2978185311041864762) --> - <skip /> + <string name="permlab_bindPrintService" msgid="8462815179572748761">"איגוד לשירות הדפסה"</string> + <string name="permdesc_bindPrintService" msgid="7960067623209111135">"ההרשאה הזו מאפשרת לבעלים לבצע איגוד לממשק הרמה העליונה של שירות הדפסה. לעולם לא אמורה להיות נחוצה עבור אפליקציות רגילות."</string> + <string name="permlab_accessAllPrintJobs" msgid="1120792468465711159">"גישה אל כל עבודות ההדפסה"</string> + <string name="permdesc_accessAllPrintJobs" msgid="2978185311041864762">"ההרשאה הזו מאפשרת לבעלים לגשת לעבודות הדפסה שנוצרו על ידי אפליקציה אחרת. לעולם לא אמורה להיות נחוצה עבור אפליקציות רגילות."</string> <string name="permlab_bindTextService" msgid="7358378401915287938">"הכפפה לשירות טקסט"</string> <string name="permdesc_bindTextService" msgid="8151968910973998670">"מאפשר למשתמש ליצור איגוד לממשק הרמה העליונה של שירות טקסט (למשל, SpellCheckerService). הרשאה זו לעולם אינה נחוצה ליישומים רגילים."</string> <string name="permlab_bindVpnService" msgid="4708596021161473255">"אגד לשירות VPN"</string> @@ -470,6 +464,8 @@ <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"מאפשר ליישום להשתמש בתכונות ברמה הנמוכה של SurfaceFlinger."</string> <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"אחסון זמני של מסגרת קריאה"</string> <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"מאפשר ליישום לקרוא את התוכן של מאגר הנתונים הזמני של המסגרות."</string> + <string name="permlab_accessInputFlinger" msgid="5348635270689553857">"גישה אל InputFlinger"</string> + <string name="permdesc_accessInputFlinger" msgid="2104864941201226616">"מאפשרת לאפליקציה להשתמש בתכונות ברמה נמוכה של InputFlinger."</string> <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"הגדר תצוגות Wi-Fi"</string> <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"מאפשר לאפליקציה להגדיר ולהתחבר לתצוגות Wi-Fi."</string> <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"שלוט בתצוגות Wi-Fi"</string> @@ -639,10 +635,14 @@ <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"מאפשר ליישום לנהל מדיניות הרשת להגדיר כללים ספציפיים-ליישום."</string> <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"שנה ניהול חשבונות של שימוש ברשת"</string> <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"הרשאה זו מאפשרת ליישום לשנות את אופן החישוב של נתוני שימוש ברשת מול כל יישום. לא מיועד לשימוש ביישומים רגילים."</string> + <string name="permlab_markNetworkSocket" msgid="3658527214914959749">"שינוי של סימני Socket"</string> + <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"ההרשאה הזו מאפשרת לאפליקציה לשנות סימני Socket עבור ניתוב"</string> <string name="permlab_accessNotifications" msgid="7673416487873432268">"גישה להתראות"</string> <string name="permdesc_accessNotifications" msgid="458457742683431387">"מאפשר ליישום לאחזר, לבדוק ולמחוק התראות, כולל כאלה שפורסמו על ידי יישומים אחרים."</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"איגוד לשירות של מאזין להתראות"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"הרשאה זו מאפשרת למשתמש לבצע איגוד לממשק הרמה העליונה של שירות מאזין להתראות. הרשאה זו אף פעם אינה נחוצה ליישומים רגילים."</string> + <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"הפעלה של אפליקציית תצורה שסופקה על ידי ספק"</string> + <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"ההרשאה הזו מאפשרת לבעלים להפעיל את אפליקציית התצורה שסופקה על ידי ספק. לעולם לא אמורה להיות נחוצה עבור אפליקציות רגילות."</string> <string name="policylab_limitPassword" msgid="4497420728857585791">"הגדר כללי סיסמה"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"שלוט באורך ובתווים המותרים בסיסמאות לביטול נעילת מסך."</string> <string name="policylab_watchLogin" msgid="914130646942199503">"עקוב אחר ניסיונות לביטול נעילת מסך"</string> @@ -752,8 +752,7 @@ <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string> <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string> <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string> - <!-- no translation found for imProtocolGoogleTalk (493902321140277304) --> - <skip /> + <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangouts"</string> <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string> <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string> <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string> @@ -1515,94 +1514,56 @@ <string name="app_no_restricted_accounts" msgid="5739463249673727736">"האפליקציה הזו לא תומכת בחשבונות עבור פרופילים מוגבלים"</string> <string name="app_not_found" msgid="3429141853498927379">"לא נמצא יישום שתומך בפעולה זו"</string> <string name="revoke" msgid="5404479185228271586">"בטל"</string> - <!-- no translation found for mediaSize_iso_a0 (7875427489420821793) --> - <skip /> - <!-- no translation found for mediaSize_iso_a1 (3760734499050875356) --> - <skip /> - <!-- no translation found for mediaSize_iso_a2 (5973266378020144382) --> - <skip /> - <!-- no translation found for mediaSize_iso_a3 (1373407105687300884) --> - <skip /> - <!-- no translation found for mediaSize_iso_a4 (6689772807982597254) --> - <skip /> - <!-- no translation found for mediaSize_iso_a5 (5353549652015741040) --> - <skip /> - <!-- no translation found for mediaSize_iso_a6 (8585038048674911907) --> - <skip /> - <!-- no translation found for mediaSize_iso_a7 (6641836716963839119) --> - <skip /> - <!-- no translation found for mediaSize_iso_a8 (7571139437465693355) --> - <skip /> - <!-- no translation found for mediaSize_iso_a9 (1378455891957115079) --> - <skip /> - <!-- no translation found for mediaSize_iso_a10 (2480747457429475344) --> - <skip /> - <!-- no translation found for mediaSize_iso_b0 (3965935097661108039) --> - <skip /> - <!-- no translation found for mediaSize_iso_b1 (2505753285010115437) --> - <skip /> - <!-- no translation found for mediaSize_iso_b2 (8763874709859458453) --> - <skip /> - <!-- no translation found for mediaSize_iso_b3 (4210506688191764076) --> - <skip /> - <!-- no translation found for mediaSize_iso_b4 (5749404165888526034) --> - <skip /> - <!-- no translation found for mediaSize_iso_b5 (7640627414621904733) --> - <skip /> - <!-- no translation found for mediaSize_iso_b6 (7342988864712748544) --> - <skip /> - <!-- no translation found for mediaSize_iso_b7 (5069844065235382429) --> - <skip /> - <!-- no translation found for mediaSize_iso_b8 (7316818922278779774) --> - <skip /> - <!-- no translation found for mediaSize_iso_b9 (5414727094026532341) --> - <skip /> - <!-- no translation found for mediaSize_iso_b10 (5251253731832048185) --> - <skip /> - <!-- no translation found for mediaSize_iso_c0 (4003138342671964217) --> - <skip /> - <!-- no translation found for mediaSize_iso_c1 (1935188063393553008) --> - <skip /> - <!-- no translation found for mediaSize_iso_c2 (3197307969712069904) --> - <skip /> - <!-- no translation found for mediaSize_iso_c3 (4335826087321913508) --> - <skip /> - <!-- no translation found for mediaSize_iso_c4 (3745639598281015005) --> - <skip /> - <!-- no translation found for mediaSize_iso_c5 (8269457765822791013) --> - <skip /> - <!-- no translation found for mediaSize_iso_c6 (566666105260346930) --> - <skip /> - <!-- no translation found for mediaSize_iso_c7 (8678413180782608498) --> - <skip /> - <!-- no translation found for mediaSize_iso_c8 (8392376206627041730) --> - <skip /> - <!-- no translation found for mediaSize_iso_c9 (9191613372324845405) --> - <skip /> - <!-- no translation found for mediaSize_iso_c10 (7327709699184920822) --> - <skip /> - <!-- no translation found for mediaSize_na_letter (4191805615829472953) --> - <skip /> - <!-- no translation found for mediaSize_na_gvrnmt_letter (7853382192649405507) --> - <skip /> - <!-- no translation found for mediaSize_na_legal (6697982988283823150) --> - <skip /> - <!-- no translation found for mediaSize_na_junior_legal (3727743969902758948) --> - <skip /> - <!-- no translation found for mediaSize_na_ledger (281871464896601236) --> - <skip /> - <!-- no translation found for mediaSize_na_tabloid (5775966416333578127) --> - <skip /> - <!-- no translation found for restr_pin_create_pin (8017600000263450337) --> - <skip /> - <!-- no translation found for restr_pin_enter_pin (3395953421368476103) --> - <skip /> - <!-- no translation found for restr_pin_confirm_pin (2891475237150965991) --> - <skip /> - <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) --> - <skip /> - <!-- no translation found for restr_pin_error_too_short (8173982756265777792) --> - <skip /> - <!-- no translation found for restr_pin_countdown:one (4835639969503729874) --> - <!-- no translation found for restr_pin_countdown:other (8030607343223287654) --> + <string name="mediaSize_iso_a0" msgid="7875427489420821793">"ISO A0"</string> + <string name="mediaSize_iso_a1" msgid="3760734499050875356">"ISO A1"</string> + <string name="mediaSize_iso_a2" msgid="5973266378020144382">"ISO A2"</string> + <string name="mediaSize_iso_a3" msgid="1373407105687300884">"ISO A3"</string> + <string name="mediaSize_iso_a4" msgid="6689772807982597254">"ISO A4"</string> + <string name="mediaSize_iso_a5" msgid="5353549652015741040">"ISO A5"</string> + <string name="mediaSize_iso_a6" msgid="8585038048674911907">"ISO A6"</string> + <string name="mediaSize_iso_a7" msgid="6641836716963839119">"ISO A7"</string> + <string name="mediaSize_iso_a8" msgid="7571139437465693355">"ISO A8"</string> + <string name="mediaSize_iso_a9" msgid="1378455891957115079">"ISO A9"</string> + <string name="mediaSize_iso_a10" msgid="2480747457429475344">"ISO A10"</string> + <string name="mediaSize_iso_b0" msgid="3965935097661108039">"ISO B0"</string> + <string name="mediaSize_iso_b1" msgid="2505753285010115437">"ISO B1"</string> + <string name="mediaSize_iso_b2" msgid="8763874709859458453">"ISO B2"</string> + <string name="mediaSize_iso_b3" msgid="4210506688191764076">"ISO B3"</string> + <string name="mediaSize_iso_b4" msgid="5749404165888526034">"ISO B4"</string> + <string name="mediaSize_iso_b5" msgid="7640627414621904733">"ISO B5"</string> + <string name="mediaSize_iso_b6" msgid="7342988864712748544">"ISO B6"</string> + <string name="mediaSize_iso_b7" msgid="5069844065235382429">"ISO B7"</string> + <string name="mediaSize_iso_b8" msgid="7316818922278779774">"ISO B8"</string> + <string name="mediaSize_iso_b9" msgid="5414727094026532341">"ISO B9"</string> + <string name="mediaSize_iso_b10" msgid="5251253731832048185">"ISO B10"</string> + <string name="mediaSize_iso_c0" msgid="4003138342671964217">"ISO C0"</string> + <string name="mediaSize_iso_c1" msgid="1935188063393553008">"ISO C1"</string> + <string name="mediaSize_iso_c2" msgid="3197307969712069904">"ISO C2"</string> + <string name="mediaSize_iso_c3" msgid="4335826087321913508">"ISO C3"</string> + <string name="mediaSize_iso_c4" msgid="3745639598281015005">"ISO C4"</string> + <string name="mediaSize_iso_c5" msgid="8269457765822791013">"ISO C5"</string> + <string name="mediaSize_iso_c6" msgid="566666105260346930">"ISO C6"</string> + <string name="mediaSize_iso_c7" msgid="8678413180782608498">"ISO C7"</string> + <string name="mediaSize_iso_c8" msgid="8392376206627041730">"ISO C8"</string> + <string name="mediaSize_iso_c9" msgid="9191613372324845405">"ISO C9"</string> + <string name="mediaSize_iso_c10" msgid="7327709699184920822">"ISO C10"</string> + <string name="mediaSize_na_letter" msgid="4191805615829472953">"Letter"</string> + <string name="mediaSize_na_gvrnmt_letter" msgid="7853382192649405507">"Government Letter"</string> + <string name="mediaSize_na_legal" msgid="6697982988283823150">"Legal"</string> + <string name="mediaSize_na_junior_legal" msgid="3727743969902758948">"Junior Legal"</string> + <string name="mediaSize_na_ledger" msgid="281871464896601236">"Ledger"</string> + <string name="mediaSize_na_tabloid" msgid="5775966416333578127">"Tabloid"</string> + <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"בוטלה"</string> + <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"שגיאה בכתיבת תוכן"</string> + <string name="restr_pin_enter_pin" msgid="3395953421368476103">"הזן מספר PIN"</string> + <string name="restr_pin_enter_old_pin" msgid="1462206225512910757">"מספר PIN נוכחי"</string> + <string name="restr_pin_enter_new_pin" msgid="5959606691619959184">"מספר PIN חדש"</string> + <string name="restr_pin_confirm_pin" msgid="8501523829633146239">"אשר את מספר ה-PIN החדש"</string> + <string name="restr_pin_create_pin" msgid="8017600000263450337">"צור מספר PIN לשינוי הגבלות"</string> + <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"מספרי ה-PIN לא תואמים. נסה שוב."</string> + <string name="restr_pin_error_too_short" msgid="8173982756265777792">"מספר ה-PIN קצר מדי. חייב להיות באורך 4 ספרות לפחות."</string> + <plurals name="restr_pin_countdown"> + <item quantity="one" msgid="4835639969503729874">"מספר PIN שגוי. נסה שוב בעוד שניה."</item> + <item quantity="other" msgid="8030607343223287654">"מספר PIN שגוי. נסה שוב בעוד <xliff:g id="COUNT">%d</xliff:g> שניות."</item> + </plurals> </resources> diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml index eb1556d..9ed6742 100644 --- a/core/res/res/values-ja/strings.xml +++ b/core/res/res/values-ja/strings.xml @@ -470,6 +470,10 @@ <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"SurfaceFlingerの低レベルの機能の使用をアプリに許可します。"</string> <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"フレームバッファの読み取り"</string> <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"フレームバッファの内容の読み取りをアプリに許可します。"</string> + <!-- no translation found for permlab_accessInputFlinger (5348635270689553857) --> + <skip /> + <!-- no translation found for permdesc_accessInputFlinger (2104864941201226616) --> + <skip /> <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"Wi-Fiディスプレイの設定"</string> <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Wi-Fiディスプレイを設定して接続することをアプリに許可します。"</string> <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"Wi-Fiディスプレイの制御"</string> @@ -639,10 +643,18 @@ <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"ネットワークポリシーを管理しアプリ固有のルールを定義することをアプリに許可します。"</string> <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"ネットワークの課金の変更"</string> <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"アプリに対するネットワーク利用の計算方法を変更することをアプリに許可します。通常のアプリでは使用しません。"</string> + <!-- no translation found for permlab_markNetworkSocket (3658527214914959749) --> + <skip /> + <!-- no translation found for permdesc_markNetworkSocket (7655568433696356578) --> + <skip /> <string name="permlab_accessNotifications" msgid="7673416487873432268">"通知にアクセス"</string> <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_invokeCarrierSetup (3699600833975117478) --> + <skip /> + <!-- no translation found for permdesc_invokeCarrierSetup (4159549152529111920) --> + <skip /> <string name="policylab_limitPassword" msgid="4497420728857585791">"パスワードルールの設定"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"画面ロック解除パスワードの長さと使用できる文字を制御します。"</string> <string name="policylab_watchLogin" msgid="914130646942199503">"画面ロック解除試行の監視"</string> @@ -1593,11 +1605,19 @@ <skip /> <!-- no translation found for mediaSize_na_tabloid (5775966416333578127) --> <skip /> - <!-- no translation found for restr_pin_create_pin (8017600000263450337) --> + <!-- no translation found for write_fail_reason_cancelled (7091258378121627624) --> + <skip /> + <!-- no translation found for write_fail_reason_cannot_write (8132505417935337724) --> <skip /> <!-- no translation found for restr_pin_enter_pin (3395953421368476103) --> <skip /> - <!-- no translation found for restr_pin_confirm_pin (2891475237150965991) --> + <!-- no translation found for restr_pin_enter_old_pin (1462206225512910757) --> + <skip /> + <!-- no translation found for restr_pin_enter_new_pin (5959606691619959184) --> + <skip /> + <!-- no translation found for restr_pin_confirm_pin (8501523829633146239) --> + <skip /> + <!-- no translation found for restr_pin_create_pin (8017600000263450337) --> <skip /> <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) --> <skip /> diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml index 8cd152d..0375383 100644 --- a/core/res/res/values-ko/strings.xml +++ b/core/res/res/values-ko/strings.xml @@ -470,6 +470,10 @@ <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"앱이 SurfaceFlinger의 하위 수준 기능을 사용할 수 있도록 허용합니다."</string> <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"프레임 버퍼 읽기"</string> <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"앱이 프레임 버퍼의 내용을 읽을 수 있도록 허용합니다."</string> + <!-- no translation found for permlab_accessInputFlinger (5348635270689553857) --> + <skip /> + <!-- no translation found for permdesc_accessInputFlinger (2104864941201226616) --> + <skip /> <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"Wi-Fi 디스플레이 설정"</string> <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"앱이 Wi-Fi 디스플레이를 설정하고 연결하도록 허용합니다."</string> <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"Wi-Fi 디스플레이 제어"</string> @@ -639,10 +643,18 @@ <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"앱이 네트워크 정책을 관리하고 앱별 규칙을 정의할 수 있도록 허용합니다."</string> <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"네트워크 사용량 계산 수정"</string> <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"애플리케이션이 애플리케이션의 네트워크 사용량을 계산하는 방식을 수정할 수 있도록 허용합니다. 일반 애플리케이션에서는 사용하지 않습니다."</string> + <!-- no translation found for permlab_markNetworkSocket (3658527214914959749) --> + <skip /> + <!-- no translation found for permdesc_markNetworkSocket (7655568433696356578) --> + <skip /> <string name="permlab_accessNotifications" msgid="7673416487873432268">"알림 액세스"</string> <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_invokeCarrierSetup (3699600833975117478) --> + <skip /> + <!-- no translation found for permdesc_invokeCarrierSetup (4159549152529111920) --> + <skip /> <string name="policylab_limitPassword" msgid="4497420728857585791">"비밀번호 규칙 설정"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"화면 잠금해제 비밀번호에 허용되는 길이 및 문자 수를 제어합니다."</string> <string name="policylab_watchLogin" msgid="914130646942199503">"화면 잠금해제 시도 모니터링"</string> @@ -1593,11 +1605,19 @@ <skip /> <!-- no translation found for mediaSize_na_tabloid (5775966416333578127) --> <skip /> - <!-- no translation found for restr_pin_create_pin (8017600000263450337) --> + <!-- no translation found for write_fail_reason_cancelled (7091258378121627624) --> + <skip /> + <!-- no translation found for write_fail_reason_cannot_write (8132505417935337724) --> <skip /> <!-- no translation found for restr_pin_enter_pin (3395953421368476103) --> <skip /> - <!-- no translation found for restr_pin_confirm_pin (2891475237150965991) --> + <!-- no translation found for restr_pin_enter_old_pin (1462206225512910757) --> + <skip /> + <!-- no translation found for restr_pin_enter_new_pin (5959606691619959184) --> + <skip /> + <!-- no translation found for restr_pin_confirm_pin (8501523829633146239) --> + <skip /> + <!-- no translation found for restr_pin_create_pin (8017600000263450337) --> <skip /> <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) --> <skip /> diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml index ea10f2f..26d0cc7 100644 --- a/core/res/res/values-lt/strings.xml +++ b/core/res/res/values-lt/strings.xml @@ -470,6 +470,10 @@ <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Leidžiama programai naudoti „SurfaceFlinger“ žemo lygio funkcijas."</string> <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"skaityti kadrų buferį"</string> <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Leidžiama programai skaityti rėmelio buferio turinį."</string> + <!-- no translation found for permlab_accessInputFlinger (5348635270689553857) --> + <skip /> + <!-- no translation found for permdesc_accessInputFlinger (2104864941201226616) --> + <skip /> <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"konfigūruoti „Wi-Fi“ pateiktis"</string> <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Leidžiama programai konfigūruoti ir prisijungti prie „Wi-Fi“ pateikčių."</string> <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"valdyti „Wi-Fi“ pateiktis"</string> @@ -639,10 +643,18 @@ <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Leidžiama programai valdyti tinklo politiką ir apibrėžti konkrečios programos taisykles."</string> <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"keisti tinklo naudojimo apskaitą"</string> <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Leidžiama programai keisti, kaip tinklas naudojamas, palyginti su programomis. Neskirta naudoti įprastoms programoms."</string> + <!-- no translation found for permlab_markNetworkSocket (3658527214914959749) --> + <skip /> + <!-- no translation found for permdesc_markNetworkSocket (7655568433696356578) --> + <skip /> <string name="permlab_accessNotifications" msgid="7673416487873432268">"pasiekti pranešimus"</string> <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> + <!-- no translation found for permlab_invokeCarrierSetup (3699600833975117478) --> + <skip /> + <!-- no translation found for permdesc_invokeCarrierSetup (4159549152529111920) --> + <skip /> <string name="policylab_limitPassword" msgid="4497420728857585791">"Nustatyti slaptažodžio taisykles"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"Valdyti leidžiamą ekrano atrakinimo slaptažodžių ilgį ir leidžiamus naudoti simbolius."</string> <string name="policylab_watchLogin" msgid="914130646942199503">"Stebėti bandymus atrakinti ekraną"</string> @@ -1593,11 +1605,19 @@ <skip /> <!-- no translation found for mediaSize_na_tabloid (5775966416333578127) --> <skip /> - <!-- no translation found for restr_pin_create_pin (8017600000263450337) --> + <!-- no translation found for write_fail_reason_cancelled (7091258378121627624) --> + <skip /> + <!-- no translation found for write_fail_reason_cannot_write (8132505417935337724) --> <skip /> <!-- no translation found for restr_pin_enter_pin (3395953421368476103) --> <skip /> - <!-- no translation found for restr_pin_confirm_pin (2891475237150965991) --> + <!-- no translation found for restr_pin_enter_old_pin (1462206225512910757) --> + <skip /> + <!-- no translation found for restr_pin_enter_new_pin (5959606691619959184) --> + <skip /> + <!-- no translation found for restr_pin_confirm_pin (8501523829633146239) --> + <skip /> + <!-- no translation found for restr_pin_create_pin (8017600000263450337) --> <skip /> <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) --> <skip /> diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml index 3e3ab2c..aa7634e 100644 --- a/core/res/res/values-lv/strings.xml +++ b/core/res/res/values-lv/strings.xml @@ -470,6 +470,10 @@ <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Ļauj lietotnei lietot SurfaceFlinger zema līmeņa funkcijas."</string> <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"lasīt kadru buferi"</string> <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Ļauj lietotnei lasīt kadru bufera saturu."</string> + <!-- no translation found for permlab_accessInputFlinger (5348635270689553857) --> + <skip /> + <!-- no translation found for permdesc_accessInputFlinger (2104864941201226616) --> + <skip /> <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"Wi-Fi displeju konfigurēšana"</string> <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Ļauj lietotnei konfigurēt Wi-Fi displejus un veidot savienojumu ar tiem."</string> <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"Wi-Fi displeju vadība"</string> @@ -639,10 +643,18 @@ <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Ļauj lietotnei pārvaldīt tīkla politikas un noteikt lietotnes kārtulas."</string> <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"Tīkla lietojuma uzskaites mainīšana"</string> <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Ļauj lietotnei mainīt to, kā tīkla lietojums tiek uzskaitīts saistībā ar lietotnēm. Atļauja neattiecas uz parastām lietotnēm."</string> + <!-- no translation found for permlab_markNetworkSocket (3658527214914959749) --> + <skip /> + <!-- no translation found for permdesc_markNetworkSocket (7655568433696356578) --> + <skip /> <string name="permlab_accessNotifications" msgid="7673416487873432268">"piekļuve paziņojumiem"</string> <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> + <!-- no translation found for permlab_invokeCarrierSetup (3699600833975117478) --> + <skip /> + <!-- no translation found for permdesc_invokeCarrierSetup (4159549152529111920) --> + <skip /> <string name="policylab_limitPassword" msgid="4497420728857585791">"Paroles kārtulu iestatīšana"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"Kontrolē ekrāna atbloķēšanas parolē atļautās rakstzīmes un garumu."</string> <string name="policylab_watchLogin" msgid="914130646942199503">"Ekrāna atbloķēšanas mēģinājumu pārraudzīšana"</string> @@ -1593,11 +1605,19 @@ <skip /> <!-- no translation found for mediaSize_na_tabloid (5775966416333578127) --> <skip /> - <!-- no translation found for restr_pin_create_pin (8017600000263450337) --> + <!-- no translation found for write_fail_reason_cancelled (7091258378121627624) --> + <skip /> + <!-- no translation found for write_fail_reason_cannot_write (8132505417935337724) --> <skip /> <!-- no translation found for restr_pin_enter_pin (3395953421368476103) --> <skip /> - <!-- no translation found for restr_pin_confirm_pin (2891475237150965991) --> + <!-- no translation found for restr_pin_enter_old_pin (1462206225512910757) --> + <skip /> + <!-- no translation found for restr_pin_enter_new_pin (5959606691619959184) --> + <skip /> + <!-- no translation found for restr_pin_confirm_pin (8501523829633146239) --> + <skip /> + <!-- no translation found for restr_pin_create_pin (8017600000263450337) --> <skip /> <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) --> <skip /> diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml index 9260061..4602922 100644 --- a/core/res/res/values-ms/strings.xml +++ b/core/res/res/values-ms/strings.xml @@ -470,6 +470,10 @@ <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Membenarkan apl menggunakan ciri peringkat rendah SurfaceFlinger."</string> <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"baca penimbal bingkai"</string> <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Membenarkan apl membaca kandungan penimbal bingkai."</string> + <!-- no translation found for permlab_accessInputFlinger (5348635270689553857) --> + <skip /> + <!-- no translation found for permdesc_accessInputFlinger (2104864941201226616) --> + <skip /> <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"konfigurasikan paparan Wifi"</string> <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Membenarkan apl mengkonfigurasi dan menyambung ke paparan Wifi."</string> <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"kawal paparan Wifi"</string> @@ -639,10 +643,18 @@ <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Membenarkan apl mengurus dasar rangkaian dan menentukan peraturan khusus apl."</string> <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"ubah suai perakaunan penggunaan rangkaian"</string> <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Membenarkan apl untuk mengubah suai bagaimana penggunaan rangkaian diambil kira terhadap apl. Bukan untuk digunakan oleh apl biasa."</string> + <!-- no translation found for permlab_markNetworkSocket (3658527214914959749) --> + <skip /> + <!-- no translation found for permdesc_markNetworkSocket (7655568433696356578) --> + <skip /> <string name="permlab_accessNotifications" msgid="7673416487873432268">"pemberitahuan akses"</string> <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> + <!-- no translation found for permlab_invokeCarrierSetup (3699600833975117478) --> + <skip /> + <!-- no translation found for permdesc_invokeCarrierSetup (4159549152529111920) --> + <skip /> <string name="policylab_limitPassword" msgid="4497420728857585791">"Tetapkan peraturan kata laluan"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"Mengawal panjang dan aksara yang dibenarkan dalam kata laluan buka kunci skrin."</string> <string name="policylab_watchLogin" msgid="914130646942199503">"Memantau percubaan buka kunci skrin"</string> @@ -1593,11 +1605,19 @@ <skip /> <!-- no translation found for mediaSize_na_tabloid (5775966416333578127) --> <skip /> - <!-- no translation found for restr_pin_create_pin (8017600000263450337) --> + <!-- no translation found for write_fail_reason_cancelled (7091258378121627624) --> + <skip /> + <!-- no translation found for write_fail_reason_cannot_write (8132505417935337724) --> <skip /> <!-- no translation found for restr_pin_enter_pin (3395953421368476103) --> <skip /> - <!-- no translation found for restr_pin_confirm_pin (2891475237150965991) --> + <!-- no translation found for restr_pin_enter_old_pin (1462206225512910757) --> + <skip /> + <!-- no translation found for restr_pin_enter_new_pin (5959606691619959184) --> + <skip /> + <!-- no translation found for restr_pin_confirm_pin (8501523829633146239) --> + <skip /> + <!-- no translation found for restr_pin_create_pin (8017600000263450337) --> <skip /> <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) --> <skip /> diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml index b998377..cab4cb1 100644 --- a/core/res/res/values-nb/strings.xml +++ b/core/res/res/values-nb/strings.xml @@ -279,10 +279,8 @@ <string name="permdesc_reorderTasks" msgid="7734217754877439351">"Lar appen flytte oppgaver til forgrunnen eller bakgrunnen. Appen kan gjøre dette uten instruksjoner fra deg."</string> <string name="permlab_removeTasks" msgid="6821513401870377403">"avslutte apper som kjører"</string> <string name="permdesc_removeTasks" msgid="1394714352062635493">"Lar appen fjerne oppgaver og avslutte apper. Ondsinnede apper kan forstyrre atferden til andre apper."</string> - <!-- no translation found for permlab_manageActivityStacks (7391191384027303065) --> - <skip /> - <!-- no translation found for permdesc_manageActivityStacks (1615881933034084440) --> - <skip /> + <string name="permlab_manageActivityStacks" msgid="7391191384027303065">"administrering av aktivitetsstabler"</string> + <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"Gir appen tillatelse til å legge til, fjerne og endre aktivitetsstablene som andre apper kjøres i. Skadelige apper kan skape problemer i atferden til andre apper."</string> <string name="permlab_startAnyActivity" msgid="2918768238045206456">"igangsetting av aktiviteter"</string> <string name="permdesc_startAnyActivity" msgid="997823695343584001">"Tillater at appen kan starte en aktivitet, uavhengig av tillatelsesbeskyttelse og eksportstatus."</string> <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"angi skjermkompatibilitet"</string> @@ -360,14 +358,10 @@ <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Lar innehaveren binde det øverste nivået av grensesnittet til en inndatametode. Skal aldri være nødvendig for normale apper."</string> <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"binde seg til en tilgjengelighetstjeneste"</string> <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Gir innehaveren tillatelse til å bindes til det øverste nivået av grensesnittet for en tilgjengelighetstjeneste. Skal aldri være nødvendig for vanlige apper."</string> - <!-- no translation found for permlab_bindPrintService (8462815179572748761) --> - <skip /> - <!-- no translation found for permdesc_bindPrintService (7960067623209111135) --> - <skip /> - <!-- no translation found for permlab_accessAllPrintJobs (1120792468465711159) --> - <skip /> - <!-- no translation found for permdesc_accessAllPrintJobs (2978185311041864762) --> - <skip /> + <string name="permlab_bindPrintService" msgid="8462815179572748761">"binding til en utskriftstjeneste"</string> + <string name="permdesc_bindPrintService" msgid="7960067623209111135">"Gir innehaveren tillatelse til å binde til toppnivået av brukergrensesnittet for en utskriftstjeneste. Dette skal ikke være nødvendig for vanlige apper."</string> + <string name="permlab_accessAllPrintJobs" msgid="1120792468465711159">"tilgang til alle utskriftsjobber"</string> + <string name="permdesc_accessAllPrintJobs" msgid="2978185311041864762">"Gir innehaveren tillatelse til å åpne utskriftsjobber som ble opprettet av andre apper. Dette skal ikke være nødvendig for vanlige apper."</string> <string name="permlab_bindTextService" msgid="7358378401915287938">"binde til en teksttjeneste"</string> <string name="permdesc_bindTextService" msgid="8151968910973998670">"Lar innehaveren binde seg til øverste grensesnittnivå for en teksttjeneste (f.eks. SpellCheckerService). Skal aldri være nødvendig for vanlige apper."</string> <string name="permlab_bindVpnService" msgid="4708596021161473255">"binde deg til en VPN-tjeneste"</string> @@ -470,6 +464,8 @@ <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Lar appen bruke grunnleggende SurfaceFlinger-funksjoner."</string> <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"lese skjermbufferet"</string> <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Lar appen lese innholdet i rammebufferen."</string> + <string name="permlab_accessInputFlinger" msgid="5348635270689553857">"tilgang til InputFlinger"</string> + <string name="permdesc_accessInputFlinger" msgid="2104864941201226616">"Lar appen bruke grunnleggende InputFlinger-funksjoner."</string> <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"konfigurere Wi-Fi-skjermer"</string> <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Tillater appen å konfigurere og koble til Wi-Fi-skjermer."</string> <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"kontrollere Wi-Fi-skjermer"</string> @@ -639,10 +635,14 @@ <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Lar appen administrere retningslinjene for nettverket og definere appspesifikke regler."</string> <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"Modifisering av regnskapsføring av nettverksbruk"</string> <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Lar appen endre hvordan nettverksbruk regnes ut for apper. Ikke beregnet på vanlige apper."</string> + <string name="permlab_markNetworkSocket" msgid="3658527214914959749">"endring av kontaktmerker"</string> + <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"Gir appen tillatelse til å endre kontaktmerker for ruting"</string> <string name="permlab_accessNotifications" msgid="7673416487873432268">"varseltilgang"</string> <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_invokeCarrierSetup" msgid="3699600833975117478">"anrop av konfigurasjonsappen som ble levert av operatøren"</string> + <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Gir innehaveren tillatelse til å kalle opp den konfigurasjonsappen som ble levert av operatøren. Dette skal ikke være nødvendig for vanlige apper."</string> <string name="policylab_limitPassword" msgid="4497420728857585791">"Angi passordregler"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"Kontroller tillatt lengde og tillatte tegn i passord for opplåsing av skjerm."</string> <string name="policylab_watchLogin" msgid="914130646942199503">"Overvåk forsøk på opplåsing av skjerm"</string> @@ -752,8 +752,7 @@ <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string> <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string> <string name="imProtocolQq" msgid="8887484379494111884">"OQ"</string> - <!-- no translation found for imProtocolGoogleTalk (493902321140277304) --> - <skip /> + <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangouts"</string> <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string> <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string> <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string> @@ -1515,94 +1514,59 @@ <string name="app_no_restricted_accounts" msgid="5739463249673727736">"Denne appen støtter ikke kontoer for begrensede profiler"</string> <string name="app_not_found" msgid="3429141853498927379">"Finner ingen apper som kan utføre denne handlingen"</string> <string name="revoke" msgid="5404479185228271586">"Opphev"</string> - <!-- no translation found for mediaSize_iso_a0 (7875427489420821793) --> - <skip /> - <!-- no translation found for mediaSize_iso_a1 (3760734499050875356) --> - <skip /> - <!-- no translation found for mediaSize_iso_a2 (5973266378020144382) --> - <skip /> - <!-- no translation found for mediaSize_iso_a3 (1373407105687300884) --> - <skip /> - <!-- no translation found for mediaSize_iso_a4 (6689772807982597254) --> - <skip /> - <!-- no translation found for mediaSize_iso_a5 (5353549652015741040) --> - <skip /> - <!-- no translation found for mediaSize_iso_a6 (8585038048674911907) --> - <skip /> - <!-- no translation found for mediaSize_iso_a7 (6641836716963839119) --> - <skip /> - <!-- no translation found for mediaSize_iso_a8 (7571139437465693355) --> - <skip /> - <!-- no translation found for mediaSize_iso_a9 (1378455891957115079) --> - <skip /> - <!-- no translation found for mediaSize_iso_a10 (2480747457429475344) --> - <skip /> - <!-- no translation found for mediaSize_iso_b0 (3965935097661108039) --> - <skip /> - <!-- no translation found for mediaSize_iso_b1 (2505753285010115437) --> - <skip /> - <!-- no translation found for mediaSize_iso_b2 (8763874709859458453) --> - <skip /> - <!-- no translation found for mediaSize_iso_b3 (4210506688191764076) --> - <skip /> - <!-- no translation found for mediaSize_iso_b4 (5749404165888526034) --> - <skip /> - <!-- no translation found for mediaSize_iso_b5 (7640627414621904733) --> - <skip /> - <!-- no translation found for mediaSize_iso_b6 (7342988864712748544) --> - <skip /> - <!-- no translation found for mediaSize_iso_b7 (5069844065235382429) --> + <string name="mediaSize_iso_a0" msgid="7875427489420821793">"ISO A0"</string> + <string name="mediaSize_iso_a1" msgid="3760734499050875356">"ISO A1"</string> + <string name="mediaSize_iso_a2" msgid="5973266378020144382">"ISO A2"</string> + <string name="mediaSize_iso_a3" msgid="1373407105687300884">"ISO A3"</string> + <string name="mediaSize_iso_a4" msgid="6689772807982597254">"ISO A4"</string> + <string name="mediaSize_iso_a5" msgid="5353549652015741040">"ISO A5"</string> + <string name="mediaSize_iso_a6" msgid="8585038048674911907">"ISO A6"</string> + <string name="mediaSize_iso_a7" msgid="6641836716963839119">"ISO A7"</string> + <string name="mediaSize_iso_a8" msgid="7571139437465693355">"ISO A8"</string> + <string name="mediaSize_iso_a9" msgid="1378455891957115079">"ISO A9"</string> + <string name="mediaSize_iso_a10" msgid="2480747457429475344">"ISO A10"</string> + <string name="mediaSize_iso_b0" msgid="3965935097661108039">"ISO B0"</string> + <string name="mediaSize_iso_b1" msgid="2505753285010115437">"ISO B1"</string> + <string name="mediaSize_iso_b2" msgid="8763874709859458453">"ISO B2"</string> + <string name="mediaSize_iso_b3" msgid="4210506688191764076">"ISO B3"</string> + <string name="mediaSize_iso_b4" msgid="5749404165888526034">"ISO B4"</string> + <string name="mediaSize_iso_b5" msgid="7640627414621904733">"ISO B5"</string> + <string name="mediaSize_iso_b6" msgid="7342988864712748544">"ISO B6"</string> + <string name="mediaSize_iso_b7" msgid="5069844065235382429">"ISO B7"</string> + <string name="mediaSize_iso_b8" msgid="7316818922278779774">"ISO B8"</string> + <string name="mediaSize_iso_b9" msgid="5414727094026532341">"ISO B9"</string> + <string name="mediaSize_iso_b10" msgid="5251253731832048185">"ISO B10"</string> + <string name="mediaSize_iso_c0" msgid="4003138342671964217">"ISO C0"</string> + <string name="mediaSize_iso_c1" msgid="1935188063393553008">"ISO C1"</string> + <string name="mediaSize_iso_c2" msgid="3197307969712069904">"ISO C2"</string> + <string name="mediaSize_iso_c3" msgid="4335826087321913508">"ISO C3"</string> + <string name="mediaSize_iso_c4" msgid="3745639598281015005">"ISO C4"</string> + <string name="mediaSize_iso_c5" msgid="8269457765822791013">"ISO C5"</string> + <string name="mediaSize_iso_c6" msgid="566666105260346930">"ISO C6"</string> + <string name="mediaSize_iso_c7" msgid="8678413180782608498">"ISO C7"</string> + <string name="mediaSize_iso_c8" msgid="8392376206627041730">"ISO C8"</string> + <string name="mediaSize_iso_c9" msgid="9191613372324845405">"ISO C9"</string> + <string name="mediaSize_iso_c10" msgid="7327709699184920822">"ISO C10"</string> + <string name="mediaSize_na_letter" msgid="4191805615829472953">"Letter"</string> + <string name="mediaSize_na_gvrnmt_letter" msgid="7853382192649405507">"Government Letter"</string> + <string name="mediaSize_na_legal" msgid="6697982988283823150">"Legal"</string> + <string name="mediaSize_na_junior_legal" msgid="3727743969902758948">"Junior Legal (Nord-Amerika)"</string> + <string name="mediaSize_na_ledger" msgid="281871464896601236">"Ledger"</string> + <string name="mediaSize_na_tabloid" msgid="5775966416333578127">"Tabloid"</string> + <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"Kansellert"</string> + <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"Feil under skriving av innhold"</string> + <string name="restr_pin_enter_pin" msgid="3395953421368476103">"Skriv inn PIN-koden"</string> + <!-- no translation found for restr_pin_enter_old_pin (1462206225512910757) --> <skip /> - <!-- no translation found for mediaSize_iso_b8 (7316818922278779774) --> + <!-- no translation found for restr_pin_enter_new_pin (5959606691619959184) --> <skip /> - <!-- no translation found for mediaSize_iso_b9 (5414727094026532341) --> + <!-- no translation found for restr_pin_confirm_pin (8501523829633146239) --> <skip /> - <!-- no translation found for mediaSize_iso_b10 (5251253731832048185) --> - <skip /> - <!-- no translation found for mediaSize_iso_c0 (4003138342671964217) --> - <skip /> - <!-- no translation found for mediaSize_iso_c1 (1935188063393553008) --> - <skip /> - <!-- no translation found for mediaSize_iso_c2 (3197307969712069904) --> - <skip /> - <!-- no translation found for mediaSize_iso_c3 (4335826087321913508) --> - <skip /> - <!-- no translation found for mediaSize_iso_c4 (3745639598281015005) --> - <skip /> - <!-- no translation found for mediaSize_iso_c5 (8269457765822791013) --> - <skip /> - <!-- no translation found for mediaSize_iso_c6 (566666105260346930) --> - <skip /> - <!-- no translation found for mediaSize_iso_c7 (8678413180782608498) --> - <skip /> - <!-- no translation found for mediaSize_iso_c8 (8392376206627041730) --> - <skip /> - <!-- no translation found for mediaSize_iso_c9 (9191613372324845405) --> - <skip /> - <!-- no translation found for mediaSize_iso_c10 (7327709699184920822) --> - <skip /> - <!-- no translation found for mediaSize_na_letter (4191805615829472953) --> - <skip /> - <!-- no translation found for mediaSize_na_gvrnmt_letter (7853382192649405507) --> - <skip /> - <!-- no translation found for mediaSize_na_legal (6697982988283823150) --> - <skip /> - <!-- no translation found for mediaSize_na_junior_legal (3727743969902758948) --> - <skip /> - <!-- no translation found for mediaSize_na_ledger (281871464896601236) --> - <skip /> - <!-- no translation found for mediaSize_na_tabloid (5775966416333578127) --> - <skip /> - <!-- no translation found for restr_pin_create_pin (8017600000263450337) --> - <skip /> - <!-- no translation found for restr_pin_enter_pin (3395953421368476103) --> - <skip /> - <!-- no translation found for restr_pin_confirm_pin (2891475237150965991) --> - <skip /> - <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) --> - <skip /> - <!-- no translation found for restr_pin_error_too_short (8173982756265777792) --> - <skip /> - <!-- no translation found for restr_pin_countdown:one (4835639969503729874) --> - <!-- no translation found for restr_pin_countdown:other (8030607343223287654) --> + <string name="restr_pin_create_pin" msgid="8017600000263450337">"Angi en PIN-kode for endring av begresninger"</string> + <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PIN-kodene stemmer ikke overens. Prøv på nytt."</string> + <string name="restr_pin_error_too_short" msgid="8173982756265777792">"PIN-koden er for kort. Den må bestå av minst fire tegn."</string> + <plurals name="restr_pin_countdown"> + <item quantity="one" msgid="4835639969503729874">"Feil PIN-kode. Prøv på nytt om 1 sekund."</item> + <item quantity="other" msgid="8030607343223287654">"Feil PIN-kode. Prøv på nytt om <xliff:g id="COUNT">%d</xliff:g> sekunder."</item> + </plurals> </resources> diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml index af72700..b3fef17 100644 --- a/core/res/res/values-nl/strings.xml +++ b/core/res/res/values-nl/strings.xml @@ -279,10 +279,8 @@ <string name="permdesc_reorderTasks" msgid="7734217754877439351">"Hiermee kan de app taken naar de voor- en achtergrond verplaatsen. De app kan dit doen zonder om uw bevestiging te vragen."</string> <string name="permlab_removeTasks" msgid="6821513401870377403">"actieve apps stoppen"</string> <string name="permdesc_removeTasks" msgid="1394714352062635493">"Hiermee kan de app taken verwijderen en apps sluiten. Schadelijke apps kunnen het gedrag van andere apps verstoren."</string> - <!-- no translation found for permlab_manageActivityStacks (7391191384027303065) --> - <skip /> - <!-- no translation found for permdesc_manageActivityStacks (1615881933034084440) --> - <skip /> + <string name="permlab_manageActivityStacks" msgid="7391191384027303065">"activiteitstacks beheren"</string> + <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"Hiermee kan de app de activiteitstacks waarin andere apps worden uitgevoerd, toevoegen, verwijderen en aanpassen. Schadelijke apps kunnen het gedrag van andere apps verstoren."</string> <string name="permlab_startAnyActivity" msgid="2918768238045206456">"elke activiteit starten"</string> <string name="permdesc_startAnyActivity" msgid="997823695343584001">"Toestaan dat de app elke activiteit start, ongeacht rechtenbeveiliging of geëxporteerde status."</string> <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"schermcompatibiliteit instellen"</string> @@ -360,14 +358,10 @@ <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Hiermee kan de houder zich verbinden met de hoofdinterface van een invoermethode. Nooit vereist voor normale apps."</string> <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"koppelen aan een toegankelijkheidsservice"</string> <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Hiermee wordt de houder toegestaan verbinding te maken met de hoofdinterface van een toegankelijkheidsservice. Nooit vereist voor normale apps."</string> - <!-- no translation found for permlab_bindPrintService (8462815179572748761) --> - <skip /> - <!-- no translation found for permdesc_bindPrintService (7960067623209111135) --> - <skip /> - <!-- no translation found for permlab_accessAllPrintJobs (1120792468465711159) --> - <skip /> - <!-- no translation found for permdesc_accessAllPrintJobs (2978185311041864762) --> - <skip /> + <string name="permlab_bindPrintService" msgid="8462815179572748761">"koppelen aan een afdrukservice"</string> + <string name="permdesc_bindPrintService" msgid="7960067623209111135">"Hiermee kan de houder verbinding maken met de hoofdinterface van een afdrukservice. Nooit vereist voor normale apps."</string> + <string name="permlab_accessAllPrintJobs" msgid="1120792468465711159">"toegang krijgen tot alle afdruktaken"</string> + <string name="permdesc_accessAllPrintJobs" msgid="2978185311041864762">"Hiermee kan de houder toegang krijgen tot afdruktaken die zijn gemaakt door een andere app. Nooit vereist voor normale apps."</string> <string name="permlab_bindTextService" msgid="7358378401915287938">"koppelen aan een sms-service"</string> <string name="permdesc_bindTextService" msgid="8151968910973998670">"Hiermee kan de gebruiker koppelen met de hoofdinterface van een tekstservice (zoals SpellCheckerService). Dit is niet nodig voor normale apps."</string> <string name="permlab_bindVpnService" msgid="4708596021161473255">"koppelen aan een VPN-service"</string> @@ -470,6 +464,8 @@ <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Hiermee kan de app SurfaceFlinger-functies op laag niveau gebruiken."</string> <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"framebuffer lezen"</string> <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Hiermee kan de app de inhoud van de framebuffer lezen."</string> + <string name="permlab_accessInputFlinger" msgid="5348635270689553857">"toegang krijgen tot InputFlinger"</string> + <string name="permdesc_accessInputFlinger" msgid="2104864941201226616">"Hiermee kan de app InputFlinger-functies op laag niveau gebruiken."</string> <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"wifi-displays configureren"</string> <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"De app toestaan wifi-displays te configureren en hiermee verbinding te maken."</string> <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"wifi-displays beheren"</string> @@ -639,10 +635,14 @@ <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Hiermee kan de app het netwerkbeleid beheren en app-specifieke regels definiëren."</string> <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"verrekening van netwerkgebruik aanpassen"</string> <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Hiermee kan een app aanpassen hoe het netwerkgebruik wordt toegekend aan apps. Dit wordt niet gebruikt door normale apps."</string> + <string name="permlab_markNetworkSocket" msgid="3658527214914959749">"socketmarkeringen aanpassen"</string> + <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"Hiermee kan de app socketmarkeringen voor routeren aanpassen"</string> <string name="permlab_accessNotifications" msgid="7673416487873432268">"toegang tot meldingen"</string> <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_invokeCarrierSetup" msgid="3699600833975117478">"de door de provider geleverde configuratie-app aanroepen"</string> + <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Hiermee kan de houder de door de provider geleverde configuratie-app aanroepen. Nooit vereist voor normale apps."</string> <string name="policylab_limitPassword" msgid="4497420728857585791">"Wachtwoordregels instellen"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"De lengte en tekens beheren die zijn toegestaan in wachtwoorden voor schermontgrendeling."</string> <string name="policylab_watchLogin" msgid="914130646942199503">"Pogingen voor schermontgrendeling bijhouden"</string> @@ -752,8 +752,7 @@ <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string> <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string> <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string> - <!-- no translation found for imProtocolGoogleTalk (493902321140277304) --> - <skip /> + <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangouts"</string> <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string> <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string> <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string> @@ -1515,94 +1514,59 @@ <string name="app_no_restricted_accounts" msgid="5739463249673727736">"Deze app biedt geen ondersteuning voor accounts voor beperkte profielen"</string> <string name="app_not_found" msgid="3429141853498927379">"Er is geen app gevonden om deze actie uit te voeren"</string> <string name="revoke" msgid="5404479185228271586">"Intrekken"</string> - <!-- no translation found for mediaSize_iso_a0 (7875427489420821793) --> - <skip /> - <!-- no translation found for mediaSize_iso_a1 (3760734499050875356) --> - <skip /> - <!-- no translation found for mediaSize_iso_a2 (5973266378020144382) --> - <skip /> - <!-- no translation found for mediaSize_iso_a3 (1373407105687300884) --> - <skip /> - <!-- no translation found for mediaSize_iso_a4 (6689772807982597254) --> - <skip /> - <!-- no translation found for mediaSize_iso_a5 (5353549652015741040) --> - <skip /> - <!-- no translation found for mediaSize_iso_a6 (8585038048674911907) --> - <skip /> - <!-- no translation found for mediaSize_iso_a7 (6641836716963839119) --> - <skip /> - <!-- no translation found for mediaSize_iso_a8 (7571139437465693355) --> - <skip /> - <!-- no translation found for mediaSize_iso_a9 (1378455891957115079) --> - <skip /> - <!-- no translation found for mediaSize_iso_a10 (2480747457429475344) --> - <skip /> - <!-- no translation found for mediaSize_iso_b0 (3965935097661108039) --> - <skip /> - <!-- no translation found for mediaSize_iso_b1 (2505753285010115437) --> - <skip /> - <!-- no translation found for mediaSize_iso_b2 (8763874709859458453) --> - <skip /> - <!-- no translation found for mediaSize_iso_b3 (4210506688191764076) --> - <skip /> - <!-- no translation found for mediaSize_iso_b4 (5749404165888526034) --> - <skip /> - <!-- no translation found for mediaSize_iso_b5 (7640627414621904733) --> - <skip /> - <!-- no translation found for mediaSize_iso_b6 (7342988864712748544) --> - <skip /> - <!-- no translation found for mediaSize_iso_b7 (5069844065235382429) --> + <string name="mediaSize_iso_a0" msgid="7875427489420821793">"ISO A0"</string> + <string name="mediaSize_iso_a1" msgid="3760734499050875356">"ISO A1"</string> + <string name="mediaSize_iso_a2" msgid="5973266378020144382">"ISO A2"</string> + <string name="mediaSize_iso_a3" msgid="1373407105687300884">"ISO A3"</string> + <string name="mediaSize_iso_a4" msgid="6689772807982597254">"ISO A4"</string> + <string name="mediaSize_iso_a5" msgid="5353549652015741040">"ISO A5"</string> + <string name="mediaSize_iso_a6" msgid="8585038048674911907">"ISO A6"</string> + <string name="mediaSize_iso_a7" msgid="6641836716963839119">"ISO A7"</string> + <string name="mediaSize_iso_a8" msgid="7571139437465693355">"ISO A8"</string> + <string name="mediaSize_iso_a9" msgid="1378455891957115079">"ISO A9"</string> + <string name="mediaSize_iso_a10" msgid="2480747457429475344">"ISO A10"</string> + <string name="mediaSize_iso_b0" msgid="3965935097661108039">"ISO B0"</string> + <string name="mediaSize_iso_b1" msgid="2505753285010115437">"ISO B1"</string> + <string name="mediaSize_iso_b2" msgid="8763874709859458453">"ISO B2"</string> + <string name="mediaSize_iso_b3" msgid="4210506688191764076">"ISO B3"</string> + <string name="mediaSize_iso_b4" msgid="5749404165888526034">"ISO B4"</string> + <string name="mediaSize_iso_b5" msgid="7640627414621904733">"ISO B5"</string> + <string name="mediaSize_iso_b6" msgid="7342988864712748544">"ISO B6"</string> + <string name="mediaSize_iso_b7" msgid="5069844065235382429">"ISO B7"</string> + <string name="mediaSize_iso_b8" msgid="7316818922278779774">"ISO B8"</string> + <string name="mediaSize_iso_b9" msgid="5414727094026532341">"ISO B9"</string> + <string name="mediaSize_iso_b10" msgid="5251253731832048185">"ISO B10"</string> + <string name="mediaSize_iso_c0" msgid="4003138342671964217">"ISO C0"</string> + <string name="mediaSize_iso_c1" msgid="1935188063393553008">"ISO C1"</string> + <string name="mediaSize_iso_c2" msgid="3197307969712069904">"ISO C2"</string> + <string name="mediaSize_iso_c3" msgid="4335826087321913508">"ISO C3"</string> + <string name="mediaSize_iso_c4" msgid="3745639598281015005">"ISO C4"</string> + <string name="mediaSize_iso_c5" msgid="8269457765822791013">"ISO C5"</string> + <string name="mediaSize_iso_c6" msgid="566666105260346930">"ISO C6"</string> + <string name="mediaSize_iso_c7" msgid="8678413180782608498">"ISO C7"</string> + <string name="mediaSize_iso_c8" msgid="8392376206627041730">"ISO C8"</string> + <string name="mediaSize_iso_c9" msgid="9191613372324845405">"ISO C9"</string> + <string name="mediaSize_iso_c10" msgid="7327709699184920822">"ISO C10"</string> + <string name="mediaSize_na_letter" msgid="4191805615829472953">"Letter"</string> + <string name="mediaSize_na_gvrnmt_letter" msgid="7853382192649405507">"Government Letter"</string> + <string name="mediaSize_na_legal" msgid="6697982988283823150">"Legal"</string> + <string name="mediaSize_na_junior_legal" msgid="3727743969902758948">"Junior Legal"</string> + <string name="mediaSize_na_ledger" msgid="281871464896601236">"Ledger"</string> + <string name="mediaSize_na_tabloid" msgid="5775966416333578127">"Tabloid"</string> + <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"Geannuleerd"</string> + <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"Fout bij schrijven van inhoud"</string> + <string name="restr_pin_enter_pin" msgid="3395953421368476103">"Geef de pincode op"</string> + <!-- no translation found for restr_pin_enter_old_pin (1462206225512910757) --> <skip /> - <!-- no translation found for mediaSize_iso_b8 (7316818922278779774) --> + <!-- no translation found for restr_pin_enter_new_pin (5959606691619959184) --> <skip /> - <!-- no translation found for mediaSize_iso_b9 (5414727094026532341) --> + <!-- no translation found for restr_pin_confirm_pin (8501523829633146239) --> <skip /> - <!-- no translation found for mediaSize_iso_b10 (5251253731832048185) --> - <skip /> - <!-- no translation found for mediaSize_iso_c0 (4003138342671964217) --> - <skip /> - <!-- no translation found for mediaSize_iso_c1 (1935188063393553008) --> - <skip /> - <!-- no translation found for mediaSize_iso_c2 (3197307969712069904) --> - <skip /> - <!-- no translation found for mediaSize_iso_c3 (4335826087321913508) --> - <skip /> - <!-- no translation found for mediaSize_iso_c4 (3745639598281015005) --> - <skip /> - <!-- no translation found for mediaSize_iso_c5 (8269457765822791013) --> - <skip /> - <!-- no translation found for mediaSize_iso_c6 (566666105260346930) --> - <skip /> - <!-- no translation found for mediaSize_iso_c7 (8678413180782608498) --> - <skip /> - <!-- no translation found for mediaSize_iso_c8 (8392376206627041730) --> - <skip /> - <!-- no translation found for mediaSize_iso_c9 (9191613372324845405) --> - <skip /> - <!-- no translation found for mediaSize_iso_c10 (7327709699184920822) --> - <skip /> - <!-- no translation found for mediaSize_na_letter (4191805615829472953) --> - <skip /> - <!-- no translation found for mediaSize_na_gvrnmt_letter (7853382192649405507) --> - <skip /> - <!-- no translation found for mediaSize_na_legal (6697982988283823150) --> - <skip /> - <!-- no translation found for mediaSize_na_junior_legal (3727743969902758948) --> - <skip /> - <!-- no translation found for mediaSize_na_ledger (281871464896601236) --> - <skip /> - <!-- no translation found for mediaSize_na_tabloid (5775966416333578127) --> - <skip /> - <!-- no translation found for restr_pin_create_pin (8017600000263450337) --> - <skip /> - <!-- no translation found for restr_pin_enter_pin (3395953421368476103) --> - <skip /> - <!-- no translation found for restr_pin_confirm_pin (2891475237150965991) --> - <skip /> - <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) --> - <skip /> - <!-- no translation found for restr_pin_error_too_short (8173982756265777792) --> - <skip /> - <!-- no translation found for restr_pin_countdown:one (4835639969503729874) --> - <!-- no translation found for restr_pin_countdown:other (8030607343223287654) --> + <string name="restr_pin_create_pin" msgid="8017600000263450337">"Maak een pincode voor het aanpassen van beperkingen"</string> + <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"De pincodes komen niet overeen. Probeer het opnieuw."</string> + <string name="restr_pin_error_too_short" msgid="8173982756265777792">"Pincode is te kort. Moet ten minste vier cijfers lang zijn."</string> + <plurals name="restr_pin_countdown"> + <item quantity="one" msgid="4835639969503729874">"Onjuiste pincode. Probeer het over één seconde opnieuw."</item> + <item quantity="other" msgid="8030607343223287654">"Onjuiste pincode. Probeer het over <xliff:g id="COUNT">%d</xliff:g> seconden opnieuw."</item> + </plurals> </resources> diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml index 588df6f..a6dfe94 100644 --- a/core/res/res/values-pl/strings.xml +++ b/core/res/res/values-pl/strings.xml @@ -470,6 +470,10 @@ <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Pozwala aplikacji na wykorzystanie funkcji niskiego poziomu usługi SurfaceFlinger."</string> <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"czytanie bufora ramki"</string> <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Pozwala aplikacji na odczyt zawartości bufora ramki."</string> + <!-- no translation found for permlab_accessInputFlinger (5348635270689553857) --> + <skip /> + <!-- no translation found for permdesc_accessInputFlinger (2104864941201226616) --> + <skip /> <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"konfigurowanie wyświetlaczy Wi-Fi"</string> <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Zezwala aplikacji na konfigurację wyświetlaczy Wi-Fi i łączenie z nimi."</string> <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"zarządzanie wyświetlaczami Wi-Fi"</string> @@ -639,10 +643,18 @@ <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Pozwala aplikacji na zarządzanie zasadami dotyczącymi sieci i definiowanie reguł aplikacji."</string> <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"modyfikowanie sposobu naliczania użycia sieci"</string> <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Pozwala aplikacji na zmienianie sposobu rozliczania wykorzystania sieci przez aplikacje. Nieprzeznaczone dla zwykłych aplikacji."</string> + <!-- no translation found for permlab_markNetworkSocket (3658527214914959749) --> + <skip /> + <!-- no translation found for permdesc_markNetworkSocket (7655568433696356578) --> + <skip /> <string name="permlab_accessNotifications" msgid="7673416487873432268">"dostęp do powiadomień"</string> <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> + <!-- no translation found for permlab_invokeCarrierSetup (3699600833975117478) --> + <skip /> + <!-- no translation found for permdesc_invokeCarrierSetup (4159549152529111920) --> + <skip /> <string name="policylab_limitPassword" msgid="4497420728857585791">"Określ reguły hasła"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"Kontrolowanie długości haseł odblokowania ekranu i dozwolonych w nich znaków"</string> <string name="policylab_watchLogin" msgid="914130646942199503">"Monitoruj próby odblokowania ekranu"</string> @@ -1593,11 +1605,19 @@ <skip /> <!-- no translation found for mediaSize_na_tabloid (5775966416333578127) --> <skip /> - <!-- no translation found for restr_pin_create_pin (8017600000263450337) --> + <!-- no translation found for write_fail_reason_cancelled (7091258378121627624) --> + <skip /> + <!-- no translation found for write_fail_reason_cannot_write (8132505417935337724) --> <skip /> <!-- no translation found for restr_pin_enter_pin (3395953421368476103) --> <skip /> - <!-- no translation found for restr_pin_confirm_pin (2891475237150965991) --> + <!-- no translation found for restr_pin_enter_old_pin (1462206225512910757) --> + <skip /> + <!-- no translation found for restr_pin_enter_new_pin (5959606691619959184) --> + <skip /> + <!-- no translation found for restr_pin_confirm_pin (8501523829633146239) --> + <skip /> + <!-- no translation found for restr_pin_create_pin (8017600000263450337) --> <skip /> <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) --> <skip /> diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml index 4d22c52..39bfbf2 100644 --- a/core/res/res/values-pt-rPT/strings.xml +++ b/core/res/res/values-pt-rPT/strings.xml @@ -279,10 +279,8 @@ <string name="permdesc_reorderTasks" msgid="7734217754877439351">"Permite que a aplicação mova tarefas para primeiro e segundo plano. A aplicação poderá fazê-lo sem qualquer entrada do utilizador."</string> <string name="permlab_removeTasks" msgid="6821513401870377403">"parar aplicações em execução"</string> <string name="permdesc_removeTasks" msgid="1394714352062635493">"Permite que a aplicação remova tarefas e elimine as respetivas aplicações. As aplicações maliciosas podem perturbar o comportamento de outras aplicações."</string> - <!-- no translation found for permlab_manageActivityStacks (7391191384027303065) --> - <skip /> - <!-- no translation found for permdesc_manageActivityStacks (1615881933034084440) --> - <skip /> + <string name="permlab_manageActivityStacks" msgid="7391191384027303065">"gerir pilhas de atividade"</string> + <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"Permite que a aplicação adicione, remova e modifique as pilhas de atividade em que são executadas outras aplicações. As aplicações maliciosas podem afetar o comportamento de outras aplicações."</string> <string name="permlab_startAnyActivity" msgid="2918768238045206456">"iniciar qualquer atividade"</string> <string name="permdesc_startAnyActivity" msgid="997823695343584001">"Permite que a aplicação inicie qualquer atividade, independentemente da proteção de permissão ou do estado exportado."</string> <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"definir compatibilidade de ecrã"</string> @@ -360,14 +358,10 @@ <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Permite ao titular vincular-se à interface de nível superior de um método de entrada. Nunca deve ser necessário para aplicações normais."</string> <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"vincular a um serviço de acessibilidade"</string> <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Permite que o titular vincule a interface de nível superior de um serviço de acessibilidade. Nunca deverá ser necessário para aplicações normais."</string> - <!-- no translation found for permlab_bindPrintService (8462815179572748761) --> - <skip /> - <!-- no translation found for permdesc_bindPrintService (7960067623209111135) --> - <skip /> - <!-- no translation found for permlab_accessAllPrintJobs (1120792468465711159) --> - <skip /> - <!-- no translation found for permdesc_accessAllPrintJobs (2978185311041864762) --> - <skip /> + <string name="permlab_bindPrintService" msgid="8462815179572748761">"vincular a um serviço de impressão"</string> + <string name="permdesc_bindPrintService" msgid="7960067623209111135">"Permite que o titular vincule a interface de nível superior de um serviço de impressão. Nunca deverá ser necessário para aplicações normais."</string> + <string name="permlab_accessAllPrintJobs" msgid="1120792468465711159">"aceder a todas as tarefas de impressão"</string> + <string name="permdesc_accessAllPrintJobs" msgid="2978185311041864762">"Permite que o titular aceda a tarefas de impressão criadas por outra aplicação. Nunca deverá ser necessário para aplicações normais."</string> <string name="permlab_bindTextService" msgid="7358378401915287938">"vincular a um serviço de texto"</string> <string name="permdesc_bindTextService" msgid="8151968910973998670">"Permite ao titular ligar-se à interface de nível superior de um serviço de texto (por exemplo SpellCheckerService). Nunca deverá ser necessário para aplicações normais."</string> <string name="permlab_bindVpnService" msgid="4708596021161473255">"vincular a um serviço VPN"</string> @@ -470,6 +464,8 @@ <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Permite à aplicação utilizar funcionalidades de SurfaceFlinger de nível inferior."</string> <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"ler memória intermédia de fotogramas"</string> <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Permite à aplicação ler o conteúdo da memória intermédia de fotogramas."</string> + <string name="permlab_accessInputFlinger" msgid="5348635270689553857">"aceder a InputFlinger"</string> + <string name="permdesc_accessInputFlinger" msgid="2104864941201226616">"Permite que a aplicação utilize funcionalidades de InputFlinger de nível inferior."</string> <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"configurar visores Wi-Fi"</string> <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Permite que a aplicação se configure e se ligue a visores Wi-Fi."</string> <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"controlar visores Wi-Fi"</string> @@ -639,10 +635,14 @@ <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Permite que a aplicação faça a gestão de políticas de rede e defina regras específicas de aplicações."</string> <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"modificar contabilização da utilização da rede"</string> <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Permite que a aplicação modifique o modo como a utilização da rede é contabilizada em relação a aplicações. Nunca é necessário para aplicações normais."</string> + <string name="permlab_markNetworkSocket" msgid="3658527214914959749">"modificar marcas de socket"</string> + <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"Permite que a aplicação modifique as marcas de socket para encaminhamento"</string> <string name="permlab_accessNotifications" msgid="7673416487873432268">"aceder às notificações"</string> <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_invokeCarrierSetup" msgid="3699600833975117478">"invocar a aplicação de configuração fornecida pela operadora"</string> + <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Permite que o titular invoque a aplicação de configuração fornecida pela operadora. Nunca deverá ser necessário para aplicações normais."</string> <string name="policylab_limitPassword" msgid="4497420728857585791">"Definir regras de palavra-passe"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"Controlar o comprimento e os caracteres permitidos nas palavras-passe de desbloqueio do ecrã."</string> <string name="policylab_watchLogin" msgid="914130646942199503">"Monitorizar tentativas de desbloqueio do ecrã"</string> @@ -752,8 +752,7 @@ <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string> <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string> <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string> - <!-- no translation found for imProtocolGoogleTalk (493902321140277304) --> - <skip /> + <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangouts"</string> <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string> <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string> <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string> @@ -1515,94 +1514,59 @@ <string name="app_no_restricted_accounts" msgid="5739463249673727736">"Esta aplicação não suporta contas de perfis restritos"</string> <string name="app_not_found" msgid="3429141853498927379">"Não foram encontradas aplicações para executar esta ação"</string> <string name="revoke" msgid="5404479185228271586">"Revogar"</string> - <!-- no translation found for mediaSize_iso_a0 (7875427489420821793) --> - <skip /> - <!-- no translation found for mediaSize_iso_a1 (3760734499050875356) --> - <skip /> - <!-- no translation found for mediaSize_iso_a2 (5973266378020144382) --> - <skip /> - <!-- no translation found for mediaSize_iso_a3 (1373407105687300884) --> - <skip /> - <!-- no translation found for mediaSize_iso_a4 (6689772807982597254) --> - <skip /> - <!-- no translation found for mediaSize_iso_a5 (5353549652015741040) --> - <skip /> - <!-- no translation found for mediaSize_iso_a6 (8585038048674911907) --> - <skip /> - <!-- no translation found for mediaSize_iso_a7 (6641836716963839119) --> - <skip /> - <!-- no translation found for mediaSize_iso_a8 (7571139437465693355) --> - <skip /> - <!-- no translation found for mediaSize_iso_a9 (1378455891957115079) --> - <skip /> - <!-- no translation found for mediaSize_iso_a10 (2480747457429475344) --> - <skip /> - <!-- no translation found for mediaSize_iso_b0 (3965935097661108039) --> - <skip /> - <!-- no translation found for mediaSize_iso_b1 (2505753285010115437) --> - <skip /> - <!-- no translation found for mediaSize_iso_b2 (8763874709859458453) --> - <skip /> - <!-- no translation found for mediaSize_iso_b3 (4210506688191764076) --> - <skip /> - <!-- no translation found for mediaSize_iso_b4 (5749404165888526034) --> - <skip /> - <!-- no translation found for mediaSize_iso_b5 (7640627414621904733) --> - <skip /> - <!-- no translation found for mediaSize_iso_b6 (7342988864712748544) --> - <skip /> - <!-- no translation found for mediaSize_iso_b7 (5069844065235382429) --> + <string name="mediaSize_iso_a0" msgid="7875427489420821793">"ISO A0"</string> + <string name="mediaSize_iso_a1" msgid="3760734499050875356">"ISO A1"</string> + <string name="mediaSize_iso_a2" msgid="5973266378020144382">"ISO A2"</string> + <string name="mediaSize_iso_a3" msgid="1373407105687300884">"ISO A3"</string> + <string name="mediaSize_iso_a4" msgid="6689772807982597254">"ISO A4"</string> + <string name="mediaSize_iso_a5" msgid="5353549652015741040">"ISO A5"</string> + <string name="mediaSize_iso_a6" msgid="8585038048674911907">"ISO A6"</string> + <string name="mediaSize_iso_a7" msgid="6641836716963839119">"ISO A7"</string> + <string name="mediaSize_iso_a8" msgid="7571139437465693355">"ISO A8"</string> + <string name="mediaSize_iso_a9" msgid="1378455891957115079">"ISO A9"</string> + <string name="mediaSize_iso_a10" msgid="2480747457429475344">"ISO A10"</string> + <string name="mediaSize_iso_b0" msgid="3965935097661108039">"ISO B0"</string> + <string name="mediaSize_iso_b1" msgid="2505753285010115437">"ISO B1"</string> + <string name="mediaSize_iso_b2" msgid="8763874709859458453">"ISO B2"</string> + <string name="mediaSize_iso_b3" msgid="4210506688191764076">"ISO B3"</string> + <string name="mediaSize_iso_b4" msgid="5749404165888526034">"ISO B4"</string> + <string name="mediaSize_iso_b5" msgid="7640627414621904733">"ISO B5"</string> + <string name="mediaSize_iso_b6" msgid="7342988864712748544">"ISO B6"</string> + <string name="mediaSize_iso_b7" msgid="5069844065235382429">"ISO B7"</string> + <string name="mediaSize_iso_b8" msgid="7316818922278779774">"ISO B8"</string> + <string name="mediaSize_iso_b9" msgid="5414727094026532341">"ISO B9"</string> + <string name="mediaSize_iso_b10" msgid="5251253731832048185">"ISO B10"</string> + <string name="mediaSize_iso_c0" msgid="4003138342671964217">"ISO C0"</string> + <string name="mediaSize_iso_c1" msgid="1935188063393553008">"ISO C1"</string> + <string name="mediaSize_iso_c2" msgid="3197307969712069904">"ISO C2"</string> + <string name="mediaSize_iso_c3" msgid="4335826087321913508">"ISO C3"</string> + <string name="mediaSize_iso_c4" msgid="3745639598281015005">"ISO C4"</string> + <string name="mediaSize_iso_c5" msgid="8269457765822791013">"ISO C5"</string> + <string name="mediaSize_iso_c6" msgid="566666105260346930">"ISO C6"</string> + <string name="mediaSize_iso_c7" msgid="8678413180782608498">"ISO C7"</string> + <string name="mediaSize_iso_c8" msgid="8392376206627041730">"ISO C8"</string> + <string name="mediaSize_iso_c9" msgid="9191613372324845405">"ISO C9"</string> + <string name="mediaSize_iso_c10" msgid="7327709699184920822">"ISO C10"</string> + <string name="mediaSize_na_letter" msgid="4191805615829472953">"Letter"</string> + <string name="mediaSize_na_gvrnmt_letter" msgid="7853382192649405507">"Government Letter"</string> + <string name="mediaSize_na_legal" msgid="6697982988283823150">"Legal"</string> + <string name="mediaSize_na_junior_legal" msgid="3727743969902758948">"Junior Legal"</string> + <string name="mediaSize_na_ledger" msgid="281871464896601236">"Ledger"</string> + <string name="mediaSize_na_tabloid" msgid="5775966416333578127">"Tabloid"</string> + <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"Cancelada"</string> + <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"Erro ao escrever conteúdo"</string> + <string name="restr_pin_enter_pin" msgid="3395953421368476103">"Introduzir PIN"</string> + <!-- no translation found for restr_pin_enter_old_pin (1462206225512910757) --> <skip /> - <!-- no translation found for mediaSize_iso_b8 (7316818922278779774) --> + <!-- no translation found for restr_pin_enter_new_pin (5959606691619959184) --> <skip /> - <!-- no translation found for mediaSize_iso_b9 (5414727094026532341) --> + <!-- no translation found for restr_pin_confirm_pin (8501523829633146239) --> <skip /> - <!-- no translation found for mediaSize_iso_b10 (5251253731832048185) --> - <skip /> - <!-- no translation found for mediaSize_iso_c0 (4003138342671964217) --> - <skip /> - <!-- no translation found for mediaSize_iso_c1 (1935188063393553008) --> - <skip /> - <!-- no translation found for mediaSize_iso_c2 (3197307969712069904) --> - <skip /> - <!-- no translation found for mediaSize_iso_c3 (4335826087321913508) --> - <skip /> - <!-- no translation found for mediaSize_iso_c4 (3745639598281015005) --> - <skip /> - <!-- no translation found for mediaSize_iso_c5 (8269457765822791013) --> - <skip /> - <!-- no translation found for mediaSize_iso_c6 (566666105260346930) --> - <skip /> - <!-- no translation found for mediaSize_iso_c7 (8678413180782608498) --> - <skip /> - <!-- no translation found for mediaSize_iso_c8 (8392376206627041730) --> - <skip /> - <!-- no translation found for mediaSize_iso_c9 (9191613372324845405) --> - <skip /> - <!-- no translation found for mediaSize_iso_c10 (7327709699184920822) --> - <skip /> - <!-- no translation found for mediaSize_na_letter (4191805615829472953) --> - <skip /> - <!-- no translation found for mediaSize_na_gvrnmt_letter (7853382192649405507) --> - <skip /> - <!-- no translation found for mediaSize_na_legal (6697982988283823150) --> - <skip /> - <!-- no translation found for mediaSize_na_junior_legal (3727743969902758948) --> - <skip /> - <!-- no translation found for mediaSize_na_ledger (281871464896601236) --> - <skip /> - <!-- no translation found for mediaSize_na_tabloid (5775966416333578127) --> - <skip /> - <!-- no translation found for restr_pin_create_pin (8017600000263450337) --> - <skip /> - <!-- no translation found for restr_pin_enter_pin (3395953421368476103) --> - <skip /> - <!-- no translation found for restr_pin_confirm_pin (2891475237150965991) --> - <skip /> - <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) --> - <skip /> - <!-- no translation found for restr_pin_error_too_short (8173982756265777792) --> - <skip /> - <!-- no translation found for restr_pin_countdown:one (4835639969503729874) --> - <!-- no translation found for restr_pin_countdown:other (8030607343223287654) --> + <string name="restr_pin_create_pin" msgid="8017600000263450337">"Crie um PIN para modificar as restrições"</string> + <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"Os PINs não correspondem. Tente novamente."</string> + <string name="restr_pin_error_too_short" msgid="8173982756265777792">"O PIN é demasiado pequeno. Deve ter, no mínimo, 4 dígitos."</string> + <plurals name="restr_pin_countdown"> + <item quantity="one" msgid="4835639969503729874">"PIN incorreto. Tente novamente em 1 seg."</item> + <item quantity="other" msgid="8030607343223287654">"PIN incorreto. Tente novamente em <xliff:g id="COUNT">%d</xliff:g> seg."</item> + </plurals> </resources> diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml index d9a997e..88460c4 100644 --- a/core/res/res/values-pt/strings.xml +++ b/core/res/res/values-pt/strings.xml @@ -470,6 +470,10 @@ <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Permite que o aplicativo use recursos com baixos níveis de SurfaceFlinger."</string> <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"ler o buffer do frame"</string> <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Permite que o aplicativo leia o conteúdo do buffer de frame."</string> + <!-- no translation found for permlab_accessInputFlinger (5348635270689553857) --> + <skip /> + <!-- no translation found for permdesc_accessInputFlinger (2104864941201226616) --> + <skip /> <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"configurar monitores Wi-Fi"</string> <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Permite que o aplicativo configure e conecte a monitores Wi-Fi."</string> <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"controlar monitores Wi-Fi"</string> @@ -639,10 +643,18 @@ <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Permite que o aplicativo gerencie políticas de rede e definia regras específicas para o aplicativo."</string> <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"modificar contagem de uso da rede"</string> <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Permite que o aplicativo modifique como o uso da rede é contabilizado em relação aos aplicativos. Não deve ser usado em aplicativos normais."</string> + <!-- no translation found for permlab_markNetworkSocket (3658527214914959749) --> + <skip /> + <!-- no translation found for permdesc_markNetworkSocket (7655568433696356578) --> + <skip /> <string name="permlab_accessNotifications" msgid="7673416487873432268">"acessar notificações"</string> <string name="permdesc_accessNotifications" msgid="458457742683431387">"Permite que o aplicativo recupere, examine e limpe notificações, inclusive as postadas por outros aplicativos."</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 aplicativos comuns."</string> + <!-- no translation found for permlab_invokeCarrierSetup (3699600833975117478) --> + <skip /> + <!-- no translation found for permdesc_invokeCarrierSetup (4159549152529111920) --> + <skip /> <string name="policylab_limitPassword" msgid="4497420728857585791">"Definir regras para senha"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"Controle o tamanho e os caracteres permitidos nas senhas de desbloqueio de tela."</string> <string name="policylab_watchLogin" msgid="914130646942199503">"Monitorar tentativas de desbloqueio da tela"</string> @@ -1593,11 +1605,19 @@ <skip /> <!-- no translation found for mediaSize_na_tabloid (5775966416333578127) --> <skip /> - <!-- no translation found for restr_pin_create_pin (8017600000263450337) --> + <!-- no translation found for write_fail_reason_cancelled (7091258378121627624) --> + <skip /> + <!-- no translation found for write_fail_reason_cannot_write (8132505417935337724) --> <skip /> <!-- no translation found for restr_pin_enter_pin (3395953421368476103) --> <skip /> - <!-- no translation found for restr_pin_confirm_pin (2891475237150965991) --> + <!-- no translation found for restr_pin_enter_old_pin (1462206225512910757) --> + <skip /> + <!-- no translation found for restr_pin_enter_new_pin (5959606691619959184) --> + <skip /> + <!-- no translation found for restr_pin_confirm_pin (8501523829633146239) --> + <skip /> + <!-- no translation found for restr_pin_create_pin (8017600000263450337) --> <skip /> <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) --> <skip /> diff --git a/core/res/res/values-rm/strings.xml b/core/res/res/values-rm/strings.xml index c5b4fd1..66f68d0 100644 --- a/core/res/res/values-rm/strings.xml +++ b/core/res/res/values-rm/strings.xml @@ -757,6 +757,10 @@ <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"leger il paraculp da frame"</string> <!-- no translation found for permdesc_readFrameBuffer (4937405521809454680) --> <skip /> + <!-- no translation found for permlab_accessInputFlinger (5348635270689553857) --> + <skip /> + <!-- no translation found for permdesc_accessInputFlinger (2104864941201226616) --> + <skip /> <!-- no translation found for permlab_configureWifiDisplay (5595661694746742168) --> <skip /> <!-- no translation found for permdesc_configureWifiDisplay (7916815158690218065) --> @@ -1064,6 +1068,10 @@ <skip /> <!-- no translation found for permdesc_modifyNetworkAccounting (5443412866746198123) --> <skip /> + <!-- no translation found for permlab_markNetworkSocket (3658527214914959749) --> + <skip /> + <!-- no translation found for permdesc_markNetworkSocket (7655568433696356578) --> + <skip /> <!-- no translation found for permlab_accessNotifications (7673416487873432268) --> <skip /> <!-- no translation found for permdesc_accessNotifications (458457742683431387) --> @@ -1072,6 +1080,10 @@ <skip /> <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) --> <skip /> + <!-- no translation found for permlab_invokeCarrierSetup (3699600833975117478) --> + <skip /> + <!-- no translation found for permdesc_invokeCarrierSetup (4159549152529111920) --> + <skip /> <!-- no translation found for policylab_limitPassword (4497420728857585791) --> <skip /> <!-- no translation found for policydesc_limitPassword (3252114203919510394) --> @@ -2534,11 +2546,19 @@ <skip /> <!-- no translation found for mediaSize_na_tabloid (5775966416333578127) --> <skip /> - <!-- no translation found for restr_pin_create_pin (8017600000263450337) --> + <!-- no translation found for write_fail_reason_cancelled (7091258378121627624) --> + <skip /> + <!-- no translation found for write_fail_reason_cannot_write (8132505417935337724) --> <skip /> <!-- no translation found for restr_pin_enter_pin (3395953421368476103) --> <skip /> - <!-- no translation found for restr_pin_confirm_pin (2891475237150965991) --> + <!-- no translation found for restr_pin_enter_old_pin (1462206225512910757) --> + <skip /> + <!-- no translation found for restr_pin_enter_new_pin (5959606691619959184) --> + <skip /> + <!-- no translation found for restr_pin_confirm_pin (8501523829633146239) --> + <skip /> + <!-- no translation found for restr_pin_create_pin (8017600000263450337) --> <skip /> <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) --> <skip /> diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml index a058815..fda819d 100644 --- a/core/res/res/values-ro/strings.xml +++ b/core/res/res/values-ro/strings.xml @@ -470,6 +470,10 @@ <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Permite aplicaţiei să utilizeze funcţiile de nivel redus SurfaceFlinger."</string> <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"citire zonă tampon de cadre"</string> <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Permite aplicaţiei să citească conţinutul zonei-tampon a cadrului."</string> + <!-- no translation found for permlab_accessInputFlinger (5348635270689553857) --> + <skip /> + <!-- no translation found for permdesc_accessInputFlinger (2104864941201226616) --> + <skip /> <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"configurează afişaje Wi-Fi"</string> <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Permite aplicaţiei să configureze şi să se conecteze la afişaje Wi-Fi."</string> <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"controlează afişaje Wi-Fi"</string> @@ -639,10 +643,18 @@ <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Permite aplicaţiei să gestioneze politicile de reţea şi să definească regulile specifice aplicaţiilor."</string> <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"modificaţi modul de calcul al utilizării reţelei"</string> <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Permite aplicaţiei să modifice modul în care este calculată utilizarea reţelei pentru aplicaţii. Nu se utilizează de aplicaţiile obişnuite."</string> + <!-- no translation found for permlab_markNetworkSocket (3658527214914959749) --> + <skip /> + <!-- no translation found for permdesc_markNetworkSocket (7655568433696356578) --> + <skip /> <string name="permlab_accessNotifications" msgid="7673416487873432268">"accesare notificări"</string> <string name="permdesc_accessNotifications" msgid="458457742683431387">"Permite aplicației să recupereze, să examineze și să șteargă notificări, inclusiv pe cele postate de alte aplicații."</string> <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> + <!-- no translation found for permlab_invokeCarrierSetup (3699600833975117478) --> + <skip /> + <!-- no translation found for permdesc_invokeCarrierSetup (4159549152529111920) --> + <skip /> <string name="policylab_limitPassword" msgid="4497420728857585791">"Setaţi reguli pentru parolă"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"Stabiliţi lungimea şi tipul de caractere permise în parolele pentru deblocarea ecranului."</string> <string name="policylab_watchLogin" msgid="914130646942199503">"Monitorizaţi încercările de deblocare a ecranului"</string> @@ -1593,11 +1605,19 @@ <skip /> <!-- no translation found for mediaSize_na_tabloid (5775966416333578127) --> <skip /> - <!-- no translation found for restr_pin_create_pin (8017600000263450337) --> + <!-- no translation found for write_fail_reason_cancelled (7091258378121627624) --> + <skip /> + <!-- no translation found for write_fail_reason_cannot_write (8132505417935337724) --> <skip /> <!-- no translation found for restr_pin_enter_pin (3395953421368476103) --> <skip /> - <!-- no translation found for restr_pin_confirm_pin (2891475237150965991) --> + <!-- no translation found for restr_pin_enter_old_pin (1462206225512910757) --> + <skip /> + <!-- no translation found for restr_pin_enter_new_pin (5959606691619959184) --> + <skip /> + <!-- no translation found for restr_pin_confirm_pin (8501523829633146239) --> + <skip /> + <!-- no translation found for restr_pin_create_pin (8017600000263450337) --> <skip /> <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) --> <skip /> diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml index b742263..170e469 100644 --- a/core/res/res/values-ru/strings.xml +++ b/core/res/res/values-ru/strings.xml @@ -470,6 +470,10 @@ <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Приложение сможет использовать низкоуровневые функции SurfaceFlinger."</string> <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"Чтение данных в буфере кадров"</string> <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Приложение сможет считывать содержание буфера фреймов."</string> + <!-- no translation found for permlab_accessInputFlinger (5348635270689553857) --> + <skip /> + <!-- no translation found for permdesc_accessInputFlinger (2104864941201226616) --> + <skip /> <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"настраивать экраны, подключенные через Wi-Fi"</string> <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Приложение сможет подключаться к экранам с помощью Wi-Fi и настраивать их."</string> <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"Управление мониторами, подключенными через Wi-Fi"</string> @@ -639,10 +643,18 @@ <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Приложение сможет управлять сетевыми политиками и определять правила для отдельных приложений."</string> <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"Изменение учета использования сети"</string> <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Приложение сможет изменять порядок расчета использования сетевых ресурсов различными программами. Это разрешение не используется обычными приложениями."</string> + <!-- no translation found for permlab_markNetworkSocket (3658527214914959749) --> + <skip /> + <!-- no translation found for permdesc_markNetworkSocket (7655568433696356578) --> + <skip /> <string name="permlab_accessNotifications" msgid="7673416487873432268">"Доступ к уведомлениям"</string> <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_invokeCarrierSetup (3699600833975117478) --> + <skip /> + <!-- no translation found for permdesc_invokeCarrierSetup (4159549152529111920) --> + <skip /> <string name="policylab_limitPassword" msgid="4497420728857585791">"Правила выбора паролей"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"Контролировать длину и символы при вводе паролей для снятия блокировки экрана."</string> <string name="policylab_watchLogin" msgid="914130646942199503">"Отслеживать попытки снятия блокировки экрана"</string> @@ -1593,11 +1605,19 @@ <skip /> <!-- no translation found for mediaSize_na_tabloid (5775966416333578127) --> <skip /> - <!-- no translation found for restr_pin_create_pin (8017600000263450337) --> + <!-- no translation found for write_fail_reason_cancelled (7091258378121627624) --> + <skip /> + <!-- no translation found for write_fail_reason_cannot_write (8132505417935337724) --> <skip /> <!-- no translation found for restr_pin_enter_pin (3395953421368476103) --> <skip /> - <!-- no translation found for restr_pin_confirm_pin (2891475237150965991) --> + <!-- no translation found for restr_pin_enter_old_pin (1462206225512910757) --> + <skip /> + <!-- no translation found for restr_pin_enter_new_pin (5959606691619959184) --> + <skip /> + <!-- no translation found for restr_pin_confirm_pin (8501523829633146239) --> + <skip /> + <!-- no translation found for restr_pin_create_pin (8017600000263450337) --> <skip /> <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) --> <skip /> diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml index f6a62cd..b300e9a 100644 --- a/core/res/res/values-sk/strings.xml +++ b/core/res/res/values-sk/strings.xml @@ -279,10 +279,8 @@ <string name="permdesc_reorderTasks" msgid="7734217754877439351">"Umožňuje aplikácii presunúť úlohy do popredia alebo do pozadia. Aplikácia tak môže urobiť bez vášho zásahu."</string> <string name="permlab_removeTasks" msgid="6821513401870377403">"zastaviť spustené aplikácie"</string> <string name="permdesc_removeTasks" msgid="1394714352062635493">"Umožňuje aplikácii odstrániť úlohy a ukončiť ich aplikácie. Škodlivé aplikácie môžu narušiť správanie iných aplikácií."</string> - <!-- no translation found for permlab_manageActivityStacks (7391191384027303065) --> - <skip /> - <!-- no translation found for permdesc_manageActivityStacks (1615881933034084440) --> - <skip /> + <string name="permlab_manageActivityStacks" msgid="7391191384027303065">"spravovanie zoskupení aktivít"</string> + <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"Umožňuje aplikácii pridať, odstrániť alebo upraviť zoskupenia aktivít, v ktorých sú spustené ostatné aplikácie. Škodlivé aplikácie môžu narušiť správanie ostatných aplikácií."</string> <string name="permlab_startAnyActivity" msgid="2918768238045206456">"spustiť ľubovoľnú aktivitu"</string> <string name="permdesc_startAnyActivity" msgid="997823695343584001">"Umožňuje aplikácii spustiť ľubovoľnú aktivitu bez ohľadu na ochranu povolení alebo exportovaný stav."</string> <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"nastaviť kompatibilitu obrazovky"</string> @@ -360,14 +358,10 @@ <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Umožňuje držiteľovi viazať sa na najvyššiu úroveň rozhrania metódy vstupu. Bežné aplikácie by toto nastavenie nemali nikdy potrebovať."</string> <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"viazať na službu zjednodušeného ovládania"</string> <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Umožňuje držiteľovi viazať sa na najvyššiu úroveň rozhrania služby zjednodušeného ovládania. Bežné aplikácie by toto nastavenie nemali nikdy potrebovať."</string> - <!-- no translation found for permlab_bindPrintService (8462815179572748761) --> - <skip /> - <!-- no translation found for permdesc_bindPrintService (7960067623209111135) --> - <skip /> - <!-- no translation found for permlab_accessAllPrintJobs (1120792468465711159) --> - <skip /> - <!-- no translation found for permdesc_accessAllPrintJobs (2978185311041864762) --> - <skip /> + <string name="permlab_bindPrintService" msgid="8462815179572748761">"viazanie na tlačovú službu"</string> + <string name="permdesc_bindPrintService" msgid="7960067623209111135">"Umožňuje držiteľovi viazať sa na najvyššiu úroveň rozhrania tlačovej služby. Bežné aplikácie by toto povolenie nemali nikdy potrebovať."</string> + <string name="permlab_accessAllPrintJobs" msgid="1120792468465711159">"prístup ku všetkým tlačovým úlohám"</string> + <string name="permdesc_accessAllPrintJobs" msgid="2978185311041864762">"Umožňuje držiteľovi prístup k tlačovým úlohám vytvoreným inou aplikáciou. Bežné aplikácie by toto povolenie nemali nikdy potrebovať."</string> <string name="permlab_bindTextService" msgid="7358378401915287938">"väzba na textovú službu"</string> <string name="permdesc_bindTextService" msgid="8151968910973998670">"Umožňuje držiteľovi viazať sa na najvyššiu úroveň rozhrania textovej služby (napr. SpellCheckerService). Bežné aplikácie by toto nastavenie nemali nikdy potrebovať."</string> <string name="permlab_bindVpnService" msgid="4708596021161473255">"Zaviazať k službe VPN"</string> @@ -470,6 +464,8 @@ <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Umožňuje aplikácii používať funkcie nízkej úrovne aplikácie SurfaceFlinger."</string> <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"čítanie vyrovnávacej pamäte snímok"</string> <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Umožňuje aplikácii čítať obsah vyrovnávacej pamäte snímok."</string> + <string name="permlab_accessInputFlinger" msgid="5348635270689553857">"prístup k aplikácii InputFlinger"</string> + <string name="permdesc_accessInputFlinger" msgid="2104864941201226616">"Umožňuje aplikácii používať funkcie nízkej úrovne aplikácie InputFlinger."</string> <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"konfigurovať displeje cez sieť Wi-Fi"</string> <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Umožňuje aplikácii konfigurovať displeje a pripojiť sa k nim cez siete Wi-Fi."</string> <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"ovládať displeje cez sieť Wi-Fi"</string> @@ -639,10 +635,14 @@ <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Umožňuje aplikácii spravovať pravidlá siete a definovať pravidlá pre konkrétnu aplikáciu."</string> <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"zmeniť kontrolu používania siete"</string> <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Umožňuje aplikácii upraviť používanie siete jednotlivými aplikáciami. Bežné aplikácie toto nastavenie nepoužívajú."</string> + <string name="permlab_markNetworkSocket" msgid="3658527214914959749">"upravenie značiek soketov"</string> + <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"Umožňuje aplikácii upraviť značky soketov pre smerovanie"</string> <string name="permlab_accessNotifications" msgid="7673416487873432268">"prístup k upozorneniam"</string> <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_invokeCarrierSetup" msgid="3699600833975117478">"vyvolanie aplikácie pre konfiguráciu poskytnutú operátorom"</string> + <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Umožňuje držiteľovi vyvolať aplikáciu pre konfiguráciu poskytnutú operátorom. Bežné aplikácie by toto povolenie nemali nikdy potrebovať."</string> <string name="policylab_limitPassword" msgid="4497420728857585791">"Nastaviť pravidlá pre heslo"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"Ovládanie dĺžky hesiel na odomknutie obrazovky a v nich používané znaky."</string> <string name="policylab_watchLogin" msgid="914130646942199503">"Sledovať pokusy o odomknutie obrazovky"</string> @@ -752,8 +752,7 @@ <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string> <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string> <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string> - <!-- no translation found for imProtocolGoogleTalk (493902321140277304) --> - <skip /> + <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangouts"</string> <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string> <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string> <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string> @@ -1515,94 +1514,59 @@ <string name="app_no_restricted_accounts" msgid="5739463249673727736">"Táto aplikácia nepodporuje účty pre profily s obmedzením"</string> <string name="app_not_found" msgid="3429141853498927379">"Aplikácia potrebná na spracovanie tejto akcie sa nenašla"</string> <string name="revoke" msgid="5404479185228271586">"Odvolať"</string> - <!-- no translation found for mediaSize_iso_a0 (7875427489420821793) --> - <skip /> - <!-- no translation found for mediaSize_iso_a1 (3760734499050875356) --> - <skip /> - <!-- no translation found for mediaSize_iso_a2 (5973266378020144382) --> - <skip /> - <!-- no translation found for mediaSize_iso_a3 (1373407105687300884) --> - <skip /> - <!-- no translation found for mediaSize_iso_a4 (6689772807982597254) --> - <skip /> - <!-- no translation found for mediaSize_iso_a5 (5353549652015741040) --> - <skip /> - <!-- no translation found for mediaSize_iso_a6 (8585038048674911907) --> - <skip /> - <!-- no translation found for mediaSize_iso_a7 (6641836716963839119) --> - <skip /> - <!-- no translation found for mediaSize_iso_a8 (7571139437465693355) --> - <skip /> - <!-- no translation found for mediaSize_iso_a9 (1378455891957115079) --> - <skip /> - <!-- no translation found for mediaSize_iso_a10 (2480747457429475344) --> - <skip /> - <!-- no translation found for mediaSize_iso_b0 (3965935097661108039) --> - <skip /> - <!-- no translation found for mediaSize_iso_b1 (2505753285010115437) --> - <skip /> - <!-- no translation found for mediaSize_iso_b2 (8763874709859458453) --> - <skip /> - <!-- no translation found for mediaSize_iso_b3 (4210506688191764076) --> - <skip /> - <!-- no translation found for mediaSize_iso_b4 (5749404165888526034) --> - <skip /> - <!-- no translation found for mediaSize_iso_b5 (7640627414621904733) --> - <skip /> - <!-- no translation found for mediaSize_iso_b6 (7342988864712748544) --> - <skip /> - <!-- no translation found for mediaSize_iso_b7 (5069844065235382429) --> + <string name="mediaSize_iso_a0" msgid="7875427489420821793">"ISO A0"</string> + <string name="mediaSize_iso_a1" msgid="3760734499050875356">"ISO A1"</string> + <string name="mediaSize_iso_a2" msgid="5973266378020144382">"ISO A2"</string> + <string name="mediaSize_iso_a3" msgid="1373407105687300884">"ISO A3"</string> + <string name="mediaSize_iso_a4" msgid="6689772807982597254">"ISO A4"</string> + <string name="mediaSize_iso_a5" msgid="5353549652015741040">"ISO A5"</string> + <string name="mediaSize_iso_a6" msgid="8585038048674911907">"ISO A6"</string> + <string name="mediaSize_iso_a7" msgid="6641836716963839119">"ISO A7"</string> + <string name="mediaSize_iso_a8" msgid="7571139437465693355">"ISO A8"</string> + <string name="mediaSize_iso_a9" msgid="1378455891957115079">"ISO A9"</string> + <string name="mediaSize_iso_a10" msgid="2480747457429475344">"ISO A10"</string> + <string name="mediaSize_iso_b0" msgid="3965935097661108039">"ISO B0"</string> + <string name="mediaSize_iso_b1" msgid="2505753285010115437">"ISO B1"</string> + <string name="mediaSize_iso_b2" msgid="8763874709859458453">"ISO B2"</string> + <string name="mediaSize_iso_b3" msgid="4210506688191764076">"ISO B3"</string> + <string name="mediaSize_iso_b4" msgid="5749404165888526034">"ISO B4"</string> + <string name="mediaSize_iso_b5" msgid="7640627414621904733">"ISO B5"</string> + <string name="mediaSize_iso_b6" msgid="7342988864712748544">"ISO B6"</string> + <string name="mediaSize_iso_b7" msgid="5069844065235382429">"ISO B7"</string> + <string name="mediaSize_iso_b8" msgid="7316818922278779774">"ISO B8"</string> + <string name="mediaSize_iso_b9" msgid="5414727094026532341">"ISO B9"</string> + <string name="mediaSize_iso_b10" msgid="5251253731832048185">"ISO B10"</string> + <string name="mediaSize_iso_c0" msgid="4003138342671964217">"ISO C0"</string> + <string name="mediaSize_iso_c1" msgid="1935188063393553008">"ISO C1"</string> + <string name="mediaSize_iso_c2" msgid="3197307969712069904">"ISO C2"</string> + <string name="mediaSize_iso_c3" msgid="4335826087321913508">"ISO C3"</string> + <string name="mediaSize_iso_c4" msgid="3745639598281015005">"ISO C4"</string> + <string name="mediaSize_iso_c5" msgid="8269457765822791013">"ISO C5"</string> + <string name="mediaSize_iso_c6" msgid="566666105260346930">"ISO C6"</string> + <string name="mediaSize_iso_c7" msgid="8678413180782608498">"ISO C7"</string> + <string name="mediaSize_iso_c8" msgid="8392376206627041730">"ISO C8"</string> + <string name="mediaSize_iso_c9" msgid="9191613372324845405">"ISO C9"</string> + <string name="mediaSize_iso_c10" msgid="7327709699184920822">"ISO C10"</string> + <string name="mediaSize_na_letter" msgid="4191805615829472953">"Letter"</string> + <string name="mediaSize_na_gvrnmt_letter" msgid="7853382192649405507">"Government Letter"</string> + <string name="mediaSize_na_legal" msgid="6697982988283823150">"Legal"</string> + <string name="mediaSize_na_junior_legal" msgid="3727743969902758948">"Junior Legal"</string> + <string name="mediaSize_na_ledger" msgid="281871464896601236">"Ledger"</string> + <string name="mediaSize_na_tabloid" msgid="5775966416333578127">"Tabloid"</string> + <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"Zrušené"</string> + <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"Pri zapisovaní obsahu došlo k chybe"</string> + <string name="restr_pin_enter_pin" msgid="3395953421368476103">"Zadajte kód PIN"</string> + <!-- no translation found for restr_pin_enter_old_pin (1462206225512910757) --> <skip /> - <!-- no translation found for mediaSize_iso_b8 (7316818922278779774) --> + <!-- no translation found for restr_pin_enter_new_pin (5959606691619959184) --> <skip /> - <!-- no translation found for mediaSize_iso_b9 (5414727094026532341) --> + <!-- no translation found for restr_pin_confirm_pin (8501523829633146239) --> <skip /> - <!-- no translation found for mediaSize_iso_b10 (5251253731832048185) --> - <skip /> - <!-- no translation found for mediaSize_iso_c0 (4003138342671964217) --> - <skip /> - <!-- no translation found for mediaSize_iso_c1 (1935188063393553008) --> - <skip /> - <!-- no translation found for mediaSize_iso_c2 (3197307969712069904) --> - <skip /> - <!-- no translation found for mediaSize_iso_c3 (4335826087321913508) --> - <skip /> - <!-- no translation found for mediaSize_iso_c4 (3745639598281015005) --> - <skip /> - <!-- no translation found for mediaSize_iso_c5 (8269457765822791013) --> - <skip /> - <!-- no translation found for mediaSize_iso_c6 (566666105260346930) --> - <skip /> - <!-- no translation found for mediaSize_iso_c7 (8678413180782608498) --> - <skip /> - <!-- no translation found for mediaSize_iso_c8 (8392376206627041730) --> - <skip /> - <!-- no translation found for mediaSize_iso_c9 (9191613372324845405) --> - <skip /> - <!-- no translation found for mediaSize_iso_c10 (7327709699184920822) --> - <skip /> - <!-- no translation found for mediaSize_na_letter (4191805615829472953) --> - <skip /> - <!-- no translation found for mediaSize_na_gvrnmt_letter (7853382192649405507) --> - <skip /> - <!-- no translation found for mediaSize_na_legal (6697982988283823150) --> - <skip /> - <!-- no translation found for mediaSize_na_junior_legal (3727743969902758948) --> - <skip /> - <!-- no translation found for mediaSize_na_ledger (281871464896601236) --> - <skip /> - <!-- no translation found for mediaSize_na_tabloid (5775966416333578127) --> - <skip /> - <!-- no translation found for restr_pin_create_pin (8017600000263450337) --> - <skip /> - <!-- no translation found for restr_pin_enter_pin (3395953421368476103) --> - <skip /> - <!-- no translation found for restr_pin_confirm_pin (2891475237150965991) --> - <skip /> - <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) --> - <skip /> - <!-- no translation found for restr_pin_error_too_short (8173982756265777792) --> - <skip /> - <!-- no translation found for restr_pin_countdown:one (4835639969503729874) --> - <!-- no translation found for restr_pin_countdown:other (8030607343223287654) --> + <string name="restr_pin_create_pin" msgid="8017600000263450337">"Vytvoriť kód PIN pre obmedzenia upravovania"</string> + <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"Kódy PIN sa nezhodujú. Skúste to znova."</string> + <string name="restr_pin_error_too_short" msgid="8173982756265777792">"Kód PIN je príliš krátky. Musí mať minimálne 4 číslice."</string> + <plurals name="restr_pin_countdown"> + <item quantity="one" msgid="4835639969503729874">"Nespr. PIN. Skús. o 1 s"</item> + <item quantity="other" msgid="8030607343223287654">"Nespr. PIN. Skús. o <xliff:g id="COUNT">%d</xliff:g> s"</item> + </plurals> </resources> diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml index ffbae22..f303f66 100644 --- a/core/res/res/values-sl/strings.xml +++ b/core/res/res/values-sl/strings.xml @@ -279,10 +279,8 @@ <string name="permdesc_reorderTasks" msgid="7734217754877439351">"Aplikaciji omogoča premikanje opravil v ospredje in ozadje. Aplikacija lahko to naredi brez vašega nadzora."</string> <string name="permlab_removeTasks" msgid="6821513401870377403">"ustavitev programov, ki se izvajajo"</string> <string name="permdesc_removeTasks" msgid="1394714352062635493">"Programu omogoča odstranjevanje opravil in zapiranje njihovih programov. Zlonamerni programi lahko motijo delovanje drugih programov."</string> - <!-- no translation found for permlab_manageActivityStacks (7391191384027303065) --> - <skip /> - <!-- no translation found for permdesc_manageActivityStacks (1615881933034084440) --> - <skip /> + <string name="permlab_manageActivityStacks" msgid="7391191384027303065">"upravljanje skladov dejavnosti"</string> + <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"Aplikaciji omogoča dodajanje, odstranjevanje in spreminjanje skladov dejavnosti, v katerih se izvajajo druge aplikacije. Zlonamerne aplikacije lahko motijo delovanje drugih aplikacij."</string> <string name="permlab_startAnyActivity" msgid="2918768238045206456">"zagon poljubne dejavnosti"</string> <string name="permdesc_startAnyActivity" msgid="997823695343584001">"Omogoča aplikaciji zagon poljubne dejavnosti, ne glede na zaščito dovoljenj ali izvoženo stanje."</string> <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"nastavitev združljivosti zaslona"</string> @@ -360,14 +358,10 @@ <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Lastniku omogoča, da se poveže z vmesnikom načina vnosa najvišje ravni. Tega nikoli ni treba uporabiti za navadne programe."</string> <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"povezovanje s storitvijo za ljudi s posebnimi potrebami"</string> <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Lastniku omogoča povezovanje z vmesnikom najvišje ravni storitve za ljudi s posebnimi potrebami. Tega nikoli ni treba uporabiti za navadne aplikacije."</string> - <!-- no translation found for permlab_bindPrintService (8462815179572748761) --> - <skip /> - <!-- no translation found for permdesc_bindPrintService (7960067623209111135) --> - <skip /> - <!-- no translation found for permlab_accessAllPrintJobs (1120792468465711159) --> - <skip /> - <!-- no translation found for permdesc_accessAllPrintJobs (2978185311041864762) --> - <skip /> + <string name="permlab_bindPrintService" msgid="8462815179572748761">"vezava na storitev tiskanja"</string> + <string name="permdesc_bindPrintService" msgid="7960067623209111135">"Lastniku omogoča povezovanje z vmesnikom storitve tiskanja najvišje ravni. Tega nikoli ni treba uporabiti za navadne aplikacije."</string> + <string name="permlab_accessAllPrintJobs" msgid="1120792468465711159">"dostop do vseh tiskalnih poslov"</string> + <string name="permdesc_accessAllPrintJobs" msgid="2978185311041864762">"Lastniku omogoča dostop do tiskalnih poslov, ki jih je ustvarila druga aplikacija. Tega nikoli ni treba uporabiti za navadne aplikacije."</string> <string name="permlab_bindTextService" msgid="7358378401915287938">"poveži z besedilno storitvijo"</string> <string name="permdesc_bindTextService" msgid="8151968910973998670">"Dovoljuje, da se lastnik poveže z vmesnikom besedilne storitve najvišje ravni (npr. SpellCheckerService). Tega nikoli ni treba uporabiti za navadne programe."</string> <string name="permlab_bindVpnService" msgid="4708596021161473255">"povezava s storitvijo navideznega zasebnega omrežja"</string> @@ -470,6 +464,8 @@ <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Programu omogoča uporabo funkcij nizke ravni SurfaceFlinger."</string> <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"branje grafičnega/slikovnega medpomnilnika"</string> <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Programu omogoča branje vsebine grafičnega/slikovnega medpomnilnika."</string> + <string name="permlab_accessInputFlinger" msgid="5348635270689553857">"dostop do funkcij InputFlinger"</string> + <string name="permdesc_accessInputFlinger" msgid="2104864941201226616">"Aplikaciji dovoljuje uporabo funkcij InputFlinger nizke ravni."</string> <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"konfiguriranje zaslonov Wi-Fi"</string> <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Omogoča aplikaciji konfiguriranje zaslonov Wi-Fi in povezovanje z njimi."</string> <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"nadzor zaslonov Wi-Fi"</string> @@ -639,10 +635,14 @@ <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Programu omogoča upravljanje pravilnikov o omrežju in določanje pravil za program."</string> <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"spremeni obračunavanje uporabe omrežja"</string> <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Programu omogoča, da spremeni uporabo omrežja na podlagi programov. Ni za uporabo z navadnimi programi."</string> + <string name="permlab_markNetworkSocket" msgid="3658527214914959749">"spreminjanje oznak vtičnic"</string> + <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"Aplikaciji omogoča spreminjanje oznak vtičnic za usmerjanje"</string> <string name="permlab_accessNotifications" msgid="7673416487873432268">"dostop do obvestil"</string> <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_invokeCarrierSetup" msgid="3699600833975117478">"priklic operaterjeve aplikacije za konfiguracijo"</string> + <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Lastniku omogoča sproženje operaterjeve aplikacije za konfiguracijo. Tega nikoli ni treba uporabiti za navadne aplikacije."</string> <string name="policylab_limitPassword" msgid="4497420728857585791">"Nastavitev pravil za geslo"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"Nadzor nad dolžino in znaki, ki so dovoljeni v geslih za odklepanje zaslona."</string> <string name="policylab_watchLogin" msgid="914130646942199503">"nadzor nad poskusi odklepanja zaslona"</string> @@ -752,8 +752,7 @@ <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string> <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string> <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string> - <!-- no translation found for imProtocolGoogleTalk (493902321140277304) --> - <skip /> + <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangouts"</string> <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string> <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string> <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string> @@ -1515,94 +1514,59 @@ <string name="app_no_restricted_accounts" msgid="5739463249673727736">"Ta aplikacija ne podpira računov za profile z omejitvami"</string> <string name="app_not_found" msgid="3429141853498927379">"Najdena ni bila nobena aplikacija za izvedbo tega dejanja"</string> <string name="revoke" msgid="5404479185228271586">"Prekliči"</string> - <!-- no translation found for mediaSize_iso_a0 (7875427489420821793) --> - <skip /> - <!-- no translation found for mediaSize_iso_a1 (3760734499050875356) --> - <skip /> - <!-- no translation found for mediaSize_iso_a2 (5973266378020144382) --> - <skip /> - <!-- no translation found for mediaSize_iso_a3 (1373407105687300884) --> - <skip /> - <!-- no translation found for mediaSize_iso_a4 (6689772807982597254) --> - <skip /> - <!-- no translation found for mediaSize_iso_a5 (5353549652015741040) --> - <skip /> - <!-- no translation found for mediaSize_iso_a6 (8585038048674911907) --> - <skip /> - <!-- no translation found for mediaSize_iso_a7 (6641836716963839119) --> - <skip /> - <!-- no translation found for mediaSize_iso_a8 (7571139437465693355) --> - <skip /> - <!-- no translation found for mediaSize_iso_a9 (1378455891957115079) --> - <skip /> - <!-- no translation found for mediaSize_iso_a10 (2480747457429475344) --> - <skip /> - <!-- no translation found for mediaSize_iso_b0 (3965935097661108039) --> - <skip /> - <!-- no translation found for mediaSize_iso_b1 (2505753285010115437) --> - <skip /> - <!-- no translation found for mediaSize_iso_b2 (8763874709859458453) --> - <skip /> - <!-- no translation found for mediaSize_iso_b3 (4210506688191764076) --> - <skip /> - <!-- no translation found for mediaSize_iso_b4 (5749404165888526034) --> - <skip /> - <!-- no translation found for mediaSize_iso_b5 (7640627414621904733) --> - <skip /> - <!-- no translation found for mediaSize_iso_b6 (7342988864712748544) --> - <skip /> - <!-- no translation found for mediaSize_iso_b7 (5069844065235382429) --> + <string name="mediaSize_iso_a0" msgid="7875427489420821793">"ISO A0"</string> + <string name="mediaSize_iso_a1" msgid="3760734499050875356">"ISO A1"</string> + <string name="mediaSize_iso_a2" msgid="5973266378020144382">"ISO A2"</string> + <string name="mediaSize_iso_a3" msgid="1373407105687300884">"ISO A3"</string> + <string name="mediaSize_iso_a4" msgid="6689772807982597254">"ISO A4"</string> + <string name="mediaSize_iso_a5" msgid="5353549652015741040">"ISO A5"</string> + <string name="mediaSize_iso_a6" msgid="8585038048674911907">"ISO A6"</string> + <string name="mediaSize_iso_a7" msgid="6641836716963839119">"ISO A7"</string> + <string name="mediaSize_iso_a8" msgid="7571139437465693355">"ISO A8"</string> + <string name="mediaSize_iso_a9" msgid="1378455891957115079">"ISO A9"</string> + <string name="mediaSize_iso_a10" msgid="2480747457429475344">"ISO A10"</string> + <string name="mediaSize_iso_b0" msgid="3965935097661108039">"ISO B0"</string> + <string name="mediaSize_iso_b1" msgid="2505753285010115437">"ISO B1"</string> + <string name="mediaSize_iso_b2" msgid="8763874709859458453">"ISO B2"</string> + <string name="mediaSize_iso_b3" msgid="4210506688191764076">"ISO B3"</string> + <string name="mediaSize_iso_b4" msgid="5749404165888526034">"ISO B4"</string> + <string name="mediaSize_iso_b5" msgid="7640627414621904733">"ISO B5"</string> + <string name="mediaSize_iso_b6" msgid="7342988864712748544">"ISO B6"</string> + <string name="mediaSize_iso_b7" msgid="5069844065235382429">"ISO B7"</string> + <string name="mediaSize_iso_b8" msgid="7316818922278779774">"ISO B8"</string> + <string name="mediaSize_iso_b9" msgid="5414727094026532341">"ISO B9"</string> + <string name="mediaSize_iso_b10" msgid="5251253731832048185">"ISO B10"</string> + <string name="mediaSize_iso_c0" msgid="4003138342671964217">"ISO C0"</string> + <string name="mediaSize_iso_c1" msgid="1935188063393553008">"ISO C1"</string> + <string name="mediaSize_iso_c2" msgid="3197307969712069904">"ISO C2"</string> + <string name="mediaSize_iso_c3" msgid="4335826087321913508">"ISO C3"</string> + <string name="mediaSize_iso_c4" msgid="3745639598281015005">"ISO C4"</string> + <string name="mediaSize_iso_c5" msgid="8269457765822791013">"ISO C5"</string> + <string name="mediaSize_iso_c6" msgid="566666105260346930">"ISO C6"</string> + <string name="mediaSize_iso_c7" msgid="8678413180782608498">"ISO C7"</string> + <string name="mediaSize_iso_c8" msgid="8392376206627041730">"ISO C8"</string> + <string name="mediaSize_iso_c9" msgid="9191613372324845405">"ISO C9"</string> + <string name="mediaSize_iso_c10" msgid="7327709699184920822">"ISO C10"</string> + <string name="mediaSize_na_letter" msgid="4191805615829472953">"Letter"</string> + <string name="mediaSize_na_gvrnmt_letter" msgid="7853382192649405507">"Government Letter"</string> + <string name="mediaSize_na_legal" msgid="6697982988283823150">"Legal"</string> + <string name="mediaSize_na_junior_legal" msgid="3727743969902758948">"Junior Legal"</string> + <string name="mediaSize_na_ledger" msgid="281871464896601236">"Ledger"</string> + <string name="mediaSize_na_tabloid" msgid="5775966416333578127">"Tabloid"</string> + <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"Preklicano"</string> + <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"Napaka pri pisanju vsebine"</string> + <string name="restr_pin_enter_pin" msgid="3395953421368476103">"Vnesite PIN"</string> + <!-- no translation found for restr_pin_enter_old_pin (1462206225512910757) --> <skip /> - <!-- no translation found for mediaSize_iso_b8 (7316818922278779774) --> + <!-- no translation found for restr_pin_enter_new_pin (5959606691619959184) --> <skip /> - <!-- no translation found for mediaSize_iso_b9 (5414727094026532341) --> + <!-- no translation found for restr_pin_confirm_pin (8501523829633146239) --> <skip /> - <!-- no translation found for mediaSize_iso_b10 (5251253731832048185) --> - <skip /> - <!-- no translation found for mediaSize_iso_c0 (4003138342671964217) --> - <skip /> - <!-- no translation found for mediaSize_iso_c1 (1935188063393553008) --> - <skip /> - <!-- no translation found for mediaSize_iso_c2 (3197307969712069904) --> - <skip /> - <!-- no translation found for mediaSize_iso_c3 (4335826087321913508) --> - <skip /> - <!-- no translation found for mediaSize_iso_c4 (3745639598281015005) --> - <skip /> - <!-- no translation found for mediaSize_iso_c5 (8269457765822791013) --> - <skip /> - <!-- no translation found for mediaSize_iso_c6 (566666105260346930) --> - <skip /> - <!-- no translation found for mediaSize_iso_c7 (8678413180782608498) --> - <skip /> - <!-- no translation found for mediaSize_iso_c8 (8392376206627041730) --> - <skip /> - <!-- no translation found for mediaSize_iso_c9 (9191613372324845405) --> - <skip /> - <!-- no translation found for mediaSize_iso_c10 (7327709699184920822) --> - <skip /> - <!-- no translation found for mediaSize_na_letter (4191805615829472953) --> - <skip /> - <!-- no translation found for mediaSize_na_gvrnmt_letter (7853382192649405507) --> - <skip /> - <!-- no translation found for mediaSize_na_legal (6697982988283823150) --> - <skip /> - <!-- no translation found for mediaSize_na_junior_legal (3727743969902758948) --> - <skip /> - <!-- no translation found for mediaSize_na_ledger (281871464896601236) --> - <skip /> - <!-- no translation found for mediaSize_na_tabloid (5775966416333578127) --> - <skip /> - <!-- no translation found for restr_pin_create_pin (8017600000263450337) --> - <skip /> - <!-- no translation found for restr_pin_enter_pin (3395953421368476103) --> - <skip /> - <!-- no translation found for restr_pin_confirm_pin (2891475237150965991) --> - <skip /> - <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) --> - <skip /> - <!-- no translation found for restr_pin_error_too_short (8173982756265777792) --> - <skip /> - <!-- no translation found for restr_pin_countdown:one (4835639969503729874) --> - <!-- no translation found for restr_pin_countdown:other (8030607343223287654) --> + <string name="restr_pin_create_pin" msgid="8017600000263450337">"Ustvarite PIN za spreminjanje omejitev"</string> + <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"Kodi PIN se ne ujemata. Poskusite znova."</string> + <string name="restr_pin_error_too_short" msgid="8173982756265777792">"PIN je prekratek. Imeti mora vsaj 4 števke."</string> + <plurals name="restr_pin_countdown"> + <item quantity="one" msgid="4835639969503729874">"Napačen PIN. Poskusite znova čez eno sekundo."</item> + <item quantity="other" msgid="8030607343223287654">"Napačen PIN. Poskusite znova čez <xliff:g id="COUNT">%d</xliff:g> s."</item> + </plurals> </resources> diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml index 7465798..74ef9e4 100644 --- a/core/res/res/values-sr/strings.xml +++ b/core/res/res/values-sr/strings.xml @@ -279,10 +279,8 @@ <string name="permdesc_reorderTasks" msgid="7734217754877439351">"Дозвољава апликацији да премешта задатке у први план и у позадину. Апликација може да ради ово без вашег уноса."</string> <string name="permlab_removeTasks" msgid="6821513401870377403">"заустављање покренутих апликација"</string> <string name="permdesc_removeTasks" msgid="1394714352062635493">"Дозвољава апликацији да уклања задатке и уништава њихове апликације. Злонамерне апликације могу да поремете понашање других апликација."</string> - <!-- no translation found for permlab_manageActivityStacks (7391191384027303065) --> - <skip /> - <!-- no translation found for permdesc_manageActivityStacks (1615881933034084440) --> - <skip /> + <string name="permlab_manageActivityStacks" msgid="7391191384027303065">"управљање групама активности"</string> + <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"Дозвољава апликацији да додаје, уклања и мења групе активности у којима се покрећу друге апликације. Злонамерне апликације могу да поремете понашање других апликација."</string> <string name="permlab_startAnyActivity" msgid="2918768238045206456">"покретање било које активности"</string> <string name="permdesc_startAnyActivity" msgid="997823695343584001">"Омогућава да апликација покрене било коју активност, без обзира на заштиту дозволе или стање извоза."</string> <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"подешавање компатибилности екрана"</string> @@ -360,14 +358,10 @@ <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Омогућава да се власник обавеже на интерфејс методе уноса највишег нивоа. Уобичајене апликације никада не би требало да је користе."</string> <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"повезивање са услугом приступачности"</string> <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Дозвољава власнику да се повеже са интерфејсом услуге приступачности највишег нивоа. Уобичајене апликације никада не би требало да је користе."</string> - <!-- no translation found for permlab_bindPrintService (8462815179572748761) --> - <skip /> - <!-- no translation found for permdesc_bindPrintService (7960067623209111135) --> - <skip /> - <!-- no translation found for permlab_accessAllPrintJobs (1120792468465711159) --> - <skip /> - <!-- no translation found for permdesc_accessAllPrintJobs (2978185311041864762) --> - <skip /> + <string name="permlab_bindPrintService" msgid="8462815179572748761">"повезивање са услугом штампања"</string> + <string name="permdesc_bindPrintService" msgid="7960067623209111135">"Дозвољава власнику да се повеже са интерфејсом услуге штампања највишег нивоа. Уобичајене апликације никада не би требало да је користе."</string> + <string name="permlab_accessAllPrintJobs" msgid="1120792468465711159">"приступ свим задацима за штампање"</string> + <string name="permdesc_accessAllPrintJobs" msgid="2978185311041864762">"Дозвољава власнику да приступа задацима за штампање које је направила друга апликација. Уобичајене апликације никада не би требало да је користе."</string> <string name="permlab_bindTextService" msgid="7358378401915287938">"обавезивање на текстуалну услугу"</string> <string name="permdesc_bindTextService" msgid="8151968910973998670">"Омогућава власнику да се обавеже на интерфејс текстуалне услуге највишег нивоа (нпр. SpellCheckerService). Обичне апликације никада не би требало да је користе."</string> <string name="permlab_bindVpnService" msgid="4708596021161473255">"везивање за VPN услугу"</string> @@ -470,6 +464,8 @@ <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Дозвољава апликацији да користи SurfaceFlinger функције ниског нивоа."</string> <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"читање бафера кадрова"</string> <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Дозвољава апликацији да чита садржај међумеморије кадрова."</string> + <string name="permlab_accessInputFlinger" msgid="5348635270689553857">"приступ InputFlinger функцијама"</string> + <string name="permdesc_accessInputFlinger" msgid="2104864941201226616">"Дозвољава апликацији да користи InputFlinger функције ниског нивоа."</string> <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"конфигурисање Wi-Fi екрана"</string> <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Дозвољава апликацији да конфигурише Wi-Fi екране и повезује се са њима."</string> <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"контрола Wi-Fi екрана"</string> @@ -639,10 +635,14 @@ <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Дозвољава апликацији да управља смерницама за мрежу и одређује посебна правила за апликацију."</string> <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"измените обрачунавање коришћења мреже"</string> <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Дозвољава апликацији да измени начин на који апликације користе мрежу. Не користе је уобичајене апликације."</string> + <string name="permlab_markNetworkSocket" msgid="3658527214914959749">"измена ознака утичнице"</string> + <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"Дозвољава апликацији да мења ознаке утичнице за усмеравање"</string> <string name="permlab_accessNotifications" msgid="7673416487873432268">"приступ обавештењима"</string> <string name="permdesc_accessNotifications" msgid="458457742683431387">"Дозвољава апликацији да преузима, испитује и брише обавештења, укључујући она која постављају друге апликације."</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"повезивање са услугом монитора обавештења"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Дозвољава власнику да се повеже са интерфејсом услуге монитора обавештења највишег нивоа. Уобичајене апликације никада не би требало да је користе."</string> + <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"позивање апликације са конфигурацијом коју одређује оператер"</string> + <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Дозвољава власнику да позива апликацију са конфигурацијом коју одређује оператер. Уобичајене апликације никада не би требало да је користе."</string> <string name="policylab_limitPassword" msgid="4497420728857585791">"Подешавање правила за лозинку"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"Контролишите дужину и знакове дозвољене у лозинкама за откључавање екрана."</string> <string name="policylab_watchLogin" msgid="914130646942199503">"Надгледање покушаја откључавања екрана"</string> @@ -752,8 +752,7 @@ <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string> <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string> <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string> - <!-- no translation found for imProtocolGoogleTalk (493902321140277304) --> - <skip /> + <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangouts"</string> <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string> <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string> <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string> @@ -1515,94 +1514,59 @@ <string name="app_no_restricted_accounts" msgid="5739463249673727736">"Ова апликација не подржава налоге за ограничене профиле"</string> <string name="app_not_found" msgid="3429141853498927379">"Није пронађена ниједна апликација која би могла да обави ову радњу"</string> <string name="revoke" msgid="5404479185228271586">"Опозови"</string> - <!-- no translation found for mediaSize_iso_a0 (7875427489420821793) --> - <skip /> - <!-- no translation found for mediaSize_iso_a1 (3760734499050875356) --> - <skip /> - <!-- no translation found for mediaSize_iso_a2 (5973266378020144382) --> - <skip /> - <!-- no translation found for mediaSize_iso_a3 (1373407105687300884) --> - <skip /> - <!-- no translation found for mediaSize_iso_a4 (6689772807982597254) --> - <skip /> - <!-- no translation found for mediaSize_iso_a5 (5353549652015741040) --> - <skip /> - <!-- no translation found for mediaSize_iso_a6 (8585038048674911907) --> - <skip /> - <!-- no translation found for mediaSize_iso_a7 (6641836716963839119) --> - <skip /> - <!-- no translation found for mediaSize_iso_a8 (7571139437465693355) --> - <skip /> - <!-- no translation found for mediaSize_iso_a9 (1378455891957115079) --> - <skip /> - <!-- no translation found for mediaSize_iso_a10 (2480747457429475344) --> - <skip /> - <!-- no translation found for mediaSize_iso_b0 (3965935097661108039) --> - <skip /> - <!-- no translation found for mediaSize_iso_b1 (2505753285010115437) --> - <skip /> - <!-- no translation found for mediaSize_iso_b2 (8763874709859458453) --> - <skip /> - <!-- no translation found for mediaSize_iso_b3 (4210506688191764076) --> - <skip /> - <!-- no translation found for mediaSize_iso_b4 (5749404165888526034) --> - <skip /> - <!-- no translation found for mediaSize_iso_b5 (7640627414621904733) --> - <skip /> - <!-- no translation found for mediaSize_iso_b6 (7342988864712748544) --> - <skip /> - <!-- no translation found for mediaSize_iso_b7 (5069844065235382429) --> + <string name="mediaSize_iso_a0" msgid="7875427489420821793">"ISO A0"</string> + <string name="mediaSize_iso_a1" msgid="3760734499050875356">"ISO A1"</string> + <string name="mediaSize_iso_a2" msgid="5973266378020144382">"ISO A2"</string> + <string name="mediaSize_iso_a3" msgid="1373407105687300884">"ISO A3"</string> + <string name="mediaSize_iso_a4" msgid="6689772807982597254">"ISO A4"</string> + <string name="mediaSize_iso_a5" msgid="5353549652015741040">"ISO A5"</string> + <string name="mediaSize_iso_a6" msgid="8585038048674911907">"ISO A6"</string> + <string name="mediaSize_iso_a7" msgid="6641836716963839119">"ISO A7"</string> + <string name="mediaSize_iso_a8" msgid="7571139437465693355">"ISO A8"</string> + <string name="mediaSize_iso_a9" msgid="1378455891957115079">"ISO A9"</string> + <string name="mediaSize_iso_a10" msgid="2480747457429475344">"ISO A10"</string> + <string name="mediaSize_iso_b0" msgid="3965935097661108039">"ISO B0"</string> + <string name="mediaSize_iso_b1" msgid="2505753285010115437">"ISO B1"</string> + <string name="mediaSize_iso_b2" msgid="8763874709859458453">"ISO B2"</string> + <string name="mediaSize_iso_b3" msgid="4210506688191764076">"ISO B3"</string> + <string name="mediaSize_iso_b4" msgid="5749404165888526034">"ISO B4"</string> + <string name="mediaSize_iso_b5" msgid="7640627414621904733">"ISO B5"</string> + <string name="mediaSize_iso_b6" msgid="7342988864712748544">"ISO B6"</string> + <string name="mediaSize_iso_b7" msgid="5069844065235382429">"ISO B7"</string> + <string name="mediaSize_iso_b8" msgid="7316818922278779774">"ISO B8"</string> + <string name="mediaSize_iso_b9" msgid="5414727094026532341">"ISO B9"</string> + <string name="mediaSize_iso_b10" msgid="5251253731832048185">"ISO B10"</string> + <string name="mediaSize_iso_c0" msgid="4003138342671964217">"ISO C0"</string> + <string name="mediaSize_iso_c1" msgid="1935188063393553008">"ISO C1"</string> + <string name="mediaSize_iso_c2" msgid="3197307969712069904">"ISO C2"</string> + <string name="mediaSize_iso_c3" msgid="4335826087321913508">"ISO C3"</string> + <string name="mediaSize_iso_c4" msgid="3745639598281015005">"ISO C4"</string> + <string name="mediaSize_iso_c5" msgid="8269457765822791013">"ISO C5"</string> + <string name="mediaSize_iso_c6" msgid="566666105260346930">"ISO C6"</string> + <string name="mediaSize_iso_c7" msgid="8678413180782608498">"ISO C7"</string> + <string name="mediaSize_iso_c8" msgid="8392376206627041730">"ISO C8"</string> + <string name="mediaSize_iso_c9" msgid="9191613372324845405">"ISO C9"</string> + <string name="mediaSize_iso_c10" msgid="7327709699184920822">"ISO C10"</string> + <string name="mediaSize_na_letter" msgid="4191805615829472953">"Letter"</string> + <string name="mediaSize_na_gvrnmt_letter" msgid="7853382192649405507">"Government Letter"</string> + <string name="mediaSize_na_legal" msgid="6697982988283823150">"Legal"</string> + <string name="mediaSize_na_junior_legal" msgid="3727743969902758948">"Junior Legal"</string> + <string name="mediaSize_na_ledger" msgid="281871464896601236">"Ledger"</string> + <string name="mediaSize_na_tabloid" msgid="5775966416333578127">"Tabloid"</string> + <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"Отказано је"</string> + <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"Грешка при исписивању садржаја"</string> + <string name="restr_pin_enter_pin" msgid="3395953421368476103">"Унесите PIN"</string> + <!-- no translation found for restr_pin_enter_old_pin (1462206225512910757) --> <skip /> - <!-- no translation found for mediaSize_iso_b8 (7316818922278779774) --> + <!-- no translation found for restr_pin_enter_new_pin (5959606691619959184) --> <skip /> - <!-- no translation found for mediaSize_iso_b9 (5414727094026532341) --> + <!-- no translation found for restr_pin_confirm_pin (8501523829633146239) --> <skip /> - <!-- no translation found for mediaSize_iso_b10 (5251253731832048185) --> - <skip /> - <!-- no translation found for mediaSize_iso_c0 (4003138342671964217) --> - <skip /> - <!-- no translation found for mediaSize_iso_c1 (1935188063393553008) --> - <skip /> - <!-- no translation found for mediaSize_iso_c2 (3197307969712069904) --> - <skip /> - <!-- no translation found for mediaSize_iso_c3 (4335826087321913508) --> - <skip /> - <!-- no translation found for mediaSize_iso_c4 (3745639598281015005) --> - <skip /> - <!-- no translation found for mediaSize_iso_c5 (8269457765822791013) --> - <skip /> - <!-- no translation found for mediaSize_iso_c6 (566666105260346930) --> - <skip /> - <!-- no translation found for mediaSize_iso_c7 (8678413180782608498) --> - <skip /> - <!-- no translation found for mediaSize_iso_c8 (8392376206627041730) --> - <skip /> - <!-- no translation found for mediaSize_iso_c9 (9191613372324845405) --> - <skip /> - <!-- no translation found for mediaSize_iso_c10 (7327709699184920822) --> - <skip /> - <!-- no translation found for mediaSize_na_letter (4191805615829472953) --> - <skip /> - <!-- no translation found for mediaSize_na_gvrnmt_letter (7853382192649405507) --> - <skip /> - <!-- no translation found for mediaSize_na_legal (6697982988283823150) --> - <skip /> - <!-- no translation found for mediaSize_na_junior_legal (3727743969902758948) --> - <skip /> - <!-- no translation found for mediaSize_na_ledger (281871464896601236) --> - <skip /> - <!-- no translation found for mediaSize_na_tabloid (5775966416333578127) --> - <skip /> - <!-- no translation found for restr_pin_create_pin (8017600000263450337) --> - <skip /> - <!-- no translation found for restr_pin_enter_pin (3395953421368476103) --> - <skip /> - <!-- no translation found for restr_pin_confirm_pin (2891475237150965991) --> - <skip /> - <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) --> - <skip /> - <!-- no translation found for restr_pin_error_too_short (8173982756265777792) --> - <skip /> - <!-- no translation found for restr_pin_countdown:one (4835639969503729874) --> - <!-- no translation found for restr_pin_countdown:other (8030607343223287654) --> + <string name="restr_pin_create_pin" msgid="8017600000263450337">"Направите PIN за измену ограничења"</string> + <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PIN-ови се не подударају. Покушајте поново."</string> + <string name="restr_pin_error_too_short" msgid="8173982756265777792">"PIN је прекратак. Мора да садржи најмање 4 цифре."</string> + <plurals name="restr_pin_countdown"> + <item quantity="one" msgid="4835639969503729874">"Нетачан PIN. Покушајте опет за 1 сек."</item> + <item quantity="other" msgid="8030607343223287654">"Нетачан PIN. Покушајте опет за <xliff:g id="COUNT">%d</xliff:g> сек."</item> + </plurals> </resources> diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml index 5e39d66..cd60ac8 100644 --- a/core/res/res/values-sv/strings.xml +++ b/core/res/res/values-sv/strings.xml @@ -470,6 +470,10 @@ <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Tillåter att appen använder lågnivåfunktioner i SurfaceFlinger."</string> <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"läsa rambuffert"</string> <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Tillåter att appen läser innehållet i rambufferten."</string> + <!-- no translation found for permlab_accessInputFlinger (5348635270689553857) --> + <skip /> + <!-- no translation found for permdesc_accessInputFlinger (2104864941201226616) --> + <skip /> <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"konfigurerar Wi-Fi-skärmar"</string> <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Tillåter att appen konfigurerar och ansluter till Wi-Fi-skärmar."</string> <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"kontrollerar Wi-Fi-skärmar"</string> @@ -639,10 +643,18 @@ <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Tillåter att appen hanterar nätverkspolicyer och definierar appspecifika regler."</string> <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"ändra nätverksredovisningen"</string> <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Tillåter att appen ändrar hur nätverksanvändning redovisas för appar. Används inte av vanliga appar."</string> + <!-- no translation found for permlab_markNetworkSocket (3658527214914959749) --> + <skip /> + <!-- no translation found for permdesc_markNetworkSocket (7655568433696356578) --> + <skip /> <string name="permlab_accessNotifications" msgid="7673416487873432268">"få åtkomst till meddelanden"</string> <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> + <!-- no translation found for permlab_invokeCarrierSetup (3699600833975117478) --> + <skip /> + <!-- no translation found for permdesc_invokeCarrierSetup (4159549152529111920) --> + <skip /> <string name="policylab_limitPassword" msgid="4497420728857585791">"Ange lösenordsregler"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"Bestäm hur många och vilka tecken som är tillåtna i skärmlåsets lösenord."</string> <string name="policylab_watchLogin" msgid="914130646942199503">"Övervaka försök att låsa upp skärmen"</string> @@ -1593,11 +1605,19 @@ <skip /> <!-- no translation found for mediaSize_na_tabloid (5775966416333578127) --> <skip /> - <!-- no translation found for restr_pin_create_pin (8017600000263450337) --> + <!-- no translation found for write_fail_reason_cancelled (7091258378121627624) --> + <skip /> + <!-- no translation found for write_fail_reason_cannot_write (8132505417935337724) --> <skip /> <!-- no translation found for restr_pin_enter_pin (3395953421368476103) --> <skip /> - <!-- no translation found for restr_pin_confirm_pin (2891475237150965991) --> + <!-- no translation found for restr_pin_enter_old_pin (1462206225512910757) --> + <skip /> + <!-- no translation found for restr_pin_enter_new_pin (5959606691619959184) --> + <skip /> + <!-- no translation found for restr_pin_confirm_pin (8501523829633146239) --> + <skip /> + <!-- no translation found for restr_pin_create_pin (8017600000263450337) --> <skip /> <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) --> <skip /> diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml index 29ef9b3..0076d9a 100644 --- a/core/res/res/values-sw/strings.xml +++ b/core/res/res/values-sw/strings.xml @@ -279,10 +279,8 @@ <string name="permdesc_reorderTasks" msgid="7734217754877439351">"Inaruhusu programu kusongesha kazi hadi kwenye mandhari-mbele na mandari nyuma. Programu inaweza kufanya haya bila ya maingizo yako."</string> <string name="permlab_removeTasks" msgid="6821513401870377403">"Komesha programu zinazoendeshwa"</string> <string name="permdesc_removeTasks" msgid="1394714352062635493">"Huruhusu programu kuondoa majukumu na kuua programu zao. Programu hasidi zinaweza kutatiza tabia ya programu zingine."</string> - <!-- no translation found for permlab_manageActivityStacks (7391191384027303065) --> - <skip /> - <!-- no translation found for permdesc_manageActivityStacks (1615881933034084440) --> - <skip /> + <string name="permlab_manageActivityStacks" msgid="7391191384027303065">"dhibiti bunda za shughuli"</string> + <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"Inaruhusu programu kuongeza, kuondoa, na kubadilisha bunda za shughuli ambamo programu nyingine huendeshwa. Programu hasidi zinaweza kusitisha tabia ya programu nyingine."</string> <string name="permlab_startAnyActivity" msgid="2918768238045206456">"anzisha shughuli yoyote"</string> <string name="permdesc_startAnyActivity" msgid="997823695343584001">"Huruhusu programu kuanzisha shughuli yoyote, pasi kujali ulinzi wa idhini au hali ya nje."</string> <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"weka utangamano wa skrini"</string> @@ -360,14 +358,10 @@ <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Inaruhusu mmiliki kushurutisha kwenye kusano ya kiwango cha juu ya mbinu ya ingizo. Haipaswi kuhitajika kwa programu za kawaida."</string> <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"funga kwa huduma ya ufikiaji"</string> <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Inamuruhusu mmiliki kufunga kipengee kinachojitokeza katika nyanja mbalimbali za kiwango cha juu cha huduma ya afikiaji. Hapaswi kuhitajika kwa programu za kawaida."</string> - <!-- no translation found for permlab_bindPrintService (8462815179572748761) --> - <skip /> - <!-- no translation found for permdesc_bindPrintService (7960067623209111135) --> - <skip /> - <!-- no translation found for permlab_accessAllPrintJobs (1120792468465711159) --> - <skip /> - <!-- no translation found for permdesc_accessAllPrintJobs (2978185311041864762) --> - <skip /> + <string name="permlab_bindPrintService" msgid="8462815179572748761">"shurutisha kwenye huduma ya kuchapisha"</string> + <string name="permdesc_bindPrintService" msgid="7960067623209111135">"Inaruhusu kishikiliaji kujifungilia kiolesura cha kiwango cha juu cha huduma ya kuchapisha. Haipaswi kuhitajika kwa programu za kawaida."</string> + <string name="permlab_accessAllPrintJobs" msgid="1120792468465711159">"fikia kazi zote za kuchapisha"</string> + <string name="permdesc_accessAllPrintJobs" msgid="2978185311041864762">"Huruhusu mmiliki kufikia kazi za kuchapisha zilizoundwa na programu nyingine. Haipaswi kuhitajika kwa programu za kawaida kamwe."</string> <string name="permlab_bindTextService" msgid="7358378401915287938">"Imefungwa kwa huduma ya maandishi"</string> <string name="permdesc_bindTextService" msgid="8151968910973998670">"Inaruhusu kishikiliaji kushurutisha kusano ya kiwango cha juu ya huduma ya matini(k.m.SpellCheckerService). Haipaswi kuhitajika kwa programu za kawaida."</string> <string name="permlab_bindVpnService" msgid="4708596021161473255">"funga kwa huduma ya VPN"</string> @@ -470,6 +464,8 @@ <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Inaruhusu programu kutumia vipengee vya kiwango cha chini vya SurfaceFlinger."</string> <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"soma bafa ya fremu"</string> <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Inaruhusu programu kusoma maudhui ya fremu ya bafa."</string> + <string name="permlab_accessInputFlinger" msgid="5348635270689553857">"fikia InputFlinger"</string> + <string name="permdesc_accessInputFlinger" msgid="2104864941201226616">"Inaruhusu programu kutumia vipengele vya chini vya InputFlinger."</string> <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"sanidi maonyesho ya Wifi"</string> <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Inaruhusu programu kusanidi na kuunganika kwenye maonyesho ya Wifi."</string> <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"dhibiti maonyesho ya Wifi"</string> @@ -639,10 +635,14 @@ <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Inaruhusu programu kudhibiti sera za mtandao na kufafanua sheria maalum za programu."</string> <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"badilisha uthibitishaji wa matumizi ya mtandao"</string> <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Huruhusu programu kurekebisha jinsi matumizi ya mtandao yana hesabika dhidi ya programu. Sio ya matumizi na programu za kawaida."</string> + <string name="permlab_markNetworkSocket" msgid="3658527214914959749">"rekebisha alama za soketi"</string> + <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"Inaruhusu programu kurekebisha alama za soketi za upelekaji"</string> <string name="permlab_accessNotifications" msgid="7673416487873432268">"fikia arifa"</string> <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_invokeCarrierSetup" msgid="3699600833975117478">"omba programu ya usakinishaji inayotolewa na mto huduma."</string> + <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Inaruhusu kishikiliaji kuomba programu ya usakinishaji inayotolewa na mto huduma. Haipaswi kuhitajika kwa programu za kawaida."</string> <string name="policylab_limitPassword" msgid="4497420728857585791">"Weka kanuni za nenosiri"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"Dhibiti urefu na vibambo vinavyoruhusiwa katika manenosiri ya kufungua skrini."</string> <string name="policylab_watchLogin" msgid="914130646942199503">"Chunguza majaribio ya kutofun gua skrini"</string> @@ -752,8 +752,7 @@ <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string> <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string> <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string> - <!-- no translation found for imProtocolGoogleTalk (493902321140277304) --> - <skip /> + <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangout"</string> <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string> <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string> <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string> @@ -1515,94 +1514,56 @@ <string name="app_no_restricted_accounts" msgid="5739463249673727736">"Programu hii haiwezi kutumiwa na akaunti za wasifu zilizowekewa vikwazo"</string> <string name="app_not_found" msgid="3429141853498927379">"Hakuna programu iliyopatikana ili kushughulikia kitendo hiki"</string> <string name="revoke" msgid="5404479185228271586">"Batilisha"</string> - <!-- no translation found for mediaSize_iso_a0 (7875427489420821793) --> - <skip /> - <!-- no translation found for mediaSize_iso_a1 (3760734499050875356) --> - <skip /> - <!-- no translation found for mediaSize_iso_a2 (5973266378020144382) --> - <skip /> - <!-- no translation found for mediaSize_iso_a3 (1373407105687300884) --> - <skip /> - <!-- no translation found for mediaSize_iso_a4 (6689772807982597254) --> - <skip /> - <!-- no translation found for mediaSize_iso_a5 (5353549652015741040) --> - <skip /> - <!-- no translation found for mediaSize_iso_a6 (8585038048674911907) --> - <skip /> - <!-- no translation found for mediaSize_iso_a7 (6641836716963839119) --> - <skip /> - <!-- no translation found for mediaSize_iso_a8 (7571139437465693355) --> - <skip /> - <!-- no translation found for mediaSize_iso_a9 (1378455891957115079) --> - <skip /> - <!-- no translation found for mediaSize_iso_a10 (2480747457429475344) --> - <skip /> - <!-- no translation found for mediaSize_iso_b0 (3965935097661108039) --> - <skip /> - <!-- no translation found for mediaSize_iso_b1 (2505753285010115437) --> - <skip /> - <!-- no translation found for mediaSize_iso_b2 (8763874709859458453) --> - <skip /> - <!-- no translation found for mediaSize_iso_b3 (4210506688191764076) --> - <skip /> - <!-- no translation found for mediaSize_iso_b4 (5749404165888526034) --> - <skip /> - <!-- no translation found for mediaSize_iso_b5 (7640627414621904733) --> - <skip /> - <!-- no translation found for mediaSize_iso_b6 (7342988864712748544) --> - <skip /> - <!-- no translation found for mediaSize_iso_b7 (5069844065235382429) --> - <skip /> - <!-- no translation found for mediaSize_iso_b8 (7316818922278779774) --> - <skip /> - <!-- no translation found for mediaSize_iso_b9 (5414727094026532341) --> - <skip /> - <!-- no translation found for mediaSize_iso_b10 (5251253731832048185) --> - <skip /> - <!-- no translation found for mediaSize_iso_c0 (4003138342671964217) --> - <skip /> - <!-- no translation found for mediaSize_iso_c1 (1935188063393553008) --> - <skip /> - <!-- no translation found for mediaSize_iso_c2 (3197307969712069904) --> - <skip /> - <!-- no translation found for mediaSize_iso_c3 (4335826087321913508) --> - <skip /> - <!-- no translation found for mediaSize_iso_c4 (3745639598281015005) --> - <skip /> - <!-- no translation found for mediaSize_iso_c5 (8269457765822791013) --> - <skip /> - <!-- no translation found for mediaSize_iso_c6 (566666105260346930) --> - <skip /> - <!-- no translation found for mediaSize_iso_c7 (8678413180782608498) --> - <skip /> - <!-- no translation found for mediaSize_iso_c8 (8392376206627041730) --> - <skip /> - <!-- no translation found for mediaSize_iso_c9 (9191613372324845405) --> - <skip /> - <!-- no translation found for mediaSize_iso_c10 (7327709699184920822) --> - <skip /> - <!-- no translation found for mediaSize_na_letter (4191805615829472953) --> - <skip /> - <!-- no translation found for mediaSize_na_gvrnmt_letter (7853382192649405507) --> - <skip /> - <!-- no translation found for mediaSize_na_legal (6697982988283823150) --> - <skip /> - <!-- no translation found for mediaSize_na_junior_legal (3727743969902758948) --> - <skip /> - <!-- no translation found for mediaSize_na_ledger (281871464896601236) --> - <skip /> - <!-- no translation found for mediaSize_na_tabloid (5775966416333578127) --> - <skip /> - <!-- no translation found for restr_pin_create_pin (8017600000263450337) --> - <skip /> - <!-- no translation found for restr_pin_enter_pin (3395953421368476103) --> - <skip /> - <!-- no translation found for restr_pin_confirm_pin (2891475237150965991) --> - <skip /> - <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) --> - <skip /> - <!-- no translation found for restr_pin_error_too_short (8173982756265777792) --> - <skip /> - <!-- no translation found for restr_pin_countdown:one (4835639969503729874) --> - <!-- no translation found for restr_pin_countdown:other (8030607343223287654) --> + <string name="mediaSize_iso_a0" msgid="7875427489420821793">"ISO A0"</string> + <string name="mediaSize_iso_a1" msgid="3760734499050875356">"ISO A1"</string> + <string name="mediaSize_iso_a2" msgid="5973266378020144382">"ISO A2"</string> + <string name="mediaSize_iso_a3" msgid="1373407105687300884">"ISO A3"</string> + <string name="mediaSize_iso_a4" msgid="6689772807982597254">"ISO A4"</string> + <string name="mediaSize_iso_a5" msgid="5353549652015741040">"ISO A5"</string> + <string name="mediaSize_iso_a6" msgid="8585038048674911907">"ISO A6"</string> + <string name="mediaSize_iso_a7" msgid="6641836716963839119">"ISO A7"</string> + <string name="mediaSize_iso_a8" msgid="7571139437465693355">"ISO A8"</string> + <string name="mediaSize_iso_a9" msgid="1378455891957115079">"ISO A9"</string> + <string name="mediaSize_iso_a10" msgid="2480747457429475344">"ISO A10"</string> + <string name="mediaSize_iso_b0" msgid="3965935097661108039">"ISO B0"</string> + <string name="mediaSize_iso_b1" msgid="2505753285010115437">"ISO B1"</string> + <string name="mediaSize_iso_b2" msgid="8763874709859458453">"ISO B2"</string> + <string name="mediaSize_iso_b3" msgid="4210506688191764076">"ISO B3"</string> + <string name="mediaSize_iso_b4" msgid="5749404165888526034">"ISO B4"</string> + <string name="mediaSize_iso_b5" msgid="7640627414621904733">"ISO B5"</string> + <string name="mediaSize_iso_b6" msgid="7342988864712748544">"ISO B6"</string> + <string name="mediaSize_iso_b7" msgid="5069844065235382429">"ISO B7"</string> + <string name="mediaSize_iso_b8" msgid="7316818922278779774">"ISO B8"</string> + <string name="mediaSize_iso_b9" msgid="5414727094026532341">"ISO B9"</string> + <string name="mediaSize_iso_b10" msgid="5251253731832048185">"ISO B10"</string> + <string name="mediaSize_iso_c0" msgid="4003138342671964217">"ISO C0"</string> + <string name="mediaSize_iso_c1" msgid="1935188063393553008">"ISO C1"</string> + <string name="mediaSize_iso_c2" msgid="3197307969712069904">"ISO C2"</string> + <string name="mediaSize_iso_c3" msgid="4335826087321913508">"ISO C3"</string> + <string name="mediaSize_iso_c4" msgid="3745639598281015005">"ISO C4"</string> + <string name="mediaSize_iso_c5" msgid="8269457765822791013">"ISO C5"</string> + <string name="mediaSize_iso_c6" msgid="566666105260346930">"ISO C6"</string> + <string name="mediaSize_iso_c7" msgid="8678413180782608498">"ISO C7"</string> + <string name="mediaSize_iso_c8" msgid="8392376206627041730">"ISO C8"</string> + <string name="mediaSize_iso_c9" msgid="9191613372324845405">"ISO C9"</string> + <string name="mediaSize_iso_c10" msgid="7327709699184920822">"ISO C10"</string> + <string name="mediaSize_na_letter" msgid="4191805615829472953">"Barua"</string> + <string name="mediaSize_na_gvrnmt_letter" msgid="7853382192649405507">"Barua ya Serikali"</string> + <string name="mediaSize_na_legal" msgid="6697982988283823150">"Kisheria"</string> + <string name="mediaSize_na_junior_legal" msgid="3727743969902758948">"Mwanasheria Mdogo"</string> + <string name="mediaSize_na_ledger" msgid="281871464896601236">"Leja"</string> + <string name="mediaSize_na_tabloid" msgid="5775966416333578127">"Gazeti"</string> + <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"Imeghairiwa"</string> + <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"Hitilafu katika kuandika maudhui"</string> + <string name="restr_pin_enter_pin" msgid="3395953421368476103">"Ingiza PIN"</string> + <string name="restr_pin_enter_old_pin" msgid="1462206225512910757">"PIN ya sasa"</string> + <string name="restr_pin_enter_new_pin" msgid="5959606691619959184">"PIN mpya"</string> + <string name="restr_pin_confirm_pin" msgid="8501523829633146239">"Thibitisha PIN mpya"</string> + <string name="restr_pin_create_pin" msgid="8017600000263450337">"Unda PIN ya kurekebisha vikwazo"</string> + <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PIN hazilingani. Jaribu tena."</string> + <string name="restr_pin_error_too_short" msgid="8173982756265777792">"PIN ni fupi mno. Lazima iwe angalau tarakimu 4."</string> + <plurals name="restr_pin_countdown"> + <item quantity="one" msgid="4835639969503729874">"PIN sio sahihi. Jaribu tena baada ya sekunde 1."</item> + <item quantity="other" msgid="8030607343223287654">"PIN sio sahihi. Jaribu tena baada ya sekunde <xliff:g id="COUNT">%d</xliff:g>."</item> + </plurals> </resources> diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml index 9087783..786d441 100644 --- a/core/res/res/values-th/strings.xml +++ b/core/res/res/values-th/strings.xml @@ -470,6 +470,10 @@ <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"อนุญาตให้แอปพลิเคชันใช้คุณลักษณะระดับต่ำของ SurfaceFlinger"</string> <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"อ่านเฟรมบัฟเฟอร์"</string> <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"อนุญาตให้แอปพลิเคชันอ่านเนื้อหาในเฟรมบัฟเฟอร์"</string> + <!-- no translation found for permlab_accessInputFlinger (5348635270689553857) --> + <skip /> + <!-- no translation found for permdesc_accessInputFlinger (2104864941201226616) --> + <skip /> <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"กำหนดค่าการแสดงผลด้วย WiFi"</string> <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"อนุญาตให้แอปกำหนดค่าและเชื่อมต่อกับจอแสดงผล WiFi ได้"</string> <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"ควบคุมการแสดงผลด้วย WiFi"</string> @@ -639,10 +643,18 @@ <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"อนุญาตให้แอปพลิเคชันจัดการนโยบายเครือข่ายและกำหนดกฎเฉพาะแอปพลิเคชัน"</string> <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"แก้ไขการบันทึกบัญชีการใช้งานเครือข่าย"</string> <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"อนุญาตให้แอปพลิเคชันแก้ไขวิธีการบันทึกบัญชีการใช้งานเครือข่ายของแอปพลิเคชัน ไม่ใช้สำหรับแอปพลิเคชันทั่วไป"</string> + <!-- no translation found for permlab_markNetworkSocket (3658527214914959749) --> + <skip /> + <!-- no translation found for permdesc_markNetworkSocket (7655568433696356578) --> + <skip /> <string name="permlab_accessNotifications" msgid="7673416487873432268">"เข้าถึงการแจ้งเตือน"</string> <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_invokeCarrierSetup (3699600833975117478) --> + <skip /> + <!-- no translation found for permdesc_invokeCarrierSetup (4159549152529111920) --> + <skip /> <string name="policylab_limitPassword" msgid="4497420728857585791">"ตั้งค่ากฎรหัสผ่าน"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"ควบคุมความยาวและอักขระที่อนุญาตให้ใช้ในรหัสผ่านการปลดล็อกหน้าจอ"</string> <string name="policylab_watchLogin" msgid="914130646942199503">"ตรวจสอบความพยายามในการปลดล็อกหน้าจอ"</string> @@ -1593,11 +1605,19 @@ <skip /> <!-- no translation found for mediaSize_na_tabloid (5775966416333578127) --> <skip /> - <!-- no translation found for restr_pin_create_pin (8017600000263450337) --> + <!-- no translation found for write_fail_reason_cancelled (7091258378121627624) --> + <skip /> + <!-- no translation found for write_fail_reason_cannot_write (8132505417935337724) --> <skip /> <!-- no translation found for restr_pin_enter_pin (3395953421368476103) --> <skip /> - <!-- no translation found for restr_pin_confirm_pin (2891475237150965991) --> + <!-- no translation found for restr_pin_enter_old_pin (1462206225512910757) --> + <skip /> + <!-- no translation found for restr_pin_enter_new_pin (5959606691619959184) --> + <skip /> + <!-- no translation found for restr_pin_confirm_pin (8501523829633146239) --> + <skip /> + <!-- no translation found for restr_pin_create_pin (8017600000263450337) --> <skip /> <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) --> <skip /> diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml index d30fb77..0770504 100644 --- a/core/res/res/values-tl/strings.xml +++ b/core/res/res/values-tl/strings.xml @@ -470,6 +470,10 @@ <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Pinapayagan ang app na gamitin ang mababang antas na mga tampok ng SurfaceFlinger."</string> <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"basahin ang buffer ng frame"</string> <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Pinapayagan ang app na basahin ang nilalaman ng buffer ng frame."</string> + <!-- no translation found for permlab_accessInputFlinger (5348635270689553857) --> + <skip /> + <!-- no translation found for permdesc_accessInputFlinger (2104864941201226616) --> + <skip /> <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"mag-configure ng mga Wifi display"</string> <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Pinapayagan ang app na mag-configure at kumonekta sa mga Wifi display."</string> <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"magkontrol ng mga Wifi display"</string> @@ -639,10 +643,18 @@ <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Pinapayagan ang app na pamahalaan ang mga patakaran ng network at ilarawan ang mga patakarang tukoy sa app."</string> <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"baguhin ang pagkukuwenta sa paggamit ng network"</string> <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Pinapayagan ang app na baguhin kung paano isinasaalang-alang ang paggamit ng network laban sa apps. Hindi para sa paggamit ng normal na apps."</string> + <!-- no translation found for permlab_markNetworkSocket (3658527214914959749) --> + <skip /> + <!-- no translation found for permdesc_markNetworkSocket (7655568433696356578) --> + <skip /> <string name="permlab_accessNotifications" msgid="7673416487873432268">"i-access ang mga notification"</string> <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> + <!-- no translation found for permlab_invokeCarrierSetup (3699600833975117478) --> + <skip /> + <!-- no translation found for permdesc_invokeCarrierSetup (4159549152529111920) --> + <skip /> <string name="policylab_limitPassword" msgid="4497420728857585791">"Magtakda ng mga panuntunan sa password"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"Kontrolin ang haba at mga character na pinapayagan sa mga password sa pag-unlock ng screen."</string> <string name="policylab_watchLogin" msgid="914130646942199503">"Subaybayan ang mga pagsubok sa pag-unlock ng screen"</string> @@ -1593,11 +1605,19 @@ <skip /> <!-- no translation found for mediaSize_na_tabloid (5775966416333578127) --> <skip /> - <!-- no translation found for restr_pin_create_pin (8017600000263450337) --> + <!-- no translation found for write_fail_reason_cancelled (7091258378121627624) --> + <skip /> + <!-- no translation found for write_fail_reason_cannot_write (8132505417935337724) --> <skip /> <!-- no translation found for restr_pin_enter_pin (3395953421368476103) --> <skip /> - <!-- no translation found for restr_pin_confirm_pin (2891475237150965991) --> + <!-- no translation found for restr_pin_enter_old_pin (1462206225512910757) --> + <skip /> + <!-- no translation found for restr_pin_enter_new_pin (5959606691619959184) --> + <skip /> + <!-- no translation found for restr_pin_confirm_pin (8501523829633146239) --> + <skip /> + <!-- no translation found for restr_pin_create_pin (8017600000263450337) --> <skip /> <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) --> <skip /> diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml index 30691d9..4e3cef6 100644 --- a/core/res/res/values-tr/strings.xml +++ b/core/res/res/values-tr/strings.xml @@ -279,10 +279,8 @@ <string name="permdesc_reorderTasks" msgid="7734217754877439351">"Uygulamaya, görevleri ön plana ve arka plana taşıma izni verir. Uygulama bunu sizden bir giriş olmadan yapabilir."</string> <string name="permlab_removeTasks" msgid="6821513401870377403">"çalışan uygulamaları durdur"</string> <string name="permdesc_removeTasks" msgid="1394714352062635493">"Uygulamaya, görevleri kaldırma ve bunlara ait uygulamaları kapatma izni verir. Kötü amaçlı uygulamalar diğer uygulamaların çalışmasını bozabilir."</string> - <!-- no translation found for permlab_manageActivityStacks (7391191384027303065) --> - <skip /> - <!-- no translation found for permdesc_manageActivityStacks (1615881933034084440) --> - <skip /> + <string name="permlab_manageActivityStacks" msgid="7391191384027303065">"etkinlik yığınlarını yönet"</string> + <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"Uygulamaya, diğer uygulamaların içinde çalıştığı etkinlik yığınlarını ekleme, kaldırma ve değiştirme izni verir. Kötü amaçlı uygulamalar diğer uygulamaların davranışlarını olumsuz etkileyebilir."</string> <string name="permlab_startAnyActivity" msgid="2918768238045206456">"herhangi bir etkinlik başlat"</string> <string name="permdesc_startAnyActivity" msgid="997823695343584001">"Uygulamaya, izin koruma veya dışa aktarma durumu ne olursa olsun bir etkinlik başlatma izni verir."</string> <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"ekran uyumluluğunu ayarla"</string> @@ -360,14 +358,10 @@ <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Cihazın sahibine, bir giriş yönteminin en üst düzey arayüzüne bağlanma izni verir. Normal uygulamalarda hiçbir zaman gerek duyulmaz."</string> <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"erişilebilirlik hizmetine bağlan"</string> <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"İzin sahibine bir erişilebilirlik hizmetinin en üst düzey arayüzüne bağlanma izni verir. Normal uygulamalarda hiçbir zaman gerek duyulmaz."</string> - <!-- no translation found for permlab_bindPrintService (8462815179572748761) --> - <skip /> - <!-- no translation found for permdesc_bindPrintService (7960067623209111135) --> - <skip /> - <!-- no translation found for permlab_accessAllPrintJobs (1120792468465711159) --> - <skip /> - <!-- no translation found for permdesc_accessAllPrintJobs (2978185311041864762) --> - <skip /> + <string name="permlab_bindPrintService" msgid="8462815179572748761">"bir yazdırma hizmetine bağlan"</string> + <string name="permdesc_bindPrintService" msgid="7960067623209111135">"İzin sahibine, bir yazdırma hizmetinin en üst düzey arayüzüne bağlanma izni verir. Normal uygulamalarda hiçbir zaman gerek duyulmaz."</string> + <string name="permlab_accessAllPrintJobs" msgid="1120792468465711159">"tüm yazdırma işlerine eriş"</string> + <string name="permdesc_accessAllPrintJobs" msgid="2978185311041864762">"İzin sahibine, başka uygulama tarafından oluşturulan yazdırma işlerine erişim izni verir. Normal uygulamalarda hiçbir zaman gerek duyulmaz."</string> <string name="permlab_bindTextService" msgid="7358378401915287938">"kısa mesaj hizmetine bağla"</string> <string name="permdesc_bindTextService" msgid="8151968910973998670">"Cihazın sahibine, bir metin hizmetinin (ör. SpellCheckerService) en üst düzey arayüzüne bağlanma izni verir. Normal uygulamalarda hiçbir zaman gerekmez."</string> <string name="permlab_bindVpnService" msgid="4708596021161473255">"VPN hizmetine bağlan"</string> @@ -470,6 +464,8 @@ <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Uygulamaya, SurfaceFlinger\'a ait düşük düzey özellikleri kullanma izni verir."</string> <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"çerçeve arabelleğini oku"</string> <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Uygulamaya, çerçeve arabelleğinin içeriğini okuma izni verir."</string> + <string name="permlab_accessInputFlinger" msgid="5348635270689553857">"InputFlinger\'a eriş"</string> + <string name="permdesc_accessInputFlinger" msgid="2104864941201226616">"Uygulamaya, alt düzey InputFlinger özelliklerini kullanma izni verir."</string> <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"Kablosuz ekranları yapılandır"</string> <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Uygulamaya kablosuz ekranları yapılandırma ve bunlara bağlanma izni verir."</string> <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"Kablosuz ekranları denetle"</string> @@ -639,10 +635,14 @@ <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Uygulamaya, ağ politikalarını yönetme ve uygulamaya özgü kuralları tanımlama izni verir."</string> <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"ağ kullanım hesaplamasını değiştir"</string> <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Uygulamaya, ağın uygulamalara göre nasıl kullanılacağını değiştirme izni verir. Normal uygulamalar tarafından kullanılmak için değildir."</string> + <string name="permlab_markNetworkSocket" msgid="3658527214914959749">"soket işaretlerini değiştir"</string> + <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"Uygulamaya, yönlendirme için soket işaretlerini değiştirme izni verir"</string> <string name="permlab_accessNotifications" msgid="7673416487873432268">"bildirimlere eriş"</string> <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_invokeCarrierSetup" msgid="3699600833975117478">"operatör tarafından sağlanan yapılandırma uygulamasını çalıştır"</string> + <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"İzin sahibine, operatör tarafından sağlanan yapılandırma uygulamasını çalıştırma izni verir. Normal uygulamalarda hiçbir zaman gerek duyulmaz."</string> <string name="policylab_limitPassword" msgid="4497420728857585791">"Şifre kuralları ayarla"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"Ekran kilidini açma şifrelerinde izin verilen uzunluğu ve karakterleri denetleme."</string> <string name="policylab_watchLogin" msgid="914130646942199503">"Ekran kilidini açma denemelerini izle"</string> @@ -752,8 +752,7 @@ <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string> <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string> <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string> - <!-- no translation found for imProtocolGoogleTalk (493902321140277304) --> - <skip /> + <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangouts"</string> <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string> <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string> <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string> @@ -1515,94 +1514,59 @@ <string name="app_no_restricted_accounts" msgid="5739463249673727736">"Bu uygulama, kısıtlanmış profillerin hesaplarını desteklemez"</string> <string name="app_not_found" msgid="3429141853498927379">"Bu eylemi gerçekleştirecek bir uygulama bulunamadı"</string> <string name="revoke" msgid="5404479185228271586">"İptal et"</string> - <!-- no translation found for mediaSize_iso_a0 (7875427489420821793) --> - <skip /> - <!-- no translation found for mediaSize_iso_a1 (3760734499050875356) --> - <skip /> - <!-- no translation found for mediaSize_iso_a2 (5973266378020144382) --> - <skip /> - <!-- no translation found for mediaSize_iso_a3 (1373407105687300884) --> - <skip /> - <!-- no translation found for mediaSize_iso_a4 (6689772807982597254) --> - <skip /> - <!-- no translation found for mediaSize_iso_a5 (5353549652015741040) --> - <skip /> - <!-- no translation found for mediaSize_iso_a6 (8585038048674911907) --> - <skip /> - <!-- no translation found for mediaSize_iso_a7 (6641836716963839119) --> - <skip /> - <!-- no translation found for mediaSize_iso_a8 (7571139437465693355) --> - <skip /> - <!-- no translation found for mediaSize_iso_a9 (1378455891957115079) --> - <skip /> - <!-- no translation found for mediaSize_iso_a10 (2480747457429475344) --> - <skip /> - <!-- no translation found for mediaSize_iso_b0 (3965935097661108039) --> - <skip /> - <!-- no translation found for mediaSize_iso_b1 (2505753285010115437) --> - <skip /> - <!-- no translation found for mediaSize_iso_b2 (8763874709859458453) --> - <skip /> - <!-- no translation found for mediaSize_iso_b3 (4210506688191764076) --> - <skip /> - <!-- no translation found for mediaSize_iso_b4 (5749404165888526034) --> - <skip /> - <!-- no translation found for mediaSize_iso_b5 (7640627414621904733) --> - <skip /> - <!-- no translation found for mediaSize_iso_b6 (7342988864712748544) --> - <skip /> - <!-- no translation found for mediaSize_iso_b7 (5069844065235382429) --> + <string name="mediaSize_iso_a0" msgid="7875427489420821793">"ISO A0"</string> + <string name="mediaSize_iso_a1" msgid="3760734499050875356">"ISO A1"</string> + <string name="mediaSize_iso_a2" msgid="5973266378020144382">"ISO A2"</string> + <string name="mediaSize_iso_a3" msgid="1373407105687300884">"ISO A3"</string> + <string name="mediaSize_iso_a4" msgid="6689772807982597254">"ISO A4"</string> + <string name="mediaSize_iso_a5" msgid="5353549652015741040">"ISO A5"</string> + <string name="mediaSize_iso_a6" msgid="8585038048674911907">"ISO A6"</string> + <string name="mediaSize_iso_a7" msgid="6641836716963839119">"ISO A7"</string> + <string name="mediaSize_iso_a8" msgid="7571139437465693355">"ISO A8"</string> + <string name="mediaSize_iso_a9" msgid="1378455891957115079">"ISO A9"</string> + <string name="mediaSize_iso_a10" msgid="2480747457429475344">"ISO A10"</string> + <string name="mediaSize_iso_b0" msgid="3965935097661108039">"ISO B0"</string> + <string name="mediaSize_iso_b1" msgid="2505753285010115437">"ISO B1"</string> + <string name="mediaSize_iso_b2" msgid="8763874709859458453">"ISO B2"</string> + <string name="mediaSize_iso_b3" msgid="4210506688191764076">"ISO B3"</string> + <string name="mediaSize_iso_b4" msgid="5749404165888526034">"ISO B4"</string> + <string name="mediaSize_iso_b5" msgid="7640627414621904733">"ISO B5"</string> + <string name="mediaSize_iso_b6" msgid="7342988864712748544">"ISO B6"</string> + <string name="mediaSize_iso_b7" msgid="5069844065235382429">"ISO B7"</string> + <string name="mediaSize_iso_b8" msgid="7316818922278779774">"ISO B8"</string> + <string name="mediaSize_iso_b9" msgid="5414727094026532341">"ISO B9"</string> + <string name="mediaSize_iso_b10" msgid="5251253731832048185">"ISO B10"</string> + <string name="mediaSize_iso_c0" msgid="4003138342671964217">"ISO C0"</string> + <string name="mediaSize_iso_c1" msgid="1935188063393553008">"ISO C1"</string> + <string name="mediaSize_iso_c2" msgid="3197307969712069904">"ISO C2"</string> + <string name="mediaSize_iso_c3" msgid="4335826087321913508">"ISO C3"</string> + <string name="mediaSize_iso_c4" msgid="3745639598281015005">"ISO C4"</string> + <string name="mediaSize_iso_c5" msgid="8269457765822791013">"ISO C5"</string> + <string name="mediaSize_iso_c6" msgid="566666105260346930">"ISO C6"</string> + <string name="mediaSize_iso_c7" msgid="8678413180782608498">"ISO C7"</string> + <string name="mediaSize_iso_c8" msgid="8392376206627041730">"ISO C8"</string> + <string name="mediaSize_iso_c9" msgid="9191613372324845405">"ISO C9"</string> + <string name="mediaSize_iso_c10" msgid="7327709699184920822">"ISO C10"</string> + <string name="mediaSize_na_letter" msgid="4191805615829472953">"Letter"</string> + <string name="mediaSize_na_gvrnmt_letter" msgid="7853382192649405507">"Government Letter"</string> + <string name="mediaSize_na_legal" msgid="6697982988283823150">"Legal"</string> + <string name="mediaSize_na_junior_legal" msgid="3727743969902758948">"Junior Legal"</string> + <string name="mediaSize_na_ledger" msgid="281871464896601236">"Ledger"</string> + <string name="mediaSize_na_tabloid" msgid="5775966416333578127">"Tabloid"</string> + <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"İptal edildi"</string> + <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"İçerik yazılırken hata oluştu"</string> + <string name="restr_pin_enter_pin" msgid="3395953421368476103">"PIN\'i girin"</string> + <!-- no translation found for restr_pin_enter_old_pin (1462206225512910757) --> <skip /> - <!-- no translation found for mediaSize_iso_b8 (7316818922278779774) --> + <!-- no translation found for restr_pin_enter_new_pin (5959606691619959184) --> <skip /> - <!-- no translation found for mediaSize_iso_b9 (5414727094026532341) --> + <!-- no translation found for restr_pin_confirm_pin (8501523829633146239) --> <skip /> - <!-- no translation found for mediaSize_iso_b10 (5251253731832048185) --> - <skip /> - <!-- no translation found for mediaSize_iso_c0 (4003138342671964217) --> - <skip /> - <!-- no translation found for mediaSize_iso_c1 (1935188063393553008) --> - <skip /> - <!-- no translation found for mediaSize_iso_c2 (3197307969712069904) --> - <skip /> - <!-- no translation found for mediaSize_iso_c3 (4335826087321913508) --> - <skip /> - <!-- no translation found for mediaSize_iso_c4 (3745639598281015005) --> - <skip /> - <!-- no translation found for mediaSize_iso_c5 (8269457765822791013) --> - <skip /> - <!-- no translation found for mediaSize_iso_c6 (566666105260346930) --> - <skip /> - <!-- no translation found for mediaSize_iso_c7 (8678413180782608498) --> - <skip /> - <!-- no translation found for mediaSize_iso_c8 (8392376206627041730) --> - <skip /> - <!-- no translation found for mediaSize_iso_c9 (9191613372324845405) --> - <skip /> - <!-- no translation found for mediaSize_iso_c10 (7327709699184920822) --> - <skip /> - <!-- no translation found for mediaSize_na_letter (4191805615829472953) --> - <skip /> - <!-- no translation found for mediaSize_na_gvrnmt_letter (7853382192649405507) --> - <skip /> - <!-- no translation found for mediaSize_na_legal (6697982988283823150) --> - <skip /> - <!-- no translation found for mediaSize_na_junior_legal (3727743969902758948) --> - <skip /> - <!-- no translation found for mediaSize_na_ledger (281871464896601236) --> - <skip /> - <!-- no translation found for mediaSize_na_tabloid (5775966416333578127) --> - <skip /> - <!-- no translation found for restr_pin_create_pin (8017600000263450337) --> - <skip /> - <!-- no translation found for restr_pin_enter_pin (3395953421368476103) --> - <skip /> - <!-- no translation found for restr_pin_confirm_pin (2891475237150965991) --> - <skip /> - <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) --> - <skip /> - <!-- no translation found for restr_pin_error_too_short (8173982756265777792) --> - <skip /> - <!-- no translation found for restr_pin_countdown:one (4835639969503729874) --> - <!-- no translation found for restr_pin_countdown:other (8030607343223287654) --> + <string name="restr_pin_create_pin" msgid="8017600000263450337">"Kısıtlamaları değiştirmek için PIN oluşturun"</string> + <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PIN\'ler eşleşmiyor. Tekrar deneyin."</string> + <string name="restr_pin_error_too_short" msgid="8173982756265777792">"PIN çok kısa. En az 4 basamaklı olmalı."</string> + <plurals name="restr_pin_countdown"> + <item quantity="one" msgid="4835639969503729874">"Yanlış PIN. 1 saniye içinde tekrar deneyin."</item> + <item quantity="other" msgid="8030607343223287654">"Yanlış PIN. <xliff:g id="COUNT">%d</xliff:g> saniye içinde tekrar deneyin."</item> + </plurals> </resources> diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml index db27c85..47ad171 100644 --- a/core/res/res/values-uk/strings.xml +++ b/core/res/res/values-uk/strings.xml @@ -279,10 +279,8 @@ <string name="permdesc_reorderTasks" msgid="7734217754877439351">"Дозволяє програмі переміщувати завдання в активні чи фонові вікна. Програма може робити це без вашого відома."</string> <string name="permlab_removeTasks" msgid="6821513401870377403">"зупиняти запущені програми"</string> <string name="permdesc_removeTasks" msgid="1394714352062635493">"Дозволяє програмі видаляти завдання та примусово припиняти роботу відповідних програм. Шкідливі програми можуть переривати роботу інших програм."</string> - <!-- no translation found for permlab_manageActivityStacks (7391191384027303065) --> - <skip /> - <!-- no translation found for permdesc_manageActivityStacks (1615881933034084440) --> - <skip /> + <string name="permlab_manageActivityStacks" msgid="7391191384027303065">"керувати стеками дій"</string> + <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"Дозволяє програмі додавати, вилучати та змінювати стеки дій, у яких запущено інші програми. Шкідливі програми можуть переривати роботу інших програм."</string> <string name="permlab_startAnyActivity" msgid="2918768238045206456">"розпочинати будь-які дії"</string> <string name="permdesc_startAnyActivity" msgid="997823695343584001">"Дозволяє програмі розпочинати будь-які дії, незалежно від захищеного дозволу або стану експорту."</string> <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"установити сумісність екрана"</string> @@ -360,14 +358,10 @@ <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Дозволяє власнику прив’язуватися до інтерфейсу верхнього рівня методу введення. Ніколи не застосовується для звичайних програм."</string> <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"прив’язуватися до служби доступності"</string> <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Дозволяє власникові прив’язуватися до інтерфейсу верхнього рівня служби доступності. Ніколи не застосовується для звичайних програм."</string> - <!-- no translation found for permlab_bindPrintService (8462815179572748761) --> - <skip /> - <!-- no translation found for permdesc_bindPrintService (7960067623209111135) --> - <skip /> - <!-- no translation found for permlab_accessAllPrintJobs (1120792468465711159) --> - <skip /> - <!-- no translation found for permdesc_accessAllPrintJobs (2978185311041864762) --> - <skip /> + <string name="permlab_bindPrintService" msgid="8462815179572748761">"прив’язуватися до служби друку"</string> + <string name="permdesc_bindPrintService" msgid="7960067623209111135">"Дозволяє власникові прив’язуватися до інтерфейсу верхнього рівня служби друку. Ніколи не застосовується для звичайних програм."</string> + <string name="permlab_accessAllPrintJobs" msgid="1120792468465711159">"отримувати доступ до всіх завдань друку"</string> + <string name="permdesc_accessAllPrintJobs" msgid="2978185311041864762">"Дозволяє власнику отримувати доступ до завдань друку, створених в іншій програмі. Ніколи не застосовується для звичайних програм."</string> <string name="permlab_bindTextService" msgid="7358378401915287938">"прив’язати до текстової служби"</string> <string name="permdesc_bindTextService" msgid="8151968910973998670">"Дозволяє власникові прив’язуватися до інтерфейсу верхнього рівня текстової служби (напр. SpellCheckerService). Ніколи не застосовується для звичайних програм."</string> <string name="permlab_bindVpnService" msgid="4708596021161473255">"прив’язуватися до служби VPN"</string> @@ -470,6 +464,8 @@ <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Дозволяє програмі використовувати низькорівневі функції SurfaceFlinger."</string> <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"читати фрейм-буфер"</string> <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Дозволяє програмі читати вміст буфера кадрів."</string> + <string name="permlab_accessInputFlinger" msgid="5348635270689553857">"отримувати доступ до InputFlinger"</string> + <string name="permdesc_accessInputFlinger" msgid="2104864941201226616">"Дозволяє програмі використовувати низькорівневі функції InputFlinger."</string> <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"налаштувати екрани Wi-Fi"</string> <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Дозволяє програмі налаштовувати екрани Wi-Fi і під’єднуватися до них."</string> <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"керувати екранами Wi-Fi"</string> @@ -639,10 +635,14 @@ <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Дозволяє програмі керувати політикою мережі та визначити спеціальні правила для програм."</string> <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"змінювати облік використання мережі"</string> <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Дозволяє програмі змінювати метод підрахунку того, як програми використовують мережу. Не для використання звичайними програмами."</string> + <string name="permlab_markNetworkSocket" msgid="3658527214914959749">"змінювати мітки сокетів"</string> + <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"Дозволяє програмі змінювати мітки сокетів для маршрутизації"</string> <string name="permlab_accessNotifications" msgid="7673416487873432268">"отримувати доступ до сповіщень"</string> <string name="permdesc_accessNotifications" msgid="458457742683431387">"Дозволяє програмі отримувати, перевіряти й очищати сповіщення, зокрема опубліковані іншими програмами."</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"прив’язуватися до служби читання сповіщень"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Дозволяє власнику прив’язуватися до інтерфейсу верхнього рівня служби читання сповіщень. Ніколи не застосовується для звичайних програм."</string> + <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"викликати надану оператором програму конфігурації"</string> + <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Дозволяє власнику викликати надану оператором програму конфігурації. Ніколи не застосовується для звичайних програм."</string> <string name="policylab_limitPassword" msgid="4497420728857585791">"Устан. правила пароля"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"Контролювати довжину паролів для розблокування екрана та дозволені в них символи."</string> <string name="policylab_watchLogin" msgid="914130646942199503">"Відстежув. спроби розблок. екрана"</string> @@ -752,8 +752,7 @@ <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string> <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string> <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string> - <!-- no translation found for imProtocolGoogleTalk (493902321140277304) --> - <skip /> + <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangouts"</string> <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string> <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string> <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string> @@ -1515,94 +1514,59 @@ <string name="app_no_restricted_accounts" msgid="5739463249673727736">"Ця програма не підтримує облікові записи для обмежених профілів"</string> <string name="app_not_found" msgid="3429141853498927379">"Не знайдено програму для обробки цієї дії"</string> <string name="revoke" msgid="5404479185228271586">"Анулювати"</string> - <!-- no translation found for mediaSize_iso_a0 (7875427489420821793) --> - <skip /> - <!-- no translation found for mediaSize_iso_a1 (3760734499050875356) --> - <skip /> - <!-- no translation found for mediaSize_iso_a2 (5973266378020144382) --> - <skip /> - <!-- no translation found for mediaSize_iso_a3 (1373407105687300884) --> - <skip /> - <!-- no translation found for mediaSize_iso_a4 (6689772807982597254) --> - <skip /> - <!-- no translation found for mediaSize_iso_a5 (5353549652015741040) --> - <skip /> - <!-- no translation found for mediaSize_iso_a6 (8585038048674911907) --> - <skip /> - <!-- no translation found for mediaSize_iso_a7 (6641836716963839119) --> - <skip /> - <!-- no translation found for mediaSize_iso_a8 (7571139437465693355) --> - <skip /> - <!-- no translation found for mediaSize_iso_a9 (1378455891957115079) --> - <skip /> - <!-- no translation found for mediaSize_iso_a10 (2480747457429475344) --> - <skip /> - <!-- no translation found for mediaSize_iso_b0 (3965935097661108039) --> - <skip /> - <!-- no translation found for mediaSize_iso_b1 (2505753285010115437) --> - <skip /> - <!-- no translation found for mediaSize_iso_b2 (8763874709859458453) --> - <skip /> - <!-- no translation found for mediaSize_iso_b3 (4210506688191764076) --> - <skip /> - <!-- no translation found for mediaSize_iso_b4 (5749404165888526034) --> - <skip /> - <!-- no translation found for mediaSize_iso_b5 (7640627414621904733) --> - <skip /> - <!-- no translation found for mediaSize_iso_b6 (7342988864712748544) --> - <skip /> - <!-- no translation found for mediaSize_iso_b7 (5069844065235382429) --> + <string name="mediaSize_iso_a0" msgid="7875427489420821793">"ISO A0"</string> + <string name="mediaSize_iso_a1" msgid="3760734499050875356">"ISO A1"</string> + <string name="mediaSize_iso_a2" msgid="5973266378020144382">"ISO A2"</string> + <string name="mediaSize_iso_a3" msgid="1373407105687300884">"ISO A3"</string> + <string name="mediaSize_iso_a4" msgid="6689772807982597254">"ISO A4"</string> + <string name="mediaSize_iso_a5" msgid="5353549652015741040">"ISO A5"</string> + <string name="mediaSize_iso_a6" msgid="8585038048674911907">"ISO A6"</string> + <string name="mediaSize_iso_a7" msgid="6641836716963839119">"ISO A7"</string> + <string name="mediaSize_iso_a8" msgid="7571139437465693355">"ISO A8"</string> + <string name="mediaSize_iso_a9" msgid="1378455891957115079">"ISO A9"</string> + <string name="mediaSize_iso_a10" msgid="2480747457429475344">"ISO A10"</string> + <string name="mediaSize_iso_b0" msgid="3965935097661108039">"ISO B0"</string> + <string name="mediaSize_iso_b1" msgid="2505753285010115437">"ISO B1"</string> + <string name="mediaSize_iso_b2" msgid="8763874709859458453">"ISO B2"</string> + <string name="mediaSize_iso_b3" msgid="4210506688191764076">"ISO B3"</string> + <string name="mediaSize_iso_b4" msgid="5749404165888526034">"ISO B4"</string> + <string name="mediaSize_iso_b5" msgid="7640627414621904733">"ISO B5"</string> + <string name="mediaSize_iso_b6" msgid="7342988864712748544">"ISO B6"</string> + <string name="mediaSize_iso_b7" msgid="5069844065235382429">"ISO B7"</string> + <string name="mediaSize_iso_b8" msgid="7316818922278779774">"ISO B8"</string> + <string name="mediaSize_iso_b9" msgid="5414727094026532341">"ISO B9"</string> + <string name="mediaSize_iso_b10" msgid="5251253731832048185">"ISO B10"</string> + <string name="mediaSize_iso_c0" msgid="4003138342671964217">"ISO C0"</string> + <string name="mediaSize_iso_c1" msgid="1935188063393553008">"ISO C1"</string> + <string name="mediaSize_iso_c2" msgid="3197307969712069904">"ISO C2"</string> + <string name="mediaSize_iso_c3" msgid="4335826087321913508">"ISO C3"</string> + <string name="mediaSize_iso_c4" msgid="3745639598281015005">"ISO C4"</string> + <string name="mediaSize_iso_c5" msgid="8269457765822791013">"ISO C5"</string> + <string name="mediaSize_iso_c6" msgid="566666105260346930">"ISO C6"</string> + <string name="mediaSize_iso_c7" msgid="8678413180782608498">"ISO C7"</string> + <string name="mediaSize_iso_c8" msgid="8392376206627041730">"ISO C8"</string> + <string name="mediaSize_iso_c9" msgid="9191613372324845405">"ISO C9"</string> + <string name="mediaSize_iso_c10" msgid="7327709699184920822">"ISO C10"</string> + <string name="mediaSize_na_letter" msgid="4191805615829472953">"Letter"</string> + <string name="mediaSize_na_gvrnmt_letter" msgid="7853382192649405507">"Government Letter"</string> + <string name="mediaSize_na_legal" msgid="6697982988283823150">"Legal"</string> + <string name="mediaSize_na_junior_legal" msgid="3727743969902758948">"Junior Legal"</string> + <string name="mediaSize_na_ledger" msgid="281871464896601236">"Ledger"</string> + <string name="mediaSize_na_tabloid" msgid="5775966416333578127">"Tabloid"</string> + <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"Скасовано"</string> + <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"Помилка записування вмісту"</string> + <string name="restr_pin_enter_pin" msgid="3395953421368476103">"Введіть PIN-код"</string> + <!-- no translation found for restr_pin_enter_old_pin (1462206225512910757) --> <skip /> - <!-- no translation found for mediaSize_iso_b8 (7316818922278779774) --> + <!-- no translation found for restr_pin_enter_new_pin (5959606691619959184) --> <skip /> - <!-- no translation found for mediaSize_iso_b9 (5414727094026532341) --> + <!-- no translation found for restr_pin_confirm_pin (8501523829633146239) --> <skip /> - <!-- no translation found for mediaSize_iso_b10 (5251253731832048185) --> - <skip /> - <!-- no translation found for mediaSize_iso_c0 (4003138342671964217) --> - <skip /> - <!-- no translation found for mediaSize_iso_c1 (1935188063393553008) --> - <skip /> - <!-- no translation found for mediaSize_iso_c2 (3197307969712069904) --> - <skip /> - <!-- no translation found for mediaSize_iso_c3 (4335826087321913508) --> - <skip /> - <!-- no translation found for mediaSize_iso_c4 (3745639598281015005) --> - <skip /> - <!-- no translation found for mediaSize_iso_c5 (8269457765822791013) --> - <skip /> - <!-- no translation found for mediaSize_iso_c6 (566666105260346930) --> - <skip /> - <!-- no translation found for mediaSize_iso_c7 (8678413180782608498) --> - <skip /> - <!-- no translation found for mediaSize_iso_c8 (8392376206627041730) --> - <skip /> - <!-- no translation found for mediaSize_iso_c9 (9191613372324845405) --> - <skip /> - <!-- no translation found for mediaSize_iso_c10 (7327709699184920822) --> - <skip /> - <!-- no translation found for mediaSize_na_letter (4191805615829472953) --> - <skip /> - <!-- no translation found for mediaSize_na_gvrnmt_letter (7853382192649405507) --> - <skip /> - <!-- no translation found for mediaSize_na_legal (6697982988283823150) --> - <skip /> - <!-- no translation found for mediaSize_na_junior_legal (3727743969902758948) --> - <skip /> - <!-- no translation found for mediaSize_na_ledger (281871464896601236) --> - <skip /> - <!-- no translation found for mediaSize_na_tabloid (5775966416333578127) --> - <skip /> - <!-- no translation found for restr_pin_create_pin (8017600000263450337) --> - <skip /> - <!-- no translation found for restr_pin_enter_pin (3395953421368476103) --> - <skip /> - <!-- no translation found for restr_pin_confirm_pin (2891475237150965991) --> - <skip /> - <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) --> - <skip /> - <!-- no translation found for restr_pin_error_too_short (8173982756265777792) --> - <skip /> - <!-- no translation found for restr_pin_countdown:one (4835639969503729874) --> - <!-- no translation found for restr_pin_countdown:other (8030607343223287654) --> + <string name="restr_pin_create_pin" msgid="8017600000263450337">"Створіть PIN-код для змінення обмежень"</string> + <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PIN-коди не збігаються. Повторіть спробу."</string> + <string name="restr_pin_error_too_short" msgid="8173982756265777792">"PIN-код закороткий. Має бути принаймні 4 цифри."</string> + <plurals name="restr_pin_countdown"> + <item quantity="one" msgid="4835639969503729874">"Неправильний PIN. Повторіть через 1 с"</item> + <item quantity="other" msgid="8030607343223287654">"Неправильний PIN. Повторіть через <xliff:g id="COUNT">%d</xliff:g> с"</item> + </plurals> </resources> diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml index 3002bcd..31760d1 100644 --- a/core/res/res/values-vi/strings.xml +++ b/core/res/res/values-vi/strings.xml @@ -470,6 +470,10 @@ <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Cho phép ứng dụng sử dụng các tính năng SurfaceFlinger cấp độ thấp."</string> <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"đọc bộ đệm khung"</string> <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Cho phép ứng dụng đọc nội dung của bộ đệm khung."</string> + <!-- no translation found for permlab_accessInputFlinger (5348635270689553857) --> + <skip /> + <!-- no translation found for permdesc_accessInputFlinger (2104864941201226616) --> + <skip /> <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"định cấu hình màn hình Wi-Fi"</string> <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Cho phép ứng dụng định cấu hình và kết nối với màn hình Wi-Fi."</string> <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"kiểm soát màn hình Wi-Fi"</string> @@ -639,10 +643,18 @@ <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Cho phép ứng dụng quản lý chính sách mạng và xác định quy tắc dành riêng cho ứng dụng."</string> <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"sửa đổi hạch toán sử dụng mạng"</string> <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Cho phép ứng dụng sửa đổi cách tính mức sử dụng mạng so với ứng dụng. Không dành cho các ứng dụng thông thường."</string> + <!-- no translation found for permlab_markNetworkSocket (3658527214914959749) --> + <skip /> + <!-- no translation found for permdesc_markNetworkSocket (7655568433696356578) --> + <skip /> <string name="permlab_accessNotifications" msgid="7673416487873432268">"truy cập thông báo"</string> <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> + <!-- no translation found for permlab_invokeCarrierSetup (3699600833975117478) --> + <skip /> + <!-- no translation found for permdesc_invokeCarrierSetup (4159549152529111920) --> + <skip /> <string name="policylab_limitPassword" msgid="4497420728857585791">"Đặt quy tắc mật khẩu"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"Kiểm soát độ dài và ký tự được phép trong mật khẩu mở khóa màn hình."</string> <string name="policylab_watchLogin" msgid="914130646942199503">"Giám sát những lần thử mở khóa màn hình"</string> @@ -1593,11 +1605,19 @@ <skip /> <!-- no translation found for mediaSize_na_tabloid (5775966416333578127) --> <skip /> - <!-- no translation found for restr_pin_create_pin (8017600000263450337) --> + <!-- no translation found for write_fail_reason_cancelled (7091258378121627624) --> + <skip /> + <!-- no translation found for write_fail_reason_cannot_write (8132505417935337724) --> <skip /> <!-- no translation found for restr_pin_enter_pin (3395953421368476103) --> <skip /> - <!-- no translation found for restr_pin_confirm_pin (2891475237150965991) --> + <!-- no translation found for restr_pin_enter_old_pin (1462206225512910757) --> + <skip /> + <!-- no translation found for restr_pin_enter_new_pin (5959606691619959184) --> + <skip /> + <!-- no translation found for restr_pin_confirm_pin (8501523829633146239) --> + <skip /> + <!-- no translation found for restr_pin_create_pin (8017600000263450337) --> <skip /> <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) --> <skip /> diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml index 52526de..fbf8c9a 100644 --- a/core/res/res/values-zh-rCN/strings.xml +++ b/core/res/res/values-zh-rCN/strings.xml @@ -470,6 +470,10 @@ <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"允许应用使用 SurfaceFlinger 低级功能。"</string> <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"读取帧缓冲区"</string> <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"允许应用读取帧缓冲区的内容。"</string> + <!-- no translation found for permlab_accessInputFlinger (5348635270689553857) --> + <skip /> + <!-- no translation found for permdesc_accessInputFlinger (2104864941201226616) --> + <skip /> <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"配置 WLAN 显示设备"</string> <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"允许应用配置并连接到 WLAN 显示设备。"</string> <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"控制 WLAN 显示设备"</string> @@ -639,10 +643,18 @@ <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"允许应用管理网络政策和定义专门针对应用的规则。"</string> <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"修改网络使用情况记录方式"</string> <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"允许该应用修改对于各应用的网络使用情况的统计方式。普通应用不应使用此权限。"</string> + <!-- no translation found for permlab_markNetworkSocket (3658527214914959749) --> + <skip /> + <!-- no translation found for permdesc_markNetworkSocket (7655568433696356578) --> + <skip /> <string name="permlab_accessNotifications" msgid="7673416487873432268">"访问通知"</string> <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_invokeCarrierSetup (3699600833975117478) --> + <skip /> + <!-- no translation found for permdesc_invokeCarrierSetup (4159549152529111920) --> + <skip /> <string name="policylab_limitPassword" msgid="4497420728857585791">"设置密码规则"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"控制屏幕解锁密码所允许的长度和字符。"</string> <string name="policylab_watchLogin" msgid="914130646942199503">"监视屏幕解锁尝试次数"</string> @@ -1593,11 +1605,19 @@ <skip /> <!-- no translation found for mediaSize_na_tabloid (5775966416333578127) --> <skip /> - <!-- no translation found for restr_pin_create_pin (8017600000263450337) --> + <!-- no translation found for write_fail_reason_cancelled (7091258378121627624) --> + <skip /> + <!-- no translation found for write_fail_reason_cannot_write (8132505417935337724) --> <skip /> <!-- no translation found for restr_pin_enter_pin (3395953421368476103) --> <skip /> - <!-- no translation found for restr_pin_confirm_pin (2891475237150965991) --> + <!-- no translation found for restr_pin_enter_old_pin (1462206225512910757) --> + <skip /> + <!-- no translation found for restr_pin_enter_new_pin (5959606691619959184) --> + <skip /> + <!-- no translation found for restr_pin_confirm_pin (8501523829633146239) --> + <skip /> + <!-- no translation found for restr_pin_create_pin (8017600000263450337) --> <skip /> <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) --> <skip /> diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml index 922a4f5..045314a 100644 --- a/core/res/res/values-zh-rTW/strings.xml +++ b/core/res/res/values-zh-rTW/strings.xml @@ -470,6 +470,10 @@ <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"允許應用程式使用 SurfaceFlinger 的低階功能。"</string> <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"讀取框架緩衝"</string> <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"允許應用程式讀取畫面緩衝區的內容。"</string> + <!-- no translation found for permlab_accessInputFlinger (5348635270689553857) --> + <skip /> + <!-- no translation found for permdesc_accessInputFlinger (2104864941201226616) --> + <skip /> <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"設定 Wi-Fi 顯示裝置"</string> <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"允許應用程式設定及連接 Wi-Fi 顯示裝置。"</string> <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"控制 Wi-Fi 顯示裝置"</string> @@ -639,10 +643,18 @@ <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"允許應用程式管理網路政策並定義應用程式專用規則。"</string> <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"修改網路使用量計算方式"</string> <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"允許應用程式修改應用程式網路使用量的計算方式 (不建議一般應用程式使用)。"</string> + <!-- no translation found for permlab_markNetworkSocket (3658527214914959749) --> + <skip /> + <!-- no translation found for permdesc_markNetworkSocket (7655568433696356578) --> + <skip /> <string name="permlab_accessNotifications" msgid="7673416487873432268">"存取通知"</string> <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_invokeCarrierSetup (3699600833975117478) --> + <skip /> + <!-- no translation found for permdesc_invokeCarrierSetup (4159549152529111920) --> + <skip /> <string name="policylab_limitPassword" msgid="4497420728857585791">"設定密碼規則"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"控制螢幕解鎖密碼所允許的長度和字元。"</string> <string name="policylab_watchLogin" msgid="914130646942199503">"監視螢幕解鎖嘗試次數"</string> @@ -1593,11 +1605,19 @@ <skip /> <!-- no translation found for mediaSize_na_tabloid (5775966416333578127) --> <skip /> - <!-- no translation found for restr_pin_create_pin (8017600000263450337) --> + <!-- no translation found for write_fail_reason_cancelled (7091258378121627624) --> + <skip /> + <!-- no translation found for write_fail_reason_cannot_write (8132505417935337724) --> <skip /> <!-- no translation found for restr_pin_enter_pin (3395953421368476103) --> <skip /> - <!-- no translation found for restr_pin_confirm_pin (2891475237150965991) --> + <!-- no translation found for restr_pin_enter_old_pin (1462206225512910757) --> + <skip /> + <!-- no translation found for restr_pin_enter_new_pin (5959606691619959184) --> + <skip /> + <!-- no translation found for restr_pin_confirm_pin (8501523829633146239) --> + <skip /> + <!-- no translation found for restr_pin_create_pin (8017600000263450337) --> <skip /> <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) --> <skip /> diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml index 3eaf19f..7152ebf 100644 --- a/core/res/res/values-zu/strings.xml +++ b/core/res/res/values-zu/strings.xml @@ -279,10 +279,8 @@ <string name="permdesc_reorderTasks" msgid="7734217754877439351">"Ivumela uhlelo lokusebenza ukugudluza imisebenzi ngaphambili nangasemuva. Uhlelo lokusebenza lungenza lokhu ngaphandle kwakho."</string> <string name="permlab_removeTasks" msgid="6821513401870377403">"misa izinsiza ezisebenzayo"</string> <string name="permdesc_removeTasks" msgid="1394714352062635493">"Vumela ukuthi insiza isuse okumele kwenziwe ibulale nezinsiza zakho. Izinsiza eziwubungozi zingaphazamisa ukusebenza kwezinye izinsiza."</string> - <!-- no translation found for permlab_manageActivityStacks (7391191384027303065) --> - <skip /> - <!-- no translation found for permdesc_manageActivityStacks (1615881933034084440) --> - <skip /> + <string name="permlab_manageActivityStacks" msgid="7391191384027303065">"phatha izitaki zomsebenzi"</string> + <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"Ivumela uhlelo lokusebenza ukuthi lingeze, lisuse, noma lilungise izitaki zomsebenzi lapho ezinye izinhlelo zokusebenza ziqalisa khona. Izinhlelo zokusebenza ezinobungozi zingaphazamisa ukuziphatha kwezinye izinhlelo zokusebenza."</string> <string name="permlab_startAnyActivity" msgid="2918768238045206456">"qala noma imuphi umsebenzi"</string> <string name="permdesc_startAnyActivity" msgid="997823695343584001">"Ivumela uhlelo lokusebenza ukuqala umsebenzi, ngaphandle kokuvukeleka kwemvume noma isimo sokukhishiwe."</string> <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"setha ukuhambelana kwesikrini"</string> @@ -360,14 +358,10 @@ <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Ivumela isimeli ukuhlanganisa uxhumano nomsebenzisi wezinga eliphezulu lendlela yokufaka. Ayisoze yadingeka kwizinhlelo ezivamile."</string> <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"hlanganisa kusevisi yokufinyeleleka"</string> <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Ivumela isibambi ukuhlanganisa uxhumo nomsebenzisi kwezinga eliphezulu lesevisi yesinqunjwana. Akusoze kwadingekela izinhlelo zokusebenza ezivamile."</string> - <!-- no translation found for permlab_bindPrintService (8462815179572748761) --> - <skip /> - <!-- no translation found for permdesc_bindPrintService (7960067623209111135) --> - <skip /> - <!-- no translation found for permlab_accessAllPrintJobs (1120792468465711159) --> - <skip /> - <!-- no translation found for permdesc_accessAllPrintJobs (2978185311041864762) --> - <skip /> + <string name="permlab_bindPrintService" msgid="8462815179572748761">"bophezela kusevisi yokuphrinta"</string> + <string name="permdesc_bindPrintService" msgid="7960067623209111135">"Ivumela umnikazi ukuthi abophezele isixhumanisi esibonakalayo sezinga eliphezulu sesevisi lokuphrinta. Akumele idingelwe izinhlelo zokusebenza ezijwayelekile."</string> + <string name="permlab_accessAllPrintJobs" msgid="1120792468465711159">"finyelela kuyo yonke imisebenzi yokuphrinta"</string> + <string name="permdesc_accessAllPrintJobs" msgid="2978185311041864762">"Ivumela umnikazi ukuthi afinyelele imisebenzi yokushicilela edalwe olunye uhlelo lokusebenza. Akumele idingelwe izinhlelo zokusebenza ezijwayelekile."</string> <string name="permlab_bindTextService" msgid="7358378401915287938">"bophezela kunsizakalo yombhalo"</string> <string name="permdesc_bindTextService" msgid="8151968910973998670">"Ivumela umbambi ukuhlanganisa uxhumano nomsebenzisi kwezinga eliphezulu lwesixhumi esibonakalayo sensizakalo yombhalo(isb. InsizakaloYokuhlolaUkubhala). Akusoze kwadingeka kwezinhlelo zokusebenza ezivamile."</string> <string name="permlab_bindVpnService" msgid="4708596021161473255">"hlanganisa kwinsizakalo ye-VPN"</string> @@ -470,6 +464,8 @@ <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Ivumela insiza ukuthi isebenzise okuqukethwe i-SurfaceFlinger okusezingeni eliphansi."</string> <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"funda isikhumbuli sesikhashana sendikimba"</string> <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Ivumela insiza ukuthi ifunde okuqukethwe ifreyimu yebhafa."</string> + <string name="permlab_accessInputFlinger" msgid="5348635270689553857">"finyelela ku-InputFlinger"</string> + <string name="permdesc_accessInputFlinger" msgid="2104864941201226616">"Ivumela uhlelo lokusebenza ukuthi lusebenzise izici zezinga eliphansi ze-InputFlinger."</string> <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"lungisa ukubukwa kwe-Wi-Fi"</string> <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Ivumela uhlelo lokusebenza ukulungisa nokuxhuma ekubukisweni kwe-Wi-Fi."</string> <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"lawula ukubukwa kwe-Wi-Fi"</string> @@ -639,10 +635,14 @@ <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Ivumela insiza ukuthi yengamele iigomo iphinde ichaze imithetho ehambisana ngqo nensiza."</string> <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"lungisa ukubala kokusebenza kohleloxhumano"</string> <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Ivumela insiza ukuthi iguqule ukuthii ukusetshenziswa kwenethiwekhi kumiswa kanjani ezinsizeni. Ayisetshenziswa izinsiza ezijwayelekile."</string> + <string name="permlab_markNetworkSocket" msgid="3658527214914959749">"shintsha izimpawu zesokhethi"</string> + <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"Ivumela uhlelo lokusebenza ukuthi lilungise izimpawu zesokhethi zomzila"</string> <string name="permlab_accessNotifications" msgid="7673416487873432268">"finyelela kuzaziso"</string> <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_invokeCarrierSetup" msgid="3699600833975117478">"buyisela uhlelo lokusebenza lokulungiselelwa okunikezwe yinkampani yenethiwekhi"</string> + <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Ivumela umnikazi ukuthi abuyisele uhlelo lokusebenza lokulungiselelwa. Akumele idingelwe izinhlelo zokusebenza ezijwayelekile."</string> <string name="policylab_limitPassword" msgid="4497420728857585791">"Misa imithetho yephasiwedi"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"Lawula ubude nezinhlamvu ezivunyelwe kumaphasiwedi okuvula isikrini"</string> <string name="policylab_watchLogin" msgid="914130646942199503">"Gaka imizamo yokuvula isikrini"</string> @@ -752,8 +752,7 @@ <string name="imProtocolYahoo" msgid="8271439408469021273">"i-Yahoo"</string> <string name="imProtocolSkype" msgid="9019296744622832951">"i-Skype"</string> <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string> - <!-- no translation found for imProtocolGoogleTalk (493902321140277304) --> - <skip /> + <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Ama-Hangout"</string> <string name="imProtocolIcq" msgid="1574870433606517315">"i-ICQ"</string> <string name="imProtocolJabber" msgid="2279917630875771722">"i-Jabber"</string> <string name="imProtocolNetMeeting" msgid="8287625655986827971">"Umhlangano we-Net"</string> @@ -1515,94 +1514,56 @@ <string name="app_no_restricted_accounts" msgid="5739463249673727736">"Lolu hlelo lokusebenza alusekeli ama-akhawunti wamaphrofayela akhawulelwe"</string> <string name="app_not_found" msgid="3429141853498927379">"Alukho uhlelo lokusebenza olutholakele lokuphatha lesi senzo"</string> <string name="revoke" msgid="5404479185228271586">"Chitha"</string> - <!-- no translation found for mediaSize_iso_a0 (7875427489420821793) --> - <skip /> - <!-- no translation found for mediaSize_iso_a1 (3760734499050875356) --> - <skip /> - <!-- no translation found for mediaSize_iso_a2 (5973266378020144382) --> - <skip /> - <!-- no translation found for mediaSize_iso_a3 (1373407105687300884) --> - <skip /> - <!-- no translation found for mediaSize_iso_a4 (6689772807982597254) --> - <skip /> - <!-- no translation found for mediaSize_iso_a5 (5353549652015741040) --> - <skip /> - <!-- no translation found for mediaSize_iso_a6 (8585038048674911907) --> - <skip /> - <!-- no translation found for mediaSize_iso_a7 (6641836716963839119) --> - <skip /> - <!-- no translation found for mediaSize_iso_a8 (7571139437465693355) --> - <skip /> - <!-- no translation found for mediaSize_iso_a9 (1378455891957115079) --> - <skip /> - <!-- no translation found for mediaSize_iso_a10 (2480747457429475344) --> - <skip /> - <!-- no translation found for mediaSize_iso_b0 (3965935097661108039) --> - <skip /> - <!-- no translation found for mediaSize_iso_b1 (2505753285010115437) --> - <skip /> - <!-- no translation found for mediaSize_iso_b2 (8763874709859458453) --> - <skip /> - <!-- no translation found for mediaSize_iso_b3 (4210506688191764076) --> - <skip /> - <!-- no translation found for mediaSize_iso_b4 (5749404165888526034) --> - <skip /> - <!-- no translation found for mediaSize_iso_b5 (7640627414621904733) --> - <skip /> - <!-- no translation found for mediaSize_iso_b6 (7342988864712748544) --> - <skip /> - <!-- no translation found for mediaSize_iso_b7 (5069844065235382429) --> - <skip /> - <!-- no translation found for mediaSize_iso_b8 (7316818922278779774) --> - <skip /> - <!-- no translation found for mediaSize_iso_b9 (5414727094026532341) --> - <skip /> - <!-- no translation found for mediaSize_iso_b10 (5251253731832048185) --> - <skip /> - <!-- no translation found for mediaSize_iso_c0 (4003138342671964217) --> - <skip /> - <!-- no translation found for mediaSize_iso_c1 (1935188063393553008) --> - <skip /> - <!-- no translation found for mediaSize_iso_c2 (3197307969712069904) --> - <skip /> - <!-- no translation found for mediaSize_iso_c3 (4335826087321913508) --> - <skip /> - <!-- no translation found for mediaSize_iso_c4 (3745639598281015005) --> - <skip /> - <!-- no translation found for mediaSize_iso_c5 (8269457765822791013) --> - <skip /> - <!-- no translation found for mediaSize_iso_c6 (566666105260346930) --> - <skip /> - <!-- no translation found for mediaSize_iso_c7 (8678413180782608498) --> - <skip /> - <!-- no translation found for mediaSize_iso_c8 (8392376206627041730) --> - <skip /> - <!-- no translation found for mediaSize_iso_c9 (9191613372324845405) --> - <skip /> - <!-- no translation found for mediaSize_iso_c10 (7327709699184920822) --> - <skip /> - <!-- no translation found for mediaSize_na_letter (4191805615829472953) --> - <skip /> - <!-- no translation found for mediaSize_na_gvrnmt_letter (7853382192649405507) --> - <skip /> - <!-- no translation found for mediaSize_na_legal (6697982988283823150) --> - <skip /> - <!-- no translation found for mediaSize_na_junior_legal (3727743969902758948) --> - <skip /> - <!-- no translation found for mediaSize_na_ledger (281871464896601236) --> - <skip /> - <!-- no translation found for mediaSize_na_tabloid (5775966416333578127) --> - <skip /> - <!-- no translation found for restr_pin_create_pin (8017600000263450337) --> - <skip /> - <!-- no translation found for restr_pin_enter_pin (3395953421368476103) --> - <skip /> - <!-- no translation found for restr_pin_confirm_pin (2891475237150965991) --> - <skip /> - <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) --> - <skip /> - <!-- no translation found for restr_pin_error_too_short (8173982756265777792) --> - <skip /> - <!-- no translation found for restr_pin_countdown:one (4835639969503729874) --> - <!-- no translation found for restr_pin_countdown:other (8030607343223287654) --> + <string name="mediaSize_iso_a0" msgid="7875427489420821793">"I-ISO A0"</string> + <string name="mediaSize_iso_a1" msgid="3760734499050875356">"I-ISO A1"</string> + <string name="mediaSize_iso_a2" msgid="5973266378020144382">"I-ISO A2"</string> + <string name="mediaSize_iso_a3" msgid="1373407105687300884">"I-ISO A3"</string> + <string name="mediaSize_iso_a4" msgid="6689772807982597254">"I-ISO A4"</string> + <string name="mediaSize_iso_a5" msgid="5353549652015741040">"I-ISO A5"</string> + <string name="mediaSize_iso_a6" msgid="8585038048674911907">"I-ISO A6"</string> + <string name="mediaSize_iso_a7" msgid="6641836716963839119">"I-ISO A7"</string> + <string name="mediaSize_iso_a8" msgid="7571139437465693355">"I-ISO A8"</string> + <string name="mediaSize_iso_a9" msgid="1378455891957115079">"I-ISO A9"</string> + <string name="mediaSize_iso_a10" msgid="2480747457429475344">"I-ISO A10"</string> + <string name="mediaSize_iso_b0" msgid="3965935097661108039">"I-ISO B0"</string> + <string name="mediaSize_iso_b1" msgid="2505753285010115437">"I-ISO B1"</string> + <string name="mediaSize_iso_b2" msgid="8763874709859458453">"I-ISO B2"</string> + <string name="mediaSize_iso_b3" msgid="4210506688191764076">"I-ISO B3"</string> + <string name="mediaSize_iso_b4" msgid="5749404165888526034">"I-ISO B4"</string> + <string name="mediaSize_iso_b5" msgid="7640627414621904733">"I-ISO B5"</string> + <string name="mediaSize_iso_b6" msgid="7342988864712748544">"I-ISO B6"</string> + <string name="mediaSize_iso_b7" msgid="5069844065235382429">"I-ISO B7"</string> + <string name="mediaSize_iso_b8" msgid="7316818922278779774">"I-ISO B8"</string> + <string name="mediaSize_iso_b9" msgid="5414727094026532341">"I-ISO B9"</string> + <string name="mediaSize_iso_b10" msgid="5251253731832048185">"I-ISO B10"</string> + <string name="mediaSize_iso_c0" msgid="4003138342671964217">"I-ISO C0"</string> + <string name="mediaSize_iso_c1" msgid="1935188063393553008">"I-ISO C1"</string> + <string name="mediaSize_iso_c2" msgid="3197307969712069904">"I-ISO C2"</string> + <string name="mediaSize_iso_c3" msgid="4335826087321913508">"I-ISO C3"</string> + <string name="mediaSize_iso_c4" msgid="3745639598281015005">"I-ISO C4"</string> + <string name="mediaSize_iso_c5" msgid="8269457765822791013">"I-ISO C5"</string> + <string name="mediaSize_iso_c6" msgid="566666105260346930">"I-ISO C6"</string> + <string name="mediaSize_iso_c7" msgid="8678413180782608498">"I-ISO C7"</string> + <string name="mediaSize_iso_c8" msgid="8392376206627041730">"I-ISO C8"</string> + <string name="mediaSize_iso_c9" msgid="9191613372324845405">"I-ISO C9"</string> + <string name="mediaSize_iso_c10" msgid="7327709699184920822">"I-ISO C10"</string> + <string name="mediaSize_na_letter" msgid="4191805615829472953">"Incwadi"</string> + <string name="mediaSize_na_gvrnmt_letter" msgid="7853382192649405507">"Incwadi kahulumeni"</string> + <string name="mediaSize_na_legal" msgid="6697982988283823150">"Okusemthethweni"</string> + <string name="mediaSize_na_junior_legal" msgid="3727743969902758948">"Ezomthetho ezincane"</string> + <string name="mediaSize_na_ledger" msgid="281871464896601236">"Ileja"</string> + <string name="mediaSize_na_tabloid" msgid="5775966416333578127">"Iphephandaba"</string> + <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"Kukhanseliwe"</string> + <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"Iphutha ekubhaleni okuqukethwe"</string> + <string name="restr_pin_enter_pin" msgid="3395953421368476103">"Faka i-PIN"</string> + <string name="restr_pin_enter_old_pin" msgid="1462206225512910757">"I-PIN yamanje"</string> + <string name="restr_pin_enter_new_pin" msgid="5959606691619959184">"I-PIN entsha"</string> + <string name="restr_pin_confirm_pin" msgid="8501523829633146239">"Qinisekisa i-PIN entsha"</string> + <string name="restr_pin_create_pin" msgid="8017600000263450337">"Dala i-PIN yemikhawulo yokushintsha"</string> + <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"Ama-PIN awafani. Zama futhi."</string> + <string name="restr_pin_error_too_short" msgid="8173982756265777792">"I-PIN yimfushane kakhulu. Okungenani kumele ibe namadijithi angu-4."</string> + <plurals name="restr_pin_countdown"> + <item quantity="one" msgid="4835639969503729874">"I-PIN engalungile. Zama futhi ngesekhondi elingu-1."</item> + <item quantity="other" msgid="8030607343223287654">"I-PIN engalungile. Zama futhi kumasekhondi angu-<xliff:g id="COUNT">%d</xliff:g>."</item> + </plurals> </resources> diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index 99f7e7a..181793f 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -1550,6 +1550,7 @@ <enum name="KEYCODE_ASSIST" value="219" /> <enum name="KEYCODE_BRIGHTNESS_DOWN" value="220" /> <enum name="KEYCODE_BRIGHTNESS_UP" value="221" /> + <enum name="KEYCODE_MEDIA_AUDIO_TRACK" value="222" /> </attr> <!-- ***************************************************************** --> @@ -2577,6 +2578,31 @@ <attr name="vendor" format="string"/> </declare-styleable> + <!-- Use <code>apdu-service</code> as the root tag of the XML resource that + describes an {@link android.nfc.cardemulation.HostApduService} or + {@link android.nfc.cardemulation.SeApduService} service, which is referenced + from its SERVICE_META_DATA entry. --> + <declare-styleable name="ApduService"> + <!-- Set to true to let the NFC subsystem know that this service implements + a payment instrument. That will allow this service to be enumerated in + a list of payment services, where the user can pick his preferred payment + service. The preferred service will be bound to persistently, to make sure + it can immediately process APDUs without service startup delay. This is vital + for existing payment infrastructure that has very strict timing requirements. --> + <attr name="paymentService" format="boolean" /> + <!-- Short description of the functionality the serivce implements.--> + <attr name="description" /> + </declare-styleable> + + <!-- Specify one or more <code>aid-filter</code> elements inside a <code>apdu-service</code> + element to list the ISO7816 Application ID (AIDs) your service can handle.--> + <declare-styleable name="AidFilter"> + <!-- The ISO7816 Application ID --> + <attr name="aid" format="string" /> + <!-- Short description of what the AID implements.--> + <attr name="description" /> + </declare-styleable> + <declare-styleable name="ActionMenuItemView"> <attr name="minWidth" /> </declare-styleable> diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index 3ab8825..e5fcfb0 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -2068,5 +2068,6 @@ <public type="attr" name="sspPattern" /> <public type="attr" name="addPrintersActivity" /> <public type="attr" name="vendor" /> - + <public type="attr" name="paymentService" /> + <public type="attr" name="aid" /> </resources> diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index 37c5d48..b01b50e 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -4169,94 +4169,103 @@ <!-- Printing --> - <!-- ISO A0 media size: 33.11" × 46.81" --> + <!-- ISO (European standard) A0 media (paper) size: 33.11" × 46.81" --> <string name="mediaSize_iso_a0">ISO A0</string> - <!-- ISO A1 media size: 23.39" × 33.11" --> + <!-- ISO (European standard) A1 media (paper) size: 23.39" × 33.11" --> <string name="mediaSize_iso_a1">ISO A1</string> - <!-- ISO A2 media size: 16.54" x 23.39" --> + <!-- ISO (European standard) A2 media (paper) size: 16.54" x 23.39" --> <string name="mediaSize_iso_a2">ISO A2</string> - <!-- ISO A3 media size: 11.69" x 16.54" --> + <!-- ISO (European standard) A3 media (paper) size: 11.69" x 16.54" --> <string name="mediaSize_iso_a3">ISO A3</string> - <!-- ISO A4 media size: 8.27" x 11.69" --> + <!-- ISO (European standard) A4 media (paper) size: 8.27" x 11.69" --> <string name="mediaSize_iso_a4">ISO A4</string> - <!-- ISO A5 media size: 5.83" x 8.27" --> + <!-- ISO (European standard) A5 media (paper) size: 5.83" x 8.27" --> <string name="mediaSize_iso_a5">ISO A5</string> - <!-- ISO A6 media size: 4.13" x 5.83" --> + <!-- ISO (European standard) A6 media (paper) size: 4.13" x 5.83" --> <string name="mediaSize_iso_a6">ISO A6</string> - <!-- ISO A7 media size: 2.91" x 4.13" --> + <!-- ISO (European standard) A7 media (paper) size: 2.91" x 4.13" --> <string name="mediaSize_iso_a7">ISO A7</string> - <!-- ISO A8 media size: 2.05" x 2.91" --> + <!-- ISO (European standard) A8 media (paper) size: 2.05" x 2.91" --> <string name="mediaSize_iso_a8">ISO A8</string> - <!-- ISO A9 media size: 1.46" x 2.05" --> + <!-- ISO (European standard) A9 media (paper) size: 1.46" x 2.05" --> <string name="mediaSize_iso_a9">ISO A9</string> - <!-- ISO A10 media size: 1.02" x 1.46" --> + <!-- ISO (European standard) A10 media (paper) size: 1.02" x 1.46" --> <string name="mediaSize_iso_a10">ISO A10</string> - <!-- ISO B0 media size: 39.37" x 55.67" --> + <!-- ISO (European standard) B0 media (paper) size: 39.37" x 55.67" --> <string name="mediaSize_iso_b0">ISO B0</string> - <!-- ISO B1 media size: 27.83" x 39.37" --> + <!-- ISO (European standard) B1 media (paper) size: 27.83" x 39.37" --> <string name="mediaSize_iso_b1">ISO B1</string> - <!-- ISO B2 media size - 19.69" x 27.83" --> + <!-- ISO (European standard) B2 media (paper) size - 19.69" x 27.83" --> <string name="mediaSize_iso_b2">ISO B2</string> - <!-- ISO B3 media size: 13.90" x 19.69" --> + <!-- ISO (European standard) B3 media (paper) size: 13.90" x 19.69" --> <string name="mediaSize_iso_b3">ISO B3</string> - <!-- ISO B4 media size: 9.84" x 13.90" --> + <!-- ISO (European standard) B4 media (paper) size: 9.84" x 13.90" --> <string name="mediaSize_iso_b4">ISO B4</string> - <!-- ISO B5 media size: 6.93" x 9.84" --> + <!-- ISO (European standard) B5 media (paper) size: 6.93" x 9.84" --> <string name="mediaSize_iso_b5">ISO B5</string> - <!-- ISO B6 media size: 4.92" x 6.93" --> + <!-- ISO (European standard) B6 media (paper) size: 4.92" x 6.93" --> <string name="mediaSize_iso_b6">ISO B6</string> - <!-- ISO B7 media size: 3.46" x 4.92" --> + <!-- ISO (European standard) B7 media (paper) size: 3.46" x 4.92" --> <string name="mediaSize_iso_b7">ISO B7</string> - <!-- ISO B8 media size: 2.44" x 3.46" --> + <!-- ISO (European standard) B8 media (paper) size: 2.44" x 3.46" --> <string name="mediaSize_iso_b8">ISO B8</string> - <!-- ISO B9 media size: 1.73" x 2.44" --> + <!-- ISO (European standard) B9 media (paper) size: 1.73" x 2.44" --> <string name="mediaSize_iso_b9">ISO B9</string> - <!-- ISO B10 media size: 1.22" x 1.73" --> + <!-- ISO (European standard) B10 media (paper) size: 1.22" x 1.73" --> <string name="mediaSize_iso_b10">ISO B10</string> - <!-- ISO C0 media size: 36.10" x 51.06" --> + <!-- ISO (European standard) C0 media (paper) size: 36.10" x 51.06" --> <string name="mediaSize_iso_c0">ISO C0</string> - <!-- ISO C1 media size: 25.51" x 36.10" --> + <!-- ISO (European standard) C1 media (paper) size: 25.51" x 36.10" --> <string name="mediaSize_iso_c1">ISO C1</string> - <!-- ISO C2 media size: 18.03" x 25.51" --> + <!-- ISO (European standard) C2 media (paper) size: 18.03" x 25.51" --> <string name="mediaSize_iso_c2">ISO C2</string> - <!-- ISO C3 media size: 12.76" x 18.03" --> + <!-- ISO (European standard) C3 media (paper) size: 12.76" x 18.03" --> <string name="mediaSize_iso_c3">ISO C3</string> - <!-- ISO C4 media size: 9.02" x 12.76" --> + <!-- ISO (European standard) C4 media (paper) size: 9.02" x 12.76" --> <string name="mediaSize_iso_c4">ISO C4</string> - <!-- ISO C5 media size: 6.38" x 9.02" --> + <!-- ISO (European standard) C5 media (paper) size: 6.38" x 9.02" --> <string name="mediaSize_iso_c5">ISO C5</string> - <!-- ISO C6 media size: 4.49" x 6.38" --> + <!-- ISO (European standard) C6 media (paper) size: 4.49" x 6.38" --> <string name="mediaSize_iso_c6">ISO C6</string> - <!-- ISO C7 media size: 3.19" x 4.49" --> + <!-- ISO (European standard) C7 media (paper) size: 3.19" x 4.49" --> <string name="mediaSize_iso_c7">ISO C7</string> - <!-- ISO ISO C8 media size: 2.24" x 3.19" --> + <!-- ISO ISO C8 media (paper) size: 2.24" x 3.19" --> <string name="mediaSize_iso_c8">ISO C8</string> - <!-- ISO ISO C9 media size: 1.57" x 2.24" --> + <!-- ISO ISO C9 media (paper) size: 1.57" x 2.24" --> <string name="mediaSize_iso_c9">ISO C9</string> - <!-- ISO C10 media size: 1.10" x 1.57" --> + <!-- ISO (European standard) C10 media (paper) size: 1.10" x 1.57" --> <string name="mediaSize_iso_c10">ISO C10</string> - <!-- North America Letter media size: 8.5" × 11" --> + <!-- North America Letter media (paper) size: 8.5" × 11" --> <string name="mediaSize_na_letter">Letter</string> - <!-- North America Government Letter media size: 8.0" × 10.5" --> + <!-- North America Government Letter media (paper) size: 8.0" × 10.5" --> <string name="mediaSize_na_gvrnmt_letter">Government Letter</string> - <!-- North America Legal media size: 8.5" × 14" --> + <!-- North America Legal media (paper) size: 8.5" × 14" --> <string name="mediaSize_na_legal">Legal</string> - <!-- North America Junior Legal media size: 8.0" × 5.0" --> + <!-- North America Junior Legal media (paper) size: 8.0" × 5.0" --> <string name="mediaSize_na_junior_legal">Junior Legal</string> - <!-- North America Ledger media size: 17" × 11" --> + <!-- North America Ledger media (paper) size: 17" × 11" --> <string name="mediaSize_na_ledger">Ledger</string> - <!-- North America Tabloid media size: 11" × 17" --> + <!-- North America Tabloid media (paper) size: 11" × 17" --> <string name="mediaSize_na_tabloid">Tabloid</string> + <!-- Write fail reason: printing was cancelled.[CHAR LIMIT=none] --> + <string name="write_fail_reason_cancelled">Cancelled</string> + <!-- Write fail reason: couldn't write the printed content. [CHAR LIMIT=none] --> + <string name="write_fail_reason_cannot_write">Error writing content</string> + + <!-- PIN entry dialog label/hint for PIN [CHAR LIMIT=none] --> + <string name="restr_pin_enter_pin">Enter PIN</string> + <!-- PIN entry dialog label/hint for old PIN [CHAR LIMIT=none] --> + <string name="restr_pin_enter_old_pin">Current PIN</string> + <!-- PIN entry dialog label for new PIN [CHAR LIMIT=none] --> + <string name="restr_pin_enter_new_pin">New PIN</string> + <!-- PIN entry dialog label for new PIN confirmation [CHAR LIMIT=none] --> + <string name="restr_pin_confirm_pin">Confirm new PIN</string> <!-- PIN creation dialog message [CHAR LIMIT=none] --> <string name="restr_pin_create_pin">Create a PIN for modifying restrictions</string> - <!-- PIN entry dialog label for PIN [CHAR LIMIT=none] --> - <string name="restr_pin_enter_pin">Enter PIN</string> - <!-- PIN entry dialog label for PIN confirmation [CHAR LIMIT=none] --> - <string name="restr_pin_confirm_pin">Confirm PIN</string> <!-- PIN entry dialog error when PINs are not the same [CHAR LIMIT=none] --> <string name="restr_pin_error_doesnt_match">PINs don\'t match. Try again.</string> <!-- PIN entry dialog error when PIN is too short [CHAR LIMIT=none] --> @@ -4267,4 +4276,5 @@ <item quantity="one">Incorrect PIN. Try again in 1 second.</item> <item quantity="other">Incorrect PIN. Try again in <xliff:g id="count">%d</xliff:g> seconds.</item> </plurals> + </resources> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index b58fcfc..8a12ac8 100755 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -214,8 +214,9 @@ <java-symbol type="id" name="breadcrumb_section" /> <java-symbol type="id" name="action_bar_spinner" /> <java-symbol type="id" name="pin_message" /> - <java-symbol type="id" name="pin1_text" /> - <java-symbol type="id" name="pin2_text" /> + <java-symbol type="id" name="pin_text" /> + <java-symbol type="id" name="pin_new_text" /> + <java-symbol type="id" name="pin_confirm_text" /> <java-symbol type="id" name="pin_error_message" /> <java-symbol type="attr" name="actionModeShareDrawable" /> @@ -907,6 +908,8 @@ <java-symbol type="string" name="mediaSize_na_ledger" /> <java-symbol type="string" name="mediaSize_na_tabloid" /> <java-symbol type="string" name="restr_pin_enter_pin" /> + <java-symbol type="string" name="write_fail_reason_cancelled" /> + <java-symbol type="string" name="write_fail_reason_cannot_write" /> <java-symbol type="plurals" name="abbrev_in_num_days" /> <java-symbol type="plurals" name="abbrev_in_num_hours" /> @@ -1155,7 +1158,8 @@ <java-symbol type="layout" name="sms_short_code_confirmation_dialog" /> <java-symbol type="layout" name="action_bar_up_container" /> <java-symbol type="layout" name="app_not_authorized" /> - <java-symbol type="layout" name="pin_challenge" /> + <java-symbol type="layout" name="restrictions_pin_challenge" /> + <java-symbol type="layout" name="restrictions_pin_setup" /> <java-symbol type="anim" name="slide_in_child_bottom" /> <java-symbol type="anim" name="slide_in_right" /> diff --git a/core/res/res/xml/audio_assets.xml b/core/res/res/xml/audio_assets.xml index 746dbab..af5798a 100644 --- a/core/res/res/xml/audio_assets.xml +++ b/core/res/res/xml/audio_assets.xml @@ -34,5 +34,6 @@ <asset id="FX_KEYPRESS_SPACEBAR" file="KeypressSpacebar.ogg"/> <asset id="FX_KEYPRESS_DELETE" file="KeypressDelete.ogg"/> <asset id="FX_KEYPRESS_RETURN" file="KeypressReturn.ogg"/> + <asset id="FX_KEYPRESS_INVALID" file="KeypressInvalid.ogg"/> </group> </audio_assets> diff --git a/data/etc/platform.xml b/data/etc/platform.xml index 1289971..ec8e7ea 100644 --- a/data/etc/platform.xml +++ b/data/etc/platform.xml @@ -54,10 +54,6 @@ <group gid="inet" /> </permission> - <permission name="android.permission.CAMERA" > - <group gid="camera" /> - </permission> - <permission name="android.permission.READ_LOGS" > <group gid="log" /> </permission> diff --git a/data/sounds/AllAudio.mk b/data/sounds/AllAudio.mk index 8b03bf7..ed9bea5 100644 --- a/data/sounds/AllAudio.mk +++ b/data/sounds/AllAudio.mk @@ -221,6 +221,7 @@ PRODUCT_COPY_FILES += \ $(LOCAL_PATH)/effects/ogg/KeypressReturn_120_48k.ogg:system/media/audio/ui/KeypressReturn.ogg \ $(LOCAL_PATH)/effects/ogg/KeypressSpacebar_120_48k.ogg:system/media/audio/ui/KeypressSpacebar.ogg \ $(LOCAL_PATH)/effects/ogg/KeypressStandard_120_48k.ogg:system/media/audio/ui/KeypressStandard.ogg \ + $(LOCAL_PATH)/effects/ogg/KeypressInvalid_120_48k.ogg:system/media/audio/ui/KeypressInvalid.ogg \ $(LOCAL_PATH)/effects/ogg/Lock.ogg:system/media/audio/ui/Lock.ogg \ $(LOCAL_PATH)/effects/ogg/LowBattery.ogg:system/media/audio/ui/LowBattery.ogg \ $(LOCAL_PATH)/effects/ogg/Undock.ogg:system/media/audio/ui/Undock.ogg \ diff --git a/data/sounds/AudioPackage11.mk b/data/sounds/AudioPackage11.mk index e16a92d..2897b04 100644 --- a/data/sounds/AudioPackage11.mk +++ b/data/sounds/AudioPackage11.mk @@ -43,7 +43,7 @@ PRODUCT_COPY_FILES += \ $(LOCAL_PATH)/notifications/ogg/Spica.ogg:system/media/audio/notifications/Spica.ogg \ $(LOCAL_PATH)/notifications/ogg/Syrma.ogg:system/media/audio/notifications/Syrma.ogg \ $(LOCAL_PATH)/notifications/ogg/Talitha.ogg:system/media/audio/notifications/Talitha.ogg \ - $(LOCAL_PATH)/notifications/ogg/Tejat.ogg:system/media/audio/notifications/Tejat.ogg \ + $(LOCAL_PATH)/notifications/ogg/Tejat_proc48.ogg:system/media/audio/notifications/Tejat.ogg \ $(LOCAL_PATH)/notifications/ogg/Vega.ogg:system/media/audio/notifications/Vega.ogg \ $(LOCAL_PATH)/ringtones/ogg/Andromeda.ogg:system/media/audio/ringtones/Andromeda.ogg \ $(LOCAL_PATH)/ringtones/ogg/Aquila.ogg:system/media/audio/ringtones/Aquila.ogg \ diff --git a/data/sounds/effects/KeypressInvalid.ogg b/data/sounds/effects/KeypressInvalid.ogg Binary files differnew file mode 100644 index 0000000..24935ad --- /dev/null +++ b/data/sounds/effects/KeypressInvalid.ogg diff --git a/data/sounds/effects/KeypressInvalid.wav b/data/sounds/effects/KeypressInvalid.wav Binary files differnew file mode 100644 index 0000000..c4180e3 --- /dev/null +++ b/data/sounds/effects/KeypressInvalid.wav diff --git a/data/sounds/effects/ogg/KeypressInvalid_120_48k.ogg b/data/sounds/effects/ogg/KeypressInvalid_120_48k.ogg Binary files differnew file mode 100644 index 0000000..24935ad --- /dev/null +++ b/data/sounds/effects/ogg/KeypressInvalid_120_48k.ogg diff --git a/data/sounds/notifications/ogg/Tejat_proc48.ogg b/data/sounds/notifications/ogg/Tejat_proc48.ogg Binary files differnew file mode 100644 index 0000000..b1637d7 --- /dev/null +++ b/data/sounds/notifications/ogg/Tejat_proc48.ogg diff --git a/data/sounds/notifications/wav/Deneb_processed_48kHz.wav b/data/sounds/notifications/wav/Deneb_processed_48kHz.wav Binary files differnew file mode 100644 index 0000000..e2df8e9 --- /dev/null +++ b/data/sounds/notifications/wav/Deneb_processed_48kHz.wav diff --git a/docs/html/about/versions/android-4.3.jd b/docs/html/about/versions/android-4.3.jd index 0ca3bc6..d0ccfbe 100644 --- a/docs/html/about/versions/android-4.3.jd +++ b/docs/html/about/versions/android-4.3.jd @@ -7,7 +7,7 @@ sdk.platform.apiLevel=18 <div id="qv-wrapper"> <div id="qv"> - + <h2>In this document <a href="#" onclick="hideNestedItems('#toc43',this);return false;" class="header-toggle"> <span class="more">show more</span> @@ -62,7 +62,6 @@ sdk.platform.apiLevel=18 </li> <li><a href="#UserInput">User Input</a> <ol> - <li><a href="#SignificantMotion">Detect significant motion</a></li> <li><a href="#Sensors">New sensor types</a></li> </ol> </li> @@ -133,7 +132,7 @@ image to test your app on the <a href="{@docRoot}tools/devices/emulator.html">An Then build your apps against the Android {@sdkPlatformVersion} platform to begin using the latest APIs.</p> - + <h3 id="ApiLevel">Update your target API level</h3> <p>To better optimize your app for devices running Android {@sdkPlatformVersion}, @@ -145,7 +144,7 @@ test it, then publish an update with this change.</p> <p>You can use APIs in Android {@sdkPlatformVersion} while also supporting older versions by adding conditions to your code that check for the system API level before executing APIs not supported by your <a -href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">{@code minSdkVersion}</a>. +href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">{@code minSdkVersion}</a>. To learn more about maintaining backward compatibility, read <a href="{@docRoot}training/basics/supporting-devices/platforms.html">Supporting Different Platform Versions</a>.</p> @@ -172,11 +171,11 @@ be affected by changes in Android {@sdkPlatformVersion}.</p> <p>Your app might misbehave in a restricted profile environment.</p> -<p>Users in a <a href="#RestrictedProfiles">restricted profile</a> environment might not -have all the standard Android apps available. For example, a restricted profile might have the -web browser and camera app disabled. So your app should not make assumptions about which apps are -available, because if you call {@link android.app.Activity#startActivity startActivity()} without -verifying whether an app is available to handle the {@link android.content.Intent}, +<p>Users in a <a href="#RestrictedProfiles">restricted profile</a> environment might not +have all the standard Android apps available. For example, a restricted profile might have the +web browser and camera app disabled. So your app should not make assumptions about which apps are +available, because if you call {@link android.app.Activity#startActivity startActivity()} without +verifying whether an app is available to handle the {@link android.content.Intent}, your app might crash in a restricted profile.</p> <p>When using an implicit intent, you should always verify that an app is available to handle the intent by calling {@link android.content.Intent#resolveActivity resolveActivity()} or {@link android.content.pm.PackageManager#queryIntentActivities queryIntentActivities()}. For example:</p> @@ -197,20 +196,20 @@ if (intent.resolveActivity(getPackageManager()) != null) { <p>Your app might misbehave in a restricted profile environment.</p> <p>Users within a restricted profile environment do not have access to user accounts by default. -If your app depends on an {@link android.accounts.Account}, then your app might crash or behave +If your app depends on an {@link android.accounts.Account}, then your app might crash or behave unexpectedly when used in a restricted profile.</p> <p>If you'd like to prevent restricted profiles from using your app entirely because your -app depends on account information that's sensitive, specify the <a -href="{@docRoot}guide/topics/manifest/application-element.html#requiredAccountType">{@code -android:requiredAccountType}</a> attribute in your manifest's <a -href="{@docRoot}guide/topics/manifest/application-element.html">{@code <application>}</a> +app depends on account information that's sensitive, specify the <a +href="{@docRoot}guide/topics/manifest/application-element.html#requiredAccountType">{@code +android:requiredAccountType}</a> attribute in your manifest's <a +href="{@docRoot}guide/topics/manifest/application-element.html">{@code <application>}</a> element.</p> -<p>If you’d like to allow restricted profiles to continue using your app even though they can’t -create their own accounts, then you can either disable your app features that require an account +<p>If you’d like to allow restricted profiles to continue using your app even though they can’t +create their own accounts, then you can either disable your app features that require an account or allow restricted profiles to access the accounts created by the primary user. For more -information, see the section +information, see the section below about <a href="#AccountsInProfile">Supporting accounts in a restricted profile</a>.</p> @@ -218,67 +217,67 @@ below about <a href="#AccountsInProfile">Supporting accounts in a restricted pro <h2 id="RestrictedProfiles">Restricted Profiles</h2> -<p>On Android tablets, users can now create restricted profiles based on the primary user. +<p>On Android tablets, users can now create restricted profiles based on the primary user. When users create a restricted profile, they can enable restrictions such as which apps are available to the profile. A new set of APIs in Android 4.3 also allow you to build fine-grain -restriction settings for the apps you develop. For example, by using the new APIs, you can -allow users to control what type of content is available within your app when running in a +restriction settings for the apps you develop. For example, by using the new APIs, you can +allow users to control what type of content is available within your app when running in a restricted profile environment.</p> -<p>The UI for users to control the restrictions you've built is managed by the system's +<p>The UI for users to control the restrictions you've built is managed by the system's Settings application. To make your app's restriction settings appear to the user, -you must declare the restrictions your app provides by creating a {@link -android.content.BroadcastReceiver} that receives the {@link android.content.Intent#ACTION_GET_RESTRICTION_ENTRIES} intent. The system invokes this intent to query -all apps for available restrictions, then builds the UI to allow the primary user to +you must declare the restrictions your app provides by creating a {@link +android.content.BroadcastReceiver} that receives the {@link android.content.Intent#ACTION_GET_RESTRICTION_ENTRIES} intent. The system invokes this intent to query +all apps for available restrictions, then builds the UI to allow the primary user to manage restrictions for each restricted profile. </p> -<p>In the {@link android.content.BroadcastReceiver#onReceive onReceive()} method of -your {@link android.content.BroadcastReceiver}, you must create a {@link -android.content.RestrictionEntry} for each restriction your app provides. Each {@link -android.content.RestrictionEntry} defines a restriction title, description, and one of the +<p>In the {@link android.content.BroadcastReceiver#onReceive onReceive()} method of +your {@link android.content.BroadcastReceiver}, you must create a {@link +android.content.RestrictionEntry} for each restriction your app provides. Each {@link +android.content.RestrictionEntry} defines a restriction title, description, and one of the following data types:</p> <ul> - <li>{@link android.content.RestrictionEntry#TYPE_BOOLEAN} for a restriction that is + <li>{@link android.content.RestrictionEntry#TYPE_BOOLEAN} for a restriction that is either true or false. - <li>{@link android.content.RestrictionEntry#TYPE_CHOICE} for a restriction that has + <li>{@link android.content.RestrictionEntry#TYPE_CHOICE} for a restriction that has multiple choices that are mutually exclusive (radio button choices). - <li>{@link android.content.RestrictionEntry#TYPE_MULTI_SELECT} for a restriction that + <li>{@link android.content.RestrictionEntry#TYPE_MULTI_SELECT} for a restriction that has multiple choices that are <em>not</em> mutually exclusive (checkbox choices). </ul> -<p>You then put all the {@link android.content.RestrictionEntry} objects into an {@link -java.util.ArrayList} and put it into the broadcast receiver's result as the value for the +<p>You then put all the {@link android.content.RestrictionEntry} objects into an {@link +java.util.ArrayList} and put it into the broadcast receiver's result as the value for the {@link android.content.Intent#EXTRA_RESTRICTIONS_LIST} extra.</p> -<p>The system creates the UI for your app's restrictions in the Settings app and saves each -restriction with the unique key you provided for each {@link android.content.RestrictionEntry} -object. When the user opens your app, you can query for any current restrictions by -calling {@link android.os.UserManager#getApplicationRestrictions getApplicationRestrictions()}. +<p>The system creates the UI for your app's restrictions in the Settings app and saves each +restriction with the unique key you provided for each {@link android.content.RestrictionEntry} +object. When the user opens your app, you can query for any current restrictions by +calling {@link android.os.UserManager#getApplicationRestrictions getApplicationRestrictions()}. This returns a {@link android.os.Bundle} containing the key-value pairs for each restriction you defined with the {@link android.content.RestrictionEntry} objects.</p> -<p>If you want to provide more specific restrictions that can't be handled by boolean, single -choice, and multi-choice values, then you can create an activity where the user can specify the -restrictions and allow users to open that activity from the restriction settings. In your -broadcast receiver, include the {@link android.content.Intent#EXTRA_RESTRICTIONS_INTENT} extra +<p>If you want to provide more specific restrictions that can't be handled by boolean, single +choice, and multi-choice values, then you can create an activity where the user can specify the +restrictions and allow users to open that activity from the restriction settings. In your +broadcast receiver, include the {@link android.content.Intent#EXTRA_RESTRICTIONS_INTENT} extra in the result {@link android.os.Bundle}. This extra must specify an {@link android.content.Intent} -indicating the {@link android.app.Activity} class to launch (use the -{@link android.os.Bundle#putParcelable putParcelable()} method to pass {@link +indicating the {@link android.app.Activity} class to launch (use the +{@link android.os.Bundle#putParcelable putParcelable()} method to pass {@link android.content.Intent#EXTRA_RESTRICTIONS_INTENT} with the intent). -When the primary user enters your activity to set custom restrictions, your -activity must then return a result containing the restriction values in an extra using either -the {@link android.content.Intent#EXTRA_RESTRICTIONS_LIST} or {@link +When the primary user enters your activity to set custom restrictions, your +activity must then return a result containing the restriction values in an extra using either +the {@link android.content.Intent#EXTRA_RESTRICTIONS_LIST} or {@link android.content.Intent#EXTRA_RESTRICTIONS_BUNDLE} key, depending on whether you specify {@link android.content.RestrictionEntry} objects or key-value pairs, respectively.</p> <h3 id="AccountsInProfile">Supporting accounts in a restricted profile</h3> -<p>Any accounts added to the primary user are available to a restricted profile, but the -accounts are not accessible from the {@link android.accounts.AccountManager} APIs by default. +<p>Any accounts added to the primary user are available to a restricted profile, but the +accounts are not accessible from the {@link android.accounts.AccountManager} APIs by default. If you attempt to add an account with {@link android.accounts.AccountManager} while in a restricted -profile, you will get a failure result. Due to these restrictions, you have the following +profile, you will get a failure result. Due to these restrictions, you have the following three options:</p> <li><strong>Allow access to the owner’s accounts from a restricted profile.</strong> @@ -289,21 +288,25 @@ href="{@docRoot}guide/topics/manifest/application-element.html"><application> android:restrictedAccountType="com.example.account.type" > </pre> -<p class="caution"><strong>Caution:</strong> Enabling this attribute provides your -app access to the primary user's accounts from restricted profiles. So you should allow this +<p class="caution"><strong>Caution:</strong> Enabling this attribute provides your +app access to the primary user's accounts from restricted profiles. So you should allow this only if the information displayed by your app does not reveal personally identifiable -information (PII) that’s considered sensitive.</p> +information (PII) that’s considered sensitive. The system settings will inform the primary +user that your app grants restricted profiles to their accounts, so it should be clear to the user +that account access is important for your app's functionality. If possible, you should also +provide adequate restriction controls for the primary user that define how much account access +is allowed in your app.</p> </li> <li><strong>Disable certain functionality when unable to modify accounts.</strong> -<p>If you want to use accounts, but don’t actually require them for your app’s primary -functionality, you can check for account availability and disable features when not available. -You should first check if there is an existing account available. If not, then query whether -it’s possible to create a new account by calling {@link -android.os.UserManager#getUserRestrictions()} and check the {@link -android.os.UserManager#DISALLOW_MODIFY_ACCOUNTS} extra in the result. If it is {@code true}, -then you should disable whatever functionality of your app requires access to accounts. +<p>If you want to use accounts, but don’t actually require them for your app’s primary +functionality, you can check for account availability and disable features when not available. +You should first check if there is an existing account available. If not, then query whether +it’s possible to create a new account by calling {@link +android.os.UserManager#getUserRestrictions()} and check the {@link +android.os.UserManager#DISALLOW_MODIFY_ACCOUNTS} extra in the result. If it is {@code true}, +then you should disable whatever functionality of your app requires access to accounts. For example:</p> <pre> UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE); @@ -312,15 +315,15 @@ if (restrictions.getBoolean(UserManager.DISALLOW_MODIFY_ACCOUNTS, false)) { // cannot add accounts, disable some functionality } </pre> -<p class="note"><strong>Note:</strong> In this scenario, you should <em>not</em> declare +<p class="note"><strong>Note:</strong> In this scenario, you should <em>not</em> declare any new attributes in your manifest file.</p> </li> <li><strong>Disable your app when unable to access private accounts.</strong> -<p>If it’s instead important that your app not be available to restricted profiles because -your app depends on sensitive personal information in an account (and because restricted profiles +<p>If it’s instead important that your app not be available to restricted profiles because +your app depends on sensitive personal information in an account (and because restricted profiles currently cannot add new accounts), add -the <a href="{@docRoot}guide/topics/manifest/application-element.html#requiredAccountType">{@code +the <a href="{@docRoot}guide/topics/manifest/application-element.html#requiredAccountType">{@code android:requiredAccountType}</a> attribute to the <a href="{@docRoot}guide/topics/manifest/application-element.html"><application></a> tag:</p> <pre> @@ -338,11 +341,11 @@ because the owner's personal email should not be available to restricted profile <h3 id="BTLE">Bluetooth Low Energy (Smart Ready)</h3> -<p>Android now supports Bluetooth Low Energy (LE) with new APIs in {@link android.bluetooth}. -With the new APIs, you can build Android apps that communicate with Bluetooth Low Energy +<p>Android now supports Bluetooth Low Energy (LE) with new APIs in {@link android.bluetooth}. +With the new APIs, you can build Android apps that communicate with Bluetooth Low Energy peripherals such as heart rate monitors and pedometers.</p> -<p>Because Bluetooth LE is a hardware feature that is not available on all +<p>Because Bluetooth LE is a hardware feature that is not available on all Android-powered devices, you must declare in your manifest file a <a href="{@docRoot}guide/topics/manifest/uses-feature-element.html">{@code <uses-feature>}</a> element for {@code "android.hardware.bluetooth_le"}:</p> @@ -350,11 +353,11 @@ element for {@code "android.hardware.bluetooth_le"}:</p> <uses-feature android:name="android.hardware.bluetooth_le" android:required="true" /> </pre> -<p>If you're already familiar with Android's Classic Bluetooth APIs, notice that using the -Bluetooth LE APIs has some differences. Most importantly is that there's now a {@link -android.bluetooth.BluetoothManager} class that you should use for some high level operations -such as acquiring a {@link android.bluetooth.BluetoothAdapter}, getting a list of connected -devices, and checking the state of a device. For example, here's how you should now get the +<p>If you're already familiar with Android's Classic Bluetooth APIs, notice that using the +Bluetooth LE APIs has some differences. Most importantly is that there's now a {@link +android.bluetooth.BluetoothManager} class that you should use for some high level operations +such as acquiring a {@link android.bluetooth.BluetoothAdapter}, getting a list of connected +devices, and checking the state of a device. For example, here's how you should now get the {@link android.bluetooth.BluetoothAdapter}:</p> <pre> final BluetoothManager bluetoothManager = @@ -362,32 +365,32 @@ final BluetoothManager bluetoothManager = mBluetoothAdapter = bluetoothManager.getAdapter(); </pre> -<p>To discover Bluetooth LE peripherals, call {@link android.bluetooth.BluetoothAdapter#startLeScan -startLeScan()} on the {@link android.bluetooth.BluetoothAdapter}, passing it an implementation -of the {@link android.bluetooth.BluetoothAdapter.LeScanCallback} interface. When the Bluetooth -adapter detects a Bluetooth LE peripheral, your {@link -android.bluetooth.BluetoothAdapter.LeScanCallback} implementation receives a call to the -{@link android.bluetooth.BluetoothAdapter.LeScanCallback#onLeScan onLeScan()} method. This -method provides you with a {@link android.bluetooth.BluetoothDevice} object representing the -detected device, the RSSI value for the device, and a byte array containing the device's +<p>To discover Bluetooth LE peripherals, call {@link android.bluetooth.BluetoothAdapter#startLeScan +startLeScan()} on the {@link android.bluetooth.BluetoothAdapter}, passing it an implementation +of the {@link android.bluetooth.BluetoothAdapter.LeScanCallback} interface. When the Bluetooth +adapter detects a Bluetooth LE peripheral, your {@link +android.bluetooth.BluetoothAdapter.LeScanCallback} implementation receives a call to the +{@link android.bluetooth.BluetoothAdapter.LeScanCallback#onLeScan onLeScan()} method. This +method provides you with a {@link android.bluetooth.BluetoothDevice} object representing the +detected device, the RSSI value for the device, and a byte array containing the device's advertisement record.</p> -<p>If you want to scan for only specific types of peripherals, you can instead call {@link -android.bluetooth.BluetoothAdapter#startLeScan startLeScan()} and include an array of {@link +<p>If you want to scan for only specific types of peripherals, you can instead call {@link +android.bluetooth.BluetoothAdapter#startLeScan startLeScan()} and include an array of {@link java.util.UUID} objects that specify the GATT services your app supports.</p> -<p class="note"><strong>Note:</strong> You can only scan for Bluetooth LE devices <em>or</em> -scan for Classic Bluetooth devices using previous APIs. You cannot scan for both LE and Classic +<p class="note"><strong>Note:</strong> You can only scan for Bluetooth LE devices <em>or</em> +scan for Classic Bluetooth devices using previous APIs. You cannot scan for both LE and Classic Bluetooth devices at once.</p> -<p>To then connect to a Bluetooth LE peripheral, call {@link -android.bluetooth.BluetoothDevice#connectGatt connectGatt()} on the corresponding -{@link android.bluetooth.BluetoothDevice} object, passing it an implementation of -{@link android.bluetooth.BluetoothGattCallback}. Your implementation of {@link -android.bluetooth.BluetoothGattCallback} receives callbacks regarding the connectivity -state with the device and other events. It's during the {@link -android.bluetooth.BluetoothGattCallback#onConnectionStateChange onConnectionStateChange()} -callback that you can begin communicating with the device if the method passes {@link +<p>To then connect to a Bluetooth LE peripheral, call {@link +android.bluetooth.BluetoothDevice#connectGatt connectGatt()} on the corresponding +{@link android.bluetooth.BluetoothDevice} object, passing it an implementation of +{@link android.bluetooth.BluetoothGattCallback}. Your implementation of {@link +android.bluetooth.BluetoothGattCallback} receives callbacks regarding the connectivity +state with the device and other events. It's during the {@link +android.bluetooth.BluetoothGattCallback#onConnectionStateChange onConnectionStateChange()} +callback that you can begin communicating with the device if the method passes {@link android.bluetooth.BluetoothProfile#STATE_CONNECTED} as the new state.</p> <p>Accessing Bluetooth features on a device also requires that your app request certain @@ -397,39 +400,39 @@ href="{@docRoot}guide/topics/connectivity/bluetooth-le.html">Bluetooth Low Energ <h3 id="WiFiScan">Wi-Fi scan-only mode</h3> -<p>When attempting to identify the user's location, Android may use Wi-Fi to help determine -the location by scanning nearby access points. However, users often keep Wi-Fi turned off to -conserve battery, resulting in location data that's less accurate. Android now includes a -scan-only mode that allows the device Wi-Fi to scan access points to help obtain the location +<p>When attempting to identify the user's location, Android may use Wi-Fi to help determine +the location by scanning nearby access points. However, users often keep Wi-Fi turned off to +conserve battery, resulting in location data that's less accurate. Android now includes a +scan-only mode that allows the device Wi-Fi to scan access points to help obtain the location without connecting to an access point, thus greatly reducing battery usage.</p> -<p>If you want to acquire the user's location but Wi-Fi is currently off, you can request the -user to enable Wi-Fi scan-only mode by calling {@link android.content.Context#startActivity -startActivity()} with the action {@link +<p>If you want to acquire the user's location but Wi-Fi is currently off, you can request the +user to enable Wi-Fi scan-only mode by calling {@link android.content.Context#startActivity +startActivity()} with the action {@link android.net.wifi.WifiManager#ACTION_REQUEST_SCAN_ALWAYS_AVAILABLE}.</p> <h3 id="WiFiConfig">Wi-Fi configuration</h3> -<p>New {@link android.net.wifi.WifiEnterpriseConfig} APIs allow enterprise-oriented services to +<p>New {@link android.net.wifi.WifiEnterpriseConfig} APIs allow enterprise-oriented services to automate Wi-Fi configuration for managed devices.</p> <h3 id="QuickResponse">Quick response for incoming calls</h3> -<p>Since Android 4.0, a feature called "Quick response" allows users to respond to incoming -calls with an immediate text message without needing to pick up the call or unlock the device. -Until now, these quick messages were always handled by the default Messaging app. Now any app -can declare its capability to handle these messages by creating a {@link android.app.Service} +<p>Since Android 4.0, a feature called "Quick response" allows users to respond to incoming +calls with an immediate text message without needing to pick up the call or unlock the device. +Until now, these quick messages were always handled by the default Messaging app. Now any app +can declare its capability to handle these messages by creating a {@link android.app.Service} with an intent filter for {@link android.telephony.TelephonyManager#ACTION_RESPOND_VIA_MESSAGE}.</p> -<p>When the user responds to an incoming call with a quick response, the Phone app sends -the {@link android.telephony.TelephonyManager#ACTION_RESPOND_VIA_MESSAGE} intent with a URI -describing the recipient (the caller) and the {@link android.content.Intent#EXTRA_TEXT} extra -with the message the user wants to send. When your service receives the intent, it should deliver +<p>When the user responds to an incoming call with a quick response, the Phone app sends +the {@link android.telephony.TelephonyManager#ACTION_RESPOND_VIA_MESSAGE} intent with a URI +describing the recipient (the caller) and the {@link android.content.Intent#EXTRA_TEXT} extra +with the message the user wants to send. When your service receives the intent, it should deliver the message and immediately stop itself (your app should not show an activity).</p> -<p>In order to receive this intent, you must declare the {@link +<p>In order to receive this intent, you must declare the {@link android.Manifest.permission#SEND_RESPOND_VIA_MESSAGE} permission.</p> @@ -438,120 +441,120 @@ android.Manifest.permission#SEND_RESPOND_VIA_MESSAGE} permission.</p> <h3 id="DASH">MPEG DASH support</h3> -<p>Android now supports Dynamic Adaptive Streaming over HTTP (DASH) in accordance with the -ISO/IEC 23009-1 standard, using existing APIs in {@link android.media.MediaCodec} and {@link -android.media.MediaExtractor}. The framework underlying these APIs has been updated to support -parsing of fragmented MP4 files, but your app is still responsible for parsing the MPD metadata +<p>Android now supports Dynamic Adaptive Streaming over HTTP (DASH) in accordance with the +ISO/IEC 23009-1 standard, using existing APIs in {@link android.media.MediaCodec} and {@link +android.media.MediaExtractor}. The framework underlying these APIs has been updated to support +parsing of fragmented MP4 files, but your app is still responsible for parsing the MPD metadata and passing the individual streams to {@link android.media.MediaExtractor}.</p> -<p>If you want to use DASH with encrypted content, notice that the {@link android.media.MediaExtractor#getSampleCryptoInfo getSampleCryptoInfo()} method returns the {@link -android.media.MediaCodec.CryptoInfo} metadata describing the structure of each encrypted media -sample. Also, the {@link android.media.MediaExtractor#getPsshInfo()} method has been added to -{@link android.media.MediaExtractor} so you can access the PSSH metadata for your DASH media. -This method returns a map of {@link java.util.UUID} objects to bytes, with the -{@link java.util.UUID} specifying the crypto scheme, and the bytes being the data specific +<p>If you want to use DASH with encrypted content, notice that the {@link android.media.MediaExtractor#getSampleCryptoInfo getSampleCryptoInfo()} method returns the {@link +android.media.MediaCodec.CryptoInfo} metadata describing the structure of each encrypted media +sample. Also, the {@link android.media.MediaExtractor#getPsshInfo()} method has been added to +{@link android.media.MediaExtractor} so you can access the PSSH metadata for your DASH media. +This method returns a map of {@link java.util.UUID} objects to bytes, with the +{@link java.util.UUID} specifying the crypto scheme, and the bytes being the data specific to that scheme.</p> <h3 id="DRM">Media DRM</h3> <p>The new {@link android.media.MediaDrm} class provides a modular solution for digital rights -management (DRM) with your media content by separating DRM concerns from media playback. For -instance, this API separation allows you to play back Widevine-encrypted content without having -to use the Widevine media format. This DRM solution also supports DASH Common Encryption so you +management (DRM) with your media content by separating DRM concerns from media playback. For +instance, this API separation allows you to play back Widevine-encrypted content without having +to use the Widevine media format. This DRM solution also supports DASH Common Encryption so you can use a variety of DRM schemes with your streaming content.</p> -<p>You can use {@link android.media.MediaDrm} to obtain opaque key-request messages and process -key-response messages from the server for license acquisition and provisioning. Your app is -responsible for handling the network communication with the servers; the {@link +<p>You can use {@link android.media.MediaDrm} to obtain opaque key-request messages and process +key-response messages from the server for license acquisition and provisioning. Your app is +responsible for handling the network communication with the servers; the {@link android.media.MediaDrm} class provides only the ability to generate and process the messages.</p> -<p>The {@link android.media.MediaDrm} APIs are intended to be used in conjunction with the -{@link android.media.MediaCodec} APIs that were introduced in Android 4.1 (API level 16), -including {@link android.media.MediaCodec} for encoding and decoding your content, {@link -android.media.MediaCrypto} for handling encrypted content, and {@link android.media.MediaExtractor} +<p>The {@link android.media.MediaDrm} APIs are intended to be used in conjunction with the +{@link android.media.MediaCodec} APIs that were introduced in Android 4.1 (API level 16), +including {@link android.media.MediaCodec} for encoding and decoding your content, {@link +android.media.MediaCrypto} for handling encrypted content, and {@link android.media.MediaExtractor} for extracting and demuxing your content.</p> -<p>You must first construct {@link android.media.MediaExtractor} and -{@link android.media.MediaCodec} objects. You can then access the DRM-scheme-identifying -{@link java.util.UUID}, typically from metadata in the content, and use it to construct an +<p>You must first construct {@link android.media.MediaExtractor} and +{@link android.media.MediaCodec} objects. You can then access the DRM-scheme-identifying +{@link java.util.UUID}, typically from metadata in the content, and use it to construct an instance of a {@link android.media.MediaDrm} object with its constructor.</p> <h3 id="EncodingSurface">Video encoding from a Surface</h3> -<p>Android 4.1 (API level 16) added the {@link android.media.MediaCodec} class for low-level -encoding and decoding of media content. When encoding video, Android 4.1 required that you provide -the media with a {@link java.nio.ByteBuffer} array, but Android 4.3 now allows you to use a {@link -android.view.Surface} as the input to an encoder. For instance, this allows you to encode input +<p>Android 4.1 (API level 16) added the {@link android.media.MediaCodec} class for low-level +encoding and decoding of media content. When encoding video, Android 4.1 required that you provide +the media with a {@link java.nio.ByteBuffer} array, but Android 4.3 now allows you to use a {@link +android.view.Surface} as the input to an encoder. For instance, this allows you to encode input from an existing video file or using frames generated from OpenGL ES.</p> -<p>To use a {@link android.view.Surface} as the input to your encoder, first call {@link -android.media.MediaCodec#configure configure()} for your {@link android.media.MediaCodec}. -Then call {@link android.media.MediaCodec#createInputSurface()} to receive the {@link +<p>To use a {@link android.view.Surface} as the input to your encoder, first call {@link +android.media.MediaCodec#configure configure()} for your {@link android.media.MediaCodec}. +Then call {@link android.media.MediaCodec#createInputSurface()} to receive the {@link android.view.Surface} upon which you can stream your media.</p> -<p>For example, you can use the given {@link android.view.Surface} as the window for an OpenGL -context by passing it to {@link android.opengl.EGL14#eglCreateWindowSurface -eglCreateWindowSurface()}. Then while rendering the surface, call {@link -android.opengl.EGL14#eglSwapBuffers eglSwapBuffers()} to pass the frame to the {@link +<p>For example, you can use the given {@link android.view.Surface} as the window for an OpenGL +context by passing it to {@link android.opengl.EGL14#eglCreateWindowSurface +eglCreateWindowSurface()}. Then while rendering the surface, call {@link +android.opengl.EGL14#eglSwapBuffers eglSwapBuffers()} to pass the frame to the {@link android.media.MediaCodec}.</p> -<p>To begin encoding, call {@link android.media.MediaCodec#start()} on the {@link -android.media.MediaCodec}. When done, call {@link android.media.MediaCodec#signalEndOfInputStream} -to terminate encoding, and call {@link android.view.Surface#release()} on the +<p>To begin encoding, call {@link android.media.MediaCodec#start()} on the {@link +android.media.MediaCodec}. When done, call {@link android.media.MediaCodec#signalEndOfInputStream} +to terminate encoding, and call {@link android.view.Surface#release()} on the {@link android.view.Surface}.</p> <h3 id="MediaMuxing">Media muxing</h3> -<p>The new {@link android.media.MediaMuxer} class enables multiplexing between one audio stream -and one video stream. These APIs serve as a counterpart to the {@link android.media.MediaExtractor} +<p>The new {@link android.media.MediaMuxer} class enables multiplexing between one audio stream +and one video stream. These APIs serve as a counterpart to the {@link android.media.MediaExtractor} class added in Android 4.2 for de-multiplexing (demuxing) media.</p> -<p>Supported output formats are defined in {@link android.media.MediaMuxer.OutputFormat}. Currently, -MP4 is the only supported output format and {@link android.media.MediaMuxer} currently supports +<p>Supported output formats are defined in {@link android.media.MediaMuxer.OutputFormat}. Currently, +MP4 is the only supported output format and {@link android.media.MediaMuxer} currently supports only one audio stream and/or one video stream at a time.</p> -<p>{@link android.media.MediaMuxer} is mostly designed to work with {@link android.media.MediaCodec} -so you can perform video processing through {@link android.media.MediaCodec} then save the -output to an MP4 file through {@link android.media.MediaMuxer}. You can also use {@link -android.media.MediaMuxer} in combination with {@link android.media.MediaExtractor} to perform +<p>{@link android.media.MediaMuxer} is mostly designed to work with {@link android.media.MediaCodec} +so you can perform video processing through {@link android.media.MediaCodec} then save the +output to an MP4 file through {@link android.media.MediaMuxer}. You can also use {@link +android.media.MediaMuxer} in combination with {@link android.media.MediaExtractor} to perform media editing without the need to encode or decode.</p> <h3 id="ProgressAndScrubbing">Playback progress and scrubbing for RemoteControlClient</h3> -<p>In Android 4.0 (API level 14), the {@link android.media.RemoteControlClient} was added to -enable media playback controls from remote control clients such as the controls available on the -lock screen. Android 4.3 now provides the ability for such controllers to display the playback -position and controls for scrubbing the playback. If you've enabled remote control for your -media app with the {@link android.media.RemoteControlClient} APIs, then you can allow playback +<p>In Android 4.0 (API level 14), the {@link android.media.RemoteControlClient} was added to +enable media playback controls from remote control clients such as the controls available on the +lock screen. Android 4.3 now provides the ability for such controllers to display the playback +position and controls for scrubbing the playback. If you've enabled remote control for your +media app with the {@link android.media.RemoteControlClient} APIs, then you can allow playback scrubbing by implementing two new interfaces.</p> -<p>First, you must enable the {@link -android.media.RemoteControlClient#FLAG_KEY_MEDIA_POSITION_UPDATE} flag by passing it to -{@link android.media.RemoteControlClient#setTransportControlFlags setTransportControlsFlags()}.</p> +<p>First, you must enable the {@link +android.media.RemoteControlClient#FLAG_KEY_MEDIA_POSITION_UPDATE} flag by passing it to +{@link android.media.RemoteControlClient#setTransportControlFlags setTransportControlsFlags()}.</p> <p>Then implement the following two new interfaces:</p> <dl> <dt>{@link android.media.RemoteControlClient.OnGetPlaybackPositionListener}</dt> - <dd>This includes the callback {@link android.media.RemoteControlClient.OnGetPlaybackPositionListener#onGetPlaybackPosition}, which requests the current position + <dd>This includes the callback {@link android.media.RemoteControlClient.OnGetPlaybackPositionListener#onGetPlaybackPosition}, which requests the current position of your media when the remote control needs to update the progress in its UI.</dd> <dt>{@link android.media.RemoteControlClient.OnPlaybackPositionUpdateListener}</dt> - <dd>This includes the callback {@link android.media.RemoteControlClient.OnPlaybackPositionUpdateListener#onPlaybackPositionUpdate onPlaybackPositionUpdate()}, which - tells your app the new time code for your media when the user scrubs the playback with the + <dd>This includes the callback {@link android.media.RemoteControlClient.OnPlaybackPositionUpdateListener#onPlaybackPositionUpdate onPlaybackPositionUpdate()}, which + tells your app the new time code for your media when the user scrubs the playback with the remote control UI. - <p>Once you update your playback with the new position, call {@link - android.media.RemoteControlClient#setPlaybackState setPlaybackState()} to indicate the + <p>Once you update your playback with the new position, call {@link + android.media.RemoteControlClient#setPlaybackState setPlaybackState()} to indicate the new playback state, position, and speed.</p> </dd> </dl> -<p>With these interfaces defined, you can set them for your {@link -android.media.RemoteControlClient} by calling {@link android.media.RemoteControlClient#setOnGetPlaybackPositionListener setOnGetPlaybackPositionListener()} and -{@link android.media.RemoteControlClient#setPlaybackPositionUpdateListener +<p>With these interfaces defined, you can set them for your {@link +android.media.RemoteControlClient} by calling {@link android.media.RemoteControlClient#setOnGetPlaybackPositionListener setOnGetPlaybackPositionListener()} and +{@link android.media.RemoteControlClient#setPlaybackPositionUpdateListener setPlaybackPositionUpdateListener()}, respectively.</p> @@ -560,7 +563,7 @@ setPlaybackPositionUpdateListener()}, respectively.</p> <h3 id="OpenGL">Support for OpenGL ES 3.0</h3> -<p>Android 4.3 adds Java interfaces and native support for OpenGL ES 3.0. Key new functionality +<p>Android 4.3 adds Java interfaces and native support for OpenGL ES 3.0. Key new functionality provided in OpenGL ES 3.0 includes:</p> <ul> <li>Acceleration of advanced visual effects</li> @@ -570,8 +573,8 @@ provided in OpenGL ES 3.0 includes:</p> <li>Broader standardization of texture size and render-buffer formats</li> </ul> -<p>The Java interface for OpenGL ES 3.0 on Android is provided with {@link android.opengl.GLES30}. -When using OpenGL ES 3.0, be sure that you declare it in your manifest file with the +<p>The Java interface for OpenGL ES 3.0 on Android is provided with {@link android.opengl.GLES30}. +When using OpenGL ES 3.0, be sure that you declare it in your manifest file with the <a href="{@docRoot}guide/topics/manifest/uses-feature-element.html"><uses-feature></a> tag and the {@code android:glEsVersion} attribute. For example:</p> <pre> @@ -586,16 +589,16 @@ tag and the {@code android:glEsVersion} attribute. For example:</p> <h3 id="MipMap">Mipmapping for drawables</h3> -<p>Using a mipmap as the source for your bitmap or drawable is a simple way to provide a -quality image and various image scales, which can be particularly useful if you expect your +<p>Using a mipmap as the source for your bitmap or drawable is a simple way to provide a +quality image and various image scales, which can be particularly useful if you expect your image to be scaled during an animation.</p> -<p>Android 4.2 (API level 17) added support for mipmaps in the {@link android.graphics.Bitmap} -class—Android swaps the mip images in your {@link android.graphics.Bitmap} when you've -supplied a mipmap source and have enabled {@link android.graphics.Bitmap#setHasMipMap -setHasMipMap()}. Now in Android 4.3, you can enable mipmaps for a {@link -android.graphics.drawable.BitmapDrawable} object as well, by providing a mipmap asset and -setting the {@code android:mipMap} attribute in a bitmap resource file or by calling {@link +<p>Android 4.2 (API level 17) added support for mipmaps in the {@link android.graphics.Bitmap} +class—Android swaps the mip images in your {@link android.graphics.Bitmap} when you've +supplied a mipmap source and have enabled {@link android.graphics.Bitmap#setHasMipMap +setHasMipMap()}. Now in Android 4.3, you can enable mipmaps for a {@link +android.graphics.drawable.BitmapDrawable} object as well, by providing a mipmap asset and +setting the {@code android:mipMap} attribute in a bitmap resource file or by calling {@link android.graphics.drawable.BitmapDrawable#hasMipMap hasMipMap()}. </p> @@ -605,36 +608,36 @@ android.graphics.drawable.BitmapDrawable#hasMipMap hasMipMap()}. <h3 id="ViewOverlay">View overlays</h3> -<p>The new {@link android.view.ViewOverlay} class provides a transparent layer on top of -a {@link android.view.View} on which you can add visual content and which does not affect -the layout hierarchy. You can get a {@link android.view.ViewOverlay} for any {@link -android.view.View} by calling {@link android.view.View#getOverlay}. The overlay -always has the same size and position as its host view (the view from which it was created), -allowing you to add content that appears in front of the host view, but which cannot extend +<p>The new {@link android.view.ViewOverlay} class provides a transparent layer on top of +a {@link android.view.View} on which you can add visual content and which does not affect +the layout hierarchy. You can get a {@link android.view.ViewOverlay} for any {@link +android.view.View} by calling {@link android.view.View#getOverlay}. The overlay +always has the same size and position as its host view (the view from which it was created), +allowing you to add content that appears in front of the host view, but which cannot extend the bounds of that host view. </p> -<p>Using a {@link android.view.ViewOverlay} is particularly useful when you want to create -animations such as sliding a view outside of its container or moving items around the screen -without affecting the view hierarchy. However, because the usable area of an overlay is -restricted to the same area as its host view, if you want to animate a view moving outside -its position in the layout, you must use an overlay from a parent view that has the desired +<p>Using a {@link android.view.ViewOverlay} is particularly useful when you want to create +animations such as sliding a view outside of its container or moving items around the screen +without affecting the view hierarchy. However, because the usable area of an overlay is +restricted to the same area as its host view, if you want to animate a view moving outside +its position in the layout, you must use an overlay from a parent view that has the desired layout bounds.</p> -<p>When you create an overlay for a widget view such as a {@link android.widget.Button}, you -can add {@link android.graphics.drawable.Drawable} objects to the overlay by calling -{@link android.view.ViewOverlay#add(Drawable)}. If you call {@link +<p>When you create an overlay for a widget view such as a {@link android.widget.Button}, you +can add {@link android.graphics.drawable.Drawable} objects to the overlay by calling +{@link android.view.ViewOverlay#add(Drawable)}. If you call {@link android.view.ViewGroup#getOverlay} for a layout view, such as {@link android.widget.RelativeLayout}, the object returned is a {@link android.view.ViewGroupOverlay}. The -{@link android.view.ViewGroupOverlay} class is a subclass -of {@link android.view.ViewOverlay} that also allows you to add {@link android.view.View} +{@link android.view.ViewGroupOverlay} class is a subclass +of {@link android.view.ViewOverlay} that also allows you to add {@link android.view.View} objects by calling {@link android.view.ViewGroupOverlay#add(View)}. </p> -<p class="note"><strong>Note:</strong> All drawables and views that you add to an overlay +<p class="note"><strong>Note:</strong> All drawables and views that you add to an overlay are visual only. They cannot receive focus or input events.</p> -<p>For example, the following code animates a view sliding to the right by placing the view +<p>For example, the following code animates a view sliding to the right by placing the view in the parent view's overlay, then performing a translation animation on that view:</p> <pre> View view = findViewById(R.id.view_to_remove); @@ -647,17 +650,17 @@ anim.start(); <h3 id="OpticalBounds">Optical bounds layout</h3> -<p>For views that contain nine-patch background images, you can now specify that they should -be aligned with neighboring views based on the "optical" bounds of the background image rather +<p>For views that contain nine-patch background images, you can now specify that they should +be aligned with neighboring views based on the "optical" bounds of the background image rather than the "clip" bounds of the view.</p> -<p>For example, figures 1 and 2 each show the same layout, but the version in figure 1 is -using clip bounds (the default behavior), while figure 2 is using optical bounds. Because the -nine-patch images used for the button and the photo frame include padding around the edges, +<p>For example, figures 1 and 2 each show the same layout, but the version in figure 1 is +using clip bounds (the default behavior), while figure 2 is using optical bounds. Because the +nine-patch images used for the button and the photo frame include padding around the edges, they don’t appear to align with each other or the text when using clip bounds.</p> -<p class="note"><strong>Note:</strong> The screenshot in figures 1 and 2 have the "Show -layout bounds" developer setting enabled. For each view, red lines indicate the optical +<p class="note"><strong>Note:</strong> The screenshot in figures 1 and 2 have the "Show +layout bounds" developer setting enabled. For each view, red lines indicate the optical bounds, blue lines indicate the clip bounds, and pink indicates margins.</p> <script type="text/javascript"> @@ -725,30 +728,30 @@ optical bounds. </p> </div> -<p>For this to work, the nine-patch images applied to the background of your views must specify -the optical bounds using red lines along the bottom and right-side of the nine-patch file (as -shown in figure 3). The red lines indicate the region that should be subtracted from +<p>For this to work, the nine-patch images applied to the background of your views must specify +the optical bounds using red lines along the bottom and right-side of the nine-patch file (as +shown in figure 3). The red lines indicate the region that should be subtracted from the clip bounds, leaving the optical bounds of the image.</p> -<p>When you enable optical bounds for a {@link android.view.ViewGroup} in your layout, all -descendant views inherit the optical bounds layout mode unless you override it for a group by -setting {@code android:layoutMode} to {@code "clipBounds"}. All layout elements also honor the -optical bounds of their child views, adapting their own bounds based on the optical bounds of -the views within them. However, layout elements (subclasses of {@link android.view.ViewGroup}) +<p>When you enable optical bounds for a {@link android.view.ViewGroup} in your layout, all +descendant views inherit the optical bounds layout mode unless you override it for a group by +setting {@code android:layoutMode} to {@code "clipBounds"}. All layout elements also honor the +optical bounds of their child views, adapting their own bounds based on the optical bounds of +the views within them. However, layout elements (subclasses of {@link android.view.ViewGroup}) currently do not support optical bounds for nine-patch images applied to their own background.</p> <p>If you create a custom view by subclassing {@link android.view.View}, {@link android.view.ViewGroup}, or any subclasses thereof, your view will inherit these optical bound behaviors.</p> <p class="note"><strong>Note:</strong> All widgets supported by the Holo theme have been updated -with optical bounds, including {@link android.widget.Button}, {@link android.widget.Spinner}, +with optical bounds, including {@link android.widget.Button}, {@link android.widget.Spinner}, {@link android.widget.EditText}, and others. So you can immediately benefit by setting the -{@code android:layoutMode} attribute to {@code "opticalBounds"} if your app applies a Holo theme -({@link android.R.style#Theme_Holo Theme.Holo}, {@link android.R.style#Theme_Holo_Light +{@code android:layoutMode} attribute to {@code "opticalBounds"} if your app applies a Holo theme +({@link android.R.style#Theme_Holo Theme.Holo}, {@link android.R.style#Theme_Holo_Light Theme.Holo.Light}, etc.). </p> -<p>To specify optical bounds for your own nine-patch images with the <a -href="{@docRoot}tools/help/draw9patch.html">Draw 9-patch</a> tool, hold CTRL when clicking on +<p>To specify optical bounds for your own nine-patch images with the <a +href="{@docRoot}tools/help/draw9patch.html">Draw 9-patch</a> tool, hold CTRL when clicking on the border pixels.</p> @@ -756,59 +759,59 @@ the border pixels.</p> <h3 id="AnimationRect">Animation for Rect values</h3> -<p>You can now animate between two {@link android.graphics.Rect} values with the new {@link -android.animation.RectEvaluator}. This new class is an implementation of {@link -android.animation.TypeEvaluator} that you can pass to {@link +<p>You can now animate between two {@link android.graphics.Rect} values with the new {@link +android.animation.RectEvaluator}. This new class is an implementation of {@link +android.animation.TypeEvaluator} that you can pass to {@link android.animation.ValueAnimator#setEvaluator ValueAnimator.setEvaluator()}. </p> <h3 id="AttachFocus">Window attach and focus listener</h3> -<p>Previously, if you wanted to listen for when your view attached/detached to the window or -when its focus changed, you needed to override the {@link android.view.View} class to -implement {@link android.view.View#onAttachedToWindow onAttachedToWindow()} and {@link -android.view.View#onDetachedFromWindow onDetachedFromWindow()}, or {@link +<p>Previously, if you wanted to listen for when your view attached/detached to the window or +when its focus changed, you needed to override the {@link android.view.View} class to +implement {@link android.view.View#onAttachedToWindow onAttachedToWindow()} and {@link +android.view.View#onDetachedFromWindow onDetachedFromWindow()}, or {@link android.view.View#onWindowFocusChanged onWindowFocusChanged()}, respectively. </p> -<p>Now, to receive attach and detach events you can instead implement {@link -android.view.ViewTreeObserver.OnWindowAttachListener} and set it on a view with -{@link android.view.ViewTreeObserver#addOnWindowAttachListener addOnWindowAttachListener()}. -And to receive focus events, you can implement {@link -android.view.ViewTreeObserver.OnWindowFocusChangeListener} and set it on a view with -{@link android.view.ViewTreeObserver#addOnWindowFocusChangeListener +<p>Now, to receive attach and detach events you can instead implement {@link +android.view.ViewTreeObserver.OnWindowAttachListener} and set it on a view with +{@link android.view.ViewTreeObserver#addOnWindowAttachListener addOnWindowAttachListener()}. +And to receive focus events, you can implement {@link +android.view.ViewTreeObserver.OnWindowFocusChangeListener} and set it on a view with +{@link android.view.ViewTreeObserver#addOnWindowFocusChangeListener addOnWindowFocusChangeListener()}. </p> <h3 id="Overscan">TV overscan support</h3> -<p>To be sure your app fills the entire screen on every television, you can now enable overscan -for you app layout. Overscan mode is determined by the {@link android.view.WindowManager.LayoutParams#FLAG_LAYOUT_IN_OVERSCAN} flag, which you can enable with platform themes such as -{@link android.R.style#Theme_DeviceDefault_NoActionBar_Overscan} or by enabling the +<p>To be sure your app fills the entire screen on every television, you can now enable overscan +for you app layout. Overscan mode is determined by the {@link android.view.WindowManager.LayoutParams#FLAG_LAYOUT_IN_OVERSCAN} flag, which you can enable with platform themes such as +{@link android.R.style#Theme_DeviceDefault_NoActionBar_Overscan} or by enabling the {@link android.R.attr#windowOverscan} style in a custom theme.</p> <h3 id="Orientation">Screen orientation</h3> -<p>The <a +<p>The <a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code <activity>}</a> -tag's <a +tag's <a href="{@docRoot}guide/topics/manifest/activity-element.html#screen">{@code screenOrientation}</a> attribute now supports additional values to honor the user's preference for auto-rotation:</p> <dl> <dt>{@code "userLandscape"}</dt> -<dd>Behaves the same as {@code "sensorLandscape"}, except if the user disables auto-rotate +<dd>Behaves the same as {@code "sensorLandscape"}, except if the user disables auto-rotate then it locks in the normal landscape orientation and will not flip. </dd> <dt>{@code "userPortrait"}</dt> -<dd>Behaves the same as {@code "sensorPortrait"}, except if the user disables auto-rotate then +<dd>Behaves the same as {@code "sensorPortrait"}, except if the user disables auto-rotate then it locks in the normal portrait orientation and will not flip. </dd> <dt>{@code "fullUser"}</dt> -<dd>Behaves the same as {@code "fullSensor"} and allows rotation in all four directions, except +<dd>Behaves the same as {@code "fullSensor"} and allows rotation in all four directions, except if the user disables auto-rotate then it locks in the user's preferred orientation. </dd></dl> @@ -818,8 +821,8 @@ the screen's current orientation.</p> <h3 id="RotationAnimation">Rotation animations</h3> -<p>The new {@link android.view.WindowManager.LayoutParams#rotationAnimation} field in -{@link android.view.WindowManager} allows you to select between one of three animations you +<p>The new {@link android.view.WindowManager.LayoutParams#rotationAnimation} field in +{@link android.view.WindowManager} allows you to select between one of three animations you want to use when the system switches screen orientations. The three animations are:</p> <ul> <li>{@link android.view.WindowManager.LayoutParams#ROTATION_ANIMATION_CROSSFADE}</li> @@ -844,25 +847,17 @@ protected void onCreate(Bundle savedInstanceState) { <h2 id="UserInput">User Input</h2> -<h3 id="SignificantMotion">Detect significant motion</h3> - -<p>The {@link android.hardware.SensorManager} APIs now allow you to request a callback when the -device sensors detect "significant motion." For instance, this event may be triggered by new -motion such as when the user starts to walk.</p> - -<p>To register a listener for significant motion, extend the {@link android.hardware.TriggerEventListener} class and implement the {@link android.hardware.TriggerEventListener#onTrigger onTrigger()} callback method. Then register your event listener with the {@link android.hardware.SensorManager} by passing it to {@link android.hardware.SensorManager#requestTriggerSensor requestTriggerSensor()}, passing it your {@link android.hardware.TriggerEventListener} and {@link android.hardware.Sensor#TYPE_SIGNIFICANT_MOTION}.</p> - <h3 id="Sensors">New sensor types</h3> <p>The new {@link android.hardware.Sensor#TYPE_GAME_ROTATION_VECTOR} sensor allows you to detect the device's rotations without worrying about magnetic interferences. Unlike the {@link android.hardware.Sensor#TYPE_ROTATION_VECTOR} sensor, the {@link android.hardware.Sensor#TYPE_GAME_ROTATION_VECTOR} is not based on magnetic north.</p> -<p>The new {@link android.hardware.Sensor#TYPE_GYROSCOPE_UNCALIBRATED} and {@link -android.hardware.Sensor#TYPE_MAGNETIC_FIELD_UNCALIBRATED} sensors provide raw sensor data without -consideration for bias estimations. That is, the existing {@link -android.hardware.Sensor#TYPE_GYROSCOPE} and {@link android.hardware.Sensor#TYPE_MAGNETIC_FIELD} -sensors provide sensor data that takes into account estimated bias from gyro-drift and hard iron -in the device, respectively. Whereas the new "uncalibrated" versions of these sensors instead provide -the raw sensor data and offer the estimated bias values separately. These sensors allow you to -provide your own custom calibration for the sensor data by enhancing the estimated bias with +<p>The new {@link android.hardware.Sensor#TYPE_GYROSCOPE_UNCALIBRATED} and {@link +android.hardware.Sensor#TYPE_MAGNETIC_FIELD_UNCALIBRATED} sensors provide raw sensor data without +consideration for bias estimations. That is, the existing {@link +android.hardware.Sensor#TYPE_GYROSCOPE} and {@link android.hardware.Sensor#TYPE_MAGNETIC_FIELD} +sensors provide sensor data that takes into account estimated bias from gyro-drift and hard iron +in the device, respectively. Whereas the new "uncalibrated" versions of these sensors instead provide +the raw sensor data and offer the estimated bias values separately. These sensors allow you to +provide your own custom calibration for the sensor data by enhancing the estimated bias with external data.</p> @@ -891,13 +886,13 @@ external data.</p> <p>To track which contacts have been deleted, the new table {@link android.provider.ContactsContract.DeletedContacts} provides a log of contacts that have been deleted (but each contact deleted is held in this table for a limited time). Similar to {@link android.provider.ContactsContract.ContactsColumns#CONTACT_LAST_UPDATED_TIMESTAMP}, you can use the new selection parameter, {@link android.provider.ContactsContract.DeletedContacts#CONTACT_DELETED_TIMESTAMP} to check which contacts have been deleted since the last time you queried the provider. The table also contains the constant {@link android.provider.ContactsContract.DeletedContacts#DAYS_KEPT_MILLISECONDS} containing the number of days (in milliseconds) that the log will be kept.</p> -<p>Additionally, the Contacts Provider now broadcasts the {@link -android.provider.ContactsContract.Intents#CONTACTS_DATABASE_CREATED} action when the user -clears the contacts storage through the system settings menu, effectively recreating the -Contacts Provider database. It’s intended to signal apps that they need to drop all the contact +<p>Additionally, the Contacts Provider now broadcasts the {@link +android.provider.ContactsContract.Intents#CONTACTS_DATABASE_CREATED} action when the user +clears the contacts storage through the system settings menu, effectively recreating the +Contacts Provider database. It’s intended to signal apps that they need to drop all the contact information they’ve stored and reload it with a new query.</p> -<p>For sample code using these APIs to check for changes to the contacts, look in the ApiDemos +<p>For sample code using these APIs to check for changes to the contacts, look in the ApiDemos sample available in the <a href="{@docRoot}tools/samples/index.html">SDK Samples</a> download.</p> @@ -905,13 +900,13 @@ sample available in the <a href="{@docRoot}tools/samples/index.html">SDK Samples <h3 id="BiDi">Improved support for bi-directional text</h3> -<p>Previous versions of Android support right-to-left (RTL) languages and layout, -but sometimes don't properly handle mixed-direction text. So Android 4.3 adds the {@link -android.text.BidiFormatter} APIs that help you properly format text with opposite-direction +<p>Previous versions of Android support right-to-left (RTL) languages and layout, +but sometimes don't properly handle mixed-direction text. So Android 4.3 adds the {@link +android.text.BidiFormatter} APIs that help you properly format text with opposite-direction content without garbling any parts of it.</p> -<p>For example, when you want to create a sentence with a string variable, such as "Did you mean -15 Bay Street, Laurel, CA?", you normally pass a localized string resource and the variable to +<p>For example, when you want to create a sentence with a string variable, such as "Did you mean +15 Bay Street, Laurel, CA?", you normally pass a localized string resource and the variable to {@link java.lang.String#format String.format()}:</p> <pre> Resources res = getResources(); @@ -922,8 +917,8 @@ String suggestion = String.format(res.getString(R.string.did_you_mean), address) <p dir="rtl">האם התכוונת ל 15 Bay Street, Laurel, CA?</p> -<p>That's wrong because the "15" should be left of "Bay Street." The solution is to use {@link -android.text.BidiFormatter} and its {@link android.text.BidiFormatter#unicodeWrap(String) +<p>That's wrong because the "15" should be left of "Bay Street." The solution is to use {@link +android.text.BidiFormatter} and its {@link android.text.BidiFormatter#unicodeWrap(String) unicodeWrap()} method. For example, the code above becomes:</p> <pre> Resources res = getResources(); @@ -933,11 +928,11 @@ String suggestion = String.format(res.getString(R.string.did_you_mean), </pre> <p> -By default, {@link android.text.BidiFormatter#unicodeWrap(String) unicodeWrap()} uses the -first-strong directionality estimation heuristic, which can get things wrong if the first -signal for text direction does not represent the appropriate direction for the content as a whole. -If necessary, you can specify a different heuristic by passing one of the {@link -android.text.TextDirectionHeuristic} constants from {@link android.text.TextDirectionHeuristics} +By default, {@link android.text.BidiFormatter#unicodeWrap(String) unicodeWrap()} uses the +first-strong directionality estimation heuristic, which can get things wrong if the first +signal for text direction does not represent the appropriate direction for the content as a whole. +If necessary, you can specify a different heuristic by passing one of the {@link +android.text.TextDirectionHeuristic} constants from {@link android.text.TextDirectionHeuristics} to {@link android.text.BidiFormatter#unicodeWrap(String,TextDirectionHeuristic) unicodeWrap()}.</p> <p class="note"><strong>Note:</strong> These new APIs are also available for previous versions @@ -950,31 +945,31 @@ Library</a>, with the {@link android.support.v4.text.BidiFormatter} class and re <h3 id="A11yKeyEvents">Handle key events</h3> -<p>An {@link android.accessibilityservice.AccessibilityService} can now receive a callback for -key input events with the {@link android.accessibilityservice.AccessibilityService#onKeyEvent -onKeyEvent()} callback method. This allows your accessibility service to handle input for -key-based input devices such as a keyboard and translate those events to special actions that +<p>An {@link android.accessibilityservice.AccessibilityService} can now receive a callback for +key input events with the {@link android.accessibilityservice.AccessibilityService#onKeyEvent +onKeyEvent()} callback method. This allows your accessibility service to handle input for +key-based input devices such as a keyboard and translate those events to special actions that previously may have been possible only with touch input or the device's directional pad.</p> <h3 id="A11yText">Select text and copy/paste</h3> -<p>The {@link android.view.accessibility.AccessibilityNodeInfo} now provides APIs that allow -an {@link android.accessibilityservice.AccessibilityService} to select, cut, copy, and paste +<p>The {@link android.view.accessibility.AccessibilityNodeInfo} now provides APIs that allow +an {@link android.accessibilityservice.AccessibilityService} to select, cut, copy, and paste text in a node.</p> -<p>To specify the selection of text to cut or copy, your accessibility service can use the new -action, {@link android.view.accessibility.AccessibilityNodeInfo#ACTION_SET_SELECTION}, passing -with it the selection start and end position with {@link -android.view.accessibility.AccessibilityNodeInfo#ACTION_ARGUMENT_SELECTION_START_INT} and {@link -android.view.accessibility.AccessibilityNodeInfo#ACTION_ARGUMENT_SELECTION_END_INT}. -Alternatively you can select text by manipulating the cursor position using the existing -action, {@link android.view.accessibility.AccessibilityNodeInfo#ACTION_NEXT_AT_MOVEMENT_GRANULARITY} -(previously only for moving the cursor position), and adding the argument {@link +<p>To specify the selection of text to cut or copy, your accessibility service can use the new +action, {@link android.view.accessibility.AccessibilityNodeInfo#ACTION_SET_SELECTION}, passing +with it the selection start and end position with {@link +android.view.accessibility.AccessibilityNodeInfo#ACTION_ARGUMENT_SELECTION_START_INT} and {@link +android.view.accessibility.AccessibilityNodeInfo#ACTION_ARGUMENT_SELECTION_END_INT}. +Alternatively you can select text by manipulating the cursor position using the existing +action, {@link android.view.accessibility.AccessibilityNodeInfo#ACTION_NEXT_AT_MOVEMENT_GRANULARITY} +(previously only for moving the cursor position), and adding the argument {@link android.view.accessibility.AccessibilityNodeInfo#ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN}.</p> -<p>You can then cut or copy with {@link android.view.accessibility.AccessibilityNodeInfo#ACTION_CUT}, -{@link android.view.accessibility.AccessibilityNodeInfo#ACTION_COPY}, then later paste with +<p>You can then cut or copy with {@link android.view.accessibility.AccessibilityNodeInfo#ACTION_CUT}, +{@link android.view.accessibility.AccessibilityNodeInfo#ACTION_COPY}, then later paste with {@link android.view.accessibility.AccessibilityNodeInfo#ACTION_PASTE}.</p> @@ -987,14 +982,14 @@ class.</p> <h3 id="A11yFeatures">Declare accessibility features</h3> -<p>Beginning with Android 4.3, an accessibility service must declare accessibility capabilities -in its metadata file in order to use certain accessibility features. If the capability is not -requested in the metadata file, then the feature will be a no-op. To declare your service's -accessibility capabilities, you must use XML attributes that correspond to the various -"capability" constants in the {@link android.accessibilityservice.AccessibilityServiceInfo} +<p>Beginning with Android 4.3, an accessibility service must declare accessibility capabilities +in its metadata file in order to use certain accessibility features. If the capability is not +requested in the metadata file, then the feature will be a no-op. To declare your service's +accessibility capabilities, you must use XML attributes that correspond to the various +"capability" constants in the {@link android.accessibilityservice.AccessibilityServiceInfo} class.</p> -<p>For example, if a service does not request the {@link android.R.styleable#AccessibilityService_canRequestFilterKeyEvents flagRequestFilterKeyEvents} capability, +<p>For example, if a service does not request the {@link android.R.styleable#AccessibilityService_canRequestFilterKeyEvents flagRequestFilterKeyEvents} capability, then it will not receive key events.</p> @@ -1002,36 +997,36 @@ then it will not receive key events.</p> <h3 id="UiAutomation">Automated UI testing</h3> -<p>The new {@link android.app.UiAutomation} class provides APIs that allow you to simulate user -actions for test automation. By using the platform's {@link -android.accessibilityservice.AccessibilityService} APIs, the {@link android.app.UiAutomation} +<p>The new {@link android.app.UiAutomation} class provides APIs that allow you to simulate user +actions for test automation. By using the platform's {@link +android.accessibilityservice.AccessibilityService} APIs, the {@link android.app.UiAutomation} APIs allow you to inspect the screen content and inject arbitrary keyboard and touch events.</p> -<p>To get an instance of {@link android.app.UiAutomation}, call {@link -android.app.Instrumentation#getUiAutomation Instrumentation.getUiAutomation()}. In order -for this to work, you must supply the {@code -w} option with the {@code instrument} command -when running your {@link android.test.InstrumentationTestCase} from <a +<p>To get an instance of {@link android.app.UiAutomation}, call {@link +android.app.Instrumentation#getUiAutomation Instrumentation.getUiAutomation()}. In order +for this to work, you must supply the {@code -w} option with the {@code instrument} command +when running your {@link android.test.InstrumentationTestCase} from <a href="{@docRoot}tools/help/adb.html#am">{@code adb shell}</a>.</p> -<p>With the {@link android.app.UiAutomation} instance, you can execute arbitrary events to test -your app by calling {@link android.app.UiAutomation#executeAndWaitForEvent -executeAndWaitForEvent()}, passing it a {@link java.lang.Runnable} to perform, a timeout -period for the operation, and an implementation of the {@link -android.app.UiAutomation.AccessibilityEventFilter} interface. It's within your {@link -android.app.UiAutomation.AccessibilityEventFilter} implementation that you'll receive a call -that allows you to filter the events that you're interested in and determine the success or +<p>With the {@link android.app.UiAutomation} instance, you can execute arbitrary events to test +your app by calling {@link android.app.UiAutomation#executeAndWaitForEvent +executeAndWaitForEvent()}, passing it a {@link java.lang.Runnable} to perform, a timeout +period for the operation, and an implementation of the {@link +android.app.UiAutomation.AccessibilityEventFilter} interface. It's within your {@link +android.app.UiAutomation.AccessibilityEventFilter} implementation that you'll receive a call +that allows you to filter the events that you're interested in and determine the success or failure of a given test case.</p> -<p>To observe all the events during a test, create an implementation of {@link -android.app.UiAutomation.OnAccessibilityEventListener} and pass it to {@link -android.app.UiAutomation#setOnAccessibilityEventListener setOnAccessibilityEventListener()}. -Your listener interface then receives a call to {@link -android.app.UiAutomation.OnAccessibilityEventListener#onAccessibilityEvent onAccessibilityEvent()} -each time an event occurs, receiving an {@link android.view.accessibility.AccessibilityEvent} object +<p>To observe all the events during a test, create an implementation of {@link +android.app.UiAutomation.OnAccessibilityEventListener} and pass it to {@link +android.app.UiAutomation#setOnAccessibilityEventListener setOnAccessibilityEventListener()}. +Your listener interface then receives a call to {@link +android.app.UiAutomation.OnAccessibilityEventListener#onAccessibilityEvent onAccessibilityEvent()} +each time an event occurs, receiving an {@link android.view.accessibility.AccessibilityEvent} object that describes the event.</p> -<p>There is a variety of other operations that the {@link android.app.UiAutomation} APIs expose -at a very low level to encourage the development of UI test tools such as <a href="{@docRoot}tools/help/uiautomator/index.html">uiautomator</a>. For instance, +<p>There is a variety of other operations that the {@link android.app.UiAutomation} APIs expose +at a very low level to encourage the development of UI test tools such as <a href="{@docRoot}tools/help/uiautomator/index.html">uiautomator</a>. For instance, {@link android.app.UiAutomation} can also:</p> <ul> <li>Inject input events @@ -1039,16 +1034,16 @@ at a very low level to encourage the development of UI test tools such as <a hre <li>Take screenshots </ul> -<p>And most importantly for UI test tools, the {@link android.app.UiAutomation} APIs work +<p>And most importantly for UI test tools, the {@link android.app.UiAutomation} APIs work across application boundaries, unlike those in {@link android.app.Instrumentation}.</p> <h3 id="Systrace">Systrace events for apps</h3> -<p>Android 4.3 adds the {@link android.os.Trace} class with two static methods, -{@link android.os.Trace#beginSection beginSection()} and {@link android.os.Trace#endSection()}, -which allow you to define blocks of code to include with the systrace report. By creating -sections of traceable code in your app, the systrace logs provide you a much more detailed +<p>Android 4.3 adds the {@link android.os.Trace} class with two static methods, +{@link android.os.Trace#beginSection beginSection()} and {@link android.os.Trace#endSection()}, +which allow you to define blocks of code to include with the systrace report. By creating +sections of traceable code in your app, the systrace logs provide you a much more detailed analysis of where slowdown occurs within your app.</p> <p>For information about using the Systrace tool, read <a href="{@docRoot}tools/debugging/systrace.html">Analyzing Display and Performance with Systrace</a>.</p> @@ -1058,31 +1053,31 @@ analysis of where slowdown occurs within your app.</p> <h3 id="KeyStore">Android key store for app-private keys</h3> -<p>Android now offers a custom Java Security Provider in the {@link java.security.KeyStore} -facility, called Android Key Store, which allows you to generate and save private keys that -may be seen and used by only your app. To load the Android Key Store, pass -{@code "AndroidKeyStore"} to {@link java.security.KeyStore#getInstance(String) +<p>Android now offers a custom Java Security Provider in the {@link java.security.KeyStore} +facility, called Android Key Store, which allows you to generate and save private keys that +may be seen and used by only your app. To load the Android Key Store, pass +{@code "AndroidKeyStore"} to {@link java.security.KeyStore#getInstance(String) KeyStore.getInstance()}.</p> -<p>To manage your app's private credentials in the Android Key Store, generate a new key with -{@link java.security.KeyPairGenerator} with {@link android.security.KeyPairGeneratorSpec}. First -get an instance of {@link java.security.KeyPairGenerator} by calling {@link -java.security.KeyPairGenerator#getInstance getInstance()}. Then call -{@link java.security.KeyPairGenerator#initialize initialize()}, passing it an instance of -{@link android.security.KeyPairGeneratorSpec}, which you can get using -{@link android.security.KeyPairGeneratorSpec.Builder KeyPairGeneratorSpec.Builder}. -Finally, get your {@link java.security.KeyPair} by calling {@link +<p>To manage your app's private credentials in the Android Key Store, generate a new key with +{@link java.security.KeyPairGenerator} with {@link android.security.KeyPairGeneratorSpec}. First +get an instance of {@link java.security.KeyPairGenerator} by calling {@link +java.security.KeyPairGenerator#getInstance getInstance()}. Then call +{@link java.security.KeyPairGenerator#initialize initialize()}, passing it an instance of +{@link android.security.KeyPairGeneratorSpec}, which you can get using +{@link android.security.KeyPairGeneratorSpec.Builder KeyPairGeneratorSpec.Builder}. +Finally, get your {@link java.security.KeyPair} by calling {@link java.security.KeyPairGenerator#generateKeyPair generateKeyPair()}.</p> <h3 id="HardwareKeyChain">Hardware credential storage</h3> -<p>Android also now supports hardware-backed storage for your {@link android.security.KeyChain} -credentials, providing more security by making the keys unavailable for extraction. That is, once -keys are in a hardware-backed key store (Secure Element, TPM, or TrustZone), they can be used for -cryptographic operations but the private key material cannot be exported. Even the OS kernel -cannot access this key material. While not all Android-powered devices support storage on -hardware, you can check at runtime if hardware-backed storage is available by calling +<p>Android also now supports hardware-backed storage for your {@link android.security.KeyChain} +credentials, providing more security by making the keys unavailable for extraction. That is, once +keys are in a hardware-backed key store (Secure Element, TPM, or TrustZone), they can be used for +cryptographic operations but the private key material cannot be exported. Even the OS kernel +cannot access this key material. While not all Android-powered devices support storage on +hardware, you can check at runtime if hardware-backed storage is available by calling {@link android.security.KeyChain#isBoundKeyAlgorithm KeyChain.IsBoundKeyAlgorithm()}.</p> @@ -1091,9 +1086,9 @@ hardware, you can check at runtime if hardware-backed storage is available by ca <h3 id="ManifestFeatures">Declarable required features</h3> -<p>The following values are now supported in the <a +<p>The following values are now supported in the <a href="{@docRoot}guide/topics/manifest/uses-feature-element.html">{@code <uses-feature>}</a> -element so you can ensure that your app is installed only on devices that provide the features +element so you can ensure that your app is installed only on devices that provide the features your app needs.</p> <dl> @@ -1137,8 +1132,8 @@ Example: <h3 id="ManifestPermissions">User permissions</h3> -<p>The following values are now supported in the <a -href="{@docRoot}guide/topics/manifest/uses-permission-element.html">{@code <uses-permission>}</a> +<p>The following values are now supported in the <a +href="{@docRoot}guide/topics/manifest/uses-permission-element.html">{@code <uses-permission>}</a> to declare the permissions your app requires in order to access certain APIs.</p> diff --git a/docs/html/distribute/googleplay/spotlight/index.jd b/docs/html/distribute/googleplay/spotlight/index.jd index 88cdec4..7004b0a 100644 --- a/docs/html/distribute/googleplay/spotlight/index.jd +++ b/docs/html/distribute/googleplay/spotlight/index.jd @@ -22,6 +22,35 @@ header.hide=0 margin-bottom:40px; margin-top:30px;"> <div style="padding:0 0 0 29px;"> + <h4>Developer Story: Colopl</h4> + <img alt="" class="screenshot thumbnail" style="-webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px height:78px; + width: 78px; + float: left; + margin: 17px 20px 9px 0;" + src="//lh3.ggpht.com/sx2ILNaXQYOsHfR91T5tUWGlfXE1FutHCBN02Fll6mi9gIaG6RZCGbeJMtIvOoegCPTh=w124" > + <div style="width:700px;"> + <p style="margin-top:26px; + margin-bottom:12px;"> + The creators of Kuma The Bear, Japan-based <a href="https://play.google.com/store/apps/developer?id=COLOPL,+Inc." target="_android">Colopl</a>, talk about how Google Play and Android allowed them to grow their business to become one of the most profitable games publishers in APAC to date. </p> + </div> + <iframe style="float:left; + margin-right:24px; + margin-top:14px;" width="700" height="394" src= + "http://www.youtube.com/embed/CbpoZeQCNe4?HD=1;rel=0;origin=developer.android.com;" frameborder="0" allowfullscreen> + </iframe> + </div> +</div> + +<div style="background: #F0F0F0; + border-top: 1px solid #DDD; + padding: 0px 0 24px 0; + overflow: auto; + clear:both; + margin-bottom:40px; + margin-top:30px;"> + <div style="padding:0 0 0 29px;"> <h4>Developer Story: redBus.in</h4> <img alt="" class="screenshot thumbnail" style="-webkit-border-radius: 5px; -moz-border-radius: 5px; diff --git a/docs/html/distribute/promote/device-art-resources/nexus_7/land_back.png b/docs/html/distribute/promote/device-art-resources/nexus_7/land_back.png Binary files differindex 697fb7d..cc5b1af 100644 --- a/docs/html/distribute/promote/device-art-resources/nexus_7/land_back.png +++ b/docs/html/distribute/promote/device-art-resources/nexus_7/land_back.png diff --git a/docs/html/distribute/promote/device-art-resources/nexus_7/land_fore.png b/docs/html/distribute/promote/device-art-resources/nexus_7/land_fore.png Binary files differindex 735262f..2625edb 100644 --- a/docs/html/distribute/promote/device-art-resources/nexus_7/land_fore.png +++ b/docs/html/distribute/promote/device-art-resources/nexus_7/land_fore.png diff --git a/docs/html/distribute/promote/device-art-resources/nexus_7/land_shadow.png b/docs/html/distribute/promote/device-art-resources/nexus_7/land_shadow.png Binary files differindex cfb7952..9d91475 100644 --- a/docs/html/distribute/promote/device-art-resources/nexus_7/land_shadow.png +++ b/docs/html/distribute/promote/device-art-resources/nexus_7/land_shadow.png diff --git a/docs/html/distribute/promote/device-art-resources/nexus_7/port_back.png b/docs/html/distribute/promote/device-art-resources/nexus_7/port_back.png Binary files differindex 5bb815a..f54a8af 100644 --- a/docs/html/distribute/promote/device-art-resources/nexus_7/port_back.png +++ b/docs/html/distribute/promote/device-art-resources/nexus_7/port_back.png diff --git a/docs/html/distribute/promote/device-art-resources/nexus_7/port_fore.png b/docs/html/distribute/promote/device-art-resources/nexus_7/port_fore.png Binary files differindex 1be3b21..230bad4 100644 --- a/docs/html/distribute/promote/device-art-resources/nexus_7/port_fore.png +++ b/docs/html/distribute/promote/device-art-resources/nexus_7/port_fore.png diff --git a/docs/html/distribute/promote/device-art-resources/nexus_7/port_shadow.png b/docs/html/distribute/promote/device-art-resources/nexus_7/port_shadow.png Binary files differindex 7e8aff2..2401d20 100644 --- a/docs/html/distribute/promote/device-art-resources/nexus_7/port_shadow.png +++ b/docs/html/distribute/promote/device-art-resources/nexus_7/port_shadow.png diff --git a/docs/html/distribute/promote/device-art-resources/nexus_7/thumb.png b/docs/html/distribute/promote/device-art-resources/nexus_7/thumb.png Binary files differindex b5db82e..57b4c03 100644 --- a/docs/html/distribute/promote/device-art-resources/nexus_7/thumb.png +++ b/docs/html/distribute/promote/device-art-resources/nexus_7/thumb.png diff --git a/docs/html/distribute/promote/device-art-resources/nexus_7_2012/land_back.png b/docs/html/distribute/promote/device-art-resources/nexus_7_2012/land_back.png Binary files differnew file mode 100644 index 0000000..697fb7d --- /dev/null +++ b/docs/html/distribute/promote/device-art-resources/nexus_7_2012/land_back.png diff --git a/docs/html/distribute/promote/device-art-resources/nexus_7_2012/land_fore.png b/docs/html/distribute/promote/device-art-resources/nexus_7_2012/land_fore.png Binary files differnew file mode 100644 index 0000000..735262f --- /dev/null +++ b/docs/html/distribute/promote/device-art-resources/nexus_7_2012/land_fore.png diff --git a/docs/html/distribute/promote/device-art-resources/nexus_7_2012/land_shadow.png b/docs/html/distribute/promote/device-art-resources/nexus_7_2012/land_shadow.png Binary files differnew file mode 100644 index 0000000..cfb7952 --- /dev/null +++ b/docs/html/distribute/promote/device-art-resources/nexus_7_2012/land_shadow.png diff --git a/docs/html/distribute/promote/device-art-resources/nexus_7_2012/port_back.png b/docs/html/distribute/promote/device-art-resources/nexus_7_2012/port_back.png Binary files differnew file mode 100644 index 0000000..5bb815a --- /dev/null +++ b/docs/html/distribute/promote/device-art-resources/nexus_7_2012/port_back.png diff --git a/docs/html/distribute/promote/device-art-resources/nexus_7_2012/port_fore.png b/docs/html/distribute/promote/device-art-resources/nexus_7_2012/port_fore.png Binary files differnew file mode 100644 index 0000000..1be3b21 --- /dev/null +++ b/docs/html/distribute/promote/device-art-resources/nexus_7_2012/port_fore.png diff --git a/docs/html/distribute/promote/device-art-resources/nexus_7_2012/port_shadow.png b/docs/html/distribute/promote/device-art-resources/nexus_7_2012/port_shadow.png Binary files differnew file mode 100644 index 0000000..7e8aff2 --- /dev/null +++ b/docs/html/distribute/promote/device-art-resources/nexus_7_2012/port_shadow.png diff --git a/docs/html/distribute/promote/device-art-resources/nexus_7_2012/thumb.png b/docs/html/distribute/promote/device-art-resources/nexus_7_2012/thumb.png Binary files differnew file mode 100644 index 0000000..b5db82e --- /dev/null +++ b/docs/html/distribute/promote/device-art-resources/nexus_7_2012/thumb.png diff --git a/docs/html/distribute/promote/device-art.jd b/docs/html/distribute/promote/device-art.jd index 58e183c..09a3941 100644 --- a/docs/html/distribute/promote/device-art.jd +++ b/docs/html/distribute/promote/device-art.jd @@ -173,12 +173,13 @@ feature image or screenshots for your Google Play app listing.</p> title: 'Nexus 7', url: 'http://www.google.com/nexus/7/', physicalSize: 7, - physicalHeight: 7.81, - density: '213dpi', + physicalHeight: 8, + actualResolution: [1200,1920], + density: 'XHDPI', landRes: ['shadow', 'back', 'fore'], - landOffset: [315,270], + landOffset: [326,245], portRes: ['shadow', 'back', 'fore'], - portOffset: [264,311], + portOffset: [244,326], portSize: [800,1280] }, { @@ -210,6 +211,20 @@ feature image or screenshots for your Google Play app listing.</p> archived: true }, { + id: 'nexus_7_2012', + title: 'Nexus 7 (2012)', + url: 'http://www.google.com/nexus/7/', + physicalSize: 7, + physicalHeight: 7.81, + density: '213dpi', + landRes: ['shadow', 'back', 'fore'], + landOffset: [315,270], + portRes: ['shadow', 'back', 'fore'], + portOffset: [264,311], + portSize: [800,1280], + archived: true + }, + { id: 'galaxy_nexus', title: 'Galaxy Nexus', url: 'http://www.android.com/devices/detail/galaxy-nexus', diff --git a/docs/html/guide/topics/manifest/uses-sdk-element.jd b/docs/html/guide/topics/manifest/uses-sdk-element.jd index d5b5bdf..15092a0 100644 --- a/docs/html/guide/topics/manifest/uses-sdk-element.jd +++ b/docs/html/guide/topics/manifest/uses-sdk-element.jd @@ -227,6 +227,12 @@ Versions dashboards page</a>.</p> <table> <tr><th>Platform Version</th><th>API Level</th><th>VERSION_CODE</th><th>Notes</th></tr> + <tr><td><a href="{@docRoot}about/versions/android-4.3.html">Android 4.3</a></td> + <td><a href="{@docRoot}sdk/api_diff/18/changes.html" title="Diff Report">18</a></td> + <td>{@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}</td> + <td><a href="{@docRoot}about/versions/jelly-bean.html">Platform +Highlights</a></td></tr> + <tr><td><a href="{@docRoot}about/versions/android-4.2.html">Android 4.2, 4.2.2</a></td> <td><a href="{@docRoot}sdk/api_diff/17/changes.html" title="Diff Report">17</a></td> <td>{@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1}</td> diff --git a/docs/html/images/video-Colopl.png b/docs/html/images/video-Colopl.png Binary files differnew file mode 100644 index 0000000..0ee88c6 --- /dev/null +++ b/docs/html/images/video-Colopl.png diff --git a/docs/html/index.jd b/docs/html/index.jd index a972309..73fc302 100644 --- a/docs/html/index.jd +++ b/docs/html/index.jd @@ -57,15 +57,15 @@ page.metaDescription=The official site for Android developers. Provides the Andr <li class="item carousel-home"> <div class="content-left col-11" style="padding-top:65px;"> <script src="//ajax.googleapis.com/ajax/libs/swfobject/2.2/swfobject.js"></script> - <div style="box-shadow: 3px 10px 18px 1px #999;width:600px;height:338px"> + <div style="box-shadow: 3px 10px 18px 1px #999;width:600px;height:336px"> <div id="ytapiplayer"> - You need Flash player 8+ and JavaScript enabled to view this video. + <a href="http://www.youtube.com/watch?v=CbpoZeQCNe4"><img width=600 src="{@docRoot}images/video-Colopl.png"></a><!--You need Flash player 8+ and JavaScript enabled to view this video. --> </div> <script type="text/javascript"> var params = { allowScriptAccess: "always" }; var atts = { id: "ytapiplayer" }; - swfobject.embedSWF("//www.youtube.com/v/O8i4HUw7JYA?enablejsapi=1&playerapiid=ytplayer&version=3&HD=1;rel=0;showinfo=0;modestbranding;origin=developer.android.com;autohide=1", - "ytapiplayer", "600", "338", "8", null, null, params, atts); + swfobject.embedSWF("//www.youtube.com/v/CbpoZeQCNe4?enablejsapi=1&playerapiid=ytplayer&version=3&HD=1;rel=0;showinfo=0;modestbranding;origin=developer.android.com;autohide=1", + "ytapiplayer", "600", "336", "8", null, null, params, atts); // Callback used to pause/resume carousel based on video state function onytplayerStateChange(newState) { @@ -97,6 +97,37 @@ page.metaDescription=The official site for Android developers. Provides the Andr <p>Bangalore-based developers redBus.in talk about how Android is helping them deliver a superior booking and travel experience to millions of daily bus riders in India.</p> </div> </li> + + <li class="item carousel-home"> + <div class="content-left col-11" style="padding-top:10px;"> + <a href="{@docRoot}channels/io2013.html"> + <img src="{@docRoot}images/home/io-videos-2013.png" style="margin:60px 0 0; + box-shadow: 3px 10px 18px 1px #999;"> + </a> + </div> + <div class="content-right col-4"> + <h1>Watch the Android talks from Google I/O</h1> + <p>If you weren't able to attend Google I/O in person or couldn't make it + to all the talks, you can catch up on the action + with all the recordings, brought to you by + <a href="http://developers.google.com/live">Google Developers Live</a>.</p> + <p><a href="{@docRoot}channels/io2013.html" class="button" + >See the Android talks</a></p> + </div> + </li> + + + <li class="item carousel-home"> + <div class="content-left col-9"> + <a href="{@docRoot}about/versions/jelly-bean.html"><img src="{@docRoot}images/home/android-jellybean.png" ></a> + </div> + <div class="content-right col-6"> + <h1>Android 4.2 Jelly Bean!</h1> + <p>The latest version of Jelly Bean is here, with performance optimizations, a refreshed UI, and great new features for developers. </p> + <p>Android 4.2 includes APIs for developing lock sceen widgets and Daydream screensavers, using external displays, creating RTL layouts, building flexible UI with nested Fragments, and much more.</p> + <p><a href="{@docRoot}about/versions/jelly-bean.html" class="button">Learn More</a></p> + </div> + </li> <li class="item carousel-home"> <div class="content-left col-10"> <img src="{@docRoot}images/home/design.png" style="margin-top:30px"> diff --git a/docs/html/sdk/index.jd b/docs/html/sdk/index.jd index 0d0f348..aa3b2ec 100644 --- a/docs/html/sdk/index.jd +++ b/docs/html/sdk/index.jd @@ -5,43 +5,43 @@ header.hide=1 page.metaDescription=Download the official Android SDK to develop apps for Android-powered devices. -sdk.linux32_bundle_download=adt-bundle-linux-x86-20130522.zip -sdk.linux32_bundle_bytes=439988972 -sdk.linux32_bundle_checksum=1fdd8d7537ab9217d61d32ab912f0243 +sdk.linux32_bundle_download=adt-bundle-linux-x86-20130717.zip +sdk.linux32_bundle_bytes=440035305 +sdk.linux32_bundle_checksum=ecfacb91df1ee63cce1edd4f1a5cda5a -sdk.linux64_bundle_download=adt-bundle-linux-x86_64-20130522.zip -sdk.linux64_bundle_bytes=440275051 -sdk.linux64_bundle_checksum=e38751ff372a8d6208fcef5659133e98 +sdk.linux64_bundle_download=adt-bundle-linux-x86_64-20130717.zip +sdk.linux64_bundle_bytes=440322117 +sdk.linux64_bundle_checksum=ab177a06784340b8f1d136651e3dc62a -sdk.mac64_bundle_download=adt-bundle-mac-x86_64-20130522.zip -sdk.mac64_bundle_bytes=409047751 -sdk.mac64_bundle_checksum=3f4d05206d66e402e87b27a6b3dcf0f9 +sdk.mac64_bundle_download=adt-bundle-mac-x86_64-20130717.zip +sdk.mac64_bundle_bytes=411609229 +sdk.mac64_bundle_checksum=07c891212a49b5f8495ea9d8d47ba3fe -sdk.win32_bundle_download=adt-bundle-windows-x86-20130522.zip -sdk.win32_bundle_bytes=446736316 -sdk.win32_bundle_checksum=53345fa4121fa58cc048f66c3af3bae9 +sdk.win32_bundle_download=adt-bundle-windows-x86-20130717.zip +sdk.win32_bundle_bytes=446783216 +sdk.win32_bundle_checksum=0dd91095999d3539ca1ec4033d83d935 -sdk.win64_bundle_download=adt-bundle-windows-x86_64-20130522.zip -sdk.win64_bundle_bytes=446864400 -sdk.win64_bundle_checksum=b28817f62e7f54e3c683841b61b65564 +sdk.win64_bundle_download=adt-bundle-windows-x86_64-20130717.zip +sdk.win64_bundle_bytes=446911629 +sdk.win64_bundle_checksum=61ec74995b39166db7f079017a028cec -sdk.linux_download=android-sdk_r22.0.1-linux.tgz -sdk.linux_bytes=105617062 -sdk.linux_checksum=56ed27d456b4f0e0d3090b24f9b06757 +sdk.linux_download=android-sdk_r22.0.4-linux.tgz +sdk.linux_bytes=105640988 +sdk.linux_checksum=4a5db98a58c68c24e66f04f07ac77da5 -sdk.mac_download=android-sdk_r22.0.1-macosx.zip -sdk.mac_bytes=77206237 -sdk.mac_checksum=5c20497d7f7b9d28ee30e57cbf769c8c +sdk.mac_download=android-sdk_r22.0.4-macosx.zip +sdk.mac_bytes=77225662 +sdk.mac_checksum=384752505f4f2ba3627bd6aad0697f11 -sdk.win_download=android-sdk_r22.0.1-windows.zip -sdk.win_bytes=113483496 -sdk.win_checksum=cb7f7703450afa5914fb4b8b8332a9f3 +sdk.win_download=android-sdk_r22.0.4-windows.zip +sdk.win_bytes=113507679 +sdk.win_checksum=320b11d1ed85fd3f5e937697c333d895 -sdk.win_installer=installer_r22.0.1-windows.exe -sdk.win_installer_bytes=93479015 -sdk.win_installer_checksum=81621d3b164f81f91e066011b325f88f +sdk.win_installer=installer_r22.0.4-windows.exe +sdk.win_installer_bytes=93502726 +sdk.win_installer_checksum=96a8ae367d84ed219e1eb2cf473667d0 diff --git a/docs/html/sdk/installing/installing-adt.jd b/docs/html/sdk/installing/installing-adt.jd index b8ab24b..2a09636 100644 --- a/docs/html/sdk/installing/installing-adt.jd +++ b/docs/html/sdk/installing/installing-adt.jd @@ -1,8 +1,8 @@ page.title=Installing the Eclipse Plugin -adt.zip.version=22.0.1 -adt.zip.download=ADT-22.0.1.zip -adt.zip.bytes=16815544 -adt.zip.checksum=64473af058fa8f02e36241ee378b3ac0 +adt.zip.version=22.0.4 +adt.zip.download=ADT-22.0.4.zip +adt.zip.bytes=16838756 +adt.zip.checksum=f0291f4bb9d78ec34a7751cd2402cc2a @jd:body diff --git a/docs/html/tools/revisions/platforms.jd b/docs/html/tools/revisions/platforms.jd index 31cec0e..820edbd 100644 --- a/docs/html/tools/revisions/platforms.jd +++ b/docs/html/tools/revisions/platforms.jd @@ -29,25 +29,46 @@ release notes for each version of the platform and the subsequent revisions to t version.</p> <p>To determine what revision of an Android platform you have installed, refer to the -<strong>Installed Packages</strong> listing in the Android SDK Manager.</p> +<strong>Installed Packages</strong> listing in the Android +<a href="{@docRoot}tools/help/sdk-manager.html">SDK Manager</a>.</p> +<p class="caution"><strong>Important:</strong> To download the most recent Android +system components from the Android SDK Manager, you must first update the SDK Tools to +revision 22 or later and restart the SDK Manager. If you do not, +the latest Android system components will not be available for download.</p> +<h2 id="4.3">Android 4.3</h2> -<h2 id="4.2">Android 4.2</h2> +<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="" />Revision 1</a> <em>(July 2013)</em> + </p> -<p class="caution"><strong>Important:</strong> To download the new Android -4.2.x system components from the Android SDK Manager, you must first update the -SDK tools to revision 20 or later and restart the Android SDK Manager. If you do not, -the Android 4.2 system components will not be available for download.</p> + <div class="toggle-content-toggleme"> -<div class="toggle-content opened"> + <p>Initial release. The system version is 4.3.</p> + <dl> + <dt>Dependencies:</dt> + <dd>Android SDK Platform-tools r18 or higher is required.</dd> + <dd>Android SDK Tools 22.0.4 or higher is recommended.</dd> + </dl> + + </div> +</div> + + +<h2 id="4.2">Android 4.2</h2> + + +<div class="toggle-content closed"> <p><a href="#" onclick="return toggleContent(this)"> - <img src="{@docRoot}assets/images/triangle-opened.png" + <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img" alt="" />Revision 2</a> <em>(February 2013)</em> </p> @@ -150,12 +171,6 @@ Devices in the <a href="{@docRoot}tools/help/avd-manager.html">AVD Manager</a>:< <h2 id="4.1">Android 4.1</h2> -<p class="caution"><strong>Important:</strong> To download the new Android -4.1.x system components from the Android SDK Manager, you must first update the -SDK tools to revision 20 or later and restart the Android SDK Manager. If you do not, -the Android 4.1 system components will not be available for download.</p> - - <div class="toggle-content closed"> <p><a href="#" onclick="return toggleContent(this)"> @@ -269,11 +284,6 @@ emulator configuration.</p> <h2 id="4.0.3">Android 4.0.3</h2> -<p class="caution"><strong>Important:</strong> To download the new Android -4.0.x system components from the Android SDK Manager, you must first update the -SDK tools to revision 14 or later and restart the Android SDK Manager. If you do not, -the Android 4.0.x system components will not be available for download.</p> - <div class="toggle-content closed"> <p><a href="#" onclick="return toggleContent(this)"> @@ -711,13 +721,6 @@ ADT 12.</p> <h2 id="2.3.4">Android 2.3.4</h2> - -<p>The sections below provide notes about successive releases of -the Android 2.3.4 platform component for the Android SDK, as denoted by -revision number. To determine what revision(s) of the Android -2.3.4 platforms are installed in your SDK environment, refer to -the "Installed Packages" listing in the Android SDK and AVD Manager.</p> - <div class="toggle-content closed" > <p><a href="#" onclick="return toggleContent(this)"> @@ -865,14 +868,6 @@ emulator skins are:</p> <h2 id="2.3">Android 2.3</h2> - -<p>The sections below provide notes about successive releases of -the Android 2.3 platform component for the Android SDK, as denoted by -revision number. To determine what revision(s) of the Android -2.3 platforms are installed in your SDK environment, refer to -the "Installed Packages" listing in the Android SDK and AVD Manager.</p> - - <div class="toggle-content closed" > <p><a href="#" onclick="return toggleContent(this)"> @@ -1033,4 +1028,4 @@ emulator skins are:</p> <li> WVGA854 (480x854 high density, normal screen) </li> -</ul>
\ No newline at end of file +</ul> diff --git a/docs/html/tools/sdk/eclipse-adt.jd b/docs/html/tools/sdk/eclipse-adt.jd index 52647ff..7b0b5a8 100644 --- a/docs/html/tools/sdk/eclipse-adt.jd +++ b/docs/html/tools/sdk/eclipse-adt.jd @@ -53,9 +53,46 @@ the ADT Plugin, as denoted by revision number. </p> <p>For a summary of all known issues in ADT, see <a href="http://tools.android.com/knownissues">http://tools.android.com/knownissues</a>.</p> + <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=""/>ADT 22.0.4</a> <em>(July 2013)</em> + </p> + + <div class="toggle-content-toggleme"> +<dl> + <dt>Dependencies:</dt> + + <dd> + <ul> + <li>Java 1.6 or higher is required for ADT 22.0.4.</li> + <li>Eclipse Helios (Version 3.6.2) or higher is required for ADT 22.0.4.</li> + <li>ADT 22.0.4 is designed for use with <a href="{@docRoot}tools/sdk/tools-notes.html">SDK + Tools r22.0.4</a>. If you haven't already installed SDK Tools r22.0.4 into your SDK, use the + Android SDK Manager to do so.</li> + </ul> + </dd> + + <dt>General Notes:</dt> + <dd> + <ul> + <li>Fixed problem with compiling Renderscript code.</li> + <li>Improved Gradle export with better workflow and error reporting.</li> + <li>Improved Gradle multi-module export feature.</li> + <li>Updated build logic to force exporting of the classpath containers unless you are using + the Maven plugin.</li> + </ul> + </dd> + +</dl> +</div> +</div> + + +<div class="toggle-content closed"> + <p><a href="#" onclick="return toggleContent(this)"> + <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img" alt=""/>ADT 22.0.1</a> <em>(May 2013)</em> </p> diff --git a/docs/html/tools/sdk/ndk/index.jd b/docs/html/tools/sdk/ndk/index.jd index 74caaf4..1f34987 100644 --- a/docs/html/tools/sdk/ndk/index.jd +++ b/docs/html/tools/sdk/ndk/index.jd @@ -1,29 +1,29 @@ ndk=true page.template=sdk -ndk.mac64_download=android-ndk-r8e-darwin-x86_64.tar.bz2 -ndk.mac64_bytes=508419298 -ndk.mac64_checksum=efac96fab20e6ddb1311d6ba5648ce72 +ndk.mac64_download=android-ndk-r9-darwin-x86_64.tar.bz2 +ndk.mac64_bytes=726430529 +ndk.mac64_checksum=b975271d8f064611e7e12bf87b736826 -ndk.mac32_download=android-ndk-r8e-darwin-x86.tar.bz2 -ndk.mac32_bytes=496238878 -ndk.mac32_checksum=e17e707464c45c0d5615e4d0ae6a5cf7 +ndk.mac32_download=android-ndk-r9-darwin-x86.tar.bz2 +ndk.mac32_bytes=710781553 +ndk.mac32_checksum=6f7c4dd38df9079bb4b13846add5c0da -ndk.linux64_download=android-ndk-r8e-linux-x86_64.tar.bz2 -ndk.linux64_bytes=466853553 -ndk.linux64_checksum=fa812352956067e7a9eefc0274675e9a +ndk.linux64_download=android-ndk-r9-linux-x86_64.tar.bz2 +ndk.linux64_bytes=669064468 +ndk.linux64_checksum=3eedc86b20ec09fcd1fd03f4481a706d -ndk.linux32_download=android-ndk-r8e-linux-x86.tar.bz2 -ndk.linux32_bytes=461526099 -ndk.linux32_checksum=26d774b0884bcd98de08eb4de41ab532 +ndk.linux32_download=android-ndk-r9-linux-x86.tar.bz2 +ndk.linux32_bytes=660787157 +ndk.linux32_checksum=999d155ba772c49baacee6d41d664922 -ndk.win64_download=android-ndk-r8e-windows-x86_64.zip -ndk.win64_bytes=461298980 -ndk.win64_checksum=11eb99b3b56fc86d9d231ebff5c41db3 +ndk.win64_download=android-ndk-r9-windows-x86_64.zip +ndk.win64_bytes=826661995 +ndk.win64_checksum=cd56cc1036235f16369f2112fa27be91 -ndk.win32_download=android-ndk-r8e-windows-x86.zip -ndk.win32_bytes=434701805 -ndk.win32_checksum=fb41ed2bff5610b14a7b6f085ab86213 +ndk.win32_download=android-ndk-r9-windows-x86.zip +ndk.win32_bytes=777938252 +ndk.win32_checksum=9c1f66ff963cc61e338964c5f97a4d34 page.title=Android NDK @jd:body @@ -255,13 +255,286 @@ $('#Downloads').after($('#download-table')); <h2 id="Revisions">Revisions</h2> -<p>The sections below provide information and notes about successive releases of -the NDK, as denoted by revision number. </p> - +<p>The following sections provide information about releases of the NDK.</p> <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="" + >Android NDK, Revision 9</a> <em>(July 2013)</em> + </p> + <div class="toggle-content-toggleme"> + <dl> + <dt>Important changes:</dt> + <dd> + <ul> + <li>Added support for Android 4.3 (API level 18). For more information, see + {@code STABLE-APIS.html} and new code examples in {@code samples/gles3jni/README}. + <li>Added headers and libraries for OpenGL ES 3.0, which is supported by Android 4.3 + (API level 18) and higher.</li> + <li>Added GNU Compiler Collection (GCC) 4.8 compiler to the NDK. Since GCC 4.6 is still + the default, you must explicitly enable this option: + <ul> + <li>For {@code ndk-build} builds, export {@code NDK_TOOLCHAIN_VERSION=4.8} or + add it in {@code Application.mk}.</li> + <li>For standalone builds, use the {@code --toolchain=} option in + {@code make-standalone-toolchain.sh}, for example:<br> + {@code --toolchain=arm-linux-androideabi-4.8}</li> + </ul> + <p class="note"><strong>Note:</strong> + The {@code -Wunused-local-typedefs} option is enabled by {@code -Wall}. Be + sure to add {@code __attribute__((unused))} if you use compile-time asserts like + {@code sources/cxx-stl/stlport/stlport/stl/config/features.h}, line #311. For more + information, see + <a href="https://android-review.googlesource.com/#/c/55460">Change 55460</a></p> + <p class="note"><strong>Note:</strong> + In the GCC 4.7 release and later, ARM compilers generate unaligned access code by + default for ARMv6 and higher build targets. You may need to add the + {@code -mno-unaligned-access} build option when building for kernels that do not support + this feature.</p> + </li> + <li>Added Clang 3.3 support. The {@code NDK_TOOLCHAIN_VERSION=clang} build option + now picks Clang 3.3 by default. + <p class="note"><strong>Note:</strong> + Both GCC 4.4.3 and Clang 3.1 are deprecated, and will be removed from the next NDK + release.</p></li> + <li>Updated GNU Project Debugger (GDB) to support python 2.7.5.</li> + <li>Added MCLinker to support Windows hosts. Since {@code ld.gold} + is the default where available, you must add {@code -fuse-ld=mcld} in + {@code LOCAL_LDFLAGS} or {@code APP_LDFLAGS} to enable MCLinker.</li> + <li>Added {@code ndk-depends} tool which prints ELF library dependencies. + For more information, see {@code NDK-DEPENDS.html}. + (<a href="http://b.android.com/53486">Issue 53486</a>)</li> + </ul> + </dd> + + <dt>Important bug fixes:</dt> + <dd> + <ul> + <li>Fixed potential event handling issue in {@code android_native_app_glue}. + (<a href="http://b.android.com/41755">Issue 41755</a>)</li> + <li>Fixed ARM/GCC-4.7 build to generate sufficient alignment for NEON load and store + instructions VST and VLD. + (<a href="http://gcc.gnu.org/bugzilla/show_bug.cgi?id=57271">GCC Issue 57271</a>)</li> + <li>Fixed a GCC 4.4.3/4.6/4.7 internal compiler error (ICE) for a constant negative index + value on a string literal. + (<a href="http://b.android.com/54623">Issue 54623</a>)</li> + <li>Fixed GCC 4.7 segmentation fault for constant initialization with an object address. + (<a href="http://b.android.com/56508">Issue 56508</a>)</li> + <li>Fixed GCC 4.6 ARM segmentation fault for <code>-O</code> values when using Boost + 1.52.0. (<a href="http://b.android.com/42891">Issue 42891</a>) + <li>Fixed {@code libc.so} and {@code libc.a} to support the {@code wait4()} function. + (<a href="http://b.android.com/19854">Issue 19854</a>)</li> + <li>Updated the x86 libc.so and libc.a files to include the {@code clone()} + function.</li> + <li>Fixed {@code LOCAL_SHORT_COMMANDS} bug where the {@code linker.list} file is + empty or not used.</li> + <li>Fixed GCC MIPS build on Mac OS to use CFI directives, without which + {@code ld.mcld --eh-frame-hdr} fails frequently.</li> + <li>Fixed Clang 3.2 X86/MIPS internal compiler error in {@code llvm/lib/VMCore/Value.cpp}. + (<a href="https://android-review.googlesource.com/#/c/59021">Change 59021</a>)</li> + <li>Fixed GCC 4.7 64-bit Windows assembler crash. (Error: {@code out of memory allocating + 4294967280 bytes}).</li> + <li>Updated {@code ndk-gdb} script so that the {@code --start} or {@code --launch} actions + now wait for the GNU Debug Server, so that it can more reliably hit breakpoints set + early in the execution path (such as breakpoints in JNI code). + (<a href="http://b.android.com/41278">Issue 41278</a>) + <p class="note"><strong>Note:</strong> + This feature requires jdb and produces warning about pending breakpoints. + Specify the {@code --nowait} option to restore previous behavior. + </p> + </li> + <li>Fixed GDB crash when library list is empty.</li> + <li>Fixed GDB crash when using a {@code stepi} command past a {@code bx pc} or + {@code blx pc} Thumb instruction. + (<a href="http://b.android.com/56962">Issue 56962</a>, + <a href="http://b.android.com/36149">Issue 36149</a>)</li> + <li>Fixed MIPS {@code gdbserver} to look for {@code DT_MIPS_RLD_MAP} instead of + {@code DT_DEBUG}. (<a href="http://b.android.com/56586">Issue 56586</a>)</li> + <li>Fixed a circular dependency in the ndk-build script, for example: If A->B and + B->B, then B was dropped from build. + (<a href="http://b.android.com/56690">Issue 56690</a>)</li> + </ul> + </dd> + + <dt>Other bug fixes:</dt> + <dd> + <ul> + <li>Fixed the {@code ndk-build} script to enable you to specify a version of Clang as a + command line option (e.g., {@code NDK_TOOLCHAIN_VERSION=clang3.2}). Previously, only + specifying the version as an environment variable worked.</li> + <li>Fixed gabi++ size of {@code _Unwind_Exception} to be 24 for MIPS build targets when + using the Clang compiler. + (<a href="https://android-review.googlesource.com/#/c/54141">Change 54141</a>)</li> + <li>Fixed the {@code ndk-build} script to ensure that built libraries are actually + removed from projects that include prebuilt static libraries when using the + {@code ndk-build clean} command. + (<a href="https://android-review.googlesource.com/#/c/54461">Change 54461</a>, + <a href="https://android-review.googlesource.com/#/c/54480">Change 54480</a>)</li> + <li>Modified the {@code NDK_ANALYZE=1} option to be less verbose.</li> + <li>Fixed {@code gnu-libstdc++/Android.mk} to include a {@code backward/} path for builds + that use backward compability. + (<a href="http://b.android.com/53404">Issue 53404</a>)</li> + <li>Fixed a problem where {@code stlport new} sometimes returned random values.</li> + <li>Fixed {@code ndk-gdb} to match the order of {@code CPU_ABIS}, not {@code APP_ABIS}. + (<a href="http://b.android.com/54033">Issue 54033</a>)</li> + <li>Fixed a problem where the NDK 64-bit build on MacOSX choses the wrong path for + compiler. + (<a href="http://b.android.com/53769">Issue 53769</a>)</li> + <li>Fixed build scripts to detect 64-bit Windows Vista. + (<a href="http://b.android.com/54485">Issue 54485</a>)</li> + <li>Fixed x86 {@code ntonl/swap32} error: {@code invalid 'asm': operand number + out of range}. + (<a href="http://b.android.com/54465">Issue 54465</a>, + <a href="https://android-review.googlesource.com/#/c/57242">Change 57242</a>)</li> + <li>Fixed {@code ld.gold} to merge string literals.</li> + <li>Fixed {@code ld.gold} to handle large symbol alignment.</li> + <li>Updated {@code ld.gold} to enable the {@code --sort-section=name} option.</li> + <li>Fixed GCC 4.4.3/4.6/4.7 to suppress the {@code -export-dynamic} option for + statically linked programs. GCC no longer adds an {@code .interp} section for statically + linked programs.</li> + <li>Fixed GCC 4.4.3 {@code stlport} compilation error about inconsistent {@code typedef} + of {@code _Unwind_Control_Block}. + (<a href="http://b.android.com/54426">Issue 54426</a>)</li> + <li>Fixed {@code awk} scripts to handle {@code AndroidManifest.xml} files created on + Windows which may contain trailing {@code \r} characters and cause build errors. + (<a href="http://b.android.com/42548">Issue 42548</a>)</li> + <li>Fixed {@code make-standalone-toolchain.sh} to probe the {@code prebuilts/} + directory to detect if the host is 32 bit or 64 bit.</li> + <li>Fixed the Clang 3.2 {@code -integrated-as} option.</li> + <li>Fixed the Clang 3.2 ARM EHABI compact model {@code pr1} and {@code pr2} handler data. + </li> + <li>Added clang {@code -mllvm -arm-enable-ehabi} option to fix the following clang error: + <pre>clang: for the -arm-enable-ehabi option: may only occur zero or one times!</pre> + </li> + <li>Fixed build failure when there is no {@code uses-sdk} element in application + manifest. (<a href="http://b.android.com/57015">Issue 57015</a>)</li> + </ul> + + </dd> + <dt>Other changes:</dt> + <dd> + <ul> + <li>Header Fixes + <ul> + <li>Modified headers to make {@code __set_errno} an inlined function, since + {@code __set_errno} in {@code errno.h} is deprecated, and {@code libc.so} no longer + exports it.</li> + <li>Modified {@code elf.h} to include {@code stdint.h}. + (<a href="http://b.android.com/55443">Issue 55443</a>)</li> + <li>Fixed {@code sys/un.h} to be included independently of other headers. + (<a href="http://b.android.com/53646">Issue 53646</a>)</li> + <li>Fixed all of the {@code MotionEvent_getHistorical} API family to take the + {@code const AInputEvent* motion_event}. + (<a href="http://b.android.com/55873">Issue 55873</a>)</li> + <li>Fixed {@code malloc_usable_size} to take {@code const void*}. + (<a href="http://b.android.com/55725">Issue 55725</a>)</li> + <li>Fixed stdint.h to be more compatible with C99. + (<a href="https://android-review.googlesource.com/#/c/46821">Change 46821</a>)</li> + <li>Modified {@code wchar.h} to not redefine {@code WCHAR_MAX} and + {@code WCHAR_MIN}</li> + <li>Fixed {@code <inttypes.h>} declaration for pointer-related {@code PRI} and + {@code SCN} macros. (<a href="http://b.android.com/57218">Issue 57218</a>)</li> + <li>Changed the {@code sys/cdefs.h} header so that {@code __WCHAR_TYPE__} is 32-bit + for API levels less than 9, which means that {@code wchat_t} is 32-bit for all + API levels. To restore the previous behavior, define the {@code _WCHAR_IS_8BIT} + boolean variable. (<a href="http://b.android.com/57267">Issue 57267</a>)</li> + </ul> + </li> + <li>Added more formatting in NDK {@code docs/} and miscellaneous documentation fixes. + </li> + <li>Added support for a thin archive technique when building static libraries. + (<a href="http://b.android.com/40303">Issue 40303</a>)</li> + <li>Updated script {@code make-standalone-toolchain.sh} to support the {@code stlport} + library in addition to {@code gnustl}, when you specify the option + {@code --stl=stlport}. For more information, see {@code STANDALONE-TOOLCHAIN.html}.</li> + <li>Updated the {@code make-standalone-toolchain.sh} script so that the + {@code --llvm-version=} option creates the {@code $TOOLCHAIN_PREFIX-clang} and + {@code $TOOLCHAIN_PREFIX-clang++} scripts in addition to {@code clang} and + {@code clang++}, to avoid using the host's clang and clang++ definitions by accident. + </li> + <li>Added two flags to re-enable two optimizations in upstream Clang but disabled in + NDK for better compatibility with code compiled by GCC: + <ul> + <li>Added a {@code -fcxx-missing-return-semantics} flag to re-enable <em>missing return + semantics</em> in Clang 3.2+. Normally, all paths should terminate with a return + statement for a value-returning function. If this is not the case, clang inserts + an undefined instruction (or trap in debug mode) at the path without a return + statement. If you are sure your code is correct, use this flag to allow the + optimizer to take advantage of the undefined behavior. If you are not sure, do not + use this flag. The caller may still receive a random incorrect value, but the + optimizer will not exploit it and make your code harder to debug.</li> + <li>Added a {@code -fglobal-ctor-const-promotion} flag to re-enable + promoting global variables with static constructor to be constants. With this flag, + the global variable optimization pass of LLVM tries to evaluate the global + variables with static constructors and promote them to global constants. Although + this optimization is correct, it may cause some incompatability with code compiled + by GCC. For example, code may do {@code const_cast} to cast the constant to mutable + and modify it. In GCC, the variable is in read-write and the code is run by + accident. In Clang, the const variable is in read-only memory and may cause your + application to crash.</li> + </ul> + </li> + <li>Added {@code -mldc1-sdc1} to the MIPS GCC and Clang compilers. By default, compilers + align 8-byte objects properly and emit the {@code ldc1} and {@code sdc1} instructions + to move them around. If your app uses a custom allocator that does not always align + with a new object's 8-byte boundary in the same way as the default allocator, your app + may crash due to {@code ldc1} and {@code sdc1} operations on unaligned memory. In this + case, use the {@code -mno-ldc1-sdc1} flag to workaround the problem.</li> + <li>Downgraded the event severity from warning to info if {@code APP_PLATFORM_LEVEL} is + larger than {@code APP_MIN_PLATFORM_LEVEL}. The {@code APP_PLATFORM_LEVEL} may be lower + than {@code APP_PLATFORM} in {@code jni/Application.mk} because the NDK does not have + headers for all levels. In this case, the actual level is shifted downwards. The + {@code APP_MIN_PLATFORM_LEVEL} is specified by the {@code android:minSdkVersion} in + your application's manifest. + (<a href="http://b.android.com/39752">Issue 39752</a>)</li> + <li>Added the {@code android_getCpuIdArm()} and {@code android_setCpuArm()} methods to + {@code cpu-features.c}. This addition enables easier retrieval of the ARM CPUID + information. (<a href="http://b.android.com/53689">Issue 53689</a>)</li> + <li>Modified {@code ndk-build} to use GCC 4.7's {@code as/ld} for Clang compiling. + <p class="note"><strong>Note:</strong> + In GCC 4.7, {@code monotonic_clock} and {@code is_monotonic} have been renamed to + {@code steady_clock} and {@code is_steady}, respectively.</p></li> + <li>Added the following new warnings to the {@code ndk-build} script: + <ul> + <li>Added warnings if {@code LOCAL_LDLIBS/LDFLAGS} are used in static library + modules.</li> + <li>Added a warning if a configuration has no module to build.</li> + <li>Added a warning for non-system libraries being used in + {@code LOCAL_LDLIBS/LDFLAGS} of a shared library or executable modules.</li> + </ul> + </li> + <li>Updated build scripts, so that if {@code APP_MODULES} is not defined and only static + libraries are listed in {@code Android.mk}, the script force-builds all of them. + (<a href="http://b.android.com/53502">Issue 53502</a>)</li> + <li>Updated {@code ndk-build} to support absolute paths in {@code LOCAL_SRC_FILES}.</li> + <li>Removed the {@code *-gdbtui} executables, which are duplicates of the {@code *-gdb} + executables with the {@code -tui} option enabled.</li> + <li>Updated the build scripts to warn you when the Edison Design Group (EDG) compiler + front-end turns {@code _STLP_HAS_INCLUDE_NEXT} back on. + (<a href="http://b.android.com/53646">Issue 53646</a>)</li> + <li>Added the environment variable {@code NDK_LIBS_OUT} to allow overriding of the + path for {@code libraries/gdbserver} from the default {@code $PROJECT/libs}. + For more information, see {@code OVERVIEW.html}.</li> + <li>Changed ndk-build script defaults to compile code with format string protection + {@code -Wformat -Werror=format-security}. You may set + {@code LOCAL_DISABLE_FORMAT_STRING_CHECKS=true} to disable it. + For more information, see {@code ANDROID-MK.html}</li> + <li>Added STL pretty-print support in {@code ndk-gdb-py}. For more information, see + {@code NDK-GDB.html}.</li> + <li>Added tests based on the googletest frameworks.</li> + <li>Added a notification to the toolchain build script that warns you if the current shell + is not {@code bash}.</li> + </ul> + </dd> + </dl> + </div> +</div> + + +<div class="toggle-content closed"> <p><a href="#" onclick="return toggleContent(this)"> - <img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-content-img" + <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img" alt="">Android NDK, Revision 8e</a> <em>(March 2013)</em> </p> @@ -283,7 +556,7 @@ the NDK, as denoted by revision number. </p> build automatically sorts out the order of libraries specified in {@code LOCAL_STATIC_LIBRARIES}, {@code LOCAL_WHOLE_STATIC_LIBRARIES} and {@code LOCAL_SHARED_LIBRARIES}. For more information, see {@code CHANGES.HTML}. - (<a href="http://code.google.com/p/android/issues/detail?id=39378">Issue 39378</a>)</li> + (<a href="http://b.android.com/39378">Issue 39378</a>)</li> </ul> </dd> @@ -295,23 +568,23 @@ the NDK, as denoted by revision number. </p> <li>Fixed build script which unconditionally builds Clang/llvm for MacOSX in 64-bit.</li> <li>Fixed GCC 4.6/4.7 internal compiler error: {@code gen_thumb_movhi_clobber at config/arm/arm.md:5832}. - (<a href="http://code.google.com/p/android/issues/detail?id=52732">Issue 52732</a>)</li> + (<a href="http://b.android.com/52732">Issue 52732</a>)</li> <li>Fixed build problem where GCC/ARM 4.6/4.7 fails to link code using 64-bit atomic built-in functions. - (<a href="http://code.google.com/p/android/issues/detail?id=41297">Issue 41297</a>)</li> + (<a href="http://b.android.com/41297">Issue 41297</a>)</li> <li>Fixed GCC 4.7 linker DIV usage mismatch errors. (<a href="http://sourceware.org/ml/binutils/2012-12/msg00202.html">Sourceware Issue</a>) <li>Fixed GCC 4.7 internal compiler error {@code build_data_member_initialization, at cp/semantics.c:5790}.</li> <li>Fixed GCC 4.7 internal compiler error {@code redirect_eh_edge_1, at tree-eh.c:2214}. - (<a href="http://code.google.com/p/android/issues/detail?id=52909">Issue 52909</a>)</li> + (<a href="http://b.android.com/52909">Issue 52909</a>)</li> <li>Fixed a GCC 4.7 segfault. (<a href="http://gcc.gnu.org/bugzilla/show_bug.cgi?id=55245">GCC Issue</a>)</li> <li>Fixed {@code <chrono>} clock resolution and enabled {@code steady_clock}. - (<a href="http://code.google.com/p/android/issues/detail?id=39680">Issue 39680</a>)</li> + (<a href="http://b.android.com/39680">Issue 39680</a>)</li> <li>Fixed toolchain to enable {@code _GLIBCXX_HAS_GTHREADS} for GCC 4.7 libstdc++. - (<a href="http://code.google.com/p/android/issues/detail?id=41770">Issue 41770</a>, - <a href="http://code.google.com/p/android/issues/detail?id=41859">Issue 41859</a>)</li> + (<a href="http://b.android.com/41770">Issue 41770</a>, + <a href="http://b.android.com/41859">Issue 41859</a>)</li> <li>Fixed problem with the X86 MXX/SSE code failing to link due to missing {@code posix_memalign}. (<a href="https://android-review.googlesource.com/#/c/51872">Change 51872</a>)</li> @@ -321,24 +594,24 @@ the NDK, as denoted by revision number. </p> <li>Fixed GCC4.7/X86 to restore earlier {@code cmov} behavior. (<a href="http://gcc.gnu.org/viewcvs?view=revision&revision=193554">GCC Issue</a>)</li> <li>Fixed handling NULL return value of {@code setlocale()} in libstdc++/GCC4.7. - (<a href="http://code.google.com/p/android/issues/detail?id=46718">Issue 46718</a>) + (<a href="http://b.android.com/46718">Issue 46718</a>) <li>Fixed {@code ld.gold} runtime undefined reference to {@code __exidx_start} and {@code __exidx_start_end}. (<a href="https://android-review.googlesource.com/#/c/52134">Change 52134</a>)</li> <li>Fixed Clang 3.1 internal compiler error when using Eigen library. - (<a href="http://code.google.com/p/android/issues/detail?id=41246">Issue 41246</a>)</li> + (<a href="http://b.android.com/41246">Issue 41246</a>)</li> <li>Fixed Clang 3.1 internal compiler error including {@code <chrono>} in C++11 mode. - (<a href="http://code.google.com/p/android/issues/detail?id=39600">Issue 39600</a>)</li> + (<a href="http://b.android.com/39600">Issue 39600</a>)</li> <li>Fixed Clang 3.1 internal compiler error when generating object code for a method call to a uniform initialized {@code rvalue}. - (<a href="http://code.google.com/p/android/issues/detail?id=41387">Issue 41387</a>)</li> + (<a href="http://b.android.com/41387">Issue 41387</a>)</li> <li>Fixed Clang 3.1/X86 stack realignment. (<a href="https://android-review.googlesource.com/#/c/52154">Change 52154</a>)</li> <li>Fixed problem with GNU Debugger (GDB) SIGILL when debugging on Android 4.1.2. - (<a href="http://code.google.com/p/android/issues/detail?id=40941">Issue 40941</a>)</li> + (<a href="http://b.android.com/40941">Issue 40941</a>)</li> <li>Fixed problem where GDB cannot set {@code source:line} breakpoints when symbols contain long, indirect file paths. - (<a href="http://code.google.com/p/android/issues/detail?id=42448">Issue 42448</a>)</li> + (<a href="http://b.android.com/42448">Issue 42448</a>)</li> <li>Fixed GDB {@code read_program_header} for MIPS PIE executables. (<a href="https://android-review.googlesource.com/#/c/49592">Change 49592</a>)</li> <li>Fixed {@code STLport} segmentation fault in {@code uncaught_exception()}. @@ -346,7 +619,7 @@ the NDK, as denoted by revision number. </p> <li>Fixed {@code STLport} bus error in exception handling due to unaligned access of {@code DW_EH_PE_udata2}, {@code DW_EH_PE_udata4}, and {@code DW_EH_PE_udata8}.</li> <li>Fixed Gabi++ infinite recursion problem with {@code nothrow new[]} operator. - (<a href="http://code.google.com/p/android/issues/detail?id=52833">Issue 52833</a>)</li> + (<a href="http://b.android.com/52833">Issue 52833</a>)</li> <li>Fixed Gabi++ wrong offset to exception handler pointer. (<a href="https://android-review.googlesource.com/#/c/53446">Change 53446</a>)</li> <li>Removed Gabi++ redundant free on exception object @@ -365,11 +638,11 @@ the NDK, as denoted by revision number. </p> <li>Fixed {@code stddef.h} to not redefine {@code offsetof} since it already exists in the toolchain.</li> <li>Fixed {@code elf.h} to contain {@code Elf32_auxv_t} and {@code Elf64_auxv_t}. - (<a href="http://code.google.com/p/android/issues/detail?id=38441">Issue 38441</a>) + (<a href="http://b.android.com/38441">Issue 38441</a>) </li> <li>Fixed the {@code #ifdef} C++ definitions in the {@code OpenSLES_AndroidConfiguration.h} header file. - (<a href="http://code.google.com/p/android/issues/detail?id=53163">Issue 53163</a>) + (<a href="http://b.android.com/53163">Issue 53163</a>) </li> </ul> </li> @@ -377,7 +650,7 @@ the NDK, as denoted by revision number. </p> </li> <li>Fixed system and Gabi++ headers to be able to compile with API level 8 and lower.</li> <li>Fixed {@code cpufeatures} to not parse {@code /proc/self/auxv}. - (<a href="http://code.google.com/p/android/issues/detail?id=43055">Issue 43055</a>)</li> + (<a href="http://b.android.com/43055">Issue 43055</a>)</li> <li>Fixed {@code ld.gold} to not depend on host libstdc++ and on Windows platforms, to not depend on the {@code libgcc_sjlj_1.dll} library.</li> <li>Fixed Clang 3.1 which emits inconsistent register list in {@code .vsave} and fails @@ -394,16 +667,16 @@ the NDK, as denoted by revision number. </p> </li> <li>Fixed X86 {@code libc.so} and {@code lib.a} which were missing the {@code sigsetjmp} and {@code siglongjmp} functions already declared in {@code setjmp.h}. - (<a href="http://code.google.com/p/android/issues/detail?id=19851">Issue 19851</a>)</li> + (<a href="http://b.android.com/19851">Issue 19851</a>)</li> <li>Patched GCC 4.4.3/4.6/4.7 libstdc++ to work with Clang in C++ 11. (<a href="http://clang.llvm.org/cxx_status.html">Clang Issue</a>)</li> <li>Fixed cygwin path in argument passed to {@code HOST_AWK}.</li> <li>Fixed {@code ndk-build} script warning in windows when running from project's JNI directory. - (<a href="http://code.google.com/p/android/issues/detail?id=40192">Issue 40192</a>)</li> + (<a href="http://b.android.com/40192">Issue 40192</a>)</li> <li>Fixed problem where the {@code ndk-build} script does not build if makefile has trailing whitespace in the {@code LOCAL_PATH} definition. - (<a href="http://code.google.com/p/android/issues/detail?id=42841">Issue 42841</a>)</li> + (<a href="http://b.android.com/42841">Issue 42841</a>)</li> </ul> </dd> @@ -419,13 +692,13 @@ the NDK, as denoted by revision number. </p> hidden visibility except for exception handling helpers.</li> <li>Updated build so that {@code STLport} is built for ARM in Thumb mode.</li> <li>Added support for {@code std::set_new_handler} in Gabi++. - (<a href="http://code.google.com/p/android/issues/detail?id=52805">Issue 52805</a>)</li> + (<a href="http://b.android.com/52805">Issue 52805</a>)</li> <li>Enabled {@code FUTEX} system call in GNU libstdc++.</li> <li>Updated {@code ndk-build} so that it no longer copies prebuilt static library to a project's {@code obj/local/<abi>/} directory. - (<a href="http://code.google.com/p/android/issues/detail?id=40302">Issue 40302</a>)</li> + (<a href="http://b.android.com/40302">Issue 40302</a>)</li> <li>Removed {@code __ARM_ARCH_5*__} from ARM {@code toolchains/*/setup.mk} script. - (<a href="http://code.google.com/p/android/issues/detail?id=21132">Issue 21132</a>)</li> + (<a href="http://b.android.com/21132">Issue 21132</a>)</li> <li>Built additional GNU libstdc++ libraries in thumb for ARM.</li> <li>Enabled MIPS floating-point {@code madd/msub/nmadd/nmsub/recip/rsqrt} instructions with 32-bit FPU.</li> @@ -458,7 +731,7 @@ the NDK, as denoted by revision number. </p> which was preventing a significant amount of parallel build processing.</li> <li>Updated {@code build-gabi++.sh} and {@code build-stlport.sh} so they can now run from the NDK package. - (<a href="http://code.google.com/p/android/issues/detail?id=52835">Issue 52835</a>) + (<a href="http://b.android.com/52835">Issue 52835</a>) </li> <li>Fixed {@code run-tests.sh} in the {@code MSys} utilities collection.</li> <li>Improved 64-bit host toolchain and Canadian Cross build support.</li> @@ -540,7 +813,7 @@ the NDK, as denoted by revision number. </p> <dd> <ul> <li>Fixed unnecessary rebuild of object files when using the {@code ndk-build} script. - (<a href="http://code.google.com/p/android/issues/detail?id=39810">Issue 39810</a>)</li> + (<a href="http://b.android.com/39810">Issue 39810</a>)</li> <li>Fixed a linker failure with the NDK 8c release for Mac OS X 10.6.x that produced the following error: <pre> @@ -551,29 +824,29 @@ Expected in: /usr/lib/libSystem.B.dylib</pre> not compatible with Mac OS 10.6.x and the NDK. </li> <li>Removed the {@code -x c++} options from the Clang++ standalone build script. - (<a href="http://code.google.com/p/android/issues/detail?id=39089">Issue 39089</a>)</li> + (<a href="http://b.android.com/39089">Issue 39089</a>)</li> <li>Fixed issues using the {@code NDK_TOOLCHAIN_VERSION=clang3.1} option in Cygwin. - (<a href="http://code.google.com/p/android/issues/detail?id=39585">Issue 39585</a>)</li> + (<a href="http://b.android.com/39585">Issue 39585</a>)</li> <li>Fixed the {@code make-standalone-toolchain.sh} script to allow generation of a standalone toolchain using the Cygwin or MinGW environments. The resulting toolchain can be used in Cygwin, MingGW or CMD.exe environments. - (<a href="http://code.google.com/p/android/issues/detail?id=39915">Issue 39915</a>, - <a href="http://code.google.com/p/android/issues/detail?id=39585">Issue 39585</a>)</li> + (<a href="http://b.android.com/39915">Issue 39915</a>, + <a href="http://b.android.com/39585">Issue 39585</a>)</li> <li>Added missing {@code SL_IID_ANDROIDBUFFERQUEUESOURCE} option in android-14 builds for ARM and X86. - (<a href="http://code.google.com/p/android/issues/detail?id=40625">Issue 40625</a>)</li> + (<a href="http://b.android.com/40625">Issue 40625</a>)</li> <li>Fixed x86 CPU detection for the {@code ANDROID_CPU_X86_FEATURE_MOVBE} feature. - (<a href="http://code.google.com/p/android/issues/detail?id=39317">Issue 39317</a>)</li> + (<a href="http://b.android.com/39317">Issue 39317</a>)</li> <li>Fixed an issue preventing the Standard Template Library (STL) from using C++ sources that do not have a {@code .cpp} file extension.</li> <li>Fixed GCC 4.6 ARM internal compiler error <em>at reload1.c:1061</em>. - (<a href="http://code.google.com/p/android/issues/detail?id=20862">Issue 20862</a>)</li> + (<a href="http://b.android.com/20862">Issue 20862</a>)</li> <li>Fixed GCC 4.4.3 ARM internal compiler error <em>at emit-rtl.c:1954</em>. - (<a href="http://code.google.com/p/android/issues/detail?id=22336">Issue 22336</a>)</li> + (<a href="http://b.android.com/22336">Issue 22336</a>)</li> <li>Fixed GCC 4.4.3 ARM internal compiler error <em>at postreload.c:396</em>. - (<a href="http://code.google.com/p/android/issues/detail?id=22345">Issue 22345</a>)</li> + (<a href="http://b.android.com/22345">Issue 22345</a>)</li> <li>Fixed problem with GCC 4.6/4.7 skipping lambda functions. - (<a href="http://code.google.com/p/android/issues/detail?id=35933">Issue 35933</a>)</li> + (<a href="http://b.android.com/35933">Issue 35933</a>)</li> </ul> </dd> @@ -584,21 +857,21 @@ Expected in: /usr/lib/libSystem.B.dylib</pre> <ul> <li>Fixed {@code __WINT_TYPE__} and {@code wint_t} to be the same type.</li> <li>Corrected typo in {@code android/bitmap.h}. - (<a href="http://code.google.com/p/android/issues/detail?id=15134">Issue 15134</a>) + (<a href="http://b.android.com/15134">Issue 15134</a>) </li> <li>Corrected typo in {@code errno.h}.</li> <li>Added check for the presence of {@code __STDC_VERSION__} in {@code sys/cdefs.h}. - (<a href="http://code.google.com/p/android/issues/detail?id=14627">Issue 14627</a>) + (<a href="http://b.android.com/14627">Issue 14627</a>) </li> <li>Reorganized headers in {@code byteswap.h} and {@code dirent.h}.</li> <li>Fixed {@code limits.h} to include {@code page.h} which provides {@code PAGE_SIZE} settings. - (<a href="http://code.google.com/p/android/issues/detail?id=39983">Issue 39983</a>) + (<a href="http://b.android.com/39983">Issue 39983</a>) </li> <li>Fixed return type of {@code glGetAttribLocation()} and {@code glGetUniformLocation()} from {@code int} to {@code GLint}.</li> <li>Fixed {@code __BYTE_ORDER} constant for x86 builds. - (<a href="http://code.google.com/p/android/issues/detail?id=39824">Issue 39824</a>) + (<a href="http://b.android.com/39824">Issue 39824</a>) </li> </ul> </li> @@ -611,7 +884,7 @@ Expected in: /usr/lib/libSystem.B.dylib</pre> <li>Fixed ARM EHABI support in Clang to conform to specifications.</li> <li>Fixed GNU Debugger (GDB) to shorten the time spent on walking the target's link map during {@code solib} events. - (<a href="http://code.google.com/p/android/issues/detail?id=38402">Issue 38402</a>)</li> + (<a href="http://b.android.com/38402">Issue 38402</a>)</li> <li>Fixed missing {@code libgcc.a} file when linking shared libraries.</li> </ul> </dd> @@ -712,7 +985,7 @@ Expected in: /usr/lib/libSystem.B.dylib</pre> <ul> <li>Fixed an issue where running {@code make-standalone-toolchain.sh} with root privileges resulted in the stand alone tool chain being inaccessible to some users. - (<a href="http://code.google.com/p/android/issues/detail?id=35279">Issue 35279</a>) + (<a href="http://b.android.com/35279">Issue 35279</a>) <ul> <li>All files and executables in the NDK release package are set to have read and execute permissions for all.</li> @@ -722,23 +995,23 @@ Expected in: /usr/lib/libSystem.B.dylib</pre> <li>Removed redundant {@code \r} from Windows prebuilt {@code echo.exe}. The redundant {@code \r} caused {@code gdb.setup} to fail in the GNU Debugger (GDB) because it incorrectly became part of the path. - (<a href="http://code.google.com/p/android/issues/detail?id=36054">Issue 36054</a>)</li> + (<a href="http://b.android.com/36054">Issue 36054</a>)</li> <li>Fixed Windows parallel builds that sometimes failed due to timing issues in the {@code host-mkdir} implementation. - (<a href="http://code.google.com/p/android/issues/detail?id=25875">Issue 25875</a>)</li> + (<a href="http://b.android.com/25875">Issue 25875</a>)</li> <li>Fixed GCC 4.4.3 GNU {@code libstdc++} to <em>not</em> merge {@code typeinfo} names by default. For more details, see {@code toolchain repo gcc/gcc-4.4.3/libstdc++-v3/libsupc++/typeinfo}. - (<a href="http://code.google.com/p/android/issues/detail?id=22165">Issue 22165</a>)</li> + (<a href="http://b.android.com/22165">Issue 22165</a>)</li> <li>Fixed problem on {@code null} context in GCC 4.6 {@code cp/mangle.c::write_unscoped_name}, where GCC may crash when the context is {@code null} and dereferenced in {@code TREE_CODE}.</li> <li>Fixed GCC 4.4.3 crashes on ARM NEON-specific type definitions for floats. - (<a href="http://code.google.com/p/android/issues/detail?id=34613">Issue 34613</a>)</li> + (<a href="http://b.android.com/34613">Issue 34613</a>)</li> <li>Fixed the {@code STLport} internal {@code _IteWrapper::operator*()} implementation where a stale stack location holding the dereferenced value was returned and caused runtime crashes. - (<a href="http://code.google.com/p/android/issues/detail?id=38630">Issue 38630</a>)</li> + (<a href="http://b.android.com/38630">Issue 38630</a>)</li> <li>ARM-specific fixes: <ul> @@ -755,17 +1028,17 @@ Expected in: /usr/lib/libSystem.B.dylib</pre> <li>Fixed {@code binutils-2.21/ld.bfd} to be capable of linking object from older binutils without {@code tag_FP_arch}, which was producing <em>assertion fail</em> error messages in GNU Binutils. - (<a href="http://code.google.com/p/android/issues/detail?id=35209">Issue 35209</a>) + (<a href="http://b.android.com/35209">Issue 35209</a>) </li> <li>Removed <em>Unknown EABI object attribute 44</em> warning when {@code binutils-2.19/ld} links prebuilt object by newer {@code binutils-2.21}</li> <li>Fixed an issue in GNU {@code stdc++} compilation with both {@code -mthumb} and {@code -march=armv7-a}, by modifying {@code make-standalone-toolchain.sh} to populate {@code headers/libs} in sub-directory {@code armv7-a/thumb}. - (<a href="http://code.google.com/p/android/issues/detail?id=35616">Issue 35616</a>) + (<a href="http://b.android.com/35616">Issue 35616</a>) </li> <li>Fixed <em>unresolvable R_ARM_THM_CALL relocation</em> error. - (<a href="http://code.google.com/p/android/issues/detail?id=35342">Issue 35342</a>) + (<a href="http://b.android.com/35342">Issue 35342</a>) </li> <li>Fixed internal compiler error at {@code reload1.c:3633}, caused by the ARM back-end expecting the wrong operand type when sign-extend from {@code char}. @@ -794,11 +1067,11 @@ Expected in: /usr/lib/libSystem.B.dylib</pre> <li>Disabled Python support in gdb-7.x at build, otherwise the gdb-7.x configure function may pick up whatever Python version is available on the host and build {@code gdb} with a hard-wired dependency on a specific version of Python. - (<a href="http://code.google.com/p/android/issues/detail?id=36120">Issue 36120</a>) + (<a href="http://b.android.com/36120">Issue 36120</a>) </li> <li>Fixed {@code ndk-gdb} when {@code APP_ABI} contains {@code all} and matchs none of the known architectures. - (<a href="http://code.google.com/p/android/issues/detail?id=35392">Issue 35392</a>) + (<a href="http://b.android.com/35392">Issue 35392</a>) </li> <li>Fixed Windows pathname support, by keeping the {@code :} character if it looks like it could be part of a Windows path starting with a drive letter. @@ -809,7 +1082,7 @@ Expected in: /usr/lib/libSystem.B.dylib</pre> </li> <li>Added fix to only read the current {@code solibs} when the linker is consistent. This change speeds up {@code solib} event handling. - (<a href="http://code.google.com/p/android/issues/detail?id=37677">Issue 37677</a>) + (<a href="http://b.android.com/37677">Issue 37677</a>) </li> <li>Added fix to make repeated attempts to find {@code solib} breakpoints. GDB now retries {@code enable_break()} during every call to {@code svr4_current_sos()} until @@ -817,13 +1090,13 @@ Expected in: /usr/lib/libSystem.B.dylib</pre> (<a href="https://android-review.googlesource.com/#/c/43563">Change 43563</a>)</li> <li>Fixed an issue where {@code gdb} would not stop on breakpoints placed in {@code dlopen-ed} libraries. - (<a href="http://code.google.com/p/android/issues/detail?id=34856">Issue 34856</a>) + (<a href="http://b.android.com/34856">Issue 34856</a>) </li> <li>Fixed {@code SIGILL} in dynamic linker when calling {@code dlopen()}, on system where {@code /system/bin/linker} is stripped of symbols and {@code rtld_db_dlactivity()} is implemented as {@code Thumb}, due to not preserving {@code LSB} of {@code sym_addr}. - (<a href="http://code.google.com/p/android/issues/detail?id=37147">Issue 37147</a>) + (<a href="http://b.android.com/37147">Issue 37147</a>) </li> </ul> </li> @@ -848,7 +1121,7 @@ Expected in: /usr/lib/libSystem.B.dylib</pre> {@code __END_DECLS}.</li> <li>Removed unimplemented functions in {@code malloc.h}.</li> <li>Fixed {@code stdint.h} defintion of {@code uint64_t} for ANSI compilers. - (<a href="http://code.google.com/p/android/issues/detail?id=1952">Issue 1952</a>)</li> + (<a href="http://b.android.com/1952">Issue 1952</a>)</li> <li>Fixed preprocessor macros in {@code <arch>/include/machine/*}.</li> <li>Replaced {@code link.h} for MIPS with new version supporting all platforms.</li> <li>Removed {@code linux-unistd.h}</li> @@ -904,7 +1177,7 @@ extern "C" { {@code platforms/android-[3,4,5,8]}. Those headers were incomplete, since both X86 and MIPS ABIs are only supported at API 9 or higher.</li> <li>Simplified c++ include path in standalone packages, as shown below. - (<a href="http://code.google.com/p/android/issues/detail?id=35279">Issue 35279</a>) + (<a href="http://b.android.com/35279">Issue 35279</a>) <pre> <path>/arm-linux-androideabi/include/c++/4.6.x-google to: @@ -916,7 +1189,7 @@ extern "C" { <li>Fixed an issue in {@code samples/san-angeles} that caused a black screen or freeze frame on re-launch.</li> <li>Replaced deprecated APIs in NDK samples. - (<a href="http://code.google.com/p/android/issues/detail?id=20017">Issue 20017</a>) + (<a href="http://b.android.com/20017">Issue 20017</a>) <ul> <li>{@code hello-gl2} from android-5 to android-7</li> <li>{@code native-activity} from android-9 to android-10</li> @@ -1196,7 +1469,7 @@ is compiled for the device's CPU architecture.</p> <li>Fixed a typo in GAbi++ implementation where the result of {@code dynamic_cast<D>(b)} of base class object {@code b} to derived class {@code D} is incorrectly adjusted in the opposite direction from the base class. - (<a href="http://code.google.com/p/android/issues/detail?id=28721">Issue 28721</a>) + (<a href="http://b.android.com/28721">Issue 28721</a>) </li> <li>Fixed an issue in which {@code make-standalone-toolchain.sh} fails to copy {@code libsupc++.*}.</li> @@ -1710,7 +1983,7 @@ LOCAL_CPP_EXTENSION := .cpp .cxx <li>Fixed the standalone toolchain linker warnings about missing the definition and size for the <code>__dso_handle</code> symbol (ARM only).</li> <li>Fixed the inclusion order of <code>$(SYSROOT)/usr/include</code> for x86 builds. - See the <a href="http://code.google.com/p/android/issues/detail?id=18540">bug</a> for + See the <a href="http://b.android.com/18540">bug</a> for more information.</li> <li>Fixed the definitions of <code>ptrdiff_t</code> and <code>size_t</code> in x86-specific systems when they are used with the x86 standalone toolchain.</li> diff --git a/docs/html/tools/sdk/tools-notes.jd b/docs/html/tools/sdk/tools-notes.jd index b58fdd1..cd2d986 100644 --- a/docs/html/tools/sdk/tools-notes.jd +++ b/docs/html/tools/sdk/tools-notes.jd @@ -29,6 +29,42 @@ 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 22.0.4</a> <em>(July 2013)</em> + </p> + + <div class="toggle-content-toggleme"> + + <dl> + <dt>Dependencies:</dt> + <dd> + <ul> + <li>Android SDK Platform-tools revision 16 or later.</li> + <li>If you are developing in Eclipse with the + <a href="{@docRoot}tools/sdk/eclipse-adt.html">ADT Plugin</a>, note that this version of + SDK Tools is designed for use with ADT 22.0.4 and later. If you haven't already, update + ADT to 22.0.4.</li> + <li>If you are using <a href="{@docRoot}sdk/installing/studio.html">Android Studio</a>, + note that this version of the SDK Tools is designed to work with Android Studio + 0.2.x and later.</li> + <li>If you are developing without an integrated development environment (IDE), you must have + <a href="http://ant.apache.org/">Apache Ant</a> 1.8 or later.</li> + </ul> + </dd> + + <dt>General Notes:</dt> + <dd> + <ul> + <li>Fixed problem with compiling Renderscript code.</li> + </ul> + </dd> + </dl> + </div> +</div> + + +<div class="toggle-content closed"> + <p><a href="#" onclick="return toggleContent(this)"> + <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img" alt=""/>SDK Tools, Revision 22.0.1</a> <em>(May 2013)</em> </p> diff --git a/docs/html/training/implementing-navigation/nav-drawer.jd b/docs/html/training/implementing-navigation/nav-drawer.jd index 527d570..38b7345 100644 --- a/docs/html/training/implementing-navigation/nav-drawer.jd +++ b/docs/html/training/implementing-navigation/nav-drawer.jd @@ -124,6 +124,7 @@ android.widget.ArrayAdapter} or {@link android.widget.SimpleCursorAdapter}).</p> <pre> public class MainActivity extends Activity { private String[] mPlanetTitles; + private DrawerLayout mDrawerLayout; private ListView mDrawerList; ... @@ -133,6 +134,7 @@ public class MainActivity extends Activity { setContentView(R.layout.activity_main); mPlanetTitles = getResources().getStringArray(R.array.planets_array); + mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout); mDrawerList = (ListView) findViewById(R.id.left_drawer); // Set the adapter for the list view @@ -191,9 +193,9 @@ private void selectItem(int position) { .commit(); // Highlight the selected item, update the title, and close the drawer - mDrawer.setItemChecked(position, true); + mDrawerList.setItemChecked(position, true); setTitle(mPlanetTitles[position]); - mDrawerLayout.closeDrawer(mDrawer); + mDrawerLayout.closeDrawer(mDrawerList); } @Override diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java index 50231da..ad5bfc8 100644 --- a/graphics/java/android/graphics/Bitmap.java +++ b/graphics/java/android/graphics/Bitmap.java @@ -170,7 +170,98 @@ public final class Bitmap implements Parcelable { public void setDensity(int density) { mDensity = density; } - + + /** + * <p>Modifies the bitmap to have a specified width, height, and {@link + * Config}, without affecting the underlying allocation backing the bitmap. + * Bitmap pixel data is not re-initialized for the new configuration.</p> + * + * <p>This method can be used to avoid allocating a new bitmap, instead + * reusing an existing bitmap's allocation for a new configuration of equal + * or lesser size. If the Bitmap's allocation isn't large enough to support + * the new configuration, an IllegalArgumentException will be thrown and the + * bitmap will not be modified.</p> + * + * <p>The result of {@link #getByteCount()} will reflect the new configuration, + * while {@link #getAllocationByteCount()} will reflect that of the initial + * configuration.</p> + * + * <p>WARNING: This method should NOT be called on a bitmap currently used + * by the view system. It does not make guarantees about how the underlying + * pixel buffer is remapped to the new config, just that the allocation is + * reused. Additionally, the view system does not account for bitmap + * properties being modifying during use, e.g. while attached to + * drawables.</p> + * + * @see #setWidth(int) + * @see #setHeight(int) + * @see #setConfig(Config) + */ + public void reconfigure(int width, int height, Config config) { + checkRecycled("Can't call reconfigure() on a recycled bitmap"); + if (width <= 0 || height <= 0) { + throw new IllegalArgumentException("width and height must be > 0"); + } + if (!isMutable()) { + throw new IllegalArgumentException("only mutable bitmaps may be reconfigured"); + } + if (mBuffer == null) { + throw new IllegalArgumentException("only non-inPurgeable bitmaps may be reconfigured"); + } + + nativeReconfigure(mNativeBitmap, width, height, config.nativeInt, mBuffer.length); + mWidth = width; + mHeight = height; + } + + /** + * <p>Convenience method for calling {@link #reconfigure(int, int, Config)} + * with the current height and config.</p> + * + * <p>WARNING: this method should not be used on bitmaps currently used by + * the view system, see {@link #reconfigure(int, int, Config)} for more + * details.</p> + * + * @see #reconfigure(int, int, Config) + * @see #setHeight(int) + * @see #setConfig(Config) + */ + public void setWidth(int width) { + reconfigure(width, getHeight(), getConfig()); + } + + /** + * <p>Convenience method for calling {@link #reconfigure(int, int, Config)} + * with the current width and config.</p> + * + * <p>WARNING: this method should not be used on bitmaps currently used by + * the view system, see {@link #reconfigure(int, int, Config)} for more + * details.</p> + * + * @see #reconfigure(int, int, Config) + * @see #setWidth(int) + * @see #setConfig(Config) + */ + public void setHeight(int height) { + reconfigure(getWidth(), height, getConfig()); + } + + /** + * <p>Convenience method for calling {@link #reconfigure(int, int, Config)} + * with the current height and width.</p> + * + * <p>WARNING: this method should not be used on bitmaps currently used by + * the view system, see {@link #reconfigure(int, int, Config)} for more + * details.</p> + * + * @see #reconfigure(int, int, Config) + * @see #setWidth(int) + * @see #setHeight(int) + */ + public void setConfig(Config config) { + reconfigure(getWidth(), getHeight(), config); + } + /** * Sets the nine patch chunk. * @@ -1010,7 +1101,7 @@ public final class Bitmap implements Parcelable { * * <p>As of {@link android.os.Build.VERSION_CODES#KEY_LIME_PIE}, the result of this method can * no longer be used to determine memory usage of a bitmap. See {@link - * #getAllocationByteCount()}. + * #getAllocationByteCount()}.</p> */ public final int getByteCount() { // int result permits bitmaps up to 46,340 x 46,340 @@ -1021,11 +1112,15 @@ public final class Bitmap implements Parcelable { * Returns the size of the allocated memory used to store this bitmap's pixels. * * <p>This can be larger than the result of {@link #getByteCount()} if a bitmap is reused to - * decode other bitmaps of smaller size. See {@link BitmapFactory.Options#inBitmap inBitmap in - * BitmapFactory.Options}. If a bitmap is not reused in this way, this value will be the same as - * that returned by {@link #getByteCount()}. + * decode other bitmaps of smaller size, or by manual reconfiguration. See {@link + * #reconfigure(int, int, Config)}, {@link #setWidth(int)}, {@link #setHeight(int)}, {@link + * #setConfig(Bitmap.Config)}, and {@link BitmapFactory.Options#inBitmap + * BitmapFactory.Options.inBitmap}. If a bitmap is not modified in this way, this value will be + * the same as that returned by {@link #getByteCount()}.</p> + * + * <p>This value will not change over the lifetime of a Bitmap.</p> * - * <p>This value will not change over the lifetime of a Bitmap. + * @see #reconfigure(int, int, Config) */ public final int getAllocationByteCount() { return mBuffer.length; @@ -1423,11 +1518,13 @@ public final class Bitmap implements Parcelable { private static native Bitmap nativeCreate(int[] colors, int offset, int stride, int width, int height, - int nativeConfig, boolean mutable); + int nativeConfig, boolean mutable); private static native Bitmap nativeCopy(int srcBitmap, int nativeConfig, boolean isMutable); private static native void nativeDestructor(int nativeBitmap); private static native boolean nativeRecycle(int nativeBitmap); + private static native void nativeReconfigure(int nativeBitmap, int width, int height, + int config, int allocSize); private static native boolean nativeCompress(int nativeBitmap, int format, int quality, OutputStream stream, diff --git a/graphics/java/android/graphics/BitmapFactory.java b/graphics/java/android/graphics/BitmapFactory.java index aff4cd8..a4124bf 100644 --- a/graphics/java/android/graphics/BitmapFactory.java +++ b/graphics/java/android/graphics/BitmapFactory.java @@ -48,34 +48,40 @@ public class BitmapFactory { /** * If set, decode methods that take the Options object will attempt to - * reuse this bitmap when loading content. If the decode operation cannot - * use this bitmap, the decode method will return <code>null</code> and - * will throw an IllegalArgumentException. The current implementation - * necessitates that the reused bitmap be mutable, and the resulting - * reused bitmap will continue to remain mutable even when decoding a - * resource which would normally result in an immutable bitmap. + * reuse this bitmap when loading content. If the decode operation + * cannot use this bitmap, the decode method will return + * <code>null</code> and will throw an IllegalArgumentException. The + * current implementation necessitates that the reused bitmap be + * mutable, and the resulting reused bitmap will continue to remain + * mutable even when decoding a resource which would normally result in + * an immutable bitmap.</p> * - * <p>As of {@link android.os.Build.VERSION_CODES#KEY_LIME_PIE}, any mutable - * bitmap can be reused to decode any other bitmaps as long as the resulting - * {@link Bitmap#getByteCount() byte count} of the decoded bitmap is less - * than or equal to the {@link Bitmap#getAllocationByteCount() allocated byte count} - * of the reused bitmap. This can be because the intrinsic size is smaller, - * or the size after density / sampled size scaling is smaller. + * <p>As of {@link android.os.Build.VERSION_CODES#KEY_LIME_PIE}, any + * mutable bitmap can be reused to decode any other bitmaps as long as + * the resulting {@link Bitmap#getByteCount() byte count} of the decoded + * bitmap is less than or equal to the {@link + * Bitmap#getAllocationByteCount() allocated byte count} of the reused + * bitmap. This can be because the intrinsic size is smaller, or its + * size post scaling (for density / sample size) is smaller.</p> * - * <p>Prior to {@link android.os.Build.VERSION_CODES#KEY_LIME_PIE} additional - * constraints apply: The image being decoded (whether as a resource or - * as a stream) must be in jpeg or png format. Only equal sized bitmaps - * are supported, with {@link #inSampleSize} set to 1. Additionally, the - * {@link android.graphics.Bitmap.Config configuration} of the reused - * bitmap will override the setting of {@link #inPreferredConfig}, if set. + * <p>Prior to {@link android.os.Build.VERSION_CODES#KEY_LIME_PIE} + * additional constraints apply: The image being decoded (whether as a + * resource or as a stream) must be in jpeg or png format. Only equal + * sized bitmaps are supported, with {@link #inSampleSize} set to 1. + * Additionally, the {@link android.graphics.Bitmap.Config + * configuration} of the reused bitmap will override the setting of + * {@link #inPreferredConfig}, if set.</p> * * <p>You should still always use the returned Bitmap of the decode * method and not assume that reusing the bitmap worked, due to the * constraints outlined above and failure situations that can occur. * Checking whether the return value matches the value of the inBitmap * set in the Options structure will indicate if the bitmap was reused, - * but in all cases you should use the Bitmap returned by the decoding function to ensure - * that you are using the bitmap that was used as the decode destination.</p> + * but in all cases you should use the Bitmap returned by the decoding + * function to ensure that you are using the bitmap that was used as the + * decode destination.</p> + * + * @see Bitmap#reconfigure(int,int,Config) */ public Bitmap inBitmap; diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java index 14ac901..fdec22b 100644 --- a/graphics/java/android/graphics/Canvas.java +++ b/graphics/java/android/graphics/Canvas.java @@ -513,12 +513,13 @@ public class Canvas { public native void skew(float sx, float sy); /** - * Preconcat the current matrix with the specified matrix. + * Preconcat the current matrix with the specified matrix. If the specified + * matrix is null, this method does nothing. * * @param matrix The matrix to preconcatenate with the current matrix */ public void concat(Matrix matrix) { - native_concat(mNativeCanvas, matrix.native_instance); + if (matrix != null) native_concat(mNativeCanvas, matrix.native_instance); } /** diff --git a/graphics/java/android/graphics/SurfaceTexture.java b/graphics/java/android/graphics/SurfaceTexture.java index af1a447..aaed094 100644 --- a/graphics/java/android/graphics/SurfaceTexture.java +++ b/graphics/java/android/graphics/SurfaceTexture.java @@ -95,21 +95,6 @@ public class SurfaceTexture { * @param texName the OpenGL texture object name (e.g. generated via glGenTextures) */ public SurfaceTexture(int texName) { - this(texName, false); - } - - /** - * Construct a new SurfaceTexture to stream images to a given OpenGL texture. - * - * @param texName the OpenGL texture object name (e.g. generated via glGenTextures) - * @param allowSynchronousMode whether the SurfaceTexture can run in the synchronous mode. - * When the image stream comes from OpenGL, SurfaceTexture may run in the synchronous - * mode where the producer side may be blocked to avoid skipping frames. To avoid the - * thread block, set allowSynchronousMode to false. - * - * @hide - */ - public SurfaceTexture(int texName, boolean allowSynchronousMode) { Looper looper; if ((looper = Looper.myLooper()) != null) { mEventHandler = new EventHandler(looper); @@ -118,7 +103,7 @@ public class SurfaceTexture { } else { mEventHandler = null; } - nativeInit(texName, new WeakReference<SurfaceTexture>(this), allowSynchronousMode); + nativeInit(texName, new WeakReference<SurfaceTexture>(this)); } /** @@ -299,7 +284,7 @@ public class SurfaceTexture { } } - private native void nativeInit(int texName, Object weakSelf, boolean allowSynchronousMode); + private native void nativeInit(int texName, Object weakSelf); private native void nativeFinalize(); private native void nativeGetTransformMatrix(float[] mtx); private native long nativeGetTimestamp(); diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp index 6de8c8c..6ac637e 100644 --- a/libs/hwui/Caches.cpp +++ b/libs/hwui/Caches.cpp @@ -495,6 +495,10 @@ void Caches::activeTexture(GLuint textureUnit) { } } +void Caches::resetActiveTexture() { + mTextureUnit = -1; +} + void Caches::bindTexture(GLuint texture) { if (mBoundTextures[mTextureUnit] != texture) { glBindTexture(GL_TEXTURE_2D, texture); diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h index b7a97ad..f8b1e17 100644 --- a/libs/hwui/Caches.h +++ b/libs/hwui/Caches.h @@ -226,6 +226,11 @@ public: void activeTexture(GLuint textureUnit); /** + * Invalidate the cached value of the active texture unit. + */ + void resetActiveTexture(); + + /** * Binds the specified texture as a GL_TEXTURE_2D texture. * All texture bindings must be performed with this method or * bindTexture(GLenum, GLuint). diff --git a/libs/hwui/DisplayListOp.h b/libs/hwui/DisplayListOp.h index 2b6f4cd..5ac2511 100644 --- a/libs/hwui/DisplayListOp.h +++ b/libs/hwui/DisplayListOp.h @@ -468,7 +468,11 @@ public: } virtual void output(int level, uint32_t logFlags) const { - OP_LOG("SetMatrix " MATRIX_STRING, MATRIX_ARGS(mMatrix)); + if (mMatrix) { + OP_LOG("SetMatrix " MATRIX_STRING, MATRIX_ARGS(mMatrix)); + } else { + OP_LOGS("SetMatrix (reset)"); + } } virtual const char* name() { return "SetMatrix"; } diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h index 03f50c8..d233150 100644 --- a/libs/hwui/DisplayListRenderer.h +++ b/libs/hwui/DisplayListRenderer.h @@ -269,11 +269,14 @@ private: } inline SkMatrix* refMatrix(SkMatrix* matrix) { - // Copying the matrix is cheap and prevents against the user changing the original - // matrix before the operation that uses it - SkMatrix* copy = new SkMatrix(*matrix); - mMatrices.add(copy); - return copy; + if (matrix) { + // Copying the matrix is cheap and prevents against the user changing + // the original matrix before the operation that uses it + SkMatrix* copy = new SkMatrix(*matrix); + mMatrices.add(copy); + return copy; + } + return matrix; } inline Layer* refLayer(Layer* layer) { diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp index 73082c1..bd371a3 100644 --- a/libs/hwui/Layer.cpp +++ b/libs/hwui/Layer.cpp @@ -31,7 +31,6 @@ namespace uirenderer { Layer::Layer(const uint32_t layerWidth, const uint32_t layerHeight): caches(Caches::getInstance()), texture(caches) { mesh = NULL; - meshIndices = NULL; meshElementCount = 0; cacheable = true; dirty = false; @@ -57,7 +56,6 @@ Layer::~Layer() { deleteTexture(); delete[] mesh; - delete[] meshIndices; delete deferredList; } diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h index ebd5543..b70042f 100644 --- a/libs/hwui/Layer.h +++ b/libs/hwui/Layer.h @@ -277,7 +277,6 @@ struct Layer { * If the layer can be rendered as a mesh, this is non-null. */ TextureVertex* mesh; - uint16_t* meshIndices; GLsizei meshElementCount; /** diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp index cfb1e97..f8076cc 100644 --- a/libs/hwui/LayerRenderer.cpp +++ b/libs/hwui/LayerRenderer.cpp @@ -130,10 +130,7 @@ void LayerRenderer::generateMesh() { if (mLayer->region.isRect() || mLayer->region.isEmpty()) { if (mLayer->mesh) { delete[] mLayer->mesh; - delete[] mLayer->meshIndices; - mLayer->mesh = NULL; - mLayer->meshIndices = NULL; mLayer->meshElementCount = 0; } @@ -154,17 +151,11 @@ void LayerRenderer::generateMesh() { if (mLayer->mesh && mLayer->meshElementCount < elementCount) { delete[] mLayer->mesh; - delete[] mLayer->meshIndices; - mLayer->mesh = NULL; - mLayer->meshIndices = NULL; } - bool rebuildIndices = false; if (!mLayer->mesh) { mLayer->mesh = new TextureVertex[count * 4]; - mLayer->meshIndices = new uint16_t[elementCount]; - rebuildIndices = true; } mLayer->meshElementCount = elementCount; @@ -173,7 +164,6 @@ void LayerRenderer::generateMesh() { const float height = mLayer->layer.getHeight(); TextureVertex* mesh = mLayer->mesh; - uint16_t* indices = mLayer->meshIndices; for (size_t i = 0; i < count; i++) { const android::Rect* r = &rects[i]; @@ -187,17 +177,6 @@ void LayerRenderer::generateMesh() { TextureVertex::set(mesh++, r->right, r->top, u2, v1); TextureVertex::set(mesh++, r->left, r->bottom, u1, v2); TextureVertex::set(mesh++, r->right, r->bottom, u2, v2); - - if (rebuildIndices) { - uint16_t quad = i * 4; - int index = i * 6; - indices[index ] = quad; // top-left - indices[index + 1] = quad + 1; // top-right - indices[index + 2] = quad + 2; // bottom-left - indices[index + 3] = quad + 2; // bottom-left - indices[index + 4] = quad + 1; // top-right - indices[index + 5] = quad + 3; // bottom-right - } } } diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index 7c0f3ad..bc00ce8 100644 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -107,6 +107,15 @@ static const Blender gBlendsSwap[] = { }; /////////////////////////////////////////////////////////////////////////////// +// Functions +/////////////////////////////////////////////////////////////////////////////// + +template<typename T> +static inline T min(T a, T b) { + return a < b ? a : b; +} + +/////////////////////////////////////////////////////////////////////////////// // Constructors/destructor /////////////////////////////////////////////////////////////////////////////// @@ -351,6 +360,7 @@ void OpenGLRenderer::interrupt() { mCaches.currentProgram = NULL; } } + mCaches.resetActiveTexture(); mCaches.unbindMeshBuffer(); mCaches.unbindIndicesBuffer(); mCaches.resetVertexPointers(); @@ -445,6 +455,7 @@ status_t OpenGLRenderer::callDrawGLFunction(Functor* functor, Rect& dirty) { mCaches.enableScissor(); if (mDirtyClip) { setScissorFromClip(); + setStencilFromClip(); } Rect clip(*mSnapshot->clipRect); @@ -1283,7 +1294,6 @@ void OpenGLRenderer::drawRegionRects(const Region& region) { void OpenGLRenderer::drawRegionRects(const SkRegion& region, int color, SkXfermode::Mode mode, bool dirty) { - int count = 0; Vector<float> rects; SkRegion::Iterator it(region); @@ -1293,11 +1303,10 @@ void OpenGLRenderer::drawRegionRects(const SkRegion& region, int color, rects.push(r.fTop); rects.push(r.fRight); rects.push(r.fBottom); - count += 4; it.next(); } - drawColorRects(rects.array(), count, color, mode, true, dirty, false); + drawColorRects(rects.array(), rects.size(), color, mode, true, dirty, false); } void OpenGLRenderer::dirtyLayer(const float left, const float top, @@ -1327,6 +1336,21 @@ void OpenGLRenderer::dirtyLayerUnchecked(Rect& bounds, Region* region) { } } +void OpenGLRenderer::drawIndexedQuads(Vertex* mesh, GLsizei quadsCount) { + GLsizei elementsCount = quadsCount * 6; + while (elementsCount > 0) { + GLsizei drawCount = min(elementsCount, (GLsizei) gMaxNumberOfQuads * 6); + + setupDrawIndexedVertices(&mesh[0].position[0]); + glDrawElements(GL_TRIANGLES, drawCount, GL_UNSIGNED_SHORT, NULL); + + elementsCount -= drawCount; + // Though there are 4 vertices in a quad, we use 6 indices per + // quad to draw with GL_TRIANGLES + mesh += (drawCount / 6) * 4; + } +} + void OpenGLRenderer::clearLayerRegions() { const size_t count = mLayers.size(); if (count == 0) return; @@ -1341,17 +1365,15 @@ void OpenGLRenderer::clearLayerRegions() { // is likely different so we need to disable clipping here bool scissorChanged = mCaches.disableScissor(); - Vertex mesh[count * 6]; + Vertex mesh[count * 4]; Vertex* vertex = mesh; for (uint32_t i = 0; i < count; i++) { Rect* bounds = mLayers.itemAt(i); - Vertex::set(vertex++, bounds->left, bounds->bottom); Vertex::set(vertex++, bounds->left, bounds->top); Vertex::set(vertex++, bounds->right, bounds->top); Vertex::set(vertex++, bounds->left, bounds->bottom); - Vertex::set(vertex++, bounds->right, bounds->top); Vertex::set(vertex++, bounds->right, bounds->bottom); delete bounds; @@ -1367,9 +1389,8 @@ void OpenGLRenderer::clearLayerRegions() { setupDrawProgram(); setupDrawPureColorUniforms(); setupDrawModelViewTranslate(0.0f, 0.0f, 0.0f, 0.0f, true); - setupDrawVertices(&mesh[0].position[0]); - glDrawArrays(GL_TRIANGLES, 0, count * 6); + drawIndexedQuads(&mesh[0], count); if (scissorChanged) mCaches.enableScissor(); } else { @@ -1975,10 +1996,10 @@ void OpenGLRenderer::setupDrawMeshIndices(GLvoid* vertices, GLvoid* texCoords, G } } -void OpenGLRenderer::setupDrawVertices(GLvoid* vertices) { +void OpenGLRenderer::setupDrawIndexedVertices(GLvoid* vertices) { bool force = mCaches.unbindMeshBuffer(); + mCaches.bindIndicesBuffer(); mCaches.bindPositionVertexPointer(force, vertices, gVertexStride); - mCaches.unbindIndicesBuffer(); } void OpenGLRenderer::finishDrawTexture() { @@ -3138,11 +3159,22 @@ status_t OpenGLRenderer::drawLayer(Layer* layer, float x, float y) { setupDrawModelViewTranslate(x, y, x + layer->layer.getWidth(), y + layer->layer.getHeight()); } - setupDrawMesh(&layer->mesh[0].position[0], &layer->mesh[0].texture[0]); - DRAW_DOUBLE_STENCIL_IF(!layer->hasDrawnSinceUpdate, - glDrawElements(GL_TRIANGLES, layer->meshElementCount, - GL_UNSIGNED_SHORT, layer->meshIndices)); + TextureVertex* mesh = &layer->mesh[0]; + GLsizei elementsCount = layer->meshElementCount; + + while (elementsCount > 0) { + GLsizei drawCount = min(elementsCount, (GLsizei) gMaxNumberOfQuads * 6); + + setupDrawMeshIndices(&mesh[0].position[0], &mesh[0].texture[0]); + DRAW_DOUBLE_STENCIL_IF(!layer->hasDrawnSinceUpdate, + glDrawElements(GL_TRIANGLES, drawCount, GL_UNSIGNED_SHORT, NULL)); + + elementsCount -= drawCount; + // Though there are 4 vertices in a quad, we use 6 indices per + // quad to draw with GL_TRIANGLES + mesh += (drawCount / 6) * 4; + } finishDrawTexture(); @@ -3360,8 +3392,7 @@ status_t OpenGLRenderer::drawColorRects(const float* rects, int count, int color float right = FLT_MIN; float bottom = FLT_MIN; - int vertexCount = 0; - Vertex mesh[count * 6]; + Vertex mesh[count]; Vertex* vertex = mesh; for (int index = 0; index < count; index += 4) { @@ -3370,15 +3401,11 @@ status_t OpenGLRenderer::drawColorRects(const float* rects, int count, int color float r = rects[index + 2]; float b = rects[index + 3]; - Vertex::set(vertex++, l, b); Vertex::set(vertex++, l, t); Vertex::set(vertex++, r, t); Vertex::set(vertex++, l, b); - Vertex::set(vertex++, r, t); Vertex::set(vertex++, r, b); - vertexCount += 6; - left = fminf(left, l); top = fminf(top, t); right = fmaxf(right, r); @@ -3401,13 +3428,12 @@ status_t OpenGLRenderer::drawColorRects(const float* rects, int count, int color setupDrawColorUniforms(); setupDrawShaderUniforms(); setupDrawColorFilterUniforms(); - setupDrawVertices((GLvoid*) &mesh[0].position[0]); if (dirty && hasLayer()) { dirtyLayer(left, top, right, bottom, currentTransform()); } - glDrawArrays(GL_TRIANGLES, 0, vertexCount); + drawIndexedQuads(&mesh[0], count / 4); return DrawGlInfo::kStatusDrew; } diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h index 5e731b4..eb42540 100644 --- a/libs/hwui/OpenGLRenderer.h +++ b/libs/hwui/OpenGLRenderer.h @@ -850,6 +850,13 @@ private: bool ignoreTransform, bool ignoreScale = false, bool dirty = true); /** + * Draws the specified list of vertices as quads using indexed GL_TRIANGLES. + * If the number of vertices to draw exceeds the number of indices we have + * pre-allocated, this method will generate several glDrawElements() calls. + */ + void drawIndexedQuads(Vertex* mesh, GLsizei quadsCount); + + /** * Draws text underline and strike-through if needed. * * @param text The text to decor @@ -988,7 +995,7 @@ private: void setupDrawMesh(GLvoid* vertices, GLvoid* texCoords = NULL, GLuint vbo = 0); void setupDrawMesh(GLvoid* vertices, GLvoid* texCoords, GLvoid* colors); void setupDrawMeshIndices(GLvoid* vertices, GLvoid* texCoords, GLuint vbo = 0); - void setupDrawVertices(GLvoid* vertices); + void setupDrawIndexedVertices(GLvoid* vertices); void finishDrawTexture(); void accountForClear(SkXfermode::Mode mode); diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java index 3144e8a..bcd0398 100644 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -1659,10 +1659,16 @@ public class AudioManager { * @see #playSoundEffect(int) */ public static final int FX_KEYPRESS_RETURN = 8; + + /** + * Invalid keypress sound + * @see #playSoundEffect(int) + */ + public static final int FX_KEYPRESS_INVALID = 9; /** * @hide Number of sound effects */ - public static final int NUM_SOUND_EFFECTS = 9; + public static final int NUM_SOUND_EFFECTS = 10; /** * Plays a sound effect (Key clicks, lid open/close...) @@ -1676,6 +1682,7 @@ public class AudioManager { * {@link #FX_KEYPRESS_SPACEBAR}, * {@link #FX_KEYPRESS_DELETE}, * {@link #FX_KEYPRESS_RETURN}, + * {@link #FX_KEYPRESS_INVALID}, * NOTE: This version uses the UI settings to determine * whether sounds are heard or not. */ @@ -1708,6 +1715,7 @@ public class AudioManager { * {@link #FX_KEYPRESS_SPACEBAR}, * {@link #FX_KEYPRESS_DELETE}, * {@link #FX_KEYPRESS_RETURN}, + * {@link #FX_KEYPRESS_INVALID}, * @param volume Sound effect volume. * The volume value is a raw scalar so UI controls should be scaled logarithmically. * If a volume of -1 is specified, the AudioManager.STREAM_MUSIC stream volume minus 3dB will be used. @@ -1988,7 +1996,7 @@ public class AudioManager { IAudioService service = getService(); try { service.requestAudioFocus(streamType, durationHint, mICallBack, null, - AudioService.IN_VOICE_COMM_FOCUS_ID, + MediaFocusControl.IN_VOICE_COMM_FOCUS_ID, mContext.getBasePackageName()); } catch (RemoteException e) { Log.e(TAG, "Can't call requestAudioFocusForCall() on AudioService due to "+e); @@ -2004,7 +2012,7 @@ public class AudioManager { public void abandonAudioFocusForCall() { IAudioService service = getService(); try { - service.abandonAudioFocus(null, AudioService.IN_VOICE_COMM_FOCUS_ID); + service.abandonAudioFocus(null, MediaFocusControl.IN_VOICE_COMM_FOCUS_ID); } catch (RemoteException e) { Log.e(TAG, "Can't call abandonAudioFocusForCall() on AudioService due to "+e); } diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java index 5383d08..1e46f0a 100644 --- a/media/java/android/media/AudioRecord.java +++ b/media/java/android/media/AudioRecord.java @@ -99,7 +99,7 @@ public class AudioRecord */ private static final int NATIVE_EVENT_NEW_POS = 3; - private final static String TAG = "AudioRecord-Java"; + private final static String TAG = "android.media.AudioRecord"; //--------------------------------------------------------- @@ -421,7 +421,9 @@ public class AudioRecord * @see AudioRecord#RECORDSTATE_RECORDING */ public int getRecordingState() { - return mRecordingState; + synchronized (mRecordingStateLock) { + return mRecordingState; + } } /** @@ -474,21 +476,21 @@ public class AudioRecord case AudioFormat.CHANNEL_INVALID: default: loge("getMinBufferSize(): Invalid channel configuration."); - return AudioRecord.ERROR_BAD_VALUE; + return ERROR_BAD_VALUE; } // PCM_8BIT is not supported at the moment if (audioFormat != AudioFormat.ENCODING_PCM_16BIT) { loge("getMinBufferSize(): Invalid audio format."); - return AudioRecord.ERROR_BAD_VALUE; + return ERROR_BAD_VALUE; } int size = native_get_min_buff_size(sampleRateInHz, channelCount, audioFormat); if (size == 0) { - return AudioRecord.ERROR_BAD_VALUE; + return ERROR_BAD_VALUE; } else if (size == -1) { - return AudioRecord.ERROR; + return ERROR; } else { return size; @@ -585,6 +587,7 @@ public class AudioRecord } if ( (audioData == null) || (offsetInBytes < 0 ) || (sizeInBytes < 0) + || (offsetInBytes + sizeInBytes < 0) // detect integer overflow || (offsetInBytes + sizeInBytes > audioData.length)) { return ERROR_BAD_VALUE; } @@ -609,6 +612,7 @@ public class AudioRecord } if ( (audioData == null) || (offsetInShorts < 0 ) || (sizeInShorts < 0) + || (offsetInShorts + sizeInShorts < 0) // detect integer overflow || (offsetInShorts + sizeInShorts > audioData.length)) { return ERROR_BAD_VALUE; } @@ -692,6 +696,9 @@ public class AudioRecord * {@link #ERROR_INVALID_OPERATION} */ public int setNotificationMarkerPosition(int markerInFrames) { + if (mState == STATE_UNINITIALIZED) { + return ERROR_INVALID_OPERATION; + } return native_set_marker_pos(markerInFrames); } @@ -704,6 +711,9 @@ public class AudioRecord * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_INVALID_OPERATION} */ public int setPositionNotificationPeriod(int periodInFrames) { + if (mState == STATE_UNINITIALIZED) { + return ERROR_INVALID_OPERATION; + } return native_set_pos_update_period(periodInFrames); } @@ -769,9 +779,8 @@ public class AudioRecord } break; default: - Log.e(TAG, "[ android.media.AudioRecord.NativeEventHandler ] " + - "Unknown event type: " + msg.what); - break; + loge("Unknown native event type: " + msg.what); + break; } } }; @@ -837,11 +846,11 @@ public class AudioRecord //------------------ private static void logd(String msg) { - Log.d(TAG, "[ android.media.AudioRecord ] " + msg); + Log.d(TAG, msg); } private static void loge(String msg) { - Log.e(TAG, "[ android.media.AudioRecord ] " + msg); + Log.e(TAG, msg); } } diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java index 9e13ca4..c178ae4 100644 --- a/media/java/android/media/AudioService.java +++ b/media/java/android/media/AudioService.java @@ -22,12 +22,12 @@ import static android.media.AudioManager.RINGER_MODE_SILENT; import static android.media.AudioManager.RINGER_MODE_VIBRATE; import android.app.Activity; +import android.app.ActivityManager; import android.app.ActivityManagerNative; import android.app.AppOpsManager; import android.app.KeyguardManager; import android.app.PendingIntent; import android.app.PendingIntent.CanceledException; -import android.app.PendingIntent.OnFinished; import android.bluetooth.BluetoothA2dp; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothClass; @@ -106,7 +106,7 @@ import java.util.Stack; * * @hide */ -public class AudioService extends IAudioService.Stub implements OnFinished { +public class AudioService extends IAudioService.Stub { private static final String TAG = "AudioService"; @@ -145,34 +145,25 @@ public class AudioService extends IAudioService.Stub implements OnFinished { private static final int MSG_BTA2DP_DOCK_TIMEOUT = 7; private static final int MSG_LOAD_SOUND_EFFECTS = 8; private static final int MSG_SET_FORCE_USE = 9; - private static final int MSG_PERSIST_MEDIABUTTONRECEIVER = 10; - private static final int MSG_BT_HEADSET_CNCT_FAILED = 11; - private static final int MSG_RCDISPLAY_CLEAR = 12; - private static final int MSG_RCDISPLAY_UPDATE = 13; - private static final int MSG_SET_ALL_VOLUMES = 14; - private static final int MSG_PERSIST_MASTER_VOLUME_MUTE = 15; - private static final int MSG_REPORT_NEW_ROUTES = 16; - private static final int MSG_REEVALUATE_REMOTE = 17; - private static final int MSG_RCC_NEW_PLAYBACK_INFO = 18; - private static final int MSG_RCC_NEW_VOLUME_OBS = 19; - private static final int MSG_SET_FORCE_BT_A2DP_USE = 20; + private static final int MSG_BT_HEADSET_CNCT_FAILED = 10; + private static final int MSG_SET_ALL_VOLUMES = 11; + private static final int MSG_PERSIST_MASTER_VOLUME_MUTE = 12; + private static final int MSG_REPORT_NEW_ROUTES = 13; + private static final int MSG_SET_FORCE_BT_A2DP_USE = 14; + private static final int MSG_SET_RSX_CONNECTION_STATE = 15; // change remote submix connection + private static final int MSG_CHECK_MUSIC_ACTIVE = 16; + private static final int MSG_BROADCAST_AUDIO_BECOMING_NOISY = 17; + private static final int MSG_CONFIGURE_SAFE_MEDIA_VOLUME = 18; + private static final int MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED = 19; + private static final int MSG_PERSIST_SAFE_VOLUME_STATE = 20; + private static final int MSG_BROADCAST_BT_CONNECTION_STATE = 21; + private static final int MSG_UNLOAD_SOUND_EFFECTS = 22; // start of messages handled under wakelock // these messages can only be queued, i.e. sent with queueMsgUnderWakeLock(), // and not with sendMsg(..., ..., SENDMSG_QUEUE, ...) - private static final int MSG_SET_WIRED_DEVICE_CONNECTION_STATE = 21; - private static final int MSG_SET_A2DP_CONNECTION_STATE = 22; + private static final int MSG_SET_WIRED_DEVICE_CONNECTION_STATE = 100; + private static final int MSG_SET_A2DP_CONNECTION_STATE = 101; // end of messages handled under wakelock - private static final int MSG_SET_RSX_CONNECTION_STATE = 23; // change remote submix connection - private static final int MSG_CHECK_MUSIC_ACTIVE = 24; - private static final int MSG_BROADCAST_AUDIO_BECOMING_NOISY = 25; - private static final int MSG_CONFIGURE_SAFE_MEDIA_VOLUME = 26; - private static final int MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED = 27; - private static final int MSG_PERSIST_SAFE_VOLUME_STATE = 28; - private static final int MSG_PROMOTE_RCC = 29; - private static final int MSG_BROADCAST_BT_CONNECTION_STATE = 30; - private static final int MSG_UNLOAD_SOUND_EFFECTS = 31; - private static final int MSG_RCC_NEW_PLAYBACK_STATE = 32; - private static final int MSG_RCC_SEEK_REQUEST = 33; private static final int BTA2DP_DOCK_TIMEOUT_MILLIS = 8000; // Timeout for connection to bluetooth headset service @@ -186,7 +177,7 @@ public class AudioService extends IAudioService.Stub implements OnFinished { private VolumeStreamState[] mStreamStates; private SettingsObserver mSettingsObserver; - private int mMode; + private int mMode = AudioSystem.MODE_NORMAL; // protects mRingerMode private final Object mSettingsLock = new Object(); @@ -213,7 +204,7 @@ public class AudioService extends IAudioService.Stub implements OnFinished { private final int[][] SOUND_EFFECT_FILES_MAP = new int[AudioManager.NUM_SOUND_EFFECTS][2]; /** @hide Maximum volume index values for audio streams */ - private final int[] MAX_STREAM_VOLUME = new int[] { + private static final int[] MAX_STREAM_VOLUME = new int[] { 5, // STREAM_VOICE_CALL 7, // STREAM_SYSTEM 7, // STREAM_RING @@ -345,9 +336,6 @@ public class AudioService extends IAudioService.Stub implements OnFinished { // Broadcast receiver for device connections intent broadcasts private final BroadcastReceiver mReceiver = new AudioServiceBroadcastReceiver(); - // Used to alter media button redirection when the phone is ringing. - private boolean mIsRinging = false; - // Devices currently connected private final HashMap <Integer, String> mConnectedDevices = new HashMap <Integer, String>(); @@ -468,6 +456,10 @@ public class AudioService extends IAudioService.Stub implements OnFinished { // and used later when/if disableSafeMediaVolume() is called. private StreamVolumeCommand mPendingVolumeCommand; + private PowerManager.WakeLock mAudioEventWakeLock; + + private final MediaFocusControl mMediaFocusControl; + /////////////////////////////////////////////////////////////////////////// // Construction /////////////////////////////////////////////////////////////////////////// @@ -481,7 +473,7 @@ public class AudioService extends IAudioService.Stub implements OnFinished { com.android.internal.R.bool.config_voice_capable); PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE); - mMediaEventWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "handleMediaEvent"); + mAudioEventWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "handleAudioEvent"); Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE); mHasVibrator = vibrator == null ? false : vibrator.hasVibrator(); @@ -495,11 +487,13 @@ public class AudioService extends IAudioService.Stub implements OnFinished { com.android.internal.R.integer.config_soundEffectVolumeDb); mVolumePanel = new VolumePanel(context, this); - mMode = AudioSystem.MODE_NORMAL; mForcedUseForComm = AudioSystem.FORCE_NONE; createAudioSystemThread(); + mMediaFocusControl = new MediaFocusControl(mAudioHandler.getLooper(), + mContext, /*VolumeController*/ mVolumePanel, this); + boolean cameraSoundForced = mContext.getResources().getBoolean( com.android.internal.R.bool.config_camera_sound_forced); mCameraSoundForced = new Boolean(cameraSoundForced); @@ -528,6 +522,7 @@ public class AudioService extends IAudioService.Stub implements OnFinished { updateStreamVolumeAlias(false /*updateVolumes*/); createStreamStates(); + readAndSetLowRamDevice(); mMediaServerOk = true; // Call setRingerModeInt() to apply correct mute @@ -568,20 +563,6 @@ public class AudioService extends IAudioService.Stub implements OnFinished { context.registerReceiver(mReceiver, intentFilter); - // Register for package removal intent broadcasts for media button receiver persistence - IntentFilter pkgFilter = new IntentFilter(); - pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); - pkgFilter.addAction(Intent.ACTION_PACKAGE_ADDED); - pkgFilter.addAction(Intent.ACTION_PACKAGE_CHANGED); - pkgFilter.addAction(Intent.ACTION_PACKAGE_DATA_CLEARED); - pkgFilter.addDataScheme("package"); - context.registerReceiver(mReceiver, pkgFilter); - - // Register for phone state monitoring - TelephonyManager tmgr = (TelephonyManager) - context.getSystemService(Context.TELEPHONY_SERVICE); - tmgr.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE); - mUseMasterVolume = context.getResources().getBoolean( com.android.internal.R.bool.config_useMasterVolume); restoreMasterVolume(); @@ -589,11 +570,6 @@ public class AudioService extends IAudioService.Stub implements OnFinished { mMasterVolumeRamp = context.getResources().getIntArray( com.android.internal.R.array.config_masterVolumeRamp); - mMainRemote = new RemotePlaybackState(-1, MAX_STREAM_VOLUME[AudioManager.STREAM_MUSIC], - MAX_STREAM_VOLUME[AudioManager.STREAM_MUSIC]); - mHasRemotePlayback = false; - mMainRemoteIsActive = false; - postReevaluateRemote(); } private void createAudioSystemThread() { @@ -795,7 +771,7 @@ public class AudioService extends IAudioService.Stub implements OnFinished { broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_NOTIFICATION); // Restore the default media button receiver from the system settings - restoreMediaButtonReceiver(); + mMediaFocusControl.restoreMediaButtonReceiver(); } private int rescaleIndex(int index, int srcStream, int dstStream) { @@ -817,8 +793,8 @@ public class AudioService extends IAudioService.Stub implements OnFinished { public void adjustLocalOrRemoteStreamVolume(int streamType, int direction, String callingPackage) { if (DEBUG_VOL) Log.d(TAG, "adjustLocalOrRemoteStreamVolume(dir="+direction+")"); - if (checkUpdateRemoteStateIfActive(AudioSystem.STREAM_MUSIC)) { - adjustRemoteVolume(AudioSystem.STREAM_MUSIC, direction, 0); + if (mMediaFocusControl.checkUpdateRemoteStateIfActive(AudioSystem.STREAM_MUSIC)) { + mMediaFocusControl.adjustRemoteVolume(AudioSystem.STREAM_MUSIC, direction, 0); } else if (AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0)) { adjustStreamVolume(AudioSystem.STREAM_MUSIC, direction, 0, callingPackage); } @@ -847,7 +823,7 @@ public class AudioService extends IAudioService.Stub implements OnFinished { // don't play sounds for remote flags &= ~(AudioManager.FLAG_PLAY_SOUND|AudioManager.FLAG_FIXED_VOLUME); //if (DEBUG_VOL) Log.i(TAG, "Need to adjust remote volume: calling adjustRemoteVolume()"); - adjustRemoteVolume(AudioSystem.STREAM_MUSIC, direction, flags); + mMediaFocusControl.adjustRemoteVolume(AudioSystem.STREAM_MUSIC, direction, flags); } else { adjustStreamVolume(streamType, direction, flags, callingPackage); } @@ -1274,6 +1250,10 @@ public class AudioService extends IAudioService.Stub implements OnFinished { return AudioSystem.getMasterMute(); } + protected static int getMaxStreamVolume(int streamType) { + return MAX_STREAM_VOLUME[streamType]; + } + /** @see AudioManager#getStreamVolume(int) */ public int getStreamVolume(int streamType) { ensureValidStreamType(streamType); @@ -2597,7 +2577,7 @@ public class AudioService extends IAudioService.Stub implements OnFinished { } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) { // Having the suggested stream be USE_DEFAULT_STREAM_TYPE is how remote control // volume can have priority over STREAM_MUSIC - if (checkUpdateRemoteStateIfActive(AudioSystem.STREAM_MUSIC)) { + if (mMediaFocusControl.checkUpdateRemoteStateIfActive(AudioSystem.STREAM_MUSIC)) { if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_REMOTE_MUSIC"); return STREAM_REMOTE_MUSIC; @@ -2637,7 +2617,7 @@ public class AudioService extends IAudioService.Stub implements OnFinished { if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_NOTIFICATION"); return AudioSystem.STREAM_NOTIFICATION; } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) { - if (checkUpdateRemoteStateIfActive(AudioSystem.STREAM_MUSIC)) { + if (mMediaFocusControl.checkUpdateRemoteStateIfActive(AudioSystem.STREAM_MUSIC)) { // Having the suggested stream be USE_DEFAULT_STREAM_TYPE is how remote control // volume can have priority over STREAM_MUSIC if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_REMOTE_MUSIC"); @@ -2681,7 +2661,7 @@ public class AudioService extends IAudioService.Stub implements OnFinished { */ private void queueMsgUnderWakeLock(Handler handler, int msg, int arg1, int arg2, Object obj, int delay) { - mMediaEventWakeLock.acquire(); + mAudioEventWakeLock.acquire(); sendMsg(handler, msg, SENDMSG_QUEUE, arg1, arg2, obj, delay); } @@ -3379,13 +3359,6 @@ public class AudioService extends IAudioService.Stub implements OnFinished { } } - private void onHandlePersistMediaButtonReceiver(ComponentName receiver) { - Settings.System.putStringForUser(mContentResolver, - Settings.System.MEDIA_BUTTON_RECEIVER, - receiver == null ? "" : receiver.flattenToString(), - UserHandle.USER_CURRENT); - } - private void cleanupPlayer(MediaPlayer mp) { if (mp != null) { try { @@ -3469,6 +3442,8 @@ public class AudioService extends IAudioService.Stub implements OnFinished { // process restarts after a crash, not the first time it is started. AudioSystem.setParameters("restarting=true"); + readAndSetLowRamDevice(); + // Restore device connection states synchronized (mConnectedDevices) { Set set = mConnectedDevices.entrySet(); @@ -3562,31 +3537,18 @@ public class AudioService extends IAudioService.Stub implements OnFinished { setForceUse(msg.arg1, msg.arg2); break; - case MSG_PERSIST_MEDIABUTTONRECEIVER: - onHandlePersistMediaButtonReceiver( (ComponentName) msg.obj ); - break; - - case MSG_RCDISPLAY_CLEAR: - onRcDisplayClear(); - break; - - case MSG_RCDISPLAY_UPDATE: - // msg.obj is guaranteed to be non null - onRcDisplayUpdate( (RemoteControlStackEntry) msg.obj, msg.arg1); - break; - case MSG_BT_HEADSET_CNCT_FAILED: resetBluetoothSco(); break; case MSG_SET_WIRED_DEVICE_CONNECTION_STATE: onSetWiredDeviceConnectionState(msg.arg1, msg.arg2, (String)msg.obj); - mMediaEventWakeLock.release(); + mAudioEventWakeLock.release(); break; case MSG_SET_A2DP_CONNECTION_STATE: onSetA2dpConnectionState((BluetoothDevice)msg.obj, msg.arg1); - mMediaEventWakeLock.release(); + mAudioEventWakeLock.release(); break; case MSG_REPORT_NEW_ROUTES: { @@ -3609,26 +3571,6 @@ public class AudioService extends IAudioService.Stub implements OnFinished { break; } - case MSG_REEVALUATE_REMOTE: - onReevaluateRemote(); - break; - - case MSG_RCC_NEW_PLAYBACK_INFO: - onNewPlaybackInfoForRcc(msg.arg1 /* rccId */, msg.arg2 /* key */, - ((Integer)msg.obj).intValue() /* value */); - break; - case MSG_RCC_NEW_VOLUME_OBS: - onRegisterVolumeObserverForRcc(msg.arg1 /* rccId */, - (IRemoteVolumeObserver)msg.obj /* rvo */); - break; - case MSG_RCC_NEW_PLAYBACK_STATE: - onNewPlaybackStateForRcc(msg.arg1 /* rccId */, msg.arg2 /* state */, - (RccPlaybackState)msg.obj /* newState */); - break; - case MSG_RCC_SEEK_REQUEST: - onSetRemoteControlClientPlaybackPosition(msg.arg1 /* generationId */, - ((Long)msg.obj).longValue() /* timeMs */); - case MSG_SET_RSX_CONNECTION_STATE: onSetRsxConnectionState(msg.arg1/*available*/, msg.arg2/*address*/); break; @@ -3649,10 +3591,6 @@ public class AudioService extends IAudioService.Stub implements OnFinished { onPersistSafeVolumeState(msg.arg1); break; - case MSG_PROMOTE_RCC: - onPromoteRcc(msg.arg1); - break; - case MSG_BROADCAST_BT_CONNECTION_STATE: onBroadcastScoConnectionState(msg.arg1); break; @@ -4130,21 +4068,6 @@ public class AudioService extends IAudioService.Stub implements OnFinished { 0, null, SAFE_VOLUME_CONFIGURE_TIMEOUT_MS); - } else if (action.equals(Intent.ACTION_PACKAGE_REMOVED) - || action.equals(Intent.ACTION_PACKAGE_DATA_CLEARED)) { - if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) { - // a package is being removed, not replaced - String packageName = intent.getData().getSchemeSpecificPart(); - if (packageName != null) { - cleanupMediaButtonReceiverForPackage(packageName, true); - } - } - } else if (action.equals(Intent.ACTION_PACKAGE_ADDED) - || action.equals(Intent.ACTION_PACKAGE_CHANGED)) { - String packageName = intent.getData().getSchemeSpecificPart(); - if (packageName != null) { - cleanupMediaButtonReceiverForPackage(packageName, false); - } } else if (action.equals(Intent.ACTION_SCREEN_ON)) { AudioSystem.setParameters("screen_state=on"); } else if (action.equals(Intent.ACTION_SCREEN_OFF)) { @@ -4161,7 +4084,7 @@ public class AudioService extends IAudioService.Stub implements OnFinished { null, 0); // the current audio focus owner is no longer valid - discardAudioFocusOwner(); + mMediaFocusControl.discardAudioFocusOwner(); // load volume settings for new user readAudioSettings(true /*userSwitch*/); @@ -4177,2213 +4100,102 @@ public class AudioService extends IAudioService.Stub implements OnFinished { } //========================================================================================== - // AudioFocus - //========================================================================================== - - /* constant to identify focus stack entry that is used to hold the focus while the phone - * is ringing or during a call. Used by com.android.internal.telephony.CallManager when - * entering and exiting calls. - */ - public final static String IN_VOICE_COMM_FOCUS_ID = "AudioFocus_For_Phone_Ring_And_Calls"; - - private final static Object mAudioFocusLock = new Object(); - - private final static Object mRingingLock = new Object(); - - private PhoneStateListener mPhoneStateListener = new PhoneStateListener() { - @Override - public void onCallStateChanged(int state, String incomingNumber) { - if (state == TelephonyManager.CALL_STATE_RINGING) { - //Log.v(TAG, " CALL_STATE_RINGING"); - synchronized(mRingingLock) { - mIsRinging = true; - } - } else if ((state == TelephonyManager.CALL_STATE_OFFHOOK) - || (state == TelephonyManager.CALL_STATE_IDLE)) { - synchronized(mRingingLock) { - mIsRinging = false; - } - } - } - }; - - /** - * Discard the current audio focus owner. - * Notify top of audio focus stack that it lost focus (regardless of possibility to reassign - * focus), remove it from the stack, and clear the remote control display. - */ - private void discardAudioFocusOwner() { - synchronized(mAudioFocusLock) { - if (!mFocusStack.empty() && (mFocusStack.peek().mFocusDispatcher != null)) { - // notify the current focus owner it lost focus after removing it from stack - FocusStackEntry focusOwner = mFocusStack.pop(); - try { - focusOwner.mFocusDispatcher.dispatchAudioFocusChange( - AudioManager.AUDIOFOCUS_LOSS, focusOwner.mClientId); - } catch (RemoteException e) { - Log.e(TAG, "Failure to signal loss of audio focus due to "+ e); - e.printStackTrace(); - } - focusOwner.unlinkToDeath(); - // clear RCD - synchronized(mRCStack) { - clearRemoteControlDisplay_syncAfRcs(); - } - } - } - } - - private void notifyTopOfAudioFocusStack() { - // notify the top of the stack it gained focus - if (!mFocusStack.empty() && (mFocusStack.peek().mFocusDispatcher != null)) { - if (canReassignAudioFocus()) { - try { - mFocusStack.peek().mFocusDispatcher.dispatchAudioFocusChange( - AudioManager.AUDIOFOCUS_GAIN, mFocusStack.peek().mClientId); - } catch (RemoteException e) { - Log.e(TAG, "Failure to signal gain of audio control focus due to "+ e); - e.printStackTrace(); - } - } - } - } - - private static class FocusStackEntry { - public int mStreamType = -1;// no stream type - public IAudioFocusDispatcher mFocusDispatcher = null; - public IBinder mSourceRef = null; - public String mClientId; - public int mFocusChangeType; - public AudioFocusDeathHandler mHandler; - public String mPackageName; - public int mCallingUid; - - public FocusStackEntry() { - } - - public FocusStackEntry(int streamType, int duration, - IAudioFocusDispatcher afl, IBinder source, String id, AudioFocusDeathHandler hdlr, - String pn, int uid) { - mStreamType = streamType; - mFocusDispatcher = afl; - mSourceRef = source; - mClientId = id; - mFocusChangeType = duration; - mHandler = hdlr; - mPackageName = pn; - mCallingUid = uid; - } - - public void unlinkToDeath() { - try { - if (mSourceRef != null && mHandler != null) { - mSourceRef.unlinkToDeath(mHandler, 0); - mHandler = null; - } - } catch (java.util.NoSuchElementException e) { - Log.e(TAG, "Encountered " + e + " in FocusStackEntry.unlinkToDeath()"); - } - } - - @Override - protected void finalize() throws Throwable { - unlinkToDeath(); // unlink exception handled inside method - super.finalize(); - } - } - - private final Stack<FocusStackEntry> mFocusStack = new Stack<FocusStackEntry>(); - - /** - * Helper function: - * Display in the log the current entries in the audio focus stack - */ - private void dumpFocusStack(PrintWriter pw) { - pw.println("\nAudio Focus stack entries (last is top of stack):"); - synchronized(mAudioFocusLock) { - Iterator<FocusStackEntry> stackIterator = mFocusStack.iterator(); - while(stackIterator.hasNext()) { - FocusStackEntry fse = stackIterator.next(); - pw.println(" source:" + fse.mSourceRef - + " -- pack: " + fse.mPackageName - + " -- client: " + fse.mClientId - + " -- duration: " + fse.mFocusChangeType - + " -- uid: " + fse.mCallingUid - + " -- stream: " + fse.mStreamType); - } - } - } - - /** - * Helper function: - * Called synchronized on mAudioFocusLock - * Remove a focus listener from the focus stack. - * @param clientToRemove the focus listener - * @param signal if true and the listener was at the top of the focus stack, i.e. it was holding - * focus, notify the next item in the stack it gained focus. - */ - private void removeFocusStackEntry(String clientToRemove, boolean signal) { - // is the current top of the focus stack abandoning focus? (because of request, not death) - if (!mFocusStack.empty() && mFocusStack.peek().mClientId.equals(clientToRemove)) - { - //Log.i(TAG, " removeFocusStackEntry() removing top of stack"); - FocusStackEntry fse = mFocusStack.pop(); - fse.unlinkToDeath(); - if (signal) { - // notify the new top of the stack it gained focus - notifyTopOfAudioFocusStack(); - // there's a new top of the stack, let the remote control know - synchronized(mRCStack) { - checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL); - } - } - } else { - // focus is abandoned by a client that's not at the top of the stack, - // no need to update focus. - // (using an iterator on the stack so we can safely remove an entry after having - // evaluated it, traversal order doesn't matter here) - Iterator<FocusStackEntry> stackIterator = mFocusStack.iterator(); - while(stackIterator.hasNext()) { - FocusStackEntry fse = (FocusStackEntry)stackIterator.next(); - if(fse.mClientId.equals(clientToRemove)) { - Log.i(TAG, " AudioFocus abandonAudioFocus(): removing entry for " - + fse.mClientId); - stackIterator.remove(); - fse.unlinkToDeath(); - } - } - } - } - - /** - * Helper function: - * Called synchronized on mAudioFocusLock - * Remove focus listeners from the focus stack for a particular client when it has died. - */ - private void removeFocusStackEntryForClient(IBinder cb) { - // is the owner of the audio focus part of the client to remove? - boolean isTopOfStackForClientToRemove = !mFocusStack.isEmpty() && - mFocusStack.peek().mSourceRef.equals(cb); - // (using an iterator on the stack so we can safely remove an entry after having - // evaluated it, traversal order doesn't matter here) - Iterator<FocusStackEntry> stackIterator = mFocusStack.iterator(); - while(stackIterator.hasNext()) { - FocusStackEntry fse = (FocusStackEntry)stackIterator.next(); - if(fse.mSourceRef.equals(cb)) { - Log.i(TAG, " AudioFocus abandonAudioFocus(): removing entry for " - + fse.mClientId); - stackIterator.remove(); - // the client just died, no need to unlink to its death - } - } - if (isTopOfStackForClientToRemove) { - // we removed an entry at the top of the stack: - // notify the new top of the stack it gained focus. - notifyTopOfAudioFocusStack(); - // there's a new top of the stack, let the remote control know - synchronized(mRCStack) { - checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL); - } - } - } - - /** - * Helper function: - * Returns true if the system is in a state where the focus can be reevaluated, false otherwise. - */ - private boolean canReassignAudioFocus() { - // focus requests are rejected during a phone call or when the phone is ringing - // this is equivalent to IN_VOICE_COMM_FOCUS_ID having the focus - if (!mFocusStack.isEmpty() && IN_VOICE_COMM_FOCUS_ID.equals(mFocusStack.peek().mClientId)) { - return false; - } - return true; - } - - /** - * Inner class to monitor audio focus client deaths, and remove them from the audio focus - * stack if necessary. - */ - private class AudioFocusDeathHandler implements IBinder.DeathRecipient { - private IBinder mCb; // To be notified of client's death - - AudioFocusDeathHandler(IBinder cb) { - mCb = cb; - } - - public void binderDied() { - synchronized(mAudioFocusLock) { - Log.w(TAG, " AudioFocus audio focus client died"); - removeFocusStackEntryForClient(mCb); - } - } - - public IBinder getBinder() { - return mCb; - } - } - - - /** @see AudioManager#requestAudioFocus(AudioManager.OnAudioFocusChangeListener, int, int) */ - public int requestAudioFocus(int mainStreamType, int focusChangeHint, IBinder cb, - IAudioFocusDispatcher fd, String clientId, String callingPackageName) { - Log.i(TAG, " AudioFocus requestAudioFocus() from " + clientId); - // the main stream type for the audio focus request is currently not used. It may - // potentially be used to handle multiple stream type-dependent audio focuses. - - // we need a valid binder callback for clients - if (!cb.pingBinder()) { - Log.e(TAG, " AudioFocus DOA client for requestAudioFocus(), aborting."); - return AudioManager.AUDIOFOCUS_REQUEST_FAILED; - } - - if (mAppOps.noteOp(AppOpsManager.OP_TAKE_AUDIO_FOCUS, Binder.getCallingUid(), - callingPackageName) != AppOpsManager.MODE_ALLOWED) { - return AudioManager.AUDIOFOCUS_REQUEST_FAILED; - } - - synchronized(mAudioFocusLock) { - if (!canReassignAudioFocus()) { - return AudioManager.AUDIOFOCUS_REQUEST_FAILED; - } - - // handle the potential premature death of the new holder of the focus - // (premature death == death before abandoning focus) - // Register for client death notification - AudioFocusDeathHandler afdh = new AudioFocusDeathHandler(cb); - try { - cb.linkToDeath(afdh, 0); - } catch (RemoteException e) { - // client has already died! - Log.w(TAG, "AudioFocus requestAudioFocus() could not link to "+cb+" binder death"); - return AudioManager.AUDIOFOCUS_REQUEST_FAILED; - } - - if (!mFocusStack.empty() && mFocusStack.peek().mClientId.equals(clientId)) { - // if focus is already owned by this client and the reason for acquiring the focus - // hasn't changed, don't do anything - if (mFocusStack.peek().mFocusChangeType == focusChangeHint) { - // unlink death handler so it can be gc'ed. - // linkToDeath() creates a JNI global reference preventing collection. - cb.unlinkToDeath(afdh, 0); - return AudioManager.AUDIOFOCUS_REQUEST_GRANTED; - } - // the reason for the audio focus request has changed: remove the current top of - // stack and respond as if we had a new focus owner - FocusStackEntry fse = mFocusStack.pop(); - fse.unlinkToDeath(); - } - - // notify current top of stack it is losing focus - if (!mFocusStack.empty() && (mFocusStack.peek().mFocusDispatcher != null)) { - try { - mFocusStack.peek().mFocusDispatcher.dispatchAudioFocusChange( - -1 * focusChangeHint, // loss and gain codes are inverse of each other - mFocusStack.peek().mClientId); - } catch (RemoteException e) { - Log.e(TAG, " Failure to signal loss of focus due to "+ e); - e.printStackTrace(); - } - } - - // focus requester might already be somewhere below in the stack, remove it - removeFocusStackEntry(clientId, false /* signal */); - - // push focus requester at the top of the audio focus stack - mFocusStack.push(new FocusStackEntry(mainStreamType, focusChangeHint, fd, cb, - clientId, afdh, callingPackageName, Binder.getCallingUid())); - - // there's a new top of the stack, let the remote control know - synchronized(mRCStack) { - checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL); - } - }//synchronized(mAudioFocusLock) - - return AudioManager.AUDIOFOCUS_REQUEST_GRANTED; - } - - /** @see AudioManager#abandonAudioFocus(AudioManager.OnAudioFocusChangeListener) */ - public int abandonAudioFocus(IAudioFocusDispatcher fl, String clientId) { - Log.i(TAG, " AudioFocus abandonAudioFocus() from " + clientId); - try { - // this will take care of notifying the new focus owner if needed - synchronized(mAudioFocusLock) { - removeFocusStackEntry(clientId, true); - } - } catch (java.util.ConcurrentModificationException cme) { - // Catching this exception here is temporary. It is here just to prevent - // a crash seen when the "Silent" notification is played. This is believed to be fixed - // but this try catch block is left just to be safe. - Log.e(TAG, "FATAL EXCEPTION AudioFocus abandonAudioFocus() caused " + cme); - cme.printStackTrace(); - } - - return AudioManager.AUDIOFOCUS_REQUEST_GRANTED; - } - - - public void unregisterAudioFocusClient(String clientId) { - synchronized(mAudioFocusLock) { - removeFocusStackEntry(clientId, false); - } - } - - - //========================================================================================== - // RemoteControl - //========================================================================================== - public void dispatchMediaKeyEvent(KeyEvent keyEvent) { - filterMediaKeyEvent(keyEvent, false /*needWakeLock*/); - } - - public void dispatchMediaKeyEventUnderWakelock(KeyEvent keyEvent) { - filterMediaKeyEvent(keyEvent, true /*needWakeLock*/); - } - - private void filterMediaKeyEvent(KeyEvent keyEvent, boolean needWakeLock) { - // sanity check on the incoming key event - if (!isValidMediaKeyEvent(keyEvent)) { - Log.e(TAG, "not dispatching invalid media key event " + keyEvent); - return; - } - // event filtering for telephony - synchronized(mRingingLock) { - synchronized(mRCStack) { - if ((mMediaReceiverForCalls != null) && - (mIsRinging || (getMode() == AudioSystem.MODE_IN_CALL))) { - dispatchMediaKeyEventForCalls(keyEvent, needWakeLock); - return; - } - } - } - // event filtering based on voice-based interactions - if (isValidVoiceInputKeyCode(keyEvent.getKeyCode())) { - filterVoiceInputKeyEvent(keyEvent, needWakeLock); - } else { - dispatchMediaKeyEvent(keyEvent, needWakeLock); - } - } - - /** - * Handles the dispatching of the media button events to the telephony package. - * Precondition: mMediaReceiverForCalls != null - * @param keyEvent a non-null KeyEvent whose key code is one of the supported media buttons - * @param needWakeLock true if a PARTIAL_WAKE_LOCK needs to be held while this key event - * is dispatched. - */ - private void dispatchMediaKeyEventForCalls(KeyEvent keyEvent, boolean needWakeLock) { - Intent keyIntent = new Intent(Intent.ACTION_MEDIA_BUTTON, null); - keyIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent); - keyIntent.setPackage(mMediaReceiverForCalls.getPackageName()); - if (needWakeLock) { - mMediaEventWakeLock.acquire(); - keyIntent.putExtra(EXTRA_WAKELOCK_ACQUIRED, WAKELOCK_RELEASE_ON_FINISHED); - } - final long ident = Binder.clearCallingIdentity(); - try { - mContext.sendOrderedBroadcastAsUser(keyIntent, UserHandle.ALL, - null, mKeyEventDone, mAudioHandler, Activity.RESULT_OK, null, null); - } finally { - Binder.restoreCallingIdentity(ident); - } - } - - /** - * Handles the dispatching of the media button events to one of the registered listeners, - * or if there was none, broadcast an ACTION_MEDIA_BUTTON intent to the rest of the system. - * @param keyEvent a non-null KeyEvent whose key code is one of the supported media buttons - * @param needWakeLock true if a PARTIAL_WAKE_LOCK needs to be held while this key event - * is dispatched. - */ - private void dispatchMediaKeyEvent(KeyEvent keyEvent, boolean needWakeLock) { - if (needWakeLock) { - mMediaEventWakeLock.acquire(); - } - Intent keyIntent = new Intent(Intent.ACTION_MEDIA_BUTTON, null); - keyIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent); - synchronized(mRCStack) { - if (!mRCStack.empty()) { - // send the intent that was registered by the client - try { - mRCStack.peek().mMediaIntent.send(mContext, - needWakeLock ? WAKELOCK_RELEASE_ON_FINISHED : 0 /*code*/, - keyIntent, AudioService.this, mAudioHandler); - } catch (CanceledException e) { - Log.e(TAG, "Error sending pending intent " + mRCStack.peek()); - e.printStackTrace(); - } - } else { - // legacy behavior when nobody registered their media button event receiver - // through AudioManager - if (needWakeLock) { - keyIntent.putExtra(EXTRA_WAKELOCK_ACQUIRED, WAKELOCK_RELEASE_ON_FINISHED); - } - final long ident = Binder.clearCallingIdentity(); - try { - mContext.sendOrderedBroadcastAsUser(keyIntent, UserHandle.ALL, - null, mKeyEventDone, - mAudioHandler, Activity.RESULT_OK, null, null); - } finally { - Binder.restoreCallingIdentity(ident); - } - } - } - } - - /** - * The different actions performed in response to a voice button key event. - */ - private final static int VOICEBUTTON_ACTION_DISCARD_CURRENT_KEY_PRESS = 1; - private final static int VOICEBUTTON_ACTION_START_VOICE_INPUT = 2; - private final static int VOICEBUTTON_ACTION_SIMULATE_KEY_PRESS = 3; - - private final Object mVoiceEventLock = new Object(); - private boolean mVoiceButtonDown; - private boolean mVoiceButtonHandled; - - /** - * Filter key events that may be used for voice-based interactions - * @param keyEvent a non-null KeyEvent whose key code is that of one of the supported - * media buttons that can be used to trigger voice-based interactions. - * @param needWakeLock true if a PARTIAL_WAKE_LOCK needs to be held while this key event - * is dispatched. - */ - private void filterVoiceInputKeyEvent(KeyEvent keyEvent, boolean needWakeLock) { - if (DEBUG_RC) { - Log.v(TAG, "voice input key event: " + keyEvent + ", needWakeLock=" + needWakeLock); - } - - int voiceButtonAction = VOICEBUTTON_ACTION_DISCARD_CURRENT_KEY_PRESS; - int keyAction = keyEvent.getAction(); - synchronized (mVoiceEventLock) { - if (keyAction == KeyEvent.ACTION_DOWN) { - if (keyEvent.getRepeatCount() == 0) { - // initial down - mVoiceButtonDown = true; - mVoiceButtonHandled = false; - } else if (mVoiceButtonDown && !mVoiceButtonHandled - && (keyEvent.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0) { - // long-press, start voice-based interactions - mVoiceButtonHandled = true; - voiceButtonAction = VOICEBUTTON_ACTION_START_VOICE_INPUT; - } - } else if (keyAction == KeyEvent.ACTION_UP) { - if (mVoiceButtonDown) { - // voice button up - mVoiceButtonDown = false; - if (!mVoiceButtonHandled && !keyEvent.isCanceled()) { - voiceButtonAction = VOICEBUTTON_ACTION_SIMULATE_KEY_PRESS; - } - } - } - }//synchronized (mVoiceEventLock) - - // take action after media button event filtering for voice-based interactions - switch (voiceButtonAction) { - case VOICEBUTTON_ACTION_DISCARD_CURRENT_KEY_PRESS: - if (DEBUG_RC) Log.v(TAG, " ignore key event"); - break; - case VOICEBUTTON_ACTION_START_VOICE_INPUT: - if (DEBUG_RC) Log.v(TAG, " start voice-based interactions"); - // then start the voice-based interactions - startVoiceBasedInteractions(needWakeLock); - break; - case VOICEBUTTON_ACTION_SIMULATE_KEY_PRESS: - if (DEBUG_RC) Log.v(TAG, " send simulated key event, wakelock=" + needWakeLock); - sendSimulatedMediaButtonEvent(keyEvent, needWakeLock); - break; - } - } - - private void sendSimulatedMediaButtonEvent(KeyEvent originalKeyEvent, boolean needWakeLock) { - // send DOWN event - KeyEvent keyEvent = KeyEvent.changeAction(originalKeyEvent, KeyEvent.ACTION_DOWN); - dispatchMediaKeyEvent(keyEvent, needWakeLock); - // send UP event - keyEvent = KeyEvent.changeAction(originalKeyEvent, KeyEvent.ACTION_UP); - dispatchMediaKeyEvent(keyEvent, needWakeLock); - - } - - - private static boolean isValidMediaKeyEvent(KeyEvent keyEvent) { - if (keyEvent == null) { - return false; - } - final int keyCode = keyEvent.getKeyCode(); - switch (keyCode) { - case KeyEvent.KEYCODE_MUTE: - case KeyEvent.KEYCODE_HEADSETHOOK: - case KeyEvent.KEYCODE_MEDIA_PLAY: - case KeyEvent.KEYCODE_MEDIA_PAUSE: - case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE: - case KeyEvent.KEYCODE_MEDIA_STOP: - case KeyEvent.KEYCODE_MEDIA_NEXT: - case KeyEvent.KEYCODE_MEDIA_PREVIOUS: - case KeyEvent.KEYCODE_MEDIA_REWIND: - case KeyEvent.KEYCODE_MEDIA_RECORD: - case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: - case KeyEvent.KEYCODE_MEDIA_CLOSE: - case KeyEvent.KEYCODE_MEDIA_EJECT: - break; - default: - return false; - } - return true; - } - - /** - * Checks whether the given key code is one that can trigger the launch of voice-based - * interactions. - * @param keyCode the key code associated with the key event - * @return true if the key is one of the supported voice-based interaction triggers - */ - private static boolean isValidVoiceInputKeyCode(int keyCode) { - if (keyCode == KeyEvent.KEYCODE_HEADSETHOOK) { - return true; - } else { - return false; - } - } - - /** - * Tell the system to start voice-based interactions / voice commands - */ - private void startVoiceBasedInteractions(boolean needWakeLock) { - Intent voiceIntent = null; - // select which type of search to launch: - // - screen on and device unlocked: action is ACTION_WEB_SEARCH - // - device locked or screen off: action is ACTION_VOICE_SEARCH_HANDS_FREE - // with EXTRA_SECURE set to true if the device is securely locked - PowerManager pm = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE); - boolean isLocked = mKeyguardManager != null && mKeyguardManager.isKeyguardLocked(); - if (!isLocked && pm.isScreenOn()) { - voiceIntent = new Intent(android.speech.RecognizerIntent.ACTION_WEB_SEARCH); - Log.i(TAG, "voice-based interactions: about to use ACTION_WEB_SEARCH"); - } else { - voiceIntent = new Intent(RecognizerIntent.ACTION_VOICE_SEARCH_HANDS_FREE); - voiceIntent.putExtra(RecognizerIntent.EXTRA_SECURE, - isLocked && mKeyguardManager.isKeyguardSecure()); - Log.i(TAG, "voice-based interactions: about to use ACTION_VOICE_SEARCH_HANDS_FREE"); - } - // start the search activity - if (needWakeLock) { - mMediaEventWakeLock.acquire(); - } - try { - if (voiceIntent != null) { - voiceIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK - | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); - mContext.startActivity(voiceIntent); - } - } catch (ActivityNotFoundException e) { - Log.w(TAG, "No activity for search: " + e); - } finally { - if (needWakeLock) { - mMediaEventWakeLock.release(); - } - } - } - - private PowerManager.WakeLock mMediaEventWakeLock; - - private static final int WAKELOCK_RELEASE_ON_FINISHED = 1980; //magic number - - // only set when wakelock was acquired, no need to check value when received - private static final String EXTRA_WAKELOCK_ACQUIRED = - "android.media.AudioService.WAKELOCK_ACQUIRED"; - - public void onSendFinished(PendingIntent pendingIntent, Intent intent, - int resultCode, String resultData, Bundle resultExtras) { - if (resultCode == WAKELOCK_RELEASE_ON_FINISHED) { - mMediaEventWakeLock.release(); - } - } - - BroadcastReceiver mKeyEventDone = new BroadcastReceiver() { - public void onReceive(Context context, Intent intent) { - if (intent == null) { - return; - } - Bundle extras = intent.getExtras(); - if (extras == null) { - return; - } - if (extras.containsKey(EXTRA_WAKELOCK_ACQUIRED)) { - mMediaEventWakeLock.release(); - } - } - }; - - /** - * Synchronization on mCurrentRcLock always inside a block synchronized on mRCStack - */ - private final Object mCurrentRcLock = new Object(); - /** - * The one remote control client which will receive a request for display information. - * This object may be null. - * Access protected by mCurrentRcLock. - */ - private IRemoteControlClient mCurrentRcClient = null; - - private final static int RC_INFO_NONE = 0; - private final static int RC_INFO_ALL = - RemoteControlClient.FLAG_INFORMATION_REQUEST_ALBUM_ART | - RemoteControlClient.FLAG_INFORMATION_REQUEST_KEY_MEDIA | - RemoteControlClient.FLAG_INFORMATION_REQUEST_METADATA | - RemoteControlClient.FLAG_INFORMATION_REQUEST_PLAYSTATE; - - /** - * A monotonically increasing generation counter for mCurrentRcClient. - * Only accessed with a lock on mCurrentRcLock. - * No value wrap-around issues as we only act on equal values. - */ - private int mCurrentRcClientGen = 0; - - /** - * Inner class to monitor remote control client deaths, and remove the client for the - * remote control stack if necessary. - */ - private class RcClientDeathHandler implements IBinder.DeathRecipient { - final private IBinder mCb; // To be notified of client's death - final private PendingIntent mMediaIntent; - - RcClientDeathHandler(IBinder cb, PendingIntent pi) { - mCb = cb; - mMediaIntent = pi; - } - - public void binderDied() { - Log.w(TAG, " RemoteControlClient died"); - // remote control client died, make sure the displays don't use it anymore - // by setting its remote control client to null - registerRemoteControlClient(mMediaIntent, null/*rcClient*/, null/*ignored*/); - // the dead client was maybe handling remote playback, reevaluate - postReevaluateRemote(); - } - - public IBinder getBinder() { - return mCb; - } - } - - /** - * A global counter for RemoteControlClient identifiers - */ - private static int sLastRccId = 0; - - private class RemotePlaybackState { - int mRccId; - int mVolume; - int mVolumeMax; - int mVolumeHandling; - - private RemotePlaybackState(int id, int vol, int volMax) { - mRccId = id; - mVolume = vol; - mVolumeMax = volMax; - mVolumeHandling = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME_HANDLING; - } - } - - /** - * Internal cache for the playback information of the RemoteControlClient whose volume gets to - * be controlled by the volume keys ("main"), so we don't have to iterate over the RC stack - * every time we need this info. - */ - private RemotePlaybackState mMainRemote; - /** - * Indicates whether the "main" RemoteControlClient is considered active. - * Use synchronized on mMainRemote. - */ - private boolean mMainRemoteIsActive; - /** - * Indicates whether there is remote playback going on. True even if there is no "active" - * remote playback (mMainRemoteIsActive is false), but a RemoteControlClient has declared it - * handles remote playback. - * Use synchronized on mMainRemote. - */ - private boolean mHasRemotePlayback; - - private static class RccPlaybackState { - public int mState; - public long mPositionMs; - public float mSpeed; - - public RccPlaybackState(int state, long positionMs, float speed) { - mState = state; - mPositionMs = positionMs; - mSpeed = speed; - } - - public void reset() { - mState = RemoteControlClient.PLAYSTATE_STOPPED; - mPositionMs = RemoteControlClient.PLAYBACK_POSITION_INVALID; - mSpeed = RemoteControlClient.PLAYBACK_SPEED_1X; - } - - @Override - public String toString() { - return stateToString() + ", " - + ((mPositionMs == RemoteControlClient.PLAYBACK_POSITION_INVALID) ? - "PLAYBACK_POSITION_INVALID ," : String.valueOf(mPositionMs)) + "ms ," - + mSpeed + "X"; - } - - private String stateToString() { - switch (mState) { - case RemoteControlClient.PLAYSTATE_NONE: - return "PLAYSTATE_NONE"; - case RemoteControlClient.PLAYSTATE_STOPPED: - return "PLAYSTATE_STOPPED"; - case RemoteControlClient.PLAYSTATE_PAUSED: - return "PLAYSTATE_PAUSED"; - case RemoteControlClient.PLAYSTATE_PLAYING: - return "PLAYSTATE_PLAYING"; - case RemoteControlClient.PLAYSTATE_FAST_FORWARDING: - return "PLAYSTATE_FAST_FORWARDING"; - case RemoteControlClient.PLAYSTATE_REWINDING: - return "PLAYSTATE_REWINDING"; - case RemoteControlClient.PLAYSTATE_SKIPPING_FORWARDS: - return "PLAYSTATE_SKIPPING_FORWARDS"; - case RemoteControlClient.PLAYSTATE_SKIPPING_BACKWARDS: - return "PLAYSTATE_SKIPPING_BACKWARDS"; - case RemoteControlClient.PLAYSTATE_BUFFERING: - return "PLAYSTATE_BUFFERING"; - case RemoteControlClient.PLAYSTATE_ERROR: - return "PLAYSTATE_ERROR"; - default: - return "[invalid playstate]"; - } - } - } - - private static class RemoteControlStackEntry implements DeathRecipient { - public int mRccId = RemoteControlClient.RCSE_ID_UNREGISTERED; - final public AudioService mService; - /** - * The target for the ACTION_MEDIA_BUTTON events. - * Always non null. - */ - final public PendingIntent mMediaIntent; - /** - * The registered media button event receiver. - * Always non null. - */ - final public ComponentName mReceiverComponent; - public IBinder mToken; - public String mCallingPackageName; - public int mCallingUid; - /** - * Provides access to the information to display on the remote control. - * May be null (when a media button event receiver is registered, - * but no remote control client has been registered) */ - public IRemoteControlClient mRcClient; - public RcClientDeathHandler mRcClientDeathHandler; - /** - * Information only used for non-local playback - */ - public int mPlaybackType; - public int mPlaybackVolume; - public int mPlaybackVolumeMax; - public int mPlaybackVolumeHandling; - public int mPlaybackStream; - public RccPlaybackState mPlaybackState; - public IRemoteVolumeObserver mRemoteVolumeObs; - - public void resetPlaybackInfo() { - mPlaybackType = RemoteControlClient.PLAYBACK_TYPE_LOCAL; - mPlaybackVolume = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME; - mPlaybackVolumeMax = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME; - mPlaybackVolumeHandling = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME_HANDLING; - mPlaybackStream = AudioManager.STREAM_MUSIC; - mPlaybackState.reset(); - mRemoteVolumeObs = null; - } - - /** precondition: mediaIntent != null */ - public RemoteControlStackEntry(AudioService service, PendingIntent mediaIntent, - ComponentName eventReceiver, IBinder token) { - mService = service; - mMediaIntent = mediaIntent; - mReceiverComponent = eventReceiver; - mToken = token; - mCallingUid = -1; - mRcClient = null; - mRccId = ++sLastRccId; - mPlaybackState = new RccPlaybackState( - RemoteControlClient.PLAYSTATE_STOPPED, - RemoteControlClient.PLAYBACK_POSITION_INVALID, - RemoteControlClient.PLAYBACK_SPEED_1X); - - resetPlaybackInfo(); - if (mToken != null) { - try { - mToken.linkToDeath(this, 0); - } catch (RemoteException e) { - mService.mAudioHandler.post(new Runnable() { - @Override public void run() { - mService.unregisterMediaButtonIntent(mMediaIntent); - } - }); - } - } - } - - public void unlinkToRcClientDeath() { - if ((mRcClientDeathHandler != null) && (mRcClientDeathHandler.mCb != null)) { - try { - mRcClientDeathHandler.mCb.unlinkToDeath(mRcClientDeathHandler, 0); - mRcClientDeathHandler = null; - } catch (java.util.NoSuchElementException e) { - // not much we can do here - Log.e(TAG, "Encountered " + e + " in unlinkToRcClientDeath()"); - e.printStackTrace(); - } - } - } - - public void destroy() { - unlinkToRcClientDeath(); - if (mToken != null) { - mToken.unlinkToDeath(this, 0); - mToken = null; - } - } - - @Override - public void binderDied() { - mService.unregisterMediaButtonIntent(mMediaIntent); - } - - @Override - protected void finalize() throws Throwable { - destroy(); // unlink exception handled inside method - super.finalize(); - } - } - - /** - * The stack of remote control event receivers. - * Code sections and methods that modify the remote control event receiver stack are - * synchronized on mRCStack, but also BEFORE on mFocusLock as any change in either - * stack, audio focus or RC, can lead to a change in the remote control display - */ - private final Stack<RemoteControlStackEntry> mRCStack = new Stack<RemoteControlStackEntry>(); - - /** - * The component the telephony package can register so telephony calls have priority to - * handle media button events - */ - private ComponentName mMediaReceiverForCalls = null; - - /** - * Helper function: - * Display in the log the current entries in the remote control focus stack - */ - private void dumpRCStack(PrintWriter pw) { - pw.println("\nRemote Control stack entries (last is top of stack):"); - synchronized(mRCStack) { - Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); - while(stackIterator.hasNext()) { - RemoteControlStackEntry rcse = stackIterator.next(); - pw.println(" pi: " + rcse.mMediaIntent + - " -- pack: " + rcse.mCallingPackageName + - " -- ercvr: " + rcse.mReceiverComponent + - " -- client: " + rcse.mRcClient + - " -- uid: " + rcse.mCallingUid + - " -- type: " + rcse.mPlaybackType + - " state: " + rcse.mPlaybackState); - } - } - } - - /** - * Helper function: - * Display in the log the current entries in the remote control stack, focusing - * on RemoteControlClient data - */ - private void dumpRCCStack(PrintWriter pw) { - pw.println("\nRemote Control Client stack entries (last is top of stack):"); - synchronized(mRCStack) { - Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); - while(stackIterator.hasNext()) { - RemoteControlStackEntry rcse = stackIterator.next(); - pw.println(" uid: " + rcse.mCallingUid + - " -- id: " + rcse.mRccId + - " -- type: " + rcse.mPlaybackType + - " -- state: " + rcse.mPlaybackState + - " -- vol handling: " + rcse.mPlaybackVolumeHandling + - " -- vol: " + rcse.mPlaybackVolume + - " -- volMax: " + rcse.mPlaybackVolumeMax + - " -- volObs: " + rcse.mRemoteVolumeObs); - } - synchronized(mCurrentRcLock) { - pw.println("\nCurrent remote control generation ID = " + mCurrentRcClientGen); - } - } - synchronized (mMainRemote) { - pw.println("\nRemote Volume State:"); - pw.println(" has remote: " + mHasRemotePlayback); - pw.println(" is remote active: " + mMainRemoteIsActive); - pw.println(" rccId: " + mMainRemote.mRccId); - pw.println(" volume handling: " - + ((mMainRemote.mVolumeHandling == RemoteControlClient.PLAYBACK_VOLUME_FIXED) ? - "PLAYBACK_VOLUME_FIXED(0)" : "PLAYBACK_VOLUME_VARIABLE(1)")); - pw.println(" volume: " + mMainRemote.mVolume); - pw.println(" volume steps: " + mMainRemote.mVolumeMax); - } - } - - /** - * Helper function: - * Display in the log the current entries in the list of remote control displays - */ - private void dumpRCDList(PrintWriter pw) { - pw.println("\nRemote Control Display list entries:"); - synchronized(mRCStack) { - final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator(); - while (displayIterator.hasNext()) { - final DisplayInfoForServer di = (DisplayInfoForServer) displayIterator.next(); - pw.println(" IRCD: " + di.mRcDisplay + - " -- w:" + di.mArtworkExpectedWidth + - " -- h:" + di.mArtworkExpectedHeight+ - " -- wantsPosSync:" + di.mWantsPositionSync); - } - } - } - - /** - * Helper function: - * Remove any entry in the remote control stack that has the same package name as packageName - * Pre-condition: packageName != null - */ - private void cleanupMediaButtonReceiverForPackage(String packageName, boolean removeAll) { - synchronized(mRCStack) { - if (mRCStack.empty()) { - return; - } else { - final PackageManager pm = mContext.getPackageManager(); - RemoteControlStackEntry oldTop = mRCStack.peek(); - Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); - // iterate over the stack entries - // (using an iterator on the stack so we can safely remove an entry after having - // evaluated it, traversal order doesn't matter here) - while(stackIterator.hasNext()) { - RemoteControlStackEntry rcse = (RemoteControlStackEntry)stackIterator.next(); - if (removeAll && packageName.equals(rcse.mMediaIntent.getCreatorPackage())) { - // a stack entry is from the package being removed, remove it from the stack - stackIterator.remove(); - rcse.destroy(); - } else if (rcse.mReceiverComponent != null) { - try { - // Check to see if this receiver still exists. - pm.getReceiverInfo(rcse.mReceiverComponent, 0); - } catch (PackageManager.NameNotFoundException e) { - // Not found -- remove it! - stackIterator.remove(); - rcse.destroy(); - } - } - } - if (mRCStack.empty()) { - // no saved media button receiver - mAudioHandler.sendMessage( - mAudioHandler.obtainMessage(MSG_PERSIST_MEDIABUTTONRECEIVER, 0, 0, - null)); - } else if (oldTop != mRCStack.peek()) { - // the top of the stack has changed, save it in the system settings - // by posting a message to persist it; only do this however if it has - // a concrete component name (is not a transient registration) - RemoteControlStackEntry rcse = mRCStack.peek(); - if (rcse.mReceiverComponent != null) { - mAudioHandler.sendMessage( - mAudioHandler.obtainMessage(MSG_PERSIST_MEDIABUTTONRECEIVER, 0, 0, - rcse.mReceiverComponent)); - } - } - } - } - } - - /** - * Helper function: - * Restore remote control receiver from the system settings. - */ - private void restoreMediaButtonReceiver() { - String receiverName = Settings.System.getStringForUser(mContentResolver, - Settings.System.MEDIA_BUTTON_RECEIVER, UserHandle.USER_CURRENT); - if ((null != receiverName) && !receiverName.isEmpty()) { - ComponentName eventReceiver = ComponentName.unflattenFromString(receiverName); - if (eventReceiver == null) { - // an invalid name was persisted - return; - } - // construct a PendingIntent targeted to the restored component name - // for the media button and register it - Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON); - // the associated intent will be handled by the component being registered - mediaButtonIntent.setComponent(eventReceiver); - PendingIntent pi = PendingIntent.getBroadcast(mContext, - 0/*requestCode, ignored*/, mediaButtonIntent, 0/*flags*/); - registerMediaButtonIntent(pi, eventReceiver, null); - } - } - - /** - * Helper function: - * Set the new remote control receiver at the top of the RC focus stack. - * Called synchronized on mAudioFocusLock, then mRCStack - * precondition: mediaIntent != null - */ - private void pushMediaButtonReceiver_syncAfRcs(PendingIntent mediaIntent, ComponentName target, - IBinder token) { - // already at top of stack? - if (!mRCStack.empty() && mRCStack.peek().mMediaIntent.equals(mediaIntent)) { - return; - } - if (mAppOps.noteOp(AppOpsManager.OP_TAKE_MEDIA_BUTTONS, Binder.getCallingUid(), - mediaIntent.getCreatorPackage()) != AppOpsManager.MODE_ALLOWED) { - return; - } - RemoteControlStackEntry rcse = null; - boolean wasInsideStack = false; - try { - for (int index = mRCStack.size()-1; index >= 0; index--) { - rcse = mRCStack.elementAt(index); - if(rcse.mMediaIntent.equals(mediaIntent)) { - // ok to remove element while traversing the stack since we're leaving the loop - mRCStack.removeElementAt(index); - wasInsideStack = true; - break; - } - } - } catch (ArrayIndexOutOfBoundsException e) { - // not expected to happen, indicates improper concurrent modification - Log.e(TAG, "Wrong index accessing media button stack, lock error? ", e); - } - if (!wasInsideStack) { - rcse = new RemoteControlStackEntry(this, mediaIntent, target, token); - } - mRCStack.push(rcse); // rcse is never null - - // post message to persist the default media button receiver - if (target != null) { - mAudioHandler.sendMessage( mAudioHandler.obtainMessage( - MSG_PERSIST_MEDIABUTTONRECEIVER, 0, 0, target/*obj*/) ); - } - } - - /** - * Helper function: - * Remove the remote control receiver from the RC focus stack. - * Called synchronized on mAudioFocusLock, then mRCStack - * precondition: pi != null - */ - private void removeMediaButtonReceiver_syncAfRcs(PendingIntent pi) { - try { - for (int index = mRCStack.size()-1; index >= 0; index--) { - final RemoteControlStackEntry rcse = mRCStack.elementAt(index); - if (rcse.mMediaIntent.equals(pi)) { - rcse.destroy(); - // ok to remove element while traversing the stack since we're leaving the loop - mRCStack.removeElementAt(index); - break; - } - } - } catch (ArrayIndexOutOfBoundsException e) { - // not expected to happen, indicates improper concurrent modification - Log.e(TAG, "Wrong index accessing media button stack, lock error? ", e); - } - } - - /** - * Helper function: - * Called synchronized on mRCStack - */ - private boolean isCurrentRcController(PendingIntent pi) { - if (!mRCStack.empty() && mRCStack.peek().mMediaIntent.equals(pi)) { - return true; - } - return false; - } - - //========================================================================================== - // Remote control display / client + // RemoteControlDisplay / RemoteControlClient / Remote info //========================================================================================== - /** - * Update the remote control displays with the new "focused" client generation - */ - private void setNewRcClientOnDisplays_syncRcsCurrc(int newClientGeneration, - PendingIntent newMediaIntent, boolean clearing) { - synchronized(mRCStack) { - if (mRcDisplays.size() > 0) { - final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator(); - while (displayIterator.hasNext()) { - final DisplayInfoForServer di = displayIterator.next(); - try { - di.mRcDisplay.setCurrentClientId( - newClientGeneration, newMediaIntent, clearing); - } catch (RemoteException e) { - Log.e(TAG, "Dead display in setNewRcClientOnDisplays_syncRcsCurrc()",e); - di.release(); - displayIterator.remove(); - } - } - } - } - } - - /** - * Update the remote control clients with the new "focused" client generation - */ - private void setNewRcClientGenerationOnClients_syncRcsCurrc(int newClientGeneration) { - // (using an iterator on the stack so we can safely remove an entry if needed, - // traversal order doesn't matter here as we update all entries) - Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); - while(stackIterator.hasNext()) { - RemoteControlStackEntry se = stackIterator.next(); - if ((se != null) && (se.mRcClient != null)) { - try { - se.mRcClient.setCurrentClientGenerationId(newClientGeneration); - } catch (RemoteException e) { - Log.w(TAG, "Dead client in setNewRcClientGenerationOnClients_syncRcsCurrc()",e); - stackIterator.remove(); - se.unlinkToRcClientDeath(); - } - } - } - } - - /** - * Update the displays and clients with the new "focused" client generation and name - * @param newClientGeneration the new generation value matching a client update - * @param newMediaIntent the media button event receiver associated with the client. - * May be null, which implies there is no registered media button event receiver. - * @param clearing true if the new client generation value maps to a remote control update - * where the display should be cleared. - */ - private void setNewRcClient_syncRcsCurrc(int newClientGeneration, - PendingIntent newMediaIntent, boolean clearing) { - // send the new valid client generation ID to all displays - setNewRcClientOnDisplays_syncRcsCurrc(newClientGeneration, newMediaIntent, clearing); - // send the new valid client generation ID to all clients - setNewRcClientGenerationOnClients_syncRcsCurrc(newClientGeneration); - } - - /** - * Called when processing MSG_RCDISPLAY_CLEAR event - */ - private void onRcDisplayClear() { - if (DEBUG_RC) Log.i(TAG, "Clear remote control display"); - - synchronized(mRCStack) { - synchronized(mCurrentRcLock) { - mCurrentRcClientGen++; - // synchronously update the displays and clients with the new client generation - setNewRcClient_syncRcsCurrc(mCurrentRcClientGen, - null /*newMediaIntent*/, true /*clearing*/); - } - } - } - - /** - * Called when processing MSG_RCDISPLAY_UPDATE event - */ - private void onRcDisplayUpdate(RemoteControlStackEntry rcse, int flags /* USED ?*/) { - synchronized(mRCStack) { - synchronized(mCurrentRcLock) { - if ((mCurrentRcClient != null) && (mCurrentRcClient.equals(rcse.mRcClient))) { - if (DEBUG_RC) Log.i(TAG, "Display/update remote control "); - - mCurrentRcClientGen++; - // synchronously update the displays and clients with - // the new client generation - setNewRcClient_syncRcsCurrc(mCurrentRcClientGen, - rcse.mMediaIntent /*newMediaIntent*/, - false /*clearing*/); - - // tell the current client that it needs to send info - try { - mCurrentRcClient.onInformationRequested(mCurrentRcClientGen, flags); - } catch (RemoteException e) { - Log.e(TAG, "Current valid remote client is dead: "+e); - mCurrentRcClient = null; - } - } else { - // the remote control display owner has changed between the - // the message to update the display was sent, and the time it - // gets to be processed (now) - } - } - } - } - - - /** - * Helper function: - * Called synchronized on mRCStack - */ - private void clearRemoteControlDisplay_syncAfRcs() { - synchronized(mCurrentRcLock) { - mCurrentRcClient = null; - } - // will cause onRcDisplayClear() to be called in AudioService's handler thread - mAudioHandler.sendMessage( mAudioHandler.obtainMessage(MSG_RCDISPLAY_CLEAR) ); - } - - /** - * Helper function for code readability: only to be called from - * checkUpdateRemoteControlDisplay_syncAfRcs() which checks the preconditions for - * this method. - * Preconditions: - * - called synchronized mAudioFocusLock then on mRCStack - * - mRCStack.isEmpty() is false - */ - private void updateRemoteControlDisplay_syncAfRcs(int infoChangedFlags) { - RemoteControlStackEntry rcse = mRCStack.peek(); - int infoFlagsAboutToBeUsed = infoChangedFlags; - // this is where we enforce opt-in for information display on the remote controls - // with the new AudioManager.registerRemoteControlClient() API - if (rcse.mRcClient == null) { - //Log.w(TAG, "Can't update remote control display with null remote control client"); - clearRemoteControlDisplay_syncAfRcs(); - return; - } - synchronized(mCurrentRcLock) { - if (!rcse.mRcClient.equals(mCurrentRcClient)) { - // new RC client, assume every type of information shall be queried - infoFlagsAboutToBeUsed = RC_INFO_ALL; - } - mCurrentRcClient = rcse.mRcClient; - } - // will cause onRcDisplayUpdate() to be called in AudioService's handler thread - mAudioHandler.sendMessage( mAudioHandler.obtainMessage(MSG_RCDISPLAY_UPDATE, - infoFlagsAboutToBeUsed /* arg1 */, 0, rcse /* obj, != null */) ); - } - - /** - * Helper function: - * Called synchronized on mAudioFocusLock, then mRCStack - * Check whether the remote control display should be updated, triggers the update if required - * @param infoChangedFlags the flags corresponding to the remote control client information - * that has changed, if applicable (checking for the update conditions might trigger a - * clear, rather than an update event). - */ - private void checkUpdateRemoteControlDisplay_syncAfRcs(int infoChangedFlags) { - // determine whether the remote control display should be refreshed - // if either stack is empty, there is a mismatch, so clear the RC display - if (mRCStack.isEmpty() || mFocusStack.isEmpty()) { - clearRemoteControlDisplay_syncAfRcs(); - return; - } - - // determine which entry in the AudioFocus stack to consider, and compare against the - // top of the stack for the media button event receivers : simply using the top of the - // stack would make the entry disappear from the RemoteControlDisplay in conditions such as - // notifications playing during music playback. - // Crawl the AudioFocus stack from the top until an entry is found with the following - // characteristics: - // - focus gain on STREAM_MUSIC stream - // - non-transient focus gain on a stream other than music - FocusStackEntry af = null; - try { - for (int index = mFocusStack.size()-1; index >= 0; index--) { - FocusStackEntry fse = mFocusStack.elementAt(index); - if ((fse.mStreamType == AudioManager.STREAM_MUSIC) - || (fse.mFocusChangeType == AudioManager.AUDIOFOCUS_GAIN)) { - af = fse; - break; - } - } - } catch (ArrayIndexOutOfBoundsException e) { - Log.e(TAG, "Wrong index accessing audio focus stack when updating RCD: " + e); - af = null; - } - if (af == null) { - clearRemoteControlDisplay_syncAfRcs(); - return; - } - - // if the audio focus and RC owners belong to different packages, there is a mismatch, clear - if ((mRCStack.peek().mCallingPackageName != null) - && (af.mPackageName != null) - && !(mRCStack.peek().mCallingPackageName.compareTo( - af.mPackageName) == 0)) { - clearRemoteControlDisplay_syncAfRcs(); - return; - } - // if the audio focus didn't originate from the same Uid as the one in which the remote - // control information will be retrieved, clear - if (mRCStack.peek().mCallingUid != af.mCallingUid) { - clearRemoteControlDisplay_syncAfRcs(); - return; - } - - // refresh conditions were verified: update the remote controls - // ok to call: synchronized mAudioFocusLock then on mRCStack, mRCStack is not empty - updateRemoteControlDisplay_syncAfRcs(infoChangedFlags); - } - - /** - * Helper function: - * Post a message to asynchronously move the media button event receiver associated with the - * given remote control client ID to the top of the remote control stack - * @param rccId - */ - private void postPromoteRcc(int rccId) { - sendMsg(mAudioHandler, MSG_PROMOTE_RCC, SENDMSG_REPLACE, - rccId /*arg1*/, 0, null, 0/*delay*/); - } - - private void onPromoteRcc(int rccId) { - if (DEBUG_RC) { Log.d(TAG, "Promoting RCC " + rccId); } - synchronized(mAudioFocusLock) { - synchronized(mRCStack) { - // ignore if given RCC ID is already at top of remote control stack - if (!mRCStack.isEmpty() && (mRCStack.peek().mRccId == rccId)) { - return; - } - int indexToPromote = -1; - try { - for (int index = mRCStack.size()-1; index >= 0; index--) { - final RemoteControlStackEntry rcse = mRCStack.elementAt(index); - if (rcse.mRccId == rccId) { - indexToPromote = index; - break; - } - } - if (indexToPromote >= 0) { - if (DEBUG_RC) { Log.d(TAG, " moving RCC from index " + indexToPromote - + " to " + (mRCStack.size()-1)); } - final RemoteControlStackEntry rcse = mRCStack.remove(indexToPromote); - mRCStack.push(rcse); - // the RC stack changed, reevaluate the display - checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL); - } - } catch (ArrayIndexOutOfBoundsException e) { - // not expected to happen, indicates improper concurrent modification - Log.e(TAG, "Wrong index accessing RC stack, lock error? ", e); - } - }//synchronized(mRCStack) - }//synchronized(mAudioFocusLock) - } - - /** - * see AudioManager.registerMediaButtonIntent(PendingIntent pi, ComponentName c) - * precondition: mediaIntent != null - */ - public void registerMediaButtonIntent(PendingIntent mediaIntent, ComponentName eventReceiver, - IBinder token) { - Log.i(TAG, " Remote Control registerMediaButtonIntent() for " + mediaIntent); - - synchronized(mAudioFocusLock) { - synchronized(mRCStack) { - pushMediaButtonReceiver_syncAfRcs(mediaIntent, eventReceiver, token); - // new RC client, assume every type of information shall be queried - checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL); - } - } - } - - /** - * see AudioManager.unregisterMediaButtonIntent(PendingIntent mediaIntent) - * precondition: mediaIntent != null, eventReceiver != null - */ - public void unregisterMediaButtonIntent(PendingIntent mediaIntent) - { - Log.i(TAG, " Remote Control unregisterMediaButtonIntent() for " + mediaIntent); - - synchronized(mAudioFocusLock) { - synchronized(mRCStack) { - boolean topOfStackWillChange = isCurrentRcController(mediaIntent); - removeMediaButtonReceiver_syncAfRcs(mediaIntent); - if (topOfStackWillChange) { - // current RC client will change, assume every type of info needs to be queried - checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL); - } - } - } - } - - /** - * see AudioManager.registerMediaButtonEventReceiverForCalls(ComponentName c) - * precondition: c != null - */ - public void registerMediaButtonEventReceiverForCalls(ComponentName c) { - if (mContext.checkCallingPermission("android.permission.MODIFY_PHONE_STATE") - != PackageManager.PERMISSION_GRANTED) { - Log.e(TAG, "Invalid permissions to register media button receiver for calls"); - return; - } - synchronized(mRCStack) { - mMediaReceiverForCalls = c; - } - } - - /** - * see AudioManager.unregisterMediaButtonEventReceiverForCalls() - */ - public void unregisterMediaButtonEventReceiverForCalls() { - if (mContext.checkCallingPermission("android.permission.MODIFY_PHONE_STATE") - != PackageManager.PERMISSION_GRANTED) { - Log.e(TAG, "Invalid permissions to unregister media button receiver for calls"); - return; - } - synchronized(mRCStack) { - mMediaReceiverForCalls = null; - } - } - - /** - * see AudioManager.registerRemoteControlClient(ComponentName eventReceiver, ...) - * @return the unique ID of the RemoteControlStackEntry associated with the RemoteControlClient - * Note: using this method with rcClient == null is a way to "disable" the IRemoteControlClient - * without modifying the RC stack, but while still causing the display to refresh (will - * become blank as a result of this) - */ - public int registerRemoteControlClient(PendingIntent mediaIntent, - IRemoteControlClient rcClient, String callingPackageName) { - if (DEBUG_RC) Log.i(TAG, "Register remote control client rcClient="+rcClient); - int rccId = RemoteControlClient.RCSE_ID_UNREGISTERED; - synchronized(mAudioFocusLock) { - synchronized(mRCStack) { - // store the new display information - try { - for (int index = mRCStack.size()-1; index >= 0; index--) { - final RemoteControlStackEntry rcse = mRCStack.elementAt(index); - if(rcse.mMediaIntent.equals(mediaIntent)) { - // already had a remote control client? - if (rcse.mRcClientDeathHandler != null) { - // stop monitoring the old client's death - rcse.unlinkToRcClientDeath(); - } - // save the new remote control client - rcse.mRcClient = rcClient; - rcse.mCallingPackageName = callingPackageName; - rcse.mCallingUid = Binder.getCallingUid(); - if (rcClient == null) { - // here rcse.mRcClientDeathHandler is null; - rcse.resetPlaybackInfo(); - break; - } - rccId = rcse.mRccId; - - // there is a new (non-null) client: - // 1/ give the new client the displays (if any) - if (mRcDisplays.size() > 0) { - plugRemoteControlDisplaysIntoClient_syncRcStack(rcse.mRcClient); - } - // 2/ monitor the new client's death - IBinder b = rcse.mRcClient.asBinder(); - RcClientDeathHandler rcdh = - new RcClientDeathHandler(b, rcse.mMediaIntent); - try { - b.linkToDeath(rcdh, 0); - } catch (RemoteException e) { - // remote control client is DOA, disqualify it - Log.w(TAG, "registerRemoteControlClient() has a dead client " + b); - rcse.mRcClient = null; - } - rcse.mRcClientDeathHandler = rcdh; - break; - } - }//for - } catch (ArrayIndexOutOfBoundsException e) { - // not expected to happen, indicates improper concurrent modification - Log.e(TAG, "Wrong index accessing RC stack, lock error? ", e); - } - - // if the eventReceiver is at the top of the stack - // then check for potential refresh of the remote controls - if (isCurrentRcController(mediaIntent)) { - checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL); - } - }//synchronized(mRCStack) - }//synchronized(mAudioFocusLock) - return rccId; - } - - /** - * see AudioManager.unregisterRemoteControlClient(PendingIntent pi, ...) - * rcClient is guaranteed non-null - */ - public void unregisterRemoteControlClient(PendingIntent mediaIntent, - IRemoteControlClient rcClient) { - if (DEBUG_RC) Log.i(TAG, "Unregister remote control client rcClient="+rcClient); - synchronized(mAudioFocusLock) { - synchronized(mRCStack) { - boolean topRccChange = false; - try { - for (int index = mRCStack.size()-1; index >= 0; index--) { - final RemoteControlStackEntry rcse = mRCStack.elementAt(index); - if ((rcse.mMediaIntent.equals(mediaIntent)) - && rcClient.equals(rcse.mRcClient)) { - // we found the IRemoteControlClient to unregister - // stop monitoring its death - rcse.unlinkToRcClientDeath(); - // reset the client-related fields - rcse.mRcClient = null; - rcse.mCallingPackageName = null; - topRccChange = (index == mRCStack.size()-1); - // there can only be one matching RCC in the RC stack, we're done - break; - } - } - } catch (ArrayIndexOutOfBoundsException e) { - // not expected to happen, indicates improper concurrent modification - Log.e(TAG, "Wrong index accessing RC stack, lock error? ", e); - } - if (topRccChange) { - // no more RCC for the RCD, check for potential refresh of the remote controls - checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL); - } - } - } - } - - - /** - * A class to encapsulate all the information about a remote control display. - * After instanciation, init() must always be called before the object is added in the list - * of displays. - * Before being removed from the list of displays, release() must always be called (otherwise - * it will leak death handlers). - */ - private class DisplayInfoForServer implements IBinder.DeathRecipient { - /** may never be null */ - private IRemoteControlDisplay mRcDisplay; - private IBinder mRcDisplayBinder; - private int mArtworkExpectedWidth = -1; - private int mArtworkExpectedHeight = -1; - private boolean mWantsPositionSync = false; - - public DisplayInfoForServer(IRemoteControlDisplay rcd, int w, int h) { - if (DEBUG_RC) Log.i(TAG, "new DisplayInfoForServer for " + rcd + " w=" + w + " h=" + h); - mRcDisplay = rcd; - mRcDisplayBinder = rcd.asBinder(); - mArtworkExpectedWidth = w; - mArtworkExpectedHeight = h; - } - - public boolean init() { - try { - mRcDisplayBinder.linkToDeath(this, 0); - } catch (RemoteException e) { - // remote control display is DOA, disqualify it - Log.w(TAG, "registerRemoteControlDisplay() has a dead client " + mRcDisplayBinder); - return false; - } - return true; - } - - public void release() { - try { - mRcDisplayBinder.unlinkToDeath(this, 0); - } catch (java.util.NoSuchElementException e) { - // not much we can do here, the display should have been unregistered anyway - Log.e(TAG, "Error in DisplaInfoForServer.relase()", e); - } - } - - public void binderDied() { - synchronized(mRCStack) { - Log.w(TAG, "RemoteControl: display " + mRcDisplay + " died"); - // remove the display from the list - final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator(); - while (displayIterator.hasNext()) { - final DisplayInfoForServer di = (DisplayInfoForServer) displayIterator.next(); - if (di.mRcDisplay == mRcDisplay) { - if (DEBUG_RC) Log.w(TAG, " RCD removed from list"); - displayIterator.remove(); - return; - } - } - } - } - } - - /** - * The remote control displays. - * Access synchronized on mRCStack - */ - private ArrayList<DisplayInfoForServer> mRcDisplays = new ArrayList<DisplayInfoForServer>(1); - - /** - * Plug each registered display into the specified client - * @param rcc, guaranteed non null - */ - private void plugRemoteControlDisplaysIntoClient_syncRcStack(IRemoteControlClient rcc) { - final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator(); - while (displayIterator.hasNext()) { - final DisplayInfoForServer di = (DisplayInfoForServer) displayIterator.next(); - try { - rcc.plugRemoteControlDisplay(di.mRcDisplay, di.mArtworkExpectedWidth, - di.mArtworkExpectedHeight); - if (di.mWantsPositionSync) { - rcc.setWantsSyncForDisplay(di.mRcDisplay, true); - } - } catch (RemoteException e) { - Log.e(TAG, "Error connecting RCD to RCC in RCC registration",e); - } - } - } - - /** - * Is the remote control display interface already registered - * @param rcd - * @return true if the IRemoteControlDisplay is already in the list of displays - */ - private boolean rcDisplayIsPluggedIn_syncRcStack(IRemoteControlDisplay rcd) { - final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator(); - while (displayIterator.hasNext()) { - final DisplayInfoForServer di = (DisplayInfoForServer) displayIterator.next(); - if (di.mRcDisplay.asBinder().equals(rcd.asBinder())) { - return true; - } - } - return false; - } - - /** - * Register an IRemoteControlDisplay. - * Notify all IRemoteControlClient of the new display and cause the RemoteControlClient - * at the top of the stack to update the new display with its information. - * @see android.media.IAudioService#registerRemoteControlDisplay(android.media.IRemoteControlDisplay, int, int) - * @param rcd the IRemoteControlDisplay to register. No effect if null. - * @param w the maximum width of the expected bitmap. Negative or zero values indicate this - * display doesn't need to receive artwork. - * @param h the maximum height of the expected bitmap. Negative or zero values indicate this - * display doesn't need to receive artwork. - */ public void registerRemoteControlDisplay(IRemoteControlDisplay rcd, int w, int h) { - if (DEBUG_RC) Log.d(TAG, ">>> registerRemoteControlDisplay("+rcd+")"); - synchronized(mAudioFocusLock) { - synchronized(mRCStack) { - if ((rcd == null) || rcDisplayIsPluggedIn_syncRcStack(rcd)) { - return; - } - DisplayInfoForServer di = new DisplayInfoForServer(rcd, w, h); - if (!di.init()) { - if (DEBUG_RC) Log.e(TAG, " error registering RCD"); - return; - } - // add RCD to list of displays - mRcDisplays.add(di); - - // let all the remote control clients know there is a new display (so the remote - // control stack traversal order doesn't matter). - Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); - while(stackIterator.hasNext()) { - RemoteControlStackEntry rcse = stackIterator.next(); - if(rcse.mRcClient != null) { - try { - rcse.mRcClient.plugRemoteControlDisplay(rcd, w, h); - } catch (RemoteException e) { - Log.e(TAG, "Error connecting RCD to client: ", e); - } - } - } - - // we have a new display, of which all the clients are now aware: have it be updated - checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL); - } - } + mMediaFocusControl.registerRemoteControlDisplay(rcd, w, h); } - /** - * Unregister an IRemoteControlDisplay. - * No effect if the IRemoteControlDisplay hasn't been successfully registered. - * @see android.media.IAudioService#unregisterRemoteControlDisplay(android.media.IRemoteControlDisplay) - * @param rcd the IRemoteControlDisplay to unregister. No effect if null. - */ public void unregisterRemoteControlDisplay(IRemoteControlDisplay rcd) { - if (DEBUG_RC) Log.d(TAG, "<<< unregisterRemoteControlDisplay("+rcd+")"); - synchronized(mRCStack) { - if (rcd == null) { - return; - } - - boolean displayWasPluggedIn = false; - final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator(); - while (displayIterator.hasNext() && !displayWasPluggedIn) { - final DisplayInfoForServer di = (DisplayInfoForServer) displayIterator.next(); - if (di.mRcDisplay.asBinder().equals(rcd.asBinder())) { - displayWasPluggedIn = true; - di.release(); - displayIterator.remove(); - } - } - - if (displayWasPluggedIn) { - // disconnect this remote control display from all the clients, so the remote - // control stack traversal order doesn't matter - final Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); - while(stackIterator.hasNext()) { - final RemoteControlStackEntry rcse = stackIterator.next(); - if(rcse.mRcClient != null) { - try { - rcse.mRcClient.unplugRemoteControlDisplay(rcd); - } catch (RemoteException e) { - Log.e(TAG, "Error disconnecting remote control display to client: ", e); - } - } - } - } else { - if (DEBUG_RC) Log.w(TAG, " trying to unregister unregistered RCD"); - } - } + mMediaFocusControl.unregisterRemoteControlDisplay(rcd); } - /** - * Update the size of the artwork used by an IRemoteControlDisplay. - * @see android.media.IAudioService#remoteControlDisplayUsesBitmapSize(android.media.IRemoteControlDisplay, int, int) - * @param rcd the IRemoteControlDisplay with the new artwork size requirement - * @param w the maximum width of the expected bitmap. Negative or zero values indicate this - * display doesn't need to receive artwork. - * @param h the maximum height of the expected bitmap. Negative or zero values indicate this - * display doesn't need to receive artwork. - */ public void remoteControlDisplayUsesBitmapSize(IRemoteControlDisplay rcd, int w, int h) { - synchronized(mRCStack) { - final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator(); - boolean artworkSizeUpdate = false; - while (displayIterator.hasNext() && !artworkSizeUpdate) { - final DisplayInfoForServer di = (DisplayInfoForServer) displayIterator.next(); - if (di.mRcDisplay.asBinder().equals(rcd.asBinder())) { - if ((di.mArtworkExpectedWidth != w) || (di.mArtworkExpectedHeight != h)) { - di.mArtworkExpectedWidth = w; - di.mArtworkExpectedHeight = h; - artworkSizeUpdate = true; - } - } - } - if (artworkSizeUpdate) { - // RCD is currently plugged in and its artwork size has changed, notify all RCCs, - // stack traversal order doesn't matter - final Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); - while(stackIterator.hasNext()) { - final RemoteControlStackEntry rcse = stackIterator.next(); - if(rcse.mRcClient != null) { - try { - rcse.mRcClient.setBitmapSizeForDisplay(rcd, w, h); - } catch (RemoteException e) { - Log.e(TAG, "Error setting bitmap size for RCD on RCC: ", e); - } - } - } - } - } + mMediaFocusControl.remoteControlDisplayUsesBitmapSize(rcd, w, h); } - /** - * Controls whether a remote control display needs periodic checks of the RemoteControlClient - * playback position to verify that the estimated position has not drifted from the actual - * position. By default the check is not performed. - * The IRemoteControlDisplay must have been previously registered for this to have any effect. - * @param rcd the IRemoteControlDisplay for which the anti-drift mechanism will be enabled - * or disabled. Not null. - * @param wantsSync if true, RemoteControlClient instances which expose their playback position - * to the framework will regularly compare the estimated playback position with the actual - * position, and will update the IRemoteControlDisplay implementation whenever a drift is - * detected. - */ public void remoteControlDisplayWantsPlaybackPositionSync(IRemoteControlDisplay rcd, boolean wantsSync) { - synchronized(mRCStack) { - boolean rcdRegistered = false; - // store the information about this display - // (display stack traversal order doesn't matter). - final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator(); - while (displayIterator.hasNext()) { - final DisplayInfoForServer di = (DisplayInfoForServer) displayIterator.next(); - if (di.mRcDisplay.asBinder().equals(rcd.asBinder())) { - di.mWantsPositionSync = wantsSync; - rcdRegistered = true; - break; - } - } - if (!rcdRegistered) { - return; - } - // notify all current RemoteControlClients - // (stack traversal order doesn't matter as we notify all RCCs) - final Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); - while (stackIterator.hasNext()) { - final RemoteControlStackEntry rcse = stackIterator.next(); - if (rcse.mRcClient != null) { - try { - rcse.mRcClient.setWantsSyncForDisplay(rcd, wantsSync); - } catch (RemoteException e) { - Log.e(TAG, "Error setting position sync flag for RCD on RCC: ", e); - } - } - } - } + mMediaFocusControl.remoteControlDisplayWantsPlaybackPositionSync(rcd, wantsSync); } - public void setRemoteControlClientPlaybackPosition(int generationId, long timeMs) { - // ignore position change requests if invalid generation ID - synchronized(mRCStack) { - synchronized(mCurrentRcLock) { - if (mCurrentRcClientGen != generationId) { - return; - } - } - } - // discard any unprocessed seek request in the message queue, and replace with latest - sendMsg(mAudioHandler, MSG_RCC_SEEK_REQUEST, SENDMSG_REPLACE, generationId /* arg1 */, - 0 /* arg2 ignored*/, new Long(timeMs) /* obj */, 0 /* delay */); + public void registerMediaButtonEventReceiverForCalls(ComponentName c) { + mMediaFocusControl.registerMediaButtonEventReceiverForCalls(c); } - public void onSetRemoteControlClientPlaybackPosition(int generationId, long timeMs) { - if(DEBUG_RC) Log.d(TAG, "onSetRemoteControlClientPlaybackPosition(genId=" + generationId + - ", timeMs=" + timeMs + ")"); - synchronized(mRCStack) { - synchronized(mCurrentRcLock) { - if ((mCurrentRcClient != null) && (mCurrentRcClientGen == generationId)) { - // tell the current client to seek to the requested location - try { - mCurrentRcClient.seekTo(generationId, timeMs); - } catch (RemoteException e) { - Log.e(TAG, "Current valid remote client is dead: "+e); - mCurrentRcClient = null; - } - } - } - } + public void unregisterMediaButtonEventReceiverForCalls() { + mMediaFocusControl.unregisterMediaButtonEventReceiverForCalls(); } - public void setPlaybackInfoForRcc(int rccId, int what, int value) { - sendMsg(mAudioHandler, MSG_RCC_NEW_PLAYBACK_INFO, SENDMSG_QUEUE, - rccId /* arg1 */, what /* arg2 */, Integer.valueOf(value) /* obj */, 0 /* delay */); + public void registerMediaButtonIntent(PendingIntent pi, ComponentName c, IBinder token) { + mMediaFocusControl.registerMediaButtonIntent(pi, c, token); } - // handler for MSG_RCC_NEW_PLAYBACK_INFO - private void onNewPlaybackInfoForRcc(int rccId, int key, int value) { - if(DEBUG_RC) Log.d(TAG, "onNewPlaybackInfoForRcc(id=" + rccId + - ", what=" + key + ",val=" + value + ")"); - synchronized(mRCStack) { - // iterating from top of stack as playback information changes are more likely - // on entries at the top of the remote control stack - try { - for (int index = mRCStack.size()-1; index >= 0; index--) { - final RemoteControlStackEntry rcse = mRCStack.elementAt(index); - if (rcse.mRccId == rccId) { - switch (key) { - case RemoteControlClient.PLAYBACKINFO_PLAYBACK_TYPE: - rcse.mPlaybackType = value; - postReevaluateRemote(); - break; - case RemoteControlClient.PLAYBACKINFO_VOLUME: - rcse.mPlaybackVolume = value; - synchronized (mMainRemote) { - if (rccId == mMainRemote.mRccId) { - mMainRemote.mVolume = value; - mVolumePanel.postHasNewRemotePlaybackInfo(); - } - } - break; - case RemoteControlClient.PLAYBACKINFO_VOLUME_MAX: - rcse.mPlaybackVolumeMax = value; - synchronized (mMainRemote) { - if (rccId == mMainRemote.mRccId) { - mMainRemote.mVolumeMax = value; - mVolumePanel.postHasNewRemotePlaybackInfo(); - } - } - break; - case RemoteControlClient.PLAYBACKINFO_VOLUME_HANDLING: - rcse.mPlaybackVolumeHandling = value; - synchronized (mMainRemote) { - if (rccId == mMainRemote.mRccId) { - mMainRemote.mVolumeHandling = value; - mVolumePanel.postHasNewRemotePlaybackInfo(); - } - } - break; - case RemoteControlClient.PLAYBACKINFO_USES_STREAM: - rcse.mPlaybackStream = value; - break; - default: - Log.e(TAG, "unhandled key " + key + " for RCC " + rccId); - break; - } - return; - } - }//for - } catch (ArrayIndexOutOfBoundsException e) { - // not expected to happen, indicates improper concurrent modification - Log.e(TAG, "Wrong index mRCStack on onNewPlaybackInfoForRcc, lock error? ", e); - } - } + public void unregisterMediaButtonIntent(PendingIntent pi) { + mMediaFocusControl.unregisterMediaButtonIntent(pi); + } + + public int registerRemoteControlClient(PendingIntent mediaIntent, + IRemoteControlClient rcClient, String callingPckg) { + return mMediaFocusControl.registerRemoteControlClient(mediaIntent, rcClient, callingPckg); } - public void setPlaybackStateForRcc(int rccId, int state, long timeMs, float speed) { - sendMsg(mAudioHandler, MSG_RCC_NEW_PLAYBACK_STATE, SENDMSG_QUEUE, - rccId /* arg1 */, state /* arg2 */, - new RccPlaybackState(state, timeMs, speed) /* obj */, 0 /* delay */); + public void unregisterRemoteControlClient(PendingIntent mediaIntent, + IRemoteControlClient rcClient) { + mMediaFocusControl.unregisterRemoteControlClient(mediaIntent, rcClient); } - public void onNewPlaybackStateForRcc(int rccId, int state, RccPlaybackState newState) { - if(DEBUG_RC) Log.d(TAG, "onNewPlaybackStateForRcc(id=" + rccId + ", state=" + state - + ", time=" + newState.mPositionMs + ", speed=" + newState.mSpeed + ")"); - synchronized(mRCStack) { - // iterating from top of stack as playback information changes are more likely - // on entries at the top of the remote control stack - try { - for (int index = mRCStack.size()-1; index >= 0; index--) { - final RemoteControlStackEntry rcse = mRCStack.elementAt(index); - if (rcse.mRccId == rccId) { - rcse.mPlaybackState = newState; - synchronized (mMainRemote) { - if (rccId == mMainRemote.mRccId) { - mMainRemoteIsActive = isPlaystateActive(state); - postReevaluateRemote(); - } - } - // an RCC moving to a "playing" state should become the media button - // event receiver so it can be controlled, without requiring the - // app to re-register its receiver - if (isPlaystateActive(state)) { - postPromoteRcc(rccId); - } - } - }//for - } catch (ArrayIndexOutOfBoundsException e) { - // not expected to happen, indicates improper concurrent modification - Log.e(TAG, "Wrong index on mRCStack in onNewPlaybackStateForRcc, lock error? ", e); - } - } + public void setRemoteControlClientPlaybackPosition(int generationId, long timeMs) { + mMediaFocusControl.setRemoteControlClientPlaybackPosition(generationId, timeMs); } public void registerRemoteVolumeObserverForRcc(int rccId, IRemoteVolumeObserver rvo) { - sendMsg(mAudioHandler, MSG_RCC_NEW_VOLUME_OBS, SENDMSG_QUEUE, - rccId /* arg1 */, 0, rvo /* obj */, 0 /* delay */); + mMediaFocusControl.registerRemoteVolumeObserverForRcc(rccId, rvo); } - // handler for MSG_RCC_NEW_VOLUME_OBS - private void onRegisterVolumeObserverForRcc(int rccId, IRemoteVolumeObserver rvo) { - synchronized(mRCStack) { - // The stack traversal order doesn't matter because there is only one stack entry - // with this RCC ID, but the matching ID is more likely at the top of the stack, so - // start iterating from the top. - try { - for (int index = mRCStack.size()-1; index >= 0; index--) { - final RemoteControlStackEntry rcse = mRCStack.elementAt(index); - if (rcse.mRccId == rccId) { - rcse.mRemoteVolumeObs = rvo; - break; - } - } - } catch (ArrayIndexOutOfBoundsException e) { - // not expected to happen, indicates improper concurrent modification - Log.e(TAG, "Wrong index accessing media button stack, lock error? ", e); - } - } + public int getRemoteStreamVolume() { + return mMediaFocusControl.getRemoteStreamVolume(); } - /** - * Checks if a remote client is active on the supplied stream type. Update the remote stream - * volume state if found and playing - * @param streamType - * @return false if no remote playing is currently playing - */ - private boolean checkUpdateRemoteStateIfActive(int streamType) { - synchronized(mRCStack) { - // iterating from top of stack as active playback is more likely on entries at the top - try { - for (int index = mRCStack.size()-1; index >= 0; index--) { - final RemoteControlStackEntry rcse = mRCStack.elementAt(index); - if ((rcse.mPlaybackType == RemoteControlClient.PLAYBACK_TYPE_REMOTE) - && isPlaystateActive(rcse.mPlaybackState.mState) - && (rcse.mPlaybackStream == streamType)) { - if (DEBUG_RC) Log.d(TAG, "remote playback active on stream " + streamType - + ", vol =" + rcse.mPlaybackVolume); - synchronized (mMainRemote) { - mMainRemote.mRccId = rcse.mRccId; - mMainRemote.mVolume = rcse.mPlaybackVolume; - mMainRemote.mVolumeMax = rcse.mPlaybackVolumeMax; - mMainRemote.mVolumeHandling = rcse.mPlaybackVolumeHandling; - mMainRemoteIsActive = true; - } - return true; - } - } - } catch (ArrayIndexOutOfBoundsException e) { - // not expected to happen, indicates improper concurrent modification - Log.e(TAG, "Wrong index accessing RC stack, lock error? ", e); - } - } - synchronized (mMainRemote) { - mMainRemoteIsActive = false; - } - return false; + public int getRemoteStreamMaxVolume() { + return mMediaFocusControl.getRemoteStreamMaxVolume(); } - /** - * Returns true if the given playback state is considered "active", i.e. it describes a state - * where playback is happening, or about to - * @param playState the playback state to evaluate - * @return true if active, false otherwise (inactive or unknown) - */ - private static boolean isPlaystateActive(int playState) { - switch (playState) { - case RemoteControlClient.PLAYSTATE_PLAYING: - case RemoteControlClient.PLAYSTATE_BUFFERING: - case RemoteControlClient.PLAYSTATE_FAST_FORWARDING: - case RemoteControlClient.PLAYSTATE_REWINDING: - case RemoteControlClient.PLAYSTATE_SKIPPING_BACKWARDS: - case RemoteControlClient.PLAYSTATE_SKIPPING_FORWARDS: - return true; - default: - return false; - } + public void setRemoteStreamVolume(int index) { + mMediaFocusControl.setRemoteStreamVolume(index); } - private void adjustRemoteVolume(int streamType, int direction, int flags) { - int rccId = RemoteControlClient.RCSE_ID_UNREGISTERED; - boolean volFixed = false; - synchronized (mMainRemote) { - if (!mMainRemoteIsActive) { - if (DEBUG_VOL) Log.w(TAG, "adjustRemoteVolume didn't find an active client"); - return; - } - rccId = mMainRemote.mRccId; - volFixed = (mMainRemote.mVolumeHandling == - RemoteControlClient.PLAYBACK_VOLUME_FIXED); - } - // unlike "local" stream volumes, we can't compute the new volume based on the direction, - // we can only notify the remote that volume needs to be updated, and we'll get an async' - // update through setPlaybackInfoForRcc() - if (!volFixed) { - sendVolumeUpdateToRemote(rccId, direction); - } + public void setPlaybackStateForRcc(int rccId, int state, long timeMs, float speed) { + mMediaFocusControl.setPlaybackStateForRcc(rccId, state, timeMs, speed); + } - // fire up the UI - mVolumePanel.postRemoteVolumeChanged(streamType, flags); + public void setPlaybackInfoForRcc(int rccId, int what, int value) { + mMediaFocusControl.setPlaybackInfoForRcc(rccId, what, value); } - private void sendVolumeUpdateToRemote(int rccId, int direction) { - if (DEBUG_VOL) { Log.d(TAG, "sendVolumeUpdateToRemote(rccId="+rccId+" , dir="+direction); } - if (direction == 0) { - // only handling discrete events - return; - } - IRemoteVolumeObserver rvo = null; - synchronized (mRCStack) { - // The stack traversal order doesn't matter because there is only one stack entry - // with this RCC ID, but the matching ID is more likely at the top of the stack, so - // start iterating from the top. - try { - for (int index = mRCStack.size()-1; index >= 0; index--) { - final RemoteControlStackEntry rcse = mRCStack.elementAt(index); - //FIXME OPTIMIZE store this info in mMainRemote so we don't have to iterate? - if (rcse.mRccId == rccId) { - rvo = rcse.mRemoteVolumeObs; - break; - } - } - } catch (ArrayIndexOutOfBoundsException e) { - // not expected to happen, indicates improper concurrent modification - Log.e(TAG, "Wrong index accessing media button stack, lock error? ", e); - } - } - if (rvo != null) { - try { - rvo.dispatchRemoteVolumeUpdate(direction, -1); - } catch (RemoteException e) { - Log.e(TAG, "Error dispatching relative volume update", e); - } - } + public void dispatchMediaKeyEvent(KeyEvent keyEvent) { + mMediaFocusControl.dispatchMediaKeyEvent(keyEvent); } - public int getRemoteStreamMaxVolume() { - synchronized (mMainRemote) { - if (mMainRemote.mRccId == RemoteControlClient.RCSE_ID_UNREGISTERED) { - return 0; - } - return mMainRemote.mVolumeMax; - } + public void dispatchMediaKeyEventUnderWakelock(KeyEvent keyEvent) { + mMediaFocusControl.dispatchMediaKeyEventUnderWakelock(keyEvent); } - public int getRemoteStreamVolume() { - synchronized (mMainRemote) { - if (mMainRemote.mRccId == RemoteControlClient.RCSE_ID_UNREGISTERED) { - return 0; - } - return mMainRemote.mVolume; - } + //========================================================================================== + // Audio Focus + //========================================================================================== + public int requestAudioFocus(int mainStreamType, int durationHint, IBinder cb, + IAudioFocusDispatcher fd, String clientId, String callingPackageName) { + return mMediaFocusControl.requestAudioFocus(mainStreamType, durationHint, cb, fd, + clientId, callingPackageName); } - public void setRemoteStreamVolume(int vol) { - if (DEBUG_VOL) { Log.d(TAG, "setRemoteStreamVolume(vol="+vol+")"); } - int rccId = RemoteControlClient.RCSE_ID_UNREGISTERED; - synchronized (mMainRemote) { - if (mMainRemote.mRccId == RemoteControlClient.RCSE_ID_UNREGISTERED) { - return; - } - rccId = mMainRemote.mRccId; - } - IRemoteVolumeObserver rvo = null; - synchronized (mRCStack) { - // The stack traversal order doesn't matter because there is only one stack entry - // with this RCC ID, but the matching ID is more likely at the top of the stack, so - // start iterating from the top. - try { - for (int index = mRCStack.size()-1; index >= 0; index--) { - final RemoteControlStackEntry rcse = mRCStack.elementAt(index); - //FIXME OPTIMIZE store this info in mMainRemote so we don't have to iterate? - if (rcse.mRccId == rccId) { - rvo = rcse.mRemoteVolumeObs; - break; - } - } - } catch (ArrayIndexOutOfBoundsException e) { - // not expected to happen, indicates improper concurrent modification - Log.e(TAG, "Wrong index accessing media button stack, lock error? ", e); - } - } - if (rvo != null) { - try { - rvo.dispatchRemoteVolumeUpdate(0, vol); - } catch (RemoteException e) { - Log.e(TAG, "Error dispatching absolute volume update", e); - } - } + public int abandonAudioFocus(IAudioFocusDispatcher fd, String clientId) { + return mMediaFocusControl.abandonAudioFocus(fd, clientId); } - /** - * Call to make AudioService reevaluate whether it's in a mode where remote players should - * have their volume controlled. In this implementation this is only to reset whether - * VolumePanel should display remote volumes - */ - private void postReevaluateRemote() { - sendMsg(mAudioHandler, MSG_REEVALUATE_REMOTE, SENDMSG_QUEUE, 0, 0, null, 0); - } - - private void onReevaluateRemote() { - if (DEBUG_VOL) { Log.w(TAG, "onReevaluateRemote()"); } - // is there a registered RemoteControlClient that is handling remote playback - boolean hasRemotePlayback = false; - synchronized (mRCStack) { - // iteration stops when PLAYBACK_TYPE_REMOTE is found, so remote control stack - // traversal order doesn't matter - Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); - while(stackIterator.hasNext()) { - RemoteControlStackEntry rcse = stackIterator.next(); - if (rcse.mPlaybackType == RemoteControlClient.PLAYBACK_TYPE_REMOTE) { - hasRemotePlayback = true; - break; - } - } - } - synchronized (mMainRemote) { - if (mHasRemotePlayback != hasRemotePlayback) { - mHasRemotePlayback = hasRemotePlayback; - mVolumePanel.postRemoteSliderVisibility(hasRemotePlayback); - } - } + public void unregisterAudioFocusClient(String clientId) { + mMediaFocusControl.unregisterAudioFocusClient(clientId); } //========================================================================================== @@ -6687,14 +4499,20 @@ public class AudioService extends IAudioService.Stub implements OnFinished { protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG); - dumpFocusStack(pw); - dumpRCStack(pw); - dumpRCCStack(pw); - dumpRCDList(pw); + mMediaFocusControl.dump(pw); dumpStreamStates(pw); dumpRingerMode(pw); pw.println("\nAudio routes:"); pw.print(" mMainType=0x"); pw.println(Integer.toHexString(mCurAudioRoutes.mMainType)); pw.print(" mBluetoothName="); pw.println(mCurAudioRoutes.mBluetoothName); } + + // Inform AudioFlinger of our device's low RAM attribute + private static void readAndSetLowRamDevice() + { + int status = AudioSystem.setLowRamDevice(ActivityManager.isLowRamDeviceStatic()); + if (status != 0) { + Log.w(TAG, "AudioFlinger informed of device's low RAM attribute; status " + status); + } + } } diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java index d42bfd4..4805da5 100644 --- a/media/java/android/media/AudioSystem.java +++ b/media/java/android/media/AudioSystem.java @@ -403,4 +403,6 @@ public class AudioSystem public static native int getPrimaryOutputFrameCount(); public static native int getOutputLatency(int stream); + public static native int setLowRamDevice(boolean isLowRamDevice); + } diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl index e60ecc4..4a1646b 100644 --- a/media/java/android/media/IAudioService.aidl +++ b/media/java/android/media/IAudioService.aidl @@ -112,10 +112,10 @@ interface IAudioService { oneway void setRemoteSubmixOn(boolean on, int address); - int requestAudioFocus(int mainStreamType, int durationHint, IBinder cb, IAudioFocusDispatcher l, - String clientId, String callingPackageName); + int requestAudioFocus(int mainStreamType, int durationHint, IBinder cb, + IAudioFocusDispatcher fd, String clientId, String callingPackageName); - int abandonAudioFocus(IAudioFocusDispatcher l, String clientId); + int abandonAudioFocus(IAudioFocusDispatcher fd, String clientId); void unregisterAudioFocusClient(String clientId); diff --git a/media/java/android/media/MediaFocusControl.java b/media/java/android/media/MediaFocusControl.java new file mode 100644 index 0000000..e56baef --- /dev/null +++ b/media/java/android/media/MediaFocusControl.java @@ -0,0 +1,2455 @@ +/* + * 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.media; + +import android.app.Activity; +import android.app.AppOpsManager; +import android.app.KeyguardManager; +import android.app.PendingIntent; +import android.app.PendingIntent.CanceledException; +import android.app.PendingIntent.OnFinished; +import android.content.ActivityNotFoundException; +import android.content.BroadcastReceiver; +import android.content.ComponentName; +import android.content.ContentResolver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.PackageManager; +import android.os.Binder; +import android.os.Bundle; +import android.os.Handler; +import android.os.IBinder; +import android.os.Looper; +import android.os.Message; +import android.os.PowerManager; +import android.os.RemoteException; +import android.os.UserHandle; +import android.os.IBinder.DeathRecipient; +import android.provider.Settings; +import android.speech.RecognizerIntent; +import android.telephony.PhoneStateListener; +import android.telephony.TelephonyManager; +import android.util.Log; +import android.view.KeyEvent; + +import java.io.FileDescriptor; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.Stack; + +/** + * @hide + * + */ +public class MediaFocusControl implements OnFinished { + + private static final String TAG = "MediaFocusControl"; + + /** Debug remote control client/display feature */ + protected static final boolean DEBUG_RC = false; + /** Debug volumes */ + protected static final boolean DEBUG_VOL = false; + + /** Used to alter media button redirection when the phone is ringing. */ + private boolean mIsRinging = false; + + private final PowerManager.WakeLock mMediaEventWakeLock; + private final MediaEventHandler mEventHandler; + private final Context mContext; + private final ContentResolver mContentResolver; + private final VolumeController mVolumeController; + private final BroadcastReceiver mReceiver = new PackageIntentsReceiver(); + private final AppOpsManager mAppOps; + private final KeyguardManager mKeyguardManager; + private final AudioService mAudioService; + + protected MediaFocusControl(Looper looper, Context cntxt, + VolumeController volumeCtrl, AudioService as) { + mEventHandler = new MediaEventHandler(looper); + mContext = cntxt; + mContentResolver = mContext.getContentResolver(); + mVolumeController = volumeCtrl; + mAudioService = as; + + PowerManager pm = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE); + mMediaEventWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "handleMediaEvent"); + mMainRemote = new RemotePlaybackState(-1, + AudioService.getMaxStreamVolume(AudioManager.STREAM_MUSIC), + AudioService.getMaxStreamVolume(AudioManager.STREAM_MUSIC)); + + // Register for phone state monitoring + TelephonyManager tmgr = (TelephonyManager) + mContext.getSystemService(Context.TELEPHONY_SERVICE); + tmgr.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE); + + // Register for package addition/removal/change intent broadcasts + // for media button receiver persistence + IntentFilter pkgFilter = new IntentFilter(); + pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); + pkgFilter.addAction(Intent.ACTION_PACKAGE_ADDED); + pkgFilter.addAction(Intent.ACTION_PACKAGE_CHANGED); + pkgFilter.addAction(Intent.ACTION_PACKAGE_DATA_CLEARED); + pkgFilter.addDataScheme("package"); + mContext.registerReceiver(mReceiver, pkgFilter); + + mAppOps = (AppOpsManager)mContext.getSystemService(Context.APP_OPS_SERVICE); + mKeyguardManager = + (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE); + + mHasRemotePlayback = false; + mMainRemoteIsActive = false; + postReevaluateRemote(); + } + + // event handler messages + private static final int MSG_PERSIST_MEDIABUTTONRECEIVER = 0; + private static final int MSG_RCDISPLAY_CLEAR = 1; + private static final int MSG_RCDISPLAY_UPDATE = 2; + private static final int MSG_REEVALUATE_REMOTE = 3; + private static final int MSG_RCC_NEW_PLAYBACK_INFO = 4; + private static final int MSG_RCC_NEW_VOLUME_OBS = 5; + private static final int MSG_PROMOTE_RCC = 6; + private static final int MSG_RCC_NEW_PLAYBACK_STATE = 7; + private static final int MSG_RCC_SEEK_REQUEST = 8; + + // sendMsg() flags + /** If the msg is already queued, replace it with this one. */ + private static final int SENDMSG_REPLACE = 0; + /** If the msg is already queued, ignore this one and leave the old. */ + private static final int SENDMSG_NOOP = 1; + /** If the msg is already queued, queue this one and leave the old. */ + private static final int SENDMSG_QUEUE = 2; + + private static void sendMsg(Handler handler, int msg, + int existingMsgPolicy, int arg1, int arg2, Object obj, int delay) { + + if (existingMsgPolicy == SENDMSG_REPLACE) { + handler.removeMessages(msg); + } else if (existingMsgPolicy == SENDMSG_NOOP && handler.hasMessages(msg)) { + return; + } + + handler.sendMessageDelayed(handler.obtainMessage(msg, arg1, arg2, obj), delay); + } + + private class MediaEventHandler extends Handler { + MediaEventHandler(Looper looper) { + super(looper); + } + + @Override + public void handleMessage(Message msg) { + switch(msg.what) { + case MSG_PERSIST_MEDIABUTTONRECEIVER: + onHandlePersistMediaButtonReceiver( (ComponentName) msg.obj ); + break; + + case MSG_RCDISPLAY_CLEAR: + onRcDisplayClear(); + break; + + case MSG_RCDISPLAY_UPDATE: + // msg.obj is guaranteed to be non null + onRcDisplayUpdate( (RemoteControlStackEntry) msg.obj, msg.arg1); + break; + + case MSG_REEVALUATE_REMOTE: + onReevaluateRemote(); + break; + + case MSG_RCC_NEW_PLAYBACK_INFO: + onNewPlaybackInfoForRcc(msg.arg1 /* rccId */, msg.arg2 /* key */, + ((Integer)msg.obj).intValue() /* value */); + break; + case MSG_RCC_NEW_VOLUME_OBS: + onRegisterVolumeObserverForRcc(msg.arg1 /* rccId */, + (IRemoteVolumeObserver)msg.obj /* rvo */); + break; + case MSG_RCC_NEW_PLAYBACK_STATE: + onNewPlaybackStateForRcc(msg.arg1 /* rccId */, + msg.arg2 /* state */, + (RccPlaybackState)msg.obj /* newState */); + break; + case MSG_RCC_SEEK_REQUEST: + onSetRemoteControlClientPlaybackPosition( + msg.arg1 /* generationId */, ((Long)msg.obj).longValue() /* timeMs */); + + case MSG_PROMOTE_RCC: + onPromoteRcc(msg.arg1); + break; + } + } + } + + protected void dump(PrintWriter pw) { + dumpFocusStack(pw); + dumpRCStack(pw); + dumpRCCStack(pw); + dumpRCDList(pw); + } + + private class PackageIntentsReceiver extends BroadcastReceiver { + @Override + public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + if (action.equals(Intent.ACTION_PACKAGE_REMOVED) + || action.equals(Intent.ACTION_PACKAGE_DATA_CLEARED)) { + if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) { + // a package is being removed, not replaced + String packageName = intent.getData().getSchemeSpecificPart(); + if (packageName != null) { + cleanupMediaButtonReceiverForPackage(packageName, true); + } + } + } else if (action.equals(Intent.ACTION_PACKAGE_ADDED) + || action.equals(Intent.ACTION_PACKAGE_CHANGED)) { + String packageName = intent.getData().getSchemeSpecificPart(); + if (packageName != null) { + cleanupMediaButtonReceiverForPackage(packageName, false); + } + } + } + } + + //========================================================================================== + // AudioFocus + //========================================================================================== + + /* constant to identify focus stack entry that is used to hold the focus while the phone + * is ringing or during a call. Used by com.android.internal.telephony.CallManager when + * entering and exiting calls. + */ + protected final static String IN_VOICE_COMM_FOCUS_ID = "AudioFocus_For_Phone_Ring_And_Calls"; + + private final static Object mAudioFocusLock = new Object(); + + private final static Object mRingingLock = new Object(); + + private PhoneStateListener mPhoneStateListener = new PhoneStateListener() { + @Override + public void onCallStateChanged(int state, String incomingNumber) { + if (state == TelephonyManager.CALL_STATE_RINGING) { + //Log.v(TAG, " CALL_STATE_RINGING"); + synchronized(mRingingLock) { + mIsRinging = true; + } + } else if ((state == TelephonyManager.CALL_STATE_OFFHOOK) + || (state == TelephonyManager.CALL_STATE_IDLE)) { + synchronized(mRingingLock) { + mIsRinging = false; + } + } + } + }; + + /** + * Discard the current audio focus owner. + * Notify top of audio focus stack that it lost focus (regardless of possibility to reassign + * focus), remove it from the stack, and clear the remote control display. + */ + protected void discardAudioFocusOwner() { + synchronized(mAudioFocusLock) { + if (!mFocusStack.empty() && (mFocusStack.peek().mFocusDispatcher != null)) { + // notify the current focus owner it lost focus after removing it from stack + FocusStackEntry focusOwner = mFocusStack.pop(); + try { + focusOwner.mFocusDispatcher.dispatchAudioFocusChange( + AudioManager.AUDIOFOCUS_LOSS, focusOwner.mClientId); + } catch (RemoteException e) { + Log.e(TAG, "Failure to signal loss of audio focus due to "+ e); + e.printStackTrace(); + } + focusOwner.unlinkToDeath(); + // clear RCD + synchronized(mRCStack) { + clearRemoteControlDisplay_syncAfRcs(); + } + } + } + } + + private void notifyTopOfAudioFocusStack() { + // notify the top of the stack it gained focus + if (!mFocusStack.empty() && (mFocusStack.peek().mFocusDispatcher != null)) { + if (canReassignAudioFocus()) { + try { + mFocusStack.peek().mFocusDispatcher.dispatchAudioFocusChange( + AudioManager.AUDIOFOCUS_GAIN, mFocusStack.peek().mClientId); + } catch (RemoteException e) { + Log.e(TAG, "Failure to signal gain of audio control focus due to "+ e); + e.printStackTrace(); + } + } + } + } + + private static class FocusStackEntry { + public int mStreamType = -1;// no stream type + public IAudioFocusDispatcher mFocusDispatcher = null; + public IBinder mSourceRef = null; + public String mClientId; + public int mFocusChangeType; + public AudioFocusDeathHandler mHandler; + public String mPackageName; + public int mCallingUid; + + public FocusStackEntry() { + } + + public FocusStackEntry(int streamType, int duration, + IAudioFocusDispatcher afl, IBinder source, String id, AudioFocusDeathHandler hdlr, + String pn, int uid) { + mStreamType = streamType; + mFocusDispatcher = afl; + mSourceRef = source; + mClientId = id; + mFocusChangeType = duration; + mHandler = hdlr; + mPackageName = pn; + mCallingUid = uid; + } + + public void unlinkToDeath() { + try { + if (mSourceRef != null && mHandler != null) { + mSourceRef.unlinkToDeath(mHandler, 0); + mHandler = null; + } + } catch (java.util.NoSuchElementException e) { + Log.e(TAG, "Encountered " + e + " in FocusStackEntry.unlinkToDeath()"); + } + } + + @Override + protected void finalize() throws Throwable { + unlinkToDeath(); // unlink exception handled inside method + super.finalize(); + } + } + + private final Stack<FocusStackEntry> mFocusStack = new Stack<FocusStackEntry>(); + + /** + * Helper function: + * Display in the log the current entries in the audio focus stack + */ + private void dumpFocusStack(PrintWriter pw) { + pw.println("\nAudio Focus stack entries (last is top of stack):"); + synchronized(mAudioFocusLock) { + Iterator<FocusStackEntry> stackIterator = mFocusStack.iterator(); + while(stackIterator.hasNext()) { + FocusStackEntry fse = stackIterator.next(); + pw.println(" source:" + fse.mSourceRef + + " -- pack: " + fse.mPackageName + + " -- client: " + fse.mClientId + + " -- duration: " + fse.mFocusChangeType + + " -- uid: " + fse.mCallingUid + + " -- stream: " + fse.mStreamType); + } + } + } + + /** + * Helper function: + * Called synchronized on mAudioFocusLock + * Remove a focus listener from the focus stack. + * @param clientToRemove the focus listener + * @param signal if true and the listener was at the top of the focus stack, i.e. it was holding + * focus, notify the next item in the stack it gained focus. + */ + private void removeFocusStackEntry(String clientToRemove, boolean signal) { + // is the current top of the focus stack abandoning focus? (because of request, not death) + if (!mFocusStack.empty() && mFocusStack.peek().mClientId.equals(clientToRemove)) + { + //Log.i(TAG, " removeFocusStackEntry() removing top of stack"); + FocusStackEntry fse = mFocusStack.pop(); + fse.unlinkToDeath(); + if (signal) { + // notify the new top of the stack it gained focus + notifyTopOfAudioFocusStack(); + // there's a new top of the stack, let the remote control know + synchronized(mRCStack) { + checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL); + } + } + } else { + // focus is abandoned by a client that's not at the top of the stack, + // no need to update focus. + // (using an iterator on the stack so we can safely remove an entry after having + // evaluated it, traversal order doesn't matter here) + Iterator<FocusStackEntry> stackIterator = mFocusStack.iterator(); + while(stackIterator.hasNext()) { + FocusStackEntry fse = (FocusStackEntry)stackIterator.next(); + if(fse.mClientId.equals(clientToRemove)) { + Log.i(TAG, " AudioFocus abandonAudioFocus(): removing entry for " + + fse.mClientId); + stackIterator.remove(); + fse.unlinkToDeath(); + } + } + } + } + + /** + * Helper function: + * Called synchronized on mAudioFocusLock + * Remove focus listeners from the focus stack for a particular client when it has died. + */ + private void removeFocusStackEntryForClient(IBinder cb) { + // is the owner of the audio focus part of the client to remove? + boolean isTopOfStackForClientToRemove = !mFocusStack.isEmpty() && + mFocusStack.peek().mSourceRef.equals(cb); + // (using an iterator on the stack so we can safely remove an entry after having + // evaluated it, traversal order doesn't matter here) + Iterator<FocusStackEntry> stackIterator = mFocusStack.iterator(); + while(stackIterator.hasNext()) { + FocusStackEntry fse = (FocusStackEntry)stackIterator.next(); + if(fse.mSourceRef.equals(cb)) { + Log.i(TAG, " AudioFocus abandonAudioFocus(): removing entry for " + + fse.mClientId); + stackIterator.remove(); + // the client just died, no need to unlink to its death + } + } + if (isTopOfStackForClientToRemove) { + // we removed an entry at the top of the stack: + // notify the new top of the stack it gained focus. + notifyTopOfAudioFocusStack(); + // there's a new top of the stack, let the remote control know + synchronized(mRCStack) { + checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL); + } + } + } + + /** + * Helper function: + * Returns true if the system is in a state where the focus can be reevaluated, false otherwise. + */ + private boolean canReassignAudioFocus() { + // focus requests are rejected during a phone call or when the phone is ringing + // this is equivalent to IN_VOICE_COMM_FOCUS_ID having the focus + if (!mFocusStack.isEmpty() && IN_VOICE_COMM_FOCUS_ID.equals(mFocusStack.peek().mClientId)) { + return false; + } + return true; + } + + /** + * Inner class to monitor audio focus client deaths, and remove them from the audio focus + * stack if necessary. + */ + private class AudioFocusDeathHandler implements IBinder.DeathRecipient { + private IBinder mCb; // To be notified of client's death + + AudioFocusDeathHandler(IBinder cb) { + mCb = cb; + } + + public void binderDied() { + synchronized(mAudioFocusLock) { + Log.w(TAG, " AudioFocus audio focus client died"); + removeFocusStackEntryForClient(mCb); + } + } + + public IBinder getBinder() { + return mCb; + } + } + + + /** @see AudioManager#requestAudioFocus(AudioManager.OnAudioFocusChangeListener, int, int) */ + protected int requestAudioFocus(int mainStreamType, int focusChangeHint, IBinder cb, + IAudioFocusDispatcher fd, String clientId, String callingPackageName) { + Log.i(TAG, " AudioFocus requestAudioFocus() from " + clientId); + // the main stream type for the audio focus request is currently not used. It may + // potentially be used to handle multiple stream type-dependent audio focuses. + + // we need a valid binder callback for clients + if (!cb.pingBinder()) { + Log.e(TAG, " AudioFocus DOA client for requestAudioFocus(), aborting."); + return AudioManager.AUDIOFOCUS_REQUEST_FAILED; + } + + if (mAppOps.noteOp(AppOpsManager.OP_TAKE_AUDIO_FOCUS, Binder.getCallingUid(), + callingPackageName) != AppOpsManager.MODE_ALLOWED) { + return AudioManager.AUDIOFOCUS_REQUEST_FAILED; + } + + synchronized(mAudioFocusLock) { + if (!canReassignAudioFocus()) { + return AudioManager.AUDIOFOCUS_REQUEST_FAILED; + } + + // handle the potential premature death of the new holder of the focus + // (premature death == death before abandoning focus) + // Register for client death notification + AudioFocusDeathHandler afdh = new AudioFocusDeathHandler(cb); + try { + cb.linkToDeath(afdh, 0); + } catch (RemoteException e) { + // client has already died! + Log.w(TAG, "AudioFocus requestAudioFocus() could not link to "+cb+" binder death"); + return AudioManager.AUDIOFOCUS_REQUEST_FAILED; + } + + if (!mFocusStack.empty() && mFocusStack.peek().mClientId.equals(clientId)) { + // if focus is already owned by this client and the reason for acquiring the focus + // hasn't changed, don't do anything + if (mFocusStack.peek().mFocusChangeType == focusChangeHint) { + // unlink death handler so it can be gc'ed. + // linkToDeath() creates a JNI global reference preventing collection. + cb.unlinkToDeath(afdh, 0); + return AudioManager.AUDIOFOCUS_REQUEST_GRANTED; + } + // the reason for the audio focus request has changed: remove the current top of + // stack and respond as if we had a new focus owner + FocusStackEntry fse = mFocusStack.pop(); + fse.unlinkToDeath(); + } + + // notify current top of stack it is losing focus + if (!mFocusStack.empty() && (mFocusStack.peek().mFocusDispatcher != null)) { + try { + mFocusStack.peek().mFocusDispatcher.dispatchAudioFocusChange( + -1 * focusChangeHint, // loss and gain codes are inverse of each other + mFocusStack.peek().mClientId); + } catch (RemoteException e) { + Log.e(TAG, " Failure to signal loss of focus due to "+ e); + e.printStackTrace(); + } + } + + // focus requester might already be somewhere below in the stack, remove it + removeFocusStackEntry(clientId, false /* signal */); + + // push focus requester at the top of the audio focus stack + mFocusStack.push(new FocusStackEntry(mainStreamType, focusChangeHint, fd, cb, + clientId, afdh, callingPackageName, Binder.getCallingUid())); + + // there's a new top of the stack, let the remote control know + synchronized(mRCStack) { + checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL); + } + }//synchronized(mAudioFocusLock) + + return AudioManager.AUDIOFOCUS_REQUEST_GRANTED; + } + + /** @see AudioManager#abandonAudioFocus(AudioManager.OnAudioFocusChangeListener) */ + protected int abandonAudioFocus(IAudioFocusDispatcher fl, String clientId) { + Log.i(TAG, " AudioFocus abandonAudioFocus() from " + clientId); + try { + // this will take care of notifying the new focus owner if needed + synchronized(mAudioFocusLock) { + removeFocusStackEntry(clientId, true); + } + } catch (java.util.ConcurrentModificationException cme) { + // Catching this exception here is temporary. It is here just to prevent + // a crash seen when the "Silent" notification is played. This is believed to be fixed + // but this try catch block is left just to be safe. + Log.e(TAG, "FATAL EXCEPTION AudioFocus abandonAudioFocus() caused " + cme); + cme.printStackTrace(); + } + + return AudioManager.AUDIOFOCUS_REQUEST_GRANTED; + } + + + protected void unregisterAudioFocusClient(String clientId) { + synchronized(mAudioFocusLock) { + removeFocusStackEntry(clientId, false); + } + } + + + //========================================================================================== + // RemoteControl + //========================================================================================== + protected void dispatchMediaKeyEvent(KeyEvent keyEvent) { + filterMediaKeyEvent(keyEvent, false /*needWakeLock*/); + } + + protected void dispatchMediaKeyEventUnderWakelock(KeyEvent keyEvent) { + filterMediaKeyEvent(keyEvent, true /*needWakeLock*/); + } + + private void filterMediaKeyEvent(KeyEvent keyEvent, boolean needWakeLock) { + // sanity check on the incoming key event + if (!isValidMediaKeyEvent(keyEvent)) { + Log.e(TAG, "not dispatching invalid media key event " + keyEvent); + return; + } + // event filtering for telephony + synchronized(mRingingLock) { + synchronized(mRCStack) { + if ((mMediaReceiverForCalls != null) && + (mIsRinging || (mAudioService.getMode() == AudioSystem.MODE_IN_CALL))) { + dispatchMediaKeyEventForCalls(keyEvent, needWakeLock); + return; + } + } + } + // event filtering based on voice-based interactions + if (isValidVoiceInputKeyCode(keyEvent.getKeyCode())) { + filterVoiceInputKeyEvent(keyEvent, needWakeLock); + } else { + dispatchMediaKeyEvent(keyEvent, needWakeLock); + } + } + + /** + * Handles the dispatching of the media button events to the telephony package. + * Precondition: mMediaReceiverForCalls != null + * @param keyEvent a non-null KeyEvent whose key code is one of the supported media buttons + * @param needWakeLock true if a PARTIAL_WAKE_LOCK needs to be held while this key event + * is dispatched. + */ + private void dispatchMediaKeyEventForCalls(KeyEvent keyEvent, boolean needWakeLock) { + Intent keyIntent = new Intent(Intent.ACTION_MEDIA_BUTTON, null); + keyIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent); + keyIntent.setPackage(mMediaReceiverForCalls.getPackageName()); + if (needWakeLock) { + mMediaEventWakeLock.acquire(); + keyIntent.putExtra(EXTRA_WAKELOCK_ACQUIRED, WAKELOCK_RELEASE_ON_FINISHED); + } + final long ident = Binder.clearCallingIdentity(); + try { + mContext.sendOrderedBroadcastAsUser(keyIntent, UserHandle.ALL, + null, mKeyEventDone, mEventHandler, Activity.RESULT_OK, null, null); + } finally { + Binder.restoreCallingIdentity(ident); + } + } + + /** + * Handles the dispatching of the media button events to one of the registered listeners, + * or if there was none, broadcast an ACTION_MEDIA_BUTTON intent to the rest of the system. + * @param keyEvent a non-null KeyEvent whose key code is one of the supported media buttons + * @param needWakeLock true if a PARTIAL_WAKE_LOCK needs to be held while this key event + * is dispatched. + */ + private void dispatchMediaKeyEvent(KeyEvent keyEvent, boolean needWakeLock) { + if (needWakeLock) { + mMediaEventWakeLock.acquire(); + } + Intent keyIntent = new Intent(Intent.ACTION_MEDIA_BUTTON, null); + keyIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent); + synchronized(mRCStack) { + if (!mRCStack.empty()) { + // send the intent that was registered by the client + try { + mRCStack.peek().mMediaIntent.send(mContext, + needWakeLock ? WAKELOCK_RELEASE_ON_FINISHED : 0 /*code*/, + keyIntent, this, mEventHandler); + } catch (CanceledException e) { + Log.e(TAG, "Error sending pending intent " + mRCStack.peek()); + e.printStackTrace(); + } + } else { + // legacy behavior when nobody registered their media button event receiver + // through AudioManager + if (needWakeLock) { + keyIntent.putExtra(EXTRA_WAKELOCK_ACQUIRED, WAKELOCK_RELEASE_ON_FINISHED); + } + final long ident = Binder.clearCallingIdentity(); + try { + mContext.sendOrderedBroadcastAsUser(keyIntent, UserHandle.ALL, + null, mKeyEventDone, + mEventHandler, Activity.RESULT_OK, null, null); + } finally { + Binder.restoreCallingIdentity(ident); + } + } + } + } + + /** + * The different actions performed in response to a voice button key event. + */ + private final static int VOICEBUTTON_ACTION_DISCARD_CURRENT_KEY_PRESS = 1; + private final static int VOICEBUTTON_ACTION_START_VOICE_INPUT = 2; + private final static int VOICEBUTTON_ACTION_SIMULATE_KEY_PRESS = 3; + + private final Object mVoiceEventLock = new Object(); + private boolean mVoiceButtonDown; + private boolean mVoiceButtonHandled; + + /** + * Filter key events that may be used for voice-based interactions + * @param keyEvent a non-null KeyEvent whose key code is that of one of the supported + * media buttons that can be used to trigger voice-based interactions. + * @param needWakeLock true if a PARTIAL_WAKE_LOCK needs to be held while this key event + * is dispatched. + */ + private void filterVoiceInputKeyEvent(KeyEvent keyEvent, boolean needWakeLock) { + if (DEBUG_RC) { + Log.v(TAG, "voice input key event: " + keyEvent + ", needWakeLock=" + needWakeLock); + } + + int voiceButtonAction = VOICEBUTTON_ACTION_DISCARD_CURRENT_KEY_PRESS; + int keyAction = keyEvent.getAction(); + synchronized (mVoiceEventLock) { + if (keyAction == KeyEvent.ACTION_DOWN) { + if (keyEvent.getRepeatCount() == 0) { + // initial down + mVoiceButtonDown = true; + mVoiceButtonHandled = false; + } else if (mVoiceButtonDown && !mVoiceButtonHandled + && (keyEvent.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0) { + // long-press, start voice-based interactions + mVoiceButtonHandled = true; + voiceButtonAction = VOICEBUTTON_ACTION_START_VOICE_INPUT; + } + } else if (keyAction == KeyEvent.ACTION_UP) { + if (mVoiceButtonDown) { + // voice button up + mVoiceButtonDown = false; + if (!mVoiceButtonHandled && !keyEvent.isCanceled()) { + voiceButtonAction = VOICEBUTTON_ACTION_SIMULATE_KEY_PRESS; + } + } + } + }//synchronized (mVoiceEventLock) + + // take action after media button event filtering for voice-based interactions + switch (voiceButtonAction) { + case VOICEBUTTON_ACTION_DISCARD_CURRENT_KEY_PRESS: + if (DEBUG_RC) Log.v(TAG, " ignore key event"); + break; + case VOICEBUTTON_ACTION_START_VOICE_INPUT: + if (DEBUG_RC) Log.v(TAG, " start voice-based interactions"); + // then start the voice-based interactions + startVoiceBasedInteractions(needWakeLock); + break; + case VOICEBUTTON_ACTION_SIMULATE_KEY_PRESS: + if (DEBUG_RC) Log.v(TAG, " send simulated key event, wakelock=" + needWakeLock); + sendSimulatedMediaButtonEvent(keyEvent, needWakeLock); + break; + } + } + + private void sendSimulatedMediaButtonEvent(KeyEvent originalKeyEvent, boolean needWakeLock) { + // send DOWN event + KeyEvent keyEvent = KeyEvent.changeAction(originalKeyEvent, KeyEvent.ACTION_DOWN); + dispatchMediaKeyEvent(keyEvent, needWakeLock); + // send UP event + keyEvent = KeyEvent.changeAction(originalKeyEvent, KeyEvent.ACTION_UP); + dispatchMediaKeyEvent(keyEvent, needWakeLock); + + } + + + private static boolean isValidMediaKeyEvent(KeyEvent keyEvent) { + if (keyEvent == null) { + return false; + } + final int keyCode = keyEvent.getKeyCode(); + switch (keyCode) { + case KeyEvent.KEYCODE_MUTE: + case KeyEvent.KEYCODE_HEADSETHOOK: + case KeyEvent.KEYCODE_MEDIA_PLAY: + case KeyEvent.KEYCODE_MEDIA_PAUSE: + case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE: + case KeyEvent.KEYCODE_MEDIA_STOP: + case KeyEvent.KEYCODE_MEDIA_NEXT: + case KeyEvent.KEYCODE_MEDIA_PREVIOUS: + case KeyEvent.KEYCODE_MEDIA_REWIND: + case KeyEvent.KEYCODE_MEDIA_RECORD: + case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: + case KeyEvent.KEYCODE_MEDIA_CLOSE: + case KeyEvent.KEYCODE_MEDIA_EJECT: + case KeyEvent.KEYCODE_MEDIA_AUDIO_TRACK: + break; + default: + return false; + } + return true; + } + + /** + * Checks whether the given key code is one that can trigger the launch of voice-based + * interactions. + * @param keyCode the key code associated with the key event + * @return true if the key is one of the supported voice-based interaction triggers + */ + private static boolean isValidVoiceInputKeyCode(int keyCode) { + if (keyCode == KeyEvent.KEYCODE_HEADSETHOOK) { + return true; + } else { + return false; + } + } + + /** + * Tell the system to start voice-based interactions / voice commands + */ + private void startVoiceBasedInteractions(boolean needWakeLock) { + Intent voiceIntent = null; + // select which type of search to launch: + // - screen on and device unlocked: action is ACTION_WEB_SEARCH + // - device locked or screen off: action is ACTION_VOICE_SEARCH_HANDS_FREE + // with EXTRA_SECURE set to true if the device is securely locked + PowerManager pm = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE); + boolean isLocked = mKeyguardManager != null && mKeyguardManager.isKeyguardLocked(); + if (!isLocked && pm.isScreenOn()) { + voiceIntent = new Intent(android.speech.RecognizerIntent.ACTION_WEB_SEARCH); + Log.i(TAG, "voice-based interactions: about to use ACTION_WEB_SEARCH"); + } else { + voiceIntent = new Intent(RecognizerIntent.ACTION_VOICE_SEARCH_HANDS_FREE); + voiceIntent.putExtra(RecognizerIntent.EXTRA_SECURE, + isLocked && mKeyguardManager.isKeyguardSecure()); + Log.i(TAG, "voice-based interactions: about to use ACTION_VOICE_SEARCH_HANDS_FREE"); + } + // start the search activity + if (needWakeLock) { + mMediaEventWakeLock.acquire(); + } + final long identity = Binder.clearCallingIdentity(); + try { + if (voiceIntent != null) { + voiceIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK + | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); + mContext.startActivityAsUser(voiceIntent, UserHandle.CURRENT); + } + } catch (ActivityNotFoundException e) { + Log.w(TAG, "No activity for search: " + e); + } finally { + Binder.restoreCallingIdentity(identity); + if (needWakeLock) { + mMediaEventWakeLock.release(); + } + } + } + + private static final int WAKELOCK_RELEASE_ON_FINISHED = 1980; //magic number + + // only set when wakelock was acquired, no need to check value when received + private static final String EXTRA_WAKELOCK_ACQUIRED = + "android.media.AudioService.WAKELOCK_ACQUIRED"; + + public void onSendFinished(PendingIntent pendingIntent, Intent intent, + int resultCode, String resultData, Bundle resultExtras) { + if (resultCode == WAKELOCK_RELEASE_ON_FINISHED) { + mMediaEventWakeLock.release(); + } + } + + BroadcastReceiver mKeyEventDone = new BroadcastReceiver() { + public void onReceive(Context context, Intent intent) { + if (intent == null) { + return; + } + Bundle extras = intent.getExtras(); + if (extras == null) { + return; + } + if (extras.containsKey(EXTRA_WAKELOCK_ACQUIRED)) { + mMediaEventWakeLock.release(); + } + } + }; + + /** + * Synchronization on mCurrentRcLock always inside a block synchronized on mRCStack + */ + private final Object mCurrentRcLock = new Object(); + /** + * The one remote control client which will receive a request for display information. + * This object may be null. + * Access protected by mCurrentRcLock. + */ + private IRemoteControlClient mCurrentRcClient = null; + + private final static int RC_INFO_NONE = 0; + private final static int RC_INFO_ALL = + RemoteControlClient.FLAG_INFORMATION_REQUEST_ALBUM_ART | + RemoteControlClient.FLAG_INFORMATION_REQUEST_KEY_MEDIA | + RemoteControlClient.FLAG_INFORMATION_REQUEST_METADATA | + RemoteControlClient.FLAG_INFORMATION_REQUEST_PLAYSTATE; + + /** + * A monotonically increasing generation counter for mCurrentRcClient. + * Only accessed with a lock on mCurrentRcLock. + * No value wrap-around issues as we only act on equal values. + */ + private int mCurrentRcClientGen = 0; + + /** + * Inner class to monitor remote control client deaths, and remove the client for the + * remote control stack if necessary. + */ + private class RcClientDeathHandler implements IBinder.DeathRecipient { + final private IBinder mCb; // To be notified of client's death + final private PendingIntent mMediaIntent; + + RcClientDeathHandler(IBinder cb, PendingIntent pi) { + mCb = cb; + mMediaIntent = pi; + } + + public void binderDied() { + Log.w(TAG, " RemoteControlClient died"); + // remote control client died, make sure the displays don't use it anymore + // by setting its remote control client to null + registerRemoteControlClient(mMediaIntent, null/*rcClient*/, null/*ignored*/); + // the dead client was maybe handling remote playback, reevaluate + postReevaluateRemote(); + } + + public IBinder getBinder() { + return mCb; + } + } + + /** + * A global counter for RemoteControlClient identifiers + */ + private static int sLastRccId = 0; + + private class RemotePlaybackState { + int mRccId; + int mVolume; + int mVolumeMax; + int mVolumeHandling; + + private RemotePlaybackState(int id, int vol, int volMax) { + mRccId = id; + mVolume = vol; + mVolumeMax = volMax; + mVolumeHandling = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME_HANDLING; + } + } + + /** + * Internal cache for the playback information of the RemoteControlClient whose volume gets to + * be controlled by the volume keys ("main"), so we don't have to iterate over the RC stack + * every time we need this info. + */ + private RemotePlaybackState mMainRemote; + /** + * Indicates whether the "main" RemoteControlClient is considered active. + * Use synchronized on mMainRemote. + */ + private boolean mMainRemoteIsActive; + /** + * Indicates whether there is remote playback going on. True even if there is no "active" + * remote playback (mMainRemoteIsActive is false), but a RemoteControlClient has declared it + * handles remote playback. + * Use synchronized on mMainRemote. + */ + private boolean mHasRemotePlayback; + + private static class RccPlaybackState { + public int mState; + public long mPositionMs; + public float mSpeed; + + public RccPlaybackState(int state, long positionMs, float speed) { + mState = state; + mPositionMs = positionMs; + mSpeed = speed; + } + + public void reset() { + mState = RemoteControlClient.PLAYSTATE_STOPPED; + mPositionMs = RemoteControlClient.PLAYBACK_POSITION_INVALID; + mSpeed = RemoteControlClient.PLAYBACK_SPEED_1X; + } + + @Override + public String toString() { + return stateToString() + ", " + posToString() + ", " + mSpeed + "X"; + } + + private String posToString() { + if (mPositionMs == RemoteControlClient.PLAYBACK_POSITION_INVALID) { + return "PLAYBACK_POSITION_INVALID"; + } else if (mPositionMs == RemoteControlClient.PLAYBACK_POSITION_ALWAYS_UNKNOWN) { + return "PLAYBACK_POSITION_ALWAYS_UNKNOWN"; + } else { + return (String.valueOf(mPositionMs) + "ms"); + } + } + + private String stateToString() { + switch (mState) { + case RemoteControlClient.PLAYSTATE_NONE: + return "PLAYSTATE_NONE"; + case RemoteControlClient.PLAYSTATE_STOPPED: + return "PLAYSTATE_STOPPED"; + case RemoteControlClient.PLAYSTATE_PAUSED: + return "PLAYSTATE_PAUSED"; + case RemoteControlClient.PLAYSTATE_PLAYING: + return "PLAYSTATE_PLAYING"; + case RemoteControlClient.PLAYSTATE_FAST_FORWARDING: + return "PLAYSTATE_FAST_FORWARDING"; + case RemoteControlClient.PLAYSTATE_REWINDING: + return "PLAYSTATE_REWINDING"; + case RemoteControlClient.PLAYSTATE_SKIPPING_FORWARDS: + return "PLAYSTATE_SKIPPING_FORWARDS"; + case RemoteControlClient.PLAYSTATE_SKIPPING_BACKWARDS: + return "PLAYSTATE_SKIPPING_BACKWARDS"; + case RemoteControlClient.PLAYSTATE_BUFFERING: + return "PLAYSTATE_BUFFERING"; + case RemoteControlClient.PLAYSTATE_ERROR: + return "PLAYSTATE_ERROR"; + default: + return "[invalid playstate]"; + } + } + } + + protected static class RemoteControlStackEntry implements DeathRecipient { + public int mRccId = RemoteControlClient.RCSE_ID_UNREGISTERED; + final public MediaFocusControl mController; + /** + * The target for the ACTION_MEDIA_BUTTON events. + * Always non null. + */ + final public PendingIntent mMediaIntent; + /** + * The registered media button event receiver. + * Always non null. + */ + final public ComponentName mReceiverComponent; + public IBinder mToken; + public String mCallingPackageName; + public int mCallingUid; + /** + * Provides access to the information to display on the remote control. + * May be null (when a media button event receiver is registered, + * but no remote control client has been registered) */ + public IRemoteControlClient mRcClient; + public RcClientDeathHandler mRcClientDeathHandler; + /** + * Information only used for non-local playback + */ + public int mPlaybackType; + public int mPlaybackVolume; + public int mPlaybackVolumeMax; + public int mPlaybackVolumeHandling; + public int mPlaybackStream; + public RccPlaybackState mPlaybackState; + public IRemoteVolumeObserver mRemoteVolumeObs; + + public void resetPlaybackInfo() { + mPlaybackType = RemoteControlClient.PLAYBACK_TYPE_LOCAL; + mPlaybackVolume = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME; + mPlaybackVolumeMax = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME; + mPlaybackVolumeHandling = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME_HANDLING; + mPlaybackStream = AudioManager.STREAM_MUSIC; + mPlaybackState.reset(); + mRemoteVolumeObs = null; + } + + /** precondition: mediaIntent != null */ + public RemoteControlStackEntry(MediaFocusControl controller, PendingIntent mediaIntent, + ComponentName eventReceiver, IBinder token) { + mController = controller; + mMediaIntent = mediaIntent; + mReceiverComponent = eventReceiver; + mToken = token; + mCallingUid = -1; + mRcClient = null; + mRccId = ++sLastRccId; + mPlaybackState = new RccPlaybackState( + RemoteControlClient.PLAYSTATE_STOPPED, + RemoteControlClient.PLAYBACK_POSITION_INVALID, + RemoteControlClient.PLAYBACK_SPEED_1X); + + resetPlaybackInfo(); + if (mToken != null) { + try { + mToken.linkToDeath(this, 0); + } catch (RemoteException e) { + mController.mEventHandler.post(new Runnable() { + @Override public void run() { + mController.unregisterMediaButtonIntent(mMediaIntent); + } + }); + } + } + } + + public void unlinkToRcClientDeath() { + if ((mRcClientDeathHandler != null) && (mRcClientDeathHandler.mCb != null)) { + try { + mRcClientDeathHandler.mCb.unlinkToDeath(mRcClientDeathHandler, 0); + mRcClientDeathHandler = null; + } catch (java.util.NoSuchElementException e) { + // not much we can do here + Log.e(TAG, "Encountered " + e + " in unlinkToRcClientDeath()"); + e.printStackTrace(); + } + } + } + + public void destroy() { + unlinkToRcClientDeath(); + if (mToken != null) { + mToken.unlinkToDeath(this, 0); + mToken = null; + } + } + + @Override + public void binderDied() { + mController.unregisterMediaButtonIntent(mMediaIntent); + } + + @Override + protected void finalize() throws Throwable { + destroy(); // unlink exception handled inside method + super.finalize(); + } + } + + /** + * The stack of remote control event receivers. + * Code sections and methods that modify the remote control event receiver stack are + * synchronized on mRCStack, but also BEFORE on mFocusLock as any change in either + * stack, audio focus or RC, can lead to a change in the remote control display + */ + private final Stack<RemoteControlStackEntry> mRCStack = new Stack<RemoteControlStackEntry>(); + + /** + * The component the telephony package can register so telephony calls have priority to + * handle media button events + */ + private ComponentName mMediaReceiverForCalls = null; + + /** + * Helper function: + * Display in the log the current entries in the remote control focus stack + */ + private void dumpRCStack(PrintWriter pw) { + pw.println("\nRemote Control stack entries (last is top of stack):"); + synchronized(mRCStack) { + Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); + while(stackIterator.hasNext()) { + RemoteControlStackEntry rcse = stackIterator.next(); + pw.println(" pi: " + rcse.mMediaIntent + + " -- pack: " + rcse.mCallingPackageName + + " -- ercvr: " + rcse.mReceiverComponent + + " -- client: " + rcse.mRcClient + + " -- uid: " + rcse.mCallingUid + + " -- type: " + rcse.mPlaybackType + + " state: " + rcse.mPlaybackState); + } + } + } + + /** + * Helper function: + * Display in the log the current entries in the remote control stack, focusing + * on RemoteControlClient data + */ + private void dumpRCCStack(PrintWriter pw) { + pw.println("\nRemote Control Client stack entries (last is top of stack):"); + synchronized(mRCStack) { + Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); + while(stackIterator.hasNext()) { + RemoteControlStackEntry rcse = stackIterator.next(); + pw.println(" uid: " + rcse.mCallingUid + + " -- id: " + rcse.mRccId + + " -- type: " + rcse.mPlaybackType + + " -- state: " + rcse.mPlaybackState + + " -- vol handling: " + rcse.mPlaybackVolumeHandling + + " -- vol: " + rcse.mPlaybackVolume + + " -- volMax: " + rcse.mPlaybackVolumeMax + + " -- volObs: " + rcse.mRemoteVolumeObs); + } + synchronized(mCurrentRcLock) { + pw.println("\nCurrent remote control generation ID = " + mCurrentRcClientGen); + } + } + synchronized (mMainRemote) { + pw.println("\nRemote Volume State:"); + pw.println(" has remote: " + mHasRemotePlayback); + pw.println(" is remote active: " + mMainRemoteIsActive); + pw.println(" rccId: " + mMainRemote.mRccId); + pw.println(" volume handling: " + + ((mMainRemote.mVolumeHandling == RemoteControlClient.PLAYBACK_VOLUME_FIXED) ? + "PLAYBACK_VOLUME_FIXED(0)" : "PLAYBACK_VOLUME_VARIABLE(1)")); + pw.println(" volume: " + mMainRemote.mVolume); + pw.println(" volume steps: " + mMainRemote.mVolumeMax); + } + } + + /** + * Helper function: + * Display in the log the current entries in the list of remote control displays + */ + private void dumpRCDList(PrintWriter pw) { + pw.println("\nRemote Control Display list entries:"); + synchronized(mRCStack) { + final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator(); + while (displayIterator.hasNext()) { + final DisplayInfoForServer di = (DisplayInfoForServer) displayIterator.next(); + pw.println(" IRCD: " + di.mRcDisplay + + " -- w:" + di.mArtworkExpectedWidth + + " -- h:" + di.mArtworkExpectedHeight+ + " -- wantsPosSync:" + di.mWantsPositionSync); + } + } + } + + /** + * Helper function: + * Remove any entry in the remote control stack that has the same package name as packageName + * Pre-condition: packageName != null + */ + private void cleanupMediaButtonReceiverForPackage(String packageName, boolean removeAll) { + synchronized(mRCStack) { + if (mRCStack.empty()) { + return; + } else { + final PackageManager pm = mContext.getPackageManager(); + RemoteControlStackEntry oldTop = mRCStack.peek(); + Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); + // iterate over the stack entries + // (using an iterator on the stack so we can safely remove an entry after having + // evaluated it, traversal order doesn't matter here) + while(stackIterator.hasNext()) { + RemoteControlStackEntry rcse = (RemoteControlStackEntry)stackIterator.next(); + if (removeAll && packageName.equals(rcse.mMediaIntent.getCreatorPackage())) { + // a stack entry is from the package being removed, remove it from the stack + stackIterator.remove(); + rcse.destroy(); + } else if (rcse.mReceiverComponent != null) { + try { + // Check to see if this receiver still exists. + pm.getReceiverInfo(rcse.mReceiverComponent, 0); + } catch (PackageManager.NameNotFoundException e) { + // Not found -- remove it! + stackIterator.remove(); + rcse.destroy(); + } + } + } + if (mRCStack.empty()) { + // no saved media button receiver + mEventHandler.sendMessage( + mEventHandler.obtainMessage(MSG_PERSIST_MEDIABUTTONRECEIVER, 0, 0, + null)); + } else if (oldTop != mRCStack.peek()) { + // the top of the stack has changed, save it in the system settings + // by posting a message to persist it; only do this however if it has + // a concrete component name (is not a transient registration) + RemoteControlStackEntry rcse = mRCStack.peek(); + if (rcse.mReceiverComponent != null) { + mEventHandler.sendMessage( + mEventHandler.obtainMessage(MSG_PERSIST_MEDIABUTTONRECEIVER, 0, 0, + rcse.mReceiverComponent)); + } + } + } + } + } + + /** + * Helper function: + * Restore remote control receiver from the system settings. + */ + protected void restoreMediaButtonReceiver() { + String receiverName = Settings.System.getStringForUser(mContentResolver, + Settings.System.MEDIA_BUTTON_RECEIVER, UserHandle.USER_CURRENT); + if ((null != receiverName) && !receiverName.isEmpty()) { + ComponentName eventReceiver = ComponentName.unflattenFromString(receiverName); + if (eventReceiver == null) { + // an invalid name was persisted + return; + } + // construct a PendingIntent targeted to the restored component name + // for the media button and register it + Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON); + // the associated intent will be handled by the component being registered + mediaButtonIntent.setComponent(eventReceiver); + PendingIntent pi = PendingIntent.getBroadcast(mContext, + 0/*requestCode, ignored*/, mediaButtonIntent, 0/*flags*/); + registerMediaButtonIntent(pi, eventReceiver, null); + } + } + + /** + * Helper function: + * Set the new remote control receiver at the top of the RC focus stack. + * Called synchronized on mAudioFocusLock, then mRCStack + * precondition: mediaIntent != null + */ + private void pushMediaButtonReceiver_syncAfRcs(PendingIntent mediaIntent, ComponentName target, + IBinder token) { + // already at top of stack? + if (!mRCStack.empty() && mRCStack.peek().mMediaIntent.equals(mediaIntent)) { + return; + } + if (mAppOps.noteOp(AppOpsManager.OP_TAKE_MEDIA_BUTTONS, Binder.getCallingUid(), + mediaIntent.getCreatorPackage()) != AppOpsManager.MODE_ALLOWED) { + return; + } + RemoteControlStackEntry rcse = null; + boolean wasInsideStack = false; + try { + for (int index = mRCStack.size()-1; index >= 0; index--) { + rcse = mRCStack.elementAt(index); + if(rcse.mMediaIntent.equals(mediaIntent)) { + // ok to remove element while traversing the stack since we're leaving the loop + mRCStack.removeElementAt(index); + wasInsideStack = true; + break; + } + } + } catch (ArrayIndexOutOfBoundsException e) { + // not expected to happen, indicates improper concurrent modification + Log.e(TAG, "Wrong index accessing media button stack, lock error? ", e); + } + if (!wasInsideStack) { + rcse = new RemoteControlStackEntry(this, mediaIntent, target, token); + } + mRCStack.push(rcse); // rcse is never null + + // post message to persist the default media button receiver + if (target != null) { + mEventHandler.sendMessage( mEventHandler.obtainMessage( + MSG_PERSIST_MEDIABUTTONRECEIVER, 0, 0, target/*obj*/) ); + } + } + + /** + * Helper function: + * Remove the remote control receiver from the RC focus stack. + * Called synchronized on mAudioFocusLock, then mRCStack + * precondition: pi != null + */ + private void removeMediaButtonReceiver_syncAfRcs(PendingIntent pi) { + try { + for (int index = mRCStack.size()-1; index >= 0; index--) { + final RemoteControlStackEntry rcse = mRCStack.elementAt(index); + if (rcse.mMediaIntent.equals(pi)) { + rcse.destroy(); + // ok to remove element while traversing the stack since we're leaving the loop + mRCStack.removeElementAt(index); + break; + } + } + } catch (ArrayIndexOutOfBoundsException e) { + // not expected to happen, indicates improper concurrent modification + Log.e(TAG, "Wrong index accessing media button stack, lock error? ", e); + } + } + + /** + * Helper function: + * Called synchronized on mRCStack + */ + private boolean isCurrentRcController(PendingIntent pi) { + if (!mRCStack.empty() && mRCStack.peek().mMediaIntent.equals(pi)) { + return true; + } + return false; + } + + private void onHandlePersistMediaButtonReceiver(ComponentName receiver) { + Settings.System.putStringForUser(mContentResolver, + Settings.System.MEDIA_BUTTON_RECEIVER, + receiver == null ? "" : receiver.flattenToString(), + UserHandle.USER_CURRENT); + } + + //========================================================================================== + // Remote control display / client + //========================================================================================== + /** + * Update the remote control displays with the new "focused" client generation + */ + private void setNewRcClientOnDisplays_syncRcsCurrc(int newClientGeneration, + PendingIntent newMediaIntent, boolean clearing) { + synchronized(mRCStack) { + if (mRcDisplays.size() > 0) { + final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator(); + while (displayIterator.hasNext()) { + final DisplayInfoForServer di = displayIterator.next(); + try { + di.mRcDisplay.setCurrentClientId( + newClientGeneration, newMediaIntent, clearing); + } catch (RemoteException e) { + Log.e(TAG, "Dead display in setNewRcClientOnDisplays_syncRcsCurrc()",e); + di.release(); + displayIterator.remove(); + } + } + } + } + } + + /** + * Update the remote control clients with the new "focused" client generation + */ + private void setNewRcClientGenerationOnClients_syncRcsCurrc(int newClientGeneration) { + // (using an iterator on the stack so we can safely remove an entry if needed, + // traversal order doesn't matter here as we update all entries) + Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); + while(stackIterator.hasNext()) { + RemoteControlStackEntry se = stackIterator.next(); + if ((se != null) && (se.mRcClient != null)) { + try { + se.mRcClient.setCurrentClientGenerationId(newClientGeneration); + } catch (RemoteException e) { + Log.w(TAG, "Dead client in setNewRcClientGenerationOnClients_syncRcsCurrc()",e); + stackIterator.remove(); + se.unlinkToRcClientDeath(); + } + } + } + } + + /** + * Update the displays and clients with the new "focused" client generation and name + * @param newClientGeneration the new generation value matching a client update + * @param newMediaIntent the media button event receiver associated with the client. + * May be null, which implies there is no registered media button event receiver. + * @param clearing true if the new client generation value maps to a remote control update + * where the display should be cleared. + */ + private void setNewRcClient_syncRcsCurrc(int newClientGeneration, + PendingIntent newMediaIntent, boolean clearing) { + // send the new valid client generation ID to all displays + setNewRcClientOnDisplays_syncRcsCurrc(newClientGeneration, newMediaIntent, clearing); + // send the new valid client generation ID to all clients + setNewRcClientGenerationOnClients_syncRcsCurrc(newClientGeneration); + } + + /** + * Called when processing MSG_RCDISPLAY_CLEAR event + */ + private void onRcDisplayClear() { + if (DEBUG_RC) Log.i(TAG, "Clear remote control display"); + + synchronized(mRCStack) { + synchronized(mCurrentRcLock) { + mCurrentRcClientGen++; + // synchronously update the displays and clients with the new client generation + setNewRcClient_syncRcsCurrc(mCurrentRcClientGen, + null /*newMediaIntent*/, true /*clearing*/); + } + } + } + + /** + * Called when processing MSG_RCDISPLAY_UPDATE event + */ + private void onRcDisplayUpdate(RemoteControlStackEntry rcse, int flags /* USED ?*/) { + synchronized(mRCStack) { + synchronized(mCurrentRcLock) { + if ((mCurrentRcClient != null) && (mCurrentRcClient.equals(rcse.mRcClient))) { + if (DEBUG_RC) Log.i(TAG, "Display/update remote control "); + + mCurrentRcClientGen++; + // synchronously update the displays and clients with + // the new client generation + setNewRcClient_syncRcsCurrc(mCurrentRcClientGen, + rcse.mMediaIntent /*newMediaIntent*/, + false /*clearing*/); + + // tell the current client that it needs to send info + try { + mCurrentRcClient.onInformationRequested(mCurrentRcClientGen, flags); + } catch (RemoteException e) { + Log.e(TAG, "Current valid remote client is dead: "+e); + mCurrentRcClient = null; + } + } else { + // the remote control display owner has changed between the + // the message to update the display was sent, and the time it + // gets to be processed (now) + } + } + } + } + + + /** + * Helper function: + * Called synchronized on mRCStack + */ + private void clearRemoteControlDisplay_syncAfRcs() { + synchronized(mCurrentRcLock) { + mCurrentRcClient = null; + } + // will cause onRcDisplayClear() to be called in AudioService's handler thread + mEventHandler.sendMessage( mEventHandler.obtainMessage(MSG_RCDISPLAY_CLEAR) ); + } + + /** + * Helper function for code readability: only to be called from + * checkUpdateRemoteControlDisplay_syncAfRcs() which checks the preconditions for + * this method. + * Preconditions: + * - called synchronized mAudioFocusLock then on mRCStack + * - mRCStack.isEmpty() is false + */ + private void updateRemoteControlDisplay_syncAfRcs(int infoChangedFlags) { + RemoteControlStackEntry rcse = mRCStack.peek(); + int infoFlagsAboutToBeUsed = infoChangedFlags; + // this is where we enforce opt-in for information display on the remote controls + // with the new AudioManager.registerRemoteControlClient() API + if (rcse.mRcClient == null) { + //Log.w(TAG, "Can't update remote control display with null remote control client"); + clearRemoteControlDisplay_syncAfRcs(); + return; + } + synchronized(mCurrentRcLock) { + if (!rcse.mRcClient.equals(mCurrentRcClient)) { + // new RC client, assume every type of information shall be queried + infoFlagsAboutToBeUsed = RC_INFO_ALL; + } + mCurrentRcClient = rcse.mRcClient; + } + // will cause onRcDisplayUpdate() to be called in AudioService's handler thread + mEventHandler.sendMessage( mEventHandler.obtainMessage(MSG_RCDISPLAY_UPDATE, + infoFlagsAboutToBeUsed /* arg1 */, 0, rcse /* obj, != null */) ); + } + + /** + * Helper function: + * Called synchronized on mAudioFocusLock, then mRCStack + * Check whether the remote control display should be updated, triggers the update if required + * @param infoChangedFlags the flags corresponding to the remote control client information + * that has changed, if applicable (checking for the update conditions might trigger a + * clear, rather than an update event). + */ + private void checkUpdateRemoteControlDisplay_syncAfRcs(int infoChangedFlags) { + // determine whether the remote control display should be refreshed + // if either stack is empty, there is a mismatch, so clear the RC display + if (mRCStack.isEmpty() || mFocusStack.isEmpty()) { + clearRemoteControlDisplay_syncAfRcs(); + return; + } + + // determine which entry in the AudioFocus stack to consider, and compare against the + // top of the stack for the media button event receivers : simply using the top of the + // stack would make the entry disappear from the RemoteControlDisplay in conditions such as + // notifications playing during music playback. + // Crawl the AudioFocus stack from the top until an entry is found with the following + // characteristics: + // - focus gain on STREAM_MUSIC stream + // - non-transient focus gain on a stream other than music + FocusStackEntry af = null; + try { + for (int index = mFocusStack.size()-1; index >= 0; index--) { + FocusStackEntry fse = mFocusStack.elementAt(index); + if ((fse.mStreamType == AudioManager.STREAM_MUSIC) + || (fse.mFocusChangeType == AudioManager.AUDIOFOCUS_GAIN)) { + af = fse; + break; + } + } + } catch (ArrayIndexOutOfBoundsException e) { + Log.e(TAG, "Wrong index accessing audio focus stack when updating RCD: " + e); + af = null; + } + if (af == null) { + clearRemoteControlDisplay_syncAfRcs(); + return; + } + + // if the audio focus and RC owners belong to different packages, there is a mismatch, clear + if ((mRCStack.peek().mCallingPackageName != null) + && (af.mPackageName != null) + && !(mRCStack.peek().mCallingPackageName.compareTo( + af.mPackageName) == 0)) { + clearRemoteControlDisplay_syncAfRcs(); + return; + } + // if the audio focus didn't originate from the same Uid as the one in which the remote + // control information will be retrieved, clear + if (mRCStack.peek().mCallingUid != af.mCallingUid) { + clearRemoteControlDisplay_syncAfRcs(); + return; + } + + // refresh conditions were verified: update the remote controls + // ok to call: synchronized mAudioFocusLock then on mRCStack, mRCStack is not empty + updateRemoteControlDisplay_syncAfRcs(infoChangedFlags); + } + + /** + * Helper function: + * Post a message to asynchronously move the media button event receiver associated with the + * given remote control client ID to the top of the remote control stack + * @param rccId + */ + private void postPromoteRcc(int rccId) { + sendMsg(mEventHandler, MSG_PROMOTE_RCC, SENDMSG_REPLACE, + rccId /*arg1*/, 0, null, 0/*delay*/); + } + + private void onPromoteRcc(int rccId) { + if (DEBUG_RC) { Log.d(TAG, "Promoting RCC " + rccId); } + synchronized(mAudioFocusLock) { + synchronized(mRCStack) { + // ignore if given RCC ID is already at top of remote control stack + if (!mRCStack.isEmpty() && (mRCStack.peek().mRccId == rccId)) { + return; + } + int indexToPromote = -1; + try { + for (int index = mRCStack.size()-1; index >= 0; index--) { + final RemoteControlStackEntry rcse = mRCStack.elementAt(index); + if (rcse.mRccId == rccId) { + indexToPromote = index; + break; + } + } + if (indexToPromote >= 0) { + if (DEBUG_RC) { Log.d(TAG, " moving RCC from index " + indexToPromote + + " to " + (mRCStack.size()-1)); } + final RemoteControlStackEntry rcse = mRCStack.remove(indexToPromote); + mRCStack.push(rcse); + // the RC stack changed, reevaluate the display + checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL); + } + } catch (ArrayIndexOutOfBoundsException e) { + // not expected to happen, indicates improper concurrent modification + Log.e(TAG, "Wrong index accessing RC stack, lock error? ", e); + } + }//synchronized(mRCStack) + }//synchronized(mAudioFocusLock) + } + + /** + * see AudioManager.registerMediaButtonIntent(PendingIntent pi, ComponentName c) + * precondition: mediaIntent != null + */ + protected void registerMediaButtonIntent(PendingIntent mediaIntent, ComponentName eventReceiver, + IBinder token) { + Log.i(TAG, " Remote Control registerMediaButtonIntent() for " + mediaIntent); + + synchronized(mAudioFocusLock) { + synchronized(mRCStack) { + pushMediaButtonReceiver_syncAfRcs(mediaIntent, eventReceiver, token); + // new RC client, assume every type of information shall be queried + checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL); + } + } + } + + /** + * see AudioManager.unregisterMediaButtonIntent(PendingIntent mediaIntent) + * precondition: mediaIntent != null, eventReceiver != null + */ + protected void unregisterMediaButtonIntent(PendingIntent mediaIntent) + { + Log.i(TAG, " Remote Control unregisterMediaButtonIntent() for " + mediaIntent); + + synchronized(mAudioFocusLock) { + synchronized(mRCStack) { + boolean topOfStackWillChange = isCurrentRcController(mediaIntent); + removeMediaButtonReceiver_syncAfRcs(mediaIntent); + if (topOfStackWillChange) { + // current RC client will change, assume every type of info needs to be queried + checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL); + } + } + } + } + + /** + * see AudioManager.registerMediaButtonEventReceiverForCalls(ComponentName c) + * precondition: c != null + */ + protected void registerMediaButtonEventReceiverForCalls(ComponentName c) { + if (mContext.checkCallingPermission("android.permission.MODIFY_PHONE_STATE") + != PackageManager.PERMISSION_GRANTED) { + Log.e(TAG, "Invalid permissions to register media button receiver for calls"); + return; + } + synchronized(mRCStack) { + mMediaReceiverForCalls = c; + } + } + + /** + * see AudioManager.unregisterMediaButtonEventReceiverForCalls() + */ + protected void unregisterMediaButtonEventReceiverForCalls() { + if (mContext.checkCallingPermission("android.permission.MODIFY_PHONE_STATE") + != PackageManager.PERMISSION_GRANTED) { + Log.e(TAG, "Invalid permissions to unregister media button receiver for calls"); + return; + } + synchronized(mRCStack) { + mMediaReceiverForCalls = null; + } + } + + /** + * see AudioManager.registerRemoteControlClient(ComponentName eventReceiver, ...) + * @return the unique ID of the RemoteControlStackEntry associated with the RemoteControlClient + * Note: using this method with rcClient == null is a way to "disable" the IRemoteControlClient + * without modifying the RC stack, but while still causing the display to refresh (will + * become blank as a result of this) + */ + protected int registerRemoteControlClient(PendingIntent mediaIntent, + IRemoteControlClient rcClient, String callingPackageName) { + if (DEBUG_RC) Log.i(TAG, "Register remote control client rcClient="+rcClient); + int rccId = RemoteControlClient.RCSE_ID_UNREGISTERED; + synchronized(mAudioFocusLock) { + synchronized(mRCStack) { + // store the new display information + try { + for (int index = mRCStack.size()-1; index >= 0; index--) { + final RemoteControlStackEntry rcse = mRCStack.elementAt(index); + if(rcse.mMediaIntent.equals(mediaIntent)) { + // already had a remote control client? + if (rcse.mRcClientDeathHandler != null) { + // stop monitoring the old client's death + rcse.unlinkToRcClientDeath(); + } + // save the new remote control client + rcse.mRcClient = rcClient; + rcse.mCallingPackageName = callingPackageName; + rcse.mCallingUid = Binder.getCallingUid(); + if (rcClient == null) { + // here rcse.mRcClientDeathHandler is null; + rcse.resetPlaybackInfo(); + break; + } + rccId = rcse.mRccId; + + // there is a new (non-null) client: + // 1/ give the new client the displays (if any) + if (mRcDisplays.size() > 0) { + plugRemoteControlDisplaysIntoClient_syncRcStack(rcse.mRcClient); + } + // 2/ monitor the new client's death + IBinder b = rcse.mRcClient.asBinder(); + RcClientDeathHandler rcdh = + new RcClientDeathHandler(b, rcse.mMediaIntent); + try { + b.linkToDeath(rcdh, 0); + } catch (RemoteException e) { + // remote control client is DOA, disqualify it + Log.w(TAG, "registerRemoteControlClient() has a dead client " + b); + rcse.mRcClient = null; + } + rcse.mRcClientDeathHandler = rcdh; + break; + } + }//for + } catch (ArrayIndexOutOfBoundsException e) { + // not expected to happen, indicates improper concurrent modification + Log.e(TAG, "Wrong index accessing RC stack, lock error? ", e); + } + + // if the eventReceiver is at the top of the stack + // then check for potential refresh of the remote controls + if (isCurrentRcController(mediaIntent)) { + checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL); + } + }//synchronized(mRCStack) + }//synchronized(mAudioFocusLock) + return rccId; + } + + /** + * see AudioManager.unregisterRemoteControlClient(PendingIntent pi, ...) + * rcClient is guaranteed non-null + */ + protected void unregisterRemoteControlClient(PendingIntent mediaIntent, + IRemoteControlClient rcClient) { + if (DEBUG_RC) Log.i(TAG, "Unregister remote control client rcClient="+rcClient); + synchronized(mAudioFocusLock) { + synchronized(mRCStack) { + boolean topRccChange = false; + try { + for (int index = mRCStack.size()-1; index >= 0; index--) { + final RemoteControlStackEntry rcse = mRCStack.elementAt(index); + if ((rcse.mMediaIntent.equals(mediaIntent)) + && rcClient.equals(rcse.mRcClient)) { + // we found the IRemoteControlClient to unregister + // stop monitoring its death + rcse.unlinkToRcClientDeath(); + // reset the client-related fields + rcse.mRcClient = null; + rcse.mCallingPackageName = null; + topRccChange = (index == mRCStack.size()-1); + // there can only be one matching RCC in the RC stack, we're done + break; + } + } + } catch (ArrayIndexOutOfBoundsException e) { + // not expected to happen, indicates improper concurrent modification + Log.e(TAG, "Wrong index accessing RC stack, lock error? ", e); + } + if (topRccChange) { + // no more RCC for the RCD, check for potential refresh of the remote controls + checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL); + } + } + } + } + + + /** + * A class to encapsulate all the information about a remote control display. + * After instanciation, init() must always be called before the object is added in the list + * of displays. + * Before being removed from the list of displays, release() must always be called (otherwise + * it will leak death handlers). + */ + private class DisplayInfoForServer implements IBinder.DeathRecipient { + /** may never be null */ + private IRemoteControlDisplay mRcDisplay; + private IBinder mRcDisplayBinder; + private int mArtworkExpectedWidth = -1; + private int mArtworkExpectedHeight = -1; + private boolean mWantsPositionSync = false; + + public DisplayInfoForServer(IRemoteControlDisplay rcd, int w, int h) { + if (DEBUG_RC) Log.i(TAG, "new DisplayInfoForServer for " + rcd + " w=" + w + " h=" + h); + mRcDisplay = rcd; + mRcDisplayBinder = rcd.asBinder(); + mArtworkExpectedWidth = w; + mArtworkExpectedHeight = h; + } + + public boolean init() { + try { + mRcDisplayBinder.linkToDeath(this, 0); + } catch (RemoteException e) { + // remote control display is DOA, disqualify it + Log.w(TAG, "registerRemoteControlDisplay() has a dead client " + mRcDisplayBinder); + return false; + } + return true; + } + + public void release() { + try { + mRcDisplayBinder.unlinkToDeath(this, 0); + } catch (java.util.NoSuchElementException e) { + // not much we can do here, the display should have been unregistered anyway + Log.e(TAG, "Error in DisplaInfoForServer.relase()", e); + } + } + + public void binderDied() { + synchronized(mRCStack) { + Log.w(TAG, "RemoteControl: display " + mRcDisplay + " died"); + // remove the display from the list + final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator(); + while (displayIterator.hasNext()) { + final DisplayInfoForServer di = (DisplayInfoForServer) displayIterator.next(); + if (di.mRcDisplay == mRcDisplay) { + if (DEBUG_RC) Log.w(TAG, " RCD removed from list"); + displayIterator.remove(); + return; + } + } + } + } + } + + /** + * The remote control displays. + * Access synchronized on mRCStack + */ + private ArrayList<DisplayInfoForServer> mRcDisplays = new ArrayList<DisplayInfoForServer>(1); + + /** + * Plug each registered display into the specified client + * @param rcc, guaranteed non null + */ + private void plugRemoteControlDisplaysIntoClient_syncRcStack(IRemoteControlClient rcc) { + final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator(); + while (displayIterator.hasNext()) { + final DisplayInfoForServer di = (DisplayInfoForServer) displayIterator.next(); + try { + rcc.plugRemoteControlDisplay(di.mRcDisplay, di.mArtworkExpectedWidth, + di.mArtworkExpectedHeight); + if (di.mWantsPositionSync) { + rcc.setWantsSyncForDisplay(di.mRcDisplay, true); + } + } catch (RemoteException e) { + Log.e(TAG, "Error connecting RCD to RCC in RCC registration",e); + } + } + } + + /** + * Is the remote control display interface already registered + * @param rcd + * @return true if the IRemoteControlDisplay is already in the list of displays + */ + private boolean rcDisplayIsPluggedIn_syncRcStack(IRemoteControlDisplay rcd) { + final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator(); + while (displayIterator.hasNext()) { + final DisplayInfoForServer di = (DisplayInfoForServer) displayIterator.next(); + if (di.mRcDisplay.asBinder().equals(rcd.asBinder())) { + return true; + } + } + return false; + } + + /** + * Register an IRemoteControlDisplay. + * Notify all IRemoteControlClient of the new display and cause the RemoteControlClient + * at the top of the stack to update the new display with its information. + * @see android.media.IAudioService#registerRemoteControlDisplay(android.media.IRemoteControlDisplay, int, int) + * @param rcd the IRemoteControlDisplay to register. No effect if null. + * @param w the maximum width of the expected bitmap. Negative or zero values indicate this + * display doesn't need to receive artwork. + * @param h the maximum height of the expected bitmap. Negative or zero values indicate this + * display doesn't need to receive artwork. + */ + protected void registerRemoteControlDisplay(IRemoteControlDisplay rcd, int w, int h) { + if (DEBUG_RC) Log.d(TAG, ">>> registerRemoteControlDisplay("+rcd+")"); + synchronized(mAudioFocusLock) { + synchronized(mRCStack) { + if ((rcd == null) || rcDisplayIsPluggedIn_syncRcStack(rcd)) { + return; + } + DisplayInfoForServer di = new DisplayInfoForServer(rcd, w, h); + if (!di.init()) { + if (DEBUG_RC) Log.e(TAG, " error registering RCD"); + return; + } + // add RCD to list of displays + mRcDisplays.add(di); + + // let all the remote control clients know there is a new display (so the remote + // control stack traversal order doesn't matter). + Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); + while(stackIterator.hasNext()) { + RemoteControlStackEntry rcse = stackIterator.next(); + if(rcse.mRcClient != null) { + try { + rcse.mRcClient.plugRemoteControlDisplay(rcd, w, h); + } catch (RemoteException e) { + Log.e(TAG, "Error connecting RCD to client: ", e); + } + } + } + + // we have a new display, of which all the clients are now aware: have it be updated + checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL); + } + } + } + + /** + * Unregister an IRemoteControlDisplay. + * No effect if the IRemoteControlDisplay hasn't been successfully registered. + * @see android.media.IAudioService#unregisterRemoteControlDisplay(android.media.IRemoteControlDisplay) + * @param rcd the IRemoteControlDisplay to unregister. No effect if null. + */ + protected void unregisterRemoteControlDisplay(IRemoteControlDisplay rcd) { + if (DEBUG_RC) Log.d(TAG, "<<< unregisterRemoteControlDisplay("+rcd+")"); + synchronized(mRCStack) { + if (rcd == null) { + return; + } + + boolean displayWasPluggedIn = false; + final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator(); + while (displayIterator.hasNext() && !displayWasPluggedIn) { + final DisplayInfoForServer di = (DisplayInfoForServer) displayIterator.next(); + if (di.mRcDisplay.asBinder().equals(rcd.asBinder())) { + displayWasPluggedIn = true; + di.release(); + displayIterator.remove(); + } + } + + if (displayWasPluggedIn) { + // disconnect this remote control display from all the clients, so the remote + // control stack traversal order doesn't matter + final Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); + while(stackIterator.hasNext()) { + final RemoteControlStackEntry rcse = stackIterator.next(); + if(rcse.mRcClient != null) { + try { + rcse.mRcClient.unplugRemoteControlDisplay(rcd); + } catch (RemoteException e) { + Log.e(TAG, "Error disconnecting remote control display to client: ", e); + } + } + } + } else { + if (DEBUG_RC) Log.w(TAG, " trying to unregister unregistered RCD"); + } + } + } + + /** + * Update the size of the artwork used by an IRemoteControlDisplay. + * @see android.media.IAudioService#remoteControlDisplayUsesBitmapSize(android.media.IRemoteControlDisplay, int, int) + * @param rcd the IRemoteControlDisplay with the new artwork size requirement + * @param w the maximum width of the expected bitmap. Negative or zero values indicate this + * display doesn't need to receive artwork. + * @param h the maximum height of the expected bitmap. Negative or zero values indicate this + * display doesn't need to receive artwork. + */ + protected void remoteControlDisplayUsesBitmapSize(IRemoteControlDisplay rcd, int w, int h) { + synchronized(mRCStack) { + final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator(); + boolean artworkSizeUpdate = false; + while (displayIterator.hasNext() && !artworkSizeUpdate) { + final DisplayInfoForServer di = (DisplayInfoForServer) displayIterator.next(); + if (di.mRcDisplay.asBinder().equals(rcd.asBinder())) { + if ((di.mArtworkExpectedWidth != w) || (di.mArtworkExpectedHeight != h)) { + di.mArtworkExpectedWidth = w; + di.mArtworkExpectedHeight = h; + artworkSizeUpdate = true; + } + } + } + if (artworkSizeUpdate) { + // RCD is currently plugged in and its artwork size has changed, notify all RCCs, + // stack traversal order doesn't matter + final Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); + while(stackIterator.hasNext()) { + final RemoteControlStackEntry rcse = stackIterator.next(); + if(rcse.mRcClient != null) { + try { + rcse.mRcClient.setBitmapSizeForDisplay(rcd, w, h); + } catch (RemoteException e) { + Log.e(TAG, "Error setting bitmap size for RCD on RCC: ", e); + } + } + } + } + } + } + + /** + * Controls whether a remote control display needs periodic checks of the RemoteControlClient + * playback position to verify that the estimated position has not drifted from the actual + * position. By default the check is not performed. + * The IRemoteControlDisplay must have been previously registered for this to have any effect. + * @param rcd the IRemoteControlDisplay for which the anti-drift mechanism will be enabled + * or disabled. Not null. + * @param wantsSync if true, RemoteControlClient instances which expose their playback position + * to the framework will regularly compare the estimated playback position with the actual + * position, and will update the IRemoteControlDisplay implementation whenever a drift is + * detected. + */ + protected void remoteControlDisplayWantsPlaybackPositionSync(IRemoteControlDisplay rcd, + boolean wantsSync) { + synchronized(mRCStack) { + boolean rcdRegistered = false; + // store the information about this display + // (display stack traversal order doesn't matter). + final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator(); + while (displayIterator.hasNext()) { + final DisplayInfoForServer di = (DisplayInfoForServer) displayIterator.next(); + if (di.mRcDisplay.asBinder().equals(rcd.asBinder())) { + di.mWantsPositionSync = wantsSync; + rcdRegistered = true; + break; + } + } + if (!rcdRegistered) { + return; + } + // notify all current RemoteControlClients + // (stack traversal order doesn't matter as we notify all RCCs) + final Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); + while (stackIterator.hasNext()) { + final RemoteControlStackEntry rcse = stackIterator.next(); + if (rcse.mRcClient != null) { + try { + rcse.mRcClient.setWantsSyncForDisplay(rcd, wantsSync); + } catch (RemoteException e) { + Log.e(TAG, "Error setting position sync flag for RCD on RCC: ", e); + } + } + } + } + } + + protected void setRemoteControlClientPlaybackPosition(int generationId, long timeMs) { + // ignore position change requests if invalid generation ID + synchronized(mRCStack) { + synchronized(mCurrentRcLock) { + if (mCurrentRcClientGen != generationId) { + return; + } + } + } + // discard any unprocessed seek request in the message queue, and replace with latest + sendMsg(mEventHandler, MSG_RCC_SEEK_REQUEST, SENDMSG_REPLACE, generationId /* arg1 */, + 0 /* arg2 ignored*/, new Long(timeMs) /* obj */, 0 /* delay */); + } + + private void onSetRemoteControlClientPlaybackPosition(int generationId, long timeMs) { + if(DEBUG_RC) Log.d(TAG, "onSetRemoteControlClientPlaybackPosition(genId=" + generationId + + ", timeMs=" + timeMs + ")"); + synchronized(mRCStack) { + synchronized(mCurrentRcLock) { + if ((mCurrentRcClient != null) && (mCurrentRcClientGen == generationId)) { + // tell the current client to seek to the requested location + try { + mCurrentRcClient.seekTo(generationId, timeMs); + } catch (RemoteException e) { + Log.e(TAG, "Current valid remote client is dead: "+e); + mCurrentRcClient = null; + } + } + } + } + } + + protected void setPlaybackInfoForRcc(int rccId, int what, int value) { + sendMsg(mEventHandler, MSG_RCC_NEW_PLAYBACK_INFO, SENDMSG_QUEUE, + rccId /* arg1 */, what /* arg2 */, Integer.valueOf(value) /* obj */, 0 /* delay */); + } + + // handler for MSG_RCC_NEW_PLAYBACK_INFO + private void onNewPlaybackInfoForRcc(int rccId, int key, int value) { + if(DEBUG_RC) Log.d(TAG, "onNewPlaybackInfoForRcc(id=" + rccId + + ", what=" + key + ",val=" + value + ")"); + synchronized(mRCStack) { + // iterating from top of stack as playback information changes are more likely + // on entries at the top of the remote control stack + try { + for (int index = mRCStack.size()-1; index >= 0; index--) { + final RemoteControlStackEntry rcse = mRCStack.elementAt(index); + if (rcse.mRccId == rccId) { + switch (key) { + case RemoteControlClient.PLAYBACKINFO_PLAYBACK_TYPE: + rcse.mPlaybackType = value; + postReevaluateRemote(); + break; + case RemoteControlClient.PLAYBACKINFO_VOLUME: + rcse.mPlaybackVolume = value; + synchronized (mMainRemote) { + if (rccId == mMainRemote.mRccId) { + mMainRemote.mVolume = value; + mVolumeController.postHasNewRemotePlaybackInfo(); + } + } + break; + case RemoteControlClient.PLAYBACKINFO_VOLUME_MAX: + rcse.mPlaybackVolumeMax = value; + synchronized (mMainRemote) { + if (rccId == mMainRemote.mRccId) { + mMainRemote.mVolumeMax = value; + mVolumeController.postHasNewRemotePlaybackInfo(); + } + } + break; + case RemoteControlClient.PLAYBACKINFO_VOLUME_HANDLING: + rcse.mPlaybackVolumeHandling = value; + synchronized (mMainRemote) { + if (rccId == mMainRemote.mRccId) { + mMainRemote.mVolumeHandling = value; + mVolumeController.postHasNewRemotePlaybackInfo(); + } + } + break; + case RemoteControlClient.PLAYBACKINFO_USES_STREAM: + rcse.mPlaybackStream = value; + break; + default: + Log.e(TAG, "unhandled key " + key + " for RCC " + rccId); + break; + } + return; + } + }//for + } catch (ArrayIndexOutOfBoundsException e) { + // not expected to happen, indicates improper concurrent modification + Log.e(TAG, "Wrong index mRCStack on onNewPlaybackInfoForRcc, lock error? ", e); + } + } + } + + protected void setPlaybackStateForRcc(int rccId, int state, long timeMs, float speed) { + sendMsg(mEventHandler, MSG_RCC_NEW_PLAYBACK_STATE, SENDMSG_QUEUE, + rccId /* arg1 */, state /* arg2 */, + new RccPlaybackState(state, timeMs, speed) /* obj */, 0 /* delay */); + } + + protected void onNewPlaybackStateForRcc(int rccId, int state, RccPlaybackState newState) { + if(DEBUG_RC) Log.d(TAG, "onNewPlaybackStateForRcc(id=" + rccId + ", state=" + state + + ", time=" + newState.mPositionMs + ", speed=" + newState.mSpeed + ")"); + synchronized(mRCStack) { + // iterating from top of stack as playback information changes are more likely + // on entries at the top of the remote control stack + try { + for (int index = mRCStack.size()-1; index >= 0; index--) { + final RemoteControlStackEntry rcse = mRCStack.elementAt(index); + if (rcse.mRccId == rccId) { + rcse.mPlaybackState = newState; + synchronized (mMainRemote) { + if (rccId == mMainRemote.mRccId) { + mMainRemoteIsActive = isPlaystateActive(state); + postReevaluateRemote(); + } + } + // an RCC moving to a "playing" state should become the media button + // event receiver so it can be controlled, without requiring the + // app to re-register its receiver + if (isPlaystateActive(state)) { + postPromoteRcc(rccId); + } + } + }//for + } catch (ArrayIndexOutOfBoundsException e) { + // not expected to happen, indicates improper concurrent modification + Log.e(TAG, "Wrong index on mRCStack in onNewPlaybackStateForRcc, lock error? ", e); + } + } + } + + protected void registerRemoteVolumeObserverForRcc(int rccId, IRemoteVolumeObserver rvo) { + sendMsg(mEventHandler, MSG_RCC_NEW_VOLUME_OBS, SENDMSG_QUEUE, + rccId /* arg1 */, 0, rvo /* obj */, 0 /* delay */); + } + + // handler for MSG_RCC_NEW_VOLUME_OBS + private void onRegisterVolumeObserverForRcc(int rccId, IRemoteVolumeObserver rvo) { + synchronized(mRCStack) { + // The stack traversal order doesn't matter because there is only one stack entry + // with this RCC ID, but the matching ID is more likely at the top of the stack, so + // start iterating from the top. + try { + for (int index = mRCStack.size()-1; index >= 0; index--) { + final RemoteControlStackEntry rcse = mRCStack.elementAt(index); + if (rcse.mRccId == rccId) { + rcse.mRemoteVolumeObs = rvo; + break; + } + } + } catch (ArrayIndexOutOfBoundsException e) { + // not expected to happen, indicates improper concurrent modification + Log.e(TAG, "Wrong index accessing media button stack, lock error? ", e); + } + } + } + + /** + * Checks if a remote client is active on the supplied stream type. Update the remote stream + * volume state if found and playing + * @param streamType + * @return false if no remote playing is currently playing + */ + protected boolean checkUpdateRemoteStateIfActive(int streamType) { + synchronized(mRCStack) { + // iterating from top of stack as active playback is more likely on entries at the top + try { + for (int index = mRCStack.size()-1; index >= 0; index--) { + final RemoteControlStackEntry rcse = mRCStack.elementAt(index); + if ((rcse.mPlaybackType == RemoteControlClient.PLAYBACK_TYPE_REMOTE) + && isPlaystateActive(rcse.mPlaybackState.mState) + && (rcse.mPlaybackStream == streamType)) { + if (DEBUG_RC) Log.d(TAG, "remote playback active on stream " + streamType + + ", vol =" + rcse.mPlaybackVolume); + synchronized (mMainRemote) { + mMainRemote.mRccId = rcse.mRccId; + mMainRemote.mVolume = rcse.mPlaybackVolume; + mMainRemote.mVolumeMax = rcse.mPlaybackVolumeMax; + mMainRemote.mVolumeHandling = rcse.mPlaybackVolumeHandling; + mMainRemoteIsActive = true; + } + return true; + } + } + } catch (ArrayIndexOutOfBoundsException e) { + // not expected to happen, indicates improper concurrent modification + Log.e(TAG, "Wrong index accessing RC stack, lock error? ", e); + } + } + synchronized (mMainRemote) { + mMainRemoteIsActive = false; + } + return false; + } + + /** + * Returns true if the given playback state is considered "active", i.e. it describes a state + * where playback is happening, or about to + * @param playState the playback state to evaluate + * @return true if active, false otherwise (inactive or unknown) + */ + private static boolean isPlaystateActive(int playState) { + switch (playState) { + case RemoteControlClient.PLAYSTATE_PLAYING: + case RemoteControlClient.PLAYSTATE_BUFFERING: + case RemoteControlClient.PLAYSTATE_FAST_FORWARDING: + case RemoteControlClient.PLAYSTATE_REWINDING: + case RemoteControlClient.PLAYSTATE_SKIPPING_BACKWARDS: + case RemoteControlClient.PLAYSTATE_SKIPPING_FORWARDS: + return true; + default: + return false; + } + } + + protected void adjustRemoteVolume(int streamType, int direction, int flags) { + int rccId = RemoteControlClient.RCSE_ID_UNREGISTERED; + boolean volFixed = false; + synchronized (mMainRemote) { + if (!mMainRemoteIsActive) { + if (DEBUG_VOL) Log.w(TAG, "adjustRemoteVolume didn't find an active client"); + return; + } + rccId = mMainRemote.mRccId; + volFixed = (mMainRemote.mVolumeHandling == + RemoteControlClient.PLAYBACK_VOLUME_FIXED); + } + // unlike "local" stream volumes, we can't compute the new volume based on the direction, + // we can only notify the remote that volume needs to be updated, and we'll get an async' + // update through setPlaybackInfoForRcc() + if (!volFixed) { + sendVolumeUpdateToRemote(rccId, direction); + } + + // fire up the UI + mVolumeController.postRemoteVolumeChanged(streamType, flags); + } + + private void sendVolumeUpdateToRemote(int rccId, int direction) { + if (DEBUG_VOL) { Log.d(TAG, "sendVolumeUpdateToRemote(rccId="+rccId+" , dir="+direction); } + if (direction == 0) { + // only handling discrete events + return; + } + IRemoteVolumeObserver rvo = null; + synchronized (mRCStack) { + // The stack traversal order doesn't matter because there is only one stack entry + // with this RCC ID, but the matching ID is more likely at the top of the stack, so + // start iterating from the top. + try { + for (int index = mRCStack.size()-1; index >= 0; index--) { + final RemoteControlStackEntry rcse = mRCStack.elementAt(index); + //FIXME OPTIMIZE store this info in mMainRemote so we don't have to iterate? + if (rcse.mRccId == rccId) { + rvo = rcse.mRemoteVolumeObs; + break; + } + } + } catch (ArrayIndexOutOfBoundsException e) { + // not expected to happen, indicates improper concurrent modification + Log.e(TAG, "Wrong index accessing media button stack, lock error? ", e); + } + } + if (rvo != null) { + try { + rvo.dispatchRemoteVolumeUpdate(direction, -1); + } catch (RemoteException e) { + Log.e(TAG, "Error dispatching relative volume update", e); + } + } + } + + protected int getRemoteStreamMaxVolume() { + synchronized (mMainRemote) { + if (mMainRemote.mRccId == RemoteControlClient.RCSE_ID_UNREGISTERED) { + return 0; + } + return mMainRemote.mVolumeMax; + } + } + + protected int getRemoteStreamVolume() { + synchronized (mMainRemote) { + if (mMainRemote.mRccId == RemoteControlClient.RCSE_ID_UNREGISTERED) { + return 0; + } + return mMainRemote.mVolume; + } + } + + protected void setRemoteStreamVolume(int vol) { + if (DEBUG_VOL) { Log.d(TAG, "setRemoteStreamVolume(vol="+vol+")"); } + int rccId = RemoteControlClient.RCSE_ID_UNREGISTERED; + synchronized (mMainRemote) { + if (mMainRemote.mRccId == RemoteControlClient.RCSE_ID_UNREGISTERED) { + return; + } + rccId = mMainRemote.mRccId; + } + IRemoteVolumeObserver rvo = null; + synchronized (mRCStack) { + // The stack traversal order doesn't matter because there is only one stack entry + // with this RCC ID, but the matching ID is more likely at the top of the stack, so + // start iterating from the top. + try { + for (int index = mRCStack.size()-1; index >= 0; index--) { + final RemoteControlStackEntry rcse = mRCStack.elementAt(index); + //FIXME OPTIMIZE store this info in mMainRemote so we don't have to iterate? + if (rcse.mRccId == rccId) { + rvo = rcse.mRemoteVolumeObs; + break; + } + } + } catch (ArrayIndexOutOfBoundsException e) { + // not expected to happen, indicates improper concurrent modification + Log.e(TAG, "Wrong index accessing media button stack, lock error? ", e); + } + } + if (rvo != null) { + try { + rvo.dispatchRemoteVolumeUpdate(0, vol); + } catch (RemoteException e) { + Log.e(TAG, "Error dispatching absolute volume update", e); + } + } + } + + /** + * Call to make AudioService reevaluate whether it's in a mode where remote players should + * have their volume controlled. In this implementation this is only to reset whether + * VolumePanel should display remote volumes + */ + private void postReevaluateRemote() { + sendMsg(mEventHandler, MSG_REEVALUATE_REMOTE, SENDMSG_QUEUE, 0, 0, null, 0); + } + + private void onReevaluateRemote() { + if (DEBUG_VOL) { Log.w(TAG, "onReevaluateRemote()"); } + // is there a registered RemoteControlClient that is handling remote playback + boolean hasRemotePlayback = false; + synchronized (mRCStack) { + // iteration stops when PLAYBACK_TYPE_REMOTE is found, so remote control stack + // traversal order doesn't matter + Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); + while(stackIterator.hasNext()) { + RemoteControlStackEntry rcse = stackIterator.next(); + if (rcse.mPlaybackType == RemoteControlClient.PLAYBACK_TYPE_REMOTE) { + hasRemotePlayback = true; + break; + } + } + } + synchronized (mMainRemote) { + if (mHasRemotePlayback != hasRemotePlayback) { + mHasRemotePlayback = hasRemotePlayback; + mVolumeController.postRemoteSliderVisibility(hasRemotePlayback); + } + } + } + +} diff --git a/media/java/android/media/VolumeController.java b/media/java/android/media/VolumeController.java new file mode 100644 index 0000000..2d12bf2 --- /dev/null +++ b/media/java/android/media/VolumeController.java @@ -0,0 +1,29 @@ +/* + * 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.media; + +/** + * @hide + */ +public interface VolumeController { + + public void postHasNewRemotePlaybackInfo(); + + public void postRemoteVolumeChanged(int streamType, int flags); + + public void postRemoteSliderVisibility(boolean visible); +} diff --git a/media/jni/android_media_ImageReader.cpp b/media/jni/android_media_ImageReader.cpp index 7866df4..d876bd2 100644 --- a/media/jni/android_media_ImageReader.cpp +++ b/media/jni/android_media_ImageReader.cpp @@ -541,7 +541,8 @@ static void ImageReader_init(JNIEnv* env, jobject thiz, jobject weakThiz, nativeFormat = Image_getPixelFormat(env, format); - sp<CpuConsumer> consumer = new CpuConsumer(maxImages); + sp<BufferQueue> bq = new BufferQueue(); + sp<CpuConsumer> consumer = new CpuConsumer(bq, true, maxImages); // TODO: throw dvm exOutOfMemoryError? if (consumer == NULL) { jniThrowRuntimeException(env, "Failed to allocate native CpuConsumer"); diff --git a/media/mca/filterfw/native/core/gl_env.cpp b/media/mca/filterfw/native/core/gl_env.cpp index 73768fe..63fd16e 100644 --- a/media/mca/filterfw/native/core/gl_env.cpp +++ b/media/mca/filterfw/native/core/gl_env.cpp @@ -160,7 +160,8 @@ bool GLEnv::InitWithNewContext() { } // Create dummy surface using a GLConsumer - surfaceTexture_ = new GLConsumer(0); + sp<BufferQueue> bq = new BufferQueue(); + surfaceTexture_ = new GLConsumer(bq, 0); window_ = new Surface(static_cast<sp<IGraphicBufferProducer> >( surfaceTexture_->getBufferQueue())); 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 1f478d2..5e4fabd 100644 --- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java @@ -271,10 +271,10 @@ public class CameraDeviceBinderTest extends AndroidTestCase { // (streaming) int requestId1; - requestId1 = mCameraUser.submitRequest(request, /* streaming */true); + requestId1 = mCameraUser.submitRequest(request, /* streaming */false); assertTrue("Request IDs should be non-negative", requestId1 >= 0); - int requestIdStreaming = mCameraUser.submitRequest(request, /* streaming */false); + int requestIdStreaming = mCameraUser.submitRequest(request, /* streaming */true); assertTrue("Request IDs should be non-negative", requestIdStreaming >= 0); assertNotSame("Request IDs should be unique for multiple requests", requestId1, requestIdStreaming); diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java index 0c2f3a3..131441b 100644 --- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java @@ -19,8 +19,10 @@ package com.android.mediaframeworktest.unit; import android.os.Parcel; import android.test.suitebuilder.annotation.SmallTest; import android.graphics.ImageFormat; +import android.graphics.Rect; import android.hardware.photography.CameraMetadata; import android.hardware.photography.Rational; +import android.hardware.photography.Size; import static android.hardware.photography.CameraMetadata.*; @@ -223,6 +225,10 @@ public class CameraMetadataTest extends junit.framework.TestCase { assertEquals(null, mMetadata.readValues(ANDROID_COLOR_CORRECTION_MODE)); + // Write/read null values + mMetadata.writeValues(ANDROID_COLOR_CORRECTION_MODE, null); + assertEquals(null, mMetadata.readValues(ANDROID_COLOR_CORRECTION_MODE)); + // Write 0 values mMetadata.writeValues(ANDROID_COLOR_CORRECTION_MODE, new byte[] {}); @@ -286,13 +292,21 @@ public class CameraMetadataTest extends junit.framework.TestCase { } private <T> void checkKeyGetAndSet(String keyStr, Class<T> type, T value) { + assertFalse("Use checkKeyGetAndSetArray to compare array Keys", type.isArray()); + Key<T> key = new Key<T>(keyStr, type); assertNull(mMetadata.get(key)); + mMetadata.set(key, null); + assertNull(mMetadata.get(key)); mMetadata.set(key, value); - assertEquals(value, mMetadata.get(key)); + + T actual = mMetadata.get(key); + assertEquals(value, actual); } private <T> void checkKeyGetAndSetArray(String keyStr, Class<T> type, T value) { + assertTrue(type.isArray()); + Key<T> key = new Key<T>(keyStr, type); assertNull(mMetadata.get(key)); mMetadata.set(key, value); @@ -508,4 +522,73 @@ public class CameraMetadataTest extends junit.framework.TestCase { assertEquals(expectedIntValues[i], bf.getInt()); } } + + @SmallTest + public void testReadWriteSize() { + // int32 x n + checkKeyGetAndSet("android.jpeg.thumbnailSize", Size.class, new Size(123, 456)); + + // int32 x 2 x n + checkKeyGetAndSetArray("android.scaler.availableJpegSizes", Size[].class, new Size[] { + new Size(123, 456), + new Size(0xDEAD, 0xF00D), + new Size(0xF00, 0xB00) + }); + } + + @SmallTest + public void testReadWriteRectangle() { + // int32 x n + checkKeyGetAndSet("android.scaler.cropRegion", Rect.class, new Rect(10, 11, 1280, 1024)); + + // int32 x 2 x n + checkKeyGetAndSetArray("android.statistics.faceRectangles", Rect[].class, new Rect[] { + new Rect(110, 111, 11280, 11024), + new Rect(210, 111, 21280, 21024), + new Rect(310, 111, 31280, 31024) + }); + } + + @SmallTest + public void testReadWriteString() { + // (byte) string + Key<String> gpsProcessingMethodKey = + new Key<String>("android.jpeg.gpsProcessingMethod", String.class); + + String helloWorld = new String("HelloWorld"); + byte[] helloWorldBytes = new byte[] { + 'H', 'e', 'l', 'l', 'o', 'W', 'o', 'r', 'l', 'd', '\0' }; + + mMetadata.set(gpsProcessingMethodKey, helloWorld); + + String actual = mMetadata.get(gpsProcessingMethodKey); + assertEquals(helloWorld, actual); + + byte[] actualBytes = mMetadata.readValues(getTag(gpsProcessingMethodKey.getName())); + assertArrayEquals(helloWorldBytes, actualBytes); + + // Does not yet test as a string[] since we don't support that in native code. + + // (byte) string + Key<String[]> gpsProcessingMethodKeyArray = + new Key<String[]>("android.jpeg.gpsProcessingMethod", String[].class); + + String[] gpsStrings = new String[] { "HelloWorld", "FooBar", "Shazbot" }; + byte[] gpsBytes = new byte[] { + 'H', 'e', 'l', 'l', 'o', 'W', 'o', 'r', 'l', 'd', '\0', + 'F', 'o', 'o', 'B', 'a', 'r', '\0', + 'S', 'h', 'a', 'z', 'b', 'o', 't', '\0'}; + + mMetadata.set(gpsProcessingMethodKeyArray, gpsStrings); + + String[] actualArray = mMetadata.get(gpsProcessingMethodKeyArray); + assertArrayEquals(gpsStrings, actualArray); + + byte[] actualBytes2 = mMetadata.readValues(getTag(gpsProcessingMethodKeyArray.getName())); + assertArrayEquals(gpsBytes, actualBytes2); + } + + <T> void compareGeneric(T expected, T actual) { + assertEquals(expected, actual); + } } diff --git a/packages/DocumentsUI/AndroidManifest.xml b/packages/DocumentsUI/AndroidManifest.xml index ae11a8c..453ef45 100644 --- a/packages/DocumentsUI/AndroidManifest.xml +++ b/packages/DocumentsUI/AndroidManifest.xml @@ -22,7 +22,7 @@ </activity> <!-- TODO: remove when we have real clients --> - <activity android:name=".TestActivity"> + <activity android:name=".TestActivity" android:enabled="false"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.DEFAULT" /> diff --git a/packages/Keyguard/res/values-hdpi/dimens.xml b/packages/Keyguard/res/values-hdpi/dimens.xml new file mode 100644 index 0000000..2c209e2 --- /dev/null +++ b/packages/Keyguard/res/values-hdpi/dimens.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* //device/apps/common/assets/res/any/dimens.xml +** +** Copyright 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. +*/ +--> +<resources> + + <!-- Height of the sliding KeyguardSecurityContainer (includes 2x keyguard_security_view_margin) --> + <dimen name="keyguard_security_height">345dp</dimen> + +</resources> diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardViewBase.java b/packages/Keyguard/src/com/android/keyguard/KeyguardViewBase.java index 714dfbd..893562e 100644 --- a/packages/Keyguard/src/com/android/keyguard/KeyguardViewBase.java +++ b/packages/Keyguard/src/com/android/keyguard/KeyguardViewBase.java @@ -163,7 +163,8 @@ public abstract class KeyguardViewBase extends FrameLayout { case KeyEvent.KEYCODE_MEDIA_PREVIOUS: case KeyEvent.KEYCODE_MEDIA_REWIND: case KeyEvent.KEYCODE_MEDIA_RECORD: - case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: { + case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: + case KeyEvent.KEYCODE_MEDIA_AUDIO_TRACK: { handleMediaKeyEvent(event); return true; } @@ -204,7 +205,8 @@ public abstract class KeyguardViewBase extends FrameLayout { case KeyEvent.KEYCODE_MEDIA_PREVIOUS: case KeyEvent.KEYCODE_MEDIA_REWIND: case KeyEvent.KEYCODE_MEDIA_RECORD: - case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: { + case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: + case KeyEvent.KEYCODE_MEDIA_AUDIO_TRACK: { handleMediaKeyEvent(event); return true; } diff --git a/packages/PrintSpooler/Android.mk b/packages/PrintSpooler/Android.mk index a68fcdf..8ae0302 100644 --- a/packages/PrintSpooler/Android.mk +++ b/packages/PrintSpooler/Android.mk @@ -22,7 +22,7 @@ LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_PACKAGE_NAME := PrintSpooler -LOCAL_JAVA_LIBRARIES := framework +LOCAL_JAVA_LIBRARIES := framework-base LOCAL_CERTIFICATE := platform diff --git a/packages/PrintSpooler/AndroidManifest.xml b/packages/PrintSpooler/AndroidManifest.xml index fbb0060..f0bbfa4 100644 --- a/packages/PrintSpooler/AndroidManifest.xml +++ b/packages/PrintSpooler/AndroidManifest.xml @@ -46,7 +46,8 @@ <activity android:name=".PrintJobConfigActivity" - android:exported="true"> + android:exported="true" + android:theme="@android:style/Theme.Holo.Light.Dialog.NoActionBar"> </activity> </application> diff --git a/packages/PrintSpooler/res/layout/print_job_config_activity.xml b/packages/PrintSpooler/res/layout/print_job_config_activity.xml index 51e425d..8736bdd 100644 --- a/packages/PrintSpooler/res/layout/print_job_config_activity.xml +++ b/packages/PrintSpooler/res/layout/print_job_config_activity.xml @@ -14,248 +14,197 @@ limitations under the License. --> -<ScrollView xmlns:android="http://schemas.android.com/apk/res/android" +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" - android:layout_height="wrap_content"> + android:layout_height="wrap_content" + android:orientation="vertical"> - <GridLayout - android:layout_width="wrap_content" + <ScrollView + android:layout_width="fill_parent" android:layout_height="wrap_content" - android:layout_gravity="center" - android:orientation="vertical" - android:columnCount="2"> + android:background="@*android:color/bright_foreground_disabled_holo_light"> - <EditText - android:id="@+id/copies_edittext" - android:layout_width="fill_parent" - android:layout_height="wrap_content" - android:layout_marginLeft="12dip" - android:layout_marginRight="12dip" - android:layout_row="0" - android:layout_column="1" - android:minWidth="150dip" - android:inputType="number" - android:selectAllOnFocus="true"> - </EditText> - - <TextView - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginLeft="12dip" - android:layout_marginRight="12dip" - android:layout_row="0" - android:layout_column="0" - android:text="@string/label_copies" - android:textAppearance="?android:attr/textAppearanceMedium" - android:labelFor="@id/copies_edittext"> - </TextView> - - <TextView - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginLeft="12dip" - android:layout_marginRight="12dip" - android:layout_row="1" - android:layout_column="0" - android:text="@string/label_destination" - android:textAppearance="?android:attr/textAppearanceMedium"> - </TextView> - - <Spinner - android:id="@+id/destination_spinner" - android:layout_width="fill_parent" - android:layout_height="wrap_content" - android:layout_marginLeft="12dip" - android:layout_marginRight="12dip" - android:layout_row="1" - android:layout_column="1" - android:minWidth="150dip"> - </Spinner> - - - <TextView - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginLeft="12dip" - android:layout_marginRight="12dip" - android:layout_row="2" - android:layout_column="0" - android:text="@string/label_media_size" - android:textAppearance="?android:attr/textAppearanceMedium"> - </TextView> - - <Spinner - android:id="@+id/media_size_spinner" - android:layout_width="fill_parent" - android:layout_height="wrap_content" - android:layout_marginLeft="12dip" - android:layout_marginRight="12dip" - android:layout_row="2" - android:layout_column="1" - android:minWidth="150dip"> - </Spinner> - - - <TextView - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginLeft="12dip" - android:layout_marginRight="12dip" - android:layout_row="3" - android:layout_column="0" - android:text="@string/label_resolution" - android:textAppearance="?android:attr/textAppearanceMedium"> - </TextView> - - <Spinner - android:id="@+id/resolution_spinner" - android:layout_width="fill_parent" - android:layout_height="wrap_content" - android:layout_marginLeft="12dip" - android:layout_marginRight="12dip" - android:layout_row="3" - android:layout_column="1" - android:minWidth="150dip"> - </Spinner> - - - <TextView - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginLeft="12dip" - android:layout_marginRight="12dip" - android:layout_row="4" - android:layout_column="0" - android:text="@string/label_input_tray" - android:textAppearance="?android:attr/textAppearanceMedium"> - </TextView> - - <Spinner - android:id="@+id/input_tray_spinner" - android:layout_width="fill_parent" - android:layout_height="wrap_content" - android:layout_marginLeft="12dip" - android:layout_marginRight="12dip" - android:layout_row="4" - android:layout_column="1" - android:minWidth="150dip"> - </Spinner> - - - <TextView + <GridLayout android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_marginLeft="12dip" - android:layout_marginRight="12dip" - android:layout_row="5" - android:layout_column="0" - android:text="@string/label_output_tray" - android:textAppearance="?android:attr/textAppearanceMedium"> - </TextView> - - <Spinner - android:id="@+id/output_tray_spinner" - android:layout_width="fill_parent" - android:layout_height="wrap_content" - android:layout_marginLeft="12dip" - android:layout_marginRight="12dip" - android:layout_row="5" - android:layout_column="1" - android:minWidth="150dip"> - </Spinner> - - - <TextView - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginLeft="12dip" - android:layout_marginRight="12dip" - android:layout_row="6" - android:layout_column="0" - android:text="@string/label_duplex_mode" - android:textAppearance="?android:attr/textAppearanceMedium"> - </TextView> - - <Spinner - android:id="@+id/duplex_mode_spinner" - android:layout_width="fill_parent" - android:layout_height="wrap_content" - android:layout_marginLeft="12dip" - android:layout_marginRight="12dip" - android:layout_row="6" - android:layout_column="1" - android:minWidth="150dip"> - </Spinner> - - - <TextView - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginLeft="12dip" - android:layout_marginRight="12dip" - android:layout_row="7" - android:layout_column="0" - android:text="@string/label_color_mode" - android:textAppearance="?android:attr/textAppearanceMedium"> - </TextView> - - <Spinner - android:id="@+id/color_mode_spinner" - android:layout_width="fill_parent" - android:layout_height="wrap_content" - android:layout_marginLeft="12dip" - android:layout_marginRight="12dip" - android:layout_row="7" - android:layout_column="1" - android:minWidth="150dip"> - </Spinner> - - - <TextView - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginLeft="12dip" - android:layout_marginRight="12dip" - android:layout_row="8" - android:layout_column="0" - android:text="@string/label_fitting_mode" - android:textAppearance="?android:attr/textAppearanceMedium"> - </TextView> - - <Spinner - android:id="@+id/fitting_mode_spinner" - android:layout_width="fill_parent" - android:layout_height="wrap_content" - android:layout_marginLeft="12dip" - android:layout_marginRight="12dip" - android:layout_row="8" - android:layout_column="1" - android:minWidth="150dip"> - </Spinner> - - - <TextView - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginLeft="12dip" - android:layout_marginRight="12dip" - android:layout_row="9" - android:layout_column="0" - android:text="@string/label_orientation" - android:textAppearance="?android:attr/textAppearanceMedium"> - </TextView> - - <Spinner - android:id="@+id/orientation_spinner" - android:layout_width="fill_parent" - android:layout_height="wrap_content" - android:layout_marginLeft="12dip" - android:layout_marginRight="12dip" - android:layout_row="9" - android:layout_column="1" - android:minWidth="150dip"> - </Spinner> - - </GridLayout> + android:layout_margin="32dip" + android:orientation="vertical" + android:columnCount="2"> + + <!-- Destination --> + + <Spinner + android:id="@+id/destination_spinner" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:layout_marginBottom="12dip" + android:layout_row="0" + android:layout_column="0" + android:layout_columnSpan="2" + android:minWidth="324dip" + android:minHeight="?android:attr/listPreferredItemHeightSmall"> + </Spinner> + + <!-- Copies --> + + <view + class="com.android.printspooler.PrintJobConfigActivity$CustomEditText" + android:id="@+id/copies_edittext" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:layout_marginRight="12dip" + android:layout_marginBottom="12dip" + android:layout_row="2" + android:layout_column="0" + android:layout_gravity="bottom" + android:inputType="numberDecimal" + android:selectAllOnFocus="true" + android:minWidth="150dip"> + </view> + + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="12dip" + android:layout_marginRight="12dip" + android:layout_row="1" + android:layout_column="0" + android:layout_gravity="left|bottom" + android:text="@string/label_copies" + android:textAppearance="?android:attr/textAppearanceSmall" + android:textStyle="bold" + android:labelFor="@id/copies_edittext"> + </TextView> + + <!-- Paper size --> + + <Spinner + android:id="@+id/paper_size_spinner" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:layout_marginLeft="12dip" + android:layout_marginBottom="12dip" + android:layout_row="2" + android:layout_column="1" + android:minWidth="150dip"> + </Spinner> + + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginLeft="12dip" + android:layout_marginTop="12dip" + android:layout_row="1" + android:layout_column="1" + android:text="@string/label_paper_size" + android:textAppearance="?android:attr/textAppearanceSmall" + android:textStyle="bold" + android:labelFor="@id/paper_size_spinner"> + </TextView> + + <!-- Color --> + + <Spinner + android:id="@+id/color_spinner" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:layout_marginRight="12dip" + android:layout_marginBottom="12dip" + android:layout_row="4" + android:layout_column="0" + android:minWidth="150dip"> + </Spinner> + + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="12dip" + android:layout_marginRight="12dip" + android:layout_row="3" + android:layout_column="0" + android:text="@string/label_color" + android:textAppearance="?android:attr/textAppearanceSmall" + android:textStyle="bold" + android:labelFor="@id/color_spinner"> + </TextView> + + <!-- Orientation --> + + <Spinner + android:id="@+id/orientation_spinner" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:layout_marginLeft="12dip" + android:layout_marginBottom="12dip" + android:layout_row="4" + android:layout_column="1" + android:minWidth="150dip"> + </Spinner> + + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginLeft="12dip" + android:layout_marginTop="12dip" + android:layout_row="3" + android:layout_column="1" + android:text="@string/label_orientation" + android:textAppearance="?android:attr/textAppearanceSmall" + android:textStyle="bold" + android:labelFor="@id/orientation_spinner"> + </TextView> + + <!-- Pages --> + + <Spinner + android:id="@+id/range_options_spinner" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:layout_marginRight="12dip" + android:layout_row="6" + android:layout_column="0" + android:minWidth="150dip"> + </Spinner> + + <EditText + android:id="@+id/page_range_edittext" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:layout_marginLeft="12dip" + android:layout_row="6" + android:layout_column="1" + android:layout_gravity="bottom" + android:selectAllOnFocus="true" + android:minWidth="150dip" + android:hint="@string/pages_range_example" + android:inputType="textNoSuggestions" + android:visibility="gone"> + </EditText> + + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="12dip" + android:layout_marginRight="12dip" + android:layout_row="5" + android:layout_column="0" + android:text="@string/label_pages" + android:textAppearance="?android:attr/textAppearanceSmall" + android:textStyle="bold" + android:labelFor="@id/range_options_spinner"> + </TextView> + + </GridLayout> + + </ScrollView> + + <Button + android:id="@+id/print_button" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:padding="0dip" + android:text="@string/print_button" + android:background="?android:attr/selectableItemBackground"> + </Button> -</ScrollView> +</LinearLayout> diff --git a/packages/PrintSpooler/res/layout/spinner_dropdown_item.xml b/packages/PrintSpooler/res/layout/spinner_dropdown_item.xml new file mode 100644 index 0000000..66c6724 --- /dev/null +++ b/packages/PrintSpooler/res/layout/spinner_dropdown_item.xml @@ -0,0 +1,48 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:paddingLeft="8dip" + android:paddingRight="8dip" + android:minHeight="?android:attr/listPreferredItemHeightSmall" + android:orientation="vertical" + android:gravity="center_vertical"> + + <TextView + android:id="@+id/title" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textAppearance="?android:attr/textAppearanceMedium" + android:singleLine="true" + android:ellipsize="end" + android:textIsSelectable="false"> + </TextView> + + <TextView + android:id="@+id/subtitle" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textAppearance="?android:attr/textAppearanceSmall" + android:singleLine="true" + android:ellipsize="end" + android:textIsSelectable="false" + android:visibility="gone"> + + </TextView> + +</LinearLayout> diff --git a/packages/PrintSpooler/res/menu/print_job_config_activity.xml b/packages/PrintSpooler/res/values/constants.xml index 149c274..7d2cdc3 100644 --- a/packages/PrintSpooler/res/menu/print_job_config_activity.xml +++ b/packages/PrintSpooler/res/values/constants.xml @@ -13,9 +13,15 @@ See the License for the specific language governing permissions and limitations under the License. --> -<menu xmlns:android="http://schemas.android.com/apk/res/android"> - <item android:id="@+id/print_button" - android:title="@string/print_button" - android:showAsAction="ifRoom"> - </item> -</menu> + +<resources> + + <integer name="page_option_value_all">1</integer> + <integer name="page_option_value_page_range">2</integer> + + <integer-array name="page_options_values" translatable="false"> + <item>@integer/page_option_value_all</item> + <item>@integer/page_option_value_page_range</item> + </integer-array> + +</resources>
\ No newline at end of file diff --git a/packages/PrintSpooler/res/values/strings.xml b/packages/PrintSpooler/res/values/strings.xml index 8b4b40a..de6fb60 100644 --- a/packages/PrintSpooler/res/values/strings.xml +++ b/packages/PrintSpooler/res/values/strings.xml @@ -16,74 +16,44 @@ <resources> - <!-- Title of the PrintSpooler application. [CHAR LIMIT=16] --> + <!-- Title of the PrintSpooler application. [CHAR LIMIT=50] --> <string name="app_label">Print Spooler</string> - <!-- Title of the print dialog. [CHAR LIMIT=10] --> - <string name="print_job_config_dialog_title">Print</string> - <!-- Label of the print dialog's print button. [CHAR LIMIT=16] --> - <string name="print_button">Print</string> - - <!-- Label of the print dialog's cancel button. [CHAR LIMIT=16] --> - <string name="cancel_button">Cancel</string> - - <!-- Label of the destination spinner. [CHAR LIMIT=16] --> - <string name="label_destination">Destination</string> - - <!-- Label of the copies count edit text. [CHAR LIMIT=16] --> - <string name="label_copies">Copies</string> - - <!-- Label of the media size spinner. [CHAR LIMIT=16] --> - <string name="label_media_size">Media size</string> + <string name="print_button">PRINT</string> - <!-- Label of the resolution spinner. [CHAR LIMIT=16] --> - <string name="label_resolution">Resolution</string> + <!-- Label of the destination widget. [CHAR LIMIT=20] --> + <string name="label_destination">DESTIINATION</string> - <!-- Label of the input tray spinner. [CHAR LIMIT=16] --> - <string name="label_input_tray">Input tray</string> + <!-- Label of the copies count widget. [CHAR LIMIT=20] --> + <string name="label_copies">COPIES</string> - <!-- Label of the output tray spinner. [CHAR LIMIT=16] --> - <string name="label_output_tray">Output tray</string> + <!-- Label of the paper size widget. [CHAR LIMIT=20] --> + <string name="label_paper_size">PAPER SIZE</string> - <!-- Label of the duplex mode spinner. [CHAR LIMIT=16] --> - <string name="label_duplex_mode">Duplex mode</string> + <!-- Label of the color mode widget. [CHAR LIMIT=20] --> + <string name="label_color">COLOR</string> - <!-- Label of the color mode spinner. [CHAR LIMIT=16] --> - <string name="label_color_mode">Color mode</string> + <!-- Label of the orientation widget. [CHAR LIMIT=20] --> + <string name="label_orientation">ORIENTATION</string> - <!-- Label of the fitting mode spinner. [CHAR LIMIT=16] --> - <string name="label_fitting_mode">Fitting mode</string> + <!-- Label of the page selection widget. [CHAR LIMIT=20] --> + <string name="label_pages">PAGES</string> - <!-- Label of the orientation spinner. [CHAR LIMIT=16] --> - <string name="label_orientation">Orientation</string> + <!-- Page range exmple used as a hint of how to specify such. [CHAR LIMIT=15] --> + <string name="pages_range_example">e.g. 1–5, 8</string> - <!-- Duplex mode labels. --> - <string-array name="duplex_mode_labels"> - <!-- Duplex mode label: No duplexing. [CHAR LIMIT=20] --> - <item>None</item> - <!-- Duplex mode label: Turn a page along its long edge, e.g. like a book. [CHAR LIMIT=20] --> - <item>Long edge</item> - <!-- Duplex mode label: Turn a page along its short edge, e.g. like a notepad. [CHAR LIMIT=20] --> - <item>Short edge</item> - </string-array> + <!-- Message to notify the user of entering invalid input. [CHAR LIMIT=25] --> + <string name="invalid_input">Invalid input</string> <!-- Color mode labels. --> <string-array name="color_mode_labels"> <!-- Color modelabel: Monochrome color scheme, e.g. one color is used. [CHAR LIMIT=20] --> - <item>Monochrome</item> + <item>Black & White</item> <!-- Color mode label: Color color scheme, e.g. many colors are used. [CHAR LIMIT=20] --> <item>Color</item> </string-array> - <!-- Fitting mode labels. --> - <string-array name="fitting_mode_labels"> - <!-- Fitting mode label: No fitting. [CHAR LIMIT=30] --> - <item>None</item> - <!-- Fitting mode label: Fit the content to the page. [CHAR LIMIT=30] --> - <item>Fit to page</item> - </string-array> - <!-- Orientation labels. --> <string-array name="orientation_labels"> <!-- Orientation label: Portrait page orientation. [CHAR LIMIT=30] --> @@ -92,6 +62,14 @@ <item>Landscape</item> </string-array> + <!-- Page options labels. --> + <string-array name="page_options_labels"> + <!-- Page range option label: Print all pages [CHAR LIMIT=30] --> + <item>All</item> + <!-- Page range option label: Print a page range [CHAR LIMIT=30] --> + <item>Range</item> + </string-array> + <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. --> <string name="permlab_bindPrintSpoolerService">bind to a print spooler service</string> diff --git a/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java b/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java index ae2fe5c..19f545d 100644 --- a/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java +++ b/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java @@ -17,50 +17,57 @@ package com.android.printspooler; import android.app.Activity; +import android.content.Context; import android.content.Intent; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; +import android.graphics.Rect; import android.net.Uri; import android.os.AsyncTask; import android.os.Binder; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; +import android.os.IBinder.DeathRecipient; import android.os.Looper; import android.os.Message; import android.os.RemoteException; -import android.os.ServiceManager; import android.os.UserHandle; -import android.os.IBinder.DeathRecipient; -import android.print.IPrintAdapter; -import android.print.IPrintManager; +import android.print.IPrintDocumentAdapter; import android.print.IPrinterDiscoveryObserver; import android.print.PageRange; import android.print.PrintAttributes; import android.print.PrintAttributes.MediaSize; -import android.print.PrintAttributes.Resolution; -import android.print.PrintAttributes.Tray; +import android.print.PrintDocumentAdapter.LayoutResultCallback; +import android.print.PrintDocumentAdapter.WriteResultCallback; +import android.print.PrintDocumentInfo; import android.print.PrintJobInfo; import android.print.PrinterId; import android.print.PrinterInfo; import android.text.Editable; -import android.text.InputFilter; -import android.text.Spanned; import android.text.TextUtils; import android.text.TextWatcher; +import android.util.AttributeSet; import android.util.Log; -import android.view.Menu; -import android.view.MenuItem; import android.view.View; +import android.view.View.OnClickListener; +import android.view.ViewGroup; import android.view.WindowManager; +import android.view.inputmethod.InputMethodManager; import android.widget.AdapterView; import android.widget.AdapterView.OnItemSelectedListener; import android.widget.ArrayAdapter; +import android.widget.Button; import android.widget.EditText; import android.widget.Spinner; +import android.widget.TextView; import java.io.File; -import java.io.IOException; import java.util.ArrayList; import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; /** * Activity for configuring a print job. @@ -78,9 +85,15 @@ public class PrintJobConfigActivity extends Activity { private static final int MIN_COPIES = 1; - private final List<QueuedAsyncTask<?>> mTaskQueue = new ArrayList<QueuedAsyncTask<?>>(); + private static final Pattern PATTERN_DIGITS = Pattern.compile("\\d"); + + private static final Pattern PATTERN_ESCAPE_SPECIAL_CHARS = Pattern.compile( + "(?=[]\\[+&|!(){}^\"~*?:\\\\])"); + + private static final Pattern PATTERN_PAGE_RANGE = Pattern.compile( + "([0-9]+[\\s]*[\\-]?[\\s]*[0-9]*[\\s]*[,]?[\\s]*)+"); - private IPrintManager mPrintManager; + private final PrintSpooler mPrintSpooler = PrintSpooler.getInstance(this); private IPrinterDiscoveryObserver mPrinterDiscoveryObserver; @@ -89,46 +102,38 @@ public class PrintJobConfigActivity extends Activity { private PrintAttributes mPrintAttributes; - private final PrintSpooler mPrintSpooler = PrintSpooler.getInstance(this); + private RemotePrintDocumentAdapter mRemotePrintAdapter; + + private boolean mPrintConfirmed; - private RemotePrintAdapter mRemotePrintAdapter; + private boolean mStarted; + + private IBinder mIPrintDocumentAdapter; + + private PrintDocumentInfo mPrintDocumentInfo; // UI elements private EditText mCopiesEditText; + private EditText mRangeEditText; + private Spinner mDestinationSpinner; public ArrayAdapter<SpinnerItem<PrinterInfo>> mDestinationSpinnerAdapter; private Spinner mMediaSizeSpinner; public ArrayAdapter<SpinnerItem<MediaSize>> mMediaSizeSpinnerAdapter; - private Spinner mResolutionSpinner; - public ArrayAdapter<SpinnerItem<Resolution>> mResolutionSpinnerAdapter; - - private Spinner mInputTraySpinner; - public ArrayAdapter<SpinnerItem<Tray>> mInputTraySpinnerAdapter; - - private Spinner mOutputTraySpinner; - public ArrayAdapter<SpinnerItem<Tray>> mOutputTraySpinnerAdapter; - - private Spinner mDuplexModeSpinner; - public ArrayAdapter<SpinnerItem<Integer>> mDuplexModeSpinnerAdapter; - private Spinner mColorModeSpinner; public ArrayAdapter<SpinnerItem<Integer>> mColorModeSpinnerAdapter; - private Spinner mFittingModeSpinner; - public ArrayAdapter<SpinnerItem<Integer>> mFittingModeSpinnerAdapter; - private Spinner mOrientationSpinner; public ArrayAdapter<SpinnerItem<Integer>> mOrientationSpinnerAdapter; - private boolean mPrintStarted; + private Spinner mRangeOptionsSpinner; + public ArrayAdapter<SpinnerItem<Integer>> mRangeOptionsSpinnerAdapter; - private boolean mPrintConfirmed; - - private IBinder mPrinable; + private Button mPrintButton; // TODO: Implement store/restore state. @@ -143,35 +148,34 @@ public class PrintJobConfigActivity extends Activity { SpinnerItem<MediaSize> mediaItem = mMediaSizeSpinnerAdapter.getItem(position); mPrintAttributes.setMediaSize(mediaItem.value); updatePrintableContentIfNeeded(); - } else if (spinner == mResolutionSpinner) { - SpinnerItem<Resolution> resolutionItem = - mResolutionSpinnerAdapter.getItem(position); - mPrintAttributes.setResolution(resolutionItem.value); - updatePrintableContentIfNeeded(); - } else if (spinner == mInputTraySpinner) { - SpinnerItem<Tray> inputTrayItem = - mInputTraySpinnerAdapter.getItem(position); - mPrintAttributes.setInputTray(inputTrayItem.value); - } else if (spinner == mOutputTraySpinner) { - SpinnerItem<Tray> outputTrayItem = - mOutputTraySpinnerAdapter.getItem(position); - mPrintAttributes.setOutputTray(outputTrayItem.value); - } else if (spinner == mDuplexModeSpinner) { - SpinnerItem<Integer> duplexModeItem = - mDuplexModeSpinnerAdapter.getItem(position); - mPrintAttributes.setDuplexMode(duplexModeItem.value); } else if (spinner == mColorModeSpinner) { SpinnerItem<Integer> colorModeItem = mColorModeSpinnerAdapter.getItem(position); mPrintAttributes.setColorMode(colorModeItem.value); - } else if (spinner == mFittingModeSpinner) { - SpinnerItem<Integer> fittingModeItem = - mFittingModeSpinnerAdapter.getItem(position); - mPrintAttributes.setFittingMode(fittingModeItem.value); } else if (spinner == mOrientationSpinner) { SpinnerItem<Integer> orientationItem = mOrientationSpinnerAdapter.getItem(position); mPrintAttributes.setOrientation(orientationItem.value); + } else if (spinner == mRangeOptionsSpinner) { + SpinnerItem<Integer> rangeOptionItem = + mRangeOptionsSpinnerAdapter.getItem(position); + if (rangeOptionItem.value == getResources().getInteger( + R.integer.page_option_value_all)) { + mRangeEditText.setVisibility(View.INVISIBLE); + mRangeEditText.setEnabled(false); + mRangeEditText.setText(null); + mRangeEditText.setError(null); + mPrintButton.setEnabled(true); + } else if (rangeOptionItem.value == getResources().getInteger( + R.integer.page_option_value_page_range)) { + mRangeEditText.setVisibility(View.VISIBLE); + mRangeEditText.setEnabled(true); + mRangeEditText.requestFocus(); + mRangeEditText.setError(getString(R.string.invalid_input)); + InputMethodManager imm = (InputMethodManager) + getSystemService(INPUT_METHOD_SERVICE); + imm.showSoftInput(mRangeEditText, 0); + } } } @@ -181,11 +185,10 @@ public class PrintJobConfigActivity extends Activity { } }; - private final TextWatcher mTextWatcher = new TextWatcher() { + private final TextWatcher mCopiesTextWatcher = new TextWatcher() { @Override public void onTextChanged(CharSequence s, int start, int before, int count) { - final int copies = Integer.parseInt(mCopiesEditText.getText().toString()); - mPrintAttributes.setCopies(copies); + /* do nothing */ } @Override @@ -194,25 +197,64 @@ public class PrintJobConfigActivity extends Activity { } @Override - public void afterTextChanged(Editable s) { - /* do nothing */ + public void afterTextChanged(Editable editable) { + if (editable.length() == 0) { + mCopiesEditText.setError(getString(R.string.invalid_input)); + mPrintButton.setEnabled(false); + return; + } + final int copies = Integer.parseInt(editable.toString()); + if (copies < MIN_COPIES) { + mCopiesEditText.setError(getString(R.string.invalid_input)); + mPrintButton.setEnabled(false); + return; + } + mPrintAttributes.setCopies(copies); + mPrintButton.setEnabled(true); } }; - private final InputFilter mInputFilter = new InputFilter() { + private final TextWatcher mRangeTextWatcher = new TextWatcher() { + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + /* do nothing */ + } + + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + /* do nothing */ + } + @Override - public CharSequence filter(CharSequence source, int start, int end, - Spanned dest, int dstart, int dend) { - StringBuffer text = new StringBuffer(dest.toString()); - text.replace(dstart, dend, source.subSequence(start, end).toString()); + public void afterTextChanged(Editable editable) { + String text = editable.toString(); + if (TextUtils.isEmpty(text)) { - return dest; + mRangeEditText.setError(getString(R.string.invalid_input)); + mPrintButton.setEnabled(false); + return; } - final int copies = Integer.parseInt(text.toString()); - if (copies < MIN_COPIES) { - return dest; + + String escapedText = PATTERN_ESCAPE_SPECIAL_CHARS.matcher(text).replaceAll("////"); + if (!PATTERN_PAGE_RANGE.matcher(escapedText).matches()) { + mRangeEditText.setError(getString(R.string.invalid_input)); + mPrintButton.setEnabled(false); + return; } - return null; + + Matcher matcher = PATTERN_DIGITS.matcher(text); + while (matcher.find()) { + String numericString = text.substring(matcher.start(), matcher.end()); + final int pageIndex = Integer.parseInt(numericString); + if (pageIndex < 1 || pageIndex > mPrintDocumentInfo.getPageCount()) { + mRangeEditText.setError(getString(R.string.invalid_input)); + mPrintButton.setEnabled(false); + return; + } + } + + mRangeEditText.setError(null); + mPrintButton.setEnabled(true); } }; @@ -231,9 +273,6 @@ public class PrintJobConfigActivity extends Activity { getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN | WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN); - mPrintManager = (IPrintManager) IPrintManager.Stub.asInterface( - ServiceManager.getService(PRINT_SERVICE)); - Bundle extras = getIntent().getExtras(); mPrintJobId = extras.getInt(EXTRA_PRINT_JOB_ID, -1); @@ -251,15 +290,16 @@ public class PrintJobConfigActivity extends Activity { mPrintAttributes = new PrintAttributes.Builder().create(); } - mPrinable = extras.getBinder(EXTRA_PRINTABLE); - if (mPrinable == null) { + mIPrintDocumentAdapter = extras.getBinder(EXTRA_PRINTABLE); + if (mIPrintDocumentAdapter == null) { throw new IllegalArgumentException("Printable cannot be null"); } - mRemotePrintAdapter = new RemotePrintAdapter(IPrintAdapter.Stub.asInterface(mPrinable), + mRemotePrintAdapter = new RemotePrintDocumentAdapter( + IPrintDocumentAdapter.Stub.asInterface(mIPrintDocumentAdapter), mPrintSpooler.generateFileForPrintJob(mPrintJobId)); try { - mPrinable.linkToDeath(mDeathRecipient, 0); + mIPrintDocumentAdapter.linkToDeath(mDeathRecipient, 0); } catch (RemoteException re) { finish(); } @@ -271,7 +311,7 @@ public class PrintJobConfigActivity extends Activity { @Override protected void onDestroy() { - mPrinable.unlinkToDeath(mDeathRecipient, 0); + mIPrintDocumentAdapter.unlinkToDeath(mDeathRecipient, 0); super.onDestroy(); } @@ -279,70 +319,95 @@ public class PrintJobConfigActivity extends Activity { // Copies mCopiesEditText = (EditText) findViewById(R.id.copies_edittext); mCopiesEditText.setText(String.valueOf(MIN_COPIES)); - mCopiesEditText.addTextChangedListener(mTextWatcher); - mCopiesEditText.setFilters(new InputFilter[] {mInputFilter}); + mCopiesEditText.addTextChangedListener(mCopiesTextWatcher); // Destination. mDestinationSpinner = (Spinner) findViewById(R.id.destination_spinner); mDestinationSpinnerAdapter = new ArrayAdapter<SpinnerItem<PrinterInfo>>(this, - android.R.layout.simple_spinner_dropdown_item); + R.layout.spinner_dropdown_item) { + @Override + public View getDropDownView(int position, View convertView, ViewGroup parent) { + return getView(position, convertView, parent); + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + if (convertView == null) { + convertView = getLayoutInflater().inflate( + R.layout.spinner_dropdown_item, parent, false); + } + + PrinterInfo printerInfo = getItem(position).value; + TextView title = (TextView) convertView.findViewById(R.id.title); + title.setText(printerInfo.getLabel()); + + try { + TextView subtitle = (TextView) convertView.findViewById(R.id.subtitle); + PackageManager pm = getPackageManager(); + PackageInfo packageInfo = pm.getPackageInfo( + printerInfo.getId().getService().getPackageName(), 0); + subtitle.setText(packageInfo.applicationInfo.loadLabel(pm)); + subtitle.setVisibility(View.VISIBLE); + } catch (NameNotFoundException nnfe) { + /* ignore */ + } + + return convertView; + } + }; mDestinationSpinner.setAdapter(mDestinationSpinnerAdapter); mDestinationSpinner.setOnItemSelectedListener(mOnItemSelectedListener); // Media size. - mMediaSizeSpinner = (Spinner) findViewById(R.id.media_size_spinner); + mMediaSizeSpinner = (Spinner) findViewById(R.id.paper_size_spinner); mMediaSizeSpinnerAdapter = new ArrayAdapter<SpinnerItem<MediaSize>>(this, - android.R.layout.simple_spinner_dropdown_item); + R.layout.spinner_dropdown_item, R.id.title); mMediaSizeSpinner.setAdapter(mMediaSizeSpinnerAdapter); mMediaSizeSpinner.setOnItemSelectedListener(mOnItemSelectedListener); - // Resolution. - mResolutionSpinner = (Spinner) findViewById(R.id.resolution_spinner); - mResolutionSpinnerAdapter = new ArrayAdapter<SpinnerItem<Resolution>>(this, - android.R.layout.simple_spinner_dropdown_item); - mResolutionSpinner.setAdapter(mResolutionSpinnerAdapter); - mResolutionSpinner.setOnItemSelectedListener(mOnItemSelectedListener); - - // Input tray. - mInputTraySpinner = (Spinner) findViewById(R.id.input_tray_spinner); - mInputTraySpinnerAdapter = new ArrayAdapter<SpinnerItem<Tray>>(this, - android.R.layout.simple_spinner_dropdown_item); - mInputTraySpinner.setAdapter(mInputTraySpinnerAdapter); - - // Output tray. - mOutputTraySpinner = (Spinner) findViewById(R.id.output_tray_spinner); - mOutputTraySpinnerAdapter = new ArrayAdapter<SpinnerItem<Tray>>(this, - android.R.layout.simple_spinner_dropdown_item); - mOutputTraySpinner.setAdapter(mOutputTraySpinnerAdapter); - mOutputTraySpinner.setOnItemSelectedListener(mOnItemSelectedListener); - - // Duplex mode. - mDuplexModeSpinner = (Spinner) findViewById(R.id.duplex_mode_spinner); - mDuplexModeSpinnerAdapter = new ArrayAdapter<SpinnerItem<Integer>>(this, - android.R.layout.simple_spinner_dropdown_item); - mDuplexModeSpinner.setAdapter(mDuplexModeSpinnerAdapter); - mDuplexModeSpinner.setOnItemSelectedListener(mOnItemSelectedListener); - // Color mode. - mColorModeSpinner = (Spinner) findViewById(R.id.color_mode_spinner); + mColorModeSpinner = (Spinner) findViewById(R.id.color_spinner); mColorModeSpinnerAdapter = new ArrayAdapter<SpinnerItem<Integer>>(this, - android.R.layout.simple_spinner_dropdown_item); + R.layout.spinner_dropdown_item, R.id.title); mColorModeSpinner.setAdapter(mColorModeSpinnerAdapter); mColorModeSpinner.setOnItemSelectedListener(mOnItemSelectedListener); - // Color mode. - mFittingModeSpinner = (Spinner) findViewById(R.id.fitting_mode_spinner); - mFittingModeSpinnerAdapter = new ArrayAdapter<SpinnerItem<Integer>>(this, - android.R.layout.simple_spinner_dropdown_item); - mFittingModeSpinner.setAdapter(mFittingModeSpinnerAdapter); - mFittingModeSpinner.setOnItemSelectedListener(mOnItemSelectedListener); - // Orientation mOrientationSpinner = (Spinner) findViewById(R.id.orientation_spinner); mOrientationSpinnerAdapter = new ArrayAdapter<SpinnerItem<Integer>>(this, - android.R.layout.simple_spinner_dropdown_item); + R.layout.spinner_dropdown_item, R.id.title); mOrientationSpinner.setAdapter(mOrientationSpinnerAdapter); mOrientationSpinner.setOnItemSelectedListener(mOnItemSelectedListener); + + // Range + mRangeEditText = (EditText) findViewById(R.id.page_range_edittext); + mRangeEditText.addTextChangedListener(mRangeTextWatcher); + + // Range options + mRangeOptionsSpinner = (Spinner) findViewById(R.id.range_options_spinner); + mRangeOptionsSpinnerAdapter = new ArrayAdapter<SpinnerItem<Integer>>(this, + R.layout.spinner_dropdown_item, R.id.title); + mRangeOptionsSpinner.setAdapter(mRangeOptionsSpinnerAdapter); + mRangeOptionsSpinner.setOnItemSelectedListener(mOnItemSelectedListener); + final int[] rangeOptionsValues = getResources().getIntArray( + R.array.page_options_values); + String[] rangeOptionsLabels = getResources().getStringArray( + R.array.page_options_labels); + final int rangeOptionsCount = rangeOptionsLabels.length; + for (int i = 0; i < rangeOptionsCount; i++) { + mRangeOptionsSpinnerAdapter.add(new SpinnerItem<Integer>( + rangeOptionsValues[i], rangeOptionsLabels[i])); + } + mRangeOptionsSpinner.setSelection(0); + + mPrintButton = (Button) findViewById(R.id.print_button); + mPrintButton.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + mPrintConfirmed = true; + finish(); + } + }); } private void updateUi() { @@ -353,6 +418,7 @@ public class PrintJobConfigActivity extends Activity { // Copies. mCopiesEditText.setText(String.valueOf( Math.max(mPrintAttributes.getCopies(), MIN_COPIES))); + mCopiesEditText.selectAll(); // Media size. mMediaSizeSpinnerAdapter.clear(); @@ -361,71 +427,12 @@ public class PrintJobConfigActivity extends Activity { for (int i = 0; i < mediaSizeCount; i++) { MediaSize mediaSize = mediaSizes.get(i); mMediaSizeSpinnerAdapter.add(new SpinnerItem<MediaSize>( - mediaSize, mediaSize.getLabel(getPackageManager()))); + mediaSize, mediaSize.getLabel())); } final int selectedMediaSizeIndex = mediaSizes.indexOf( mPrintAttributes.getMediaSize()); mMediaSizeSpinner.setOnItemSelectedListener(null); mMediaSizeSpinner.setSelection(selectedMediaSizeIndex); - mMediaSizeSpinner.setOnItemSelectedListener(mOnItemSelectedListener); - - // Resolution. - mResolutionSpinnerAdapter.clear(); - List<Resolution> resolutions = printer.getResolutions(); - final int resolutionCount = resolutions.size(); - for (int i = 0; i < resolutionCount; i++) { - Resolution resolution = resolutions.get(i); - mResolutionSpinnerAdapter.add(new SpinnerItem<Resolution>( - resolution, resolution.getLabel(getPackageManager()))); - } - final int selectedResolutionIndex = resolutions.indexOf( - mPrintAttributes.getResolution()); - mResolutionSpinner.setOnItemSelectedListener(null); - mResolutionSpinner.setSelection(selectedResolutionIndex); - mResolutionSpinner.setOnItemSelectedListener(mOnItemSelectedListener); - - // Input tray. - mInputTraySpinnerAdapter.clear(); - List<Tray> inputTrays = printer.getInputTrays(); - final int inputTrayCount = inputTrays.size(); - for (int i = 0; i < inputTrayCount; i++) { - Tray inputTray = inputTrays.get(i); - mInputTraySpinnerAdapter.add(new SpinnerItem<Tray>( - inputTray, inputTray.getLabel(getPackageManager()))); - } - final int selectedInputTrayIndex = inputTrays.indexOf( - mPrintAttributes.getInputTray()); - mInputTraySpinner.setSelection(selectedInputTrayIndex); - - // Output tray. - mOutputTraySpinnerAdapter.clear(); - List<Tray> outputTrays = printer.getOutputTrays(); - final int outputTrayCount = outputTrays.size(); - for (int i = 0; i < outputTrayCount; i++) { - Tray outputTray = outputTrays.get(i); - mOutputTraySpinnerAdapter.add(new SpinnerItem<Tray>( - outputTray, outputTray.getLabel(getPackageManager()))); - } - final int selectedOutputTrayIndex = outputTrays.indexOf( - mPrintAttributes.getOutputTray()); - mOutputTraySpinner.setSelection(selectedOutputTrayIndex); - - // Duplex mode. - final int duplexModes = printer.getDuplexModes(); - mDuplexModeSpinnerAdapter.clear(); - String[] duplexModeLabels = getResources().getStringArray( - R.array.duplex_mode_labels); - int remainingDuplexModes = duplexModes; - while (remainingDuplexModes != 0) { - final int duplexBitOffset = Integer.numberOfTrailingZeros(remainingDuplexModes); - final int duplexMode = 1 << duplexBitOffset; - remainingDuplexModes &= ~duplexMode; - mDuplexModeSpinnerAdapter.add(new SpinnerItem<Integer>(duplexMode, - duplexModeLabels[duplexBitOffset])); - } - final int selectedDuplexModeIndex = Integer.numberOfTrailingZeros( - (duplexModes & mPrintAttributes.getDuplexMode())); - mDuplexModeSpinner.setSelection(selectedDuplexModeIndex); // Color mode. final int colorModes = printer.getColorModes(); @@ -444,23 +451,6 @@ public class PrintJobConfigActivity extends Activity { (colorModes & mPrintAttributes.getColorMode())); mColorModeSpinner.setSelection(selectedColorModeIndex); - // Fitting mode. - final int fittingModes = printer.getFittingModes(); - mFittingModeSpinnerAdapter.clear(); - String[] fittingModeLabels = getResources().getStringArray( - R.array.fitting_mode_labels); - int remainingFittingModes = fittingModes; - while (remainingFittingModes != 0) { - final int fittingBitOffset = Integer.numberOfTrailingZeros(remainingFittingModes); - final int fittingMode = 1 << fittingBitOffset; - remainingFittingModes &= ~fittingMode; - mFittingModeSpinnerAdapter.add(new SpinnerItem<Integer>(fittingMode, - fittingModeLabels[fittingBitOffset])); - } - final int selectedFittingModeIndex = Integer.numberOfTrailingZeros( - (fittingModes & mPrintAttributes.getFittingMode())); - mFittingModeSpinner.setSelection(selectedFittingModeIndex); - // Orientation. final int orientations = printer.getOrientations(); mOrientationSpinnerAdapter.clear(); @@ -482,155 +472,96 @@ public class PrintJobConfigActivity extends Activity { @Override protected void onResume() { super.onResume(); - try { - mPrintManager.startDiscoverPrinters(mPrinterDiscoveryObserver); - } catch (RemoteException re) { - Log.e(LOG_TAG, "Error starting printer discovery!", re); - } + mPrintSpooler.startPrinterDiscovery(mPrinterDiscoveryObserver); notifyPrintableStartIfNeeded(); } @Override protected void onPause() { super.onPause(); - try { - mPrintManager.stopDiscoverPrinters(); - } catch (RemoteException re) { - Log.e(LOG_TAG, "Error starting printer discovery!", re); - } + mPrintSpooler.stopPrinterDiscovery(); notifyPrintableFinishIfNeeded(); } - @Override - public boolean onCreateOptionsMenu(Menu menu) { - getMenuInflater().inflate(R.menu.print_job_config_activity, menu); - return true; - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - if (item.getItemId() == R.id.print_button) { - mPrintConfirmed = true; - finish(); - } - return super.onOptionsItemSelected(item); - } - private void notifyPrintableStartIfNeeded() { if (mDestinationSpinner.getSelectedItemPosition() < 0 - || mPrintStarted) { + || mStarted) { return; } - mPrintStarted = true; - new QueuedAsyncTask<Void>(mTaskQueue) { - @Override - protected Void doInBackground(Void... params) { - try { - mRemotePrintAdapter.start(); - } catch (IOException ioe) { - Log.e(LOG_TAG, "Error reading printed data!", ioe); - } - return null; - } - - @Override - protected void onPostExecute(Void result) { - super.onPostExecute(result); - updatePrintableContentIfNeeded(); - } - }.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, (Void[]) null); + mStarted = true; + mRemotePrintAdapter.start(); + updatePrintableContentIfNeeded(); } private void updatePrintableContentIfNeeded() { - if (!mPrintStarted) { + if (!mStarted) { return; } + // TODO: Implement old attributes tracking mPrintSpooler.setPrintJobAttributes(mPrintJobId, mPrintAttributes); - // TODO: Implement page selector. - final List<PageRange> pages = new ArrayList<PageRange>(); - pages.add(PageRange.ALL_PAGES); - - new QueuedAsyncTask<File>(mTaskQueue) { + // TODO: Implement setting the print preview attribute + mRemotePrintAdapter.layout(new PrintAttributes.Builder().create(), + mPrintAttributes, new LayoutResultCallback() { @Override - protected File doInBackground(Void... params) { - try { - mRemotePrintAdapter.printAttributesChanged(mPrintAttributes); - mRemotePrintAdapter.cancelPrint(); - mRemotePrintAdapter.print(pages); - return mRemotePrintAdapter.getFile(); - } catch (IOException ioe) { - Log.e(LOG_TAG, "Error reading printed data!", ioe); - } - return null; + public void onLayoutFinished(PrintDocumentInfo info, boolean changed) { + mPrintDocumentInfo = info; + + // TODO: Handle the case of unchanged content + mPrintSpooler.setPrintJobPrintDocumentInfo(mPrintJobId, info); + + // TODO: Implement page selector. + final List<PageRange> pages = new ArrayList<PageRange>(); + pages.add(PageRange.ALL_PAGES); + + mRemotePrintAdapter.write(pages, new WriteResultCallback() { + @Override + public void onWriteFinished(List<PageRange> pages) { + updatePrintPreview(mRemotePrintAdapter.getFile()); + } + + @Override + public void onWriteFailed(CharSequence error) { + Log.e(LOG_TAG, "Error write layout: " + error); + finishActivity(Activity.RESULT_CANCELED); + } + }); } @Override - protected void onPostExecute(File file) { - super.onPostExecute(file); - updatePrintPreview(file); + public void onLayoutFailed(CharSequence error) { + Log.e(LOG_TAG, "Error during layout: " + error); + finishActivity(Activity.RESULT_CANCELED); } - }.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, (Void[]) null); + }, new Bundle()); } private void notifyPrintableFinishIfNeeded() { - if (!mPrintStarted) { + if (!mStarted) { return; } - mPrintStarted = false; - - // Cancel all pending async tasks if the activity was canceled. - if (!mPrintConfirmed) { - final int taskCount = mTaskQueue.size(); - for (int i = taskCount - 1; i >= 0; i--) { - mTaskQueue.remove(i).cancel(); - } - } - - new AsyncTask<Void, Void, Void>() { - @Override - protected Void doInBackground(Void... params) { - // Notify the app that printing completed. - try { - mRemotePrintAdapter.finish(); - } catch (IOException ioe) { - Log.e(LOG_TAG, "Error reading printed data!", ioe); - } - // If canceled, nothing to do. - if (!mPrintConfirmed) { - mPrintSpooler.setPrintJobState(mPrintJobId, - PrintJobInfo.STATE_CANCELED); - return null; - } - - // No printer, nothing to do. - final int selectedIndex = mDestinationSpinner.getSelectedItemPosition(); - if (selectedIndex < 0) { - // Update the print job's status. - mPrintSpooler.setPrintJobState(mPrintJobId, - PrintJobInfo.STATE_CANCELED); - return null; - } + mRemotePrintAdapter.finish(!mPrintConfirmed); - // Update the print job's printer. - SpinnerItem<PrinterInfo> printerItem = - mDestinationSpinnerAdapter.getItem(selectedIndex); - PrinterId printerId = printerItem.value.getId(); - mPrintSpooler.setPrintJobPrinterId(mPrintJobId, printerId); + // If canceled or no printer, nothing to do. + final int selectedIndex = mDestinationSpinner.getSelectedItemPosition(); + if (!mPrintConfirmed || selectedIndex < 0) { + // Update the print job's status. + mPrintSpooler.setPrintJobState(mPrintJobId, + PrintJobInfo.STATE_CANCELED); + return; + } - // Update the print job's status. - mPrintSpooler.setPrintJobState(mPrintJobId, - PrintJobInfo.STATE_QUEUED); - return null; - } + // Update the print job's printer. + SpinnerItem<PrinterInfo> printerItem = + mDestinationSpinnerAdapter.getItem(selectedIndex); + PrinterId printerId = printerItem.value.getId(); + mPrintSpooler.setPrintJobPrinterId(mPrintJobId, printerId); - // Important: If we are canceling, then we do not wait for the write - // to complete since the result will be discarded anyway, we simply - // execute the finish immediately which will interrupt the write. - }.executeOnExecutor(mPrintConfirmed ? AsyncTask.SERIAL_EXECUTOR - : AsyncTask.THREAD_POOL_EXECUTOR, (Void[]) null); + // Update the print job's status. + mPrintSpooler.setPrintJobState(mPrintJobId, + PrintJobInfo.STATE_QUEUED); if (DEBUG) { if (mPrintConfirmed) { @@ -689,30 +620,7 @@ public class PrintJobConfigActivity extends Activity { } } - private abstract class QueuedAsyncTask<T> extends AsyncTask<Void, Void, T> { - - private final List<QueuedAsyncTask<?>> mPendingOrRunningTasks; - - public QueuedAsyncTask(List<QueuedAsyncTask<?>> pendingOrRunningTasks) { - mPendingOrRunningTasks = pendingOrRunningTasks; - } - - @Override - protected void onPreExecute() { - mPendingOrRunningTasks.add(this); - } - - @Override - protected void onPostExecute(T result) { - mPendingOrRunningTasks.remove(this); - } - - public void cancel() { - super.cancel(true); - mPendingOrRunningTasks.remove(this); - } - } - + // Caution: Use this only for debugging private final class ViewSpooledFileAsyncTask extends AsyncTask<Void, Void, Void> { private final File mFile; @@ -791,4 +699,38 @@ public class PrintJobConfigActivity extends Activity { return label.toString(); } } + + /** + * An instance of this class class is intended to be the first focusable + * in a layout to which the system automatically gives focus. It performs + * some voodoo to avoid the first tap on it to start an edit mode, rather + * to bring up the IME, i.e. to get the behavior as if the view was not + * focused. + */ + public static final class CustomEditText extends EditText { + private boolean mClickedBeforeFocus; + + public CustomEditText(Context context, AttributeSet attrs) { + super(context, attrs); + } + + @Override + public boolean performClick() { + super.performClick(); + if (isFocused() && !mClickedBeforeFocus) { + clearFocus(); + requestFocus(); + } + mClickedBeforeFocus = true; + return true; + } + + protected void onFocusChanged(boolean gainFocus, int direction, + Rect previouslyFocusedRect) { + if (!gainFocus) { + mClickedBeforeFocus = false; + } + super.onFocusChanged(gainFocus, direction, previouslyFocusedRect); + } + } } diff --git a/packages/PrintSpooler/src/com/android/printspooler/PrintSpooler.java b/packages/PrintSpooler/src/com/android/printspooler/PrintSpooler.java index 2b27b69..53ae145 100644 --- a/packages/PrintSpooler/src/com/android/printspooler/PrintSpooler.java +++ b/packages/PrintSpooler/src/com/android/printspooler/PrintSpooler.java @@ -16,28 +16,21 @@ package com.android.printspooler; -import java.io.Closeable; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; - -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; -import org.xmlpull.v1.XmlSerializer; - import android.content.ComponentName; import android.content.Context; import android.os.AsyncTask; import android.os.ParcelFileDescriptor; import android.os.RemoteException; -import android.os.ServiceManager; import android.print.IPrintClient; -import android.print.IPrintManager; +import android.print.IPrintSpoolerClient; +import android.print.IPrinterDiscoveryObserver; +import android.print.PageRange; import android.print.PrintAttributes; +import android.print.PrintAttributes.Margins; +import android.print.PrintAttributes.MediaSize; +import android.print.PrintAttributes.Resolution; +import android.print.PrintAttributes.Tray; +import android.print.PrintDocumentInfo; import android.print.PrintJobInfo; import android.print.PrintManager; import android.print.PrinterId; @@ -48,15 +41,31 @@ import android.util.Xml; import com.android.internal.util.FastXmlSerializer; +import libcore.io.IoUtils; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; +import org.xmlpull.v1.XmlSerializer; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + public class PrintSpooler { private static final String LOG_TAG = PrintSpooler.class.getSimpleName(); private static final boolean DEBUG_PRINT_JOB_LIFECYCLE = false; - private static final boolean DEBUG_PERSISTENCE = false; + private static final boolean DEBUG_PERSISTENCE = true; - private static final boolean PERSISTNECE_MANAGER_ENABLED = false; + private static final boolean PERSISTNECE_MANAGER_ENABLED = true; private static final String PRINT_FILE_EXTENSION = "pdf"; @@ -64,17 +73,17 @@ public class PrintSpooler { private static final Object sLock = new Object(); - private final Object mLock = new Object(); - private static PrintSpooler sInstance; + private final Object mLock = new Object(); + private final List<PrintJobInfo> mPrintJobs = new ArrayList<PrintJobInfo>(); private final PersistenceManager mPersistanceManager; private final Context mContext; - private final IPrintManager mPrintManager; + public IPrintSpoolerClient mClient; public static PrintSpooler getInstance(Context context) { synchronized (sLock) { @@ -87,13 +96,50 @@ public class PrintSpooler { private PrintSpooler(Context context) { mContext = context; - mPersistanceManager = new PersistenceManager(); - mPersistanceManager.readStateLocked(); - mPrintManager = IPrintManager.Stub.asInterface( - ServiceManager.getService("print")); + mPersistanceManager = new PersistenceManager(context); + } + + public void setCleint(IPrintSpoolerClient client) { + synchronized (mLock) { + mClient = client; + } } - public List<PrintJobInfo> getPrintJobs(ComponentName componentName, int state, int appId) { + public void restorePersistedState() { + synchronized (mLock) { + mPersistanceManager.readStateLocked(); + } + } + + public void startPrinterDiscovery(IPrinterDiscoveryObserver observer) { + IPrintSpoolerClient client = null; + synchronized (mLock) { + client = mClient; + } + if (client != null) { + try { + client.onStartPrinterDiscovery(observer); + } catch (RemoteException re) { + Log.e(LOG_TAG, "Error notifying start printer discovery.", re); + } + } + } + + public void stopPrinterDiscovery() { + IPrintSpoolerClient client = null; + synchronized (mLock) { + client = mClient; + } + if (client != null) { + try { + client.onStopPrinterDiscovery(); + } catch (RemoteException re) { + Log.e(LOG_TAG, "Error notifying stop printer discovery.", re); + } + } + } + + public List<PrintJobInfo> getPrintJobInfos(ComponentName componentName, int state, int appId) { synchronized (mLock) { List<PrintJobInfo> foundPrintJobs = null; final int printJobCount = mPrintJobs.size(); @@ -102,11 +148,13 @@ public class PrintSpooler { PrinterId printerId = printJob.getPrinterId(); final boolean sameComponent = (componentName == null || (printerId != null - && componentName.equals(printerId.getServiceComponentName()))); + && componentName.equals(printerId.getService()))); final boolean sameAppId = appId == PrintManager.APP_ID_ANY || printJob.getAppId() == appId; - final boolean sameState = state == PrintJobInfo.STATE_ANY - || state == printJob.getState(); + final boolean sameState = (state == printJob.getState()) + || (state == PrintJobInfo.STATE_ANY) + || (state == PrintJobInfo.STATE_ANY_VISIBLE_TO_CLIENTS + && printJob.getState() > PrintJobInfo.STATE_CREATED); if (sameComponent && sameAppId && sameState) { if (foundPrintJobs == null) { foundPrintJobs = new ArrayList<PrintJobInfo>(); @@ -118,7 +166,7 @@ public class PrintSpooler { } } - public PrintJobInfo getPrintJob(int printJobId, int appId) { + public PrintJobInfo getPrintJobInfo(int printJobId, int appId) { synchronized (mLock) { final int printJobCount = mPrintJobs.size(); for (int i = 0; i < printJobCount; i++) { @@ -134,18 +182,13 @@ public class PrintSpooler { public boolean cancelPrintJob(int printJobId, int appId) { synchronized (mLock) { - PrintJobInfo printJob = getPrintJob(printJobId, appId); + PrintJobInfo printJob = getPrintJobInfo(printJobId, appId); if (printJob != null) { switch (printJob.getState()) { - case PrintJobInfo.STATE_CREATED: { - removePrintJobLocked(printJob); - } return true; + case PrintJobInfo.STATE_CREATED: case PrintJobInfo.STATE_QUEUED: { - removePrintJobLocked(printJob); + setPrintJobState(printJobId, PrintJobInfo.STATE_CANCELED); } return true; - default: { - return false; - } } } return false; @@ -161,14 +204,80 @@ public class PrintSpooler { printJob.setAppId(appId); printJob.setLabel(label); printJob.setAttributes(attributes); + printJob.setState(PrintJobInfo.STATE_CREATED); addPrintJobLocked(printJob); - setPrintJobState(printJobId, PrintJobInfo.STATE_CREATED); return printJob; } } + public void notifyClientForActivteJobs() { + IPrintSpoolerClient client = null; + Map<ComponentName, List<PrintJobInfo>> activeJobsPerServiceMap = + new HashMap<ComponentName, List<PrintJobInfo>>(); + + synchronized(mLock) { + if (mClient == null) { + throw new IllegalStateException("Client cannot be null."); + } + client = mClient; + + final int printJobCount = mPrintJobs.size(); + for (int i = 0; i < printJobCount; i++) { + PrintJobInfo printJob = mPrintJobs.get(i); + switch (printJob.getState()) { + case PrintJobInfo.STATE_CREATED: { + /* skip - not ready to be handled by a service */ + } break; + + case PrintJobInfo.STATE_QUEUED: + case PrintJobInfo.STATE_STARTED: { + ComponentName service = printJob.getPrinterId().getService(); + List<PrintJobInfo> jobsPerService = activeJobsPerServiceMap.get(service); + if (jobsPerService == null) { + jobsPerService = new ArrayList<PrintJobInfo>(); + activeJobsPerServiceMap.put(service, jobsPerService); + } + jobsPerService.add(printJob); + } break; + + default: { + ComponentName service = printJob.getPrinterId().getService(); + if (!activeJobsPerServiceMap.containsKey(service)) { + activeJobsPerServiceMap.put(service, null); + } + } + } + } + } + + boolean allPrintJobsHandled = true; + + for (Map.Entry<ComponentName, List<PrintJobInfo>> entry + : activeJobsPerServiceMap.entrySet()) { + ComponentName service = entry.getKey(); + List<PrintJobInfo> printJobs = entry.getValue(); + + if (printJobs != null) { + allPrintJobsHandled = false; + final int printJobCount = printJobs.size(); + for (int i = 0; i < printJobCount; i++) { + PrintJobInfo printJob = printJobs.get(i); + if (printJob.getState() == PrintJobInfo.STATE_QUEUED) { + callOnPrintJobQueuedQuietly(client, printJob); + } + } + } else { + callOnAllPrintJobsForServiceHandledQuietly(client, service); + } + } + + if (allPrintJobsHandled) { + callOnAllPrintJobsHandledQuietly(client); + } + } + private int generatePrintJobIdLocked() { int printJobId = sPrintJobIdCounter++; while (isDuplicatePrintJobId(printJobId)) { @@ -194,7 +303,7 @@ public class PrintSpooler { FileInputStream in = null; FileOutputStream out = null; try { - PrintJobInfo printJob = getPrintJob(printJobId, PrintManager.APP_ID_ANY); + PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY); if (printJob != null) { File file = generateFileForPrintJob(printJobId); in = new FileInputStream(file); @@ -213,24 +322,14 @@ public class PrintSpooler { } catch (IOException ioe) { Log.e(LOG_TAG, "Error writing print job data!", ioe); } finally { - closeIfNotNullNoException(in); - closeIfNotNullNoException(out); - closeIfNotNullNoException(fd); + IoUtils.closeQuietly(in); + IoUtils.closeQuietly(out); + IoUtils.closeQuietly(fd); } } return false; } - private void closeIfNotNullNoException(Closeable closeable) { - if (closeable != null) { - try { - closeable.close(); - } catch (IOException ioe) { - /* ignore */; - } - } - } - public File generateFileForPrintJob(int printJobId) { return new File(mContext.getFilesDir(), "print_job_" + printJobId + "." + PRINT_FILE_EXTENSION); @@ -254,10 +353,21 @@ public class PrintSpooler { public boolean setPrintJobState(int printJobId, int state) { boolean success = false; + + boolean allPrintJobsHandled = false; + boolean allPrintJobsForServiceHandled = false; + + IPrintSpoolerClient client = null; PrintJobInfo queuedPrintJob = null; + PrintJobInfo removedPrintJob = null; synchronized (mLock) { - PrintJobInfo printJob = getPrintJob(printJobId, PrintManager.APP_ID_ANY); + if (mClient == null) { + throw new IllegalStateException("Client cannot be null."); + } + client = mClient; + + PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY); if (printJob != null && printJob.getState() < state) { success = true; printJob.setState(state); @@ -265,8 +375,23 @@ public class PrintSpooler { switch (state) { case PrintJobInfo.STATE_COMPLETED: case PrintJobInfo.STATE_CANCELED: { + removedPrintJob = printJob; removePrintJobLocked(printJob); + + // No printer means creation of a print job was cancelled, + // therefore the state of the spooler did not change and no + // notifications are needed. We also do not need to persist + // the state. + PrinterId printerId = printJob.getPrinterId(); + if (printerId == null) { + return true; + } + + allPrintJobsHandled = !hasActivePrintJobsLocked(); + allPrintJobsForServiceHandled = !hasActivePrintJobsForServiceLocked( + printerId.getService()); } break; + case PrintJobInfo.STATE_QUEUED: { queuedPrintJob = new PrintJobInfo(printJob); } break; @@ -279,20 +404,90 @@ public class PrintSpooler { } if (queuedPrintJob != null) { - try { - mPrintManager.onPrintJobQueued(queuedPrintJob.getPrinterId(), - queuedPrintJob); - } catch (RemoteException re) { - /* ignore */ - } + callOnPrintJobQueuedQuietly(client, queuedPrintJob); + } + + if (allPrintJobsForServiceHandled) { + callOnAllPrintJobsForServiceHandledQuietly(client, + removedPrintJob.getPrinterId().getService()); + } + + if (allPrintJobsHandled) { + callOnAllPrintJobsHandledQuietly(client); } return success; } + private void callOnPrintJobQueuedQuietly(IPrintSpoolerClient client, + PrintJobInfo printJob) { + try { + client.onPrintJobQueued(printJob); + } catch (RemoteException re) { + Slog.e(LOG_TAG, "Error notify for a queued print job.", re); + } + } + + private void callOnAllPrintJobsForServiceHandledQuietly(IPrintSpoolerClient client, + ComponentName service) { + try { + client.onAllPrintJobsForServiceHandled(service); + } catch (RemoteException re) { + Slog.e(LOG_TAG, "Error notify for all print jobs per service handled.", re); + } + } + + private void callOnAllPrintJobsHandledQuietly(final IPrintSpoolerClient client) { + // This has to run on the tread that is persisting the current state + // since this call may result in the system unbinding from the spooler + // and as a result the spooler process may get killed before the write + // completes. + new AsyncTask<Void, Void, Void>() { + @Override + protected Void doInBackground(Void... params) { + try { + client.onAllPrintJobsHandled(); + } catch (RemoteException re) { + Slog.e(LOG_TAG, "Error notify for all print job handled.", re); + } + return null; + } + }.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, (Void[]) null); + } + + private boolean hasActivePrintJobsLocked() { + final int printJobCount = mPrintJobs.size(); + for (int i = 0; i < printJobCount; i++) { + PrintJobInfo printJob = mPrintJobs.get(i); + switch (printJob.getState()) { + case PrintJobInfo.STATE_QUEUED: + case PrintJobInfo.STATE_STARTED: { + return true; + } + } + } + return false; + } + + private boolean hasActivePrintJobsForServiceLocked(ComponentName service) { + final int printJobCount = mPrintJobs.size(); + for (int i = 0; i < printJobCount; i++) { + PrintJobInfo printJob = mPrintJobs.get(i); + switch (printJob.getState()) { + case PrintJobInfo.STATE_QUEUED: + case PrintJobInfo.STATE_STARTED: { + if (printJob.getPrinterId().getService().equals(service)) { + return true; + } + } break; + } + } + return false; + } + public boolean setPrintJobTag(int printJobId, String tag) { synchronized (mLock) { - PrintJobInfo printJob = getPrintJob(printJobId, PrintManager.APP_ID_ANY); + PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY); if (printJob != null) { printJob.setTag(tag); mPersistanceManager.writeStateLocked(); @@ -302,9 +497,21 @@ public class PrintSpooler { return false; } + public final boolean setPrintJobPrintDocumentInfo(int printJobId, PrintDocumentInfo info) { + synchronized (mLock) { + PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY); + if (printJob != null) { + printJob.setDocumentInfo(info); + mPersistanceManager.writeStateLocked(); + return true; + } + } + return false; + } + public void setPrintJobAttributes(int printJobId, PrintAttributes attributes) { synchronized (mLock) { - PrintJobInfo printJob = getPrintJob(printJobId, PrintManager.APP_ID_ANY); + PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY); if (printJob != null) { printJob.setAttributes(attributes); mPersistanceManager.writeStateLocked(); @@ -314,7 +521,7 @@ public class PrintSpooler { public void setPrintJobPrinterId(int printJobId, PrinterId printerId) { synchronized (mLock) { - PrintJobInfo printJob = getPrintJob(printJobId, PrintManager.APP_ID_ANY); + PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY); if (printJob != null) { printJob.setPrinterId(printerId); mPersistanceManager.writeStateLocked(); @@ -322,40 +529,77 @@ public class PrintSpooler { } } + public boolean setPrintJobPages(int printJobId, PageRange[] pages) { + synchronized (mLock) { + PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY); + if (printJob != null) { + printJob.setPages(pages); + mPersistanceManager.writeStateLocked(); + return true; + } + } + return false; + } + private final class PersistenceManager { private static final String PERSIST_FILE_NAME = "print_spooler_state.xml"; private static final String TAG_SPOOLER = "spooler"; private static final String TAG_JOB = "job"; - private static final String TAG_ID = "id"; - private static final String TAG_TAG = "tag"; - private static final String TAG_APP_ID = "app-id"; - private static final String TAG_STATE = "state"; + + private static final String TAG_PRINTER_ID = "printerId"; + private static final String TAG_PAGE_RANGE = "pageRange"; private static final String TAG_ATTRIBUTES = "attributes"; - private static final String TAG_LABEL = "label"; - private static final String TAG_PRINTER = "printer"; - - private static final String ATTRIBUTE_MEDIA_SIZE = "mediaSize"; - private static final String ATTRIBUTE_RESOLUTION = "resolution"; - private static final String ATTRIBUTE_MARGINS = "margins"; - private static final String ATTRIBUTE_INPUT_TRAY = "inputTray"; - private static final String ATTRIBUTE_OUTPUT_TRAY = "outputTray"; - private static final String ATTRIBUTE_DUPLEX_MODE = "duplexMode"; - private static final String ATTRIBUTE_COLOR_MODE = "colorMode"; - private static final String ATTRIBUTE_FITTING_MODE = "fittingMode"; - private static final String ATTRIBUTE_ORIENTATION = "orientation"; + private static final String TAG_DOCUMENT_INFO = "documentInfo"; + + private static final String ATTR_ID = "id"; + private static final String ATTR_LABEL = "label"; + private static final String ATTR_STATE = "state"; + private static final String ATTR_APP_ID = "appId"; + private static final String ATTR_USER_ID = "userId"; + private static final String ATTR_TAG = "tag"; + + private static final String TAG_MEDIA_SIZE = "mediaSize"; + private static final String TAG_RESOLUTION = "resolution"; + private static final String TAG_MARGINS = "margins"; + private static final String TAG_INPUT_TRAY = "inputTray"; + private static final String TAG_OUTPUT_TRAY = "outputTray"; + + private static final String ATTR_DUPLEX_MODE = "duplexMode"; + private static final String ATTR_COLOR_MODE = "colorMode"; + private static final String ATTR_FITTING_MODE = "fittingMode"; + private static final String ATTR_ORIENTATION = "orientation"; + + private static final String ATTR_LOCAL_ID = "localId"; + private static final String ATTR_SERVICE = "service"; + + private static final String ATTR_WIDTH_MILS = "widthMils"; + private static final String ATTR_HEIGHT_MILS = "heightMils"; + + private static final String ATTR_HORIZONTAL_DPI = "horizontalDip"; + private static final String ATTR_VERTICAL_DPI = "verticalDpi"; + + private static final String ATTR_LEFT_MILS = "leftMils"; + private static final String ATTR_TOP_MILS = "topMils"; + private static final String ATTR_RIGHT_MILS = "rightMils"; + private static final String ATTR_BOTTOM_MILS = "bottomMils"; + + private static final String ATTR_START = "start"; + private static final String ATTR_END = "end"; + + private static final String ATTR_PAGE_COUNT = "pageCount"; + private static final String ATTR_CONTENT_TYPE = "contentType"; private final AtomicFile mStatePersistFile; private boolean mWriteStateScheduled; - private PersistenceManager() { - mStatePersistFile = new AtomicFile(new File(mContext.getFilesDir(), + private PersistenceManager(Context context) { + mStatePersistFile = new AtomicFile(new File(context.getFilesDir(), PERSIST_FILE_NAME)); } public void writeStateLocked() { - // TODO: Implement persistence of PrintableInfo if (!PERSISTNECE_MANAGER_ENABLED) { return; } @@ -393,99 +637,134 @@ public class PrintSpooler { final int state = printJob.getState(); if (state < PrintJobInfo.STATE_QUEUED - || state > PrintJobInfo.STATE_FAILED) { + || state > PrintJobInfo.STATE_CANCELED) { continue; } serializer.startTag(null, TAG_JOB); - serializer.startTag(null, TAG_ID); - serializer.text(String.valueOf(printJob.getId())); - serializer.endTag(null, TAG_ID); - - serializer.startTag(null, TAG_TAG); - serializer.text(printJob.getTag()); - serializer.endTag(null, TAG_TAG); - - serializer.startTag(null, TAG_APP_ID); - serializer.text(String.valueOf(printJob.getAppId())); - serializer.endTag(null, TAG_APP_ID); - - serializer.startTag(null, TAG_LABEL); - serializer.text(printJob.getLabel().toString()); - serializer.endTag(null, TAG_LABEL); + serializer.attribute(null, ATTR_ID, String.valueOf(printJob.getId())); + serializer.attribute(null, ATTR_LABEL, printJob.getLabel().toString()); + serializer.attribute(null, ATTR_STATE, String.valueOf(printJob.getState())); + serializer.attribute(null, ATTR_APP_ID, String.valueOf(printJob.getAppId())); + serializer.attribute(null, ATTR_USER_ID, String.valueOf(printJob.getUserId())); + String tag = printJob.getTag(); + if (tag != null) { + serializer.attribute(null, ATTR_TAG, tag); + } - serializer.startTag(null, TAG_STATE); - serializer.text(String.valueOf(printJob.getState())); - serializer.endTag(null, TAG_STATE); + PrinterId printerId = printJob.getPrinterId(); + if (printerId != null) { + serializer.startTag(null, TAG_PRINTER_ID); + serializer.attribute(null, ATTR_LOCAL_ID, printerId.getLocalId()); + serializer.attribute(null, ATTR_SERVICE, printerId.getService() + .flattenToString()); + serializer.endTag(null, TAG_PRINTER_ID); + } - serializer.startTag(null, TAG_PRINTER); - serializer.text(printJob.getPrinterId().flattenToString()); - serializer.endTag(null, TAG_PRINTER); + PageRange[] pages = printJob.getPages(); + if (pages != null) { + for (int i = 0; i < pages.length; i++) { + serializer.startTag(null, TAG_PAGE_RANGE); + serializer.attribute(null, ATTR_START, String.valueOf( + pages[i].getStart())); + serializer.attribute(null, ATTR_END, String.valueOf( + pages[i].getEnd())); + serializer.endTag(null, TAG_PAGE_RANGE); + } + } PrintAttributes attributes = printJob.getAttributes(); if (attributes != null) { serializer.startTag(null, TAG_ATTRIBUTES); - //TODO: Implement persistence of the attributes below. - -// MediaSize mediaSize = attributes.getMediaSize(); -// if (mediaSize != null) { -// serializer.attribute(null, ATTRIBUTE_MEDIA_SIZE, -// mediaSize.flattenToString()); -// } -// -// Resolution resolution = attributes.getResolution(); -// if (resolution != null) { -// serializer.attribute(null, ATTRIBUTE_RESOLUTION, -// resolution.flattenToString()); -// } -// -// Margins margins = attributes.getMargins(); -// if (margins != null) { -// serializer.attribute(null, ATTRIBUTE_MARGINS, -// margins.flattenToString()); -// } -// -// Tray inputTray = attributes.getInputTray(); -// if (inputTray != null) { -// serializer.attribute(null, ATTRIBUTE_INPUT_TRAY, -// inputTray.flattenToString()); -// } -// -// Tray outputTray = attributes.getOutputTray(); -// if (outputTray != null) { -// serializer.attribute(null, ATTRIBUTE_OUTPUT_TRAY, -// outputTray.flattenToString()); -// } - final int duplexMode = attributes.getDuplexMode(); - if (duplexMode > 0) { - serializer.attribute(null, ATTRIBUTE_DUPLEX_MODE, - String.valueOf(duplexMode)); - } + serializer.attribute(null, ATTR_DUPLEX_MODE, + String.valueOf(duplexMode)); final int colorMode = attributes.getColorMode(); - if (colorMode > 0) { - serializer.attribute(null, ATTRIBUTE_COLOR_MODE, - String.valueOf(colorMode)); - } + serializer.attribute(null, ATTR_COLOR_MODE, + String.valueOf(colorMode)); final int fittingMode = attributes.getFittingMode(); - if (fittingMode > 0) { - serializer.attribute(null, ATTRIBUTE_FITTING_MODE, - String.valueOf(fittingMode)); - } + serializer.attribute(null, ATTR_FITTING_MODE, + String.valueOf(fittingMode)); final int orientation = attributes.getOrientation(); - if (orientation > 0) { - serializer.attribute(null, ATTRIBUTE_ORIENTATION, - String.valueOf(orientation)); + serializer.attribute(null, ATTR_ORIENTATION, + String.valueOf(orientation)); + + MediaSize mediaSize = attributes.getMediaSize(); + if (mediaSize != null) { + serializer.startTag(null, TAG_MEDIA_SIZE); + serializer.attribute(null, ATTR_ID, mediaSize.getId()); + serializer.attribute(null, ATTR_LABEL, mediaSize.getLabel() + .toString()); + serializer.attribute(null, ATTR_WIDTH_MILS, String.valueOf( + mediaSize.getWidthMils())); + serializer.attribute(null, ATTR_HEIGHT_MILS,String.valueOf( + mediaSize.getHeightMils())); + serializer.endTag(null, TAG_MEDIA_SIZE); + } + + Resolution resolution = attributes.getResolution(); + if (resolution != null) { + serializer.startTag(null, TAG_RESOLUTION); + serializer.attribute(null, ATTR_ID, resolution.getId()); + serializer.attribute(null, ATTR_LABEL, resolution.getLabel() + .toString()); + serializer.attribute(null, ATTR_HORIZONTAL_DPI, String.valueOf( + resolution.getHorizontalDpi())); + serializer.attribute(null, ATTR_VERTICAL_DPI, String.valueOf( + resolution.getVerticalDpi())); + serializer.endTag(null, TAG_RESOLUTION); + } + + Margins margins = attributes.getMargins(); + if (margins != null) { + serializer.startTag(null, TAG_MARGINS); + serializer.attribute(null, ATTR_LEFT_MILS, String.valueOf( + margins.getLeftMils())); + serializer.attribute(null, ATTR_TOP_MILS, String.valueOf( + margins.getTopMils())); + serializer.attribute(null, ATTR_RIGHT_MILS, String.valueOf( + margins.getRightMils())); + serializer.attribute(null, ATTR_BOTTOM_MILS, String.valueOf( + margins.getBottomMils())); + serializer.endTag(null, TAG_MARGINS); + } + + Tray inputTray = attributes.getInputTray(); + if (inputTray != null) { + serializer.startTag(null, TAG_INPUT_TRAY); + serializer.attribute(null, ATTR_ID, inputTray.getId()); + serializer.attribute(null, ATTR_LABEL, inputTray.getLabel() + .toString()); + serializer.endTag(null, TAG_INPUT_TRAY); + } + + Tray outputTray = attributes.getOutputTray(); + if (outputTray != null) { + serializer.startTag(null, TAG_OUTPUT_TRAY); + serializer.attribute(null, ATTR_ID, outputTray.getId()); + serializer.attribute(null, ATTR_LABEL, outputTray.getLabel() + .toString()); + serializer.endTag(null, TAG_OUTPUT_TRAY); } serializer.endTag(null, TAG_ATTRIBUTES); } + PrintDocumentInfo documentInfo = printJob.getDocumentInfo(); + if (documentInfo != null) { + serializer.startTag(null, TAG_DOCUMENT_INFO); + serializer.attribute(null, ATTR_CONTENT_TYPE, String.valueOf( + documentInfo.getContentType())); + serializer.attribute(null, ATTR_PAGE_COUNT, String.valueOf( + documentInfo.getPageCount())); + serializer.endTag(null, TAG_DOCUMENT_INFO); + } + serializer.endTag(null, TAG_JOB); if (DEBUG_PERSISTENCE) { @@ -567,125 +846,169 @@ public class PrintSpooler { if (!accept(parser, XmlPullParser.START_TAG, TAG_JOB)) { return false; } - parser.next(); - - skipEmptyTextTags(parser); - expect(parser, XmlPullParser.START_TAG, TAG_ID); - parser.next(); - final int printJobId = Integer.parseInt(parser.getText()); - parser.next(); - skipEmptyTextTags(parser); - expect(parser, XmlPullParser.END_TAG, TAG_ID); - parser.next(); - skipEmptyTextTags(parser); - expect(parser, XmlPullParser.START_TAG, TAG_TAG); - parser.next(); - String tag = parser.getText(); - parser.next(); - skipEmptyTextTags(parser); - expect(parser, XmlPullParser.END_TAG, TAG_TAG); - parser.next(); + PrintJobInfo printJob = new PrintJobInfo(); - skipEmptyTextTags(parser); - expect(parser, XmlPullParser.START_TAG, TAG_APP_ID); - parser.next(); - final int appId = Integer.parseInt(parser.getText()); - parser.next(); - skipEmptyTextTags(parser); - expect(parser, XmlPullParser.END_TAG, TAG_APP_ID); - parser.next(); + final int printJobId = Integer.parseInt(parser.getAttributeValue(null, ATTR_ID)); + printJob.setId(printJobId); + String label = parser.getAttributeValue(null, ATTR_LABEL); + printJob.setLabel(label); + final int state = Integer.parseInt(parser.getAttributeValue(null, ATTR_STATE)); + printJob.setState(state); + final int appId = Integer.parseInt(parser.getAttributeValue(null, ATTR_APP_ID)); + printJob.setAppId(appId); + final int userId = Integer.parseInt(parser.getAttributeValue(null, ATTR_USER_ID)); + printJob.setUserId(userId); + String tag = parser.getAttributeValue(null, ATTR_TAG); + printJob.setTag(tag); - skipEmptyTextTags(parser); - expect(parser, XmlPullParser.START_TAG, TAG_LABEL); - parser.next(); - String label = parser.getText(); - parser.next(); - skipEmptyTextTags(parser); - expect(parser, XmlPullParser.END_TAG, TAG_LABEL); parser.next(); skipEmptyTextTags(parser); - expect(parser, XmlPullParser.START_TAG, TAG_STATE); - parser.next(); - final int state = Integer.parseInt(parser.getText()); - parser.next(); - skipEmptyTextTags(parser); - expect(parser, XmlPullParser.END_TAG, TAG_STATE); - parser.next(); + if (accept(parser, XmlPullParser.START_TAG, TAG_PRINTER_ID)) { + String localId = parser.getAttributeValue(null, ATTR_LOCAL_ID); + ComponentName service = ComponentName.unflattenFromString(parser.getAttributeValue( + null, ATTR_SERVICE)); + printJob.setPrinterId(new PrinterId(service, localId)); + parser.next(); + skipEmptyTextTags(parser); + expect(parser, XmlPullParser.END_TAG, TAG_PRINTER_ID); + parser.next(); + } skipEmptyTextTags(parser); - expect(parser, XmlPullParser.START_TAG, TAG_PRINTER); - parser.next(); - PrinterId printerId = PrinterId.unflattenFromString(parser.getText()); - parser.next(); - skipEmptyTextTags(parser); - expect(parser, XmlPullParser.END_TAG, TAG_PRINTER); - parser.next(); + List<PageRange> pageRanges = null; + while (accept(parser, XmlPullParser.START_TAG, TAG_PAGE_RANGE)) { + final int start = Integer.parseInt(parser.getAttributeValue(null, ATTR_START)); + final int end = Integer.parseInt(parser.getAttributeValue(null, ATTR_END)); + PageRange pageRange = new PageRange(start, end); + if (pageRanges == null) { + pageRanges = new ArrayList<PageRange>(); + } + pageRanges.add(pageRange); + parser.next(); + skipEmptyTextTags(parser); + expect(parser, XmlPullParser.END_TAG, TAG_PAGE_RANGE); + parser.next(); + } + if (pageRanges != null) { + printJob.setPages((PageRange[]) pageRanges.toArray()); + } skipEmptyTextTags(parser); - expect(parser, XmlPullParser.START_TAG, TAG_ATTRIBUTES); + if (accept(parser, XmlPullParser.START_TAG, TAG_ATTRIBUTES)) { - final int attributeCount = parser.getAttributeCount(); - PrintAttributes attributes = null; - if (attributeCount > 0) { PrintAttributes.Builder builder = new PrintAttributes.Builder(); - // TODO: Implement reading of the attributes below. - -// String mediaSize = parser.getAttributeValue(null, ATTRIBUTE_MEDIA_SIZE); -// if (mediaSize != null) { -// builder.setMediaSize(MediaSize.unflattenFromString(mediaSize)); -// } -// -// String resolution = parser.getAttributeValue(null, ATTRIBUTE_RESOLUTION); -// if (resolution != null) { -// builder.setMediaSize(Resolution.unflattenFromString(resolution)); -// } -// -// String margins = parser.getAttributeValue(null, ATTRIBUTE_MARGINS); -// if (margins != null) { -// builder.setMediaSize(Margins.unflattenFromString(margins)); -// } -// -// String inputTray = parser.getAttributeValue(null, ATTRIBUTE_INPUT_TRAY); -// if (inputTray != null) { -// builder.setMediaSize(Tray.unflattenFromString(inputTray)); -// } -// -// String outputTray = parser.getAttributeValue(null, ATTRIBUTE_OUTPUT_TRAY); -// if (outputTray != null) { -// builder.setMediaSize(Tray.unflattenFromString(outputTray)); -// } -// -// String duplexMode = parser.getAttributeValue(null, ATTRIBUTE_DUPLEX_MODE); -// if (duplexMode != null) { -// builder.setDuplexMode(Integer.parseInt(duplexMode)); -// } - - String colorMode = parser.getAttributeValue(null, ATTRIBUTE_COLOR_MODE); - if (colorMode != null) { - builder.setColorMode(Integer.parseInt(colorMode)); + String duplexMode = parser.getAttributeValue(null, ATTR_DUPLEX_MODE); + builder.setDuplexMode(Integer.parseInt(duplexMode)); + + String colorMode = parser.getAttributeValue(null, ATTR_COLOR_MODE); + builder.setColorMode(Integer.parseInt(colorMode)); + + String fittingMode = parser.getAttributeValue(null, ATTR_FITTING_MODE); + builder.setFittingMode(Integer.parseInt(fittingMode)); + + String orientation = parser.getAttributeValue(null, ATTR_ORIENTATION); + builder.setOrientation(Integer.parseInt(orientation)); + + parser.next(); + + skipEmptyTextTags(parser); + if (accept(parser, XmlPullParser.START_TAG, TAG_MEDIA_SIZE)) { + String id = parser.getAttributeValue(null, ATTR_ID); + label = parser.getAttributeValue(null, ATTR_LABEL); + final int widthMils = Integer.parseInt(parser.getAttributeValue(null, + ATTR_WIDTH_MILS)); + final int heightMils = Integer.parseInt(parser.getAttributeValue(null, + ATTR_HEIGHT_MILS)); + MediaSize mediaSize = new MediaSize(id, label, widthMils, heightMils); + builder.setMediaSize(mediaSize); + parser.next(); + skipEmptyTextTags(parser); + expect(parser, XmlPullParser.END_TAG, TAG_MEDIA_SIZE); + parser.next(); + } + + skipEmptyTextTags(parser); + if (accept(parser, XmlPullParser.START_TAG, TAG_RESOLUTION)) { + String id = parser.getAttributeValue(null, ATTR_ID); + label = parser.getAttributeValue(null, ATTR_LABEL); + final int horizontalDpi = Integer.parseInt(parser.getAttributeValue(null, + ATTR_HORIZONTAL_DPI)); + final int verticalDpi = Integer.parseInt(parser.getAttributeValue(null, + ATTR_VERTICAL_DPI)); + Resolution resolution = new Resolution(id, label, horizontalDpi, verticalDpi); + builder.setResolution(resolution); + parser.next(); + skipEmptyTextTags(parser); + expect(parser, XmlPullParser.END_TAG, TAG_RESOLUTION); + parser.next(); + } + + skipEmptyTextTags(parser); + if (accept(parser, XmlPullParser.START_TAG, TAG_MARGINS)) { + final int leftMils = Integer.parseInt(parser.getAttributeValue(null, + ATTR_LEFT_MILS)); + final int topMils = Integer.parseInt(parser.getAttributeValue(null, + ATTR_TOP_MILS)); + final int rightMils = Integer.parseInt(parser.getAttributeValue(null, + ATTR_RIGHT_MILS)); + final int bottomMils = Integer.parseInt(parser.getAttributeValue(null, + ATTR_BOTTOM_MILS)); + Margins margins = new Margins(leftMils, topMils, rightMils, bottomMils); + builder.setMargins(margins); + parser.next(); + skipEmptyTextTags(parser); + expect(parser, XmlPullParser.END_TAG, TAG_MARGINS); + parser.next(); + } + + skipEmptyTextTags(parser); + if (accept(parser, XmlPullParser.START_TAG, TAG_INPUT_TRAY)) { + String id = parser.getAttributeValue(null, ATTR_ID); + label = parser.getAttributeValue(null, ATTR_LABEL); + Tray tray = new Tray(id, label); + builder.setInputTray(tray); + parser.next(); + skipEmptyTextTags(parser); + expect(parser, XmlPullParser.END_TAG, TAG_INPUT_TRAY); + parser.next(); } - String fittingMode = parser.getAttributeValue(null, ATTRIBUTE_COLOR_MODE); - if (fittingMode != null) { - builder.setFittingMode(Integer.parseInt(fittingMode)); + skipEmptyTextTags(parser); + if (accept(parser, XmlPullParser.START_TAG, TAG_OUTPUT_TRAY)) { + String id = parser.getAttributeValue(null, ATTR_ID); + label = parser.getAttributeValue(null, ATTR_LABEL); + Tray tray = new Tray(id, label); + builder.setOutputTray(tray); + parser.next(); + skipEmptyTextTags(parser); + expect(parser, XmlPullParser.END_TAG, TAG_OUTPUT_TRAY); + parser.next(); } + + printJob.setAttributes(builder.create()); + + skipEmptyTextTags(parser); + expect(parser, XmlPullParser.END_TAG, TAG_ATTRIBUTES); + parser.next(); } - parser.next(); - skipEmptyTextTags(parser); - expect(parser, XmlPullParser.END_TAG, TAG_ATTRIBUTES); - parser.next(); - PrintJobInfo printJob = new PrintJobInfo(); - printJob.setId(printJobId); - printJob.setTag(tag); - printJob.setAppId(appId); - printJob.setLabel(label); - printJob.setState(state); - printJob.setAttributes(attributes); - printJob.setPrinterId(printerId); + skipEmptyTextTags(parser); + if (accept(parser, XmlPullParser.START_TAG, TAG_DOCUMENT_INFO)) { + final int pageCount = Integer.parseInt(parser.getAttributeValue(null, + ATTR_PAGE_COUNT)); + final int contentType = Integer.parseInt(parser.getAttributeValue(null, + ATTR_CONTENT_TYPE)); + PrintDocumentInfo info = new PrintDocumentInfo.Builder().setPageCount(pageCount) + .setContentType(contentType).create(); + printJob.setDocumentInfo(info); + parser.next(); + skipEmptyTextTags(parser); + expect(parser, XmlPullParser.END_TAG, TAG_DOCUMENT_INFO); + parser.next(); + } mPrintJobs.add(printJob); diff --git a/packages/PrintSpooler/src/com/android/printspooler/PrintSpoolerService.java b/packages/PrintSpooler/src/com/android/printspooler/PrintSpoolerService.java index 57c4557..26d2a33 100644 --- a/packages/PrintSpooler/src/com/android/printspooler/PrintSpoolerService.java +++ b/packages/PrintSpooler/src/com/android/printspooler/PrintSpoolerService.java @@ -29,10 +29,11 @@ import android.os.Looper; import android.os.Message; import android.os.ParcelFileDescriptor; import android.os.RemoteException; -import android.print.IPrintAdapter; +import android.print.IPrintDocumentAdapter; import android.print.IPrintClient; -import android.print.IPrintSpoolerService; -import android.print.IPrintSpoolerServiceCallbacks; +import android.print.IPrintSpoolerClient; +import android.print.IPrintSpooler; +import android.print.IPrintSpoolerCallbacks; import android.print.PrintAttributes; import android.print.PrintJobInfo; import android.util.Slog; @@ -64,32 +65,34 @@ public final class PrintSpoolerService extends Service { @Override public IBinder onBind(Intent intent) { - return new IPrintSpoolerService.Stub() { + mSpooler.restorePersistedState(); + + return new IPrintSpooler.Stub() { @Override - public void getPrintJobs(IPrintSpoolerServiceCallbacks callback, + public void getPrintJobInfos(IPrintSpoolerCallbacks callback, ComponentName componentName, int state, int appId, int sequence) throws RemoteException { List<PrintJobInfo> printJobs = null; try { - printJobs = mSpooler.getPrintJobs(componentName, state, appId); + printJobs = mSpooler.getPrintJobInfos(componentName, state, appId); } finally { - callback.onGetPrintJobsResult(printJobs, sequence); + callback.onGetPrintJobInfosResult(printJobs, sequence); } } @Override - public void getPrintJob(int printJobId, IPrintSpoolerServiceCallbacks callback, + public void getPrintJobInfo(int printJobId, IPrintSpoolerCallbacks callback, int appId, int sequence) throws RemoteException { PrintJobInfo printJob = null; try { - printJob = mSpooler.getPrintJob(printJobId, appId); + printJob = mSpooler.getPrintJobInfo(printJobId, appId); } finally { callback.onGetPrintJobInfoResult(printJob, sequence); } } @Override - public void cancelPrintJob(int printJobId, IPrintSpoolerServiceCallbacks callback, + public void cancelPrintJob(int printJobId, IPrintSpoolerCallbacks callback, int appId, int sequence) throws RemoteException { boolean success = false; try { @@ -102,8 +105,8 @@ public final class PrintSpoolerService extends Service { @SuppressWarnings("deprecation") @Override public void createPrintJob(String printJobName, IPrintClient client, - IPrintAdapter printAdapter, PrintAttributes attributes, - IPrintSpoolerServiceCallbacks callback, int appId, int sequence) + IPrintDocumentAdapter printAdapter, PrintAttributes attributes, + IPrintSpoolerCallbacks callback, int appId, int sequence) throws RemoteException { PrintJobInfo printJob = null; try { @@ -134,7 +137,7 @@ public final class PrintSpoolerService extends Service { @Override public void setPrintJobState(int printJobId, int state, - IPrintSpoolerServiceCallbacks callback, int sequece) + IPrintSpoolerCallbacks callback, int sequece) throws RemoteException { boolean success = false; try { @@ -148,7 +151,7 @@ public final class PrintSpoolerService extends Service { @Override public void setPrintJobTag(int printJobId, String tag, - IPrintSpoolerServiceCallbacks callback, int sequece) + IPrintSpoolerCallbacks callback, int sequece) throws RemoteException { boolean success = false; try { @@ -162,6 +165,16 @@ public final class PrintSpoolerService extends Service { public void writePrintJobData(ParcelFileDescriptor fd, int printJobId) { mSpooler.writePrintJobData(fd, printJobId); } + + @Override + public void setClient(IPrintSpoolerClient client) { + mSpooler.setCleint(client); + } + + @Override + public void notifyClientForActivteJobs() { + mSpooler.notifyClientForActivteJobs(); + } }; } diff --git a/packages/PrintSpooler/src/com/android/printspooler/RemotePrintAdapter.java b/packages/PrintSpooler/src/com/android/printspooler/RemotePrintAdapter.java deleted file mode 100644 index c81b00c..0000000 --- a/packages/PrintSpooler/src/com/android/printspooler/RemotePrintAdapter.java +++ /dev/null @@ -1,219 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.printspooler; - -import android.os.ICancellationSignal; -import android.os.ParcelFileDescriptor; -import android.os.RemoteException; -import android.print.IPrintAdapter; -import android.print.IPrintResultCallback; -import android.print.PageRange; -import android.print.PrintAdapterInfo; -import android.print.PrintAttributes; -import android.util.Log; - -import libcore.io.IoUtils; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.List; - -/** - * This class represents a remote print adapter instance. - */ -final class RemotePrintAdapter { - private static final String LOG_TAG = "RemotePrintAdapter"; - - private static final boolean DEBUG = true; - - private final Object mLock = new Object(); - - private final IPrintAdapter mRemoteInterface; - - private final File mFile; - - private final IPrintResultCallback mIPrintProgressListener; - - private PrintAdapterInfo mInfo; - - private ICancellationSignal mCancellationSignal; - - private Thread mWriteThread; - - public RemotePrintAdapter(IPrintAdapter printAdatper, File file) { - mRemoteInterface = printAdatper; - mFile = file; - mIPrintProgressListener = new IPrintResultCallback.Stub() { - @Override - public void onPrintStarted(PrintAdapterInfo info, - ICancellationSignal cancellationSignal) { - if (DEBUG) { - Log.i(LOG_TAG, "IPrintProgressListener#onPrintStarted()"); - } - synchronized (mLock) { - mInfo = info; - mCancellationSignal = cancellationSignal; - } - } - - @Override - public void onPrintFinished(List<PageRange> pages) { - if (DEBUG) { - Log.i(LOG_TAG, "IPrintProgressListener#onPrintFinished(" + pages + ")"); - } - synchronized (mLock) { - if (isPrintingLocked()) { - mWriteThread.interrupt(); - mCancellationSignal = null; - } - } - } - - @Override - public void onPrintFailed(CharSequence error) { - if (DEBUG) { - Log.i(LOG_TAG, "IPrintProgressListener#onPrintFailed(" + error + ")"); - } - synchronized (mLock) { - if (isPrintingLocked()) { - mWriteThread.interrupt(); - mCancellationSignal = null; - } - } - } - }; - } - - public File getFile() { - if (DEBUG) { - Log.i(LOG_TAG, "getFile()"); - } - return mFile; - } - - public void start() throws IOException { - if (DEBUG) { - Log.i(LOG_TAG, "start()"); - } - try { - mRemoteInterface.start(); - } catch (RemoteException re) { - throw new IOException("Error reading file", re); - } - } - - public void printAttributesChanged(PrintAttributes attributes) throws IOException { - if (DEBUG) { - Log.i(LOG_TAG, "printAttributesChanged(" + attributes +")"); - } - try { - mRemoteInterface.printAttributesChanged(attributes); - } catch (RemoteException re) { - throw new IOException("Error reading file", re); - } - } - - public void print(List<PageRange> pages) throws IOException { - if (DEBUG) { - Log.i(LOG_TAG, "print(" + pages +")"); - } - InputStream in = null; - OutputStream out = null; - ParcelFileDescriptor source = null; - ParcelFileDescriptor sink = null; - synchronized (mLock) { - mWriteThread = Thread.currentThread(); - } - try { - ParcelFileDescriptor[] pipe = ParcelFileDescriptor.createPipe(); - source = pipe[0]; - sink = pipe[1]; - - in = new FileInputStream(source.getFileDescriptor()); - out = new FileOutputStream(mFile); - - // Async call to initiate the other process writing the data. - mRemoteInterface.print(pages, sink, mIPrintProgressListener); - - // Close the source. It is now held by the client. - sink.close(); - sink = null; - - final byte[] buffer = new byte[8192]; - while (true) { - if (Thread.currentThread().isInterrupted()) { - Thread.currentThread().interrupt(); - break; - } - final int readByteCount = in.read(buffer); - if (readByteCount < 0) { - break; - } - out.write(buffer, 0, readByteCount); - } - } catch (RemoteException re) { - throw new IOException("Error reading file", re); - } catch (IOException ioe) { - throw new IOException("Error reading file", ioe); - } finally { - IoUtils.closeQuietly(in); - IoUtils.closeQuietly(out); - IoUtils.closeQuietly(sink); - IoUtils.closeQuietly(source); - } - } - - public void cancelPrint() throws IOException { - if (DEBUG) { - Log.i(LOG_TAG, "cancelPrint()"); - } - synchronized (mLock) { - if (isPrintingLocked()) { - try { - mCancellationSignal.cancel(); - } catch (RemoteException re) { - throw new IOException("Error cancelling print", re); - } - } - } - } - - public void finish() throws IOException { - if (DEBUG) { - Log.i(LOG_TAG, "finish()"); - } - try { - mRemoteInterface.finish(); - } catch (RemoteException re) { - throw new IOException("Error reading file", re); - } - } - - public PrintAdapterInfo getInfo() { - synchronized (mLock) { - return mInfo; - } - } - - private boolean isPrintingLocked() { - return mCancellationSignal != null; - } -} diff --git a/packages/PrintSpooler/src/com/android/printspooler/RemotePrintDocumentAdapter.java b/packages/PrintSpooler/src/com/android/printspooler/RemotePrintDocumentAdapter.java new file mode 100644 index 0000000..2bf62ee --- /dev/null +++ b/packages/PrintSpooler/src/com/android/printspooler/RemotePrintDocumentAdapter.java @@ -0,0 +1,444 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.printspooler; + +import android.os.AsyncTask; +import android.os.Bundle; +import android.os.ICancellationSignal; +import android.os.ParcelFileDescriptor; +import android.os.RemoteException; +import android.print.ILayoutResultCallback; +import android.print.IPrintDocumentAdapter; +import android.print.IWriteResultCallback; +import android.print.PageRange; +import android.print.PrintAttributes; +import android.print.PrintDocumentAdapter.LayoutResultCallback; +import android.print.PrintDocumentAdapter.WriteResultCallback; +import android.print.PrintDocumentInfo; +import android.util.Log; +import android.util.Slog; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.List; + +import libcore.io.IoUtils; + +/** + * This class represents a remote print document adapter instance. + */ +final class RemotePrintDocumentAdapter { + private static final String LOG_TAG = "RemotePrintDocumentAdapter"; + + private static final boolean DEBUG = true; + + public static final int STATE_INITIALIZED = 0; + public static final int STATE_START_COMPLETED = 1; + public static final int STATE_LAYOUT_COMPLETED = 2; + public static final int STATE_WRITE_COMPLETED = 3; + public static final int STATE_FINISH_COMPLETED = 4; + public static final int STATE_FAILED = 6; + + private final Object mLock = new Object(); + + private final List<QueuedAsyncTask> mTaskQueue = new ArrayList<QueuedAsyncTask>(); + + private final IPrintDocumentAdapter mRemoteInterface; + + private final File mFile; + + private int mState = STATE_INITIALIZED; + + public RemotePrintDocumentAdapter(IPrintDocumentAdapter printAdatper, File file) { + mRemoteInterface = printAdatper; + mFile = file; + } + + public File getFile() { + if (DEBUG) { + Log.i(LOG_TAG, "getFile()"); + } + synchronized (mLock) { + if (mState != STATE_WRITE_COMPLETED + && mState != STATE_FINISH_COMPLETED) { + throw new IllegalStateException("Write not completed"); + } + return mFile; + } + } + + public void start() { + QueuedAsyncTask task = new QueuedAsyncTask() { + @Override + protected Void doInBackground(Void... params) { + if (DEBUG) { + Log.i(LOG_TAG, "start()"); + } + synchronized (mLock) { + mTaskQueue.add(this); + if (mState != STATE_INITIALIZED) { + throw new IllegalStateException("Invalid state: " + mState); + } + } + try { + mRemoteInterface.start(); + synchronized (mLock) { + mState = STATE_START_COMPLETED; + } + } catch (RemoteException re) { + Log.e(LOG_TAG, "Error reading file", re); + } + return null; + } + }; + task.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, (Void[]) null); + } + + public void layout(PrintAttributes oldAttributes, PrintAttributes newAttributes, + LayoutResultCallback callback, Bundle metadata) { + LayoutAsyncTask task = new LayoutAsyncTask(oldAttributes, newAttributes, callback, + metadata); + task.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, (Void[]) null); + } + + public void write(List<PageRange> pages, WriteResultCallback callback) { + WriteAsyncTask task = new WriteAsyncTask(pages, callback); + task.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, (Void[]) null); + } + + public void finish(final boolean abortPendingWork) { + QueuedAsyncTask task = new QueuedAsyncTask() { + @Override + protected Void doInBackground(Void... params) { + if (DEBUG) { + Log.i(LOG_TAG, "finish"); + } + synchronized (mLock) { + if (abortPendingWork) { + final int taskCount = mTaskQueue.size(); + for (int i = taskCount - 1; i >= 0; i--) { + mTaskQueue.remove(i).cancel(); + } + } + mTaskQueue.add(this); + if (mState < STATE_START_COMPLETED) { + return null; + } + } + try { + mRemoteInterface.finish(); + synchronized (mLock) { + mState = STATE_FINISH_COMPLETED; + } + } catch (RemoteException re) { + Log.e(LOG_TAG, "Error reading file", re); + mState = STATE_FAILED; + } + return null; + } + }; + task.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, (Void[]) null); + } + + private abstract class QueuedAsyncTask extends AsyncTask<Void, Void, Void> { + public void cancel() { + super.cancel(true); + } + } + + private final class LayoutAsyncTask extends QueuedAsyncTask { + + private final PrintAttributes mOldAttributes; + + private final PrintAttributes mNewAttributes; + + private final LayoutResultCallback mCallback; + + private final Bundle mMetadata; + + private final ILayoutResultCallback mILayoutResultCallback = + new ILayoutResultCallback.Stub() { + @Override + public void onLayoutStarted(ICancellationSignal cancellationSignal) { + synchronized (mLock) { + mCancellationSignal = cancellationSignal; + if (isCancelled()) { + cancelSignalQuietlyLocked(); + } + } + } + + @Override + public void onLayoutFinished(PrintDocumentInfo info, boolean changed) { + synchronized (mLock) { + mCancellationSignal = null; + mCompleted = true; + mLock.notifyAll(); + } + mCallback.onLayoutFinished(info, changed); + } + + @Override + public void onLayoutFailed(CharSequence error) { + synchronized (mLock) { + mCancellationSignal = null; + mCompleted = true; + mLock.notifyAll(); + } + Slog.e(LOG_TAG, "Error laying out print document: " + error); + mCallback.onLayoutFailed(error); + } + }; + + private ICancellationSignal mCancellationSignal; + + private boolean mCompleted; + + public LayoutAsyncTask(PrintAttributes oldAttributes, PrintAttributes newAttributes, + LayoutResultCallback callback, Bundle metadata) { + mOldAttributes = oldAttributes; + mNewAttributes = newAttributes; + mCallback = callback; + mMetadata = metadata; + } + + @Override + public void cancel() { + synchronized (mLock) { + throwIfCancelledLocked(); + cancelSignalQuietlyLocked(); + } + super.cancel(); + } + + @Override + protected Void doInBackground(Void... params) { + synchronized (mLock) { + mTaskQueue.add(this); + if (mState != STATE_START_COMPLETED + && mState != STATE_LAYOUT_COMPLETED + && mState != STATE_WRITE_COMPLETED) { + throw new IllegalStateException("Invalid state: " + mState); + } + } + try { + mRemoteInterface.layout(mOldAttributes, mNewAttributes, + mILayoutResultCallback, mMetadata); + synchronized (mLock) { + while (true) { + if (isCancelled()) { + mTaskQueue.remove(this); + break; + } + if (mCompleted) { + mState = STATE_LAYOUT_COMPLETED; + mTaskQueue.remove(this); + break; + } + try { + mLock.wait(); + } catch (InterruptedException ie) { + /* ignore */ + } + } + } + } catch (RemoteException re) { + Slog.e(LOG_TAG, "Error calling layout", re); + mState = STATE_FAILED; + } + return null; + } + + private void cancelSignalQuietlyLocked() { + if (mCancellationSignal != null) { + try { + mCancellationSignal.cancel(); + } catch (RemoteException re) { + Slog.e(LOG_TAG, "Error cancelling layout", re); + } + } + } + + private void throwIfCancelledLocked() { + if (isCancelled()) { + throw new IllegalStateException("Already cancelled"); + } + } + } + + private final class WriteAsyncTask extends QueuedAsyncTask { + + private final List<PageRange> mPages; + + private final WriteResultCallback mCallback; + + private final IWriteResultCallback mIWriteResultCallback = + new IWriteResultCallback.Stub() { + @Override + public void onWriteStarted(ICancellationSignal cancellationSignal) { + synchronized (mLock) { + mCancellationSignal = cancellationSignal; + if (isCancelled()) { + cancelSignalQuietlyLocked(); + } + } + } + + @Override + public void onWriteFinished(List<PageRange> pages) { + synchronized (mLock) { + mCancellationSignal = null; + mCompleted = true; + mLock.notifyAll(); + } + mCallback.onWriteFinished(pages); + } + + @Override + public void onWriteFailed(CharSequence error) { + synchronized (mLock) { + mCancellationSignal = null; + mCompleted = true; + mLock.notifyAll(); + } + Slog.e(LOG_TAG, "Error writing print document: " + error); + mCallback.onWriteFailed(error); + } + }; + + private ICancellationSignal mCancellationSignal; + + private boolean mCompleted; + + private Thread mWriteThread; + + public WriteAsyncTask(List<PageRange> pages, WriteResultCallback callback) { + mPages = pages; + mCallback = callback; + } + + @Override + public void cancel() { + synchronized (mLock) { + throwIfCancelledLocked(); + cancelSignalQuietlyLocked(); + mWriteThread.interrupt(); + } + super.cancel(); + } + + @Override + protected Void doInBackground(Void... params) { + if (DEBUG) { + Log.i(LOG_TAG, "print()"); + } + synchronized (mLock) { + mTaskQueue.add(this); + if (mState != STATE_LAYOUT_COMPLETED + && mState != STATE_WRITE_COMPLETED) { + throw new IllegalStateException("Invalid state: " + mState); + } + } + InputStream in = null; + OutputStream out = null; + ParcelFileDescriptor source = null; + ParcelFileDescriptor sink = null; + synchronized (mLock) { + mWriteThread = Thread.currentThread(); + } + try { + ParcelFileDescriptor[] pipe = ParcelFileDescriptor.createPipe(); + source = pipe[0]; + sink = pipe[1]; + + in = new FileInputStream(source.getFileDescriptor()); + out = new FileOutputStream(mFile); + + // Async call to initiate the other process writing the data. + mRemoteInterface.write(mPages, sink, mIWriteResultCallback); + + // Close the source. It is now held by the client. + sink.close(); + sink = null; + + final byte[] buffer = new byte[8192]; + while (true) { + if (Thread.currentThread().isInterrupted()) { + Thread.currentThread().interrupt(); + break; + } + final int readByteCount = in.read(buffer); + if (readByteCount < 0) { + break; + } + out.write(buffer, 0, readByteCount); + } + synchronized (mLock) { + while (true) { + if (isCancelled()) { + mTaskQueue.remove(this); + break; + } + if (mCompleted) { + mState = STATE_WRITE_COMPLETED; + mTaskQueue.remove(this); + break; + } + try { + mLock.wait(); + } catch (InterruptedException ie) { + /* ignore */ + } + } + } + } catch (RemoteException re) { + Slog.e(LOG_TAG, "Error writing print document", re); + mState = STATE_FAILED; + } catch (IOException ioe) { + Slog.e(LOG_TAG, "Error writing print document", ioe); + mState = STATE_FAILED; + } finally { + IoUtils.closeQuietly(in); + IoUtils.closeQuietly(out); + IoUtils.closeQuietly(sink); + IoUtils.closeQuietly(source); + } + return null; + } + + private void cancelSignalQuietlyLocked() { + if (mCancellationSignal != null) { + try { + mCancellationSignal.cancel(); + } catch (RemoteException re) { + Slog.e(LOG_TAG, "Error cancelling layout", re); + } + } + } + + private void throwIfCancelledLocked() { + if (isCancelled()) { + throw new IllegalStateException("Already cancelled"); + } + } + } +} diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml index dfc68f4..2629b11 100644 --- a/packages/SystemUI/AndroidManifest.xml +++ b/packages/SystemUI/AndroidManifest.xml @@ -64,6 +64,9 @@ <uses-permission android:name="android.permission.READ_DREAM_STATE" /> <uses-permission android:name="android.permission.WRITE_DREAM_STATE" /> + <!-- Alarm clocks --> + <uses-permission android:name="com.android.alarm.permission.SET_ALARM" /> + <application android:persistent="true" android:allowClearUserData="false" diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml index 5e18d0a..190c4be 100644 --- a/packages/SystemUI/res/values-nl/strings.xml +++ b/packages/SystemUI/res/values-nl/strings.xml @@ -63,13 +63,13 @@ <string name="compat_mode_off" msgid="4434467572461327898">"Rek uit v. schermvulling"</string> <string name="compat_mode_help_header" msgid="7969493989397529910">"Compatibiliteitszoom"</string> <string name="compat_mode_help_body" msgid="4946726776359270040">"Wanneer een app is ontworpen voor een kleiner scherm, wordt naast de klok een zoomknop weergegeven."</string> - <string name="screenshot_saving_ticker" msgid="7403652894056693515">"Schermafbeelding opslaan..."</string> - <string name="screenshot_saving_title" msgid="8242282144535555697">"Schermafbeelding opslaan..."</string> - <string name="screenshot_saving_text" msgid="2419718443411738818">"Schermafbeelding wordt opgeslagen."</string> - <string name="screenshot_saved_title" msgid="6461865960961414961">"Schermafbeelding gemaakt."</string> - <string name="screenshot_saved_text" msgid="1152839647677558815">"Raak aan om uw schermafbeelding te bekijken."</string> - <string name="screenshot_failed_title" msgid="705781116746922771">"Schermafbeelding is niet gemaakt."</string> - <string name="screenshot_failed_text" msgid="8134011269572415402">"Kan schermafbeelding niet opslaan. Mogelijk is de opslag in gebruik."</string> + <string name="screenshot_saving_ticker" msgid="7403652894056693515">"Screenshot opslaan..."</string> + <string name="screenshot_saving_title" msgid="8242282144535555697">"Screenshot opslaan..."</string> + <string name="screenshot_saving_text" msgid="2419718443411738818">"Screenshot wordt opgeslagen."</string> + <string name="screenshot_saved_title" msgid="6461865960961414961">"Screenshot gemaakt."</string> + <string name="screenshot_saved_text" msgid="1152839647677558815">"Raak aan om uw screenshot te bekijken."</string> + <string name="screenshot_failed_title" msgid="705781116746922771">"Screenshot is niet gemaakt."</string> + <string name="screenshot_failed_text" msgid="8134011269572415402">"Kan screenshot niet opslaan. Mogelijk is de opslag in gebruik."</string> <string name="usb_preference_title" msgid="6551050377388882787">"Opties voor USB-bestandsoverdracht"</string> <string name="use_mtp_button_title" msgid="4333504413563023626">"Koppelen als mediaspeler (MTP)"</string> <string name="use_ptp_button_title" msgid="7517127540301625751">"Koppelen als camera (PTP)"</string> diff --git a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java index fa1e3fe..4fd8aee 100644 --- a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java +++ b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java @@ -109,7 +109,7 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener { private View mScrollView; - private OnScaleGestureListener mScaleGestureListener + private OnScaleGestureListener mScaleGestureListener = new ScaleGestureDetector.SimpleOnScaleGestureListener() { @Override public boolean onScaleBegin(ScaleGestureDetector detector) { diff --git a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java index ca6a06f..6fa863d 100644 --- a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java +++ b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java @@ -140,7 +140,7 @@ public class ImageWallpaper extends WallpaperService { "\nvoid main(void) {\n" + " gl_FragColor = texture2D(texture, outTexCoords);\n" + "}\n\n"; - + private static final int FLOAT_SIZE_BYTES = 4; private static final int TRIANGLE_VERTICES_DATA_STRIDE_BYTES = 5 * FLOAT_SIZE_BYTES; private static final int TRIANGLE_VERTICES_DATA_POS_OFFSET = 0; @@ -184,7 +184,7 @@ public class ImageWallpaper extends WallpaperService { } super.onCreate(surfaceHolder); - + // TODO: Don't need this currently because the wallpaper service // will restart the image wallpaper whenever the image changes. //IntentFilter filter = new IntentFilter(Intent.ACTION_WALLPAPER_CHANGED); @@ -512,44 +512,44 @@ public class ImageWallpaper extends WallpaperService { private int loadTexture(Bitmap bitmap) { int[] textures = new int[1]; - + glActiveTexture(GL_TEXTURE0); glGenTextures(1, textures, 0); checkGlError(); - + int texture = textures[0]; glBindTexture(GL_TEXTURE_2D, texture); checkGlError(); - + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - + GLUtils.texImage2D(GL_TEXTURE_2D, 0, GL_RGBA, bitmap, GL_UNSIGNED_BYTE, 0); checkGlError(); return texture; } - + private int buildProgram(String vertex, String fragment) { int vertexShader = buildShader(vertex, GL_VERTEX_SHADER); if (vertexShader == 0) return 0; - + int fragmentShader = buildShader(fragment, GL_FRAGMENT_SHADER); if (fragmentShader == 0) return 0; - + int program = glCreateProgram(); glAttachShader(program, vertexShader); checkGlError(); - + glAttachShader(program, fragmentShader); checkGlError(); - + glLinkProgram(program); checkGlError(); - + int[] status = new int[1]; glGetProgramiv(program, GL_LINK_STATUS, status, 0); if (status[0] != GL_TRUE) { @@ -560,19 +560,19 @@ public class ImageWallpaper extends WallpaperService { glDeleteProgram(program); return 0; } - + return program; } private int buildShader(String source, int type) { int shader = glCreateShader(type); - + glShaderSource(shader, source); checkGlError(); - + glCompileShader(shader); checkGlError(); - + int[] status = new int[1]; glGetShaderiv(shader, GL_COMPILE_STATUS, status, 0); if (status[0] != GL_TRUE) { @@ -581,7 +581,7 @@ public class ImageWallpaper extends WallpaperService { glDeleteShader(shader); return 0; } - + return shader; } @@ -608,24 +608,24 @@ public class ImageWallpaper extends WallpaperService { private boolean initGL(SurfaceHolder surfaceHolder) { mEgl = (EGL10) EGLContext.getEGL(); - + mEglDisplay = mEgl.eglGetDisplay(EGL_DEFAULT_DISPLAY); if (mEglDisplay == EGL_NO_DISPLAY) { throw new RuntimeException("eglGetDisplay failed " + GLUtils.getEGLErrorString(mEgl.eglGetError())); } - + int[] version = new int[2]; if (!mEgl.eglInitialize(mEglDisplay, version)) { throw new RuntimeException("eglInitialize failed " + GLUtils.getEGLErrorString(mEgl.eglGetError())); } - + mEglConfig = chooseEglConfig(); if (mEglConfig == null) { throw new RuntimeException("eglConfig not initialized"); } - + mEglContext = createContext(mEgl, mEglDisplay, mEglConfig); if (mEglContext == EGL_NO_CONTEXT) { throw new RuntimeException("createContext failed " + @@ -667,7 +667,7 @@ public class ImageWallpaper extends WallpaperService { throw new RuntimeException("createWindowSurface failed " + GLUtils.getEGLErrorString(error)); } - + if (!mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) { throw new RuntimeException("eglMakeCurrent failed " + GLUtils.getEGLErrorString(mEgl.eglGetError())); @@ -675,13 +675,13 @@ public class ImageWallpaper extends WallpaperService { return true; } - - + + EGLContext createContext(EGL10 egl, EGLDisplay eglDisplay, EGLConfig eglConfig) { int[] attrib_list = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; - return egl.eglCreateContext(eglDisplay, eglConfig, EGL_NO_CONTEXT, attrib_list); + return egl.eglCreateContext(eglDisplay, eglConfig, EGL_NO_CONTEXT, attrib_list); } - + private EGLConfig chooseEglConfig() { int[] configsCount = new int[1]; EGLConfig[] configs = new EGLConfig[1]; diff --git a/packages/SystemUI/src/com/android/systemui/LoadAverageService.java b/packages/SystemUI/src/com/android/systemui/LoadAverageService.java index 37e974b..efbee5b 100644 --- a/packages/SystemUI/src/com/android/systemui/LoadAverageService.java +++ b/packages/SystemUI/src/com/android/systemui/LoadAverageService.java @@ -33,18 +33,18 @@ import com.android.internal.os.ProcessStats; public class LoadAverageService extends Service { private View mView; - + private static final class Stats extends ProcessStats { String mLoadText; int mLoadWidth; - + private final Paint mPaint; - + Stats(Paint paint) { super(false); mPaint = paint; } - + @Override public void onLoadChanged(float load1, float load5, float load15) { mLoadText = load1 + " / " + load5 + " / " + load15; @@ -56,7 +56,7 @@ public class LoadAverageService extends Service { return (int)mPaint.measureText(name); } } - + private class LoadView extends View { private Handler mHandler = new Handler() { @Override @@ -71,7 +71,7 @@ public class LoadAverageService extends Service { }; private final Stats mStats; - + private Paint mLoadPaint; private Paint mAddedPaint; private Paint mRemovedPaint; @@ -186,7 +186,7 @@ public class LoadAverageService extends Service { final int irqTime = stats.getLastIrqTime(); final int softIrqTime = stats.getLastSoftIrqTime(); final int idleTime = stats.getLastIdleTime(); - + final int totalTime = userTime+systemTime+iowaitTime+irqTime+softIrqTime+idleTime; if (totalTime == 0) { return; @@ -269,7 +269,7 @@ public class LoadAverageService extends Service { maxWidth = st.nameWidth; } } - + int neededWidth = mPaddingLeft + mPaddingRight + maxWidth; int neededHeight = mPaddingTop + mPaddingBottom + (mFH*(1+NW)); if (neededWidth != mNeededWidth || neededHeight != mNeededHeight) { diff --git a/packages/SystemUI/src/com/android/systemui/SystemUI.java b/packages/SystemUI/src/com/android/systemui/SystemUI.java index fec7329..cb624ad 100644 --- a/packages/SystemUI/src/com/android/systemui/SystemUI.java +++ b/packages/SystemUI/src/com/android/systemui/SystemUI.java @@ -28,7 +28,7 @@ public abstract class SystemUI { public Map<Class<?>, Object> mComponents; public abstract void start(); - + protected void onConfigurationChanged(Configuration newConfig) { } diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java index e084dac..a08eb9b 100644 --- a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java +++ b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java @@ -283,7 +283,7 @@ public class PowerUI extends SystemUI { d.show(); mInvalidChargerDialog = d; } - + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { pw.print("mLowBatteryAlertCloseLevel="); pw.println(mLowBatteryAlertCloseLevel); diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java index 5617520..119299f 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java @@ -222,12 +222,12 @@ class SaveImageInBackgroundTask extends AsyncTask<SaveImageInBackgroundData, Voi sharingIntent.putExtra(Intent.EXTRA_SUBJECT, subject); Intent chooserIntent = Intent.createChooser(sharingIntent, null); - chooserIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK + chooserIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK); mNotificationBuilder.addAction(R.drawable.ic_menu_share, r.getString(com.android.internal.R.string.share), - PendingIntent.getActivity(context, 0, chooserIntent, + PendingIntent.getActivity(context, 0, chooserIntent, PendingIntent.FLAG_CANCEL_CURRENT)); OutputStream out = resolver.openOutputStream(uri); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java index 69fc3cf..b1e38d8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java @@ -621,9 +621,9 @@ public abstract class BaseStatusBar extends SystemUI implements int maxHeight = mContext.getResources().getDimensionPixelSize(R.dimen.notification_max_height); StatusBarNotification sbn = entry.notification; - RemoteViews oneU = sbn.getNotification().contentView; - RemoteViews large = sbn.getNotification().bigContentView; - if (oneU == null) { + RemoteViews contentView = sbn.getNotification().contentView; + RemoteViews bigContentView = sbn.getNotification().bigContentView; + if (contentView == null) { return false; } @@ -657,13 +657,12 @@ public abstract class BaseStatusBar extends SystemUI implements content.setOnClickListener(null); } - // TODO(cwren) normalize variable names with those in updateNotification - View expandedOneU = null; - View expandedLarge = null; + View contentViewLocal = null; + View bigContentViewLocal = null; try { - expandedOneU = oneU.apply(mContext, adaptive, mOnClickHandler); - if (large != null) { - expandedLarge = large.apply(mContext, adaptive, mOnClickHandler); + contentViewLocal = contentView.apply(mContext, adaptive, mOnClickHandler); + if (bigContentView != null) { + bigContentViewLocal = bigContentView.apply(mContext, adaptive, mOnClickHandler); } } catch (RuntimeException e) { @@ -672,26 +671,24 @@ public abstract class BaseStatusBar extends SystemUI implements return false; } - if (expandedOneU != null) { + if (contentViewLocal != null) { SizeAdaptiveLayout.LayoutParams params = - new SizeAdaptiveLayout.LayoutParams(expandedOneU.getLayoutParams()); + new SizeAdaptiveLayout.LayoutParams(contentViewLocal.getLayoutParams()); params.minHeight = minHeight; params.maxHeight = minHeight; - adaptive.addView(expandedOneU, params); + adaptive.addView(contentViewLocal, params); } - if (expandedLarge != null) { + if (bigContentViewLocal != null) { SizeAdaptiveLayout.LayoutParams params = - new SizeAdaptiveLayout.LayoutParams(expandedLarge.getLayoutParams()); + new SizeAdaptiveLayout.LayoutParams(bigContentViewLocal.getLayoutParams()); params.minHeight = minHeight+1; params.maxHeight = maxHeight; - adaptive.addView(expandedLarge, params); + adaptive.addView(bigContentViewLocal, params); } row.setDrawingCacheEnabled(true); applyLegacyRowBackground(sbn, content); - row.setTag(R.id.expandable_tag, Boolean.valueOf(large != null)); - if (MULTIUSER_DEBUG) { TextView debug = (TextView) row.findViewById(R.id.debug_info); if (debug != null) { @@ -701,8 +698,8 @@ public abstract class BaseStatusBar extends SystemUI implements } entry.row = row; entry.content = content; - entry.expanded = expandedOneU; - entry.setLargeView(expandedLarge); + entry.expanded = contentViewLocal; + entry.setBigContentView(bigContentViewLocal); return true; } @@ -944,8 +941,8 @@ public abstract class BaseStatusBar extends SystemUI implements && oldContentView.getLayoutId() == contentView.getLayoutId(); // large view may be null boolean bigContentsUnchanged = - (oldEntry.getLargeView() == null && bigContentView == null) - || ((oldEntry.getLargeView() != null && bigContentView != null) + (oldEntry.getBigContentView() == null && bigContentView == null) + || ((oldEntry.getBigContentView() != null && bigContentView != null) && bigContentView.getPackage() != null && oldBigContentView.getPackage() != null && oldBigContentView.getPackage().equals(bigContentView.getPackage()) @@ -965,8 +962,8 @@ public abstract class BaseStatusBar extends SystemUI implements try { // Reapply the RemoteViews contentView.reapply(mContext, oldEntry.expanded, mOnClickHandler); - if (bigContentView != null && oldEntry.getLargeView() != null) { - bigContentView.reapply(mContext, oldEntry.getLargeView(), mOnClickHandler); + if (bigContentView != null && oldEntry.getBigContentView() != null) { + bigContentView.reapply(mContext, oldEntry.getBigContentView(), mOnClickHandler); } // update the contentIntent final PendingIntent contentIntent = notification.getNotification().contentIntent; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java index 673ca6b..8f62ebf 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java @@ -38,19 +38,19 @@ public class NotificationData { public View content; // takes the click events and sends the PendingIntent public View expanded; // the inflated RemoteViews public ImageView largeIcon; - protected View expandedLarge; + private View expandedBig; public Entry() {} public Entry(IBinder key, StatusBarNotification n, StatusBarIconView ic) { this.key = key; this.notification = n; this.icon = ic; } - public void setLargeView(View expandedLarge) { - this.expandedLarge = expandedLarge; - writeBooleanTag(row, R.id.expandable_tag, expandedLarge != null); + public void setBigContentView(View bigContentView) { + this.expandedBig = bigContentView; + writeBooleanTag(row, R.id.expandable_tag, bigContentView != null); } - public View getLargeView() { - return expandedLarge; + public View getBigContentView() { + return expandedBig; } /** * Return whether the entry can be expanded. diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java index 8b50a38..5bda813 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java @@ -166,7 +166,7 @@ public class StatusBarIconView extends AnimatedImageView { /** * Returns the right icon to use for this item, respecting the iconId and * iconPackage (if set) - * + * * @param context Context to use to get resources if iconPackage is not set * @return Drawable for this item, or null if the package or item could not * be found @@ -193,7 +193,7 @@ public class StatusBarIconView extends AnimatedImageView { if (icon.iconId == 0) { return null; } - + try { return r.getDrawable(icon.iconId); } catch (RuntimeException e) { @@ -285,7 +285,7 @@ public class StatusBarIconView extends AnimatedImageView { } public String toString() { - return "StatusBarIconView(slot=" + mSlot + " icon=" + mIcon + return "StatusBarIconView(slot=" + mSlot + " icon=" + mIcon + " notification=" + mNotification + ")"; } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java index 9eaee30..de33b87 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java @@ -370,11 +370,11 @@ public class NavigationBarView extends LinearLayout { @Override public void onFinishInflate() { - mRotatedViews[Surface.ROTATION_0] = + mRotatedViews[Surface.ROTATION_0] = mRotatedViews[Surface.ROTATION_180] = findViewById(R.id.rot0); mRotatedViews[Surface.ROTATION_90] = findViewById(R.id.rot90); - + mRotatedViews[Surface.ROTATION_270] = NAVBAR_ALWAYS_AT_RIGHT ? findViewById(R.id.rot90) : findViewById(R.id.rot270); @@ -434,7 +434,7 @@ public class NavigationBarView extends LinearLayout { @Override protected void onLayout (boolean changed, int left, int top, int right, int bottom) { if (DEBUG) Log.d(TAG, String.format( - "onLayout: %s (%d,%d,%d,%d)", + "onLayout: %s (%d,%d,%d,%d)", changed?"changed":"notchanged", left, top, right, bottom)); super.onLayout(changed, left, top, right, bottom); } @@ -450,7 +450,7 @@ public class NavigationBarView extends LinearLayout { return super.onInterceptTouchEvent(ev); } */ - + private String getResourceName(int resId) { if (resId != 0) { @@ -491,7 +491,7 @@ public class NavigationBarView extends LinearLayout { getWindowVisibleDisplayFrame(r); final boolean offscreen = r.right > size.x || r.bottom > size.y; - pw.println(" window: " + pw.println(" window: " + r.toShortString() + " " + visibilityToString(getWindowVisibility()) + (offscreen ? " OFFSCREEN!" : "")); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java index 751d944..d55754b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java @@ -198,7 +198,7 @@ public class PanelBar extends FrameLayout { } if (DEBUG) LOG("collapseAllPanels: animate=%s waiting=%s", animate, waiting); if (!waiting && mState != STATE_CLOSED) { - // it's possible that nothing animated, so we replicate the termination + // it's possible that nothing animated, so we replicate the termination // conditions of panelExpansionChanged here go(STATE_CLOSED); onAllPanelsCollapsed(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java index cf7f9c6..3a17c9c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java @@ -226,7 +226,7 @@ public class PanelView extends FrameLayout { return; } if (mPeekAnimator == null) { - mPeekAnimator = ObjectAnimator.ofFloat(this, + mPeekAnimator = ObjectAnimator.ofFloat(this, "expandedHeight", mPeekHeight) .setDuration(250); } @@ -339,7 +339,7 @@ public class PanelView extends FrameLayout { mFlingGestureMaxOutputVelocityPx = res.getDimension(R.dimen.fling_gesture_max_output_velocity); - mPeekHeight = res.getDimension(R.dimen.peek_height) + mPeekHeight = res.getDimension(R.dimen.peek_height) + getPaddingBottom() // our window might have a dropshadow - (mHandleView == null ? 0 : mHandleView.getPaddingTop()); // the handle might have a topshadow } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java index fd99f5b..6eadd2b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java @@ -147,7 +147,7 @@ public class PhoneStatusBar extends BaseStatusBar { private float mExpandAccelPx; // classic value: 2000px/s/s private float mCollapseAccelPx; // classic value: 2000px/s/s (will be negated to collapse "up") - private float mFlingGestureMaxOutputVelocityPx; // how fast can it really go? (should be a little + private float mFlingGestureMaxOutputVelocityPx; // how fast can it really go? (should be a little // faster than mSelfCollapseVelocityPx) PhoneStatusBarPolicy mIconPolicy; @@ -173,11 +173,11 @@ public class PhoneStatusBar extends BaseStatusBar { // viewgroup containing the normal contents of the statusbar LinearLayout mStatusBarContents; - + // right-hand icons LinearLayout mSystemIconArea; - - // left-hand icons + + // left-hand icons LinearLayout mStatusIcons; // the icons themselves IconMerger mNotificationIcons; @@ -204,7 +204,7 @@ public class PhoneStatusBar extends BaseStatusBar { // top bar View mNotificationPanelHeader; - View mDateTimeView; + View mDateTimeView; View mClearButton; ImageView mSettingsButton, mNotificationButton; @@ -264,7 +264,7 @@ public class PhoneStatusBar extends BaseStatusBar { // XXX: gesture research private final GestureRecorder mGestureRec = DEBUG_GESTURES - ? new GestureRecorder("/sdcard/statusbar_gestures.dat") + ? new GestureRecorder("/sdcard/statusbar_gestures.dat") : null; private int mNavigationIconHints = 0; @@ -391,7 +391,7 @@ public class PhoneStatusBar extends BaseStatusBar { mStatusBarView = (PhoneStatusBarView) mStatusBarWindow.findViewById(R.id.status_bar); mStatusBarView.setBar(this); - + PanelHolder holder = (PanelHolder) mStatusBarWindow.findViewById(R.id.panel_holder); mStatusBarView.setPanelHolder(holder); @@ -629,7 +629,7 @@ public class PhoneStatusBar extends BaseStatusBar { } } - mClingShown = ! (DEBUG_CLINGS + mClingShown = ! (DEBUG_CLINGS || !Prefs.read(mContext).getBoolean(Prefs.SHOWN_QUICK_SETTINGS_HELP, false)); if (!ENABLE_NOTIFICATION_PANEL_CLING || ActivityManager.isRunningInTestHarness()) { @@ -1080,7 +1080,7 @@ public class PhoneStatusBar extends BaseStatusBar { protected void updateCarrierLabelVisibility(boolean force) { if (!mShowCarrierInPanel) return; - // The idea here is to only show the carrier label when there is enough room to see it, + // The idea here is to only show the carrier label when there is enough room to see it, // i.e. when there aren't enough notifications to fill the panel. if (DEBUG) { Log.d(TAG, String.format("pileh=%d scrollh=%d carrierh=%d", @@ -1092,7 +1092,7 @@ public class PhoneStatusBar extends BaseStatusBar { !(emergencyCallsShownElsewhere && mNetworkController.isEmergencyOnly()) && mPile.getHeight() < (mNotificationPanel.getHeight() - mCarrierLabelHeight - mNotificationHeaderHeight) && mScrollView.getVisibility() == View.VISIBLE; - + if (force || mCarrierLabelVisible != makeVisible) { mCarrierLabelVisible = makeVisible; if (DEBUG) { @@ -1131,8 +1131,8 @@ public class PhoneStatusBar extends BaseStatusBar { + " any=" + any + " clearable=" + clearable); } - if (mHasFlipSettings - && mFlipSettingsView != null + if (mHasFlipSettings + && mFlipSettingsView != null && mFlipSettingsView.getVisibility() == View.VISIBLE && mScrollView.getVisibility() != View.VISIBLE) { // the flip settings panel is unequivocally showing; we should not be shown @@ -1444,7 +1444,7 @@ public class PhoneStatusBar extends BaseStatusBar { a.setStartDelay(d); return a; } - + public Animator start(Animator a) { a.start(); return a; @@ -1573,7 +1573,7 @@ public class PhoneStatusBar extends BaseStatusBar { interpolator(mAccelerateInterpolator, ObjectAnimator.ofFloat(mScrollView, View.SCALE_X, 1f, 0f) ) - .setDuration(FLIP_DURATION_OUT), + .setDuration(FLIP_DURATION_OUT), mScrollView, View.INVISIBLE)); mSettingsButtonAnim = start( setVisibilityWhenDone( @@ -1674,13 +1674,13 @@ public class PhoneStatusBar extends BaseStatusBar { /** * Enables or disables layers on the children of the notifications pile. - * + * * When layers are enabled, this method attempts to enable layers for the minimal * number of children. Only children visible when the notification area is fully * expanded will receive a layer. The technique used in this method might cause * more children than necessary to get a layer (at most one extra child with the * current UI.) - * + * * @param layerType {@link View#LAYER_TYPE_NONE} or {@link View#LAYER_TYPE_HARDWARE} */ private void setPileLayers(int layerType) { @@ -1693,7 +1693,7 @@ public class PhoneStatusBar extends BaseStatusBar { } break; case View.LAYER_TYPE_HARDWARE: - final int[] location = new int[2]; + final int[] location = new int[2]; mNotificationPanel.getLocationInWindow(location); final int left = location[0]; @@ -1803,9 +1803,9 @@ public class PhoneStatusBar extends BaseStatusBar { // Cling (first-run help) handling. // The cling is supposed to show the first time you drag, or even tap, the status bar. - // It should show the notification panel, then fade in after half a second, giving you + // It should show the notification panel, then fade in after half a second, giving you // an explanation of what just happened, as well as teach you how to access quick - // settings (another drag). The user can dismiss the cling by clicking OK or by + // settings (another drag). The user can dismiss the cling by clicking OK or by // dragging quick settings into view. final int act = event.getActionMasked(); if (mSuppressStatusBarDrags) { @@ -2284,7 +2284,7 @@ public class PhoneStatusBar extends BaseStatusBar { void updateDisplaySize() { mDisplay.getMetrics(mDisplayMetrics); if (DEBUG_GESTURES) { - mGestureRec.tag("display", + mGestureRec.tag("display", String.format("%dx%d", mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels)); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java index 2a65381..d2e7bd6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java @@ -114,9 +114,9 @@ public class PhoneStatusBarView extends PanelBar { if (mFullWidthNotifications) { // No double swiping. If either panel is open, nothing else can be pulled down. - return ((mSettingsPanel == null ? 0 : mSettingsPanel.getExpandedHeight()) - + mNotificationPanel.getExpandedHeight() > 0) - ? null + return ((mSettingsPanel == null ? 0 : mSettingsPanel.getExpandedHeight()) + + mNotificationPanel.getExpandedHeight() > 0) + ? null : mNotificationPanel; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java index 9ee6065..a9c5c79 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java @@ -44,6 +44,7 @@ import android.os.Handler; import android.os.RemoteException; import android.os.UserHandle; import android.os.UserManager; +import android.provider.AlarmClock; import android.provider.ContactsContract; import android.provider.ContactsContract.CommonDataKinds.Phone; import android.provider.ContactsContract.Profile; @@ -605,12 +606,7 @@ class QuickSettings { alarmTile.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - // TODO: Jump into the alarm application - Intent intent = new Intent(); - intent.setComponent(new ComponentName( - "com.google.android.deskclock", - "com.android.deskclock.AlarmClock")); - startSettingsActivity(intent); + startSettingsActivity(AlarmClock.ACTION_SET_ALARM); } }); mModel.addAlarmTile(alarmTile, new QuickSettingsModel.RefreshCallback() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/Ticker.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/Ticker.java index a784f37..a6ce288 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/Ticker.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/Ticker.java @@ -38,7 +38,7 @@ import java.util.ArrayList; public abstract class Ticker { private static final int TICKER_SEGMENT_DELAY = 3000; - + private Context mContext; private Handler mHandler = new Handler(); private ArrayList<Segment> mSegments = new ArrayList(); @@ -216,15 +216,15 @@ public abstract class Ticker { if (initialCount == 0 && mSegments.size() > 0) { Segment seg = mSegments.get(0); seg.first = false; - + mIconSwitcher.setAnimateFirstView(false); mIconSwitcher.reset(); mIconSwitcher.setImageDrawable(seg.icon); - + mTextSwitcher.setAnimateFirstView(false); mTextSwitcher.reset(); mTextSwitcher.setText(seg.getText()); - + tickerStarting(); scheduleAdvance(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java index 452ff489..575b44e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java @@ -71,7 +71,7 @@ public class BatteryController extends BroadcastReceiver { boolean plugged = false; switch (status) { - case BatteryManager.BATTERY_STATUS_CHARGING: + case BatteryManager.BATTERY_STATUS_CHARGING: case BatteryManager.BATTERY_STATUS_FULL: plugged = true; break; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java index e5816cd..93fb14f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java @@ -192,7 +192,7 @@ public class Clock extends TextView { return formatted; } } - + return result; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DateView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DateView.java index 27a3a15..847f997 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DateView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DateView.java @@ -63,7 +63,7 @@ public class DateView extends TextView { mAttachedToWindow = true; setUpdates(); } - + @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java index dbf9957..f6ac4a8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java @@ -40,10 +40,10 @@ public class HeadsUpNotificationView extends LinearLayout implements SwipeHelper Rect mTmpRect = new Rect(); private SwipeHelper mSwipeHelper; - + BaseStatusBar mBar; private ViewGroup mContentHolder; - + private Notification mHeadsUp; private OnClickListener mOnClickListener; @@ -62,14 +62,14 @@ public class HeadsUpNotificationView extends LinearLayout implements SwipeHelper float densityScale = getResources().getDisplayMetrics().density; float pagingTouchSlop = ViewConfiguration.get(getContext()).getScaledPagingTouchSlop(); mSwipeHelper = new SwipeHelper(SwipeHelper.X, this, densityScale, pagingTouchSlop); - + mContentHolder = (ViewGroup) findViewById(R.id.contentHolder); if (mHeadsUp != null) { // whoops, we're on already! applyContent(mHeadsUp, mOnClickListener); } } - + public void setBar(BaseStatusBar bar) { mBar = bar; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java index fc77be1..f325957 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java @@ -81,7 +81,7 @@ public class KeyButtonView extends ImageView { defStyle, 0); mCode = a.getInteger(R.styleable.KeyButtonView_keyCode, 0); - + mSupportsLongpress = a.getBoolean(R.styleable.KeyButtonView_keyRepeat, true); mGlowBG = a.getDrawable(R.styleable.KeyButtonView_glowBackground); @@ -90,7 +90,7 @@ public class KeyButtonView extends ImageView { mGlowWidth = mGlowBG.getIntrinsicWidth(); mGlowHeight = mGlowBG.getIntrinsicHeight(); } - + a.recycle(); setClickable(true); @@ -180,7 +180,7 @@ public class KeyButtonView extends ImageView { } final AnimatorSet as = mPressedAnim = new AnimatorSet(); if (pressed) { - if (mGlowScale < GLOW_MAX_SCALE_FACTOR) + if (mGlowScale < GLOW_MAX_SCALE_FACTOR) mGlowScale = GLOW_MAX_SCALE_FACTOR; if (mGlowAlpha < BUTTON_QUIESCENT_ALPHA) mGlowAlpha = BUTTON_QUIESCENT_ALPHA; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java index 63f1254..c5563da 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java @@ -88,7 +88,7 @@ public class LocationController extends BroadcastReceiver { textResId = R.string.gps_notification_searching_text; visible = true; } - + try { if (visible) { Intent gpsIntent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS); @@ -108,14 +108,14 @@ public class LocationController extends BroadcastReceiver { // Notification.Builder will helpfully fill these out for you no matter what you do n.tickerView = null; n.tickerText = null; - + n.priority = Notification.PRIORITY_HIGH; int[] idOut = new int[1]; mNotificationService.enqueueNotificationWithTag( mContext.getPackageName(), mContext.getBasePackageName(), - null, - GPS_NOTIFICATION_ID, + null, + GPS_NOTIFICATION_ID, n, idOut, UserHandle.USER_ALL); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java index cd8445c..92c57c8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java @@ -36,8 +36,8 @@ import com.android.systemui.statusbar.NotificationData; import java.util.HashMap; -public class NotificationRowLayout - extends LinearLayout +public class NotificationRowLayout + extends LinearLayout implements SwipeHelper.Callback, ExpandHelper.Callback { private static final String TAG = "NotificationRowLayout"; @@ -55,7 +55,7 @@ public class NotificationRowLayout HashMap<View, ValueAnimator> mDisappearingViews = new HashMap<View, ValueAnimator>(); private SwipeHelper mSwipeHelper; - + private OnSizeChangedListener mOnSizeChangedListener; // Flag set during notification removal animation to avoid causing too much work until @@ -74,7 +74,7 @@ public class NotificationRowLayout mRealLayoutTransition = new LayoutTransition(); mRealLayoutTransition.setAnimateParentHierarchy(true); setLayoutTransitionsEnabled(true); - + setOrientation(LinearLayout.VERTICAL); if (DEBUG) { diff --git a/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java b/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java index b75f8b3..2c36ab7 100644 --- a/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java +++ b/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java @@ -41,7 +41,7 @@ public class StorageNotification extends SystemUI { /** * The notification that is shown when a USB mass storage host - * is connected. + * is connected. * <p> * This is lazily created, so use {@link #setUsbStorageNotification()}. */ @@ -217,7 +217,7 @@ public class StorageNotification extends SystemUI { setMediaStorageNotification( com.android.internal.R.string.ext_media_unmountable_notification_title, com.android.internal.R.string.ext_media_unmountable_notification_message, - com.android.internal.R.drawable.stat_notify_sdcard_usb, true, false, pi); + com.android.internal.R.drawable.stat_notify_sdcard_usb, true, false, pi); updateUsbMassStorageNotification(mUmsAvailable); } else if (newState.equals(Environment.MEDIA_REMOVED)) { /* @@ -283,7 +283,7 @@ public class StorageNotification extends SystemUI { if (notificationManager == null) { return; } - + if (visible) { Resources r = Resources.getSystem(); CharSequence title = r.getText(titleId); @@ -300,7 +300,7 @@ public class StorageNotification extends SystemUI { } else { mUsbStorageNotification.defaults &= ~Notification.DEFAULT_SOUND; } - + mUsbStorageNotification.flags = Notification.FLAG_ONGOING_EVENT; mUsbStorageNotification.tickerText = title; @@ -329,7 +329,7 @@ public class StorageNotification extends SystemUI { mUsbStorageNotification.fullScreenIntent = pi; } } - + final int notificationId = mUsbStorageNotification.icon; if (visible) { notificationManager.notifyAsUser(null, notificationId, mUsbStorageNotification, @@ -373,7 +373,7 @@ public class StorageNotification extends SystemUI { final int notificationId = mMediaStorageNotification.icon; notificationManager.cancel(notificationId); } - + if (visible) { Resources r = Resources.getSystem(); CharSequence title = r.getText(titleId); @@ -402,7 +402,7 @@ public class StorageNotification extends SystemUI { mMediaStorageNotification.icon = icon; mMediaStorageNotification.setLatestEventInfo(mContext, title, message, pi); } - + final int notificationId = mMediaStorageNotification.icon; if (visible) { notificationManager.notifyAsUser(null, notificationId, diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbStorageActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbStorageActivity.java index 65315f3..0ed2a54 100644 --- a/packages/SystemUI/src/com/android/systemui/usb/UsbStorageActivity.java +++ b/packages/SystemUI/src/com/android/systemui/usb/UsbStorageActivity.java @@ -94,7 +94,7 @@ public class UsbStorageActivity extends Activity switchDisplay(on); } }; - + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -105,7 +105,7 @@ public class UsbStorageActivity extends Activity Log.w(TAG, "Failed to get StorageManager"); } } - + mUIHandler = new Handler(); HandlerThread thr = new HandlerThread("SystemUI UsbStorageActivity"); @@ -184,7 +184,7 @@ public class UsbStorageActivity extends Activity @Override protected void onPause() { super.onPause(); - + unregisterReceiver(mUsbStateReceiver); if (mStorageManager == null && mStorageListener != null) { mStorageManager.unregisterListener(mStorageListener); @@ -256,7 +256,7 @@ public class UsbStorageActivity extends Activity // will be hidden once USB mass storage kicks in (or fails) } }); - + // things to do elsewhere mAsyncStorageHandler.post(new Runnable() { @Override diff --git a/policy/src/com/android/internal/policy/impl/PhoneFallbackEventHandler.java b/policy/src/com/android/internal/policy/impl/PhoneFallbackEventHandler.java index b72bb2b..417527c 100644 --- a/policy/src/com/android/internal/policy/impl/PhoneFallbackEventHandler.java +++ b/policy/src/com/android/internal/policy/impl/PhoneFallbackEventHandler.java @@ -102,7 +102,8 @@ public class PhoneFallbackEventHandler implements FallbackEventHandler { case KeyEvent.KEYCODE_MEDIA_PREVIOUS: case KeyEvent.KEYCODE_MEDIA_REWIND: case KeyEvent.KEYCODE_MEDIA_RECORD: - case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: { + case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: + case KeyEvent.KEYCODE_MEDIA_AUDIO_TRACK: { handleMediaKeyEvent(event); return true; } @@ -215,7 +216,8 @@ public class PhoneFallbackEventHandler implements FallbackEventHandler { case KeyEvent.KEYCODE_MEDIA_PREVIOUS: case KeyEvent.KEYCODE_MEDIA_REWIND: case KeyEvent.KEYCODE_MEDIA_RECORD: - case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: { + case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: + case KeyEvent.KEYCODE_MEDIA_AUDIO_TRACK: { handleMediaKeyEvent(event); return true; } diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java index cd53800..bd56ee0 100644 --- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java @@ -1045,10 +1045,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { // SystemUI (status bar) layout policy int shortSizeDp = shortSize * DisplayMetrics.DENSITY_DEFAULT / density; - if (shortSizeDp < 600) { - // Allow the navigation bar to move on small devices (phones). - mNavigationBarCanMove = true; - } + // Allow the navigation bar to move on small devices (phones). + mNavigationBarCanMove = shortSizeDp < 600; mHasNavigationBar = mContext.getResources().getBoolean( com.android.internal.R.bool.config_showNavigationBar); @@ -3929,7 +3927,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { case KeyEvent.KEYCODE_MEDIA_PREVIOUS: case KeyEvent.KEYCODE_MEDIA_REWIND: case KeyEvent.KEYCODE_MEDIA_RECORD: - case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: { + case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: + case KeyEvent.KEYCODE_MEDIA_AUDIO_TRACK: { if ((result & ACTION_PASS_TO_USER) == 0) { // Only do this if we would otherwise not pass it to the user. In that // case, the PhoneWindow class will do the same thing, except it will @@ -3997,6 +3996,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { case KeyEvent.KEYCODE_MEDIA_REWIND: case KeyEvent.KEYCODE_MEDIA_RECORD: case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: + case KeyEvent.KEYCODE_MEDIA_AUDIO_TRACK: case KeyEvent.KEYCODE_CAMERA: return false; } diff --git a/services/input/InputReader.cpp b/services/input/InputReader.cpp index 5b64d8a..07731fc 100644 --- a/services/input/InputReader.cpp +++ b/services/input/InputReader.cpp @@ -2631,6 +2631,7 @@ void TouchInputMapper::populateDeviceInfo(InputDeviceInfo* info) { info->addMotionRange(AMOTION_EVENT_AXIS_GENERIC_4, mSource, y.min, y.max, y.flat, y.fuzz, y.resolution); } + info->setButtonUnderPad(mParameters.hasButtonUnderPad); } } @@ -2796,6 +2797,9 @@ void TouchInputMapper::configureParameters() { mParameters.deviceType = Parameters::DEVICE_TYPE_POINTER; } + mParameters.hasButtonUnderPad= + getEventHub()->hasInputProperty(getDeviceId(), INPUT_PROP_BUTTONPAD); + String8 deviceTypeString; if (getDevice()->getConfiguration().tryGetProperty(String8("touch.deviceType"), deviceTypeString)) { @@ -4650,6 +4654,14 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, mCurrentFingerIdBits, positions); } + // If the gesture ever enters a mode other than TAP, HOVER or TAP_DRAG, without first returning + // to NEUTRAL, then we should not generate tap event. + if (mPointerGesture.lastGestureMode != PointerGesture::HOVER + && mPointerGesture.lastGestureMode != PointerGesture::TAP + && mPointerGesture.lastGestureMode != PointerGesture::TAP_DRAG) { + mPointerGesture.resetTap(); + } + // Pick a new active touch id if needed. // Choose an arbitrary pointer that just went down, if there is one. // Otherwise choose an arbitrary remaining pointer. @@ -4858,8 +4870,12 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, } } else { #if DEBUG_GESTURES - ALOGD("Gestures: Not a TAP, %0.3fms since down", - (when - mPointerGesture.tapDownTime) * 0.000001f); + if (mPointerGesture.tapDownTime != LLONG_MIN) { + ALOGD("Gestures: Not a TAP, %0.3fms since down", + (when - mPointerGesture.tapDownTime) * 0.000001f); + } else { + ALOGD("Gestures: Not a TAP, incompatible mode transitions"); + } #endif } } diff --git a/services/input/InputReader.h b/services/input/InputReader.h index 7e303e4..3ed426f 100644 --- a/services/input/InputReader.h +++ b/services/input/InputReader.h @@ -1205,6 +1205,7 @@ protected: bool hasAssociatedDisplay; bool associatedDisplayIsExternal; bool orientationAware; + bool hasButtonUnderPad; enum GestureMode { GESTURE_MODE_POINTER, diff --git a/services/java/com/android/server/AlarmManagerService.java b/services/java/com/android/server/AlarmManagerService.java index 0be9ca5..d7cdb9d 100644 --- a/services/java/com/android/server/AlarmManagerService.java +++ b/services/java/com/android/server/AlarmManagerService.java @@ -38,7 +38,6 @@ import android.os.SystemProperties; import android.os.UserHandle; import android.os.WorkSource; import android.text.TextUtils; -import android.text.format.Time; import android.util.Pair; import android.util.Slog; import android.util.TimeUtils; @@ -57,31 +56,38 @@ import java.util.LinkedList; import java.util.Map; import java.util.TimeZone; +import static android.app.AlarmManager.RTC_WAKEUP; +import static android.app.AlarmManager.RTC; +import static android.app.AlarmManager.ELAPSED_REALTIME_WAKEUP; +import static android.app.AlarmManager.ELAPSED_REALTIME; + import com.android.internal.util.LocalLog; class AlarmManagerService extends IAlarmManager.Stub { // The threshold for how long an alarm can be late before we print a // warning message. The time duration is in milliseconds. private static final long LATE_ALARM_THRESHOLD = 10 * 1000; - - private static final int RTC_WAKEUP_MASK = 1 << AlarmManager.RTC_WAKEUP; - private static final int RTC_MASK = 1 << AlarmManager.RTC; - private static final int ELAPSED_REALTIME_WAKEUP_MASK = 1 << AlarmManager.ELAPSED_REALTIME_WAKEUP; - private static final int ELAPSED_REALTIME_MASK = 1 << AlarmManager.ELAPSED_REALTIME; + + private static final int RTC_WAKEUP_MASK = 1 << RTC_WAKEUP; + private static final int RTC_MASK = 1 << RTC; + private static final int ELAPSED_REALTIME_WAKEUP_MASK = 1 << ELAPSED_REALTIME_WAKEUP; + private static final int ELAPSED_REALTIME_MASK = 1 << ELAPSED_REALTIME; private static final int TIME_CHANGED_MASK = 1 << 16; private static final int IS_WAKEUP_MASK = RTC_WAKEUP_MASK|ELAPSED_REALTIME_WAKEUP_MASK; - // Alignment quantum for inexact repeating alarms - private static final long QUANTUM = AlarmManager.INTERVAL_FIFTEEN_MINUTES; + // Mask for testing whether a given alarm type is wakeup vs non-wakeup + private static final int TYPE_NONWAKEUP_MASK = 0x1; // low bit => non-wakeup private static final String TAG = "AlarmManager"; private static final String ClockReceiver_TAG = "ClockReceiver"; private static final boolean localLOGV = false; + private static final boolean DEBUG_BATCH = localLOGV || false; private static final int ALARM_EVENT = 1; private static final String TIMEZONE_PROPERTY = "persist.sys.timezone"; private static final Intent mBackgroundIntent = new Intent().addFlags(Intent.FLAG_FROM_BACKGROUND); + private static final IncreasingTimeOrder sIncreasingTimeOrder = new IncreasingTimeOrder(); private static final boolean WAKEUP_STATS = true; @@ -90,14 +96,10 @@ class AlarmManagerService extends IAlarmManager.Stub { private final LocalLog mLog = new LocalLog(TAG); private Object mLock = new Object(); - - private final ArrayList<Alarm> mRtcWakeupAlarms = new ArrayList<Alarm>(); - private final ArrayList<Alarm> mRtcAlarms = new ArrayList<Alarm>(); - private final ArrayList<Alarm> mElapsedRealtimeWakeupAlarms = new ArrayList<Alarm>(); - private final ArrayList<Alarm> mElapsedRealtimeAlarms = new ArrayList<Alarm>(); - private final IncreasingTimeOrder mIncreasingTimeOrder = new IncreasingTimeOrder(); - + private int mDescriptor; + private long mNextWakeup; + private long mNextNonWakeup; private int mBroadcastRefCount = 0; private PowerManager.WakeLock mWakeLock; private ArrayList<InFlight> mInFlight = new ArrayList<InFlight>(); @@ -124,6 +126,277 @@ class AlarmManagerService extends IAlarmManager.Stub { private final LinkedList<WakeupEvent> mRecentWakeups = new LinkedList<WakeupEvent>(); private final long RECENT_WAKEUP_PERIOD = 1000L * 60 * 60 * 24; // one day + static final class Batch { + long start; // These endpoints are always in ELAPSED + long end; + boolean standalone; // certain "batches" don't participate in coalescing + + final ArrayList<Alarm> alarms = new ArrayList<Alarm>(); + + Batch() { + start = 0; + end = Long.MAX_VALUE; + } + + Batch(Alarm seed) { + start = seed.whenElapsed; + end = seed.maxWhen; + alarms.add(seed); + } + + int size() { + return alarms.size(); + } + + Alarm get(int index) { + return alarms.get(index); + } + + boolean canHold(long whenElapsed, long maxWhen) { + return (end >= whenElapsed) && (start <= maxWhen); + } + + boolean add(Alarm alarm) { + boolean newStart = false; + // narrows the batch if necessary; presumes that canHold(alarm) is true + int index = Collections.binarySearch(alarms, alarm, sIncreasingTimeOrder); + if (index < 0) { + index = 0 - index - 1; + } + alarms.add(index, alarm); + if (DEBUG_BATCH) { + Slog.v(TAG, "Adding " + alarm + " to " + this); + } + if (alarm.whenElapsed > start) { + start = alarm.whenElapsed; + newStart = true; + } + if (alarm.maxWhen < end) { + end = alarm.maxWhen; + } + + if (DEBUG_BATCH) { + Slog.v(TAG, " => now " + this); + } + return newStart; + } + + boolean remove(final PendingIntent operation) { + boolean didRemove = false; + long newStart = 0; // recalculate endpoints as we go + long newEnd = Long.MAX_VALUE; + for (int i = 0; i < alarms.size(); i++) { + Alarm alarm = alarms.get(i); + if (alarm.operation.equals(operation)) { + alarms.remove(i); + didRemove = true; + } else { + if (alarm.whenElapsed > newStart) { + newStart = alarm.whenElapsed; + } + if (alarm.maxWhen < newEnd) { + newEnd = alarm.maxWhen; + } + i++; + } + } + if (didRemove) { + // commit the new batch bounds + start = newStart; + end = newEnd; + } + return didRemove; + } + + boolean remove(final String packageName) { + boolean didRemove = false; + long newStart = 0; // recalculate endpoints as we go + long newEnd = Long.MAX_VALUE; + for (int i = 0; i < alarms.size(); i++) { + Alarm alarm = alarms.get(i); + if (alarm.operation.getTargetPackage().equals(packageName)) { + alarms.remove(i); + didRemove = true; + } else { + if (alarm.whenElapsed > newStart) { + newStart = alarm.whenElapsed; + } + if (alarm.maxWhen < newEnd) { + newEnd = alarm.maxWhen; + } + i++; + } + } + if (didRemove) { + // commit the new batch bounds + start = newStart; + end = newEnd; + } + return didRemove; + } + + boolean remove(final int userHandle) { + boolean didRemove = false; + long newStart = 0; // recalculate endpoints as we go + long newEnd = Long.MAX_VALUE; + for (int i = 0; i < alarms.size(); i++) { + Alarm alarm = alarms.get(i); + if (UserHandle.getUserId(alarm.operation.getCreatorUid()) == userHandle) { + alarms.remove(i); + didRemove = true; + } else { + if (alarm.whenElapsed > newStart) { + newStart = alarm.whenElapsed; + } + if (alarm.maxWhen < newEnd) { + newEnd = alarm.maxWhen; + } + i++; + } + } + if (didRemove) { + // commit the new batch bounds + start = newStart; + end = newEnd; + } + return didRemove; + } + + boolean hasPackage(final String packageName) { + final int N = alarms.size(); + for (int i = 0; i < N; i++) { + Alarm a = alarms.get(i); + if (a.operation.getTargetPackage().equals(packageName)) { + return true; + } + } + return false; + } + + boolean hasWakeups() { + final int N = alarms.size(); + for (int i = 0; i < N; i++) { + Alarm a = alarms.get(i); + // non-wakeup alarms are types 1 and 3, i.e. have the low bit set + if ((a.type & TYPE_NONWAKEUP_MASK) == 0) { + return true; + } + } + return false; + } + + @Override + public String toString() { + StringBuilder b = new StringBuilder(40); + b.append("Batch{"); b.append(Integer.toHexString(this.hashCode())); + b.append(" num="); b.append(size()); + b.append(" start="); b.append(start); + b.append(" end="); b.append(end); + if (standalone) { + b.append(" STANDALONE"); + } + b.append('}'); + return b.toString(); + } + } + + static class BatchTimeOrder implements Comparator<Batch> { + public int compare(Batch b1, Batch b2) { + long when1 = b1.start; + long when2 = b2.start; + if (when1 - when2 > 0) { + return 1; + } + if (when1 - when2 < 0) { + return -1; + } + return 0; + } + } + + // minimum recurrence period or alarm futurity for us to be able to fuzz it + private static final long MIN_FUZZABLE_INTERVAL = 10000; + private static final BatchTimeOrder sBatchOrder = new BatchTimeOrder(); + private final ArrayList<Batch> mAlarmBatches = new ArrayList<Batch>(); + + static long convertToElapsed(long when, int type) { + final boolean isRtc = (type == RTC || type == RTC_WAKEUP); + if (isRtc) { + when -= System.currentTimeMillis() - SystemClock.elapsedRealtime(); + } + return when; + } + + // Apply a heuristic to { recurrence interval, futurity of the trigger time } to + // calculate the end of our nominal delivery window for the alarm. + static long maxTriggerTime(long now, long triggerAtTime, long interval) { + // Current heuristic: batchable window is 75% of either the recurrence interval + // [for a periodic alarm] or of the time from now to the desired delivery time, + // with a minimum delay/interval of 10 seconds, under which we will simply not + // defer the alarm. + long futurity = (interval == 0) + ? (triggerAtTime - now) + : interval; + if (futurity < MIN_FUZZABLE_INTERVAL) { + futurity = 0; + } + return triggerAtTime + (long)(.75 * futurity); + } + + // returns true if the batch was added at the head + static boolean addBatchLocked(ArrayList<Batch> list, Batch newBatch) { + int index = Collections.binarySearch(list, newBatch, sBatchOrder); + if (index < 0) { + index = 0 - index - 1; + } + list.add(index, newBatch); + return (index == 0); + } + + Batch attemptCoalesceLocked(long whenElapsed, long maxWhen) { + final int N = mAlarmBatches.size(); + for (int i = 0; i < N; i++) { + Batch b = mAlarmBatches.get(i); + if (!b.standalone && b.canHold(whenElapsed, maxWhen)) { + return b; + } + } + return null; + } + + // The RTC clock has moved arbitrarily, so we need to recalculate all the batching + void rebatchAllAlarms() { + if (DEBUG_BATCH) { + Slog.v(TAG, "RTC changed; rebatching"); + } + synchronized (mLock) { + ArrayList<Batch> oldSet = (ArrayList<Batch>) mAlarmBatches.clone(); + mAlarmBatches.clear(); + final long nowElapsed = SystemClock.elapsedRealtime(); + for (Batch batch : oldSet) { + final int N = batch.size(); + for (int i = 0; i < N; i++) { + Alarm a = batch.get(i); + long whenElapsed = convertToElapsed(a.when, a.type); + long maxElapsed = (a.whenElapsed == a.maxWhen) + ? whenElapsed + : maxTriggerTime(nowElapsed, whenElapsed, a.repeatInterval); + if (batch.standalone) { + // this will also be the only alarm in the batch + a = new Alarm(a.type, a.when, whenElapsed, maxElapsed, + a.repeatInterval, a.operation); + Batch newBatch = new Batch(a); + newBatch.standalone = true; + addBatchLocked(mAlarmBatches, newBatch); + } else { + setImplLocked(a.type, a.when, whenElapsed, maxElapsed, + a.repeatInterval, a.operation, false); + } + } + } + } + } + private static final class InFlight extends Intent { final PendingIntent mPendingIntent; final Pair<String, ComponentName> mTarget; @@ -184,6 +457,7 @@ class AlarmManagerService extends IAlarmManager.Stub { public AlarmManagerService(Context context) { mContext = context; mDescriptor = init(); + mNextWakeup = mNextNonWakeup = 0; // We have to set current TimeZone info to kernel // because kernel doesn't keep this after reboot @@ -224,77 +498,102 @@ class AlarmManagerService extends IAlarmManager.Stub { super.finalize(); } } - - public void set(int type, long triggerAtTime, PendingIntent operation) { - setRepeating(type, triggerAtTime, 0, operation); - } - - public void setRepeating(int type, long triggerAtTime, long interval, + + @Override + public void set(int type, long triggerAtTime, long windowLength, long interval, PendingIntent operation) { + set(type, triggerAtTime, windowLength, interval, operation, false); + } + + public void set(int type, long triggerAtTime, long windowLength, long interval, + PendingIntent operation, boolean isStandalone) { if (operation == null) { Slog.w(TAG, "set/setRepeating ignored because there is no intent"); return; } - synchronized (mLock) { - Alarm alarm = new Alarm(); - alarm.type = type; - alarm.when = triggerAtTime; - alarm.repeatInterval = interval; - alarm.operation = operation; - // Remove this alarm if already scheduled. - removeLocked(operation); + // Sanity check the window length. This will catch people mistakenly + // trying to pass an end-of-window timestamp rather than a duration. + if (windowLength > AlarmManager.INTERVAL_HALF_DAY) { + Slog.w(TAG, "Window length " + windowLength + + "ms suspiciously long; limiting to 1 hour"); + windowLength = AlarmManager.INTERVAL_HOUR; + } - if (localLOGV) Slog.v(TAG, "set: " + alarm); + if (type < RTC_WAKEUP || type > ELAPSED_REALTIME) { + throw new IllegalArgumentException("Invalid alarm type " + type); + } - int index = addAlarmLocked(alarm); - if (index == 0) { - setLocked(alarm); + final long nowElapsed = SystemClock.elapsedRealtime(); + final long triggerElapsed = convertToElapsed(triggerAtTime, type); + final long maxElapsed; + if (windowLength == AlarmManager.WINDOW_EXACT) { + maxElapsed = triggerElapsed; + } else if (windowLength < 0) { + maxElapsed = maxTriggerTime(nowElapsed, triggerElapsed, interval); + } else { + maxElapsed = triggerElapsed + windowLength; + } + + synchronized (mLock) { + if (DEBUG_BATCH) { + Slog.v(TAG, "set(" + operation + ") : type=" + type + + " triggerAtTime=" + triggerAtTime + " win=" + windowLength + + " tElapsed=" + triggerElapsed + " maxElapsed=" + maxElapsed + + " interval=" + interval + " standalone=" + isStandalone); } + setImplLocked(type, triggerAtTime, triggerElapsed, maxElapsed, + interval, operation, isStandalone); } } - - public void setInexactRepeating(int type, long triggerAtTime, long interval, - PendingIntent operation) { - if (operation == null) { - Slog.w(TAG, "setInexactRepeating ignored because there is no intent"); - return; - } - if (interval <= 0) { - Slog.w(TAG, "setInexactRepeating ignored because interval " + interval - + " is invalid"); - return; + private void setImplLocked(int type, long when, long whenElapsed, long maxWhen, long interval, + PendingIntent operation, boolean isStandalone) { + Alarm a = new Alarm(type, when, whenElapsed, maxWhen, interval, operation); + removeLocked(operation); + + final boolean reschedule; + Batch batch = (isStandalone) ? null : attemptCoalesceLocked(whenElapsed, maxWhen); + if (batch == null) { + batch = new Batch(a); + batch.standalone = isStandalone; + if (DEBUG_BATCH) { + Slog.v(TAG, "Starting new alarm batch " + batch); + } + reschedule = addBatchLocked(mAlarmBatches, batch); + } else { + reschedule = batch.add(a); } - // If the requested interval isn't a multiple of 15 minutes, just treat it as exact - if (interval % QUANTUM != 0) { - if (localLOGV) Slog.v(TAG, "Interval " + interval + " not a quantum multiple"); - setRepeating(type, triggerAtTime, interval, operation); - return; + if (reschedule) { + rescheduleKernelAlarmsLocked(); } + } - // Translate times into the ELAPSED timebase for alignment purposes so that - // alignment never tries to match against wall clock times. - final boolean isRtc = (type == AlarmManager.RTC || type == AlarmManager.RTC_WAKEUP); - final long skew = (isRtc) - ? System.currentTimeMillis() - SystemClock.elapsedRealtime() - : 0; - - // Slip forward to the next ELAPSED-timebase quantum after the stated time. If - // we're *at* a quantum point, leave it alone. - final long adjustedTriggerTime; - long offset = (triggerAtTime - skew) % QUANTUM; - if (offset != 0) { - adjustedTriggerTime = triggerAtTime - offset + QUANTUM; - } else { - adjustedTriggerTime = triggerAtTime; + private Batch findFirstWakeupBatchLocked() { + final int N = mAlarmBatches.size(); + for (int i = 0; i < N; i++) { + Batch b = mAlarmBatches.get(i); + if (b.hasWakeups()) { + return b; + } } + return null; + } - // Set the alarm based on the quantum-aligned start time - if (localLOGV) Slog.v(TAG, "setInexactRepeating: type=" + type + " interval=" + interval - + " trigger=" + adjustedTriggerTime + " orig=" + triggerAtTime); - setRepeating(type, adjustedTriggerTime, interval, operation); + private void rescheduleKernelAlarmsLocked() { + // Schedule the next upcoming wakeup alarm. If there is a deliverable batch + // prior to that which contains no wakeups, we schedule that as well. + final Batch firstWakeup = findFirstWakeupBatchLocked(); + final Batch firstBatch = mAlarmBatches.get(0); + if (firstWakeup != null && mNextWakeup != firstWakeup.start) { + mNextWakeup = firstWakeup.start; + setLocked(ELAPSED_REALTIME_WAKEUP, firstWakeup.start); + } + if (firstBatch != firstWakeup && mNextNonWakeup != firstBatch.start) { + mNextNonWakeup = firstBatch.start; + setLocked(ELAPSED_REALTIME, firstBatch.start); + } } public void setTime(long millis) { @@ -356,160 +655,61 @@ class AlarmManagerService extends IAlarmManager.Stub { } public void removeLocked(PendingIntent operation) { - removeLocked(mRtcWakeupAlarms, operation); - removeLocked(mRtcAlarms, operation); - removeLocked(mElapsedRealtimeWakeupAlarms, operation); - removeLocked(mElapsedRealtimeAlarms, operation); - } - - private void removeLocked(ArrayList<Alarm> alarmList, - PendingIntent operation) { - if (alarmList.size() <= 0) { - return; - } - - // iterator over the list removing any it where the intent match - for (int i=0; i<alarmList.size(); i++) { - Alarm alarm = alarmList.get(i); - if (alarm.operation.equals(operation)) { - alarmList.remove(i); - i--; + for (int i = mAlarmBatches.size() - 1; i >= 0; i--) { + Batch b = mAlarmBatches.get(i); + b.remove(operation); + if (b.size() == 0) { + mAlarmBatches.remove(i); } } } public void removeLocked(String packageName) { - removeLocked(mRtcWakeupAlarms, packageName); - removeLocked(mRtcAlarms, packageName); - removeLocked(mElapsedRealtimeWakeupAlarms, packageName); - removeLocked(mElapsedRealtimeAlarms, packageName); - } - - private void removeLocked(ArrayList<Alarm> alarmList, - String packageName) { - if (alarmList.size() <= 0) { - return; - } - - // iterator over the list removing any it where the intent match - for (int i=0; i<alarmList.size(); i++) { - Alarm alarm = alarmList.get(i); - if (alarm.operation.getTargetPackage().equals(packageName)) { - alarmList.remove(i); - i--; + for (int i = mAlarmBatches.size() - 1; i >= 0; i--) { + Batch b = mAlarmBatches.get(i); + b.remove(packageName); + if (b.size() == 0) { + mAlarmBatches.remove(i); } } } public void removeUserLocked(int userHandle) { - removeUserLocked(mRtcWakeupAlarms, userHandle); - removeUserLocked(mRtcAlarms, userHandle); - removeUserLocked(mElapsedRealtimeWakeupAlarms, userHandle); - removeUserLocked(mElapsedRealtimeAlarms, userHandle); - } - - private void removeUserLocked(ArrayList<Alarm> alarmList, int userHandle) { - if (alarmList.size() <= 0) { - return; - } - - // iterator over the list removing any it where the intent match - for (int i=0; i<alarmList.size(); i++) { - Alarm alarm = alarmList.get(i); - if (UserHandle.getUserId(alarm.operation.getCreatorUid()) == userHandle) { - alarmList.remove(i); - i--; + for (int i = mAlarmBatches.size() - 1; i >= 0; i--) { + Batch b = mAlarmBatches.get(i); + b.remove(userHandle); + if (b.size() == 0) { + mAlarmBatches.remove(i); } } } - - public boolean lookForPackageLocked(String packageName) { - return lookForPackageLocked(mRtcWakeupAlarms, packageName) - || lookForPackageLocked(mRtcAlarms, packageName) - || lookForPackageLocked(mElapsedRealtimeWakeupAlarms, packageName) - || lookForPackageLocked(mElapsedRealtimeAlarms, packageName); - } - private boolean lookForPackageLocked(ArrayList<Alarm> alarmList, String packageName) { - for (int i=alarmList.size()-1; i>=0; i--) { - if (alarmList.get(i).operation.getTargetPackage().equals(packageName)) { + public boolean lookForPackageLocked(String packageName) { + for (int i = 0; i < mAlarmBatches.size(); i++) { + Batch b = mAlarmBatches.get(i); + if (b.hasPackage(packageName)) { return true; } } return false; } - - private ArrayList<Alarm> getAlarmList(int type) { - switch (type) { - case AlarmManager.RTC_WAKEUP: return mRtcWakeupAlarms; - case AlarmManager.RTC: return mRtcAlarms; - case AlarmManager.ELAPSED_REALTIME_WAKEUP: return mElapsedRealtimeWakeupAlarms; - case AlarmManager.ELAPSED_REALTIME: return mElapsedRealtimeAlarms; - } - - return null; - } - - private int addAlarmLocked(Alarm alarm) { - ArrayList<Alarm> alarmList = getAlarmList(alarm.type); - - int index = Collections.binarySearch(alarmList, alarm, mIncreasingTimeOrder); - if (index < 0) { - index = 0 - index - 1; - } - if (localLOGV) Slog.v(TAG, "Adding alarm " + alarm + " at " + index); - alarmList.add(index, alarm); - - if (localLOGV) { - // Display the list of alarms for this alarm type - Slog.v(TAG, "alarms: " + alarmList.size() + " type: " + alarm.type); - int position = 0; - for (Alarm a : alarmList) { - Time time = new Time(); - time.set(a.when); - String timeStr = time.format("%b %d %I:%M:%S %p"); - Slog.v(TAG, position + ": " + timeStr - + " " + a.operation.getTargetPackage()); - position += 1; - } - } - - return index; - } - - public long timeToNextAlarm() { - long nextAlarm = Long.MAX_VALUE; - synchronized (mLock) { - for (int i=AlarmManager.RTC_WAKEUP; - i<=AlarmManager.ELAPSED_REALTIME; i++) { - ArrayList<Alarm> alarmList = getAlarmList(i); - if (alarmList.size() > 0) { - Alarm a = alarmList.get(0); - if (a.when < nextAlarm) { - nextAlarm = a.when; - } - } - } - } - return nextAlarm; - } - - private void setLocked(Alarm alarm) + + private void setLocked(int type, long when) { if (mDescriptor != -1) { // The kernel never triggers alarms with negative wakeup times // so we ensure they are positive. long alarmSeconds, alarmNanoseconds; - if (alarm.when < 0) { + if (when < 0) { alarmSeconds = 0; alarmNanoseconds = 0; } else { - alarmSeconds = alarm.when / 1000; - alarmNanoseconds = (alarm.when % 1000) * 1000 * 1000; + alarmSeconds = when / 1000; + alarmNanoseconds = (when % 1000) * 1000 * 1000; } - set(mDescriptor, alarm.type, alarmSeconds, alarmNanoseconds); + set(mDescriptor, type, alarmSeconds, alarmNanoseconds); } else { @@ -517,7 +717,7 @@ class AlarmManagerService extends IAlarmManager.Stub { msg.what = ALARM_EVENT; mHandler.removeMessages(ALARM_EVENT); - mHandler.sendMessageAtTime(msg, alarm.when); + mHandler.sendMessageAtTime(msg, when); } } @@ -533,29 +733,28 @@ class AlarmManagerService extends IAlarmManager.Stub { synchronized (mLock) { pw.println("Current Alarm Manager state:"); - if (mRtcWakeupAlarms.size() > 0 || mRtcAlarms.size() > 0) { - final long now = System.currentTimeMillis(); - SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); - pw.println(" "); - pw.print(" Realtime wakeup (now="); - pw.print(sdf.format(new Date(now))); pw.println("):"); - if (mRtcWakeupAlarms.size() > 0) { - dumpAlarmList(pw, mRtcWakeupAlarms, " ", "RTC_WAKEUP", now); - } - if (mRtcAlarms.size() > 0) { - dumpAlarmList(pw, mRtcAlarms, " ", "RTC", now); - } - } - if (mElapsedRealtimeWakeupAlarms.size() > 0 || mElapsedRealtimeAlarms.size() > 0) { - final long now = SystemClock.elapsedRealtime(); - pw.println(" "); - pw.print(" Elapsed realtime wakeup (now="); - TimeUtils.formatDuration(now, pw); pw.println("):"); - if (mElapsedRealtimeWakeupAlarms.size() > 0) { - dumpAlarmList(pw, mElapsedRealtimeWakeupAlarms, " ", "ELAPSED_WAKEUP", now); - } - if (mElapsedRealtimeAlarms.size() > 0) { - dumpAlarmList(pw, mElapsedRealtimeAlarms, " ", "ELAPSED", now); + final long nowRTC = System.currentTimeMillis(); + final long nowELAPSED = SystemClock.elapsedRealtime(); + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + + pw.print("nowRTC="); pw.print(nowRTC); + pw.print("="); pw.print(sdf.format(new Date(nowRTC))); + pw.print(" nowELAPSED="); pw.println(nowELAPSED); + + long nextWakeupRTC = mNextWakeup + (nowRTC - nowELAPSED); + long nextNonWakeupRTC = mNextNonWakeup + (nowRTC - nowELAPSED); + pw.print("Next alarm: "); pw.print(mNextNonWakeup); + pw.print(" = "); pw.println(sdf.format(new Date(nextNonWakeupRTC))); + pw.print("Next wakeup: "); pw.print(mNextWakeup); + pw.print(" = "); pw.println(sdf.format(new Date(nextWakeupRTC))); + + if (mAlarmBatches.size() > 0) { + pw.println(); + pw.print("Pending alarm batches: "); + pw.println(mAlarmBatches.size()); + for (Batch b : mAlarmBatches) { + pw.print(b); pw.println(':'); + dumpAlarmList(pw, b.alarms, " ", nowELAPSED, nowRTC); } } @@ -662,7 +861,6 @@ class AlarmManagerService extends IAlarmManager.Stub { if (WAKEUP_STATS) { pw.println(); pw.println(" Recent Wakeup History:"); - final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd-HH:mm:ss.SSS"); long last = -1; for (WakeupEvent event : mRecentWakeups) { pw.print(" "); pw.print(sdf.format(new Date(event.when))); @@ -691,77 +889,78 @@ class AlarmManagerService extends IAlarmManager.Stub { a.dump(pw, prefix + " ", now); } } - + + private static final String labelForType(int type) { + switch (type) { + case RTC: return "RTC"; + case RTC_WAKEUP : return "RTC_WAKEUP"; + case ELAPSED_REALTIME : return "ELAPSED"; + case ELAPSED_REALTIME_WAKEUP: return "ELAPSED_WAKEUP"; + default: + break; + } + return "--unknown--"; + } + + private static final void dumpAlarmList(PrintWriter pw, ArrayList<Alarm> list, + String prefix, long nowELAPSED, long nowRTC) { + for (int i=list.size()-1; i>=0; i--) { + Alarm a = list.get(i); + final String label = labelForType(a.type); + long now = (a.type <= RTC) ? nowRTC : nowELAPSED; + pw.print(prefix); pw.print(label); pw.print(" #"); pw.print(i); + pw.print(": "); pw.println(a); + a.dump(pw, prefix + " ", now); + } + } + private native int init(); private native void close(int fd); private native void set(int fd, int type, long seconds, long nanoseconds); private native int waitForAlarm(int fd); private native int setKernelTimezone(int fd, int minuteswest); - private void triggerAlarmsLocked(ArrayList<Alarm> alarmList, - ArrayList<Alarm> triggerList, - long now) - { - ArrayList<Alarm> repeats = null; - - for (int i=0; i<alarmList.size(); i++) { - Alarm alarm = alarmList.get(i); + private void triggerAlarmsLocked(ArrayList<Alarm> triggerList, long nowELAPSED, long nowRTC) { + Batch batch; - if (localLOGV) Slog.v(TAG, "Checking active alarm when=" + alarm.when + " " + alarm); - - if (alarm.when > now) { - // don't fire alarms in the future + // batches are temporally sorted, so we need only pull from the + // start of the list until we either empty it or hit a batch + // that is not yet deliverable + while ((batch = mAlarmBatches.get(0)) != null) { + if (batch.start > nowELAPSED) { + // Everything else is scheduled for the future break; } - - // If the alarm is late, then print a warning message. - // Note that this can happen if the user creates a new event on - // the Calendar app with a reminder that is in the past. In that - // case, the reminder alarm will fire immediately. - if (localLOGV && now - alarm.when > LATE_ALARM_THRESHOLD) { - Slog.v(TAG, "alarm is late! alarm time: " + alarm.when - + " now: " + now + " delay (in seconds): " - + (now - alarm.when) / 1000); - } - // Recurring alarms may have passed several alarm intervals while the - // phone was asleep or off, so pass a trigger count when sending them. - if (localLOGV) Slog.v(TAG, "Alarm triggering: " + alarm); - alarm.count = 1; - if (alarm.repeatInterval > 0) { - // this adjustment will be zero if we're late by - // less than one full repeat interval - alarm.count += (now - alarm.when) / alarm.repeatInterval; - } - triggerList.add(alarm); - - // remove the alarm from the list - alarmList.remove(i); - i--; - - // if it repeats queue it up to be read-added to the list - if (alarm.repeatInterval > 0) { - if (repeats == null) { - repeats = new ArrayList<Alarm>(); + // We will (re)schedule some alarms now; don't let that interfere + // with delivery of this current batch + mAlarmBatches.remove(0); + + final int N = batch.size(); + for (int i = 0; i < N; i++) { + Alarm alarm = batch.get(i); + alarm.count = 1; + triggerList.add(alarm); + + // Recurring alarms may have passed several alarm intervals while the + // phone was asleep or off, so pass a trigger count when sending them. + if (alarm.repeatInterval > 0) { + // this adjustment will be zero if we're late by + // less than one full repeat interval + alarm.count += (nowELAPSED - alarm.whenElapsed) / alarm.repeatInterval; + + // Also schedule its next recurrence + final long delta = alarm.count * alarm.repeatInterval; + final long nextElapsed = alarm.whenElapsed + delta; + setImplLocked(alarm.type, alarm.when + delta, nextElapsed, + maxTriggerTime(nowELAPSED, nextElapsed, alarm.repeatInterval), + alarm.repeatInterval, alarm.operation, batch.standalone); } - repeats.add(alarm); - } - } - // reset any repeating alarms. - if (repeats != null) { - for (int i=0; i<repeats.size(); i++) { - Alarm alarm = repeats.get(i); - alarm.when += alarm.count * alarm.repeatInterval; - addAlarmLocked(alarm); } } - - if (alarmList.size() > 0) { - setLocked(alarmList.get(0)); - } } - + /** * This Comparator sorts Alarms into increasing time order. */ @@ -783,15 +982,21 @@ class AlarmManagerService extends IAlarmManager.Stub { public int type; public int count; public long when; + public long whenElapsed; // 'when' in the elapsed time base + public long maxWhen; // also in the elapsed time base public long repeatInterval; public PendingIntent operation; - public Alarm() { - when = 0; - repeatInterval = 0; - operation = null; + public Alarm(int _type, long _when, long _whenElapsed, long _maxWhen, + long _interval, PendingIntent _op) { + type = _type; + when = _when; + whenElapsed = _whenElapsed; + maxWhen = _maxWhen; + repeatInterval = _interval; + operation = _op; } - + @Override public String toString() { @@ -808,6 +1013,7 @@ class AlarmManagerService extends IAlarmManager.Stub { public void dump(PrintWriter pw, String prefix, long now) { pw.print(prefix); pw.print("type="); pw.print(type); + pw.print(" whenElapsed="); pw.print(whenElapsed); pw.print(" when="); TimeUtils.formatDuration(when, now, pw); pw.print(" repeatInterval="); pw.print(repeatInterval); pw.print(" count="); pw.println(count); @@ -815,16 +1021,22 @@ class AlarmManagerService extends IAlarmManager.Stub { } } - void recordWakeupAlarms(ArrayList<Alarm> alarms, long now, long skewToRTC) { - for (Alarm a : alarms) { - if (a.when > now) { + void recordWakeupAlarms(ArrayList<Batch> batches, long nowELAPSED, long nowRTC) { + final int numBatches = batches.size(); + for (int nextBatch = 0; nextBatch < numBatches; nextBatch++) { + Batch b = batches.get(nextBatch); + if (b.start > nowELAPSED) { break; } - WakeupEvent e = new WakeupEvent(now + skewToRTC, - a.operation.getCreatorUid(), - a.operation.getIntent().getAction()); - mRecentWakeups.add(e); + final int numAlarms = b.alarms.size(); + for (int nextAlarm = 0; nextAlarm < numAlarms; nextAlarm++) { + Alarm a = b.alarms.get(nextAlarm); + WakeupEvent e = new WakeupEvent(nowRTC, + a.operation.getCreatorUid(), + a.operation.getIntent().getAction()); + mRecentWakeups.add(e); + } } } @@ -847,6 +1059,7 @@ class AlarmManagerService extends IAlarmManager.Stub { if ((result & TIME_CHANGED_MASK) != 0) { remove(mTimeTickSender); + rebatchAllAlarms(); mClockReceiver.scheduleTimeTickEvent(); Intent intent = new Intent(Intent.ACTION_TIME_CHANGED); intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING @@ -873,28 +1086,14 @@ class AlarmManagerService extends IAlarmManager.Stub { mRecentWakeups.remove(); } - recordWakeupAlarms(mRtcWakeupAlarms, - nowRTC, - 0); - recordWakeupAlarms(mElapsedRealtimeWakeupAlarms, - nowELAPSED, - nowRTC - nowELAPSED); + recordWakeupAlarms(mAlarmBatches, nowELAPSED, nowRTC); } } - if ((result & RTC_WAKEUP_MASK) != 0) - triggerAlarmsLocked(mRtcWakeupAlarms, triggerList, nowRTC); - - if ((result & RTC_MASK) != 0) - triggerAlarmsLocked(mRtcAlarms, triggerList, nowRTC); - - if ((result & ELAPSED_REALTIME_WAKEUP_MASK) != 0) - triggerAlarmsLocked(mElapsedRealtimeWakeupAlarms, triggerList, nowELAPSED); - - if ((result & ELAPSED_REALTIME_MASK) != 0) - triggerAlarmsLocked(mElapsedRealtimeAlarms, triggerList, nowELAPSED); - - // now trigger the alarms + triggerAlarmsLocked(triggerList, nowELAPSED, nowRTC); + rescheduleKernelAlarmsLocked(); + + // now deliver the alarm intents for (int i=0; i<triggerList.size(); i++) { Alarm alarm = triggerList.get(i); try { @@ -930,8 +1129,8 @@ class AlarmManagerService extends IAlarmManager.Stub { } else { fs.nesting++; } - if (alarm.type == AlarmManager.ELAPSED_REALTIME_WAKEUP - || alarm.type == AlarmManager.RTC_WAKEUP) { + if (alarm.type == ELAPSED_REALTIME_WAKEUP + || alarm.type == RTC_WAKEUP) { bs.numWakeup++; fs.numWakeup++; ActivityManagerNative.noteWakeupAlarm( @@ -980,10 +1179,8 @@ class AlarmManagerService extends IAlarmManager.Stub { ArrayList<Alarm> triggerList = new ArrayList<Alarm>(); synchronized (mLock) { final long nowRTC = System.currentTimeMillis(); - triggerAlarmsLocked(mRtcWakeupAlarms, triggerList, nowRTC); - triggerAlarmsLocked(mRtcAlarms, triggerList, nowRTC); - triggerAlarmsLocked(mElapsedRealtimeWakeupAlarms, triggerList, nowRTC); - triggerAlarmsLocked(mElapsedRealtimeAlarms, triggerList, nowRTC); + final long nowELAPSED = SystemClock.elapsedRealtime(); + triggerAlarmsLocked(triggerList, nowELAPSED, nowRTC); } // now trigger the alarms without the lock held @@ -1035,8 +1232,8 @@ class AlarmManagerService extends IAlarmManager.Stub { // the top of the next minute. final long tickEventDelay = nextTime - currentTime; - set(AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime() + tickEventDelay, - mTimeTickSender); + set(ELAPSED_REALTIME, SystemClock.elapsedRealtime() + tickEventDelay, 0, + 0, mTimeTickSender, true); } public void scheduleDateChangedEvent() { @@ -1048,7 +1245,7 @@ class AlarmManagerService extends IAlarmManager.Stub { calendar.set(Calendar.MILLISECOND, 0); calendar.add(Calendar.DAY_OF_MONTH, 1); - set(AlarmManager.RTC, calendar.getTimeInMillis(), mDateChangeSender); + set(RTC, calendar.getTimeInMillis(), 0, 0, mDateChangeSender, true); } } diff --git a/services/java/com/android/server/AppOpsService.java b/services/java/com/android/server/AppOpsService.java index 7a107e7..6b4d248 100644 --- a/services/java/com/android/server/AppOpsService.java +++ b/services/java/com/android/server/AppOpsService.java @@ -40,6 +40,7 @@ import android.os.Process; import android.os.RemoteException; import android.os.ServiceManager; import android.os.UserHandle; +import android.util.ArrayMap; import android.util.AtomicFile; import android.util.Log; import android.util.Slog; @@ -97,6 +98,8 @@ public class AppOpsService extends IAppOpsService.Stub { } public final static class Op { + public final int uid; + public final String packageName; public final int op; public int mode; public int duration; @@ -104,7 +107,9 @@ public class AppOpsService extends IAppOpsService.Stub { public long rejectTime; public int nesting; - public Op(int _op) { + public Op(int _uid, String _packageName, int _op) { + uid = _uid; + packageName = _packageName; op = _op; mode = AppOpsManager.MODE_ALLOWED; } @@ -112,10 +117,10 @@ public class AppOpsService extends IAppOpsService.Stub { final SparseArray<ArrayList<Callback>> mOpModeWatchers = new SparseArray<ArrayList<Callback>>(); - final HashMap<String, ArrayList<Callback>> mPackageModeWatchers - = new HashMap<String, ArrayList<Callback>>(); - final HashMap<IBinder, Callback> mModeWatchers - = new HashMap<IBinder, Callback>(); + final ArrayMap<String, ArrayList<Callback>> mPackageModeWatchers + = new ArrayMap<String, ArrayList<Callback>>(); + final ArrayMap<IBinder, Callback> mModeWatchers + = new ArrayMap<IBinder, Callback>(); public final class Callback implements DeathRecipient { final IAppOpsCallback mCallback; @@ -138,6 +143,47 @@ public class AppOpsService extends IAppOpsService.Stub { } } + final ArrayMap<IBinder, ClientState> mClients = new ArrayMap<IBinder, ClientState>(); + + public final class ClientState extends Binder implements DeathRecipient { + final IBinder mAppToken; + final int mPid; + final ArrayList<Op> mStartedOps; + + public ClientState(IBinder appToken) { + mAppToken = appToken; + mPid = Binder.getCallingPid(); + if (appToken instanceof Binder) { + // For local clients, there is no reason to track them. + mStartedOps = null; + } else { + mStartedOps = new ArrayList<Op>(); + try { + mAppToken.linkToDeath(this, 0); + } catch (RemoteException e) { + } + } + } + + @Override + public String toString() { + return "ClientState{" + + "mAppToken=" + mAppToken + + ", " + (mStartedOps != null ? ("pid=" + mPid) : "local") + + '}'; + } + + @Override + public void binderDied() { + synchronized (AppOpsService.this) { + for (int i=mStartedOps.size()-1; i>=0; i--) { + finishOperationLocked(mStartedOps.get(i)); + } + mClients.remove(mAppToken); + } + } + } + public AppOpsService(File storagePath) { mFile = new AtomicFile(storagePath); mHandler = new Handler(); @@ -380,21 +426,18 @@ public class AppOpsService extends IAppOpsService.Stub { Callback cb = mModeWatchers.remove(callback.asBinder()); if (cb != null) { cb.unlinkToDeath(); - for (int i=0; i<mOpModeWatchers.size(); i++) { + for (int i=mOpModeWatchers.size()-1; i>=0; i--) { ArrayList<Callback> cbs = mOpModeWatchers.valueAt(i); cbs.remove(cb); if (cbs.size() <= 0) { mOpModeWatchers.removeAt(i); } } - if (mPackageModeWatchers.size() > 0) { - Iterator<ArrayList<Callback>> it = mPackageModeWatchers.values().iterator(); - while (it.hasNext()) { - ArrayList<Callback> cbs = it.next(); - cbs.remove(cb); - if (cbs.size() <= 0) { - it.remove(); - } + for (int i=mPackageModeWatchers.size()-1; i>=0; i--) { + ArrayList<Callback> cbs = mPackageModeWatchers.valueAt(i); + cbs.remove(cb); + if (cbs.size() <= 0) { + mPackageModeWatchers.removeAt(i); } } } @@ -402,6 +445,18 @@ public class AppOpsService extends IAppOpsService.Stub { } @Override + public IBinder getToken(IBinder clientToken) { + synchronized (this) { + ClientState cs = mClients.get(clientToken); + if (cs == null) { + cs = new ClientState(clientToken); + mClients.put(clientToken, cs); + } + return cs; + } + } + + @Override public int checkOperation(int code, int uid, String packageName) { verifyIncomingUid(uid); verifyIncomingOp(code); @@ -448,9 +503,10 @@ public class AppOpsService extends IAppOpsService.Stub { } @Override - public int startOperation(int code, int uid, String packageName) { + public int startOperation(IBinder token, int code, int uid, String packageName) { verifyIncomingUid(uid); verifyIncomingOp(code); + ClientState client = (ClientState)token; synchronized (this) { Ops ops = getOpsLocked(uid, packageName, true); if (ops == null) { @@ -475,32 +531,46 @@ public class AppOpsService extends IAppOpsService.Stub { op.duration = -1; } op.nesting++; + if (client.mStartedOps != null) { + client.mStartedOps.add(op); + } return AppOpsManager.MODE_ALLOWED; } } @Override - public void finishOperation(int code, int uid, String packageName) { + public void finishOperation(IBinder token, int code, int uid, String packageName) { verifyIncomingUid(uid); verifyIncomingOp(code); + ClientState client = (ClientState)token; synchronized (this) { Op op = getOpLocked(code, uid, packageName, true); if (op == null) { return; } - if (op.nesting <= 1) { - if (op.nesting == 1) { - op.duration = (int)(System.currentTimeMillis() - op.time); - op.time += op.duration; - } else { - Slog.w(TAG, "Finishing op nesting under-run: uid " + uid + " pkg " + packageName - + " code " + code + " time=" + op.time + " duration=" + op.duration - + " nesting=" + op.nesting); + if (client.mStartedOps != null) { + if (!client.mStartedOps.remove(op)) { + throw new IllegalStateException("Operation not started: uid" + op.uid + + " pkg=" + op.packageName + " op=" + op.op); } - op.nesting = 0; + } + finishOperationLocked(op); + } + } + + void finishOperationLocked(Op op) { + if (op.nesting <= 1) { + if (op.nesting == 1) { + op.duration = (int)(System.currentTimeMillis() - op.time); + op.time += op.duration; } else { - op.nesting--; + Slog.w(TAG, "Finishing op nesting under-run: uid " + op.uid + " pkg " + + op.packageName + " code " + op.op + " time=" + op.time + + " duration=" + op.duration + " nesting=" + op.nesting); } + op.nesting = 0; + } else { + op.nesting--; } } @@ -601,7 +671,7 @@ public class AppOpsService extends IAppOpsService.Stub { if (!edit) { return null; } - op = new Op(code); + op = new Op(ops.uid, ops.packageName, code); ops.put(code, op); } if (edit) { @@ -711,7 +781,7 @@ public class AppOpsService extends IAppOpsService.Stub { String tagName = parser.getName(); if (tagName.equals("op")) { - Op op = new Op(Integer.parseInt(parser.getAttributeValue(null, "n"))); + Op op = new Op(uid, pkgName, Integer.parseInt(parser.getAttributeValue(null, "n"))); String mode = parser.getAttributeValue(null, "m"); if (mode != null) { op.mode = Integer.parseInt(mode); @@ -831,6 +901,62 @@ public class AppOpsService extends IAppOpsService.Stub { synchronized (this) { pw.println("Current AppOps Service state:"); final long now = System.currentTimeMillis(); + boolean needSep = false; + if (mOpModeWatchers.size() > 0) { + needSep = true; + pw.println(" Op mode watchers:"); + for (int i=0; i<mOpModeWatchers.size(); i++) { + pw.print(" Op "); pw.print(AppOpsManager.opToName(mOpModeWatchers.keyAt(i))); + pw.println(":"); + ArrayList<Callback> callbacks = mOpModeWatchers.valueAt(i); + for (int j=0; j<callbacks.size(); j++) { + pw.print(" #"); pw.print(j); pw.print(": "); + pw.println(callbacks.get(j)); + } + } + } + if (mPackageModeWatchers.size() > 0) { + needSep = true; + pw.println(" Package mode watchers:"); + for (int i=0; i<mPackageModeWatchers.size(); i++) { + pw.print(" Pkg "); pw.print(mPackageModeWatchers.keyAt(i)); + pw.println(":"); + ArrayList<Callback> callbacks = mPackageModeWatchers.valueAt(i); + for (int j=0; j<callbacks.size(); j++) { + pw.print(" #"); pw.print(j); pw.print(": "); + pw.println(callbacks.get(j)); + } + } + } + if (mModeWatchers.size() > 0) { + needSep = true; + pw.println(" All mode watchers:"); + for (int i=0; i<mModeWatchers.size(); i++) { + pw.print(" "); pw.print(mModeWatchers.keyAt(i)); + pw.print(" -> "); pw.println(mModeWatchers.valueAt(i)); + } + } + if (mClients.size() > 0) { + needSep = true; + pw.println(" Clients:"); + for (int i=0; i<mClients.size(); i++) { + pw.print(" "); pw.print(mClients.keyAt(i)); pw.println(":"); + ClientState cs = mClients.valueAt(i); + pw.print(" "); pw.println(cs); + if (cs.mStartedOps != null && cs.mStartedOps.size() > 0) { + pw.println(" Started ops:"); + for (int j=0; j<cs.mStartedOps.size(); j++) { + Op op = cs.mStartedOps.get(j); + pw.print(" "); pw.print("uid="); pw.print(op.uid); + pw.print(" pkg="); pw.print(op.packageName); + pw.print(" op="); pw.println(AppOpsManager.opToName(op.op)); + } + } + } + } + if (needSep) { + pw.println(); + } for (int i=0; i<mUidOps.size(); i++) { pw.print(" Uid "); UserHandle.formatUid(pw, mUidOps.keyAt(i)); pw.println(":"); HashMap<String, Ops> pkgOps = mUidOps.valueAt(i); diff --git a/services/java/com/android/server/AppWidgetService.java b/services/java/com/android/server/AppWidgetService.java index 5b76f39..203cca6 100644 --- a/services/java/com/android/server/AppWidgetService.java +++ b/services/java/com/android/server/AppWidgetService.java @@ -70,7 +70,7 @@ class AppWidgetService extends IAppWidgetService.Stub mAppWidgetServices.append(0, primary); } - public void systemReady(boolean safeMode) { + public void systemRunning(boolean safeMode) { mSafeMode = safeMode; mAppWidgetServices.get(0).systemReady(safeMode); diff --git a/services/java/com/android/server/AssetAtlasService.java b/services/java/com/android/server/AssetAtlasService.java index 33f082c..26b4652 100644 --- a/services/java/com/android/server/AssetAtlasService.java +++ b/services/java/com/android/server/AssetAtlasService.java @@ -186,7 +186,7 @@ public class AssetAtlasService extends IAssetAtlas.Stub { * Callback invoked by the server thread to indicate we can now run * 3rd party code. */ - public void systemReady() { + public void systemRunning() { } /** diff --git a/services/java/com/android/server/CommonTimeManagementService.java b/services/java/com/android/server/CommonTimeManagementService.java index c316733..aa2c8b8 100644 --- a/services/java/com/android/server/CommonTimeManagementService.java +++ b/services/java/com/android/server/CommonTimeManagementService.java @@ -153,7 +153,7 @@ class CommonTimeManagementService extends Binder { mContext = context; } - void systemReady() { + void systemRunning() { if (ServiceManager.checkService(CommonTimeConfig.SERVICE_NAME) == null) { Log.i(TAG, "No common time service detected on this platform. " + "Common time services will be unavailable."); diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 3a4b7e3..f66fa23 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -42,6 +42,7 @@ import android.content.ContextWrapper; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager; +import android.content.res.Configuration; import android.content.res.Resources; import android.database.ContentObserver; import android.net.CaptivePortalTracker; @@ -96,8 +97,9 @@ import android.security.KeyStore; import android.telephony.TelephonyManager; import android.text.TextUtils; import android.util.Slog; -import android.util.SparseIntArray; import android.util.SparseArray; +import android.util.SparseIntArray; +import android.util.Xml; import com.android.internal.R; import com.android.internal.net.LegacyVpnInfo; @@ -107,6 +109,7 @@ import com.android.internal.telephony.DctConstants; import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneConstants; import com.android.internal.util.IndentingPrintWriter; +import com.android.internal.util.XmlUtils; import com.android.server.am.BatteryStatsService; import com.android.server.connectivity.DataConnectionStats; import com.android.server.connectivity.Nat464Xlat; @@ -121,7 +124,13 @@ import com.android.internal.annotations.GuardedBy; import dalvik.system.DexClassLoader; +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +import java.io.File; import java.io.FileDescriptor; +import java.io.FileNotFoundException; +import java.io.FileReader; import java.io.IOException; import java.io.PrintWriter; import java.lang.reflect.Constructor; @@ -170,7 +179,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { private static final int MAX_HOSTROUTE_CYCLE_COUNT = 10; private Tethering mTethering; - private boolean mTetheringConfigValid = false; private KeyStore mKeyStore; @@ -381,6 +389,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { TelephonyManager mTelephonyManager; + // We only want one checkMobileProvisioning after booting. + volatile boolean mFirstProvisioningCheckStarted = false; + public ConnectivityService(Context context, INetworkManagementService netd, INetworkStatsService statsService, INetworkPolicyManager policyManager) { // Currently, omitting a NetworkFactory will create one internally @@ -583,12 +594,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { } mTethering = new Tethering(mContext, mNetd, statsService, this, mHandler.getLooper()); - mTetheringConfigValid = ((mTethering.getTetherableUsbRegexs().length != 0 || - mTethering.getTetherableWifiRegexs().length != 0 || - mTethering.getTetherableBluetoothRegexs().length != 0) && - mTethering.getUpstreamIfaceTypes().length != 0); - //set up the listener for user state for creating user VPNs + //set up the listener for user state for creating user VPNs IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(Intent.ACTION_USER_STARTING); intentFilter.addAction(Intent.ACTION_USER_STOPPING); @@ -2755,6 +2762,17 @@ public class ConnectivityService extends IConnectivityManager.Stub { state + "/" + info.getDetailedState()); } + // After booting we'll check once for mobile provisioning + // if we've provisioned by and connected. + if (!mFirstProvisioningCheckStarted + && (0 != Settings.Global.getInt(mContext.getContentResolver(), + Settings.Global.DEVICE_PROVISIONED, 0)) + && (state == NetworkInfo.State.CONNECTED)) { + log("check provisioning after booting"); + mFirstProvisioningCheckStarted = true; + checkMobileProvisioning(true, CheckMp.MAX_TIMEOUT_MS, null); + } + EventLogTags.writeConnectivityStateChanged( info.getType(), info.getSubtype(), info.getDetailedState().ordinal()); @@ -3004,7 +3022,10 @@ public class ConnectivityService extends IConnectivityManager.Stub { int defaultVal = (SystemProperties.get("ro.tether.denied").equals("true") ? 0 : 1); boolean tetherEnabledInSettings = (Settings.Global.getInt(mContext.getContentResolver(), Settings.Global.TETHER_SUPPORTED, defaultVal) != 0); - return tetherEnabledInSettings && mTetheringConfigValid; + return tetherEnabledInSettings && ((mTethering.getTetherableUsbRegexs().length != 0 || + mTethering.getTetherableWifiRegexs().length != 0 || + mTethering.getTetherableBluetoothRegexs().length != 0) && + mTethering.getUpstreamIfaceTypes().length != 0); } // An API NetworkStateTrackers can call when they lose their network. @@ -3684,13 +3705,15 @@ public class ConnectivityService extends IConnectivityManager.Stub { } @Override - public int checkMobileProvisioning(boolean sendNotification, int suggestedTimeOutMs, + public int checkMobileProvisioning(final boolean sendNotification, int suggestedTimeOutMs, final ResultReceiver resultReceiver) { log("checkMobileProvisioning: E sendNotification=" + sendNotification + " suggestedTimeOutMs=" + suggestedTimeOutMs + " resultReceiver=" + resultReceiver); enforceChangePermission(); + mFirstProvisioningCheckStarted = true; + int timeOutMs = suggestedTimeOutMs; if (suggestedTimeOutMs > CheckMp.MAX_TIMEOUT_MS) { timeOutMs = CheckMp.MAX_TIMEOUT_MS; @@ -3717,6 +3740,10 @@ public class ConnectivityService extends IConnectivityManager.Stub { log("CheckMp.onComplete: send result"); resultReceiver.send(result, null); } + if (!sendNotification) { + log("CheckMp.onComplete: done, not sending notification"); + return; + } NetworkInfo ni = mNetTrackers[ConnectivityManager.TYPE_MOBILE_HIPRI].getNetworkInfo(); switch(result) { @@ -3727,10 +3754,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { } case ConnectivityManager.CMP_RESULT_CODE_REDIRECTED: { log("CheckMp.onComplete: warm sim"); - String url = getProvisioningUrl(); + String url = getMobileProvisioningUrl(); if (TextUtils.isEmpty(url)) { - url = mContext.getResources() - .getString(R.string.mobile_redirected_provisioning_url); + url = getMobileRedirectedProvisioningUrl(); } if (TextUtils.isEmpty(url) == false) { log("CheckMp.onComplete: warm sim (redirected), url=" + url); @@ -3742,7 +3768,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { } case ConnectivityManager.CMP_RESULT_CODE_NO_DNS: case ConnectivityManager.CMP_RESULT_CODE_NO_TCP_CONNECTION: { - String url = getProvisioningUrl(); + String url = getMobileProvisioningUrl(); if (TextUtils.isEmpty(url) == false) { log("CheckMp.onComplete: warm sim (no dns/tcp), url=" + url); setNotificationVisible(true, ni, url); @@ -4116,10 +4142,114 @@ public class ConnectivityService extends IConnectivityManager.Stub { log("setNotificationVisible: X visible=" + visible + " ni=" + networkInfo + " url=" + url); } - private String getProvisioningUrl() { - String url = mContext.getResources().getString(R.string.mobile_provisioning_url); - log("getProvisioningUrl: mobile_provisioning_url=" + url); + /** Location to an updatable file listing carrier provisioning urls. + * An example: + * + * <?xml version="1.0" encoding="utf-8"?> + * <provisioningUrls> + * <provisioningUrl mcc="310" mnc="4">http://myserver.com/foo?mdn=%3$s&iccid=%1$s&imei=%2$s</provisioningUrl> + * <redirectedUrl mcc="310" mnc="4">http://www.google.com</redirectedUrl> + * </provisioningUrls> + */ + private static final String PROVISIONING_URL_PATH = + "/data/misc/radio/provisioning_urls.xml"; + private final File mProvisioningUrlFile = new File(PROVISIONING_URL_PATH); + + /** XML tag for root element. */ + private static final String TAG_PROVISIONING_URLS = "provisioningUrls"; + /** XML tag for individual url */ + private static final String TAG_PROVISIONING_URL = "provisioningUrl"; + /** XML tag for redirected url */ + private static final String TAG_REDIRECTED_URL = "redirectedUrl"; + /** XML attribute for mcc */ + private static final String ATTR_MCC = "mcc"; + /** XML attribute for mnc */ + private static final String ATTR_MNC = "mnc"; + + private static final int REDIRECTED_PROVISIONING = 1; + private static final int PROVISIONING = 2; + + private String getProvisioningUrlBaseFromFile(int type) { + FileReader fileReader = null; + XmlPullParser parser = null; + Configuration config = mContext.getResources().getConfiguration(); + String tagType; + + switch (type) { + case PROVISIONING: + tagType = TAG_PROVISIONING_URL; + break; + case REDIRECTED_PROVISIONING: + tagType = TAG_REDIRECTED_URL; + break; + default: + throw new RuntimeException("getProvisioningUrlBaseFromFile: Unexpected parameter " + + type); + } + + try { + fileReader = new FileReader(mProvisioningUrlFile); + parser = Xml.newPullParser(); + parser.setInput(fileReader); + XmlUtils.beginDocument(parser, TAG_PROVISIONING_URLS); + while (true) { + XmlUtils.nextElement(parser); + + String element = parser.getName(); + if (element == null) break; + + if (element.equals(tagType)) { + String mcc = parser.getAttributeValue(null, ATTR_MCC); + try { + if (mcc != null && Integer.parseInt(mcc) == config.mcc) { + String mnc = parser.getAttributeValue(null, ATTR_MNC); + if (mnc != null && Integer.parseInt(mnc) == config.mnc) { + parser.next(); + if (parser.getEventType() == XmlPullParser.TEXT) { + return parser.getText(); + } + } + } + } catch (NumberFormatException e) { + loge("NumberFormatException in getProvisioningUrlBaseFromFile: " + e); + } + } + } + return null; + } catch (FileNotFoundException e) { + loge("Carrier Provisioning Urls file not found"); + } catch (XmlPullParserException e) { + loge("Xml parser exception reading Carrier Provisioning Urls file: " + e); + } catch (IOException e) { + loge("I/O exception reading Carrier Provisioning Urls file: " + e); + } finally { + if (fileReader != null) { + try { + fileReader.close(); + } catch (IOException e) {} + } + } + return null; + } + + private String getMobileRedirectedProvisioningUrl() { + String url = getProvisioningUrlBaseFromFile(REDIRECTED_PROVISIONING); + if (TextUtils.isEmpty(url)) { + url = mContext.getResources().getString(R.string.mobile_redirected_provisioning_url); + } + return url; + } + + public String getMobileProvisioningUrl() { + enforceConnectivityInternalPermission(); + String url = getProvisioningUrlBaseFromFile(PROVISIONING); + if (TextUtils.isEmpty(url)) { + url = mContext.getResources().getString(R.string.mobile_provisioning_url); + log("getProvisioningUrl: mobile_provisioining_url from resource =" + url); + } else { + log("getProvisioningUrl: mobile_provisioning_url from File =" + url); + } // populate the iccid, imei and phone number in the provisioning url. if (!TextUtils.isEmpty(url)) { String phoneNumber = mTelephonyManager.getLine1Number(); diff --git a/services/java/com/android/server/CountryDetectorService.java b/services/java/com/android/server/CountryDetectorService.java index 8407fa4..4956dd5 100644 --- a/services/java/com/android/server/CountryDetectorService.java +++ b/services/java/com/android/server/CountryDetectorService.java @@ -166,7 +166,7 @@ public class CountryDetectorService extends ICountryDetector.Stub implements Run } } - void systemReady() { + void systemRunning() { // Shall we wait for the initialization finish. BackgroundThread.getHandler().post(this); } diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java index 1c1b002..35656f8 100644 --- a/services/java/com/android/server/InputMethodManagerService.java +++ b/services/java/com/android/server/InputMethodManagerService.java @@ -823,7 +823,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } } - public void systemReady(StatusBarManagerService statusBar) { + public void systemRunning(StatusBarManagerService statusBar) { synchronized (mMethodMap) { if (DEBUG) { Slog.d(TAG, "--- systemReady"); @@ -1210,7 +1210,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub mCurIntent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivity( mContext, 0, new Intent(Settings.ACTION_INPUT_METHOD_SETTINGS), 0)); if (bindCurrentInputMethodService(mCurIntent, this, Context.BIND_AUTO_CREATE - | Context.BIND_NOT_VISIBLE)) { + | Context.BIND_NOT_VISIBLE | Context.BIND_SHOWING_UI)) { mLastBindTime = SystemClock.uptimeMillis(); mHaveConnection = true; mCurId = info.getId(); diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java index c6c9845..bde9e1c 100644 --- a/services/java/com/android/server/LocationManagerService.java +++ b/services/java/com/android/server/LocationManagerService.java @@ -198,7 +198,7 @@ public class LocationManagerService extends ILocationManager.Stub { // most startup is deferred until systemReady() } - public void systemReady() { + public void systemRunning() { synchronized (mLock) { if (D) Log.d(TAG, "systemReady()"); diff --git a/services/java/com/android/server/NetworkTimeUpdateService.java b/services/java/com/android/server/NetworkTimeUpdateService.java index 02b42b8..cbddf67 100644 --- a/services/java/com/android/server/NetworkTimeUpdateService.java +++ b/services/java/com/android/server/NetworkTimeUpdateService.java @@ -108,7 +108,7 @@ public class NetworkTimeUpdateService { } /** Initialize the receivers and initiate the first NTP request */ - public void systemReady() { + public void systemRunning() { registerForTelephonyIntents(); registerForAlarms(); registerForConnectivityIntents(); diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 888064c..0bbdcfb 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -351,6 +351,7 @@ class ServerThread { LockSettingsService lockSettings = null; DreamManagerService dreamy = null; AssetAtlasService atlas = null; + PrintManagerService printManager = null; // Bring up services needed for UI. if (factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) { @@ -793,8 +794,8 @@ class ServerThread { try { Slog.i(TAG, "Print Service"); - ServiceManager.addService(Context.PRINT_SERVICE, - new PrintManagerService(context)); + printManager = new PrintManagerService(context); + ServiceManager.addService(Context.PRINT_SERVICE, printManager); } catch (Throwable e) { reportWtf("starting Print Service", e); } @@ -909,6 +910,7 @@ class ServerThread { final AssetAtlasService atlasF = atlas; final InputManagerService inputManagerF = inputManager; final TelephonyRegistry telephonyRegistryF = telephonyRegistry; + final PrintManagerService printManagerF = printManager; // We now tell the activity manager it is okay to run third party // code. It will call back into us once it has gotten to the state @@ -988,66 +990,73 @@ class ServerThread { // third party code... try { - if (appWidgetF != null) appWidgetF.systemReady(safeMode); + if (appWidgetF != null) appWidgetF.systemRunning(safeMode); } catch (Throwable e) { - reportWtf("making App Widget Service ready", e); + reportWtf("Notifying AppWidgetService running", e); } try { - if (wallpaperF != null) wallpaperF.systemReady(); + if (wallpaperF != null) wallpaperF.systemRunning(); } catch (Throwable e) { - reportWtf("making Wallpaper Service ready", e); + reportWtf("Notifying WallpaperService running", e); } try { - if (immF != null) immF.systemReady(statusBarF); + if (immF != null) immF.systemRunning(statusBarF); } catch (Throwable e) { - reportWtf("making Input Method Service ready", e); + reportWtf("Notifying InputMethodService running", e); } try { - if (locationF != null) locationF.systemReady(); + if (locationF != null) locationF.systemRunning(); } catch (Throwable e) { - reportWtf("making Location Service ready", e); + reportWtf("Notifying Location Service running", e); } try { - if (countryDetectorF != null) countryDetectorF.systemReady(); + if (countryDetectorF != null) countryDetectorF.systemRunning(); } catch (Throwable e) { - reportWtf("making Country Detector Service ready", e); + reportWtf("Notifying CountryDetectorService running", e); } try { - if (networkTimeUpdaterF != null) networkTimeUpdaterF.systemReady(); + if (networkTimeUpdaterF != null) networkTimeUpdaterF.systemRunning(); } catch (Throwable e) { - reportWtf("making Network Time Service ready", e); + reportWtf("Notifying NetworkTimeService running", e); } try { - if (commonTimeMgmtServiceF != null) commonTimeMgmtServiceF.systemReady(); + if (commonTimeMgmtServiceF != null) commonTimeMgmtServiceF.systemRunning(); } catch (Throwable e) { - reportWtf("making Common time management service ready", e); + reportWtf("Notifying CommonTimeManagementService running", e); } try { - if (textServiceManagerServiceF != null) textServiceManagerServiceF.systemReady(); + if (textServiceManagerServiceF != null) + textServiceManagerServiceF.systemRunning(); } catch (Throwable e) { - reportWtf("making Text Services Manager Service ready", e); + reportWtf("Notifying TextServicesManagerService running", e); } try { - if (dreamyF != null) dreamyF.systemReady(); + if (dreamyF != null) dreamyF.systemRunning(); } catch (Throwable e) { - reportWtf("making DreamManagerService ready", e); + reportWtf("Notifying DreamManagerService running", e); } try { - if (atlasF != null) atlasF.systemReady(); + if (atlasF != null) atlasF.systemRunning(); } catch (Throwable e) { - reportWtf("making AssetAtlasService ready", e); + reportWtf("Notifying AssetAtlasService running", e); } try { // TODO(BT) Pass parameter to input manager - if (inputManagerF != null) inputManagerF.systemReady(); + if (inputManagerF != null) inputManagerF.systemRunning(); } catch (Throwable e) { - reportWtf("making InputManagerService ready", e); + reportWtf("Notifying InputManagerService running", e); } try { - if (telephonyRegistryF != null) telephonyRegistryF.systemReady(); + if (telephonyRegistryF != null) telephonyRegistryF.systemRunning(); } catch (Throwable e) { - reportWtf("making TelephonyRegistry ready", e); + reportWtf("Notifying TelephonyRegistry running", e); + } + + try { + if (printManagerF != null) printManagerF.systemRuning(); + } catch (Throwable e) { + reportWtf("Notifying PrintManagerService running", e); } } }); diff --git a/services/java/com/android/server/TelephonyRegistry.java b/services/java/com/android/server/TelephonyRegistry.java index 17260d5..699d79e 100644 --- a/services/java/com/android/server/TelephonyRegistry.java +++ b/services/java/com/android/server/TelephonyRegistry.java @@ -178,7 +178,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { mConnectedApns = new ArrayList<String>(); } - public void systemReady() { + public void systemRunning() { // Watch for interesting updates final IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_USER_SWITCHED); diff --git a/services/java/com/android/server/TextServicesManagerService.java b/services/java/com/android/server/TextServicesManagerService.java index 7dd9988..6587c41 100644 --- a/services/java/com/android/server/TextServicesManagerService.java +++ b/services/java/com/android/server/TextServicesManagerService.java @@ -76,7 +76,7 @@ public class TextServicesManagerService extends ITextServicesManager.Stub { new HashMap<String, SpellCheckerBindGroup>(); private final TextServicesSettings mSettings; - public void systemReady() { + public void systemRunning() { if (!mSystemReady) { mSystemReady = true; } diff --git a/services/java/com/android/server/TwilightService.java b/services/java/com/android/server/TwilightService.java index 154de1c..0356faa 100644 --- a/services/java/com/android/server/TwilightService.java +++ b/services/java/com/android/server/TwilightService.java @@ -520,7 +520,7 @@ public final class TwilightService { Intent updateIntent = new Intent(ACTION_UPDATE_TWILIGHT_STATE); PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, 0, updateIntent, 0); mAlarmManager.cancel(pendingIntent); - mAlarmManager.set(AlarmManager.RTC_WAKEUP, nextUpdate, pendingIntent); + mAlarmManager.setExact(AlarmManager.RTC, nextUpdate, pendingIntent); } }; diff --git a/services/java/com/android/server/VibratorService.java b/services/java/com/android/server/VibratorService.java index 9b5f8f6..28eb948 100644 --- a/services/java/com/android/server/VibratorService.java +++ b/services/java/com/android/server/VibratorService.java @@ -342,7 +342,8 @@ public class VibratorService extends IVibratorService.Stub // Lock held on mVibrations private void startVibrationLocked(final Vibration vib) { try { - int mode = mAppOpsService.startOperation(AppOpsManager.OP_VIBRATE, vib.mUid, vib.mPackageName); + int mode = mAppOpsService.startOperation(AppOpsManager.getToken(mAppOpsService), + AppOpsManager.OP_VIBRATE, vib.mUid, vib.mPackageName); if (mode != AppOpsManager.MODE_ALLOWED) { if (mode == AppOpsManager.MODE_ERRORED) { Slog.w(TAG, "Would be an error: vibrate from uid " + vib.mUid); @@ -366,7 +367,8 @@ public class VibratorService extends IVibratorService.Stub private void reportFinishVibrationLocked() { if (mCurrentVibration != null) { try { - mAppOpsService.finishOperation(AppOpsManager.OP_VIBRATE, mCurrentVibration.mUid, + mAppOpsService.finishOperation(AppOpsManager.getToken(mAppOpsService), + AppOpsManager.OP_VIBRATE, mCurrentVibration.mUid, mCurrentVibration.mPackageName); } catch (RemoteException e) { } diff --git a/services/java/com/android/server/WallpaperManagerService.java b/services/java/com/android/server/WallpaperManagerService.java index 6823f13..d677f24 100644 --- a/services/java/com/android/server/WallpaperManagerService.java +++ b/services/java/com/android/server/WallpaperManagerService.java @@ -449,7 +449,7 @@ class WallpaperManagerService extends IWallpaperManager.Stub { } } - public void systemReady() { + public void systemRunning() { if (DEBUG) Slog.v(TAG, "systemReady"); WallpaperData wallpaper = mWallpaperMap.get(UserHandle.USER_OWNER); switchWallpaper(wallpaper, null); @@ -885,7 +885,8 @@ class WallpaperManagerService extends IWallpaperManager.Stub { Intent.createChooser(new Intent(Intent.ACTION_SET_WALLPAPER), mContext.getText(com.android.internal.R.string.chooser_wallpaper)), 0, null, new UserHandle(serviceUserId))); - if (!mContext.bindServiceAsUser(intent, newConn, Context.BIND_AUTO_CREATE, + if (!mContext.bindServiceAsUser(intent, newConn, + Context.BIND_AUTO_CREATE | Context.BIND_SHOWING_UI, new UserHandle(serviceUserId))) { String msg = "Unable to bind service: " + componentName; diff --git a/services/java/com/android/server/am/ActiveServices.java b/services/java/com/android/server/am/ActiveServices.java index 5d72102..795e142 100644 --- a/services/java/com/android/server/am/ActiveServices.java +++ b/services/java/com/android/server/am/ActiveServices.java @@ -421,7 +421,8 @@ public final class ActiveServices { private void updateServiceForegroundLocked(ProcessRecord proc, boolean oomAdj) { boolean anyForeground = false; - for (ServiceRecord sr : proc.services) { + for (int i=proc.services.size()-1; i>=0; i--) { + ServiceRecord sr = proc.services.valueAt(i); if (sr.isForeground) { anyForeground = true; break; @@ -1670,78 +1671,72 @@ public final class ActiveServices { } // Clean up any connections this application has to other services. - if (app.connections.size() > 0) { - Iterator<ConnectionRecord> it = app.connections.iterator(); - while (it.hasNext()) { - ConnectionRecord r = it.next(); - removeConnectionLocked(r, app, null); - } + for (int i=app.connections.size()-1; i>=0; i--) { + ConnectionRecord r = app.connections.valueAt(i); + removeConnectionLocked(r, app, null); } app.connections.clear(); - if (app.services.size() != 0) { + for (int i=app.services.size()-1; i>=0; i--) { // Any services running in the application need to be placed // back in the pending list. - Iterator<ServiceRecord> it = app.services.iterator(); - while (it.hasNext()) { - ServiceRecord sr = it.next(); - synchronized (sr.stats.getBatteryStats()) { - sr.stats.stopLaunchedLocked(); - } - sr.app = null; - sr.isolatedProc = null; - sr.executeNesting = 0; - if (sr.tracker != null) { - sr.tracker.setExecuting(false, mAm.mProcessTracker.getMemFactorLocked(), - SystemClock.uptimeMillis()); - } - if (mStoppingServices.remove(sr)) { - if (DEBUG_SERVICE) Slog.v(TAG, "killServices remove stopping " + 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 - + ": shouldUnbind=" + b.hasBound); - b.binder = null; - b.requested = b.received = b.hasBound = false; - } - - if (sr.crashCount >= 2 && (sr.serviceInfo.applicationInfo.flags - &ApplicationInfo.FLAG_PERSISTENT) == 0) { - Slog.w(TAG, "Service crashed " + sr.crashCount - + " times, stopping: " + sr); - EventLog.writeEvent(EventLogTags.AM_SERVICE_CRASHED_TOO_MUCH, - sr.userId, sr.crashCount, sr.shortName, app.pid); - bringDownServiceLocked(sr); - } else if (!allowRestart) { - bringDownServiceLocked(sr); - } else { - boolean canceled = scheduleServiceRestartLocked(sr, true); - - // Should the service remain running? Note that in the - // extreme case of so many attempts to deliver a command - // that it failed we also will stop it here. - if (sr.startRequested && (sr.stopIfKilled || canceled)) { - if (sr.pendingStarts.size() == 0) { - sr.startRequested = false; - if (sr.tracker != null) { - sr.tracker.setStarted(false, mAm.mProcessTracker.getMemFactorLocked(), - SystemClock.uptimeMillis()); - } - if (!sr.hasAutoCreateConnections()) { - // Whoops, no reason to restart! - bringDownServiceLocked(sr); - } + ServiceRecord sr = app.services.valueAt(i); + synchronized (sr.stats.getBatteryStats()) { + sr.stats.stopLaunchedLocked(); + } + sr.app = null; + sr.isolatedProc = null; + sr.executeNesting = 0; + if (sr.tracker != null) { + sr.tracker.setExecuting(false, mAm.mProcessTracker.getMemFactorLocked(), + SystemClock.uptimeMillis()); + } + if (mStoppingServices.remove(sr)) { + if (DEBUG_SERVICE) Slog.v(TAG, "killServices remove stopping " + 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 + + ": shouldUnbind=" + b.hasBound); + b.binder = null; + b.requested = b.received = b.hasBound = false; + } + + if (sr.crashCount >= 2 && (sr.serviceInfo.applicationInfo.flags + &ApplicationInfo.FLAG_PERSISTENT) == 0) { + Slog.w(TAG, "Service crashed " + sr.crashCount + + " times, stopping: " + sr); + EventLog.writeEvent(EventLogTags.AM_SERVICE_CRASHED_TOO_MUCH, + sr.userId, sr.crashCount, sr.shortName, app.pid); + bringDownServiceLocked(sr); + } else if (!allowRestart) { + bringDownServiceLocked(sr); + } else { + boolean canceled = scheduleServiceRestartLocked(sr, true); + + // Should the service remain running? Note that in the + // extreme case of so many attempts to deliver a command + // that it failed we also will stop it here. + if (sr.startRequested && (sr.stopIfKilled || canceled)) { + if (sr.pendingStarts.size() == 0) { + sr.startRequested = false; + if (sr.tracker != null) { + sr.tracker.setStarted(false, mAm.mProcessTracker.getMemFactorLocked(), + SystemClock.uptimeMillis()); + } + if (!sr.hasAutoCreateConnections()) { + // Whoops, no reason to restart! + bringDownServiceLocked(sr); } } } } + } - if (!allowRestart) { - app.services.clear(); - } + if (!allowRestart) { + app.services.clear(); } // Make sure we have no more records on the stopping list. @@ -1880,11 +1875,10 @@ public final class ActiveServices { return; } long maxTime = SystemClock.uptimeMillis() - SERVICE_TIMEOUT; - Iterator<ServiceRecord> it = proc.executingServices.iterator(); ServiceRecord timeout = null; long nextTime = 0; - while (it.hasNext()) { - ServiceRecord sr = it.next(); + for (int i=proc.executingServices.size()-1; i>=0; i--) { + ServiceRecord sr = proc.executingServices.valueAt(i); if (sr.executingStart < maxTime) { timeout = sr; break; diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index c41c23e..ef84254 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -30,6 +30,7 @@ import android.util.ArrayMap; import com.android.internal.R; import com.android.internal.annotations.GuardedBy; import com.android.internal.app.IAppOpsService; +import com.android.internal.app.ResolverActivity; import com.android.internal.os.BackgroundThread; import com.android.internal.os.BatteryStatsImpl; import com.android.internal.os.ProcessStats; @@ -479,38 +480,31 @@ public final class ActivityManagerService extends ActivityManagerNative int pid; IBinder token; } - final SparseArray<ForegroundToken> mForegroundProcesses - = new SparseArray<ForegroundToken>(); + final SparseArray<ForegroundToken> mForegroundProcesses = new SparseArray<ForegroundToken>(); /** * List of records for processes that someone had tried to start before the * system was ready. We don't start them at that point, but ensure they * are started by the time booting is complete. */ - final ArrayList<ProcessRecord> mProcessesOnHold - = new ArrayList<ProcessRecord>(); + final ArrayList<ProcessRecord> mProcessesOnHold = new ArrayList<ProcessRecord>(); /** * List of persistent applications that are in the process * of being started. */ - final ArrayList<ProcessRecord> mPersistentStartingProcesses - = new ArrayList<ProcessRecord>(); + final ArrayList<ProcessRecord> mPersistentStartingProcesses = new ArrayList<ProcessRecord>(); /** * Processes that are being forcibly torn down. */ - final ArrayList<ProcessRecord> mRemovedProcesses - = new ArrayList<ProcessRecord>(); + final ArrayList<ProcessRecord> mRemovedProcesses = new ArrayList<ProcessRecord>(); /** * List of running applications, sorted by recent usage. * The first entry in the list is the least recently used. - * It contains ApplicationRecord objects. This list does NOT include - * any persistent application records (since we never want to exit them). */ - final ArrayList<ProcessRecord> mLruProcesses - = new ArrayList<ProcessRecord>(); + final ArrayList<ProcessRecord> mLruProcesses = new ArrayList<ProcessRecord>(); /** * List of processes that should gc as soon as things are idle. @@ -1505,6 +1499,7 @@ public final class ActivityManagerService extends ActivityManagerNative case COLLECT_PSS_BG_MSG: { int i=0; long start = SystemClock.uptimeMillis(); + long[] tmp = new long[1]; do { ProcessRecord proc; int oomAdj; @@ -1528,10 +1523,10 @@ public final class ActivityManagerService extends ActivityManagerNative i++; } if (proc != null) { - long pss = Debug.getPss(pid); + long pss = Debug.getPss(pid, tmp); synchronized (ActivityManagerService.this) { if (proc.thread != null && proc.setAdj == oomAdj && proc.pid == pid) { - proc.baseProcessTracker.addPss(pss, true); + proc.baseProcessTracker.addPss(pss, tmp[0], true); } } } @@ -2055,7 +2050,7 @@ public final class ActivityManagerService extends ActivityManagerNative final void setFocusedActivityLocked(ActivityRecord r) { if (mFocusedActivity != r) { - if (DEBUG_FOCUS) Slog.d(TAG, "setFocusedActivitiyLocked: r=" + r); + if (DEBUG_FOCUS) Slog.d(TAG, "setFocusedActivityLocked: r=" + r); mFocusedActivity = r; mStackSupervisor.setFocusedStack(r); if (r != null) { @@ -2157,13 +2152,12 @@ public final class ActivityManagerService extends ActivityManagerNative // If the app is currently using a content provider or service, // bump those processes as well. - if (app.connections.size() > 0) { - for (ConnectionRecord cr : app.connections) { - if (cr.binding != null && cr.binding.service != null - && cr.binding.service.app != null - && cr.binding.service.app.lruSeq != mLruSeq) { - updateLruProcessInternalLocked(cr.binding.service.app, i+1); - } + for (int j=app.connections.size()-1; j>=0; j--) { + ConnectionRecord cr = app.connections.valueAt(j); + if (cr.binding != null && cr.binding.service != null + && cr.binding.service.app != null + && cr.binding.service.app.lruSeq != mLruSeq) { + updateLruProcessInternalLocked(cr.binding.service.app, i+1); } } for (int j=app.conProviders.size()-1; j>=0; j--) { @@ -2493,6 +2487,20 @@ public final class ActivityManagerService extends ActivityManagerNative } } + String getHomePackageName() { + Intent intent = new Intent(mTopAction, mTopData != null ? Uri.parse(mTopData) : null); + intent.setComponent(mTopComponent); + intent.addCategory(Intent.CATEGORY_HOME); + ActivityInfo aInfo = resolveActivityInfo(intent, STOCK_PM_FLAGS, mCurrentUserId); + if (aInfo != null) { + final String homePackageName = aInfo.applicationInfo.packageName; + if (!ResolverActivity.class.getName().equals(homePackageName)) { + return homePackageName; + } + } + return null; + } + boolean startHomeActivityLocked(int userId) { if (mHeadless) { // Added because none of the other calls to ensureBootCompleted seem to fire @@ -4010,7 +4018,8 @@ public final class ActivityManagerService extends ActivityManagerNative synchronized (this) { if (proc.thread != null && proc.setAdj == oomAdj) { // Record this for posterity if the process has been stable. - proc.baseProcessTracker.addPss(infos[i].getTotalPss(), false); + proc.baseProcessTracker.addPss(infos[i].getTotalPss(), + infos[i].getTotalUss(), false); } } } @@ -4031,12 +4040,13 @@ public final class ActivityManagerService extends ActivityManagerNative oomAdj = proc != null ? proc.setAdj : 0; } } - pss[i] = Debug.getPss(pids[i]); + long[] tmpUss = new long[1]; + pss[i] = Debug.getPss(pids[i], tmpUss); if (proc != null) { synchronized (this) { if (proc.thread != null && proc.setAdj == oomAdj) { // Record this for posterity if the process has been stable. - proc.baseProcessTracker.addPss(pss[i], false); + proc.baseProcessTracker.addPss(pss[i], tmpUss[0], false); } } } @@ -8802,14 +8812,11 @@ public final class ActivityManagerService extends ActivityManagerNative } // Bump up the crash count of any services currently running in the proc. - if (app.services.size() != 0) { + for (int i=app.services.size()-1; i>=0; i--) { // Any services running in the application need to be placed // back in the pending list. - Iterator<ServiceRecord> it = app.services.iterator(); - while (it.hasNext()) { - ServiceRecord sr = it.next(); - sr.crashCount++; - } + ServiceRecord sr = app.services.valueAt(i); + sr.crashCount++; } // If the crashing process is what we consider to be the "home process" and it has been @@ -10269,8 +10276,8 @@ public final class ActivityManagerService extends ActivityManagerNative pw.print(" FOREGROUND_APP_ADJ: "); pw.println(ProcessList.FOREGROUND_APP_ADJ); pw.print(" VISIBLE_APP_ADJ: "); pw.println(ProcessList.VISIBLE_APP_ADJ); pw.print(" PERCEPTIBLE_APP_ADJ: "); pw.println(ProcessList.PERCEPTIBLE_APP_ADJ); - pw.print(" HEAVY_WEIGHT_APP_ADJ: "); pw.println(ProcessList.HEAVY_WEIGHT_APP_ADJ); pw.print(" BACKUP_APP_ADJ: "); pw.println(ProcessList.BACKUP_APP_ADJ); + pw.print(" HEAVY_WEIGHT_APP_ADJ: "); pw.println(ProcessList.HEAVY_WEIGHT_APP_ADJ); pw.print(" SERVICE_ADJ: "); pw.println(ProcessList.SERVICE_ADJ); pw.print(" HOME_APP_ADJ: "); pw.println(ProcessList.HOME_APP_ADJ); pw.print(" PREVIOUS_APP_ADJ: "); pw.println(ProcessList.PREVIOUS_APP_ADJ); @@ -10772,10 +10779,10 @@ public final class ActivityManagerService extends ActivityManagerNative oomAdj = buildOomTag("home ", null, r.setAdj, ProcessList.HOME_APP_ADJ); } else if (r.setAdj >= ProcessList.SERVICE_ADJ) { oomAdj = buildOomTag("svc ", null, r.setAdj, ProcessList.SERVICE_ADJ); - } else if (r.setAdj >= ProcessList.BACKUP_APP_ADJ) { - oomAdj = buildOomTag("bkup ", null, r.setAdj, ProcessList.BACKUP_APP_ADJ); } else if (r.setAdj >= ProcessList.HEAVY_WEIGHT_APP_ADJ) { oomAdj = buildOomTag("hvy ", null, r.setAdj, ProcessList.HEAVY_WEIGHT_APP_ADJ); + } else if (r.setAdj >= ProcessList.BACKUP_APP_ADJ) { + oomAdj = buildOomTag("bkup ", null, r.setAdj, ProcessList.BACKUP_APP_ADJ); } else if (r.setAdj >= ProcessList.PERCEPTIBLE_APP_ADJ) { oomAdj = buildOomTag("prcp ", null, r.setAdj, ProcessList.PERCEPTIBLE_APP_ADJ); } else if (r.setAdj >= ProcessList.VISIBLE_APP_ADJ) { @@ -10820,29 +10827,38 @@ public final class ActivityManagerService extends ActivityManagerNative case ActivityManager.PROCESS_STATE_TOP: procState = "T "; break; - case ActivityManager.PROCESS_STATE_IMPORTANT_PERCEPTIBLE: - procState = "IP"; + case ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND: + procState = "IF"; break; case ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND: procState = "IB"; break; - case ActivityManager.PROCESS_STATE_RECEIVER: - procState = "R "; - break; case ActivityManager.PROCESS_STATE_BACKUP: procState = "BU"; break; + case ActivityManager.PROCESS_STATE_HEAVY_WEIGHT: + procState = "HW"; + break; case ActivityManager.PROCESS_STATE_SERVICE: procState = "S "; break; + case ActivityManager.PROCESS_STATE_RECEIVER: + procState = "R "; + break; case ActivityManager.PROCESS_STATE_HOME: - procState = "H "; + procState = "HO"; break; case ActivityManager.PROCESS_STATE_LAST_ACTIVITY: procState = "LA"; break; - case ActivityManager.PROCESS_STATE_CACHED: - procState = "C "; + case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY: + procState = "CA"; + break; + case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT: + procState = "Ca"; + break; + case ActivityManager.PROCESS_STATE_CACHED_EMPTY: + procState = "CE"; break; default: procState = "??"; @@ -10895,9 +10911,6 @@ public final class ActivityManagerService extends ActivityManagerNative pw.print(prefix); pw.print(" "); pw.print("oom: max="); pw.print(r.maxAdj); - pw.print(" cached="); pw.print(r.cachedAdj); - pw.print(" client="); pw.print(r.clientCachedAdj); - pw.print(" empty="); pw.print(r.emptyAdj); pw.print(" curRaw="); pw.print(r.curRawAdj); pw.print(" setRaw="); pw.print(r.setRawAdj); pw.print(" cur="); pw.print(r.curAdj); @@ -11139,21 +11152,24 @@ public final class ActivityManagerService extends ActivityManagerNative static final int[] DUMP_MEM_OOM_ADJ = new int[] { ProcessList.SYSTEM_ADJ, ProcessList.PERSISTENT_PROC_ADJ, ProcessList.FOREGROUND_APP_ADJ, - ProcessList.VISIBLE_APP_ADJ, ProcessList.PERCEPTIBLE_APP_ADJ, ProcessList.HEAVY_WEIGHT_APP_ADJ, - ProcessList.BACKUP_APP_ADJ, ProcessList.SERVICE_ADJ, ProcessList.HOME_APP_ADJ, + ProcessList.VISIBLE_APP_ADJ, ProcessList.PERCEPTIBLE_APP_ADJ, + ProcessList.BACKUP_APP_ADJ, ProcessList.HEAVY_WEIGHT_APP_ADJ, + ProcessList.SERVICE_ADJ, ProcessList.HOME_APP_ADJ, ProcessList.PREVIOUS_APP_ADJ, ProcessList.SERVICE_B_ADJ, ProcessList.CACHED_APP_MAX_ADJ }; static final String[] DUMP_MEM_OOM_LABEL = new String[] { "System", "Persistent", "Foreground", - "Visible", "Perceptible", "Heavy Weight", - "Backup", "A Services", "Home", "Previous", - "B Services", "Cached" + "Visible", "Perceptible", + "Heavy Weight", "Backup", + "A Services", "Home", + "Previous", "B Services", "Cached" }; static final String[] DUMP_MEM_OOM_COMPACT_LABEL = new String[] { "sys", "pers", "fore", - "vis", "percept", "heavy", - "backup", "servicea", "home", "prev", - "serviceb", "cached" + "vis", "percept", + "heavy", "backup", + "servicea", "home", + "prev", "serviceb", "cached" }; final void dumpApplicationMemoryUsage(FileDescriptor fd, @@ -11225,6 +11241,7 @@ public final class ActivityManagerService extends ActivityManagerNative long oomPss[] = new long[DUMP_MEM_OOM_LABEL.length]; ArrayList<MemItem>[] oomProcs = (ArrayList<MemItem>[]) new ArrayList[DUMP_MEM_OOM_LABEL.length]; + final long[] tmpLong = new long[1]; long totalPss = 0; long cachedPss = 0; @@ -11264,16 +11281,18 @@ public final class ActivityManagerService extends ActivityManagerNative if (!brief && !oomOnly) { Debug.getMemoryInfo(pid, mi); } else { - mi.dalvikPss = (int)Debug.getPss(pid); + mi.dalvikPss = (int)Debug.getPss(pid, tmpLong); + mi.dalvikPrivateDirty = (int)tmpLong[0]; } } final long myTotalPss = mi.getTotalPss(); + final long myTotalUss = mi.getTotalUss(); synchronized (this) { if (r.thread != null && oomAdj == r.getSetAdjWithServices()) { // Record this for posterity if the process has been stable. - r.baseProcessTracker.addPss(myTotalPss, true); + r.baseProcessTracker.addPss(myTotalPss, myTotalUss, true); } } @@ -11642,14 +11661,11 @@ public final class ActivityManagerService extends ActivityManagerNative skipCurrentReceiverLocked(app); // Unregister any receivers. - if (app.receivers.size() > 0) { - Iterator<ReceiverList> it = app.receivers.iterator(); - while (it.hasNext()) { - removeReceiverLocked(it.next()); - } - app.receivers.clear(); + for (int i=app.receivers.size()-1; i>=0; i--) { + removeReceiverLocked(app.receivers.valueAt(i)); } - + app.receivers.clear(); + // If the app is undergoing backup, tell the backup manager about it if (mBackupTarget != null && app.pid == mBackupTarget.app.pid) { if (DEBUG_BACKUP || DEBUG_CLEANUP) Slog.d(TAG, "App " @@ -13409,29 +13425,17 @@ public final class ActivityManagerService extends ActivityManagerNative return null; } - private final int computeOomAdjLocked(ProcessRecord app, int cachedAdj, int clientCachedAdj, - int emptyAdj, ProcessRecord TOP_APP, boolean recursed, boolean doingAll) { + private final int computeOomAdjLocked(ProcessRecord app, int cachedAdj, ProcessRecord TOP_APP, + boolean doingAll, long now) { if (mAdjSeq == app.adjSeq) { - // This adjustment has already been computed. If we are calling - // from the top, we may have already computed our adjustment with - // an earlier cached adjustment that isn't really for us... if - // so, use the new cached adjustment. - if (!recursed && app.cached) { - if (app.hasActivities) { - app.curAdj = app.curRawAdj = app.nonStoppingAdj = cachedAdj; - } else if (app.hasClientActivities) { - app.curAdj = app.curRawAdj = app.nonStoppingAdj = clientCachedAdj; - } else { - app.curAdj = app.curRawAdj = app.nonStoppingAdj = emptyAdj; - } - } + // This adjustment has already been computed. return app.curRawAdj; } if (app.thread == null) { app.adjSeq = mAdjSeq; app.curSchedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE; - app.curProcState = ActivityManager.PROCESS_STATE_CACHED; + app.curProcState = ActivityManager.PROCESS_STATE_CACHED_EMPTY; return (app.curAdj=app.curRawAdj=ProcessList.CACHED_APP_MAX_ADJ); } @@ -13449,7 +13453,7 @@ public final class ActivityManagerService extends ActivityManagerNative // below foreground, so it is not worth doing work for it. app.adjType = "fixed"; app.adjSeq = mAdjSeq; - app.curRawAdj = app.nonStoppingAdj = app.maxAdj; + app.curRawAdj = app.maxAdj; app.hasActivities = false; app.foregroundActivities = false; app.keeping = true; @@ -13507,7 +13511,7 @@ public final class ActivityManagerService extends ActivityManagerNative schedGroup = Process.THREAD_GROUP_DEFAULT; app.adjType = "instrumentation"; interesting = true; - procState = ActivityManager.PROCESS_STATE_IMPORTANT_PERCEPTIBLE; + procState = ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND; } else if ((queue = isReceivingBroadcast(app)) != null) { // An app that is currently receiving a broadcast also // counts as being in the foreground for OOM killer purposes. @@ -13526,33 +13530,39 @@ public final class ActivityManagerService extends ActivityManagerNative app.adjType = "exec-service"; procState = ActivityManager.PROCESS_STATE_SERVICE; } else { - // Assume process is cached (has activities); we will correct - // later if this is not the case. - adj = cachedAdj; + // As far as we know the process is empty. We may change our mind later. schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE; + // At this point we don't actually know the adjustment. Use the cached adj + // value that the caller wants us to. + adj = cachedAdj; + procState = ActivityManager.PROCESS_STATE_CACHED_EMPTY; app.cached = true; - app.adjType = "cch-act"; - procState = ActivityManager.PROCESS_STATE_CACHED; + app.empty = true; + app.adjType = "cch-empty"; } - boolean hasStoppingActivities = false; - // Examine all activities if not already foreground. if (!foregroundActivities && activitiesSize > 0) { for (int j = 0; j < activitiesSize; j++) { final ActivityRecord r = app.activities.get(j); + if (r.app != app) { + Slog.w(TAG, "Wtf, activity " + r + " in proc activity list not using proc " + + app + "?!?"); + continue; + } + app.hasActivities = true; if (r.visible) { // App has a visible activity; only upgrade adjustment. if (adj > ProcessList.VISIBLE_APP_ADJ) { adj = ProcessList.VISIBLE_APP_ADJ; app.adjType = "visible"; } - if (procState > ActivityManager.PROCESS_STATE_IMPORTANT_PERCEPTIBLE) { - procState = ActivityManager.PROCESS_STATE_IMPORTANT_PERCEPTIBLE; + if (procState > ActivityManager.PROCESS_STATE_TOP) { + procState = ActivityManager.PROCESS_STATE_TOP; } schedGroup = Process.THREAD_GROUP_DEFAULT; app.cached = false; - app.hasActivities = true; + app.empty = false; foregroundActivities = true; break; } else if (r.state == ActivityState.PAUSING || r.state == ActivityState.PAUSED) { @@ -13560,53 +13570,54 @@ public final class ActivityManagerService extends ActivityManagerNative adj = ProcessList.PERCEPTIBLE_APP_ADJ; app.adjType = "pausing"; } - if (procState > ActivityManager.PROCESS_STATE_IMPORTANT_PERCEPTIBLE) { - procState = ActivityManager.PROCESS_STATE_IMPORTANT_PERCEPTIBLE; + if (procState > ActivityManager.PROCESS_STATE_TOP) { + procState = ActivityManager.PROCESS_STATE_TOP; } + schedGroup = Process.THREAD_GROUP_DEFAULT; app.cached = false; + app.empty = false; foregroundActivities = true; } else if (r.state == ActivityState.STOPPING) { - // We will apply the actual adjustment later, because - // we want to allow this process to immediately go through - // any memory trimming that is in effect. - if (procState > ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND) { - procState = ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND; + if (adj > ProcessList.PERCEPTIBLE_APP_ADJ) { + adj = ProcessList.PERCEPTIBLE_APP_ADJ; + app.adjType = "stopping"; + } + // For the process state, we will at this point consider the + // process to be cached. It will be cached either as an activity + // or empty depending on whether the activity is finishing. We do + // this so that we can treat the process as cached for purposes of + // memory trimming (determing current memory level, trim command to + // send to process) since there can be an arbitrary number of stopping + // processes and they should soon all go into the cached state. + if (!r.finishing) { + if (procState > ActivityManager.PROCESS_STATE_CACHED_ACTIVITY) { + procState = ActivityManager.PROCESS_STATE_CACHED_ACTIVITY; + } } app.cached = false; + app.empty = false; foregroundActivities = true; - hasStoppingActivities = true; - } - if (r.app == app) { - app.hasActivities = true; + } else { + if (procState > ActivityManager.PROCESS_STATE_CACHED_ACTIVITY) { + procState = ActivityManager.PROCESS_STATE_CACHED_ACTIVITY; + app.adjType = "cch-act"; + } } } } - if (adj == cachedAdj && !app.hasActivities) { - if (app.hasClientActivities) { - adj = clientCachedAdj; - app.adjType = "cch-client-act"; - } else { - // Whoops, this process is completely empty as far as we know - // at this point. - adj = emptyAdj; - app.empty = true; - app.adjType = "cch-empty"; - } - } - if (adj > ProcessList.PERCEPTIBLE_APP_ADJ) { if (app.foregroundServices) { // The user is aware of this app, so make it visible. adj = ProcessList.PERCEPTIBLE_APP_ADJ; - procState = ActivityManager.PROCESS_STATE_IMPORTANT_PERCEPTIBLE; + procState = ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND; app.cached = false; app.adjType = "fg-service"; schedGroup = Process.THREAD_GROUP_DEFAULT; } else if (app.forcingToForeground != null) { // The user is aware of this app, so make it visible. adj = ProcessList.PERCEPTIBLE_APP_ADJ; - procState = ActivityManager.PROCESS_STATE_IMPORTANT_PERCEPTIBLE; + procState = ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND; app.cached = false; app.adjType = "force-fg"; app.adjSource = app.forcingToForeground; @@ -13618,12 +13629,17 @@ public final class ActivityManagerService extends ActivityManagerNative interesting = true; } - if (adj > ProcessList.HEAVY_WEIGHT_APP_ADJ && app == mHeavyWeightProcess) { - // We don't want to kill the current heavy-weight process. - adj = ProcessList.HEAVY_WEIGHT_APP_ADJ; - schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE; - app.cached = false; - app.adjType = "heavy"; + if (app == mHeavyWeightProcess) { + if (adj > ProcessList.HEAVY_WEIGHT_APP_ADJ) { + // We don't want to kill the current heavy-weight process. + adj = ProcessList.HEAVY_WEIGHT_APP_ADJ; + schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE; + app.cached = false; + app.adjType = "heavy"; + } + if (procState > ActivityManager.PROCESS_STATE_HEAVY_WEIGHT) { + procState = ActivityManager.PROCESS_STATE_HEAVY_WEIGHT; + } } if (app == mHomeProcess) { @@ -13663,7 +13679,7 @@ public final class ActivityManagerService extends ActivityManagerNative // this gives us a baseline and makes sure we don't get into an // infinite recursion. app.adjSeq = mAdjSeq; - app.curRawAdj = app.nonStoppingAdj = adj; + app.curRawAdj = adj; app.hasStartedServices = false; if (mBackupTarget != null && app == mBackupTarget.app) { @@ -13682,243 +13698,226 @@ public final class ActivityManagerService extends ActivityManagerNative } } - if (app.services.size() != 0 && (adj > ProcessList.FOREGROUND_APP_ADJ - || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE)) { - final long now = SystemClock.uptimeMillis(); - // This process is more important if the top activity is - // bound to the service. - Iterator<ServiceRecord> jt = app.services.iterator(); - while (jt.hasNext() && adj > ProcessList.FOREGROUND_APP_ADJ) { - ServiceRecord s = jt.next(); - if (s.startRequested) { - app.hasStartedServices = true; - if (procState > ActivityManager.PROCESS_STATE_SERVICE) { - procState = ActivityManager.PROCESS_STATE_SERVICE; - } - if (app.hasShownUi && app != mHomeProcess) { - // If this process has shown some UI, let it immediately - // go to the LRU list because it may be pretty heavy with - // UI stuff. We'll tag it with a label just to help - // debug and understand what is going on. - if (adj > ProcessList.SERVICE_ADJ) { - app.adjType = "cch-started-ui-services"; - } - } else { - if (now < (s.lastActivity + ActiveServices.MAX_SERVICE_INACTIVITY)) { - // This service has seen some activity within - // recent memory, so we will keep its process ahead - // of the background processes. - if (adj > ProcessList.SERVICE_ADJ) { - adj = ProcessList.SERVICE_ADJ; - app.adjType = "started-services"; - app.cached = false; - } - } - // If we have let the service slide into the background - // state, still have some text describing what it is doing - // even though the service no longer has an impact. + for (int is = app.services.size()-1; + is >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ + || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE + || procState > ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND); + is--) { + ServiceRecord s = app.services.valueAt(is); + if (s.startRequested) { + app.hasStartedServices = true; + if (procState > ActivityManager.PROCESS_STATE_SERVICE) { + procState = ActivityManager.PROCESS_STATE_SERVICE; + } + if (app.hasShownUi && app != mHomeProcess) { + // If this process has shown some UI, let it immediately + // go to the LRU list because it may be pretty heavy with + // UI stuff. We'll tag it with a label just to help + // debug and understand what is going on. + if (adj > ProcessList.SERVICE_ADJ) { + app.adjType = "cch-started-ui-services"; + } + } else { + if (now < (s.lastActivity + ActiveServices.MAX_SERVICE_INACTIVITY)) { + // This service has seen some activity within + // recent memory, so we will keep its process ahead + // of the background processes. if (adj > ProcessList.SERVICE_ADJ) { - app.adjType = "cch-started-services"; + adj = ProcessList.SERVICE_ADJ; + app.adjType = "started-services"; + app.cached = false; } } - // Don't kill this process because it is doing work; it - // has said it is doing work. - app.keeping = true; - } - for (int conni = s.connections.size()-1; - conni >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ - || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE); - conni--) { - ArrayList<ConnectionRecord> clist = s.connections.valueAt(conni); - for (int i = 0; - i < clist.size() && (adj > ProcessList.FOREGROUND_APP_ADJ - || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE); - i++) { - // XXX should compute this based on the max of - // all connected clients. - ConnectionRecord cr = clist.get(i); - if (cr.binding.client == app) { - // Binding to ourself is not interesting. - continue; + // If we have let the service slide into the background + // state, still have some text describing what it is doing + // even though the service no longer has an impact. + if (adj > ProcessList.SERVICE_ADJ) { + app.adjType = "cch-started-services"; + } + } + // Don't kill this process because it is doing work; it + // has said it is doing work. + app.keeping = true; + } + for (int conni = s.connections.size()-1; + conni >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ + || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE + || procState > ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND); + conni--) { + ArrayList<ConnectionRecord> clist = s.connections.valueAt(conni); + for (int i = 0; + i < clist.size() && (adj > ProcessList.FOREGROUND_APP_ADJ + || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE + || procState > ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND); + i++) { + // XXX should compute this based on the max of + // all connected clients. + ConnectionRecord cr = clist.get(i); + if (cr.binding.client == app) { + // Binding to ourself is not interesting. + continue; + } + if ((cr.flags&Context.BIND_WAIVE_PRIORITY) == 0) { + ProcessRecord client = cr.binding.client; + int clientAdj = computeOomAdjLocked(client, cachedAdj, + TOP_APP, doingAll, now); + int clientProcState = client.curProcState; + if (clientProcState >= ActivityManager.PROCESS_STATE_CACHED_ACTIVITY) { + // If the other app is cached for any reason, for purposes here + // we are going to consider it empty. The specific cached state + // doesn't propagate except under certain conditions. + clientProcState = ActivityManager.PROCESS_STATE_CACHED_EMPTY; } - if ((cr.flags&Context.BIND_WAIVE_PRIORITY) == 0) { - ProcessRecord client = cr.binding.client; - int myCachedAdj = cachedAdj; - if (myCachedAdj > client.cachedAdj) { - if (client.cachedAdj >= ProcessList.VISIBLE_APP_ADJ) { - myCachedAdj = client.cachedAdj; - } else { - myCachedAdj = ProcessList.VISIBLE_APP_ADJ; - } - } - int myClientCachedAdj = clientCachedAdj; - if (myClientCachedAdj > client.clientCachedAdj) { - if (client.clientCachedAdj >= ProcessList.VISIBLE_APP_ADJ) { - myClientCachedAdj = client.clientCachedAdj; - } else { - myClientCachedAdj = ProcessList.VISIBLE_APP_ADJ; - } - } - int myEmptyAdj = emptyAdj; - if (myEmptyAdj > client.emptyAdj) { - if (client.emptyAdj >= ProcessList.VISIBLE_APP_ADJ) { - myEmptyAdj = client.emptyAdj; - } else { - myEmptyAdj = ProcessList.VISIBLE_APP_ADJ; + String adjType = null; + if ((cr.flags&Context.BIND_ALLOW_OOM_MANAGEMENT) != 0) { + // Not doing bind OOM management, so treat + // this guy more like a started service. + if (app.hasShownUi && app != mHomeProcess) { + // If this process has shown some UI, let it immediately + // go to the LRU list because it may be pretty heavy with + // UI stuff. We'll tag it with a label just to help + // debug and understand what is going on. + if (adj > clientAdj) { + adjType = "cch-bound-ui-services"; } - } - int clientAdj = computeOomAdjLocked(client, myCachedAdj, - myClientCachedAdj, myEmptyAdj, TOP_APP, true, doingAll); - int clientProcState = client.curProcState; - String adjType = null; - if ((cr.flags&Context.BIND_ALLOW_OOM_MANAGEMENT) != 0) { - // Not doing bind OOM management, so treat - // this guy more like a started service. - if (app.hasShownUi && app != mHomeProcess) { - // If this process has shown some UI, let it immediately - // go to the LRU list because it may be pretty heavy with - // UI stuff. We'll tag it with a label just to help - // debug and understand what is going on. + app.cached = false; + clientAdj = adj; + clientProcState = procState; + } else { + if (now >= (s.lastActivity + + ActiveServices.MAX_SERVICE_INACTIVITY)) { + // This service has not seen activity within + // recent memory, so allow it to drop to the + // LRU list if there is no other reason to keep + // it around. We'll also tag it with a label just + // to help debug and undertand what is going on. if (adj > clientAdj) { - adjType = "cch-bound-ui-services"; + adjType = "cch-bound-services"; } - app.cached = false; clientAdj = adj; - clientProcState = procState; - } else { - if (now >= (s.lastActivity - + ActiveServices.MAX_SERVICE_INACTIVITY)) { - // This service has not seen activity within - // recent memory, so allow it to drop to the - // LRU list if there is no other reason to keep - // it around. We'll also tag it with a label just - // to help debug and undertand what is going on. - if (adj > clientAdj) { - adjType = "cch-bound-services"; - } - clientAdj = adj; - } - } - } else if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) { - if ((cr.flags&Context.BIND_NOT_VISIBLE) == 0) { - // If this connection is keeping the service - // created, then we want to try to better follow - // its memory management semantics for activities. - // That is, if it is sitting in the background - // LRU list as a cached process (with activities), - // we don't want the service it is connected to - // to go into the empty LRU and quickly get killed, - // because all we'll do is just end up restarting - // the service. - app.hasClientActivities |= client.hasActivities; } } - if (adj > clientAdj) { - // If this process has recently shown UI, and - // the process that is binding to it is less - // important than being visible, then we don't - // care about the binding as much as we care - // about letting this process get into the LRU - // list to be killed and restarted if needed for - // memory. - if (app.hasShownUi && app != mHomeProcess - && clientAdj > ProcessList.PERCEPTIBLE_APP_ADJ) { - adjType = "cch-bound-ui-services"; - } else { - if ((cr.flags&(Context.BIND_ABOVE_CLIENT - |Context.BIND_IMPORTANT)) != 0) { - adj = clientAdj; - } else if ((cr.flags&Context.BIND_NOT_VISIBLE) != 0 - && clientAdj < ProcessList.PERCEPTIBLE_APP_ADJ - && adj > ProcessList.PERCEPTIBLE_APP_ADJ) { - adj = ProcessList.PERCEPTIBLE_APP_ADJ; - } else if (clientAdj > ProcessList.VISIBLE_APP_ADJ) { - adj = clientAdj; - } else { - app.pendingUiClean = true; - if (adj > ProcessList.VISIBLE_APP_ADJ) { - adj = ProcessList.VISIBLE_APP_ADJ; - } - } - if (!client.cached) { - app.cached = false; + } else if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) { + if ((cr.flags&Context.BIND_NOT_VISIBLE) == 0) { + // If this connection is keeping the service + // created, then we want to try to better follow + // its memory management semantics for activities. + // That is, if it is sitting in the background + // LRU list as a cached process (with activities), + // we don't want the service it is connected to + // to go into the empty LRU and quickly get killed, + // because all we'll do is just end up restarting + // the service. + if (client.hasActivities) { + if (procState > + ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT) { + procState = + ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT; + app.adjType = "cch-client-act"; } - if (client.keeping) { - app.keeping = true; - } - adjType = "service"; + app.hasClientActivities = true; } } - if ((cr.flags&Context.BIND_NOT_FOREGROUND) == 0) { - if (client.curSchedGroup == Process.THREAD_GROUP_DEFAULT) { - schedGroup = Process.THREAD_GROUP_DEFAULT; + } + if (adj > clientAdj) { + // If this process has recently shown UI, and + // the process that is binding to it is less + // important than being visible, then we don't + // care about the binding as much as we care + // about letting this process get into the LRU + // list to be killed and restarted if needed for + // memory. + if (app.hasShownUi && app != mHomeProcess + && clientAdj > ProcessList.PERCEPTIBLE_APP_ADJ) { + adjType = "cch-bound-ui-services"; + } else { + if ((cr.flags&(Context.BIND_ABOVE_CLIENT + |Context.BIND_IMPORTANT)) != 0) { + adj = clientAdj; + } else if ((cr.flags&Context.BIND_NOT_VISIBLE) != 0 + && clientAdj < ProcessList.PERCEPTIBLE_APP_ADJ + && adj > ProcessList.PERCEPTIBLE_APP_ADJ) { + adj = ProcessList.PERCEPTIBLE_APP_ADJ; + } else if (clientAdj > ProcessList.VISIBLE_APP_ADJ) { + adj = clientAdj; + } else { + if (adj > ProcessList.VISIBLE_APP_ADJ) { + adj = ProcessList.VISIBLE_APP_ADJ; + } } - if (clientProcState < - ActivityManager.PROCESS_STATE_IMPORTANT_PERCEPTIBLE) { - clientProcState = - ActivityManager.PROCESS_STATE_IMPORTANT_PERCEPTIBLE; + if (!client.cached) { + app.cached = false; } - } else { - if (clientProcState < - ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND) { - clientProcState = - ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND; + if (client.keeping) { + app.keeping = true; } + adjType = "service"; + } + } + if ((cr.flags&Context.BIND_NOT_FOREGROUND) == 0) { + if (client.curSchedGroup == Process.THREAD_GROUP_DEFAULT) { + schedGroup = Process.THREAD_GROUP_DEFAULT; } - if (procState > clientProcState) { - procState = clientProcState; + if (clientProcState < + ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND) { + clientProcState = + ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND; } - if (adjType != null) { - app.adjType = adjType; - app.adjTypeCode = ActivityManager.RunningAppProcessInfo - .REASON_SERVICE_IN_USE; - app.adjSource = cr.binding.client; - app.adjSourceOom = clientAdj; - app.adjTarget = s.name; + } else { + if (clientProcState < + ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND) { + clientProcState = + ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND; } } - final ActivityRecord a = cr.activity; - if ((cr.flags&Context.BIND_ADJUST_WITH_ACTIVITY) != 0) { - if (a != null && adj > ProcessList.FOREGROUND_APP_ADJ && - (a.visible || a.state == ActivityState.RESUMED - || a.state == ActivityState.PAUSING)) { - adj = ProcessList.FOREGROUND_APP_ADJ; - if ((cr.flags&Context.BIND_NOT_FOREGROUND) == 0) { - schedGroup = Process.THREAD_GROUP_DEFAULT; - } - app.cached = false; - app.adjType = "service"; - app.adjTypeCode = ActivityManager.RunningAppProcessInfo - .REASON_SERVICE_IN_USE; - app.adjSource = a; - app.adjSourceOom = adj; - app.adjTarget = s.name; + if (procState > clientProcState) { + procState = clientProcState; + } + if (procState < ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND + && (cr.flags&Context.BIND_SHOWING_UI) != 0) { + app.pendingUiClean = true; + } + if (adjType != null) { + app.adjType = adjType; + app.adjTypeCode = ActivityManager.RunningAppProcessInfo + .REASON_SERVICE_IN_USE; + app.adjSource = cr.binding.client; + app.adjSourceOom = clientAdj; + app.adjTarget = s.name; + } + } + final ActivityRecord a = cr.activity; + if ((cr.flags&Context.BIND_ADJUST_WITH_ACTIVITY) != 0) { + if (a != null && adj > ProcessList.FOREGROUND_APP_ADJ && + (a.visible || a.state == ActivityState.RESUMED + || a.state == ActivityState.PAUSING)) { + adj = ProcessList.FOREGROUND_APP_ADJ; + if ((cr.flags&Context.BIND_NOT_FOREGROUND) == 0) { + schedGroup = Process.THREAD_GROUP_DEFAULT; } + app.cached = false; + app.adjType = "service"; + app.adjTypeCode = ActivityManager.RunningAppProcessInfo + .REASON_SERVICE_IN_USE; + app.adjSource = a; + app.adjSourceOom = adj; + app.adjTarget = s.name; } } } } - - // Finally, if this process has active services running in it, we - // would like to avoid killing it unless it would prevent the current - // application from running. By default we put the process in - // with the rest of the background processes; as we scan through - // its services we may bump it up from there. - if (adj > cachedAdj) { - adj = cachedAdj; - app.cached = false; - app.adjType = "cch-services"; - } } for (int provi = app.pubProviders.size()-1; provi >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ - || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE); + || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE + || procState > ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND); provi--) { ContentProviderRecord cpr = app.pubProviders.valueAt(provi); for (int i = cpr.connections.size()-1; i >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ - || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE); + || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE + || procState > ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND); i--) { ContentProviderConnection conn = cpr.connections.get(i); ProcessRecord client = conn.client; @@ -13926,32 +13925,13 @@ public final class ActivityManagerService extends ActivityManagerNative // Being our own client is not interesting. continue; } - int myCachedAdj = cachedAdj; - if (myCachedAdj > client.cachedAdj) { - if (client.cachedAdj > ProcessList.FOREGROUND_APP_ADJ) { - myCachedAdj = client.cachedAdj; - } else { - myCachedAdj = ProcessList.FOREGROUND_APP_ADJ; - } - } - int myClientCachedAdj = clientCachedAdj; - if (myClientCachedAdj > client.clientCachedAdj) { - if (client.clientCachedAdj >= ProcessList.FOREGROUND_APP_ADJ) { - myClientCachedAdj = client.clientCachedAdj; - } else { - myClientCachedAdj = ProcessList.FOREGROUND_APP_ADJ; - } - } - int myEmptyAdj = emptyAdj; - if (myEmptyAdj > client.emptyAdj) { - if (client.emptyAdj > ProcessList.FOREGROUND_APP_ADJ) { - myEmptyAdj = client.emptyAdj; - } else { - myEmptyAdj = ProcessList.FOREGROUND_APP_ADJ; - } + int clientAdj = computeOomAdjLocked(client, cachedAdj, TOP_APP, doingAll, now); + int clientProcState = client.curProcState; + if (clientProcState >= ActivityManager.PROCESS_STATE_CACHED_ACTIVITY) { + // If the other app is cached for any reason, for purposes here + // we are going to consider it empty. + clientProcState = ActivityManager.PROCESS_STATE_CACHED_EMPTY; } - int clientAdj = computeOomAdjLocked(client, myCachedAdj, - myClientCachedAdj, myEmptyAdj, TOP_APP, true, doingAll); if (adj > clientAdj) { if (app.hasShownUi && app != mHomeProcess && clientAdj > ProcessList.PERCEPTIBLE_APP_ADJ) { @@ -13961,20 +13941,17 @@ public final class ActivityManagerService extends ActivityManagerNative ? clientAdj : ProcessList.FOREGROUND_APP_ADJ; app.adjType = "provider"; } - if (!client.cached) { - app.cached = false; - } - if (client.keeping) { - app.keeping = true; - } + app.cached &= client.cached; + app.keeping |= client.keeping; app.adjTypeCode = ActivityManager.RunningAppProcessInfo .REASON_PROVIDER_IN_USE; app.adjSource = client; app.adjSourceOom = clientAdj; app.adjTarget = cpr.name; } - if (procState > client.curProcState) { - procState = client.curProcState; + if (procState > clientProcState) { + procState = clientProcState > ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND + ? clientProcState : ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND; } if (client.curSchedGroup == Process.THREAD_GROUP_DEFAULT) { schedGroup = Process.THREAD_GROUP_DEFAULT; @@ -13992,8 +13969,8 @@ public final class ActivityManagerService extends ActivityManagerNative app.adjType = "provider"; app.adjTarget = cpr.name; } - if (procState > ActivityManager.PROCESS_STATE_IMPORTANT_PERCEPTIBLE) { - procState = ActivityManager.PROCESS_STATE_IMPORTANT_PERCEPTIBLE; + if (procState > ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND) { + procState = ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND; } } } @@ -14010,16 +13987,6 @@ public final class ActivityManagerService extends ActivityManagerNative app.serviceb = false; } - app.nonStoppingAdj = adj; - - if (hasStoppingActivities) { - // Only upgrade adjustment. - if (adj > ProcessList.PERCEPTIBLE_APP_ADJ) { - adj = ProcessList.PERCEPTIBLE_APP_ADJ; - app.adjType = "stopping"; - } - } - app.curRawAdj = adj; //Slog.i(TAG, "OOM ADJ " + app + ": pid=" + app.pid + @@ -14034,24 +14001,12 @@ public final class ActivityManagerService extends ActivityManagerNative app.keeping = true; } - if (app.hasAboveClient) { - // If this process has bound to any services with BIND_ABOVE_CLIENT, - // then we need to drop its adjustment to be lower than the service's - // in order to honor the request. We want to drop it by one adjustment - // level... but there is special meaning applied to various levels so - // we will skip some of them. - if (adj < ProcessList.FOREGROUND_APP_ADJ) { - // System process will not get dropped, ever - } else if (adj < ProcessList.VISIBLE_APP_ADJ) { - adj = ProcessList.VISIBLE_APP_ADJ; - } else if (adj < ProcessList.PERCEPTIBLE_APP_ADJ) { - adj = ProcessList.PERCEPTIBLE_APP_ADJ; - } else if (adj < ProcessList.CACHED_APP_MIN_ADJ) { - adj = ProcessList.CACHED_APP_MIN_ADJ; - } else if (adj < ProcessList.CACHED_APP_MAX_ADJ) { - adj++; - } - } + // Do final modification to adj. Everything we do between here and applying + // the final setAdj must be done in this function, because we will also use + // it when computing the final cached adj later. Note that we don't need to + // worry about this for max adj above, since max adj will always be used to + // keep it out of the cached vaues. + adj = app.modifyRawOomAdj(adj); app.curProcState = procState; @@ -14407,23 +14362,10 @@ public final class ActivityManagerService extends ActivityManagerNative } } - private final boolean updateOomAdjLocked(ProcessRecord app, int cachedAdj, - int clientCachedAdj, int emptyAdj, ProcessRecord TOP_APP, boolean doingAll, - boolean doingProcessState, long now) { - app.cachedAdj = cachedAdj; - app.clientCachedAdj = clientCachedAdj; - app.emptyAdj = emptyAdj; - - if (app.thread == null) { - return false; - } - - final boolean wasKeeping = app.keeping; - + private final boolean applyOomAdjLocked(ProcessRecord app, boolean wasKeeping, + ProcessRecord TOP_APP, boolean doingAll, boolean reportingProcessState, long now) { boolean success = true; - computeOomAdjLocked(app, cachedAdj, clientCachedAdj, emptyAdj, TOP_APP, false, doingAll); - if (app.curRawAdj != app.setRawAdj) { if (wasKeeping && !app.keeping) { // This app is no longer something we want to keep. Note @@ -14467,11 +14409,6 @@ public final class ActivityManagerService extends ActivityManagerNative requestPssLocked(app, now, true); } app.setAdj = app.curAdj; - app.setAdjChanged = true; - if (!doingAll) { - app.setProcessTrackerState(TOP_APP, mProcessTracker.getMemFactorLocked(), - now, mProcessList); - } } else { success = false; Slog.w(TAG, "Failed setting oom adj of " + app + " to " + app.curAdj); @@ -14510,11 +14447,13 @@ public final class ActivityManagerService extends ActivityManagerNative } } } + Process.setSwappiness(app.pid, + app.curSchedGroup <= Process.THREAD_GROUP_BG_NONINTERACTIVE); } } if (app.repProcState != app.curProcState) { app.repProcState = app.curProcState; - if (!doingProcessState && app.thread != null) { + if (!reportingProcessState && app.thread != null) { try { if (false) { //RuntimeException h = new RuntimeException("here"); @@ -14526,9 +14465,33 @@ public final class ActivityManagerService extends ActivityManagerNative } } } + if (app.setProcState != app.curProcState) { + if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG, + "Proc state change of " + app.processName + + " to " + app.curProcState); + app.setProcState = app.curProcState; + app.procStateChanged = true; + if (!doingAll) { + app.setProcessTrackerState(mProcessTracker.getMemFactorLocked(), now); + } + } return success; } + private final boolean updateOomAdjLocked(ProcessRecord app, int cachedAdj, + ProcessRecord TOP_APP, boolean doingAll, boolean reportingProcessState, long now) { + if (app.thread == null) { + return false; + } + + final boolean wasKeeping = app.keeping; + + computeOomAdjLocked(app, cachedAdj, TOP_APP, doingAll, now); + + return applyOomAdjLocked(app, wasKeeping, TOP_APP, doingAll, + reportingProcessState, now); + } + private final ActivityRecord resumedAppLocked() { return mStackSupervisor.resumedAppLocked(); } @@ -14540,17 +14503,19 @@ public final class ActivityManagerService extends ActivityManagerNative final boolean updateOomAdjLocked(ProcessRecord app, boolean doingProcessState) { final ActivityRecord TOP_ACT = resumedAppLocked(); final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null; - int curAdj = app.curAdj; - final boolean wasCached = curAdj >= ProcessList.CACHED_APP_MIN_ADJ - && curAdj <= ProcessList.CACHED_APP_MAX_ADJ; + final boolean wasCached = app.cached; mAdjSeq++; - boolean success = updateOomAdjLocked(app, app.cachedAdj, app.clientCachedAdj, - app.emptyAdj, TOP_APP, false, doingProcessState, SystemClock.uptimeMillis()); - final boolean nowCached = app.curAdj >= ProcessList.CACHED_APP_MIN_ADJ - && app.curAdj <= ProcessList.CACHED_APP_MAX_ADJ; - if (nowCached != wasCached) { + // This is the desired cached adjusment we want to tell it to use. + // If our app is currently cached, we know it, and that is it. Otherwise, + // we don't know it yet, and it needs to now be cached we will then + // need to do a complete oom adj. + final int cachedAdj = app.curRawAdj >= ProcessList.CACHED_APP_MIN_ADJ + ? app.curRawAdj : ProcessList.UNKNOWN_ADJ; + boolean success = updateOomAdjLocked(app, cachedAdj, TOP_APP, false, doingProcessState, + SystemClock.uptimeMillis()); + if (wasCached != app.cached || app.curRawAdj == ProcessList.UNKNOWN_ADJ) { // Changed to/from cached state, so apps after it in the LRU // list may also be changed. updateOomAdjLocked(); @@ -14563,6 +14528,7 @@ public final class ActivityManagerService extends ActivityManagerNative final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null; final long now = SystemClock.uptimeMillis(); final long oldTime = now - ProcessList.MAX_EMPTY_TIME; + final int N = mLruProcesses.size(); if (false) { RuntimeException e = new RuntimeException(); @@ -14591,7 +14557,7 @@ public final class ActivityManagerService extends ActivityManagerNative // them. int numSlots = (ProcessList.CACHED_APP_MAX_ADJ - ProcessList.CACHED_APP_MIN_ADJ + 1) / 2; - int numEmptyProcs = mLruProcesses.size()- mNumNonCachedProcs - mNumCachedHiddenProcs; + int numEmptyProcs = N - mNumNonCachedProcs - mNumCachedHiddenProcs; if (numEmptyProcs > cachedProcessLimit) { // If there are more empty processes than our limit on cached // processes, then use the cached process limit for the factor. @@ -14616,80 +14582,97 @@ public final class ActivityManagerService extends ActivityManagerNative // First update the OOM adjustment for each of the // application processes based on their current state. - int i = mLruProcesses.size(); int curCachedAdj = ProcessList.CACHED_APP_MIN_ADJ; int nextCachedAdj = curCachedAdj+1; + int curClientCachedAdj = curCachedAdj+1; int curEmptyAdj = ProcessList.CACHED_APP_MIN_ADJ; int nextEmptyAdj = curEmptyAdj+2; - int curClientCachedAdj = curEmptyAdj; - boolean changed = false; - while (i > 0) { - i--; + for (int i=N-1; i>=0; i--) { ProcessRecord app = mLruProcesses.get(i); - //Slog.i(TAG, "OOM " + app + ": cur cached=" + curCachedAdj); - app.setAdjChanged = false; - updateOomAdjLocked(app, curCachedAdj, curClientCachedAdj, curEmptyAdj, TOP_APP, - true, false, now); - changed |= app.setAdjChanged; - if (!app.killedBackground) { - if (app.curRawAdj == curCachedAdj && app.hasActivities) { - // This process was assigned as a cached process... step the - // cached level. - mNumCachedHiddenProcs++; - if (curCachedAdj != nextCachedAdj) { - stepCached++; - if (stepCached >= cachedFactor) { - stepCached = 0; - curCachedAdj = nextCachedAdj; - nextCachedAdj += 2; - if (nextCachedAdj > ProcessList.CACHED_APP_MAX_ADJ) { - nextCachedAdj = ProcessList.CACHED_APP_MAX_ADJ; - } - if (curClientCachedAdj <= curCachedAdj) { - curClientCachedAdj = curCachedAdj + 1; - if (curClientCachedAdj > ProcessList.CACHED_APP_MAX_ADJ) { - curClientCachedAdj = ProcessList.CACHED_APP_MAX_ADJ; + if (!app.killedBackground && app.thread != null) { + app.procStateChanged = false; + final boolean wasKeeping = app.keeping; + computeOomAdjLocked(app, ProcessList.UNKNOWN_ADJ, TOP_APP, true, now); + + // If we haven't yet assigned the final cached adj + // to the process, do that now. + if (app.curAdj >= ProcessList.UNKNOWN_ADJ) { + switch (app.curProcState) { + case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY: + // This process is a cached process holding activities... + // assign it the next cached value for that type, and then + // step that cached level. + app.curRawAdj = curCachedAdj; + app.curAdj = app.modifyRawOomAdj(curCachedAdj); + if (curCachedAdj != nextCachedAdj) { + stepCached++; + if (stepCached >= cachedFactor) { + stepCached = 0; + curCachedAdj = nextCachedAdj; + nextCachedAdj += 2; + if (nextCachedAdj > ProcessList.CACHED_APP_MAX_ADJ) { + nextCachedAdj = ProcessList.CACHED_APP_MAX_ADJ; + } + if (curClientCachedAdj <= curCachedAdj) { + curClientCachedAdj = curCachedAdj + 1; + if (curClientCachedAdj > ProcessList.CACHED_APP_MAX_ADJ) { + curClientCachedAdj = ProcessList.CACHED_APP_MAX_ADJ; + } + } } } - } - } - numCached++; - if (numCached > cachedProcessLimit) { - Slog.i(TAG, "No longer want " + app.processName - + " (pid " + app.pid + "): cached #" + numCached); - EventLog.writeEvent(EventLogTags.AM_KILL, app.userId, app.pid, - app.processName, app.setAdj, "too many background"); - app.killedBackground = true; - Process.killProcessQuiet(app.pid); - } - } else if (app.curRawAdj == curCachedAdj && app.hasClientActivities) { - // This process has a client that has activities. We will have - // given it the current cached adj; here we will just leave it - // without stepping the cached adj. - curClientCachedAdj++; - if (curClientCachedAdj > ProcessList.CACHED_APP_MAX_ADJ) { - curClientCachedAdj = ProcessList.CACHED_APP_MAX_ADJ; - } - } else { - if (app.curRawAdj == curEmptyAdj || app.curRawAdj == curCachedAdj) { - // This process was assigned as an empty process... step the - // empty level. - if (curEmptyAdj != nextEmptyAdj) { - stepEmpty++; - if (stepEmpty >= emptyFactor) { - stepEmpty = 0; - curEmptyAdj = nextEmptyAdj; - nextEmptyAdj += 2; - if (nextEmptyAdj > ProcessList.CACHED_APP_MAX_ADJ) { - nextEmptyAdj = ProcessList.CACHED_APP_MAX_ADJ; + break; + case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT: + // Special case for cached client processes... just step + // down from after regular cached processes. + app.curRawAdj = curClientCachedAdj; + app.curAdj = app.modifyRawOomAdj(curClientCachedAdj); + curClientCachedAdj++; + if (curClientCachedAdj > ProcessList.CACHED_APP_MAX_ADJ) { + curClientCachedAdj = ProcessList.CACHED_APP_MAX_ADJ; + } + break; + default: + // For everything else, assign next empty cached process + // level and bump that up. Note that this means that + // long-running services that have dropped down to the + // cached level will be treated as empty (since their process + // state is still as a service), which is what we want. + app.curRawAdj = curEmptyAdj; + app.curAdj = app.modifyRawOomAdj(curEmptyAdj); + if (curEmptyAdj != nextEmptyAdj) { + stepEmpty++; + if (stepEmpty >= emptyFactor) { + stepEmpty = 0; + curEmptyAdj = nextEmptyAdj; + nextEmptyAdj += 2; + if (nextEmptyAdj > ProcessList.CACHED_APP_MAX_ADJ) { + nextEmptyAdj = ProcessList.CACHED_APP_MAX_ADJ; + } } } - } - } else if (app.curRawAdj < ProcessList.CACHED_APP_MIN_ADJ) { - mNumNonCachedProcs++; + break; } - if (app.curAdj >= ProcessList.CACHED_APP_MIN_ADJ - && !app.hasClientActivities) { + } + + applyOomAdjLocked(app, wasKeeping, TOP_APP, true, false, now); + + // Count the number of process types. + switch (app.curProcState) { + case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY: + case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT: + mNumCachedHiddenProcs++; + numCached++; + if (numCached > cachedProcessLimit) { + Slog.i(TAG, "No longer want " + app.processName + + " (pid " + app.pid + "): cached #" + numCached); + EventLog.writeEvent(EventLogTags.AM_KILL, app.userId, app.pid, + app.processName, app.setAdj, "too many background"); + app.killedBackground = true; + Process.killProcessQuiet(app.pid); + } + break; + case ActivityManager.PROCESS_STATE_CACHED_EMPTY: if (numEmpty > ProcessList.TRIM_EMPTY_APPS && app.lastActivityTime < oldTime) { Slog.i(TAG, "No longer want " + app.processName @@ -14711,8 +14694,12 @@ public final class ActivityManagerService extends ActivityManagerNative Process.killProcessQuiet(app.pid); } } - } + break; + default: + mNumNonCachedProcs++; + break; } + if (app.isolated && app.services.size() <= 0) { // If this is an isolated process, and there are no // services running in it, then the process is no longer @@ -14727,8 +14714,8 @@ public final class ActivityManagerService extends ActivityManagerNative app.killedBackground = true; Process.killProcessQuiet(app.pid); } - if (app.nonStoppingAdj >= ProcessList.HOME_APP_ADJ - && app.nonStoppingAdj != ProcessList.SERVICE_B_ADJ + + if (app.curProcState >= ActivityManager.PROCESS_STATE_HOME && !app.killedBackground) { numTrimming++; } @@ -14743,11 +14730,10 @@ public final class ActivityManagerService extends ActivityManagerNative // are managing to keep around is less than half the maximum we desire; // if we are keeping a good number around, we'll let them use whatever // memory they want. - int memFactor = ProcessTracker.ADJ_MEM_FACTOR_NORMAL; + boolean allChanged; if (numCached <= ProcessList.TRIM_CACHED_APPS && numEmpty <= ProcessList.TRIM_EMPTY_APPS) { final int numCachedAndEmpty = numCached + numEmpty; - final int N = mLruProcesses.size(); int factor = numTrimming/3; int minFactor = 2; if (mHomeProcess != null) minFactor++; @@ -14755,6 +14741,7 @@ public final class ActivityManagerService extends ActivityManagerNative if (factor < minFactor) factor = minFactor; int step = 0; int fgTrimLevel; + int memFactor; if (numCachedAndEmpty <= ProcessList.TRIM_CRITICAL_THRESHOLD) { fgTrimLevel = ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL; memFactor = ProcessTracker.ADJ_MEM_FACTOR_CRITICAL; @@ -14766,13 +14753,19 @@ public final class ActivityManagerService extends ActivityManagerNative memFactor = ProcessTracker.ADJ_MEM_FACTOR_MODERATE; } int curLevel = ComponentCallbacks2.TRIM_MEMORY_COMPLETE; - for (i=0; i<N; i++) { + allChanged = mProcessTracker.setMemFactorLocked(memFactor, !mSleeping, now); + for (int i=N-1; i>=0; i--) { ProcessRecord app = mLruProcesses.get(i); - if (app.nonStoppingAdj >= ProcessList.HOME_APP_ADJ - && app.nonStoppingAdj != ProcessList.SERVICE_B_ADJ + if (allChanged || app.procStateChanged) { + app.setProcessTrackerState(memFactor, now); + } + if (app.curProcState >= ActivityManager.PROCESS_STATE_HOME && !app.killedBackground) { if (app.trimMemoryLevel < curLevel && app.thread != null) { try { + if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG, + "Trimming memory of " + app.processName + + " to " + curLevel); app.thread.scheduleTrimMemory(curLevel); } catch (RemoteException e) { } @@ -14803,10 +14796,13 @@ public final class ActivityManagerService extends ActivityManagerNative break; } } - } else if (app.nonStoppingAdj == ProcessList.HEAVY_WEIGHT_APP_ADJ) { + } else if (app.curProcState == ActivityManager.PROCESS_STATE_HEAVY_WEIGHT) { if (app.trimMemoryLevel < ComponentCallbacks2.TRIM_MEMORY_BACKGROUND && app.thread != null) { try { + if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG, + "Trimming memory of heavy-weight " + app.processName + + " to " + ComponentCallbacks2.TRIM_MEMORY_BACKGROUND); app.thread.scheduleTrimMemory( ComponentCallbacks2.TRIM_MEMORY_BACKGROUND); } catch (RemoteException e) { @@ -14814,14 +14810,17 @@ public final class ActivityManagerService extends ActivityManagerNative } app.trimMemoryLevel = ComponentCallbacks2.TRIM_MEMORY_BACKGROUND; } else { - if ((app.nonStoppingAdj > ProcessList.VISIBLE_APP_ADJ || app.systemNoUi) - && app.pendingUiClean) { + if ((app.curProcState >= ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND + || app.systemNoUi) && app.pendingUiClean) { // If this application is now in the background and it // had done UI, then give it the special trim level to // have it free UI resources. final int level = ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN; if (app.trimMemoryLevel < level && app.thread != null) { try { + if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG, + "Trimming memory of bg-ui " + app.processName + + " to " + level); app.thread.scheduleTrimMemory(level); } catch (RemoteException e) { } @@ -14830,6 +14829,9 @@ public final class ActivityManagerService extends ActivityManagerNative } if (app.trimMemoryLevel < fgTrimLevel && app.thread != null) { try { + if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG, + "Trimming memory of fg " + app.processName + + " to " + fgTrimLevel); app.thread.scheduleTrimMemory(fgTrimLevel); } catch (RemoteException e) { } @@ -14838,14 +14840,21 @@ public final class ActivityManagerService extends ActivityManagerNative } } } else { - final int N = mLruProcesses.size(); - for (i=0; i<N; i++) { + allChanged = mProcessTracker.setMemFactorLocked( + ProcessTracker.ADJ_MEM_FACTOR_NORMAL, !mSleeping, now); + for (int i=N-1; i>=0; i--) { ProcessRecord app = mLruProcesses.get(i); - if ((app.nonStoppingAdj > ProcessList.VISIBLE_APP_ADJ || app.systemNoUi) - && app.pendingUiClean) { + if (allChanged || app.procStateChanged) { + app.setProcessTrackerState(ProcessTracker.ADJ_MEM_FACTOR_NORMAL, now); + } + if ((app.curProcState >= ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND + || app.systemNoUi) && app.pendingUiClean) { if (app.trimMemoryLevel < ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN && app.thread != null) { try { + if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG, + "Trimming memory of ui hidden " + app.processName + + " to " + ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN); app.thread.scheduleTrimMemory( ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN); } catch (RemoteException e) { @@ -14863,16 +14872,6 @@ public final class ActivityManagerService extends ActivityManagerNative mStackSupervisor.scheduleDestroyAllActivities(null, "always-finish"); } - boolean allChanged = mProcessTracker.setMemFactorLocked(memFactor, !mSleeping, now); - if (changed || allChanged) { - memFactor = mProcessTracker.getMemFactorLocked(); - for (i=mLruProcesses.size()-1; i>=0; i--) { - ProcessRecord app = mLruProcesses.get(i); - if (allChanged || app.setAdjChanged) { - app.setProcessTrackerState(TOP_APP, memFactor, now, mProcessList); - } - } - } if (allChanged) { requestPssAllProcsLocked(now, false); } diff --git a/services/java/com/android/server/am/ActivityRecord.java b/services/java/com/android/server/am/ActivityRecord.java index e6849ed..b858755 100644 --- a/services/java/com/android/server/am/ActivityRecord.java +++ b/services/java/com/android/server/am/ActivityRecord.java @@ -339,6 +339,10 @@ final class ActivityRecord { } } + boolean isNotResolverActivity() { + return !ResolverActivity.class.getName().equals(realActivity.getClassName()); + } + ActivityRecord(ActivityManagerService _service, ProcessRecord _caller, int _launchedFromUid, String _launchedFromPackage, Intent _intent, String _resolvedType, ActivityInfo aInfo, Configuration _configuration, @@ -442,21 +446,22 @@ final class ActivityRecord { // If we know the system has determined the component, then // we can consider this to be a home activity... - // Note the last check is so we don't count the resolver - // activity as being home... really, we don't care about - // doing anything special with something that comes from - // the core framework package. - if ((!_componentSpecified || _launchedFromUid == Process.myUid() + String homePackageName = supervisor.getHomePackageName(); + if (homePackageName != null && homePackageName.equals(packageName)) { + mActivityType = HOME_ACTIVITY_TYPE; + } else if ((!_componentSpecified || _launchedFromUid == Process.myUid() || _launchedFromUid == 0) && Intent.ACTION_MAIN.equals(_intent.getAction()) && _intent.hasCategory(Intent.CATEGORY_HOME) && _intent.getCategories().size() == 1 && _intent.getData() == null && _intent.getType() == null && - (intent.getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 && - !ResolverActivity.class.getName().equals(realActivity.getClassName())) { + (intent.getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) { // This sure looks like a home activity! mActivityType = HOME_ACTIVITY_TYPE; + if (isNotResolverActivity()) { + supervisor.setHomePackageName(userId, packageName); + } } else if (realActivity.getClassName().contains("com.android.systemui.recent")) { mActivityType = RECENTS_ACTIVITY_TYPE; } else { diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java index a154b9c..dd71044 100644 --- a/services/java/com/android/server/am/ActivityStack.java +++ b/services/java/com/android/server/am/ActivityStack.java @@ -465,7 +465,9 @@ final class ActivityStack { * Returns the top activity in any existing task matching the given * Intent. Returns null if no such task is found. */ - ActivityRecord findTaskLocked(Intent intent, ActivityInfo info) { + ActivityRecord findTaskLocked(ActivityRecord target) { + Intent intent = target.intent; + ActivityInfo info = target.info; ComponentName cls = intent.getComponent(); if (info.targetActivity != null) { cls = new ComponentName(info.packageName, info.targetActivity); @@ -474,6 +476,10 @@ final class ActivityStack { for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) { final TaskRecord task = mTaskHistory.get(taskNdx); + if (task.userId != userId) { + // Looking for a different task. + continue; + } final ActivityRecord r = task.getTopActivity(); if (r == null || r.finishing || r.userId != userId || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) { @@ -518,7 +524,11 @@ final class ActivityStack { final int userId = UserHandle.getUserId(info.applicationInfo.uid); for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) { - final ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mActivities; + TaskRecord task = mTaskHistory.get(taskNdx); + if (task.userId != mCurrentUser) { + return null; + } + final ArrayList<ActivityRecord> activities = task.mActivities; for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) { ActivityRecord r = activities.get(activityNdx); if (!r.finishing && r.intent.getComponent().equals(cls) && r.userId == userId) { @@ -534,8 +544,7 @@ final class ActivityStack { } /* - * Move the activities around in the stack to bring a user to the foreground. This only - * matters on the home stack. All other stacks are single user. + * Move the activities around in the stack to bring a user to the foreground. * @return whether there are any activities for the specified user. */ final boolean switchUserLocked(int userId) { @@ -1089,6 +1098,9 @@ final class ActivityStack { case RESUMED: case PAUSING: case PAUSED: + // This case created for transitioning activities from + // translucent to opaque {@link Activity#convertToOpaque}. + mStackSupervisor.mStoppingActivities.remove(r); stopActivityLocked(r); break; @@ -1172,6 +1184,7 @@ final class ActivityStack { // There are no more activities! Let's just start up the // Launcher... ActivityOptions.abort(options); + if (DEBUG_STATES) Slog.d(TAG, "resumeTopActivityLocked: No more activities go home"); if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked(); return mStackSupervisor.resumeHomeActivity(prev); } @@ -1186,6 +1199,7 @@ final class ActivityStack { mWindowManager.executeAppTransition(); mNoAnimActivities.clear(); ActivityOptions.abort(options); + if (DEBUG_STATES) Slog.d(TAG, "resumeTopActivityLocked: Top activity resumed " + next); if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked(); return false; } @@ -1213,6 +1227,7 @@ final class ActivityStack { final int taskNdx = mTaskHistory.indexOf(prevTask) + 1; mTaskHistory.get(taskNdx).mActivities.get(0).mLaunchHomeTaskNext = true; } else { + if (DEBUG_STATES) Slog.d(TAG, "resumeTopActivityLocked: Launching home next"); return mStackSupervisor.resumeHomeActivity(prev); } } @@ -1227,6 +1242,7 @@ final class ActivityStack { mWindowManager.executeAppTransition(); mNoAnimActivities.clear(); ActivityOptions.abort(options); + if (DEBUG_STATES) Slog.d(TAG, "resumeTopActivityLocked: Going to sleep and all paused"); if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked(); return false; } @@ -1255,7 +1271,8 @@ final class ActivityStack { // If we are currently pausing an activity, then don't do anything // until that is done. if (!mStackSupervisor.allPausedActivitiesComplete()) { - if (DEBUG_SWITCH || DEBUG_PAUSE) Slog.v(TAG, "Skip resume: some activity pausing"); + if (DEBUG_SWITCH || DEBUG_PAUSE || DEBUG_STATES) Slog.v(TAG, + "resumeTopActivityLocked: Skip resume: some activity pausing."); if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked(); return false; } @@ -1295,9 +1312,11 @@ final class ActivityStack { if (mResumedActivity != null) { pausing = true; startPausingLocked(userLeaving, false); + if (DEBUG_STATES) Slog.d(TAG, "resumeTopActivityLocked: Pausing " + mResumedActivity); } if (pausing) { - if (DEBUG_SWITCH) Slog.v(TAG, "Skip resume: need to start pausing"); + if (DEBUG_SWITCH || DEBUG_STATES) Slog.v(TAG, + "resumeTopActivityLocked: Skip resume: need to start pausing"); // At this point we want to put the upcoming activity's process // at the top of the LRU list, since we know we will be needing it // very soon and it would be a waste to let it get killed if it @@ -1459,7 +1478,7 @@ final class ActivityStack { // is still at the top and schedule another run if something // weird happened. ActivityRecord nextNext = topRunningActivityLocked(null); - if (DEBUG_SWITCH) Slog.i(TAG, + if (DEBUG_SWITCH || DEBUG_STATES) Slog.i(TAG, "Activity config changed during resume: " + next + ", new next: " + nextNext); if (nextNext != next) { @@ -1505,6 +1524,7 @@ final class ActivityStack { mStackSupervisor.checkReadyForSleepLocked(); + if (DEBUG_STATES) Slog.d(TAG, "resumeTopActivityLocked: Resumed " + next); } catch (Exception e) { // Whoops, need to restart this activity! if (DEBUG_STATES) Slog.v(TAG, "Resume failed; resetting state to " @@ -1561,6 +1581,7 @@ final class ActivityStack { } if (DEBUG_SWITCH) Slog.v(TAG, "Restarting: " + next); } + if (DEBUG_STATES) Slog.d(TAG, "resumeTopActivityLocked: Restarting " + next); mStackSupervisor.startSpecificActivityLocked(next, true, true); } @@ -1568,6 +1589,21 @@ final class ActivityStack { return true; } + private void insertTaskAtTop(TaskRecord task) { + mTaskHistory.remove(task); + // Now put task at top. + int stackNdx = mTaskHistory.size(); + if (task.userId != mCurrentUser) { + // Put non-current user tasks below current user tasks. + while (--stackNdx >= 0) { + if (mTaskHistory.get(stackNdx).userId != mCurrentUser) { + break; + } + } + ++stackNdx; + } + mTaskHistory.add(stackNdx, task); + } final void startActivityLocked(ActivityRecord r, boolean newTask, boolean doResume, boolean keepCurTransition, Bundle options) { @@ -1577,9 +1613,7 @@ final class ActivityStack { // Last activity in task had been removed or ActivityManagerService is reusing task. // Insert or replace. // Might not even be in. - mTaskHistory.remove(rTask); - // Now put task at top. - mTaskHistory.add(rTask); + insertTaskAtTop(rTask); mWindowManager.moveTaskToTop(taskId); } TaskRecord task = null; @@ -1599,7 +1633,8 @@ final class ActivityStack { r.putInHistory(); mWindowManager.addAppToken(task.mActivities.indexOf(r), r.appToken, r.task.taskId, mStackId, r.info.screenOrientation, r.fullscreen, - (r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0); + (r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0, + r.userId); if (VALIDATE_TOKENS) { validateAppTokensLocked(); } @@ -1660,7 +1695,7 @@ final class ActivityStack { r.updateOptionsLocked(options); mWindowManager.addAppToken(task.mActivities.indexOf(r), r.appToken, r.task.taskId, mStackId, r.info.screenOrientation, r.fullscreen, - (r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0); + (r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0, r.userId); boolean doShow = true; if (newTask) { // Even though this activity is starting fresh, we still need @@ -1703,7 +1738,7 @@ final class ActivityStack { // because there is nothing for it to animate on top of. mWindowManager.addAppToken(task.mActivities.indexOf(r), r.appToken, r.task.taskId, mStackId, r.info.screenOrientation, r.fullscreen, - (r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0); + (r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0, r.userId); ActivityOptions.abort(options); } if (VALIDATE_TOKENS) { @@ -2897,8 +2932,7 @@ final class ActivityStack { // Shift all activities with this task up to the top // of the stack, keeping them in the same internal order. - mTaskHistory.remove(tr); - mTaskHistory.add(tr); + insertTaskAtTop(tr); if (DEBUG_TRANSITION) Slog.v(TAG, "Prepare to front transition: task=" + tr); if (reason != null && @@ -3380,7 +3414,7 @@ final class ActivityStack { printed |= ActivityStackSupervisor.dumpHistoryList(fd, pw, mTaskHistory.get(taskNdx).mActivities, " ", "Hist", true, !dumpAll, dumpClient, dumpPackage, needSep, header, - " Task " + taskNdx + ": id #" + task.taskId); + " Task id #" + task.taskId); if (printed) { header = null; } @@ -3448,12 +3482,8 @@ final class ActivityStack { } TaskRecord createTaskRecord(int taskId, ActivityInfo info, Intent intent, boolean toTop) { - TaskRecord task = new TaskRecord(taskId, info, intent, this); - if (toTop) { - mTaskHistory.add(task); - } else { - mTaskHistory.add(0, task); - } + TaskRecord task = new TaskRecord(taskId, info, intent); + addTask(task, toTop); return task; } @@ -3464,7 +3494,7 @@ final class ActivityStack { void addTask(final TaskRecord task, final boolean toTop) { task.stack = this; if (toTop) { - mTaskHistory.add(task); + insertTaskAtTop(task); } else { mTaskHistory.add(0, task); } diff --git a/services/java/com/android/server/am/ActivityStackSupervisor.java b/services/java/com/android/server/am/ActivityStackSupervisor.java index 8d1a665..925fb3f 100644 --- a/services/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/java/com/android/server/am/ActivityStackSupervisor.java @@ -185,9 +185,6 @@ public final class ActivityStackSupervisor { * is being brought in front of us. */ boolean mUserLeaving = false; - /** Stacks belonging to users other than mCurrentUser. Indexed by userId. */ - final SparseArray<UserState> mUserStates = new SparseArray<UserState>(); - /** Set when we have taken too long waiting to go to sleep. */ boolean mSleepTimeout = false; @@ -206,6 +203,12 @@ public final class ActivityStackSupervisor { */ final PowerManager.WakeLock mGoingToSleep; + /** + * The name of the current home activity for each user. + * TODO: Remove entries when user is deleted. + */ + final SparseArray<String> mHomePackageNames = new SparseArray<String>(); + public ActivityStackSupervisor(ActivityManagerService service, Context context, Looper looper) { mService = service; @@ -263,8 +266,7 @@ public final class ActivityStackSupervisor { } boolean isFrontStack(ActivityStack stack) { - return (stack.mCurrentUser == mCurrentUser) && - !(stack.isHomeStack() ^ getFocusedStack().isHomeStack()); + return !(stack.isHomeStack() ^ getFocusedStack().isHomeStack()); } void moveHomeStack(boolean toFront) { @@ -354,7 +356,7 @@ public final class ActivityStackSupervisor { final int stackId = stack.mStackId; final int nextStackId = mWindowManager.removeStack(stackId); // TODO: Perhaps we need to let the ActivityManager determine the next focus... - if (getFocusedStack().mStackId == stackId) { + if (mFocusedStack == null || mFocusedStack.mStackId == stackId) { // If this is the last app stack, set mFocusedStack to null. mFocusedStack = nextStackId == HOME_STACK_ID ? null : getStack(nextStackId); } @@ -467,6 +469,8 @@ public final class ActivityStackSupervisor { for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { final ActivityStack stack = mStacks.get(stackNdx); if (!isFrontStack(stack) && stack.mResumedActivity != null) { + if (DEBUG_STATES) Slog.d(TAG, "pauseBackStacks: stack=" + stack + + " mResumedActivity=" + stack.mResumedActivity); stack.startPausingLocked(userLeaving, false); someActivityPaused = true; } @@ -475,16 +479,22 @@ public final class ActivityStackSupervisor { } boolean allPausedActivitiesComplete() { + boolean pausing = true; for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { final ActivityStack stack = mStacks.get(stackNdx); final ActivityRecord r = stack.mPausingActivity; if (r != null && r.state != ActivityState.PAUSED && r.state != ActivityState.STOPPED && r.state != ActivityState.STOPPING) { - return false; + if (DEBUG_STATES) { + Slog.d(TAG, "allPausedActivitiesComplete: r=" + r + " state=" + r.state); + pausing = false; + } else { + return false; + } } } - return true; + return pausing; } void reportActivityVisibleLocked(ActivityRecord r) { @@ -524,8 +534,7 @@ public final class ActivityStackSupervisor { for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { final ActivityStack stack = mStacks.get(stackNdx); - if (stack.mCurrentUser == mCurrentUser && stack != focusedStack && - isFrontStack(stack)) { + if (stack != focusedStack && isFrontStack(stack)) { r = stack.topRunningActivityLocked(null); if (r != null) { return r; @@ -895,7 +904,7 @@ public final class ActivityStackSupervisor { r.userId, System.identityHashCode(r), r.task.taskId, r.shortComponentName); } - if (r.isHomeActivity()) { + if (r.isHomeActivity() && r.isNotResolverActivity()) { mService.mHomeProcess = app; } mService.ensurePackageDexOpt(r.intent.getComponent().getPackageName()); @@ -1216,28 +1225,43 @@ public final class ActivityStackSupervisor { return err; } - ActivityStack getCorrectStack(ActivityRecord r) { + ActivityStack adjustStackFocus(ActivityRecord r) { final TaskRecord task = r.task; if (r.isApplicationActivity() || (task != null && task.isApplicationTask())) { - int stackNdx; - for (stackNdx = mStacks.size() - 1; stackNdx > 0; --stackNdx) { - if (mStacks.get(stackNdx).mCurrentUser == mCurrentUser) { - break; + if (task != null) { + if (mFocusedStack != task.stack) { + if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG, + "adjustStackFocus: Setting focused stack to r=" + r + " task=" + task); + mFocusedStack = task.stack; + } else { + if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG, + "adjustStackFocus: Focused stack already=" + mFocusedStack); } + return mFocusedStack; } - if (stackNdx == 0) { - // Time to create the first app stack for this user. - int stackId = mService.createStack(-1, HOME_STACK_ID, - StackBox.TASK_STACK_GOES_OVER, 1.0f); - if (DEBUG_FOCUS) Slog.d(TAG, "getCorrectStack: New stack r=" + r + " stackId=" - + stackId); - mFocusedStack = getStack(stackId); + + if (mFocusedStack != null) { + if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG, + "adjustStackFocus: Have a focused stack=" + mFocusedStack); + return mFocusedStack; } - if (task != null) { - if (DEBUG_FOCUS) Slog.d(TAG, "getCorrectStack: Setting focused stack to r=" + - r + " task=" + task); - mFocusedStack = task.stack; + + for (int stackNdx = mStacks.size() - 1; stackNdx > 0; --stackNdx) { + ActivityStack stack = mStacks.get(stackNdx); + if (!stack.isHomeStack()) { + if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG, + "adjustStackFocus: Setting focused stack=" + stack); + mFocusedStack = stack; + return mFocusedStack; + } } + + // Time to create the first app stack for this user. + int stackId = mService.createStack(-1, HOME_STACK_ID, + StackBox.TASK_STACK_GOES_OVER, 1.0f); + if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG, "adjustStackFocus: New stack r=" + r + + " stackId=" + stackId); + mFocusedStack = getStack(stackId); return mFocusedStack; } return mHomeStack; @@ -1256,8 +1280,9 @@ public final class ActivityStackSupervisor { mStackState = STACK_STATE_HOME_TO_FRONT; } } else { - if (DEBUG_FOCUS) Slog.d(TAG, "setFocusedStack: Setting focused stack to r=" + - r + " task=" + r.task + " Callers=" + Debug.getCallers(3)); + if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG, + "setFocusedStack: Setting focused stack to r=" + r + " task=" + r.task + + " Callers=" + Debug.getCallers(3)); mFocusedStack = r.task.stack; if (mStackState != STACK_STATE_HOME_IN_BACK) { if (DEBUG_STACK) Slog.d(TAG, "setFocusedStack: mStackState old=" + @@ -1366,7 +1391,7 @@ public final class ActivityStackSupervisor { // instance of it in the history, and it is always in its own // unique task, so we do a special search. ActivityRecord intentActivity = r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE - ? findTaskLocked(intent, r.info) + ? findTaskLocked(r) : findActivityLocked(intent, r.info); if (intentActivity != null) { if (r.task == null) { @@ -1592,7 +1617,7 @@ public final class ActivityStackSupervisor { // Should this be considered a new task? if (r.resultTo == null && !addingToTask && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) { - targetStack = getCorrectStack(r); + targetStack = adjustStackFocus(r); moveHomeStack(targetStack.isHomeStack()); if (reuseTask == null) { r.setTask(targetStack.createTaskRecord(getNextTaskId(), r.info, intent, true), @@ -1671,7 +1696,7 @@ public final class ActivityStackSupervisor { // This not being started from an existing activity, and not part // of a new task... just put it in the top task, though these days // this case should never happen. - targetStack = getCorrectStack(r); + targetStack = adjustStackFocus(r); moveHomeStack(targetStack.isHomeStack()); ActivityRecord prev = targetStack.topActivity(); r.setTask(prev != null ? prev.task @@ -2009,9 +2034,13 @@ public final class ActivityStackSupervisor { resumeTopActivitiesLocked(); } - ActivityRecord findTaskLocked(Intent intent, ActivityInfo info) { + ActivityRecord findTaskLocked(ActivityRecord r) { for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { - final ActivityRecord ar = mStacks.get(stackNdx).findTaskLocked(intent, info); + final ActivityStack stack = mStacks.get(stackNdx); + if (!r.isApplicationActivity() && !stack.isHomeStack()) { + continue; + } + final ActivityRecord ar = stack.findTaskLocked(r); if (ar != null) { return ar; } @@ -2193,21 +2222,18 @@ public final class ActivityStackSupervisor { } boolean switchUserLocked(int userId, UserStartedState uss) { - mUserStates.put(mCurrentUser, new UserState()); mCurrentUser = userId; - UserState userState = mUserStates.get(userId); - if (userState != null) { - userState.restore(); - mUserStates.delete(userId); - } else { - mFocusedStack = null; - if (DEBUG_STACK) Slog.d(TAG, "switchUserLocked: mStackState=" + - stackStateToString(STACK_STATE_HOME_IN_FRONT)); - mStackState = STACK_STATE_HOME_IN_FRONT; + + final String homePackageName = mService.getHomePackageName(); + if (homePackageName != null) { + setHomePackageName(mCurrentUser, homePackageName); } mStartingUsers.add(uss); - boolean haveActivities = mHomeStack.switchUserLocked(userId); + boolean haveActivities = false; + for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { + haveActivities |= mStacks.get(stackNdx).switchUserLocked(userId); + } resumeTopActivitiesLocked(); @@ -2304,6 +2330,12 @@ public final class ActivityStackSupervisor { pw.print(prefix); pw.print("mStackState="); pw.println(stackStateToString(mStackState)); pw.print(prefix); pw.println("mSleepTimeout: " + mSleepTimeout); pw.print(prefix); pw.println("mCurTaskId: " + mCurTaskId); + pw.print(prefix); pw.print("mHomePackageNames:"); + for (int i = 0; i < mHomePackageNames.size(); ++i) { + pw.print(" ("); pw.print(mHomePackageNames.keyAt(i)); pw.print(","); + pw.print(mHomePackageNames.valueAt(i)); pw.print(")"); + } + pw.println(); } ArrayList<ActivityRecord> getDumpActivitiesLocked(String name) { @@ -2558,22 +2590,13 @@ public final class ActivityStackSupervisor { } } - private final class UserState { - final ActivityStack mSavedFocusedStack; - final int mSavedStackState; - - public UserState() { - ActivityStackSupervisor supervisor = ActivityStackSupervisor.this; - mSavedFocusedStack = supervisor.mFocusedStack; - mSavedStackState = supervisor.mStackState; - } + String getHomePackageName() { + return mHomePackageNames.get(mCurrentUser); + } - void restore() { - ActivityStackSupervisor supervisor = ActivityStackSupervisor.this; - supervisor.mFocusedStack = mSavedFocusedStack; - if (DEBUG_STACK) Slog.d(TAG, "UserState.restore: mStackState old=" + - stackStateToString(mSavedStackState)); - supervisor.mStackState = mSavedStackState; - } + void setHomePackageName(int userId, String homePackageName) { + if (DEBUG_SWITCH) Slog.d(TAG, "setHomePackageName: user=" + userId + " package=" + + homePackageName); + mHomePackageNames.put(userId, homePackageName); } } diff --git a/services/java/com/android/server/am/ConnectionRecord.java b/services/java/com/android/server/am/ConnectionRecord.java index dd81493..576adc2 100644 --- a/services/java/com/android/server/am/ConnectionRecord.java +++ b/services/java/com/android/server/am/ConnectionRecord.java @@ -89,12 +89,15 @@ final class ConnectionRecord { if ((flags&Context.BIND_ADJUST_WITH_ACTIVITY) != 0) { sb.append("ACT "); } - if ((flags&Context.BIND_NOT_VISIBLE) != 0) { - sb.append("!VIS "); - } if ((flags&Context.BIND_VISIBLE) != 0) { sb.append("VIS "); } + if ((flags&Context.BIND_SHOWING_UI) != 0) { + sb.append("UI "); + } + if ((flags&Context.BIND_NOT_VISIBLE) != 0) { + sb.append("!VIS "); + } if (serviceDead) { sb.append("DEAD "); } diff --git a/services/java/com/android/server/am/IntentBindRecord.java b/services/java/com/android/server/am/IntentBindRecord.java index 6c84b9f..21cf266 100644 --- a/services/java/com/android/server/am/IntentBindRecord.java +++ b/services/java/com/android/server/am/IntentBindRecord.java @@ -19,6 +19,7 @@ package com.android.server.am; import android.content.Context; import android.content.Intent; import android.os.IBinder; +import android.util.ArrayMap; import java.io.PrintWriter; import java.util.HashMap; @@ -33,8 +34,8 @@ final class IntentBindRecord { /** The intent that is bound.*/ final Intent.FilterComparison intent; // /** All apps that have bound to this Intent. */ - final HashMap<ProcessRecord, AppBindRecord> apps - = new HashMap<ProcessRecord, AppBindRecord>(); + final ArrayMap<ProcessRecord, AppBindRecord> apps + = new ArrayMap<ProcessRecord, AppBindRecord>(); /** Binder published from service. */ IBinder binder; /** Set when we have initiated a request for this binder. */ @@ -62,15 +63,12 @@ final class IntentBindRecord { pw.print(" received="); pw.print(received); pw.print(" hasBound="); pw.print(hasBound); pw.print(" doRebind="); pw.println(doRebind); - if (apps.size() > 0) { - Iterator<AppBindRecord> it = apps.values().iterator(); - while (it.hasNext()) { - AppBindRecord a = it.next(); - pw.print(prefix); pw.print("* Client AppBindRecord{"); - pw.print(Integer.toHexString(System.identityHashCode(a))); - pw.print(' '); pw.print(a.client); pw.println('}'); - a.dumpInIntentBind(pw, prefix + " "); - } + for (int i=0; i<apps.size(); i++) { + AppBindRecord a = apps.valueAt(i); + pw.print(prefix); pw.print("* Client AppBindRecord{"); + pw.print(Integer.toHexString(System.identityHashCode(a))); + pw.print(' '); pw.print(a.client); pw.println('}'); + a.dumpInIntentBind(pw, prefix + " "); } } @@ -81,12 +79,11 @@ final class IntentBindRecord { int collectFlags() { int flags = 0; - if (apps.size() > 0) { - for (AppBindRecord app : apps.values()) { - if (app.connections.size() > 0) { - for (ConnectionRecord conn : app.connections) { - flags |= conn.flags; - } + for (int i=apps.size()-1; i>=0; i--) { + AppBindRecord app = apps.valueAt(i); + if (app.connections.size() > 0) { + for (ConnectionRecord conn : app.connections) { + flags |= conn.flags; } } } diff --git a/services/java/com/android/server/am/ProcessList.java b/services/java/com/android/server/am/ProcessList.java index 6a72e44..106ba22 100644 --- a/services/java/com/android/server/am/ProcessList.java +++ b/services/java/com/android/server/am/ProcessList.java @@ -36,6 +36,11 @@ final class ProcessList { // OOM adjustments for processes in various states: + // Adjustment used in certain places where we don't know it yet. + // (Generally this is something that is going to be cached, but we + // don't know the exact value in the cached range to assign yet.) + static final int UNKNOWN_ADJ = 16; + // This is a process only hosting activities that are not visible, // so it can be killed without any disruption. static final int CACHED_APP_MAX_ADJ = 15; @@ -62,14 +67,14 @@ final class ProcessList { // have much of an impact as far as the user is concerned. static final int SERVICE_ADJ = 5; - // This is a process currently hosting a backup operation. Killing it - // is not entirely fatal but is generally a bad idea. - static final int BACKUP_APP_ADJ = 4; - // This is a process with a heavy-weight application. It is in the // background, but we want to try to avoid killing it. Value set in // system/rootdir/init.rc on startup. - static final int HEAVY_WEIGHT_APP_ADJ = 3; + static final int HEAVY_WEIGHT_APP_ADJ = 4; + + // This is a process currently hosting a backup operation. Killing it + // is not entirely fatal but is generally a bad idea. + static final int BACKUP_APP_ADJ = 3; // This is a process only hosting components that are perceptible to the // user, and we really want to avoid killing them, but they are not @@ -163,40 +168,17 @@ final class ProcessList { private boolean mHaveDisplaySize; - private final int[] mAdjToTrackedState = new int[CACHED_APP_MAX_ADJ+1]; - ProcessList() { MemInfoReader minfo = new MemInfoReader(); minfo.readMemInfo(); mTotalMemMb = minfo.getTotalSize()/(1024*1024); updateOomLevels(0, 0, false); - for (int i=0; i<=CACHED_APP_MAX_ADJ; i++) { - if (i <= FOREGROUND_APP_ADJ) { - mAdjToTrackedState[i] = ProcessTracker.STATE_FOREGROUND; - } else if (i <= VISIBLE_APP_ADJ) { - mAdjToTrackedState[i] = ProcessTracker.STATE_VISIBLE; - } else if (i <= PERCEPTIBLE_APP_ADJ) { - mAdjToTrackedState[i] = ProcessTracker.STATE_PERCEPTIBLE; - } else if (i <= BACKUP_APP_ADJ) { - mAdjToTrackedState[i] = ProcessTracker.STATE_BACKUP; - } else if (i <= SERVICE_ADJ) { - mAdjToTrackedState[i] = ProcessTracker.STATE_SERVICE; - } else if (i <= HOME_APP_ADJ) { - mAdjToTrackedState[i] = ProcessTracker.STATE_HOME; - } else if (i <= PREVIOUS_APP_ADJ) { - mAdjToTrackedState[i] = ProcessTracker.STATE_PREVIOUS; - } else if (i <= SERVICE_B_ADJ) { - mAdjToTrackedState[i] = ProcessTracker.STATE_SERVICE; - } else { - mAdjToTrackedState[i] = ProcessTracker.STATE_CACHED; - } - } } void applyDisplaySize(WindowManagerService wm) { if (!mHaveDisplaySize) { Point p = new Point(); - wm.getInitialDisplaySize(Display.DEFAULT_DISPLAY, p); + wm.getBaseDisplaySize(Display.DEFAULT_DISPLAY, p); if (p.x != 0 && p.y != 0) { updateOomLevels(p.x, p.y, true); mHaveDisplaySize = true; @@ -256,11 +238,6 @@ final class ProcessList { return mOomMinFree[mOomAdj.length-1] * 1024; } - int adjToTrackedState(int adj) { - return adj >= FOREGROUND_APP_ADJ - ? mAdjToTrackedState[adj] : ProcessTracker.STATE_PERSISTENT; - } - private void writeFile(String path, String data) { FileOutputStream fos = null; try { diff --git a/services/java/com/android/server/am/ProcessRecord.java b/services/java/com/android/server/am/ProcessRecord.java index cb9a76d..1b45d30 100644 --- a/services/java/com/android/server/am/ProcessRecord.java +++ b/services/java/com/android/server/am/ProcessRecord.java @@ -16,6 +16,7 @@ package com.android.server.am; +import android.util.ArraySet; import com.android.internal.os.BatteryStatsImpl; import android.app.ActivityManager; @@ -64,12 +65,8 @@ final class ProcessRecord { long lruWeight; // Weight for ordering in LRU list long lastPssTime; // Last time we requested PSS data int maxAdj; // Maximum OOM adjustment for this process - int cachedAdj; // If cached, this is the adjustment to use - int clientCachedAdj; // If empty but cached client, this is the adjustment to use - int emptyAdj; // If empty, this is the adjustment to use int curRawAdj; // Current OOM unlimited adjustment for this process int setRawAdj; // Last set OOM unlimited adjustment for this process - int nonStoppingAdj; // Adjustment not counting any stopping activities int curAdj; // Current OOM adjustment for this process int setAdj; // Last set OOM adjustment for this process int curSchedGroup; // Currently desired scheduling class @@ -78,6 +75,7 @@ final class ProcessRecord { int memImportance; // Importance constant computed from curAdj int curProcState = -1; // Currently computed process state: ActivityManager.PROCESS_STATE_* int repProcState = -1; // Last reported process state + int setProcState = -1; // Last set process state in process tracker boolean serviceb; // Process currently is on the service B list boolean keeping; // Actively running code so don't kill due to that? boolean setIsForeground; // Running foreground UI when last set? @@ -92,7 +90,7 @@ final class ProcessRecord { boolean hasAboveClient; // Bound using BIND_ABOVE_CLIENT, so want to be lower boolean bad; // True if disabled in the bad process list boolean killedBackground; // True when proc has been killed due to too many bg - boolean setAdjChanged; // Keep track of whether we changed 'setAdj'. + boolean procStateChanged; // Keep track of whether we changed 'setAdj'. String waitingToKill; // Process is waiting to be killed when in the bg; reason IBinder forcingToForeground;// Token that is forcing this process to be foreground int adjSeq; // Sequence id for identifying oom_adj assignment cycles @@ -125,15 +123,15 @@ final class ProcessRecord { // contains HistoryRecord objects final ArrayList<ActivityRecord> activities = new ArrayList<ActivityRecord>(); // all ServiceRecord running in this process - final HashSet<ServiceRecord> services = new HashSet<ServiceRecord>(); + final ArraySet<ServiceRecord> services = new ArraySet<ServiceRecord>(); // services that are currently executing code (need to remain foreground). - final HashSet<ServiceRecord> executingServices - = new HashSet<ServiceRecord>(); + final ArraySet<ServiceRecord> executingServices + = new ArraySet<ServiceRecord>(); // All ConnectionRecord this process holds - final HashSet<ConnectionRecord> connections - = new HashSet<ConnectionRecord>(); + final ArraySet<ConnectionRecord> connections + = new ArraySet<ConnectionRecord>(); // all IIntentReceivers that are registered from this process. - final HashSet<ReceiverList> receivers = new HashSet<ReceiverList>(); + final ArraySet<ReceiverList> receivers = new ArraySet<ReceiverList>(); // class (String) -> ContentProviderRecord final ArrayMap<String, ContentProviderRecord> pubProviders = new ArrayMap<String, ContentProviderRecord>(); @@ -209,18 +207,14 @@ final class ProcessRecord { pw.println(starting); pw.print(prefix); pw.print("lastActivityTime="); TimeUtils.formatDuration(lastActivityTime, now, pw); - pw.print(" lruWeight="); pw.print(lruWeight); - pw.print(" serviceb="); pw.print(serviceb); + pw.print(" lruWeight="); pw.println(lruWeight); + pw.print(prefix); pw.print("serviceb="); pw.print(serviceb); pw.print(" keeping="); pw.print(keeping); pw.print(" cached="); pw.print(cached); pw.print(" empty="); pw.println(empty); pw.print(prefix); pw.print("oom: max="); pw.print(maxAdj); - pw.print(" cached="); pw.print(cachedAdj); - pw.print(" client="); pw.print(clientCachedAdj); - pw.print(" empty="); pw.print(emptyAdj); pw.print(" curRaw="); pw.print(curRawAdj); pw.print(" setRaw="); pw.print(setRawAdj); - pw.print(" nonStopping="); pw.print(nonStoppingAdj); pw.print(" cur="); pw.print(curAdj); pw.print(" set="); pw.println(setAdj); pw.print(prefix); pw.print("curSchedGroup="); pw.print(curSchedGroup); @@ -228,7 +222,8 @@ final class ProcessRecord { pw.print(" systemNoUi="); pw.print(systemNoUi); pw.print(" trimMemoryLevel="); pw.println(trimMemoryLevel); pw.print(prefix); pw.print("curProcState="); pw.print(curProcState); - pw.print(" repProcState="); pw.println(repProcState); + pw.print(" repProcState="); pw.print(repProcState); + pw.print(" setProcState="); pw.println(setProcState); pw.print(prefix); pw.print("adjSeq="); pw.print(adjSeq); pw.print(" lruSeq="); pw.print(lruSeq); pw.print(" lastPssTime="); pw.println(lastPssTime); @@ -301,20 +296,20 @@ final class ProcessRecord { } if (services.size() > 0) { pw.print(prefix); pw.println("Services:"); - for (ServiceRecord sr : services) { - pw.print(prefix); pw.print(" - "); pw.println(sr); + for (int i=0; i<services.size(); i++) { + pw.print(prefix); pw.print(" - "); pw.println(services.valueAt(i)); } } if (executingServices.size() > 0) { pw.print(prefix); pw.println("Executing Services:"); - for (ServiceRecord sr : executingServices) { - pw.print(prefix); pw.print(" - "); pw.println(sr); + for (int i=0; i<executingServices.size(); i++) { + pw.print(prefix); pw.print(" - "); pw.println(executingServices.valueAt(i)); } } if (connections.size() > 0) { pw.print(prefix); pw.println("Connections:"); - for (ConnectionRecord cr : connections) { - pw.print(prefix); pw.print(" - "); pw.println(cr); + for (int i=0; i<connections.size(); i++) { + pw.print(prefix); pw.print(" - "); pw.println(connections.valueAt(i)); } } if (pubProviders.size() > 0) { @@ -335,8 +330,8 @@ final class ProcessRecord { } if (receivers.size() > 0) { pw.print(prefix); pw.println("Receivers:"); - for (ReceiverList rl : receivers) { - pw.print(prefix); pw.print(" - "); pw.println(rl); + for (int i=0; i<receivers.size(); i++) { + pw.print(prefix); pw.print(" - "); pw.println(receivers.valueAt(i)); } } } @@ -353,8 +348,7 @@ final class ProcessRecord { baseProcessTracker = tracker; pkgList.put(_info.packageName, tracker); thread = _thread; - maxAdj = ProcessList.CACHED_APP_MAX_ADJ; - cachedAdj = clientCachedAdj = emptyAdj = ProcessList.CACHED_APP_MIN_ADJ; + maxAdj = ProcessList.UNKNOWN_ADJ; curRawAdj = setRawAdj = -100; curAdj = setAdj = -100; persistent = false; @@ -400,14 +394,35 @@ final class ProcessRecord { void updateHasAboveClientLocked() { hasAboveClient = false; - if (connections.size() > 0) { - for (ConnectionRecord cr : connections) { - if ((cr.flags&Context.BIND_ABOVE_CLIENT) != 0) { - hasAboveClient = true; - break; - } + for (int i=connections.size()-1; i>=0; i--) { + ConnectionRecord cr = connections.valueAt(i); + if ((cr.flags&Context.BIND_ABOVE_CLIENT) != 0) { + hasAboveClient = true; + break; + } + } + } + + int modifyRawOomAdj(int adj) { + if (hasAboveClient) { + // If this process has bound to any services with BIND_ABOVE_CLIENT, + // then we need to drop its adjustment to be lower than the service's + // in order to honor the request. We want to drop it by one adjustment + // level... but there is special meaning applied to various levels so + // we will skip some of them. + if (adj < ProcessList.FOREGROUND_APP_ADJ) { + // System process will not get dropped, ever + } else if (adj < ProcessList.VISIBLE_APP_ADJ) { + adj = ProcessList.VISIBLE_APP_ADJ; + } else if (adj < ProcessList.PERCEPTIBLE_APP_ADJ) { + adj = ProcessList.PERCEPTIBLE_APP_ADJ; + } else if (adj < ProcessList.CACHED_APP_MIN_ADJ) { + adj = ProcessList.CACHED_APP_MIN_ADJ; + } else if (adj < ProcessList.CACHED_APP_MAX_ADJ) { + adj++; } } + return adj; } public String toShortString() { @@ -483,11 +498,8 @@ final class ProcessRecord { } } - public void setProcessTrackerState(ProcessRecord TOP_APP, int memFactor, long now, - ProcessList plist) { - int state = this == TOP_APP ? ProcessTracker.STATE_TOP - : plist.adjToTrackedState(getSetAdjWithServices()); - baseProcessTracker.setState(state, memFactor, now, pkgList); + public void setProcessTrackerState(int memFactor, long now) { + baseProcessTracker.setState(repProcState, memFactor, now, pkgList); } /* diff --git a/services/java/com/android/server/am/ProcessTracker.java b/services/java/com/android/server/am/ProcessTracker.java index 0ea93e8..ef032ba 100644 --- a/services/java/com/android/server/am/ProcessTracker.java +++ b/services/java/com/android/server/am/ProcessTracker.java @@ -52,26 +52,34 @@ public final class ProcessTracker { public static final int STATE_NOTHING = -1; public static final int STATE_PERSISTENT = 0; public static final int STATE_TOP = 1; - public static final int STATE_FOREGROUND = 2; - public static final int STATE_VISIBLE = 3; - public static final int STATE_PERCEPTIBLE = 4; - public static final int STATE_BACKUP = 5; + public static final int STATE_IMPORTANT_FOREGROUND = 2; + public static final int STATE_IMPORTANT_BACKGROUND = 3; + public static final int STATE_BACKUP = 4; + public static final int STATE_HEAVY_WEIGHT = 5; public static final int STATE_SERVICE = 6; - public static final int STATE_HOME = 7; - public static final int STATE_PREVIOUS = 8; - public static final int STATE_CACHED = 9; - public static final int STATE_COUNT = STATE_CACHED+1; - - static final int[] ALL_PROC_STATES = new int[] { STATE_PERSISTENT, STATE_TOP, - STATE_FOREGROUND, STATE_VISIBLE, STATE_PERCEPTIBLE, STATE_BACKUP, - STATE_SERVICE, STATE_HOME, STATE_PREVIOUS, STATE_CACHED + public static final int STATE_RECEIVER = 7; + public static final int STATE_HOME = 8; + public static final int STATE_LAST_ACTIVITY = 9; + public static final int STATE_CACHED_ACTIVITY = 10; + public static final int STATE_CACHED_ACTIVITY_CLIENT = 11; + public static final int STATE_CACHED_EMPTY = 12; + public static final int STATE_COUNT = STATE_CACHED_EMPTY+1; + + static final int[] ALL_PROC_STATES = new int[] { STATE_PERSISTENT, + STATE_TOP, STATE_IMPORTANT_FOREGROUND, STATE_IMPORTANT_BACKGROUND, + STATE_BACKUP, STATE_HEAVY_WEIGHT, STATE_SERVICE, STATE_RECEIVER, + STATE_HOME, STATE_LAST_ACTIVITY, STATE_CACHED_ACTIVITY, + STATE_CACHED_ACTIVITY_CLIENT, STATE_CACHED_EMPTY }; public static final int PSS_SAMPLE_COUNT = 0; public static final int PSS_MINIMUM = 1; public static final int PSS_AVERAGE = 2; public static final int PSS_MAXIMUM = 3; - public static final int PSS_COUNT = PSS_MAXIMUM+1; + public static final int PSS_USS_MINIMUM = 4; + public static final int PSS_USS_AVERAGE = 5; + public static final int PSS_USS_MAXIMUM = 6; + public static final int PSS_COUNT = PSS_USS_MAXIMUM+1; public static final int ADJ_NOTHING = -1; public static final int ADJ_MEM_FACTOR_NORMAL = 0; @@ -106,8 +114,9 @@ public final class ProcessTracker { static int OFFSET_INDEX_MASK = 0xffff; static final String[] STATE_NAMES = new String[] { - "Persistent ", "Top ", "Foreground ", "Visible ", "Perceptible", - "Backup ", "Service ", "Home ", "Previous ", "Cached " + "Persistent", "Top ", "Imp Fg ", "Imp Bg ", + "Backup ", "Heavy Wght", "Service ", "Receiver ", "Home ", + "Last Act ", "Cch Actvty", "Cch Client", "Cch Empty " }; static final String[] ADJ_SCREEN_NAMES_CSV = new String[] { @@ -119,8 +128,9 @@ public final class ProcessTracker { }; static final String[] STATE_NAMES_CSV = new String[] { - "pers", "top", "fore", "vis", "percept", - "backup", "service", "home", "prev", "cached" + "pers", "top", "impfg", "impbg", "backup", "heavy", + "service", "receiver", "home", "lastact", + "cch-activity", "cch-aclient", "cch-empty" }; static final String[] ADJ_SCREEN_TAGS = new String[] { @@ -132,8 +142,26 @@ public final class ProcessTracker { }; static final String[] STATE_TAGS = new String[] { - "y", "t", "f", "v", "r", - "b", "s", "h", "p", "c" + "p", "t", "f", "b", "u", "w", + "s", "r", "h", "l", "a", "c", "e" + }; + + // Map from process states to the states we track. + static final int[] PROCESS_STATE_TO_STATE = new int[] { + STATE_PERSISTENT, // ActivityManager.PROCESS_STATE_PERSISTENT + STATE_PERSISTENT, // ActivityManager.PROCESS_STATE_PERSISTENT_UI + STATE_TOP, // ActivityManager.PROCESS_STATE_TOP + STATE_IMPORTANT_FOREGROUND, // ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND + STATE_IMPORTANT_BACKGROUND, // ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND + STATE_BACKUP, // ActivityManager.PROCESS_STATE_BACKUP + STATE_HEAVY_WEIGHT, // ActivityManager.PROCESS_STATE_HEAVY_WEIGHT + STATE_SERVICE, // ActivityManager.PROCESS_STATE_SERVICE + STATE_RECEIVER, // ActivityManager.PROCESS_STATE_RECEIVER + STATE_HOME, // ActivityManager.PROCESS_STATE_HOME + STATE_LAST_ACTIVITY, // ActivityManager.PROCESS_STATE_LAST_ACTIVITY + STATE_CACHED_ACTIVITY, // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY + STATE_CACHED_ACTIVITY_CLIENT, // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT + STATE_CACHED_EMPTY, // ActivityManager.PROCESS_STATE_CACHED_EMPTY }; static final String CSV_SEP = "\t"; @@ -322,10 +350,20 @@ public final class ProcessTracker { return true; } + /** + * Update the current state of the given list of processes. + * + * @param state Current ActivityManager.PROCESS_STATE_* + * @param memFactor Current mem factor constant. + * @param now Current time. + * @param pkgList Processes to update. + */ public void setState(int state, int memFactor, long now, ArrayMap<String, ProcessTracker.ProcessState> pkgList) { - if (state != STATE_NOTHING) { - state += memFactor*STATE_COUNT; + if (state < 0) { + state = STATE_NOTHING; + } else { + state = PROCESS_STATE_TO_STATE[state] + (memFactor*STATE_COUNT); } // First update the common process. @@ -370,7 +408,7 @@ public final class ProcessTracker { mStartTime = now; } - public void addPss(long pss, boolean always) { + public void addPss(long pss, long uss, boolean always) { if (!always) { if (mLastPssState == mCurState && SystemClock.uptimeMillis() < (mLastPssTime+(30*1000))) { @@ -399,16 +437,27 @@ public final class ProcessTracker { longs[idx+PSS_MINIMUM] = pss; longs[idx+PSS_AVERAGE] = pss; longs[idx+PSS_MAXIMUM] = pss; + longs[idx+PSS_USS_MINIMUM] = uss; + longs[idx+PSS_USS_AVERAGE] = uss; + longs[idx+PSS_USS_MAXIMUM] = uss; } else { longs[idx+PSS_SAMPLE_COUNT] = count+1; if (longs[idx+PSS_MINIMUM] > pss) { longs[idx+PSS_MINIMUM] = pss; } - longs[idx+PSS_AVERAGE] = (long)( ((longs[idx+PSS_AVERAGE]*(double)count)+pss) - / (count+1) ); + longs[idx+PSS_AVERAGE] = (long)( + ((longs[idx+PSS_AVERAGE]*(double)count)+pss) / (count+1) ); if (longs[idx+PSS_MAXIMUM] < pss) { longs[idx+PSS_MAXIMUM] = pss; } + if (longs[idx+PSS_USS_MINIMUM] > uss) { + longs[idx+PSS_USS_MINIMUM] = uss; + } + longs[idx+PSS_USS_AVERAGE] = (long)( + ((longs[idx+PSS_USS_AVERAGE]*(double)count)+uss) / (count+1) ); + if (longs[idx+PSS_USS_MAXIMUM] < uss) { + longs[idx+PSS_USS_MAXIMUM] = uss; + } } } } @@ -480,6 +529,21 @@ public final class ProcessTracker { int idx = State.binarySearch(mPssTable, mPssTableSize, state); return idx >= 0 ? mState.getLong(mPssTable[idx], PSS_MAXIMUM) : 0; } + + long getPssUssMinimum(int state) { + int idx = State.binarySearch(mPssTable, mPssTableSize, state); + return idx >= 0 ? mState.getLong(mPssTable[idx], PSS_USS_MINIMUM) : 0; + } + + long getPssUssAverage(int state) { + int idx = State.binarySearch(mPssTable, mPssTableSize, state); + return idx >= 0 ? mState.getLong(mPssTable[idx], PSS_USS_AVERAGE) : 0; + } + + long getPssUssMaximum(int state) { + int idx = State.binarySearch(mPssTable, mPssTableSize, state); + return idx >= 0 ? mState.getLong(mPssTable[idx], PSS_USS_MAXIMUM) : 0; + } } public static final class ServiceState { @@ -589,10 +653,13 @@ public final class ProcessTracker { static final class State { // Current version of the parcel format. - private static final int PARCEL_VERSION = 3; + private static final int PARCEL_VERSION = 6; // In-memory Parcel magic number, used to detect attempts to unmarshall bad data private static final int MAGIC = 0x50535453; + static final int FLAG_COMPLETE = 1<<0; + static final int FLAG_SHUTDOWN = 1<<1; + final File mBaseDir; final ProcessTracker mProcessTracker; AtomicFile mFile; @@ -603,6 +670,7 @@ public final class ProcessTracker { long mTimePeriodStartRealtime; long mTimePeriodEndRealtime; boolean mRunning; + int mFlags; final ProcessMap<PackageState> mPackages = new ProcessMap<PackageState>(); final ProcessMap<ProcessState> mProcesses = new ProcessMap<ProcessState>(); @@ -690,6 +758,7 @@ public final class ProcessTracker { Arrays.fill(mMemFactorDurations, 0); mMemFactor = STATE_NOTHING; mStartTime = 0; + mReadError = null; } private void buildTimePeriodStartClockStr() { @@ -724,7 +793,7 @@ public final class ProcessTracker { } } - void readLocked() { + boolean readLocked() { try { FileInputStream stream = mFile.openRead(); @@ -770,11 +839,14 @@ public final class ProcessTracker { } } } + return false; } } catch (Throwable e) { - mReadError = "error reading: " + e; + mReadError = "caught exception: " + e; Slog.e(TAG, "Error reading process statistics", e); + return false; } + return true; } private void writeStateLocked(boolean sync, final boolean commit) { @@ -848,6 +920,7 @@ public final class ProcessTracker { out.writeLong(mTimePeriodStartClock); out.writeLong(mTimePeriodStartRealtime); out.writeLong(mTimePeriodEndRealtime); + out.writeInt(mFlags); out.writeInt(mLongs.size()); out.writeInt(mNextLong); @@ -920,7 +993,7 @@ public final class ProcessTracker { private boolean readCheckedInt(Parcel in, int val, String what) { int got; if ((got=in.readInt()) != val) { - mReadError = "bad " + ": " + got; + mReadError = "bad " + what + ": " + got; return false; } return true; @@ -956,6 +1029,7 @@ public final class ProcessTracker { buildTimePeriodStartClockStr(); mTimePeriodStartRealtime = in.readLong(); mTimePeriodEndRealtime = in.readLong(); + mFlags = in.readInt(); final int NLONGS = in.readInt(); final int NEXTLONG = in.readInt(); @@ -1365,8 +1439,9 @@ public final class ProcessTracker { void dumpSummaryLocked(PrintWriter pw, String reqPackage, long now) { dumpFilteredSummaryLocked(pw, null, " ", ALL_SCREEN_ADJ, ALL_MEM_ADJ, - new int[] { STATE_PERSISTENT, STATE_TOP, STATE_FOREGROUND, STATE_VISIBLE, - STATE_PERCEPTIBLE, STATE_BACKUP, STATE_SERVICE, STATE_HOME, STATE_PREVIOUS }, + new int[] { STATE_PERSISTENT, STATE_TOP, STATE_IMPORTANT_FOREGROUND, + STATE_IMPORTANT_BACKGROUND, STATE_BACKUP, STATE_HEAVY_WEIGHT, + STATE_SERVICE, STATE_RECEIVER, STATE_HOME, STATE_LAST_ACTIVITY }, now, reqPackage); pw.println(); pw.println("Run time Stats:"); @@ -1379,6 +1454,9 @@ public final class ProcessTracker { TimeUtils.formatDuration( (mRunning ? SystemClock.elapsedRealtime() : mTimePeriodEndRealtime) - mTimePeriodStartRealtime, pw); + if ((mFlags&FLAG_COMPLETE) != 0) pw.print(" (complete)"); + else if ((mFlags&FLAG_SHUTDOWN) != 0) pw.print(" (shutdown)"); + else pw.print(" (partial)"); pw.println(); } @@ -1452,10 +1530,13 @@ public final class ProcessTracker { void dumpCheckinLocked(PrintWriter pw, String reqPackage) { final long now = SystemClock.uptimeMillis(); ArrayMap<String, SparseArray<PackageState>> pkgMap = mPackages.getMap(); - pw.println("vers,1"); + pw.println("vers,2"); pw.print("period,"); pw.print(mTimePeriodStartClockStr); pw.print(","); pw.print(mTimePeriodStartRealtime); pw.print(","); pw.print(mRunning ? SystemClock.elapsedRealtime() : mTimePeriodEndRealtime); + if ((mFlags&FLAG_COMPLETE) != 0) pw.print(",complete"); + else if ((mFlags&FLAG_SHUTDOWN) != 0) pw.print(",shutdown"); + else pw.print(",partial"); pw.println(); for (int ip=0; ip<pkgMap.size(); ip++) { String pkgName = pkgMap.keyAt(ip); @@ -1629,6 +1710,7 @@ public final class ProcessTracker { if (now > (mState.mLastWriteTime+WRITE_PERIOD)) { if (SystemClock.elapsedRealtime() > (mState.mTimePeriodStartRealtime+COMMIT_PERIOD)) { mCommitPending = true; + mState.mFlags |= State.FLAG_COMPLETE; } return true; } @@ -1637,6 +1719,7 @@ public final class ProcessTracker { public void shutdownLocked() { Slog.w(TAG, "Writing process stats before shutdown..."); + mState.mFlags |= State.FLAG_SHUTDOWN; writeStateSyncLocked(); mShuttingDown = true; } @@ -1841,6 +1924,9 @@ public final class ProcessTracker { long minPss; long avgPss; long maxPss; + long minUss; + long avgUss; + long maxUss; ProcessDataCollection(int[] _screenStates, int[] _memStates, int[] _procStates) { screenStates = _screenStates; @@ -1857,6 +1943,12 @@ public final class ProcessTracker { printSizeValue(pw, avgPss * 1024); pw.print("-"); printSizeValue(pw, maxPss * 1024); + pw.print("/"); + printSizeValue(pw, minUss * 1024); + pw.print("-"); + printSizeValue(pw, avgUss * 1024); + pw.print("-"); + printSizeValue(pw, maxUss * 1024); if (full) { pw.print(" over "); pw.print(numPss); @@ -1868,7 +1960,8 @@ public final class ProcessTracker { static void computeProcessData(ProcessState proc, ProcessDataCollection data, long now) { data.totalTime = 0; - data.numPss = data.minPss = data.avgPss = data.maxPss = 0; + data.numPss = data.minPss = data.avgPss = data.maxPss = + data.minUss = data.avgUss = data.maxUss = 0; for (int is=0; is<data.screenStates.length; is++) { for (int im=0; im<data.memStates.length; im++) { for (int ip=0; ip<data.procStates.length; ip++) { @@ -1880,10 +1973,16 @@ public final class ProcessTracker { long minPss = proc.getPssMinimum(bucket); long avgPss = proc.getPssAverage(bucket); long maxPss = proc.getPssMaximum(bucket); + long minUss = proc.getPssUssMinimum(bucket); + long avgUss = proc.getPssUssAverage(bucket); + long maxUss = proc.getPssUssMaximum(bucket); if (data.numPss == 0) { data.minPss = minPss; data.avgPss = avgPss; data.maxPss = maxPss; + data.minUss = minUss; + data.avgUss = avgUss; + data.maxUss = maxUss; } else { if (minPss < data.minPss) { data.minPss = minPss; @@ -1893,6 +1992,14 @@ public final class ProcessTracker { if (maxPss > data.maxPss) { data.maxPss = maxPss; } + if (minUss < data.minUss) { + data.minUss = minUss; + } + data.avgUss = (long)( ((data.avgUss*(double)data.numPss) + + (avgUss*(double)samples)) / (data.numPss+samples) ); + if (maxUss > data.maxUss) { + data.maxUss = maxUss; + } } data.numPss += samples; } @@ -1989,7 +2096,7 @@ public final class ProcessTracker { if (count > 0) { if (!printedHeader) { pw.print(prefix); - pw.print("PSS ("); + pw.print("PSS/USS ("); pw.print(proc.mPssTableSize); pw.println(" entries):"); printedHeader = true; @@ -2013,6 +2120,12 @@ public final class ProcessTracker { printSizeValue(pw, proc.getPssAverage(bucket) * 1024); pw.print(" "); printSizeValue(pw, proc.getPssMaximum(bucket) * 1024); + pw.print(" / "); + printSizeValue(pw, proc.getPssUssMinimum(bucket) * 1024); + pw.print(" "); + printSizeValue(pw, proc.getPssUssAverage(bucket) * 1024); + pw.print(" "); + printSizeValue(pw, proc.getPssUssMaximum(bucket) * 1024); pw.println(); } } @@ -2148,21 +2261,28 @@ public final class ProcessTracker { dumpProcessSummaryDetails(pw, proc, prefix, " TOTAL: ", screenStates, memStates, procStates, now, true); dumpProcessSummaryDetails(pw, proc, prefix, " Persistent: ", screenStates, memStates, - new int[] {STATE_PERSISTENT}, now, true); + new int[] { STATE_PERSISTENT }, now, true); dumpProcessSummaryDetails(pw, proc, prefix, " Top: ", screenStates, memStates, new int[] {STATE_TOP}, now, true); - dumpProcessSummaryDetails(pw, proc, prefix, " Foreground: ", screenStates, memStates, - new int[] {STATE_FOREGROUND, STATE_VISIBLE, STATE_PERCEPTIBLE}, now, true); + dumpProcessSummaryDetails(pw, proc, prefix, " Imp Fg: ", screenStates, memStates, + new int[] { STATE_IMPORTANT_FOREGROUND }, now, true); + dumpProcessSummaryDetails(pw, proc, prefix, " Imp Bg: ", screenStates, memStates, + new int[] {STATE_IMPORTANT_BACKGROUND}, now, true); dumpProcessSummaryDetails(pw, proc, prefix, " Backup: ", screenStates, memStates, new int[] {STATE_BACKUP}, now, true); + dumpProcessSummaryDetails(pw, proc, prefix, " Heavy Wgt: ", screenStates, memStates, + new int[] {STATE_HEAVY_WEIGHT}, now, true); dumpProcessSummaryDetails(pw, proc, prefix, " Service: ", screenStates, memStates, new int[] {STATE_SERVICE}, now, true); + dumpProcessSummaryDetails(pw, proc, prefix, " Receiver: ", screenStates, memStates, + new int[] {STATE_RECEIVER}, now, true); dumpProcessSummaryDetails(pw, proc, prefix, " Home: ", screenStates, memStates, new int[] {STATE_HOME}, now, true); - dumpProcessSummaryDetails(pw, proc, prefix, " Previous: ", screenStates, memStates, - new int[] {STATE_PREVIOUS}, now, true); + dumpProcessSummaryDetails(pw, proc, prefix, " Last Act: ", screenStates, memStates, + new int[] {STATE_LAST_ACTIVITY}, now, true); dumpProcessSummaryDetails(pw, proc, prefix, " (Cached): ", screenStates, memStates, - new int[] {STATE_CACHED}, now, true); + new int[] {STATE_CACHED_ACTIVITY_CLIENT, STATE_CACHED_ACTIVITY_CLIENT, + STATE_CACHED_EMPTY}, now, true); } } @@ -2193,9 +2313,9 @@ public final class ProcessTracker { if (result < 1) { value = String.format("%.2f", result); } else if (result < 10) { - value = String.format("%.2f", result); + value = String.format("%.1f", result); } else if (result < 100) { - value = String.format("%.2f", result); + value = String.format("%.0f", result); } else { value = String.format("%.0f", result); } @@ -2300,6 +2420,9 @@ public final class ProcessTracker { long min = proc.mState.getLong(off, PSS_MINIMUM); long avg = proc.mState.getLong(off, PSS_AVERAGE); long max = proc.mState.getLong(off, PSS_MAXIMUM); + long umin = proc.mState.getLong(off, PSS_USS_MINIMUM); + long uavg = proc.mState.getLong(off, PSS_USS_AVERAGE); + long umax = proc.mState.getLong(off, PSS_USS_MAXIMUM); pw.print(','); printProcStateTag(pw, type); pw.print(':'); @@ -2310,6 +2433,12 @@ public final class ProcessTracker { pw.print(avg); pw.print(':'); pw.print(max); + pw.print(':'); + pw.print(umin); + pw.print(':'); + pw.print(uavg); + pw.print(':'); + pw.print(umax); } } @@ -2391,9 +2520,10 @@ public final class ProcessTracker { int[] csvMemStats = new int[] {ADJ_MEM_FACTOR_CRITICAL}; boolean csvSepProcStats = true; int[] csvProcStats = new int[] { - STATE_PERSISTENT, STATE_TOP, STATE_FOREGROUND, STATE_VISIBLE, - STATE_PERCEPTIBLE, STATE_BACKUP, STATE_SERVICE, STATE_HOME, - STATE_PREVIOUS, STATE_CACHED }; + STATE_PERSISTENT, STATE_TOP, STATE_IMPORTANT_FOREGROUND, + STATE_IMPORTANT_BACKGROUND, STATE_BACKUP, STATE_HEAVY_WEIGHT, STATE_SERVICE, + STATE_RECEIVER, STATE_HOME, STATE_LAST_ACTIVITY, + STATE_CACHED_ACTIVITY, STATE_CACHED_ACTIVITY_CLIENT, STATE_CACHED_EMPTY }; if (args != null) { for (int i=0; i<args.length; i++) { String arg = args[i]; @@ -2457,6 +2587,7 @@ public final class ProcessTracker { } else if ("--current".equals(arg)) { currentOnly = true; } else if ("--commit".equals(arg)) { + mState.mFlags |= State.FLAG_COMPLETE; mState.writeStateLocked(true, true); pw.println("Process stats committed."); return; @@ -2557,6 +2688,13 @@ public final class ProcessTracker { if (DEBUG) Slog.d(TAG, "Retrieving state: " + files.get(i)); try { State state = new State(files.get(i)); + if (state.mReadError != null) { + pw.print("Failure reading "); pw.print(files.get(i)); + pw.print("; "); pw.println(state.mReadError); + if (DEBUG) Slog.d(TAG, "Deleting state: " + files.get(i)); + (new File(files.get(i))).delete(); + continue; + } String fileStr = state.mFile.getBaseFile().getPath(); boolean checkedIn = fileStr.endsWith(STATE_FILE_CHECKIN_SUFFIX); if (isCheckin || isCompact) { @@ -2588,7 +2726,6 @@ public final class ProcessTracker { pw.print("**** FAILURE DUMPING STATE: "); pw.println(files.get(i)); e.printStackTrace(pw); } - if (DEBUG) Slog.d(TAG, "Deleting state: " + files.get(i)); } } } finally { diff --git a/services/java/com/android/server/am/TaskRecord.java b/services/java/com/android/server/am/TaskRecord.java index d79211c..ebcf22a 100644 --- a/services/java/com/android/server/am/TaskRecord.java +++ b/services/java/com/android/server/am/TaskRecord.java @@ -59,11 +59,10 @@ final class TaskRecord extends ThumbnailHolder { private boolean mApplicationTask = true; - TaskRecord(int _taskId, ActivityInfo info, Intent _intent, ActivityStack _stack) { + TaskRecord(int _taskId, ActivityInfo info, Intent _intent) { taskId = _taskId; affinity = info.taskAffinity; setIntent(_intent, info); - stack = _stack; } void touchActiveTime() { diff --git a/services/java/com/android/server/connectivity/Tethering.java b/services/java/com/android/server/connectivity/Tethering.java index 87263b3..22a7841 100644 --- a/services/java/com/android/server/connectivity/Tethering.java +++ b/services/java/com/android/server/connectivity/Tethering.java @@ -152,6 +152,7 @@ public class Tethering extends INetworkManagementEventObserver.Stub { IntentFilter filter = new IntentFilter(); filter.addAction(UsbManager.ACTION_USB_STATE); filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); + filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED); mContext.registerReceiver(mStateReceiver, filter); filter = new IntentFilter(); @@ -511,6 +512,8 @@ public class Tethering extends INetworkManagementEventObserver.Stub { if (VDBG) Log.d(TAG, "Tethering got CONNECTIVITY_ACTION"); mTetherMasterSM.sendMessage(TetherMasterSM.CMD_UPSTREAM_CHANGED); } + } else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) { + updateConfiguration(); } } } @@ -613,7 +616,7 @@ public class Tethering extends INetworkManagementEventObserver.Stub { public int[] getUpstreamIfaceTypes() { int values[]; synchronized (mPublicSync) { - updateConfiguration(); + updateConfiguration(); // TODO - remove? values = new int[mUpstreamIfaceTypes.size()]; Iterator<Integer> iterator = mUpstreamIfaceTypes.iterator(); for (int i=0; i < mUpstreamIfaceTypes.size(); i++) { @@ -1284,7 +1287,7 @@ public class Tethering extends INetworkManagementEventObserver.Stub { int upType = ConnectivityManager.TYPE_NONE; String iface = null; - updateConfiguration(); + updateConfiguration(); // TODO - remove? synchronized (mPublicSync) { if (VDBG) { diff --git a/services/java/com/android/server/content/SyncManager.java b/services/java/com/android/server/content/SyncManager.java index 9e2e841..2da95c3 100644 --- a/services/java/com/android/server/content/SyncManager.java +++ b/services/java/com/android/server/content/SyncManager.java @@ -1273,7 +1273,7 @@ public class SyncManager { for (int i = 0; i < settings.periodicSyncs.size(); i++) { final Pair<Bundle, Long> pair = settings.periodicSyncs.get(i); final String period = String.valueOf(pair.second); - final String extras = pair.first.size() > 0 ? pair.first.toString() : ""; + final String extras = pair.first.size() > 0 ? " " + pair.first.toString() : ""; final String next = formatTime(status.getPeriodicSyncTime(i) + pair.second * 1000); table.set(row + i * 2, 12, period + extras); diff --git a/services/java/com/android/server/dreams/DreamManagerService.java b/services/java/com/android/server/dreams/DreamManagerService.java index c9e0da5..21e54fe 100644 --- a/services/java/com/android/server/dreams/DreamManagerService.java +++ b/services/java/com/android/server/dreams/DreamManagerService.java @@ -73,7 +73,7 @@ public final class DreamManagerService extends IDreamManager.Stub { mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE); } - public void systemReady() { + public void systemRunning() { mContext.registerReceiver(new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { diff --git a/services/java/com/android/server/input/InputManagerService.java b/services/java/com/android/server/input/InputManagerService.java index 5e4907e..7b4c077 100644 --- a/services/java/com/android/server/input/InputManagerService.java +++ b/services/java/com/android/server/input/InputManagerService.java @@ -283,7 +283,7 @@ public class InputManagerService extends IInputManager.Stub } // TODO(BT) Pass in paramter for bluetooth system - public void systemReady() { + public void systemRunning() { if (DEBUG) { Slog.d(TAG, "System ready."); } diff --git a/services/java/com/android/server/location/GpsLocationProvider.java b/services/java/com/android/server/location/GpsLocationProvider.java index 4791ec0..38453c8 100644 --- a/services/java/com/android/server/location/GpsLocationProvider.java +++ b/services/java/com/android/server/location/GpsLocationProvider.java @@ -892,7 +892,8 @@ public class GpsLocationProvider implements LocationProviderInterface { for (int i=0; i<newWork.size(); i++) { try { int uid = newWork.get(i); - mAppOpsService.startOperation(AppOpsManager.OP_GPS, uid, newWork.getName(i)); + mAppOpsService.startOperation(AppOpsManager.getToken(mAppOpsService), + AppOpsManager.OP_GPS, uid, newWork.getName(i)); if (uid != lastuid) { lastuid = uid; mBatteryStats.noteStartGps(uid); @@ -909,7 +910,8 @@ public class GpsLocationProvider implements LocationProviderInterface { for (int i=0; i<goneWork.size(); i++) { try { int uid = goneWork.get(i); - mAppOpsService.finishOperation(AppOpsManager.OP_GPS, uid, goneWork.getName(i)); + mAppOpsService.finishOperation(AppOpsManager.getToken(mAppOpsService), + AppOpsManager.OP_GPS, uid, goneWork.getName(i)); if (uid != lastuid) { lastuid = uid; mBatteryStats.noteStopGps(uid); diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index 5074409..05eeb36 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -154,7 +154,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private final Context mContext; private final INetworkManagementService mNetworkManager; - private final IAlarmManager mAlarmManager; + private final AlarmManager mAlarmManager; private final TrustedTime mTime; private final TelephonyManager mTeleManager; private final NetworkStatsSettings mSettings; @@ -261,10 +261,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { NetworkStatsSettings settings) { mContext = checkNotNull(context, "missing Context"); mNetworkManager = checkNotNull(networkManager, "missing INetworkManagementService"); - mAlarmManager = checkNotNull(alarmManager, "missing IAlarmManager"); mTime = checkNotNull(time, "missing TrustedTime"); mTeleManager = checkNotNull(TelephonyManager.getDefault(), "missing TelephonyManager"); mSettings = checkNotNull(settings, "missing NetworkStatsSettings"); + mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); final PowerManager powerManager = (PowerManager) context.getSystemService( Context.POWER_SERVICE); @@ -420,20 +420,16 @@ public class NetworkStatsService extends INetworkStatsService.Stub { * reschedule based on current {@link NetworkStatsSettings#getPollInterval()}. */ private void registerPollAlarmLocked() { - try { - if (mPollIntent != null) { - mAlarmManager.remove(mPollIntent); - } + if (mPollIntent != null) { + mAlarmManager.cancel(mPollIntent); + } - mPollIntent = PendingIntent.getBroadcast( - mContext, 0, new Intent(ACTION_NETWORK_STATS_POLL), 0); + mPollIntent = PendingIntent.getBroadcast( + mContext, 0, new Intent(ACTION_NETWORK_STATS_POLL), 0); - final long currentRealtime = SystemClock.elapsedRealtime(); - mAlarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME, currentRealtime, - mSettings.getPollInterval(), mPollIntent); - } catch (RemoteException e) { - // ignored; service lives in system_server - } + final long currentRealtime = SystemClock.elapsedRealtime(); + mAlarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME, currentRealtime, + mSettings.getPollInterval(), mPollIntent); } /** diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java index 6f57261..7a01219 100755 --- a/services/java/com/android/server/pm/PackageManagerService.java +++ b/services/java/com/android/server/pm/PackageManagerService.java @@ -6189,9 +6189,9 @@ public class PackageManagerService extends IPackageManager.Stub { PackageSetting pkgSetting; final int uid = Binder.getCallingUid(); if (UserHandle.getUserId(uid) != userId) { - mContext.enforceCallingPermission( + mContext.enforceCallingOrSelfPermission( android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, - "setApplicationBlocked for user " + userId); + "setApplicationBlockedSetting for user " + userId); } if (blocked && isPackageDeviceAdmin(packageName, userId)) { @@ -6224,6 +6224,8 @@ public class PackageManagerService extends IPackageManager.Stub { return true; } if (sendRemoved) { + killApplication(packageName, UserHandle.getUid(userId, pkgSetting.appId), + "blocking pkg"); sendPackageBlockedForUser(packageName, pkgSetting, userId); } } finally { @@ -10016,6 +10018,7 @@ public class PackageManagerService extends IPackageManager.Stub { } } } + sUserManager.systemReady(); } public boolean isSafeMode() { diff --git a/services/java/com/android/server/pm/UserManagerService.java b/services/java/com/android/server/pm/UserManagerService.java index 2901212..4ead8d5 100644 --- a/services/java/com/android/server/pm/UserManagerService.java +++ b/services/java/com/android/server/pm/UserManagerService.java @@ -21,11 +21,13 @@ import static android.text.format.DateUtils.MINUTE_IN_MILLIS; import android.app.Activity; import android.app.ActivityManager; import android.app.ActivityManagerNative; +import android.app.ActivityThread; import android.app.IStopUserCallback; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.RestrictionEntry; +import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.UserInfo; @@ -51,6 +53,7 @@ import android.util.SparseLongArray; import android.util.TimeUtils; import android.util.Xml; +import com.android.internal.content.PackageMonitor; import com.android.internal.util.ArrayUtils; import com.android.internal.util.FastXmlSerializer; @@ -229,6 +232,13 @@ public class UserManagerService extends IUserManager.Stub { sInstance = this; } } + + } + + void systemReady() { + mUserPackageMonitor.register(ActivityThread.systemMain().getSystemContext(), + null, UserHandle.ALL, false); + userForeground(UserHandle.USER_OWNER); } @Override @@ -406,8 +416,15 @@ public class UserManagerService extends IUserManager.Stub { @Override public void setUserRestrictions(Bundle restrictions, int userId) { checkManageUsersPermission("setUserRestrictions"); + if (restrictions == null) return; synchronized (mPackagesLock) { + // If the user has restrictions already and call is trying to disallow restrictions, + // don't modify the flag. + if (hasRestrictionsPinLocked(userId) + && restrictions.getBoolean(UserManager.DISALLOW_APP_RESTRICTIONS, false)) { + restrictions.putBoolean(UserManager.DISALLOW_APP_RESTRICTIONS, false); + } mUserRestrictions.get(userId).putAll(restrictions); writeUserLocked(mUsers.get(userId)); } @@ -671,6 +688,7 @@ public class UserManagerService extends IUserManager.Stub { writeBoolean(serializer, restrictions, UserManager.DISALLOW_USB_FILE_TRANSFER); writeBoolean(serializer, restrictions, UserManager.DISALLOW_CONFIG_CREDENTIALS); writeBoolean(serializer, restrictions, UserManager.DISALLOW_REMOVE_USER); + writeBoolean(serializer, restrictions, UserManager.DISALLOW_APP_RESTRICTIONS); serializer.endTag(null, TAG_RESTRICTIONS); } serializer.endTag(null, TAG_USER); @@ -801,6 +819,7 @@ public class UserManagerService extends IUserManager.Stub { readBoolean(parser, restrictions, UserManager.DISALLOW_USB_FILE_TRANSFER); readBoolean(parser, restrictions, UserManager.DISALLOW_CONFIG_CREDENTIALS); readBoolean(parser, restrictions, UserManager.DISALLOW_REMOVE_USER); + readBoolean(parser, restrictions, UserManager.DISALLOW_APP_RESTRICTIONS); } } } @@ -822,11 +841,6 @@ public class UserManagerService extends IUserManager.Stub { pinState.failedAttempts = failedAttempts; pinState.lastAttemptTime = lastAttemptTime; } - // If this is not a restricted profile and there is no restrictions pin, clean up - // any restrictions files that might have been left behind. - if (!userInfo.isRestricted() && salt == 0) { - cleanAppRestrictions(id); - } return userInfo; } catch (IOException ioe) { @@ -878,11 +892,22 @@ public class UserManagerService extends IUserManager.Stub { } } + private boolean isPackageInstalled(String pkg, int userId) { + final ApplicationInfo info = mPm.getApplicationInfo(pkg, + PackageManager.GET_UNINSTALLED_PACKAGES, + userId); + if (info == null || (info.flags&ApplicationInfo.FLAG_INSTALLED) == 0) { + return false; + } + return true; + } + /** - * Removes all the restrictions files (res_<packagename>) for a given user. + * Removes all the restrictions files (res_<packagename>) for a given user, if all is true, + * else removes only those packages that have been uninstalled. * Does not do any permissions checking. */ - private void cleanAppRestrictions(int userId) { + private void cleanAppRestrictions(int userId, boolean all) { synchronized (mPackagesLock) { File dir = Environment.getUserSystemDirectory(userId); String[] files = dir.list(); @@ -891,13 +916,33 @@ public class UserManagerService extends IUserManager.Stub { if (fileName.startsWith(RESTRICTIONS_FILE_PREFIX)) { File resFile = new File(dir, fileName); if (resFile.exists()) { - resFile.delete(); + if (all) { + resFile.delete(); + } else { + String pkg = fileName.substring(RESTRICTIONS_FILE_PREFIX.length()); + if (!isPackageInstalled(pkg, userId)) { + resFile.delete(); + } + } } } } } } + /** + * Removes the app restrictions file for a specific package and user id, if it exists. + */ + private void cleanAppRestrictionsForPackage(String pkg, int userId) { + synchronized (mPackagesLock) { + File dir = Environment.getUserSystemDirectory(userId); + File resFile = new File(dir, RESTRICTIONS_FILE_PREFIX + pkg); + if (resFile.exists()) { + resFile.delete(); + } + } + } + @Override public UserInfo createUser(String name, int flags) { checkManageUsersPermission("Only the system can create users"); @@ -1160,14 +1205,52 @@ public class UserManagerService extends IUserManager.Stub { public boolean hasRestrictionsPin() { int userId = UserHandle.getCallingUserId(); synchronized (mPackagesLock) { - RestrictionsPinState pinState = mRestrictionsPinStates.get(userId); - if (pinState == null || pinState.salt == 0 || pinState.pinHash == null) { - return false; - } + return hasRestrictionsPinLocked(userId); + } + } + + private boolean hasRestrictionsPinLocked(int userId) { + RestrictionsPinState pinState = mRestrictionsPinStates.get(userId); + if (pinState == null || pinState.salt == 0 || pinState.pinHash == null) { + return false; } return true; } + @Override + public void removeRestrictions() { + checkManageUsersPermission("Only system can remove restrictions"); + final int userHandle = UserHandle.getCallingUserId(); + synchronized (mPackagesLock) { + // Remove all user restrictions + setUserRestrictions(new Bundle(), userHandle); + // Remove restrictions pin + changeRestrictionsPin(null); + // Remove any app restrictions + cleanAppRestrictions(userHandle, true); + } + mHandler.post(new Runnable() { + @Override + public void run() { + List<ApplicationInfo> apps = + mPm.getInstalledApplications(PackageManager.GET_UNINSTALLED_PACKAGES, + userHandle).getList(); + final long ident = Binder.clearCallingIdentity(); + try { + for (ApplicationInfo appInfo : apps) { + if ((appInfo.flags & ApplicationInfo.FLAG_INSTALLED) != 0 + && (appInfo.flags & ApplicationInfo.FLAG_BLOCKED) != 0) { + mPm.setApplicationBlockedSettingAsUser(appInfo.packageName, false, + userHandle); + } + } + } finally { + Binder.restoreCallingIdentity(ident); + } + } + }); + } + /* * Generate a hash for the given password. To avoid brute force attacks, we use a salted hash. * Not the most secure, but it is at least a second level of protection. First level is that @@ -1372,7 +1455,7 @@ public class UserManagerService extends IUserManager.Stub { } /** - * Make a note of the last started time of a user. + * Make a note of the last started time of a user and do some cleanup. * @param userId the user that was just foregrounded */ public void userForeground(int userId) { @@ -1387,6 +1470,12 @@ public class UserManagerService extends IUserManager.Stub { user.lastLoggedInTime = now; writeUserLocked(user); } + // If this is not a restricted profile and there is no restrictions pin, clean up + // all restrictions files that might have been left behind, else clean up just the + // ones with uninstalled packages + RestrictionsPinState pinState = mRestrictionsPinStates.get(userId); + final long salt = pinState == null ? 0 : pinState.salt; + cleanAppRestrictions(userId, (!user.isRestricted() && salt == 0)); } } @@ -1453,4 +1542,17 @@ public class UserManagerService extends IUserManager.Stub { } } } + + private PackageMonitor mUserPackageMonitor = new PackageMonitor() { + @Override + public void onPackageRemoved(String pkg, int uid) { + final int userId = this.getChangingUserId(); + // Package could be disappearing because it is being blocked, so also check if + // it has been uninstalled. + final boolean uninstalled = isPackageDisappearing(pkg) == PACKAGE_PERMANENT_CHANGE; + if (uninstalled && userId >= 0 && !isPackageInstalled(pkg, userId)) { + cleanAppRestrictionsForPackage(pkg, userId); + } + } + }; } diff --git a/services/java/com/android/server/power/Notifier.java b/services/java/com/android/server/power/Notifier.java index e44cfe5..264e2e9 100644 --- a/services/java/com/android/server/power/Notifier.java +++ b/services/java/com/android/server/power/Notifier.java @@ -144,7 +144,8 @@ final class Notifier { } else { mBatteryStats.noteStartWakelock(ownerUid, ownerPid, tag, monitorType); // XXX need to deal with disabled operations. - mAppOps.startOperation(AppOpsManager.OP_WAKE_LOCK, ownerUid, packageName); + mAppOps.startOperation(AppOpsManager.getToken(mAppOps), + AppOpsManager.OP_WAKE_LOCK, ownerUid, packageName); } } catch (RemoteException ex) { // Ignore @@ -169,7 +170,8 @@ final class Notifier { mBatteryStats.noteStopWakelockFromSource(workSource, ownerPid, tag, monitorType); } else { mBatteryStats.noteStopWakelock(ownerUid, ownerPid, tag, monitorType); - mAppOps.finishOperation(AppOpsManager.OP_WAKE_LOCK, ownerUid, packageName); + mAppOps.finishOperation(AppOpsManager.getToken(mAppOps), + AppOpsManager.OP_WAKE_LOCK, ownerUid, packageName); } } catch (RemoteException ex) { // Ignore diff --git a/services/java/com/android/server/power/PowerManagerService.java b/services/java/com/android/server/power/PowerManagerService.java index 5c81cde..777ffe7 100644 --- a/services/java/com/android/server/power/PowerManagerService.java +++ b/services/java/com/android/server/power/PowerManagerService.java @@ -1711,24 +1711,30 @@ public final class PowerManagerService extends IPowerManager.Stub new DisplayPowerController.Callbacks() { @Override public void onStateChanged() { - mDirty |= DIRTY_ACTUAL_DISPLAY_POWER_STATE_UPDATED; - updatePowerStateLocked(); + synchronized (mLock) { + mDirty |= DIRTY_ACTUAL_DISPLAY_POWER_STATE_UPDATED; + updatePowerStateLocked(); + } } @Override public void onProximityPositive() { - mProximityPositive = true; - mDirty |= DIRTY_PROXIMITY_POSITIVE; - updatePowerStateLocked(); + synchronized (mLock) { + mProximityPositive = true; + mDirty |= DIRTY_PROXIMITY_POSITIVE; + updatePowerStateLocked(); + } } @Override public void onProximityNegative() { - mProximityPositive = false; - mDirty |= DIRTY_PROXIMITY_POSITIVE; - userActivityNoUpdateLocked(SystemClock.uptimeMillis(), - PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, Process.SYSTEM_UID); - updatePowerStateLocked(); + synchronized (mLock) { + mProximityPositive = false; + mDirty |= DIRTY_PROXIMITY_POSITIVE; + userActivityNoUpdateLocked(SystemClock.uptimeMillis(), + PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, Process.SYSTEM_UID); + updatePowerStateLocked(); + } } }; diff --git a/services/java/com/android/server/print/PrintManagerService.java b/services/java/com/android/server/print/PrintManagerService.java index 5173998..86e7685 100644 --- a/services/java/com/android/server/print/PrintManagerService.java +++ b/services/java/com/android/server/print/PrintManagerService.java @@ -22,118 +22,111 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; -import android.content.ServiceConnection; import android.content.pm.PackageManager; -import android.content.pm.ResolveInfo; import android.database.ContentObserver; import android.net.Uri; import android.os.Binder; -import android.os.Handler; -import android.os.IBinder; -import android.os.ParcelFileDescriptor; import android.os.Process; -import android.os.RemoteException; import android.os.UserHandle; -import android.print.IPrintAdapter; import android.print.IPrintClient; +import android.print.IPrintDocumentAdapter; import android.print.IPrintManager; -import android.print.IPrinterDiscoveryObserver; import android.print.PrintAttributes; import android.print.PrintJobInfo; -import android.print.PrintManager; -import android.print.PrinterId; -import android.print.PrinterInfo; -import android.printservice.IPrintService; -import android.printservice.IPrintServiceClient; -import android.printservice.PrintServiceInfo; import android.provider.Settings; -import android.text.TextUtils; -import android.text.TextUtils.SimpleStringSplitter; -import android.util.Slog; +import android.util.SparseArray; import com.android.internal.content.PackageMonitor; +import com.android.internal.os.BackgroundThread; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; import java.util.Iterator; import java.util.List; -import java.util.Map; -import java.util.NoSuchElementException; import java.util.Set; public final class PrintManagerService extends IPrintManager.Stub { - private static final String LOG_TAG = PrintManagerService.class.getSimpleName(); - private static final char COMPONENT_NAME_SEPARATOR = ':'; private final Object mLock = new Object(); - private final SimpleStringSplitter mStringColonSplitter = - new SimpleStringSplitter(COMPONENT_NAME_SEPARATOR); - - private final Map<ComponentName, PrintServiceClient> mServices = - new HashMap<ComponentName, PrintServiceClient>(); - - private final List<PrintServiceInfo> mInstalledServices = new ArrayList<PrintServiceInfo>(); - - private final Set<ComponentName> mEnabledServiceNames = new HashSet<ComponentName>(); - private final Context mContext; - private final RemoteSpooler mSpooler; - - private final int mMyUid; + private final SparseArray<UserState> mUserStates = new SparseArray<UserState>(); private int mCurrentUserId = UserHandle.USER_OWNER; - private IPrinterDiscoveryObserver mPrinterDiscoveryObserver; - public PrintManagerService(Context context) { mContext = context; - mSpooler = new RemoteSpooler(context); - mMyUid = android.os.Process.myUid(); registerContentObservers(); - registerBoradcastreceivers(); + registerBoradcastReceivers(); + } + + public void systemRuning() { + BackgroundThread.getHandler().post(new Runnable() { + @Override + public void run() { + synchronized (mLock) { + UserState userState = getCurrentUserStateLocked(); + userState.updateIfNeededLocked(); + userState.getSpoolerLocked().notifyClientForActivteJobs(); + } + } + }); } @Override - public PrintJobInfo print(String printJobName, IPrintClient client, IPrintAdapter printAdapter, - PrintAttributes attributes, int appId, int userId) { - final int resolvedAppId = resolveCallingAppEnforcingPermissionsLocked(appId); - final int resolvedUserId = resolveCallingUserEnforcingPermissionsIdLocked(userId); + public PrintJobInfo print(String printJobName, IPrintClient client, + IPrintDocumentAdapter documentAdapter, PrintAttributes attributes, int appId, + int userId) { + final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId); + final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId); + final UserState userState; + final RemotePrintSpooler spooler; + synchronized (mLock) { + userState = getOrCreateUserStateLocked(resolvedUserId); + spooler = userState.getSpoolerLocked(); + } final long identity = Binder.clearCallingIdentity(); try { - return mSpooler.createPrintJob(printJobName, client, printAdapter, - attributes, resolvedAppId, resolvedUserId); + return spooler.createPrintJob(printJobName, client, documentAdapter, + attributes, resolvedAppId); } finally { Binder.restoreCallingIdentity(identity); } } @Override - public List<PrintJobInfo> getPrintJobs(int appId, int userId) { - final int resolvedAppId = resolveCallingAppEnforcingPermissionsLocked(appId); - final int resolvedUserId = resolveCallingUserEnforcingPermissionsIdLocked(userId); - // TODO: Do we want to return jobs in STATE_CREATED? We should probably - // have additional argument for the types to get + public List<PrintJobInfo> getPrintJobInfos(int appId, int userId) { + final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId); + final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId); + final UserState userState; + final RemotePrintSpooler spooler; + synchronized (mLock) { + userState = getOrCreateUserStateLocked(resolvedUserId); + spooler = userState.getSpoolerLocked(); + } final long identity = Binder.clearCallingIdentity(); try { - return mSpooler.getPrintJobs(null, PrintJobInfo.STATE_ANY, - resolvedAppId, resolvedUserId); + return spooler.getPrintJobInfos(null, PrintJobInfo.STATE_ANY, + resolvedAppId); } finally { Binder.restoreCallingIdentity(identity); } } @Override - public PrintJobInfo getPrintJob(int printJobId, int appId, int userId) { - final int resolvedAppId = resolveCallingAppEnforcingPermissionsLocked(appId); - final int resolvedUserId = resolveCallingUserEnforcingPermissionsIdLocked(userId); + public PrintJobInfo getPrintJobInfo(int printJobId, int appId, int userId) { + final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId); + final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId); + final UserState userState; + final RemotePrintSpooler spooler; + synchronized (mLock) { + userState = getOrCreateUserStateLocked(resolvedUserId); + spooler = userState.getSpoolerLocked(); + } final long identity = Binder.clearCallingIdentity(); try { - return mSpooler.getPrintJobInfo(printJobId, resolvedAppId, resolvedUserId); + return spooler.getPrintJobInfo(printJobId, resolvedAppId); } finally { Binder.restoreCallingIdentity(identity); } @@ -141,93 +134,32 @@ public final class PrintManagerService extends IPrintManager.Stub { @Override public void cancelPrintJob(int printJobId, int appId, int userId) { - final int resolvedAppId = resolveCallingAppEnforcingPermissionsLocked(appId); - final int resolvedUserId = resolveCallingUserEnforcingPermissionsIdLocked(userId); + final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId); + final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId); + final UserState userState; + final RemotePrintSpooler spooler; + synchronized (mLock) { + userState = getOrCreateUserStateLocked(resolvedUserId); + spooler = userState.getSpoolerLocked(); + } final long identity = Binder.clearCallingIdentity(); try { - if (mSpooler.cancelPrintJob(printJobId, resolvedAppId, resolvedUserId)) { + if (spooler.cancelPrintJob(printJobId, resolvedAppId)) { return; } - PrintJobInfo printJob = getPrintJob(printJobId, resolvedAppId, resolvedUserId); - if (printJob == null) { + PrintJobInfo printJobInfo = getPrintJobInfo(printJobId, resolvedAppId, resolvedUserId); + if (printJobInfo == null) { return; } - ComponentName printServiceName = printJob.getPrinterId().getServiceComponentName(); - PrintServiceClient printService = null; + ComponentName printServiceName = printJobInfo.getPrinterId().getService(); + RemotePrintService printService = null; synchronized (mLock) { - printService = mServices.get(printServiceName); + printService = userState.getActiveServices().get(printServiceName); } if (printService == null) { return; } - printService.requestCancelPrintJob(printJob); - } finally { - Binder.restoreCallingIdentity(identity); - } - } - - // Called only from the spooler. - @Override - public void onPrintJobQueued(PrinterId printerId, PrintJobInfo printJob) { - throwIfCallerNotSignedWithSystemKey(); - PrintServiceClient printService = null; - synchronized (mLock) { - ComponentName printServiceName = printerId.getServiceComponentName(); - printService = mServices.get(printServiceName); - } - if (printService != null) { - final long identity = Binder.clearCallingIdentity(); - try { - printService.notifyPrintJobQueued(printJob); - } finally { - Binder.restoreCallingIdentity(identity); - } - } - } - - // Called only from the spooler. - @Override - public void startDiscoverPrinters(IPrinterDiscoveryObserver observer) { - throwIfCallerNotSignedWithSystemKey(); - List<PrintServiceClient> services = new ArrayList<PrintServiceClient>(); - synchronized (mLock) { - mPrinterDiscoveryObserver = observer; - services.addAll(mServices.values()); - } - final int serviceCount = services.size(); - if (serviceCount <= 0) { - return; - } - final long identity = Binder.clearCallingIdentity(); - try { - for (int i = 0; i < serviceCount; i++) { - PrintServiceClient service = services.get(i); - service.startPrinterDiscovery(); - } - } finally { - Binder.restoreCallingIdentity(identity); - } - } - - // Called only from the spooler. - @Override - public void stopDiscoverPrinters() { - throwIfCallerNotSignedWithSystemKey(); - List<PrintServiceClient> services = new ArrayList<PrintServiceClient>(); - synchronized (mLock) { - mPrinterDiscoveryObserver = null; - services.addAll(mServices.values()); - } - final int serviceCount = services.size(); - if (serviceCount <= 0) { - return; - } - final long identity = Binder.clearCallingIdentity(); - try { - for (int i = 0; i < serviceCount; i++) { - PrintServiceClient service = services.get(i); - service.stopPrintersDiscovery(); - } + printService.onRequestCancelPrintJob(printJobInfo); } finally { Binder.restoreCallingIdentity(identity); } @@ -237,14 +169,13 @@ public final class PrintManagerService extends IPrintManager.Stub { final Uri enabledPrintServicesUri = Settings.Secure.getUriFor( Settings.Secure.ENABLED_PRINT_SERVICES); - ContentObserver observer = new ContentObserver(new Handler(mContext.getMainLooper())) { + ContentObserver observer = new ContentObserver(BackgroundThread.getHandler()) { @Override public void onChange(boolean selfChange, Uri uri) { if (enabledPrintServicesUri.equals(uri)) { synchronized (mLock) { - if (readEnabledPrintServicesChangedLocked()) { - onUserStateChangedLocked(); - } + UserState userState = getCurrentUserStateLocked(); + userState.updateIfNeededLocked(); } } } @@ -254,32 +185,37 @@ public final class PrintManagerService extends IPrintManager.Stub { false, observer, UserHandle.USER_ALL); } - private void registerBoradcastreceivers() { + private void registerBoradcastReceivers() { PackageMonitor monitor = new PackageMonitor() { @Override - public void onSomePackagesChanged() { + public boolean onPackageChanged(String packageName, int uid, String[] components) { synchronized (mLock) { - if (getChangingUserId() != mCurrentUserId) { - return; - } - if (readConfigurationForUserStateLocked()) { - onUserStateChangedLocked(); + UserState userState = getOrCreateUserStateLocked(getChangingUserId()); + Iterator<ComponentName> iterator = userState.getEnabledServices().iterator(); + while (iterator.hasNext()) { + ComponentName componentName = iterator.next(); + if (packageName.equals(componentName.getPackageName())) { + userState.updateIfNeededLocked(); + return true; + } } } + return false; } @Override public void onPackageRemoved(String packageName, int uid) { synchronized (mLock) { - if (getChangingUserId() != mCurrentUserId) { - return; - } - Iterator<ComponentName> iterator = mEnabledServiceNames.iterator(); + UserState userState = getOrCreateUserStateLocked(getChangingUserId()); + Iterator<ComponentName> iterator = userState.getEnabledServices().iterator(); while (iterator.hasNext()) { ComponentName componentName = iterator.next(); if (packageName.equals(componentName.getPackageName())) { iterator.remove(); - onEnabledServiceNamesChangedLocked(); + persistComponentNamesToSettingLocked( + Settings.Secure.ENABLED_PRINT_SERVICES, + userState.getEnabledServices(), getChangingUserId()); + userState.updateIfNeededLocked(); return; } } @@ -290,10 +226,9 @@ public final class PrintManagerService extends IPrintManager.Stub { public boolean onHandleForceStop(Intent intent, String[] stoppedPackages, int uid, boolean doit) { synchronized (mLock) { - if (getChangingUserId() != mCurrentUserId) { - return false; - } - Iterator<ComponentName> iterator = mEnabledServiceNames.iterator(); + UserState userState = getOrCreateUserStateLocked(getChangingUserId()); + boolean stoppedSomePackages = false; + Iterator<ComponentName> iterator = userState.getEnabledServices().iterator(); while (iterator.hasNext()) { ComponentName componentName = iterator.next(); String componentPackage = componentName.getPackageName(); @@ -302,27 +237,35 @@ public final class PrintManagerService extends IPrintManager.Stub { if (!doit) { return true; } - iterator.remove(); - onEnabledServiceNamesChangedLocked(); + stoppedSomePackages = true; + break; } } } + if (stoppedSomePackages) { + userState.updateIfNeededLocked(); + } return false; } } - private void onEnabledServiceNamesChangedLocked() { - // Update the enabled services setting. - persistComponentNamesToSettingLocked( - Settings.Secure.ENABLED_PRINT_SERVICES, - mEnabledServiceNames, mCurrentUserId); - // Update the current user state. - onUserStateChangedLocked(); + private void persistComponentNamesToSettingLocked(String settingName, + Set<ComponentName> componentNames, int userId) { + StringBuilder builder = new StringBuilder(); + for (ComponentName componentName : componentNames) { + if (builder.length() > 0) { + builder.append(COMPONENT_NAME_SEPARATOR); + } + builder.append(componentName.flattenToShortString()); + } + Settings.Secure.putStringForUser(mContext.getContentResolver(), + settingName, builder.toString(), userId); } }; // package changes - monitor.register(mContext, null, UserHandle.ALL, true); + monitor.register(mContext, BackgroundThread.getHandler().getLooper(), + UserHandle.ALL, true); // user changes IntentFilter intentFilter = new IntentFilter(); @@ -334,179 +277,67 @@ public final class PrintManagerService extends IPrintManager.Stub { String action = intent.getAction(); if (Intent.ACTION_USER_SWITCHED.equals(action)) { switchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0)); + } else if (Intent.ACTION_USER_REMOVED.equals(action)) { + removeUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0)); } } - }, UserHandle.ALL, intentFilter, null, null); - } - - private void throwIfCallerNotSignedWithSystemKey() { - if (mContext.getPackageManager().checkSignatures( - mMyUid, Binder.getCallingUid()) != PackageManager.SIGNATURE_MATCH) { - throw new SecurityException("Caller must be signed with the system key!"); - } - } - - private void onUserStateChangedLocked() { - manageServicesLocked(); - } - - private void manageServicesLocked() { - final int installedCount = mInstalledServices.size(); - for (int i = 0; i < installedCount; i++) { - ResolveInfo resolveInfo = mInstalledServices.get(i).getResolveInfo(); - ComponentName serviceName = new ComponentName(resolveInfo.serviceInfo.packageName, - resolveInfo.serviceInfo.name); - if (mEnabledServiceNames.contains(serviceName)) { - if (!mServices.containsKey(serviceName)) { - new PrintServiceClient(serviceName, mCurrentUserId).ensureBoundLocked(); - } - } else { - PrintServiceClient service = mServices.get(serviceName); - if (service != null) { - service.ensureUnboundLocked(); - } - } - } + }, UserHandle.ALL, intentFilter, null, BackgroundThread.getHandler()); } - private boolean readConfigurationForUserStateLocked() { - boolean somethingChanged = false; - somethingChanged |= readInstalledPrintServiceLocked(); - somethingChanged |= readEnabledPrintServicesChangedLocked(); - return somethingChanged; - } - - private boolean readEnabledPrintServicesChangedLocked() { - Set<ComponentName> tempEnabledServiceNameSet = new HashSet<ComponentName>(); - readComponentNamesFromSettingLocked(Settings.Secure.ENABLED_PRINT_SERVICES, - mCurrentUserId, tempEnabledServiceNameSet); - if (!tempEnabledServiceNameSet.equals(mEnabledServiceNames)) { - mEnabledServiceNames.clear(); - mEnabledServiceNames.addAll(tempEnabledServiceNameSet); - return true; - } - return false; + private UserState getCurrentUserStateLocked() { + return getOrCreateUserStateLocked(mCurrentUserId); } - private boolean readInstalledPrintServiceLocked() { - Set<PrintServiceInfo> tempPrintServices = new HashSet<PrintServiceInfo>(); - - List<ResolveInfo> installedServices = mContext.getPackageManager() - .queryIntentServicesAsUser( - new Intent(android.printservice.PrintService.SERVICE_INTERFACE), - PackageManager.GET_SERVICES | PackageManager.GET_META_DATA, - mCurrentUserId); - - final int installedCount = installedServices.size(); - for (int i = 0, count = installedCount; i < count; i++) { - ResolveInfo installedService = installedServices.get(i); - if (!android.Manifest.permission.BIND_PRINT_SERVICE.equals( - installedService.serviceInfo.permission)) { - ComponentName serviceName = new ComponentName( - installedService.serviceInfo.packageName, - installedService.serviceInfo.name); - Slog.w(LOG_TAG, "Skipping print service " - + serviceName.flattenToShortString() - + " since it does not require permission " - + android.Manifest.permission.BIND_PRINT_SERVICE); - continue; - } - tempPrintServices.add(PrintServiceInfo.create(installedService, mContext)); - } - - if (!tempPrintServices.equals(mInstalledServices)) { - mInstalledServices.clear(); - mInstalledServices.addAll(tempPrintServices); - return true; + private UserState getOrCreateUserStateLocked(int userId) { + UserState userState = mUserStates.get(userId); + if (userState == null) { + userState = new UserState(mContext, userId, mLock); + mUserStates.put(userId, userState); } - return false; - } - - private void readComponentNamesFromSettingLocked(String settingName, int userId, - Set<ComponentName> outComponentNames) { - String settingValue = Settings.Secure.getStringForUser(mContext.getContentResolver(), - settingName, userId); - outComponentNames.clear(); - if (!TextUtils.isEmpty(settingValue)) { - TextUtils.SimpleStringSplitter splitter = mStringColonSplitter; - splitter.setString(settingValue); - while (splitter.hasNext()) { - String string = splitter.next(); - if (TextUtils.isEmpty(string)) { - continue; - } - ComponentName componentName = ComponentName.unflattenFromString(string); - if (componentName != null) { - outComponentNames.add(componentName); - } - } - } - } - - private void persistComponentNamesToSettingLocked(String settingName, - Set<ComponentName> componentNames, int userId) { - StringBuilder builder = new StringBuilder(); - for (ComponentName componentName : componentNames) { - if (builder.length() > 0) { - builder.append(COMPONENT_NAME_SEPARATOR); - } - builder.append(componentName.flattenToShortString()); - } - Settings.Secure.putStringForUser(mContext.getContentResolver(), - settingName, builder.toString(), userId); + return userState; } private void switchUser(int newUserId) { synchronized (mLock) { - // Disconnect services for the old user. - mEnabledServiceNames.clear(); - onUserStateChangedLocked(); - - // The user changed. + if (newUserId == mCurrentUserId) { + return; + } mCurrentUserId = newUserId; - - // Update the user state based on current settings. - readConfigurationForUserStateLocked(); - onUserStateChangedLocked(); - } - - // Unbind the spooler for the old user). - mSpooler.unbind(); - - // If we have queued jobs, advertise it, or we do - // not need the spooler for now. - if (notifyQueuedPrintJobs()) { - mSpooler.unbind(); + UserState userState = getCurrentUserStateLocked(); + userState.updateIfNeededLocked(); + userState.getSpoolerLocked().notifyClientForActivteJobs(); } } - private boolean notifyQueuedPrintJobs() { - Map<PrintServiceClient, List<PrintJobInfo>> notifications = - new HashMap<PrintServiceClient, List<PrintJobInfo>>(); + private void removeUser(int removedUserId) { synchronized (mLock) { - for (PrintServiceClient service : mServices.values()) { - List<PrintJobInfo> printJobs = mSpooler.getPrintJobs( - service.mComponentName, PrintJobInfo.STATE_QUEUED, - PrintManager.APP_ID_ANY, service.mUserId); - notifications.put(service, printJobs); + UserState userState = mUserStates.get(removedUserId); + if (userState != null) { + userState.destroyLocked(); + mUserStates.remove(removedUserId); } } - if (notifications.isEmpty()) { - return false; + } + + private int resolveCallingAppEnforcingPermissions(int appId) { + final int callingUid = Binder.getCallingUid(); + if (callingUid == 0 || callingUid == Process.SYSTEM_UID + || callingUid == Process.SHELL_UID) { + return appId; } - for (Map.Entry<PrintServiceClient, List<PrintJobInfo>> notification - : notifications.entrySet()) { - PrintServiceClient service = notification.getKey(); - List<PrintJobInfo> printJobs = notification.getValue(); - final int printJobIdCount = printJobs.size(); - for (int i = 0; i < printJobIdCount; i++) { - service.notifyPrintJobQueued(printJobs.get(i)); - } + final int callingAppId = UserHandle.getAppId(callingUid); + if (appId == callingAppId) { + return appId; + } + if (mContext.checkCallingPermission(Manifest.permission.ACCESS_ALL_PRINT_JOBS) + != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException("Call from app " + callingAppId + " as app " + + appId + " without permission ACCESS_ALL_PRINT_JOBS"); } - return true; + return appId; } - private int resolveCallingUserEnforcingPermissionsIdLocked(int userId) { + private int resolveCallingUserEnforcingPermissions(int userId) { final int callingUid = Binder.getCallingUid(); if (callingUid == 0 || callingUid == Process.SYSTEM_UID || callingUid == Process.SHELL_UID) { @@ -524,8 +355,8 @@ public final class PrintManagerService extends IPrintManager.Stub { return callingUserId; } throw new SecurityException("Call from user " + callingUserId + " as user " - + userId + " without permission INTERACT_ACROSS_USERS or " - + "INTERACT_ACROSS_USERS_FULL not allowed."); + + userId + " without permission INTERACT_ACROSS_USERS or " + + "INTERACT_ACROSS_USERS_FULL not allowed."); } if (userId == UserHandle.USER_CURRENT || userId == UserHandle.USER_CURRENT_OR_SELF) { return mCurrentUserId; @@ -533,257 +364,4 @@ public final class PrintManagerService extends IPrintManager.Stub { throw new IllegalArgumentException("Calling user can be changed to only " + "UserHandle.USER_CURRENT or UserHandle.USER_CURRENT_OR_SELF."); } - - private int resolveCallingAppEnforcingPermissionsLocked(int appId) { - final int callingUid = Binder.getCallingUid(); - if (callingUid == 0 || callingUid == Process.SYSTEM_UID - || callingUid == Process.SHELL_UID) { - return appId; - } - final int callingAppId = UserHandle.getAppId(callingUid); - if (appId == callingAppId) { - return appId; - } - if (mContext.checkCallingPermission(Manifest.permission.ACCESS_ALL_PRINT_JOBS) - != PackageManager.PERMISSION_GRANTED) { - throw new SecurityException("Call from app " + callingAppId + " as app " - + appId + " without permission INTERACT_ACROSS_APPS"); - } - return appId; - } - - private final class PrintServiceClient extends IPrintServiceClient.Stub - implements ServiceConnection, DeathRecipient { - - private final ComponentName mComponentName; - - private final Intent mIntent; - - private final int mUserId; - - private IPrintService mInterface; - - private boolean mBinding; - - private boolean mWasConnectedAndDied; - - public PrintServiceClient(ComponentName componentName, int userId) { - mComponentName = componentName; - mIntent = new Intent().setComponent(mComponentName); - mUserId = userId; - } - - @Override - public List<PrintJobInfo> getPrintJobs() { - return mSpooler.getPrintJobs(mComponentName, PrintJobInfo.STATE_ANY, - PrintManager.APP_ID_ANY, mUserId); - } - - @Override - public PrintJobInfo getPrintJob(int printJobId) { - return mSpooler.getPrintJobInfo(printJobId, - PrintManager.APP_ID_ANY, mUserId); - } - - @Override - public boolean setPrintJobState(int printJobId, int state) { - return mSpooler.setPrintJobState(printJobId, state, mUserId); - } - - @Override - public boolean setPrintJobTag(int printJobId, String tag) { - return mSpooler.setPrintJobTag(printJobId, tag, mUserId); - } - - @Override - public void writePrintJobData(ParcelFileDescriptor fd, int printJobId) { - mSpooler.writePrintJobData(fd, printJobId, mUserId); - } - - @Override - public void addDiscoveredPrinters(List<PrinterInfo> printers) { - throwIfPrinterIdsForPrinterInfoTampered(printers); - synchronized (mLock) { - if (mPrinterDiscoveryObserver != null) { - try { - mPrinterDiscoveryObserver.addDiscoveredPrinters(printers); - } catch (RemoteException re) { - /* ignore */ - } - } - } - } - - @Override - public void removeDiscoveredPrinters(List<PrinterId> printerIds) { - throwIfPrinterIdsTampered(printerIds); - synchronized (mLock) { - if (mPrinterDiscoveryObserver != null) { - try { - mPrinterDiscoveryObserver.removeDiscoveredPrinters(printerIds); - } catch (RemoteException re) { - /* ignore */ - } - } - } - } - - public void requestCancelPrintJob(PrintJobInfo printJob) { - synchronized (mLock) { - try { - mInterface.requestCancelPrintJob(printJob); - } catch (RemoteException re) { - Slog.e(LOG_TAG, "Error canceling pring job!", re); - } - } - } - - public void notifyPrintJobQueued(PrintJobInfo printJob) { - IPrintService service = mInterface; - if (service != null) { - try { - service.onPrintJobQueued(printJob); - } catch (RemoteException re) { - /* ignore */ - } - } - } - - public void startPrinterDiscovery() { - IPrintService service = mInterface; - if (service != null) { - try { - service.startPrinterDiscovery(); - } catch (RemoteException re) { - /* ignore */ - } - } - } - - public void stopPrintersDiscovery() { - IPrintService service = mInterface; - if (service != null) { - try { - service.stopPrinterDiscovery(); - } catch (RemoteException re) { - /* ignore */ - } - } - } - - public void ensureBoundLocked() { - if (mBinding) { - return; - } - if (mInterface == null) { - mBinding = true; - mContext.bindServiceAsUser(mIntent, this, - Context.BIND_AUTO_CREATE, new UserHandle(mUserId)); - } - } - - public void ensureUnboundLocked() { - if (mBinding) { - mBinding = false; - return; - } - if (mInterface != null) { - mContext.unbindService(this); - destroyLocked(); - } - } - - @Override - public void onServiceConnected(ComponentName name, IBinder service) { - synchronized (mLock) { - mInterface = IPrintService.Stub.asInterface(service); - mServices.put(mComponentName, this); - try { - mInterface.asBinder().linkToDeath(this, 0); - } catch (RemoteException re) { - destroyLocked(); - return; - } - if (mUserId != mCurrentUserId) { - destroyLocked(); - return; - } - if (mBinding || mWasConnectedAndDied) { - mBinding = false; - mWasConnectedAndDied = false; - onUserStateChangedLocked(); - try { - mInterface.setClient(this); - } catch (RemoteException re) { - Slog.w(LOG_TAG, "Error while setting client for service: " - + service, re); - } - } else { - destroyLocked(); - } - } - } - - @Override - public void onServiceDisconnected(ComponentName name) { - /* do nothing - #binderDied takes care */ - } - - @Override - public void binderDied() { - synchronized (mLock) { - if (isConnectedLocked()) { - mWasConnectedAndDied = true; - } - destroyLocked(); - } - } - - private void destroyLocked() { - if (mServices.remove(mComponentName) == null) { - return; - } - if (isConnectedLocked()) { - try { - mInterface.asBinder().unlinkToDeath(this, 0); - } catch (NoSuchElementException nse) { - /* ignore */ - } - try { - mInterface.setClient(null); - } catch (RemoteException re) { - /* ignore */ - } - mInterface = null; - } - mBinding = false; - } - - private boolean isConnectedLocked() { - return (mInterface != null); - } - - private void throwIfPrinterIdsForPrinterInfoTampered(List<PrinterInfo> printerInfos) { - final int printerInfoCount = printerInfos.size(); - for (int i = 0; i < printerInfoCount; i++) { - PrinterId printerId = printerInfos.get(i).getId(); - throwIfPrinterIdTampered(printerId); - } - } - - private void throwIfPrinterIdsTampered(List<PrinterId> printerIds) { - final int printerIdCount = printerIds.size(); - for (int i = 0; i < printerIdCount; i++) { - PrinterId printerId = printerIds.get(i); - throwIfPrinterIdTampered(printerId); - } - } - - private void throwIfPrinterIdTampered(PrinterId printerId) { - if (printerId == null || printerId.getServiceComponentName() == null - || !printerId.getServiceComponentName().equals(mComponentName)) { - throw new IllegalArgumentException("Invalid printer id: " + printerId); - } - } - } } diff --git a/services/java/com/android/server/print/RemotePrintService.java b/services/java/com/android/server/print/RemotePrintService.java new file mode 100644 index 0000000..203bc86 --- /dev/null +++ b/services/java/com/android/server/print/RemotePrintService.java @@ -0,0 +1,466 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.print; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.os.Binder; +import android.os.Handler; +import android.os.IBinder; +import android.os.Looper; +import android.os.Message; +import android.os.ParcelFileDescriptor; +import android.os.RemoteException; +import android.os.UserHandle; +import android.print.IPrinterDiscoveryObserver; +import android.print.PrintJobInfo; +import android.print.PrintManager; +import android.print.PrinterId; +import android.print.PrinterInfo; +import android.printservice.IPrintService; +import android.printservice.IPrintServiceClient; +import android.util.Slog; + +import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.List; + +/** + * This class represents a remote print service. It abstracts away the binding + * and unbinding from the remote implementation. Clients can call methods of + * this class without worrying about when and how to bind/unbind. + */ +final class RemotePrintService { + + private static final String LOG_TAG = "RemotePrintService"; + + private static final boolean DEBUG = true; + + private final Context mContext; + + private final ComponentName mComponentName; + + private final Intent mIntent; + + private final RemotePrintSpooler mSpooler; + + private final int mUserId; + + private final List<Runnable> mPendingCommands = new ArrayList<Runnable>(); + + private final ServiceConnection mServiceConnection = new RemoteServiceConneciton(); + + private final RemotePrintServiceClient mPrintServiceClient; + + private final Handler mHandler; + + private IPrintService mPrintService; + + private boolean mBinding; + + private boolean mDestroyed; + + public RemotePrintService(Context context, ComponentName componentName, int userId, + RemotePrintSpooler spooler) { + mContext = context; + mComponentName = componentName; + mIntent = new Intent().setComponent(mComponentName); + mUserId = userId; + mSpooler = spooler; + mHandler = new MyHandler(context.getMainLooper()); + mPrintServiceClient = new RemotePrintServiceClient(this); + } + + public void destroy() { + mHandler.sendEmptyMessage(MyHandler.MSG_DESTROY); + } + + private void handleDestroy() { + throwIfDestroyed(); + ensureUnbound(); + mDestroyed = true; + } + + public void onAllPrintJobsHandled() { + mHandler.sendEmptyMessage(MyHandler.MSG_ALL_PRINT_JOBS_HANDLED); + } + + private void handleOnAllPrintJobsHandled() { + throwIfDestroyed(); + if (isBound()) { + if (DEBUG) { + Slog.i(LOG_TAG, "[user: " + mUserId + "] handleOnAllPrintJobsHandled()"); + } + // If bound and all the work is completed, then unbind. + ensureUnbound(); + } + } + + public void onRequestCancelPrintJob(PrintJobInfo printJob) { + mHandler.obtainMessage(MyHandler.MSG_REQUEST_CANCEL_PRINT_JOB, + printJob).sendToTarget(); + } + + private void handleOnRequestCancelPrintJob(final PrintJobInfo printJob) { + throwIfDestroyed(); + // If we are not bound, then we have no print jobs to handle + // which means that there are no print jobs to be cancelled. + if (isBound()) { + if (DEBUG) { + Slog.i(LOG_TAG, "[user: " + mUserId + "] handleOnRequestCancelPrintJob()"); + } + try { + mPrintService.requestCancelPrintJob(printJob); + } catch (RemoteException re) { + Slog.e(LOG_TAG, "Error canceling pring job.", re); + } + } + } + + public void onPrintJobQueued(PrintJobInfo printJob) { + mHandler.obtainMessage(MyHandler.MSG_PRINT_JOB_QUEUED, + printJob).sendToTarget(); + } + + private void handleOnPrintJobQueued(final PrintJobInfo printJob) { + throwIfDestroyed(); + if (!isBound()) { + ensureBound(); + mPendingCommands.add(new Runnable() { + @Override + public void run() { + handleOnPrintJobQueued(printJob); + } + }); + } else { + if (DEBUG) { + Slog.i(LOG_TAG, "[user: " + mUserId + "] handleOnPrintJobQueued()"); + } + try { + mPrintService.onPrintJobQueued(printJob); + } catch (RemoteException re) { + Slog.e(LOG_TAG, "Error announcing queued pring job.", re); + } + } + } + + public void onStartPrinterDiscovery(IPrinterDiscoveryObserver observer) { + mHandler.obtainMessage(MyHandler.MSG_START_PRINTER_DISCOVERY, observer).sendToTarget(); + } + + private void handleOnStartPrinterDiscovery(final IPrinterDiscoveryObserver observer) { + throwIfDestroyed(); + if (!isBound()) { + ensureBound(); + mPendingCommands.add(new Runnable() { + @Override + public void run() { + handleOnStartPrinterDiscovery(observer); + } + }); + } else { + if (DEBUG) { + Slog.i(LOG_TAG, "[user: " + mUserId + "] onStartPrinterDiscovery()"); + } + try { + mPrintService.startPrinterDiscovery(observer); + } catch (RemoteException re) { + Slog.e(LOG_TAG, "Error announcing start printer dicovery.", re); + } + } + } + + public void onStopPrinterDiscovery() { + mHandler.sendEmptyMessage(MyHandler.MSG_STOP_PRINTER_DISCOVERY); + } + + private void handleStopPrinterDiscovery() { + throwIfDestroyed(); + if (!isBound()) { + ensureBound(); + mPendingCommands.add(new Runnable() { + @Override + public void run() { + handleStopPrinterDiscovery(); + } + }); + } else { + if (DEBUG) { + Slog.i(LOG_TAG, "[user: " + mUserId + "] onStopPrinterDiscovery()"); + } + try { + mPrintService.stopPrinterDiscovery(); + } catch (RemoteException re) { + Slog.e(LOG_TAG, "Error announcing stop printer dicovery.", re); + } + } + } + + private boolean isBound() { + return mPrintService != null; + } + + private void ensureBound() { + if (isBound() || mBinding) { + return; + } + if (DEBUG) { + Slog.i(LOG_TAG, "[user: " + mUserId + "] ensureBound()"); + } + mBinding = true; + mContext.bindServiceAsUser(mIntent, mServiceConnection, + Context.BIND_AUTO_CREATE, new UserHandle(mUserId)); + } + + private void ensureUnbound() { + if (!isBound() && !mBinding) { + return; + } + if (DEBUG) { + Slog.i(LOG_TAG, "[user: " + mUserId + "] ensureUnbound()"); + } + mBinding = false; + mPendingCommands.clear(); + if (isBound()) { + try { + mPrintService.setClient(null); + } catch (RemoteException re) { + /* ignore */ + } + mPrintService = null; + mContext.unbindService(mServiceConnection); + } + } + + private void throwIfDestroyed() { + if (mDestroyed) { + throw new IllegalStateException("Cannot interact with a destroyed service"); + } + } + + private class RemoteServiceConneciton implements ServiceConnection { + @Override + public void onServiceConnected(ComponentName name, IBinder service) { + if (mDestroyed || !mBinding) { + return; + } + mBinding = false; + mPrintService = IPrintService.Stub.asInterface(service); + try { + mPrintService.setClient(mPrintServiceClient); + } catch (RemoteException re) { + Slog.e(LOG_TAG, "Error setting client for: " + service, re); + handleDestroy(); + return; + } + final int pendingCommandCount = mPendingCommands.size(); + for (int i = 0; i < pendingCommandCount; i++) { + Runnable pendingCommand = mPendingCommands.get(i); + pendingCommand.run(); + } + } + + @Override + public void onServiceDisconnected(ComponentName name) { + mBinding = true; + } + } + + private final class MyHandler extends Handler { + public static final int MSG_ALL_PRINT_JOBS_HANDLED = 1; + public static final int MSG_REQUEST_CANCEL_PRINT_JOB = 2; + public static final int MSG_PRINT_JOB_QUEUED = 3; + public static final int MSG_START_PRINTER_DISCOVERY = 4; + public static final int MSG_STOP_PRINTER_DISCOVERY = 5; + public static final int MSG_DESTROY = 6; + + public MyHandler(Looper looper) { + super(looper, null, false); + } + + @Override + public void handleMessage(Message message) { + switch (message.what) { + case MSG_ALL_PRINT_JOBS_HANDLED: { + handleOnAllPrintJobsHandled(); + } break; + + case MSG_REQUEST_CANCEL_PRINT_JOB: { + PrintJobInfo printJob = (PrintJobInfo) message.obj; + handleOnRequestCancelPrintJob(printJob); + } break; + + case MSG_PRINT_JOB_QUEUED: { + PrintJobInfo printJob = (PrintJobInfo) message.obj; + handleOnPrintJobQueued(printJob); + } break; + + case MSG_START_PRINTER_DISCOVERY: { + IPrinterDiscoveryObserver observer = (IPrinterDiscoveryObserver) message.obj; + handleOnStartPrinterDiscovery(new SecurePrinterDiscoveryObserver( + mComponentName, observer)); + } break; + + case MSG_STOP_PRINTER_DISCOVERY: { + handleStopPrinterDiscovery(); + } break; + + case MSG_DESTROY: { + handleDestroy(); + } break; + } + } + } + + private static final class RemotePrintServiceClient extends IPrintServiceClient.Stub { + private final WeakReference<RemotePrintService> mWeakService; + + public RemotePrintServiceClient(RemotePrintService service) { + mWeakService = new WeakReference<RemotePrintService>(service); + } + + @Override + public List<PrintJobInfo> getPrintJobInfos() { + RemotePrintService service = mWeakService.get(); + if (service != null) { + final long identity = Binder.clearCallingIdentity(); + try { + return service.mSpooler.getPrintJobInfos(service.mComponentName, + PrintJobInfo.STATE_ANY_VISIBLE_TO_CLIENTS, PrintManager.APP_ID_ANY); + } finally { + Binder.restoreCallingIdentity(identity); + } + } + return null; + } + + @Override + public PrintJobInfo getPrintJobInfo(int printJobId) { + RemotePrintService service = mWeakService.get(); + if (service != null) { + final long identity = Binder.clearCallingIdentity(); + try { + return service.mSpooler.getPrintJobInfo(printJobId, + PrintManager.APP_ID_ANY); + } finally { + Binder.restoreCallingIdentity(identity); + } + } + return null; + } + + @Override + public boolean setPrintJobState(int printJobId, int state) { + RemotePrintService service = mWeakService.get(); + if (service != null) { + final long identity = Binder.clearCallingIdentity(); + try { + return service.mSpooler.setPrintJobState(printJobId, state); + } finally { + Binder.restoreCallingIdentity(identity); + } + } + return false; + } + + @Override + public boolean setPrintJobTag(int printJobId, String tag) { + RemotePrintService service = mWeakService.get(); + if (service != null) { + final long identity = Binder.clearCallingIdentity(); + try { + return service.mSpooler.setPrintJobTag(printJobId, tag); + } finally { + Binder.restoreCallingIdentity(identity); + } + } + return false; + } + + @Override + public void writePrintJobData(ParcelFileDescriptor fd, int printJobId) { + RemotePrintService service = mWeakService.get(); + if (service != null) { + final long identity = Binder.clearCallingIdentity(); + try { + service.mSpooler.writePrintJobData(fd, printJobId); + } finally { + Binder.restoreCallingIdentity(identity); + } + } + } + } + + private static final class SecurePrinterDiscoveryObserver + extends IPrinterDiscoveryObserver.Stub { + private final ComponentName mComponentName; + + private final IPrinterDiscoveryObserver mDecoratedObsever; + + public SecurePrinterDiscoveryObserver(ComponentName componentName, + IPrinterDiscoveryObserver observer) { + mComponentName = componentName; + mDecoratedObsever = observer; + } + + @Override + public void addDiscoveredPrinters(List<PrinterInfo> printers) { + throwIfPrinterIdsForPrinterInfoTampered(printers); + try { + mDecoratedObsever.addDiscoveredPrinters(printers); + } catch (RemoteException re) { + Slog.e(LOG_TAG, "Error delegating to addDiscoveredPrinters", re); + } + } + + @Override + public void removeDiscoveredPrinters(List<PrinterId> printerIds) { + throwIfPrinterIdsTampered(printerIds); + try { + mDecoratedObsever.removeDiscoveredPrinters(printerIds); + } catch (RemoteException re) { + Slog.e(LOG_TAG, "Error delegating to removeDiscoveredPrinters", re); + } + } + + private void throwIfPrinterIdsForPrinterInfoTampered( + List<PrinterInfo> printerInfos) { + final int printerInfoCount = printerInfos.size(); + for (int i = 0; i < printerInfoCount; i++) { + PrinterId printerId = printerInfos.get(i).getId(); + throwIfPrinterIdTampered(printerId); + } + } + + private void throwIfPrinterIdsTampered(List<PrinterId> printerIds) { + final int printerIdCount = printerIds.size(); + for (int i = 0; i < printerIdCount; i++) { + PrinterId printerId = printerIds.get(i); + throwIfPrinterIdTampered(printerId); + } + } + + private void throwIfPrinterIdTampered(PrinterId printerId) { + if (printerId == null || printerId.getService() == null + || !printerId.getService().equals(mComponentName)) { + throw new IllegalArgumentException("Invalid printer id: " + printerId); + } + } + } +} diff --git a/services/java/com/android/server/print/RemotePrintSpooler.java b/services/java/com/android/server/print/RemotePrintSpooler.java new file mode 100644 index 0000000..6445c2e --- /dev/null +++ b/services/java/com/android/server/print/RemotePrintSpooler.java @@ -0,0 +1,612 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.print; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.os.Binder; +import android.os.IBinder; +import android.os.ParcelFileDescriptor; +import android.os.RemoteException; +import android.os.SystemClock; +import android.os.UserHandle; +import android.print.IPrintClient; +import android.print.IPrintDocumentAdapter; +import android.print.IPrintSpooler; +import android.print.IPrintSpoolerCallbacks; +import android.print.IPrintSpoolerClient; +import android.print.IPrinterDiscoveryObserver; +import android.print.PrintAttributes; +import android.print.PrintJobInfo; +import android.util.Slog; +import android.util.TimedRemoteCaller; + +import libcore.io.IoUtils; + +import java.lang.ref.WeakReference; +import java.util.List; +import java.util.concurrent.TimeoutException; + +/** + * This represents the remote print spooler as a local object to the + * PrintManagerSerivce. It is responsible to connecting to the remote + * spooler if needed, to make the timed remote calls, to handle + * remote exceptions, and to bind/unbind to the remote instance as + * needed. + */ +final class RemotePrintSpooler { + + private static final String LOG_TAG = "RemotePrintSpooler"; + + private static final boolean DEBUG = true; + + private static final long BIND_SPOOLER_SERVICE_TIMEOUT = 10000; + + private final Object mLock = new Object(); + + private final GetPrintJobInfosCaller mGetPrintJobInfosCaller = new GetPrintJobInfosCaller(); + + private final CreatePrintJobCaller mCreatePrintJobCaller = new CreatePrintJobCaller(); + + private final CancelPrintJobCaller mCancelPrintJobCaller = new CancelPrintJobCaller(); + + private final GetPrintJobInfoCaller mGetPrintJobInfoCaller = new GetPrintJobInfoCaller(); + + private final SetPrintJobStateCaller mSetPrintJobStatusCaller = new SetPrintJobStateCaller(); + + private final SetPrintJobTagCaller mSetPrintJobTagCaller = new SetPrintJobTagCaller(); + + private final ServiceConnection mServiceConnection = new MyServiceConnection(); + + private final Context mContext; + + private final UserHandle mUserHandle; + + private final PrintSpoolerClient mClient; + + private final Intent mIntent; + + private final PrintSpoolerCallbacks mCallbacks; + + private IPrintSpooler mRemoteInstance; + + private boolean mDestroyed; + + public static interface PrintSpoolerCallbacks { + public void onPrintJobQueued(PrintJobInfo printJob); + public void onStartPrinterDiscovery(IPrinterDiscoveryObserver observer); + public void onStopPrinterDiscovery(); + public void onAllPrintJobsForServiceHandled(ComponentName printService); + } + + public RemotePrintSpooler(Context context, int userId, + PrintSpoolerCallbacks callbacks) { + mContext = context; + mUserHandle = new UserHandle(userId); + mCallbacks = callbacks; + mClient = new PrintSpoolerClient(this); + mIntent = new Intent(); + mIntent.setComponent(new ComponentName("com.android.printspooler", + "com.android.printspooler.PrintSpoolerService")); + } + + public final List<PrintJobInfo> getPrintJobInfos(ComponentName componentName, int state, + int appId) { + throwIfCalledOnMainThread(); + synchronized (mLock) { + throwIfDestroyedLocked(); + } + if (DEBUG) { + Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() + "] getPrintJobInfos()"); + } + try { + return mGetPrintJobInfosCaller.getPrintJobInfos(getRemoteInstanceLazy(), + componentName, state, appId); + } catch (RemoteException re) { + Slog.e(LOG_TAG, "Error getting print jobs.", re); + } catch (TimeoutException te) { + Slog.e(LOG_TAG, "Error getting print jobs.", te); + } + return null; + } + + public final PrintJobInfo createPrintJob(String printJobName, IPrintClient client, + IPrintDocumentAdapter documentAdapter, PrintAttributes attributes, int appId) { + throwIfCalledOnMainThread(); + synchronized (mLock) { + throwIfDestroyedLocked(); + } + if (DEBUG) { + Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() + "] createPrintJob()"); + } + try { + return mCreatePrintJobCaller.createPrintJob(getRemoteInstanceLazy(), + printJobName, client, documentAdapter, attributes, appId); + } catch (RemoteException re) { + Slog.e(LOG_TAG, "Error creating print job.", re); + } catch (TimeoutException te) { + Slog.e(LOG_TAG, "Error creating print job.", te); + } + return null; + } + + public final boolean cancelPrintJob(int printJobId, int appId) { + throwIfCalledOnMainThread(); + synchronized (mLock) { + throwIfDestroyedLocked(); + } + if (DEBUG) { + Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() + "] cancelPrintJob()"); + } + try { + return mCancelPrintJobCaller.cancelPrintJob(getRemoteInstanceLazy(), + printJobId, appId); + } catch (RemoteException re) { + Slog.e(LOG_TAG, "Error canceling print job.", re); + } catch (TimeoutException te) { + Slog.e(LOG_TAG, "Error canceling print job.", te); + } + return false; + } + + public final void writePrintJobData(ParcelFileDescriptor fd, int printJobId) { + throwIfCalledOnMainThread(); + synchronized (mLock) { + throwIfDestroyedLocked(); + } + if (DEBUG) { + Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() + "] writePrintJobData()"); + } + try { + getRemoteInstanceLazy().writePrintJobData(fd, printJobId); + } catch (RemoteException re) { + Slog.e(LOG_TAG, "Error writing print job data.", re); + } catch (TimeoutException te) { + Slog.e(LOG_TAG, "Error writing print job data.", te); + } finally { + // We passed the file descriptor across and now the other + // side is responsible to close it, so close the local copy. + IoUtils.closeQuietly(fd); + } + } + + public final PrintJobInfo getPrintJobInfo(int printJobId, int appId) { + throwIfCalledOnMainThread(); + synchronized (mLock) { + throwIfDestroyedLocked(); + } + if (DEBUG) { + Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() + "] getPrintJobInfo()"); + } + try { + return mGetPrintJobInfoCaller.getPrintJobInfo(getRemoteInstanceLazy(), + printJobId, appId); + } catch (RemoteException re) { + Slog.e(LOG_TAG, "Error getting print job info.", re); + } catch (TimeoutException te) { + Slog.e(LOG_TAG, "Error getting print job info.", te); + } + return null; + } + + public final boolean setPrintJobState(int printJobId, int state) { + throwIfCalledOnMainThread(); + synchronized (mLock) { + throwIfDestroyedLocked(); + } + if (DEBUG) { + Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() + "] setPrintJobState()"); + } + try { + return mSetPrintJobStatusCaller.setPrintJobState(getRemoteInstanceLazy(), + printJobId, state); + } catch (RemoteException re) { + Slog.e(LOG_TAG, "Error setting print job state.", re); + } catch (TimeoutException te) { + Slog.e(LOG_TAG, "Error setting print job state.", te); + } + return false; + } + + public final boolean setPrintJobTag(int printJobId, String tag) { + throwIfCalledOnMainThread(); + synchronized (mLock) { + throwIfDestroyedLocked(); + } + if (DEBUG) { + Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() + "] setPrintJobTag()"); + } + try { + return mSetPrintJobTagCaller.setPrintJobTag(getRemoteInstanceLazy(), + printJobId, tag); + } catch (RemoteException re) { + Slog.e(LOG_TAG, "Error setting print job tag.", re); + } catch (TimeoutException te) { + Slog.e(LOG_TAG, "Error setting print job tag.", te); + } + return false; + } + + public final void notifyClientForActivteJobs() { + throwIfCalledOnMainThread(); + synchronized (mLock) { + throwIfDestroyedLocked(); + } + if (DEBUG) { + Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() + + "] notifyClientForActivteJobs()"); + } + try { + getRemoteInstanceLazy().notifyClientForActivteJobs(); + } catch (RemoteException re) { + Slog.e(LOG_TAG, "Error asking for active print job notification.", re); + } catch (TimeoutException te) { + Slog.e(LOG_TAG, "Error asking for active print job notification.", te); + } + } + + public final void destroy() { + throwIfCalledOnMainThread(); + if (DEBUG) { + Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() + "] destroy()"); + } + synchronized (mLock) { + throwIfDestroyedLocked(); + unbindLocked(); + mDestroyed = true; + } + } + + private void onAllPrintJobsHandled() { + synchronized (mLock) { + throwIfDestroyedLocked(); + unbindLocked(); + } + } + + private IPrintSpooler getRemoteInstanceLazy() throws TimeoutException { + synchronized (mLock) { + if (mRemoteInstance != null) { + return mRemoteInstance; + } + bindLocked(); + return mRemoteInstance; + } + } + + private void bindLocked() throws TimeoutException { + if (DEBUG) { + Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() + "] bindLocked()"); + } + + mContext.bindServiceAsUser(mIntent, mServiceConnection, + Context.BIND_AUTO_CREATE, mUserHandle); + + final long startMillis = SystemClock.uptimeMillis(); + while (true) { + if (mRemoteInstance != null) { + break; + } + final long elapsedMillis = SystemClock.uptimeMillis() - startMillis; + final long remainingMillis = BIND_SPOOLER_SERVICE_TIMEOUT - elapsedMillis; + if (remainingMillis <= 0) { + throw new TimeoutException("Cannot get spooler!"); + } + try { + mLock.wait(remainingMillis); + } catch (InterruptedException ie) { + /* ignore */ + } + } + } + + private void unbindLocked() { + if (DEBUG) { + Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() + "] unbindLocked()"); + } + clearClientLocked(); + mRemoteInstance = null; + mContext.unbindService(mServiceConnection); + } + + private void setClientLocked() { + try { + mRemoteInstance.setClient(mClient); + } catch (RemoteException re) { + Slog.d(LOG_TAG, "Error setting print spooler client", re); + } + } + + private void clearClientLocked() { + try { + mRemoteInstance.setClient(null); + } catch (RemoteException re) { + Slog.d(LOG_TAG, "Error clearing print spooler client", re); + } + + } + + private void throwIfDestroyedLocked() { + if (mDestroyed) { + throw new IllegalStateException("Cannot interact with a destroyed instance."); + } + } + + private void throwIfCalledOnMainThread() { + if (Thread.currentThread() == mContext.getMainLooper().getThread()) { + throw new RuntimeException("Cannot invoke on the main thread"); + } + } + + private final class MyServiceConnection implements ServiceConnection { + @Override + public void onServiceConnected(ComponentName name, IBinder service) { + synchronized (mLock) { + mRemoteInstance = IPrintSpooler.Stub.asInterface(service); + setClientLocked(); + mLock.notifyAll(); + } + } + + @Override + public void onServiceDisconnected(ComponentName name) { + synchronized (mLock) { + clearClientLocked(); + mRemoteInstance = null; + } + } + } + + private static final class GetPrintJobInfosCaller + extends TimedRemoteCaller<List<PrintJobInfo>> { + private final IPrintSpoolerCallbacks mCallback; + + public GetPrintJobInfosCaller() { + super(TimedRemoteCaller.DEFAULT_CALL_TIMEOUT_MILLIS); + mCallback = new BasePrintSpoolerServiceCallbacks() { + @Override + public void onGetPrintJobInfosResult(List<PrintJobInfo> printJobs, int sequence) { + onRemoteMethodResult(printJobs, sequence); + } + }; + } + + public List<PrintJobInfo> getPrintJobInfos(IPrintSpooler target, + ComponentName componentName, int state, int appId) + throws RemoteException, TimeoutException { + final int sequence = onBeforeRemoteCall(); + target.getPrintJobInfos(mCallback, componentName, state, appId, sequence); + return getResultTimed(sequence); + } + } + + private static final class CreatePrintJobCaller extends TimedRemoteCaller<PrintJobInfo> { + private final IPrintSpoolerCallbacks mCallback; + + public CreatePrintJobCaller() { + super(TimedRemoteCaller.DEFAULT_CALL_TIMEOUT_MILLIS); + mCallback = new BasePrintSpoolerServiceCallbacks() { + @Override + public void onCreatePrintJobResult(PrintJobInfo printJob, int sequence) { + onRemoteMethodResult(printJob, sequence); + } + }; + } + + public PrintJobInfo createPrintJob(IPrintSpooler target, String printJobName, + IPrintClient client, IPrintDocumentAdapter documentAdapter, + PrintAttributes attributes, int appId) throws RemoteException, TimeoutException { + final int sequence = onBeforeRemoteCall(); + target.createPrintJob(printJobName, client, documentAdapter, attributes, + mCallback, appId, sequence); + return getResultTimed(sequence); + } + } + + private static final class CancelPrintJobCaller extends TimedRemoteCaller<Boolean> { + private final IPrintSpoolerCallbacks mCallback; + + public CancelPrintJobCaller() { + super(TimedRemoteCaller.DEFAULT_CALL_TIMEOUT_MILLIS); + mCallback = new BasePrintSpoolerServiceCallbacks() { + @Override + public void onCancelPrintJobResult(boolean canceled, int sequence) { + onRemoteMethodResult(canceled, sequence); + } + }; + } + + public boolean cancelPrintJob(IPrintSpooler target, int printJobId, + int appId) throws RemoteException, TimeoutException { + final int sequence = onBeforeRemoteCall(); + target.cancelPrintJob(printJobId, mCallback, appId, sequence); + return getResultTimed(sequence); + } + } + + private static final class GetPrintJobInfoCaller extends TimedRemoteCaller<PrintJobInfo> { + private final IPrintSpoolerCallbacks mCallback; + + public GetPrintJobInfoCaller() { + super(TimedRemoteCaller.DEFAULT_CALL_TIMEOUT_MILLIS); + mCallback = new BasePrintSpoolerServiceCallbacks() { + @Override + public void onGetPrintJobInfoResult(PrintJobInfo printJob, int sequence) { + onRemoteMethodResult(printJob, sequence); + } + }; + } + + public PrintJobInfo getPrintJobInfo(IPrintSpooler target, int printJobId, + int appId) throws RemoteException, TimeoutException { + final int sequence = onBeforeRemoteCall(); + target.getPrintJobInfo(printJobId, mCallback, appId, sequence); + return getResultTimed(sequence); + } + } + + private static final class SetPrintJobStateCaller extends TimedRemoteCaller<Boolean> { + private final IPrintSpoolerCallbacks mCallback; + + public SetPrintJobStateCaller() { + super(TimedRemoteCaller.DEFAULT_CALL_TIMEOUT_MILLIS); + mCallback = new BasePrintSpoolerServiceCallbacks() { + @Override + public void onSetPrintJobStateResult(boolean success, int sequence) { + onRemoteMethodResult(success, sequence); + } + }; + } + + public boolean setPrintJobState(IPrintSpooler target, int printJobId, + int status) throws RemoteException, TimeoutException { + final int sequence = onBeforeRemoteCall(); + target.setPrintJobState(printJobId, status, mCallback, sequence); + return getResultTimed(sequence); + } + } + + private static final class SetPrintJobTagCaller extends TimedRemoteCaller<Boolean> { + private final IPrintSpoolerCallbacks mCallback; + + public SetPrintJobTagCaller() { + super(TimedRemoteCaller.DEFAULT_CALL_TIMEOUT_MILLIS); + mCallback = new BasePrintSpoolerServiceCallbacks() { + @Override + public void onSetPrintJobTagResult(boolean success, int sequence) { + onRemoteMethodResult(success, sequence); + } + }; + } + + public boolean setPrintJobTag(IPrintSpooler target, int printJobId, + String tag) throws RemoteException, TimeoutException { + final int sequence = onBeforeRemoteCall(); + target.setPrintJobTag(printJobId, tag, mCallback, sequence); + return getResultTimed(sequence); + } + } + + private static abstract class BasePrintSpoolerServiceCallbacks + extends IPrintSpoolerCallbacks.Stub { + @Override + public void onGetPrintJobInfosResult(List<PrintJobInfo> printJobIds, int sequence) { + /* do nothing */ + } + + @Override + public void onGetPrintJobInfoResult(PrintJobInfo printJob, int sequence) { + /* do nothing */ + } + + @Override + public void onCreatePrintJobResult(PrintJobInfo printJob, int sequence) { + /* do nothing */ + } + + @Override + public void onCancelPrintJobResult(boolean canceled, int sequence) { + /* do nothing */ + } + + @Override + public void onSetPrintJobStateResult(boolean success, int sequece) { + /* do nothing */ + } + + @Override + public void onSetPrintJobTagResult(boolean success, int sequence) { + /* do nothing */ + } + } + + private static final class PrintSpoolerClient extends IPrintSpoolerClient.Stub { + + private final WeakReference<RemotePrintSpooler> mWeakSpooler; + + public PrintSpoolerClient(RemotePrintSpooler spooler) { + mWeakSpooler = new WeakReference<RemotePrintSpooler>(spooler); + } + + @Override + public void onPrintJobQueued(PrintJobInfo printJob) { + RemotePrintSpooler spooler = mWeakSpooler.get(); + if (spooler != null) { + final long identity = Binder.clearCallingIdentity(); + try { + spooler.mCallbacks.onPrintJobQueued(printJob); + } finally { + Binder.restoreCallingIdentity(identity); + } + } + } + + @Override + public void onAllPrintJobsForServiceHandled(ComponentName printService) { + RemotePrintSpooler spooler = mWeakSpooler.get(); + if (spooler != null) { + final long identity = Binder.clearCallingIdentity(); + try { + spooler.mCallbacks.onAllPrintJobsForServiceHandled(printService); + } finally { + Binder.restoreCallingIdentity(identity); + } + } + } + + @Override + public void onAllPrintJobsHandled() { + RemotePrintSpooler spooler = mWeakSpooler.get(); + if (spooler != null) { + final long identity = Binder.clearCallingIdentity(); + try { + spooler.onAllPrintJobsHandled(); + } finally { + Binder.restoreCallingIdentity(identity); + } + } + } + + @Override + public void onStartPrinterDiscovery(IPrinterDiscoveryObserver observer) { + RemotePrintSpooler spooler = mWeakSpooler.get(); + if (spooler != null) { + final long identity = Binder.clearCallingIdentity(); + try { + spooler.mCallbacks.onStartPrinterDiscovery(observer); + } finally { + Binder.restoreCallingIdentity(identity); + } + } + } + + @Override + public void onStopPrinterDiscovery() throws RemoteException { + RemotePrintSpooler spooler = mWeakSpooler.get(); + if (spooler != null) { + final long identity = Binder.clearCallingIdentity(); + try { + spooler.mCallbacks.onStopPrinterDiscovery(); + } finally { + Binder.restoreCallingIdentity(identity); + } + } + } + } +} diff --git a/services/java/com/android/server/print/RemoteSpooler.java b/services/java/com/android/server/print/RemoteSpooler.java deleted file mode 100644 index fef5818..0000000 --- a/services/java/com/android/server/print/RemoteSpooler.java +++ /dev/null @@ -1,416 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.print; - -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.content.ServiceConnection; -import android.os.Binder; -import android.os.IBinder; -import android.os.ParcelFileDescriptor; -import android.os.RemoteException; -import android.os.SystemClock; -import android.os.UserHandle; -import android.os.IBinder.DeathRecipient; -import android.print.IPrintAdapter; -import android.print.IPrintClient; -import android.print.IPrintSpoolerService; -import android.print.IPrintSpoolerServiceCallbacks; -import android.print.PrintAttributes; -import android.print.PrintJobInfo; -import android.util.Slog; -import android.util.TimedRemoteCaller; - -import java.io.IOException; -import java.util.List; -import java.util.concurrent.TimeoutException; - -/** - * This represents the remote print spooler as a local object to the - * PrintManagerSerivce. It is responsible to connecting to the remove - * spooler if needed, to make the timed out remote calls, and to handle - * remove exceptions. - */ -final class RemoteSpooler implements ServiceConnection, DeathRecipient { - - private static final String LOG_TAG = "Spooler"; - - private static final long BIND_SPOOLER_SERVICE_TIMEOUT = 10000; - - private final Object mLock = new Object(); - - private final Context mContext; - - private final Intent mIntent; - - private final GetPrintJobsCaller mGetPrintJobsCaller = new GetPrintJobsCaller(); - - private final CreatePrintJobCaller mCreatePrintJobCaller = new CreatePrintJobCaller(); - - private final CancelPrintJobCaller mCancelPrintJobCaller = new CancelPrintJobCaller(); - - private final GetPrintJobCaller mGetPrintJobCaller = new GetPrintJobCaller(); - - private final SetPrintJobStateCaller mSetPrintJobStatusCaller = new SetPrintJobStateCaller(); - - private final SetPrintJobTagCaller mSetPrintJobTagCaller = new SetPrintJobTagCaller(); - - private IPrintSpoolerService mRemoteInterface; - - private int mUserId = UserHandle.USER_NULL; - - public RemoteSpooler(Context context) { - mContext = context; - mIntent = new Intent(); - mIntent.setComponent(new ComponentName("com.android.printspooler", - "com.android.printspooler.PrintSpoolerService")); - } - - public List<PrintJobInfo> getPrintJobs(ComponentName componentName, int state, int appId, - int userId) { - try { - return mGetPrintJobsCaller.getPrintJobs(getRemoteInstance(userId), - componentName, state, appId); - } catch (RemoteException re) { - Slog.e(LOG_TAG, "Error getting print jobs!", re); - } catch (TimeoutException te) { - Slog.e(LOG_TAG, "Error getting print jobs!", te); - } - return null; - } - - public PrintJobInfo createPrintJob(String printJobName, IPrintClient client, - IPrintAdapter printAdapter, PrintAttributes attributes, int appId, int userId) { - try { - return mCreatePrintJobCaller.createPrintJob(getRemoteInstance(userId), - printJobName, client, printAdapter, attributes, appId); - } catch (RemoteException re) { - Slog.e(LOG_TAG, "Error creating print job!", re); - } catch (TimeoutException te) { - Slog.e(LOG_TAG, "Error creating print job!", te); - } - return null; - } - - public boolean cancelPrintJob(int printJobId, int appId, int userId) { - try { - return mCancelPrintJobCaller.cancelPrintJob(getRemoteInstance(userId), - printJobId, appId); - } catch (RemoteException re) { - Slog.e(LOG_TAG, "Error canceling print job!", re); - } catch (TimeoutException te) { - Slog.e(LOG_TAG, "Error canceling print job!", te); - } - return false; - } - - public void writePrintJobData(ParcelFileDescriptor fd, int printJobId, int userId) { - try { - getRemoteInstance(userId).writePrintJobData(fd, printJobId); - } catch (RemoteException re) { - Slog.e(LOG_TAG, "Error writing print job data!", re); - } catch (TimeoutException te) { - Slog.e(LOG_TAG, "Error writing print job data!", te); - } finally { - // We passed the file descriptor across and now the other - // side is responsible to close it, so close the local copy. - try { - fd.close(); - } catch (IOException ioe) { - /* ignore */ - } - } - } - - public PrintJobInfo getPrintJobInfo(int printJobId, int appId, int userId) { - try { - return mGetPrintJobCaller.getPrintJobInfo(getRemoteInstance(userId), - printJobId, appId); - } catch (RemoteException re) { - Slog.e(LOG_TAG, "Error getting print job!", re); - } catch (TimeoutException te) { - Slog.e(LOG_TAG, "Error getting print job!", te); - } - return null; - } - - public boolean setPrintJobState(int printJobId, int state, int userId) { - try { - return mSetPrintJobStatusCaller.setPrintJobState(getRemoteInstance(userId), - printJobId, state); - } catch (RemoteException re) { - Slog.e(LOG_TAG, "Error setting print job status!", re); - } catch (TimeoutException te) { - Slog.e(LOG_TAG, "Error setting print job status!", te); - } - return false; - } - - public boolean setPrintJobTag(int printJobId, String tag, int userId) { - try { - return mSetPrintJobTagCaller.setPrintJobTag(getRemoteInstance(userId), - printJobId, tag); - } catch (RemoteException re) { - Slog.e(LOG_TAG, "Error setting print job tag!", re); - } catch (TimeoutException te) { - Slog.e(LOG_TAG, "Error setting print job tag!", te); - } - return false; - } - - @Override - public void onServiceDisconnected(ComponentName name) { - binderDied(); - } - - @Override - public void onServiceConnected(ComponentName name, IBinder service) { - synchronized (mLock) { - try { - service.linkToDeath(this, 0); - mRemoteInterface = IPrintSpoolerService.Stub.asInterface(service); - } catch (RemoteException re) { - /* ignore */ - } - } - } - - private IPrintSpoolerService getRemoteInstance(int userId) throws TimeoutException { - synchronized (mLock) { - if (mRemoteInterface != null && mUserId == userId) { - return mRemoteInterface; - } - - final long identity = Binder.clearCallingIdentity(); - try { - if (mUserId != UserHandle.USER_NULL && mUserId != userId) { - unbind(); - } - - mContext.bindServiceAsUser(mIntent, this, - Context.BIND_AUTO_CREATE | Context.BIND_ALLOW_OOM_MANAGEMENT, - UserHandle.CURRENT); - } finally { - Binder.restoreCallingIdentity(identity); - } - - final long startMillis = SystemClock.uptimeMillis(); - while (true) { - if (mRemoteInterface != null) { - break; - } - final long elapsedMillis = SystemClock.uptimeMillis() - startMillis; - final long remainingMillis = BIND_SPOOLER_SERVICE_TIMEOUT - elapsedMillis; - if (remainingMillis <= 0) { - throw new TimeoutException("Cannot get spooler!"); - } - try { - mLock.wait(remainingMillis); - } catch (InterruptedException ie) { - /* ignore */ - } - } - - mUserId = userId; - - return mRemoteInterface; - } - } - - public void unbind() { - synchronized (mLock) { - if (mRemoteInterface != null) { - mContext.unbindService(this); - mRemoteInterface = null; - mUserId = UserHandle.USER_NULL; - } - } - } - - @Override - public void binderDied() { - synchronized (mLock) { - if (mRemoteInterface != null) { - mRemoteInterface.asBinder().unlinkToDeath(this, 0); - mRemoteInterface = null; - } - } - } - - private final class GetPrintJobsCaller extends TimedRemoteCaller<List<PrintJobInfo>> { - private final IPrintSpoolerServiceCallbacks mCallback; - - public GetPrintJobsCaller() { - super(TimedRemoteCaller.DEFAULT_CALL_TIMEOUT_MILLIS); - mCallback = new BasePrintSpoolerServiceCallbacks() { - @Override - public void onGetPrintJobsResult(List<PrintJobInfo> printJobs, int sequence) { - onRemoteMethodResult(printJobs, sequence); - } - }; - } - - public List<PrintJobInfo> getPrintJobs(IPrintSpoolerService target, - ComponentName componentName, int state, int appId) - throws RemoteException, TimeoutException { - final int sequence = onBeforeRemoteCall(); - target.getPrintJobs(mCallback, componentName, state, appId, sequence); - return getResultTimed(sequence); - } - } - - private final class CreatePrintJobCaller extends TimedRemoteCaller<PrintJobInfo> { - private final IPrintSpoolerServiceCallbacks mCallback; - - public CreatePrintJobCaller() { - super(TimedRemoteCaller.DEFAULT_CALL_TIMEOUT_MILLIS); - mCallback = new BasePrintSpoolerServiceCallbacks() { - @Override - public void onCreatePrintJobResult(PrintJobInfo printJob, int sequence) { - onRemoteMethodResult(printJob, sequence); - } - }; - } - - public PrintJobInfo createPrintJob(IPrintSpoolerService target, String printJobName, - IPrintClient client, IPrintAdapter printAdapter, PrintAttributes attributes, - int appId) throws RemoteException, TimeoutException { - final int sequence = onBeforeRemoteCall(); - target.createPrintJob(printJobName, client, printAdapter, attributes, - mCallback, appId, sequence); - return getResultTimed(sequence); - } - } - - private final class CancelPrintJobCaller extends TimedRemoteCaller<Boolean> { - private final IPrintSpoolerServiceCallbacks mCallback; - - public CancelPrintJobCaller() { - super(TimedRemoteCaller.DEFAULT_CALL_TIMEOUT_MILLIS); - mCallback = new BasePrintSpoolerServiceCallbacks() { - @Override - public void onCancelPrintJobResult(boolean canceled, int sequence) { - onRemoteMethodResult(canceled, sequence); - } - }; - } - - public boolean cancelPrintJob(IPrintSpoolerService target, int printJobId, - int appId) throws RemoteException, TimeoutException { - final int sequence = onBeforeRemoteCall(); - target.cancelPrintJob(printJobId, mCallback, appId, sequence); - return getResultTimed(sequence); - } - } - - private final class GetPrintJobCaller extends TimedRemoteCaller<PrintJobInfo> { - private final IPrintSpoolerServiceCallbacks mCallback; - - public GetPrintJobCaller() { - super(TimedRemoteCaller.DEFAULT_CALL_TIMEOUT_MILLIS); - mCallback = new BasePrintSpoolerServiceCallbacks() { - @Override - public void onGetPrintJobInfoResult(PrintJobInfo printJob, int sequence) { - onRemoteMethodResult(printJob, sequence); - } - }; - } - - public PrintJobInfo getPrintJobInfo(IPrintSpoolerService target, int printJobId, - int appId) throws RemoteException, TimeoutException { - final int sequence = onBeforeRemoteCall(); - target.getPrintJob(printJobId, mCallback, appId, sequence); - return getResultTimed(sequence); - } - } - - private final class SetPrintJobStateCaller extends TimedRemoteCaller<Boolean> { - private final IPrintSpoolerServiceCallbacks mCallback; - - public SetPrintJobStateCaller() { - super(TimedRemoteCaller.DEFAULT_CALL_TIMEOUT_MILLIS); - mCallback = new BasePrintSpoolerServiceCallbacks() { - @Override - public void onSetPrintJobStateResult(boolean success, int sequence) { - onRemoteMethodResult(success, sequence); - } - }; - } - - public boolean setPrintJobState(IPrintSpoolerService target, int printJobId, - int status) throws RemoteException, TimeoutException { - final int sequence = onBeforeRemoteCall(); - target.setPrintJobState(printJobId, status, mCallback, sequence); - return getResultTimed(sequence); - } - } - - private final class SetPrintJobTagCaller extends TimedRemoteCaller<Boolean> { - private final IPrintSpoolerServiceCallbacks mCallback; - - public SetPrintJobTagCaller() { - super(TimedRemoteCaller.DEFAULT_CALL_TIMEOUT_MILLIS); - mCallback = new BasePrintSpoolerServiceCallbacks() { - @Override - public void onSetPrintJobTagResult(boolean success, int sequence) { - onRemoteMethodResult(success, sequence); - } - }; - } - - public boolean setPrintJobTag(IPrintSpoolerService target, int printJobId, - String tag) throws RemoteException, TimeoutException { - final int sequence = onBeforeRemoteCall(); - target.setPrintJobTag(printJobId, tag, mCallback, sequence); - return getResultTimed(sequence); - } - } - - private abstract class BasePrintSpoolerServiceCallbacks - extends IPrintSpoolerServiceCallbacks.Stub { - @Override - public void onGetPrintJobsResult(List<PrintJobInfo> printJobIds, int sequence) { - /** do nothing */ - } - - @Override - public void onGetPrintJobInfoResult(PrintJobInfo printJob, int sequence) { - /** do nothing */ - } - - @Override - public void onCreatePrintJobResult(PrintJobInfo printJob, int sequence) { - /** do nothing */ - } - - @Override - public void onCancelPrintJobResult(boolean canceled, int sequence) { - /** do nothing */ - } - - @Override - public void onSetPrintJobStateResult(boolean success, int sequece) { - /** do nothing */ - } - - @Override - public void onSetPrintJobTagResult(boolean success, int sequence) { - /** do nothing */ - } - } -}
\ No newline at end of file diff --git a/services/java/com/android/server/print/UserState.java b/services/java/com/android/server/print/UserState.java new file mode 100644 index 0000000..5cef4d3 --- /dev/null +++ b/services/java/com/android/server/print/UserState.java @@ -0,0 +1,274 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.print; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.print.IPrinterDiscoveryObserver; +import android.print.PrintJobInfo; +import android.printservice.PrintServiceInfo; +import android.provider.Settings; +import android.text.TextUtils; +import android.text.TextUtils.SimpleStringSplitter; +import android.util.Slog; + +import com.android.server.print.RemotePrintSpooler.PrintSpoolerCallbacks; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * Represents the print state for a user. + */ +final class UserState implements PrintSpoolerCallbacks { + + private static final String LOG_TAG = "UserState"; + + private static final char COMPONENT_NAME_SEPARATOR = ':'; + + private final SimpleStringSplitter mStringColonSplitter = + new SimpleStringSplitter(COMPONENT_NAME_SEPARATOR); + + private final Intent mQueryIntent = + new Intent(android.printservice.PrintService.SERVICE_INTERFACE); + + private final Map<ComponentName, RemotePrintService> mActiveServices = + new HashMap<ComponentName, RemotePrintService>(); + + private final List<PrintServiceInfo> mInstalledServices = + new ArrayList<PrintServiceInfo>(); + + private final Set<ComponentName> mEnabledServices = + new HashSet<ComponentName>(); + + private final Object mLock; + + private final Context mContext; + + private final int mUserId; + + private final RemotePrintSpooler mSpooler; + + private boolean mDestroyed; + + public UserState(Context context, int userId, Object lock) { + mContext = context; + mUserId = userId; + mLock = lock; + mSpooler = new RemotePrintSpooler(context, userId, this); + } + + @Override + public void onPrintJobQueued(PrintJobInfo printJob) { + final RemotePrintService service; + synchronized (mLock) { + throwIfDestroyedLocked(); + ComponentName printServiceName = printJob.getPrinterId().getService(); + service = mActiveServices.get(printServiceName); + } + if (service != null) { + service.onPrintJobQueued(printJob); + } + } + + @Override + public void onAllPrintJobsForServiceHandled(ComponentName printService) { + final RemotePrintService service; + synchronized (mLock) { + throwIfDestroyedLocked(); + service = mActiveServices.get(printService); + } + if (service != null) { + service.onAllPrintJobsHandled(); + } + } + + @Override + public void onStartPrinterDiscovery(IPrinterDiscoveryObserver observer) { + final List<RemotePrintService> services; + synchronized (mLock) { + throwIfDestroyedLocked(); + if (mActiveServices.isEmpty()) { + return; + } + services = new ArrayList<RemotePrintService>(mActiveServices.values()); + } + final int serviceCount = services.size(); + for (int i = 0; i < serviceCount; i++) { + RemotePrintService service = services.get(i); + service.onStartPrinterDiscovery(observer); + } + } + + @Override + public void onStopPrinterDiscovery() { + final List<RemotePrintService> services; + synchronized (mLock) { + throwIfDestroyedLocked(); + if (mActiveServices.isEmpty()) { + return; + } + services = new ArrayList<RemotePrintService>(mActiveServices.values()); + } + final int serviceCount = services.size(); + for (int i = 0; i < serviceCount; i++) { + RemotePrintService service = services.get(i); + service.onStopPrinterDiscovery(); + } + } + + public void updateIfNeededLocked() { + throwIfDestroyedLocked(); + if (readConfigurationLocked()) { + onConfigurationChangedLocked(); + } + } + + public RemotePrintSpooler getSpoolerLocked() { + throwIfDestroyedLocked(); + return mSpooler; + } + + public Map<ComponentName, RemotePrintService> getActiveServices() { + synchronized(mLock) { + throwIfDestroyedLocked(); + return mActiveServices; + } + } + + public Set<ComponentName> getEnabledServices() { + synchronized(mLock) { + throwIfDestroyedLocked(); + return mEnabledServices; + } + } + + public void destroyLocked() { + throwIfDestroyedLocked(); + mSpooler.destroy(); + for (RemotePrintService service : mActiveServices.values()) { + service.destroy(); + } + mActiveServices.clear(); + mInstalledServices.clear(); + mEnabledServices.clear(); + mDestroyed = true; + } + + private boolean readConfigurationLocked() { + boolean somethingChanged = false; + somethingChanged |= readInstalledPrintServicesLocked(); + somethingChanged |= readEnabledPrintServicesLocked(); + return somethingChanged; + } + + private boolean readInstalledPrintServicesLocked() { + Set<PrintServiceInfo> tempPrintServices = new HashSet<PrintServiceInfo>(); + + List<ResolveInfo> installedServices = mContext.getPackageManager() + .queryIntentServicesAsUser(mQueryIntent, PackageManager.GET_SERVICES + | PackageManager.GET_META_DATA, mUserId); + + final int installedCount = installedServices.size(); + for (int i = 0, count = installedCount; i < count; i++) { + ResolveInfo installedService = installedServices.get(i); + if (!android.Manifest.permission.BIND_PRINT_SERVICE.equals( + installedService.serviceInfo.permission)) { + ComponentName serviceName = new ComponentName( + installedService.serviceInfo.packageName, + installedService.serviceInfo.name); + Slog.w(LOG_TAG, "Skipping print service " + + serviceName.flattenToShortString() + + " since it does not require permission " + + android.Manifest.permission.BIND_PRINT_SERVICE); + continue; + } + tempPrintServices.add(PrintServiceInfo.create(installedService, mContext)); + } + + if (!tempPrintServices.equals(mInstalledServices)) { + mInstalledServices.clear(); + mInstalledServices.addAll(tempPrintServices); + return true; + } + + return false; + } + + private boolean readEnabledPrintServicesLocked() { + Set<ComponentName> tempEnabledServiceNameSet = new HashSet<ComponentName>(); + + String settingValue = Settings.Secure.getStringForUser(mContext.getContentResolver(), + Settings.Secure.ENABLED_PRINT_SERVICES, mUserId); + if (!TextUtils.isEmpty(settingValue)) { + TextUtils.SimpleStringSplitter splitter = mStringColonSplitter; + splitter.setString(settingValue); + while (splitter.hasNext()) { + String string = splitter.next(); + if (TextUtils.isEmpty(string)) { + continue; + } + ComponentName componentName = ComponentName.unflattenFromString(string); + if (componentName != null) { + tempEnabledServiceNameSet.add(componentName); + } + } + } + + if (!tempEnabledServiceNameSet.equals(mEnabledServices)) { + mEnabledServices.clear(); + mEnabledServices.addAll(tempEnabledServiceNameSet); + return true; + } + + return false; + } + + private void onConfigurationChangedLocked() { + final int installedCount = mInstalledServices.size(); + for (int i = 0; i < installedCount; i++) { + ResolveInfo resolveInfo = mInstalledServices.get(i).getResolveInfo(); + ComponentName serviceName = new ComponentName(resolveInfo.serviceInfo.packageName, + resolveInfo.serviceInfo.name); + if (mEnabledServices.contains(serviceName)) { + if (!mActiveServices.containsKey(serviceName)) { + mActiveServices.put(serviceName, new RemotePrintService( + mContext, serviceName, mUserId, mSpooler)); + } + } else { + RemotePrintService service = mActiveServices.remove(serviceName); + if (service != null) { + service.destroy(); + } + } + } + } + + private void throwIfDestroyedLocked() { + if (mDestroyed) { + throw new IllegalStateException("Cannot interact with a destroyed instance."); + } + } +} + diff --git a/services/java/com/android/server/updates/CarrierProvisioningUrlsInstallReceiver.java b/services/java/com/android/server/updates/CarrierProvisioningUrlsInstallReceiver.java new file mode 100644 index 0000000..b53fb65 --- /dev/null +++ b/services/java/com/android/server/updates/CarrierProvisioningUrlsInstallReceiver.java @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.updates; + +public class CarrierProvisioningUrlsInstallReceiver extends ConfigUpdateInstallReceiver { + + public CarrierProvisioningUrlsInstallReceiver() { + super("/data/misc/radio/", "provisioning_urls.xml", "metadata/", "version"); + } +} diff --git a/services/java/com/android/server/wm/DisplayContent.java b/services/java/com/android/server/wm/DisplayContent.java index 088061c..4f699ae 100644 --- a/services/java/com/android/server/wm/DisplayContent.java +++ b/services/java/com/android/server/wm/DisplayContent.java @@ -25,7 +25,6 @@ import android.app.ActivityManager.StackBoxInfo; import android.graphics.Rect; import android.graphics.Region; import android.util.Slog; -import android.util.SparseArray; import android.view.Display; import android.view.DisplayInfo; @@ -106,8 +105,6 @@ class DisplayContent { /** Detect user tapping outside of current focused stack bounds .*/ Region mTouchExcludeRegion = new Region(); - SparseArray<UserStacks> mUserStacks = new SparseArray<UserStacks>(); - /** Save allocating when retrieving tasks */ ArrayList<Task> mTmpTasks = new ArrayList<Task>(); @@ -166,22 +163,6 @@ class DisplayContent { */ ArrayList<Task> getTasks() { mTmpTasks.clear(); - // First do the tasks belonging to other users. - final int numUserStacks = mUserStacks.size(); - for (int i = 0; i < numUserStacks; ++i) { - UserStacks userStacks = mUserStacks.valueAt(i); - ArrayList<TaskStack> stacks = userStacks.mSavedStackHistory; - final int numStacks = stacks.size(); - for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) { - TaskStack stack = stacks.get(stackNdx); - if (stack != mHomeStack) { - if (WindowManagerService.DEBUG_LAYERS) Slog.i(TAG, "getTasks: mStackHistory=" + - mStackHistory); - mTmpTasks.addAll(stack.getTasks()); - } - } - } - // Now do the current user's tasks. final int numStacks = mStackHistory.size(); for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) { mTmpTasks.addAll(mStackHistory.get(stackNdx).getTasks()); @@ -359,14 +340,6 @@ class DisplayContent { return bounds; } } - // Not in the visible stacks, try the saved ones. - for (int userNdx = mUserStacks.size() - 1; userNdx >= 0; --userNdx) { - UserStacks userStacks = mUserStacks.valueAt(userNdx); - Rect bounds = userStacks.mSavedStackBox.getStackBounds(stackId); - if (bounds != null) { - return bounds; - } - } return null; } @@ -400,12 +373,9 @@ class DisplayContent { win.hideLw(false); } } - // Clear the old user's non-home StackBox - mUserStacks.put(oldUserId, new UserStacks()); - UserStacks userStacks = mUserStacks.get(newUserId); - if (userStacks != null) { - userStacks.restore(); - mUserStacks.delete(newUserId); + + for (int stackBoxNdx = mStackBoxes.size() - 1; stackBoxNdx >= 0; --stackBoxNdx) { + mStackBoxes.get(stackBoxNdx).switchUserStacks(newUserId); } } @@ -508,49 +478,6 @@ class DisplayContent { token.dump(pw, " "); } } - if (mUserStacks.size() > 0) { - pw.println(); - pw.println(" Saved user stacks:"); - for (int i = 0; i < mUserStacks.size(); ++i) { - UserStacks userStacks = mUserStacks.valueAt(i); - pw.print(" UserId="); pw.println(Integer.toHexString(mUserStacks.keyAt(i))); - pw.print(" StackHistory="); pw.println(userStacks.mSavedStackHistory); - pw.print(" StackBox="); userStacks.mSavedStackBox.dump(" ", pw); - } - } pw.println(); } - - private final class UserStacks { - final ArrayList<TaskStack> mSavedStackHistory; - StackBox mSavedStackBox; - int mBoxNdx; - - public UserStacks() { - mSavedStackHistory = new ArrayList<TaskStack>(mStackHistory); - for (int stackNdx = mStackHistory.size() - 1; stackNdx >=0; --stackNdx) { - if (mStackHistory.get(stackNdx) != mHomeStack) { - mStackHistory.remove(stackNdx); - } - } - mSavedStackBox = null; - mBoxNdx = -1; - for (int boxNdx = mStackBoxes.size() - 1; boxNdx >= 0; --boxNdx) { - StackBox box = mStackBoxes.get(boxNdx); - if (box.mStack != mHomeStack) { - mSavedStackBox = box; - mBoxNdx = boxNdx; - mStackBoxes.remove(boxNdx); - break; - } - } - } - - void restore() { - mStackHistory = mSavedStackHistory; - if (mBoxNdx >= 0) { - mStackBoxes.add(mBoxNdx, mSavedStackBox); - } - } - } } diff --git a/services/java/com/android/server/wm/InputMonitor.java b/services/java/com/android/server/wm/InputMonitor.java index cacc723..d22178d 100644 --- a/services/java/com/android/server/wm/InputMonitor.java +++ b/services/java/com/android/server/wm/InputMonitor.java @@ -19,7 +19,6 @@ package com.android.server.wm; import com.android.server.input.InputManagerService; import com.android.server.input.InputApplicationHandle; import com.android.server.input.InputWindowHandle; -import com.android.server.wm.WindowManagerService.AllWindowsIterator; import android.app.ActivityManagerNative; import android.graphics.Rect; @@ -259,45 +258,47 @@ final class InputMonitor implements InputManagerService.WindowManagerCallbacks { } // Add all windows on the default display. - final AllWindowsIterator iterator = mService.new AllWindowsIterator( - WindowManagerService.REVERSE_ITERATOR); - while (iterator.hasNext()) { - final WindowState child = iterator.next(); - final InputChannel inputChannel = child.mInputChannel; - final InputWindowHandle inputWindowHandle = child.mInputWindowHandle; - if (inputChannel == null || inputWindowHandle == null || child.mRemoved) { - // Skip this window because it cannot possibly receive input. - continue; - } + final int numDisplays = mService.mDisplayContents.size(); + for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) { + WindowList windows = mService.mDisplayContents.valueAt(displayNdx).getWindowList(); + for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) { + final WindowState child = windows.get(winNdx); + final InputChannel inputChannel = child.mInputChannel; + final InputWindowHandle inputWindowHandle = child.mInputWindowHandle; + if (inputChannel == null || inputWindowHandle == null || child.mRemoved) { + // Skip this window because it cannot possibly receive input. + continue; + } - final int flags = child.mAttrs.flags; - final int type = child.mAttrs.type; + final int flags = child.mAttrs.flags; + final int type = child.mAttrs.type; - final boolean hasFocus = (child == mInputFocus); - final boolean isVisible = child.isVisibleLw(); - final boolean hasWallpaper = (child == mService.mWallpaperTarget) - && (type != WindowManager.LayoutParams.TYPE_KEYGUARD); - final boolean onDefaultDisplay = (child.getDisplayId() == Display.DEFAULT_DISPLAY); + final boolean hasFocus = (child == mInputFocus); + final boolean isVisible = child.isVisibleLw(); + final boolean hasWallpaper = (child == mService.mWallpaperTarget) + && (type != WindowManager.LayoutParams.TYPE_KEYGUARD); + final boolean onDefaultDisplay = (child.getDisplayId() == Display.DEFAULT_DISPLAY); - // If there's a drag in progress and 'child' is a potential drop target, - // make sure it's been told about the drag - if (inDrag && isVisible && onDefaultDisplay) { - mService.mDragState.sendDragStartedIfNeededLw(child); - } + // If there's a drag in progress and 'child' is a potential drop target, + // make sure it's been told about the drag + if (inDrag && isVisible && onDefaultDisplay) { + mService.mDragState.sendDragStartedIfNeededLw(child); + } - if (universeBackground != null && !addedUniverse - && child.mBaseLayer < aboveUniverseLayer && onDefaultDisplay) { - final WindowState u = universeBackground.mWin; - if (u.mInputChannel != null && u.mInputWindowHandle != null) { - addInputWindowHandleLw(u.mInputWindowHandle, u, u.mAttrs.flags, - u.mAttrs.type, true, u == mInputFocus, false); + if (universeBackground != null && !addedUniverse + && child.mBaseLayer < aboveUniverseLayer && onDefaultDisplay) { + final WindowState u = universeBackground.mWin; + if (u.mInputChannel != null && u.mInputWindowHandle != null) { + addInputWindowHandleLw(u.mInputWindowHandle, u, u.mAttrs.flags, + u.mAttrs.type, true, u == mInputFocus, false); + } + addedUniverse = true; } - addedUniverse = true; - } - if (child.mWinAnimator != universeBackground) { - addInputWindowHandleLw(inputWindowHandle, child, flags, type, - isVisible, hasFocus, hasWallpaper); + if (child.mWinAnimator != universeBackground) { + addInputWindowHandleLw(inputWindowHandle, child, flags, type, + isVisible, hasFocus, hasWallpaper); + } } } diff --git a/services/java/com/android/server/wm/StackBox.java b/services/java/com/android/server/wm/StackBox.java index d352464..d4cf4e2 100644 --- a/services/java/com/android/server/wm/StackBox.java +++ b/services/java/com/android/server/wm/StackBox.java @@ -109,8 +109,8 @@ public class StackBox { * @return true if the specified StackBox matches this or one of its descendants. */ boolean contains(int stackBoxId) { - return mStackBoxId == stackBoxId || mFirst.contains(stackBoxId) - || mSecond.contains(stackBoxId); + return mStackBoxId == stackBoxId || + (mStack == null && (mFirst.contains(stackBoxId) || mSecond.contains(stackBoxId))); } /** @@ -371,6 +371,15 @@ public class StackBox { mSecond.stopDimmingIfNeeded(); } + void switchUserStacks(int userId) { + if (mStack != null) { + mStack.switchUser(userId); + return; + } + mFirst.switchUserStacks(userId); + mSecond.switchUserStacks(userId); + } + public void dump(String prefix, PrintWriter pw) { pw.print(prefix); pw.print("mParent="); pw.println(mParent); pw.print(prefix); pw.print("mBounds="); pw.print(mBounds.toShortString()); diff --git a/services/java/com/android/server/wm/Task.java b/services/java/com/android/server/wm/Task.java index 88eb96e..d9acbb9 100644 --- a/services/java/com/android/server/wm/Task.java +++ b/services/java/com/android/server/wm/Task.java @@ -21,11 +21,13 @@ class Task { TaskStack mStack; final AppTokenList mAppTokens = new AppTokenList(); final int taskId; + final int mUserId; - Task(AppWindowToken wtoken, TaskStack stack) { + Task(AppWindowToken wtoken, TaskStack stack, int userId) { taskId = wtoken.groupId; mAppTokens.add(wtoken); mStack = stack; + mUserId = userId; } DisplayContent getDisplayContent() { diff --git a/services/java/com/android/server/wm/TaskStack.java b/services/java/com/android/server/wm/TaskStack.java index b43a7a1..29156be 100644 --- a/services/java/com/android/server/wm/TaskStack.java +++ b/services/java/com/android/server/wm/TaskStack.java @@ -87,15 +87,38 @@ public class TaskStack { return mStackId == HOME_STACK_ID; } + boolean hasSibling() { + return mStackBox.mParent != null; + } + /** * Put a Task in this stack. Used for adding and moving. * @param task The task to add. * @param toTop Whether to add it to the top or bottom. */ boolean addTask(Task task, boolean toTop) { - if (DEBUG_TASK_MOVEMENT) Slog.d(TAG, "addTask: task=" + task + " toTop=" + toTop); mStackBox.makeDirty(); - mTasks.add(toTop ? mTasks.size() : 0, task); + + int stackNdx; + if (!toTop) { + stackNdx = 0; + } else { + stackNdx = mTasks.size(); + final int currentUserId = mService.mCurrentUserId; + if (task.mUserId != currentUserId) { + // Place the task below all current user tasks. + while (--stackNdx >= 0) { + if (currentUserId != mTasks.get(stackNdx).mUserId) { + break; + } + } + ++stackNdx; + } + } + if (DEBUG_TASK_MOVEMENT) Slog.d(TAG, "addTask: task=" + task + " toTop=" + toTop + + " pos=" + stackNdx); + mTasks.add(stackNdx, task); + task.mStack = this; return mDisplayContent.moveHomeStackBox(mStackId == HOME_STACK_ID); } @@ -252,6 +275,18 @@ public class TaskStack { } } + void switchUser(int userId) { + int top = mTasks.size(); + for (int taskNdx = 0; taskNdx < top; ++taskNdx) { + Task task = mTasks.get(taskNdx); + if (task.mUserId == userId) { + mTasks.remove(taskNdx); + mTasks.add(task); + --top; + } + } + } + public void dump(String prefix, PrintWriter pw) { pw.print(prefix); pw.print("mStackId="); pw.println(mStackId); for (int taskNdx = 0; taskNdx < mTasks.size(); ++taskNdx) { diff --git a/services/java/com/android/server/wm/WindowAnimator.java b/services/java/com/android/server/wm/WindowAnimator.java index 3fc3ac6..2688cff 100644 --- a/services/java/com/android/server/wm/WindowAnimator.java +++ b/services/java/com/android/server/wm/WindowAnimator.java @@ -24,7 +24,6 @@ import android.view.SurfaceControl; import android.view.WindowManagerPolicy; import android.view.animation.Animation; -import com.android.server.wm.WindowManagerService.DisplayContentsIterator; import com.android.server.wm.WindowManagerService.LayoutFields; import java.io.PrintWriter; @@ -442,7 +441,7 @@ public class WindowAnimator { setAppLayoutChanges(appAnimator, WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM, "testTokenMayBeDrawnLocked"); - + // We can now show all of the drawn windows! if (!mService.mOpeningApps.contains(wtoken)) { mAnimating |= appAnimator.showAllWindowsLocked(); @@ -541,9 +540,9 @@ public class WindowAnimator { } boolean hasPendingLayoutChanges = false; - DisplayContentsIterator iterator = mService.new DisplayContentsIterator(); - while (iterator.hasNext()) { - final DisplayContent displayContent = iterator.next(); + final int numDisplays = mService.mDisplayContents.size(); + for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) { + final DisplayContent displayContent = mService.mDisplayContents.valueAt(displayNdx); final int pendingChanges = getPendingLayoutChanges(displayContent.getDisplayId()); if ((pendingChanges & WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER) != 0) { mBulkUpdateParams |= SET_WALLPAPER_ACTION_PENDING; diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java index 7784b16..f763068 100644 --- a/services/java/com/android/server/wm/WindowManagerService.java +++ b/services/java/com/android/server/wm/WindowManagerService.java @@ -150,7 +150,6 @@ import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; -import java.util.NoSuchElementException; /** {@hide} */ public class WindowManagerService extends IWindowManager.Stub @@ -284,6 +283,9 @@ public class WindowManagerService extends IWindowManager.Stub private static final String SYSTEM_SECURE = "ro.secure"; private static final String SYSTEM_DEBUGGABLE = "ro.debuggable"; + private static final String DENSITY_OVERRIDE = "ro.config.density_override"; + private static final String SIZE_OVERRIDE = "ro.config.size_override"; + private static final int MAX_SCREENSHOT_RETRIES = 3; final private KeyguardDisableHandler mKeyguardDisableHandler; @@ -426,9 +428,7 @@ public class WindowManagerService extends IWindowManager.Stub String mLastANRState; /** All DisplayContents in the world, kept here */ - private SparseArray<DisplayContent> mDisplayContents = new SparseArray<DisplayContent>(2); - - private final AllWindowsIterator mTmpWindowsIterator = new AllWindowsIterator(); + SparseArray<DisplayContent> mDisplayContents = new SparseArray<DisplayContent>(2); int mRotation = 0; int mForcedAppOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; @@ -2537,13 +2537,17 @@ public class WindowManagerService extends IWindowManager.Stub public void updateAppOpsState() { synchronized(mWindowMap) { - mTmpWindowsIterator.reset(FORWARD_ITERATOR); - while (mTmpWindowsIterator.hasNext()) { - final WindowState win = mTmpWindowsIterator.next(); - if (win.mAppOp != AppOpsManager.OP_NONE) { - final int mode = mAppOps.checkOpNoThrow(win.mAppOp, win.getOwningUid(), - win.getOwningPackage()); - win.setAppOpVisibilityLw(mode == AppOpsManager.MODE_ALLOWED); + final int numDisplays = mDisplayContents.size(); + for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) { + final WindowList windows = mDisplayContents.valueAt(displayNdx).getWindowList(); + final int numWindows = windows.size(); + for (int winNdx = 0; winNdx < numWindows; ++winNdx) { + final WindowState win = windows.get(winNdx); + if (win.mAppOp != AppOpsManager.OP_NONE) { + final int mode = mAppOps.checkOpNoThrow(win.mAppOp, win.getOwningUid(), + win.getOwningPackage()); + win.setAppOpVisibilityLw(mode == AppOpsManager.MODE_ALLOWED); + } } } } @@ -3370,7 +3374,7 @@ public class WindowManagerService extends IWindowManager.Stub @Override public void addAppToken(int addPos, IApplicationToken token, int taskId, int stackId, - int requestedOrientation, boolean fullscreen, boolean showWhenLocked) { + int requestedOrientation, boolean fullscreen, boolean showWhenLocked, int userId) { if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS, "addAppToken()")) { throw new SecurityException("Requires MANAGE_APP_TOKENS permission"); @@ -3403,7 +3407,7 @@ public class WindowManagerService extends IWindowManager.Stub atoken.showWhenLocked = showWhenLocked; atoken.requestedOrientation = requestedOrientation; if (DEBUG_TOKEN_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG, "addAppToken: " + atoken - + " at " + addPos); + + " to stack=" + stackId + " task=" + taskId + " at " + addPos); Task task = mTaskIdToTask.get(taskId); if (task == null) { @@ -3411,7 +3415,7 @@ public class WindowManagerService extends IWindowManager.Stub if (stack == null) { throw new IllegalArgumentException("addAppToken: invalid stackId=" + stackId); } - task = new Task(atoken, stack); + task = new Task(atoken, stack, userId); stack.addTask(task, true); stack.getDisplayContent().moveStack(stack, true); mTaskIdToTask.put(taskId, task); @@ -4551,9 +4555,9 @@ public class WindowManagerService extends IWindowManager.Stub } void dumpAppTokensLocked() { - DisplayContentsIterator iterator = new DisplayContentsIterator(); - while (iterator.hasNext()) { - DisplayContent displayContent = iterator.next(); + final int numDisplays = mDisplayContents.size(); + for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) { + final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx); Slog.v(TAG, " Display " + displayContent.getDisplayId()); final ArrayList<Task> tasks = displayContent.getTasks(); int i = displayContent.numTokens(); @@ -4569,10 +4573,12 @@ public class WindowManagerService extends IWindowManager.Stub void dumpWindowsLocked() { int i = 0; - mTmpWindowsIterator.reset(REVERSE_ITERATOR); - while (mTmpWindowsIterator.hasNext()) { - final WindowState w = mTmpWindowsIterator.next(); - Slog.v(TAG, " #" + i++ + ": " + w); + final int numDisplays = mDisplayContents.size(); + for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) { + final WindowList windows = mDisplayContents.valueAt(displayNdx).getWindowList(); + for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) { + Slog.v(TAG, " #" + i++ + ": " + windows.get(winNdx)); + } } } @@ -4823,9 +4829,9 @@ public class WindowManagerService extends IWindowManager.Stub "createStack: weight must be between " + STACK_WEIGHT_MIN + " and " + STACK_WEIGHT_MAX + ", weight=" + weight); } - DisplayContentsIterator iterator = new DisplayContentsIterator(); - while (iterator.hasNext()) { - final DisplayContent displayContent = iterator.next(); + final int numDisplays = mDisplayContents.size(); + for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) { + final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx); TaskStack stack = displayContent.createStack(this, stackId, relativeStackBoxId, position, weight); if (stack != null) { @@ -4888,9 +4894,9 @@ public class WindowManagerService extends IWindowManager.Stub STACK_WEIGHT_MAX + ", weight=" + weight); } synchronized (mWindowMap) { - DisplayContentsIterator iterator = new DisplayContentsIterator(); - while (iterator.hasNext()) { - if (iterator.next().resizeStack(stackBoxId, weight)) { + final int numDisplays = mDisplayContents.size(); + for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) { + if (mDisplayContents.valueAt(displayNdx).resizeStack(stackBoxId, weight)) { performLayoutAndPlaceSurfacesLocked(); return; } @@ -4907,9 +4913,9 @@ public class WindowManagerService extends IWindowManager.Stub } public Rect getStackBounds(int stackId) { - DisplayContentsIterator iterator = new DisplayContentsIterator(); - while (iterator.hasNext()) { - Rect bounds = iterator.next().getStackBounds(stackId); + final int numDisplays = mDisplayContents.size(); + for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) { + Rect bounds = mDisplayContents.valueAt(displayNdx).getStackBounds(stackId); if (bounds != null) { return bounds; } @@ -5036,13 +5042,17 @@ public class WindowManagerService extends IWindowManager.Stub @Override public void closeSystemDialogs(String reason) { synchronized(mWindowMap) { - mTmpWindowsIterator.reset(FORWARD_ITERATOR); - while (mTmpWindowsIterator.hasNext()) { - final WindowState w = mTmpWindowsIterator.next(); - if (w.mHasSurface) { - try { - w.mClient.closeSystemDialogs(reason); - } catch (RemoteException e) { + final int numDisplays = mDisplayContents.size(); + for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) { + final WindowList windows = mDisplayContents.valueAt(displayNdx).getWindowList(); + final int numWindows = windows.size(); + for (int winNdx = 0; winNdx < numWindows; ++winNdx) { + final WindowState w = windows.get(winNdx); + if (w.mHasSurface) { + try { + w.mClient.closeSystemDialogs(reason); + } catch (RemoteException e) { + } } } } @@ -5062,13 +5072,11 @@ public class WindowManagerService extends IWindowManager.Stub throw new SecurityException("Requires SET_ANIMATION_SCALE permission"); } - if (scale < 0) scale = 0; - else if (scale > 20) scale = 20; - scale = Math.abs(scale); + scale = fixScale(scale); switch (which) { - case 0: mWindowAnimationScale = fixScale(scale); break; - case 1: mTransitionAnimationScale = fixScale(scale); break; - case 2: mAnimatorDurationScale = fixScale(scale); break; + case 0: mWindowAnimationScale = scale; break; + case 1: mTransitionAnimationScale = scale; break; + case 2: mAnimatorDurationScale = scale; break; } // Persist setting @@ -5180,9 +5188,9 @@ public class WindowManagerService extends IWindowManager.Stub mPolicy.setCurrentUserLw(newUserId); // Hide windows that should not be seen by the new user. - DisplayContentsIterator iterator = new DisplayContentsIterator(); - while (iterator.hasNext()) { - DisplayContent displayContent = iterator.next(); + final int numDisplays = mDisplayContents.size(); + for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) { + final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx); displayContent.switchUserStacks(oldUserId, newUserId); rebuildAppWindowListLocked(displayContent); } @@ -5432,12 +5440,16 @@ public class WindowManagerService extends IWindowManager.Stub // the background..) if (on) { boolean isVisible = false; - mTmpWindowsIterator.reset(FORWARD_ITERATOR); - while (mTmpWindowsIterator.hasNext()) { - final WindowState ws = mTmpWindowsIterator.next(); - if (ws.mSession.mPid == pid && ws.isVisibleLw()) { - isVisible = true; - break; + final int numDisplays = mDisplayContents.size(); + for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) { + final WindowList windows = mDisplayContents.valueAt(displayNdx).getWindowList(); + final int numWindows = windows.size(); + for (int winNdx = 0; winNdx < numWindows; ++winNdx) { + final WindowState ws = windows.get(winNdx); + if (ws.mSession.mPid == pid && ws.isVisibleLw()) { + isVisible = true; + break; + } } } if (!isVisible) { @@ -6197,9 +6209,10 @@ public class WindowManagerService extends IWindowManager.Stub WindowList windows = new WindowList(); synchronized (mWindowMap) { //noinspection unchecked - DisplayContentsIterator iterator = new DisplayContentsIterator(); - while(iterator.hasNext()) { - windows.addAll(iterator.next().getWindowList()); + final int numDisplays = mDisplayContents.size(); + for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) { + final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx); + windows.addAll(displayContent.getWindowList()); } } @@ -6427,11 +6440,15 @@ public class WindowManagerService extends IWindowManager.Stub } synchronized (mWindowMap) { - mTmpWindowsIterator.reset(FORWARD_ITERATOR); - while (mTmpWindowsIterator.hasNext()) { - final WindowState w = mTmpWindowsIterator.next(); - if (System.identityHashCode(w) == hashCode) { - return w; + final int numDisplays = mDisplayContents.size(); + for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) { + final WindowList windows = mDisplayContents.valueAt(displayNdx).getWindowList(); + final int numWindows = windows.size(); + for (int winNdx = 0; winNdx < numWindows; ++winNdx) { + final WindowState w = windows.get(winNdx); + if (System.identityHashCode(w) == hashCode) { + return w; + } } } } @@ -6982,12 +6999,16 @@ public class WindowManagerService extends IWindowManager.Stub // TODO(multidisplay): Call isScreenOn for each display. private void sendScreenStatusToClientsLocked() { final boolean on = mPowerManager.isScreenOn(); - mTmpWindowsIterator.reset(FORWARD_ITERATOR); - while (mTmpWindowsIterator.hasNext()) { - try { - mTmpWindowsIterator.next().mClient.dispatchScreenState(on); - } catch (RemoteException e) { - // Ignored + final int numDisplays = mDisplayContents.size(); + for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) { + final WindowList windows = mDisplayContents.valueAt(displayNdx).getWindowList(); + final int numWindows = windows.size(); + for (int winNdx = 0; winNdx < numWindows; ++winNdx) { + try { + windows.get(winNdx).mClient.dispatchScreenState(on); + } catch (RemoteException e) { + // Ignored + } } } } @@ -7606,8 +7627,11 @@ public class WindowManagerService extends IWindowManager.Stub } private void readForcedDisplaySizeAndDensityLocked(final DisplayContent displayContent) { - final String sizeStr = Settings.Global.getString(mContext.getContentResolver(), + String sizeStr = Settings.Global.getString(mContext.getContentResolver(), Settings.Global.DISPLAY_SIZE_FORCED); + if (sizeStr == null) { + sizeStr = SystemProperties.get(SIZE_OVERRIDE, null); + } if (sizeStr != null && sizeStr.length() > 0) { final int pos = sizeStr.indexOf(','); if (pos > 0 && sizeStr.lastIndexOf(',') == pos) { @@ -7627,8 +7651,11 @@ public class WindowManagerService extends IWindowManager.Stub } } } - final String densityStr = Settings.Global.getString(mContext.getContentResolver(), + String densityStr = Settings.Global.getString(mContext.getContentResolver(), Settings.Global.DISPLAY_DENSITY_FORCED); + if (densityStr == null) { + densityStr = SystemProperties.get(DENSITY_OVERRIDE, null); + } if (densityStr != null && densityStr.length() > 0) { int density; try { @@ -7849,9 +7876,10 @@ public class WindowManagerService extends IWindowManager.Stub } final void rebuildAppWindowListLocked() { - DisplayContentsIterator iterator = new DisplayContentsIterator(); - while (iterator.hasNext()) { - rebuildAppWindowListLocked(iterator.next()); + final int numDisplays = mDisplayContents.size(); + for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) { + final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx); + rebuildAppWindowListLocked(displayContent); } } @@ -8800,9 +8828,9 @@ public class WindowManagerService extends IWindowManager.Stub } // Initialize state of exiting tokens. - DisplayContentsIterator iterator = new DisplayContentsIterator(); - while (iterator.hasNext()) { - final DisplayContent displayContent = iterator.next(); + final int numDisplays = mDisplayContents.size(); + for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) { + final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx); for (i=displayContent.mExitingTokens.size()-1; i>=0; i--) { displayContent.mExitingTokens.get(i).hasVisible = false; } @@ -8840,10 +8868,9 @@ public class WindowManagerService extends IWindowManager.Stub boolean focusDisplayed = false; - iterator = new DisplayContentsIterator(); - while (iterator.hasNext()) { + for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) { + final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx); boolean updateAllDrawn = false; - final DisplayContent displayContent = iterator.next(); WindowList windows = displayContent.getWindowList(); DisplayInfo displayInfo = displayContent.getDisplayInfo(); final int displayId = displayContent.getDisplayId(); @@ -9255,9 +9282,8 @@ public class WindowManagerService extends IWindowManager.Stub } // Time to remove any exiting tokens? - iterator = new DisplayContentsIterator(); - while (iterator.hasNext()) { - final DisplayContent displayContent = iterator.next(); + for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) { + final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx); ArrayList<WindowToken> exitingTokens = displayContent.mExitingTokens; for (i = exitingTokens.size() - 1; i >= 0; i--) { WindowToken token = exitingTokens.get(i); @@ -9306,9 +9332,8 @@ public class WindowManagerService extends IWindowManager.Stub defaultDisplay.layoutNeeded = true; } - iterator = new DisplayContentsIterator(); - while (iterator.hasNext()) { - DisplayContent displayContent = iterator.next(); + for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) { + final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx); if (displayContent.pendingLayoutChanges != 0) { displayContent.layoutNeeded = true; } @@ -9489,9 +9514,10 @@ public class WindowManagerService extends IWindowManager.Stub } private boolean needsLayout() { - DisplayContentsIterator iterator = new DisplayContentsIterator(); - while (iterator.hasNext()) { - if (iterator.next().layoutNeeded) { + final int numDisplays = mDisplayContents.size(); + for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) { + final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx); + if (displayContent.layoutNeeded) { return true; } } @@ -9570,35 +9596,39 @@ public class WindowManagerService extends IWindowManager.Stub // window list to make sure we haven't left any dangling surfaces // around. - mTmpWindowsIterator.reset(FORWARD_ITERATOR); Slog.i(TAG, "Out of memory for surface! Looking for leaks..."); - while (mTmpWindowsIterator.hasNext()) { - WindowState ws = mTmpWindowsIterator.next(); - WindowStateAnimator wsa = ws.mWinAnimator; - if (wsa.mSurfaceControl != null) { - if (!mSessions.contains(wsa.mSession)) { - Slog.w(TAG, "LEAKED SURFACE (session doesn't exist): " - + ws + " surface=" + wsa.mSurfaceControl - + " token=" + ws.mToken - + " pid=" + ws.mSession.mPid - + " uid=" + ws.mSession.mUid); - if (SHOW_TRANSACTIONS) logSurface(ws, "LEAK DESTROY", null); - wsa.mSurfaceControl.destroy(); - wsa.mSurfaceShown = false; - wsa.mSurfaceControl = null; - ws.mHasSurface = false; - mForceRemoves.add(ws); - leakedSurface = true; - } else if (ws.mAppToken != null && ws.mAppToken.clientHidden) { - Slog.w(TAG, "LEAKED SURFACE (app token hidden): " - + ws + " surface=" + wsa.mSurfaceControl - + " token=" + ws.mAppToken); - if (SHOW_TRANSACTIONS) logSurface(ws, "LEAK DESTROY", null); - wsa.mSurfaceControl.destroy(); - wsa.mSurfaceShown = false; - wsa.mSurfaceControl = null; - ws.mHasSurface = false; - leakedSurface = true; + final int numDisplays = mDisplayContents.size(); + for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) { + final WindowList windows = mDisplayContents.valueAt(displayNdx).getWindowList(); + final int numWindows = windows.size(); + for (int winNdx = 0; winNdx < numWindows; ++winNdx) { + final WindowState ws = windows.get(winNdx); + WindowStateAnimator wsa = ws.mWinAnimator; + if (wsa.mSurfaceControl != null) { + if (!mSessions.contains(wsa.mSession)) { + Slog.w(TAG, "LEAKED SURFACE (session doesn't exist): " + + ws + " surface=" + wsa.mSurfaceControl + + " token=" + ws.mToken + + " pid=" + ws.mSession.mPid + + " uid=" + ws.mSession.mUid); + if (SHOW_TRANSACTIONS) logSurface(ws, "LEAK DESTROY", null); + wsa.mSurfaceControl.destroy(); + wsa.mSurfaceShown = false; + wsa.mSurfaceControl = null; + ws.mHasSurface = false; + mForceRemoves.add(ws); + leakedSurface = true; + } else if (ws.mAppToken != null && ws.mAppToken.clientHidden) { + Slog.w(TAG, "LEAKED SURFACE (app token hidden): " + + ws + " surface=" + wsa.mSurfaceControl + + " token=" + ws.mAppToken); + if (SHOW_TRANSACTIONS) logSurface(ws, "LEAK DESTROY", null); + wsa.mSurfaceControl.destroy(); + wsa.mSurfaceShown = false; + wsa.mSurfaceControl = null; + ws.mHasSurface = false; + leakedSurface = true; + } } } } @@ -9606,27 +9636,30 @@ public class WindowManagerService extends IWindowManager.Stub if (!leakedSurface) { Slog.w(TAG, "No leaked surfaces; killing applicatons!"); SparseIntArray pidCandidates = new SparseIntArray(); - mTmpWindowsIterator.reset(FORWARD_ITERATOR); - while (mTmpWindowsIterator.hasNext()) { - WindowState ws = mTmpWindowsIterator.next(); - if (mForceRemoves.contains(ws)) { - continue; - } - WindowStateAnimator wsa = ws.mWinAnimator; - if (wsa.mSurfaceControl != null) { - pidCandidates.append(wsa.mSession.mPid, wsa.mSession.mPid); - } - } - if (pidCandidates.size() > 0) { - int[] pids = new int[pidCandidates.size()]; - for (int i=0; i<pids.length; i++) { - pids[i] = pidCandidates.keyAt(i); + for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) { + final WindowList windows = mDisplayContents.valueAt(displayNdx).getWindowList(); + final int numWindows = windows.size(); + for (int winNdx = 0; winNdx < numWindows; ++winNdx) { + final WindowState ws = windows.get(winNdx); + if (mForceRemoves.contains(ws)) { + continue; + } + WindowStateAnimator wsa = ws.mWinAnimator; + if (wsa.mSurfaceControl != null) { + pidCandidates.append(wsa.mSession.mPid, wsa.mSession.mPid); + } } - try { - if (mActivityManager.killPids(pids, "Free memory", secure)) { - killedApps = true; + if (pidCandidates.size() > 0) { + int[] pids = new int[pidCandidates.size()]; + for (int i=0; i<pids.length; i++) { + pids[i] = pidCandidates.keyAt(i); + } + try { + if (mActivityManager.killPids(pids, "Free memory", secure)) { + killedApps = true; + } + } catch (RemoteException e) { } - } catch (RemoteException e) { } } } @@ -10225,9 +10258,10 @@ public class WindowManagerService extends IWindowManager.Stub void dumpDisplayContentsLocked(PrintWriter pw, boolean dumpAll) { pw.println("WINDOW MANAGER DISPLAY CONTENTS (dumpsys window displays)"); if (mDisplayReady) { - DisplayContentsIterator dCIterator = new DisplayContentsIterator(); - while (dCIterator.hasNext()) { - dCIterator.next().dump(" ", pw); + final int numDisplays = mDisplayContents.size(); + for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) { + final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx); + displayContent.dump(" ", pw); } } else { pw.println(" NO DISPLAY"); @@ -10243,13 +10277,16 @@ public class WindowManagerService extends IWindowManager.Stub void dumpWindowsNoHeaderLocked(PrintWriter pw, boolean dumpAll, ArrayList<WindowState> windows) { int j = 0; - mTmpWindowsIterator.reset(REVERSE_ITERATOR); - while (mTmpWindowsIterator.hasNext()) { - final WindowState w = mTmpWindowsIterator.next(); - if (windows == null || windows.contains(w)) { - pw.print(" Window #"); pw.print(j++); pw.print(' '); - pw.print(w); pw.println(":"); - w.dump(pw, " ", dumpAll || windows != null); + final int numDisplays = mDisplayContents.size(); + for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) { + final WindowList windowList = mDisplayContents.valueAt(displayNdx).getWindowList(); + for (int winNdx = windowList.size() - 1; winNdx >= 0; --winNdx) { + final WindowState w = windowList.get(winNdx); + if (windows == null || windows.contains(w)) { + pw.print(" Window #"); pw.print(j++); pw.print(' '); + pw.print(w); pw.println(":"); + w.dump(pw, " ", dumpAll || windows != null); + } } } if (mInputMethodDialogs.size() > 0) { @@ -10402,9 +10439,8 @@ public class WindowManagerService extends IWindowManager.Stub pw.print(" mDisplayEnabled="); pw.println(mDisplayEnabled); if (needsLayout()) { pw.print(" layoutNeeded on displays="); - DisplayContentsIterator dcIterator = new DisplayContentsIterator(); - while (dcIterator.hasNext()) { - final DisplayContent displayContent = dcIterator.next(); + for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) { + final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx); if (displayContent.layoutNeeded) { pw.print(displayContent.getDisplayId()); } @@ -10438,11 +10474,15 @@ public class WindowManagerService extends IWindowManager.Stub WindowList windows = new WindowList(); if ("visible".equals(name)) { synchronized(mWindowMap) { - mTmpWindowsIterator.reset(REVERSE_ITERATOR); - while (mTmpWindowsIterator.hasNext()) { - final WindowState w = mTmpWindowsIterator.next(); - if (w.mWinAnimator.mSurfaceShown) { - windows.add(w); + final int numDisplays = mDisplayContents.size(); + for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) { + final WindowList windowList = + mDisplayContents.valueAt(displayNdx).getWindowList(); + for (int winNdx = windowList.size() - 1; winNdx >= 0; --winNdx) { + final WindowState w = windowList.get(winNdx); + if (w.mWinAnimator.mSurfaceShown) { + windows.add(w); + } } } } @@ -10455,15 +10495,19 @@ public class WindowManagerService extends IWindowManager.Stub } catch (RuntimeException e) { } synchronized(mWindowMap) { - mTmpWindowsIterator.reset(REVERSE_ITERATOR); - while (mTmpWindowsIterator.hasNext()) { - final WindowState w = mTmpWindowsIterator.next(); - if (name != null) { - if (w.mAttrs.getTitle().toString().contains(name)) { + final int numDisplays = mDisplayContents.size(); + for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) { + final WindowList windowList = + mDisplayContents.valueAt(displayNdx).getWindowList(); + for (int winNdx = windowList.size() - 1; winNdx >= 0; --winNdx) { + final WindowState w = windowList.get(winNdx); + if (name != null) { + if (w.mAttrs.getTitle().toString().contains(name)) { + windows.add(w); + } + } else if (System.identityHashCode(w) == objectId) { windows.add(w); } - } else if (System.identityHashCode(w) == objectId) { - windows.add(w); } } } @@ -10715,104 +10759,6 @@ public class WindowManagerService extends IWindowManager.Stub return displayContent; } - class DisplayContentsIterator implements Iterator<DisplayContent> { - private int cur; - - void reset() { - cur = 0; - } - - @Override - public boolean hasNext() { - return cur < mDisplayContents.size(); - } - - @Override - public DisplayContent next() { - if (hasNext()) { - return mDisplayContents.valueAt(cur++); - } - throw new NoSuchElementException(); - } - - @Override - public void remove() { - throw new IllegalArgumentException("AllDisplayContentIterator.remove not implemented"); - } - } - - class AllWindowsIterator implements Iterator<WindowState> { - private DisplayContent mDisplayContent; - private DisplayContentsIterator mDisplayContentsIterator; - private WindowList mWindowList; - private int mWindowListIndex; - private boolean mReverse; - - AllWindowsIterator() { - this(false); - } - - AllWindowsIterator(boolean reverse) { - mDisplayContentsIterator = new DisplayContentsIterator(); - reset(reverse); - } - - void reset(boolean reverse) { - mReverse = reverse; - mDisplayContentsIterator.reset(); - if (mDisplayContentsIterator.hasNext()) { - mDisplayContent = mDisplayContentsIterator.next(); - mWindowList = mDisplayContent.getWindowList(); - mWindowListIndex = reverse ? mWindowList.size() - 1 : 0; - } else { - mDisplayContent = null; - mWindowList = null; - mWindowListIndex = 0; - } - } - - @Override - public boolean hasNext() { - if (mDisplayContent == null) { - return false; - } - if (mReverse) { - return mWindowListIndex >= 0; - } - return mWindowListIndex < mWindowList.size(); - } - - @Override - public WindowState next() { - if (hasNext()) { - WindowState win = mWindowList.get(mWindowListIndex); - if (mReverse) { - mWindowListIndex--; - if (mWindowListIndex < 0 && mDisplayContentsIterator.hasNext()) { - mDisplayContent = mDisplayContentsIterator.next(); - mWindowList = mDisplayContent.getWindowList(); - mWindowListIndex = mWindowList.size() - 1; - } - } else { - mWindowListIndex++; - if (mWindowListIndex >= mWindowList.size() - && mDisplayContentsIterator.hasNext()) { - mDisplayContent = mDisplayContentsIterator.next(); - mWindowList = mDisplayContent.getWindowList(); - mWindowListIndex = 0; - } - } - return win; - } - throw new NoSuchElementException(); - } - - @Override - public void remove() { - throw new IllegalArgumentException("AllWindowsIterator.remove not implemented"); - } - } - // There is an inherent assumption that this will never return null. public DisplayContent getDefaultDisplayContentLocked() { return getDisplayContentLocked(Display.DEFAULT_DISPLAY); diff --git a/services/java/com/android/server/wm/WindowState.java b/services/java/com/android/server/wm/WindowState.java index dd19f89..0129acc 100644 --- a/services/java/com/android/server/wm/WindowState.java +++ b/services/java/com/android/server/wm/WindowState.java @@ -461,8 +461,9 @@ final class WindowState implements WindowManagerPolicy.WindowState { public void computeFrameLw(Rect pf, Rect df, Rect of, Rect cf, Rect vf) { mHaveFrame = true; - if (mAppToken != null) { - mContainingFrame.set(getStackBounds()); + TaskStack stack = mAppToken != null ? getStack() : null; + if (stack != null && stack.hasSibling()) { + mContainingFrame.set(getStackBounds(stack)); if (mUnderStatusBar) { mContainingFrame.top = pf.top; } @@ -714,7 +715,10 @@ final class WindowState implements WindowManagerPolicy.WindowState { } Rect getStackBounds() { - TaskStack stack = getStack(); + return getStackBounds(getStack()); + } + + private Rect getStackBounds(TaskStack stack) { if (stack != null) { return stack.mStackBox.mBounds; } diff --git a/services/tests/servicestests/src/com/android/server/CountryDetectorServiceTest.java b/services/tests/servicestests/src/com/android/server/CountryDetectorServiceTest.java index 17a1585..192c50c 100644 --- a/services/tests/servicestests/src/com/android/server/CountryDetectorServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/CountryDetectorServiceTest.java @@ -66,7 +66,7 @@ public class CountryDetectorServiceTest extends AndroidTestCase { public void testAddRemoveListener() throws RemoteException { CountryDetectorServiceTester serviceTester = new CountryDetectorServiceTester(getContext()); - serviceTester.systemReady(); + serviceTester.systemRunning(); waitForSystemReady(serviceTester); CountryListenerTester listenerTester = new CountryListenerTester(); serviceTester.addCountryListener(listenerTester); @@ -80,7 +80,7 @@ public class CountryDetectorServiceTest extends AndroidTestCase { CountryListenerTester listenerTesterA = new CountryListenerTester(); CountryListenerTester listenerTesterB = new CountryListenerTester(); Country country = new Country("US", Country.COUNTRY_SOURCE_NETWORK); - serviceTester.systemReady(); + serviceTester.systemRunning(); waitForSystemReady(serviceTester); serviceTester.addCountryListener(listenerTesterA); serviceTester.addCountryListener(listenerTesterB); diff --git a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java index cdc4d78..aca77b8 100644 --- a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java @@ -878,8 +878,7 @@ public class NetworkStatsServiceTest extends AndroidTestCase { mAlarmManager.remove(isA(PendingIntent.class)); expectLastCall().anyTimes(); - mAlarmManager.setInexactRepeating( - eq(AlarmManager.ELAPSED_REALTIME), anyLong(), anyLong(), isA(PendingIntent.class)); + mAlarmManager.set(eq(AlarmManager.ELAPSED_REALTIME), anyLong(), anyLong(), anyLong(), isA(PendingIntent.class)); expectLastCall().atLeastOnce(); mNetManager.setGlobalAlert(anyLong()); diff --git a/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java b/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java index 53318a4..e4c4214 100644 --- a/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java +++ b/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java @@ -93,7 +93,7 @@ public class WindowManagerPermissionTests extends TestCase { } try { - mWm.addAppToken(0, null, 0, 0, 0, false, false); + mWm.addAppToken(0, null, 0, 0, 0, false, false, 0); fail("IWindowManager.addAppToken did not throw SecurityException as" + " expected"); } catch (SecurityException e) { diff --git a/tools/layoutlib/Android.mk b/tools/layoutlib/Android.mk index b27ce0e..4e73568 100644 --- a/tools/layoutlib/Android.mk +++ b/tools/layoutlib/Android.mk @@ -25,8 +25,8 @@ include $(CLEAR_VARS) # We need to process the framework classes.jar file, but we can't # depend directly on it (private vars won't be inherited correctly). # So, we depend on framework's BUILT file. -built_framework_dep := $(call java-lib-deps,framework) -built_framework_classes := $(call java-lib-files,framework) +built_framework_dep := $(call java-lib-deps,framework-base) +built_framework_classes := $(call java-lib-files,framework-base) built_core_dep := $(call java-lib-deps,core) built_core_classes := $(call java-lib-files,core) diff --git a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java index 6343049..f0c3a75 100644 --- a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java +++ b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java @@ -81,7 +81,7 @@ public class IWindowManagerImpl implements IWindowManager { @Override public void addAppToken(int arg0, IApplicationToken arg1, int arg2, int arg3, int arg4, - boolean arg5, boolean arg6) + boolean arg5, boolean arg6, int arg7) throws RemoteException { // TODO Auto-generated method stub diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java index cbefd3d..b909bec 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java @@ -30,6 +30,7 @@ import com.android.layoutlib.bridge.Bridge; import com.android.layoutlib.bridge.android.BridgeContext; import com.android.resources.Density; import com.android.resources.ResourceType; +import com.android.resources.ScreenOrientation; import com.android.resources.ScreenSize; import android.content.res.Configuration; @@ -347,6 +348,23 @@ public abstract class RenderAction<T extends RenderParams> extends FrameworkReso config.compatScreenWidthDp = config.screenWidthDp; config.compatScreenHeightDp = config.screenHeightDp; + ScreenOrientation orientation = hardwareConfig.getOrientation(); + if (orientation != null) { + switch (orientation) { + case PORTRAIT: + config.orientation = Configuration.ORIENTATION_PORTRAIT; + break; + case LANDSCAPE: + config.orientation = Configuration.ORIENTATION_LANDSCAPE; + break; + case SQUARE: + config.orientation = Configuration.ORIENTATION_SQUARE; + break; + } + } else { + config.orientation = Configuration.ORIENTATION_UNDEFINED; + } + // TODO: fill in more config info. return config; diff --git a/wifi/java/android/net/wifi/WifiNative.java b/wifi/java/android/net/wifi/WifiNative.java index 7ee7085..b1dd2ce 100644 --- a/wifi/java/android/net/wifi/WifiNative.java +++ b/wifi/java/android/net/wifi/WifiNative.java @@ -371,10 +371,12 @@ public class WifiNative { } public void startTdls(String macAddr, boolean enable) { - if (enable) + if (enable) { + doBooleanCommand("TDLS_DISCOVER " + macAddr); doBooleanCommand("TDLS_SETUP " + macAddr); - else + } else { doBooleanCommand("TDLS_TEARDOWN " + macAddr); + } } /** Example output: |