diff options
409 files changed, 9595 insertions, 3912 deletions
diff --git a/Android.mk b/Android.mk index a748b7b3f30a..80e681c6a805 100644 --- a/Android.mk +++ b/Android.mk @@ -329,20 +329,36 @@ non_base_dirs := \ ../../external/apache-http/src/org/apache/http # These are relative to frameworks/base -dirs_to_document := \ - $(fwbase_dirs_to_document) \ +dirs_to_check_apis := \ + $(fwbase_dirs_to_document) \ $(non_base_dirs) +# These are relative to frameworks/base +# FRAMEWORKS_BASE_SUBDIRS comes from build/core/pathmap.mk +dirs_to_document := \ + $(dirs_to_check_apis) \ + $(addprefix ../../, $(FRAMEWORKS_SUPPORT_JAVA_SRC_DIRS)) + +# These are relative to frameworks/base html_dirs := \ $(FRAMEWORKS_BASE_SUBDIRS) \ $(non_base_dirs) +# Common sources for doc check and api check +common_src_files := \ + $(call find-other-html-files, $(html_dirs)) \ + $(addprefix ../../libcore/, $(call libcore_to_document, $(LOCAL_PATH)/../../libcore)) \ + $(addprefix ../../system/media/mca/, $(call libfilterfw_to_document, $(LOCAL_PATH)/../../system/media/mca)) \ + # These are relative to frameworks/base framework_docs_LOCAL_SRC_FILES := \ $(call find-other-java-files, $(dirs_to_document)) \ - $(call find-other-html-files, $(html_dirs)) \ - $(addprefix ../../libcore/, $(call libcore_to_document, $(LOCAL_PATH)/../../libcore)) \ - $(addprefix ../../system/media/mca/, $(call libfilterfw_to_document, $(LOCAL_PATH)/../../system/media/mca)) + $(common_src_files) + +# These are relative to frameworks/base +framework_docs_LOCAL_API_CHECK_SRC_FILES := \ + $(call find-other-java-files, $(dirs_to_check_apis)) \ + $(common_src_files) # This is used by ide.mk as the list of source files that are # always included. @@ -462,6 +478,8 @@ web_docs_sample_code_flags := \ resources/samples/TicTacToeLib "TicTacToeLib" \ -samplecode $(sample_dir)/TicTacToeMain \ resources/samples/TicTacToeMain "TicTacToeMain" \ + -samplecode $(sample_dir)/ToyVpn \ + resources/samples/ToyVpn "Toy VPN Client" \ -samplecode $(sample_dir)/USB \ resources/samples/USB "USB" \ -samplecode $(sample_dir)/WeatherListWidget \ @@ -495,7 +513,7 @@ framework_docs_LOCAL_DROIDDOC_OPTIONS += \ # ==== the api stubs and current.xml =========================== include $(CLEAR_VARS) -LOCAL_SRC_FILES:=$(framework_docs_LOCAL_SRC_FILES) +LOCAL_SRC_FILES:=$(framework_docs_LOCAL_API_CHECK_SRC_FILES) LOCAL_INTERMEDIATE_SOURCES:=$(framework_docs_LOCAL_INTERMEDIATE_SOURCES) LOCAL_JAVA_LIBRARIES:=$(framework_docs_LOCAL_JAVA_LIBRARIES) LOCAL_MODULE_CLASS:=$(framework_docs_LOCAL_MODULE_CLASS) diff --git a/api/current.txt b/api/current.txt index cc50ff900ceb..ddf5baf30ff9 100644 --- a/api/current.txt +++ b/api/current.txt @@ -5334,6 +5334,7 @@ package android.content { method public java.util.ArrayList<T> getParcelableArrayListExtra(java.lang.String); method public T getParcelableExtra(java.lang.String); method public java.lang.String getScheme(); + method public android.content.Intent getSelector(); method public java.io.Serializable getSerializableExtra(java.lang.String); method public short[] getShortArrayExtra(java.lang.String); method public short getShortExtra(java.lang.String, short); @@ -5346,6 +5347,7 @@ package android.content { method public boolean hasExtra(java.lang.String); method public boolean hasFileDescriptors(); method public static android.content.Intent makeMainActivity(android.content.ComponentName); + method public static android.content.Intent makeMainSelectorActivity(java.lang.String, java.lang.String); method public static android.content.Intent makeRestartActivityTask(android.content.ComponentName); method public static android.content.Intent parseIntent(android.content.res.Resources, org.xmlpull.v1.XmlPullParser, android.util.AttributeSet) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException; method public static android.content.Intent parseUri(java.lang.String, int) throws java.net.URISyntaxException; @@ -5399,6 +5401,7 @@ package android.content { method public void setExtrasClassLoader(java.lang.ClassLoader); method public android.content.Intent setFlags(int); method public android.content.Intent setPackage(java.lang.String); + method public void setSelector(android.content.Intent); method public void setSourceBounds(android.graphics.Rect); method public android.content.Intent setType(java.lang.String); method public deprecated java.lang.String toURI(); @@ -5502,7 +5505,16 @@ package android.content { field public static final java.lang.String ACTION_WALLPAPER_CHANGED = "android.intent.action.WALLPAPER_CHANGED"; field public static final java.lang.String ACTION_WEB_SEARCH = "android.intent.action.WEB_SEARCH"; field public static final java.lang.String CATEGORY_ALTERNATIVE = "android.intent.category.ALTERNATIVE"; + field public static final java.lang.String CATEGORY_APP_BROWSER = "android.intent.category.APP_BROWSER"; + field public static final java.lang.String CATEGORY_APP_CALCULATOR = "android.intent.category.APP_CALCULATOR"; + field public static final java.lang.String CATEGORY_APP_CALENDAR = "android.intent.category.APP_CALENDAR"; + field public static final java.lang.String CATEGORY_APP_CONTACTS = "android.intent.category.APP_CONTACTS"; + field public static final java.lang.String CATEGORY_APP_EMAIL = "android.intent.category.APP_EMAIL"; + field public static final java.lang.String CATEGORY_APP_GALLERY = "android.intent.category.APP_GALLERY"; + field public static final java.lang.String CATEGORY_APP_MAPS = "android.intent.category.APP_MAPS"; field public static final java.lang.String CATEGORY_APP_MARKET = "android.intent.category.APP_MARKET"; + field public static final java.lang.String CATEGORY_APP_MESSAGING = "android.intent.category.APP_MESSAGING"; + field public static final java.lang.String CATEGORY_APP_MUSIC = "android.intent.category.APP_MUSIC"; field public static final java.lang.String CATEGORY_BROWSABLE = "android.intent.category.BROWSABLE"; field public static final java.lang.String CATEGORY_CAR_DOCK = "android.intent.category.CAR_DOCK"; field public static final java.lang.String CATEGORY_CAR_MODE = "android.intent.category.CAR_MODE"; @@ -5568,6 +5580,7 @@ package android.content { field public static final int FILL_IN_COMPONENT = 8; // 0x8 field public static final int FILL_IN_DATA = 2; // 0x2 field public static final int FILL_IN_PACKAGE = 16; // 0x10 + field public static final int FILL_IN_SELECTOR = 64; // 0x40 field public static final int FILL_IN_SOURCE_BOUNDS = 32; // 0x20 field public static final int FLAG_ACTIVITY_BROUGHT_TO_FRONT = 4194304; // 0x400000 field public static final int FLAG_ACTIVITY_CLEAR_TASK = 32768; // 0x8000 @@ -13633,16 +13646,19 @@ package android.opengl { field public static final int GL_RENDERBUFFER_RED_SIZE_OES = 36176; // 0x8d50 field public static final int GL_RENDERBUFFER_STENCIL_SIZE_OES = 36181; // 0x8d55 field public static final int GL_RENDERBUFFER_WIDTH_OES = 36162; // 0x8d42 + field public static final int GL_REQUIRED_TEXTURE_IMAGE_UNITS_OES = 36200; // 0x8d68 field public static final int GL_RGB565_OES = 36194; // 0x8d62 field public static final int GL_RGB5_A1_OES = 32855; // 0x8057 field public static final int GL_RGB8_OES = 32849; // 0x8051 field public static final int GL_RGBA4_OES = 32854; // 0x8056 field public static final int GL_RGBA8_OES = 32856; // 0x8058 + field public static final int GL_SAMPLER_EXTERNAL_OES = 36198; // 0x8d66 field public static final int GL_STENCIL_ATTACHMENT_OES = 36128; // 0x8d20 field public static final int GL_STENCIL_INDEX1_OES = 36166; // 0x8d46 field public static final int GL_STENCIL_INDEX4_OES = 36167; // 0x8d47 field public static final int GL_STENCIL_INDEX8_OES = 36168; // 0x8d48 field public static final int GL_TEXTURE_BINDING_CUBE_MAP_OES = 34068; // 0x8514 + field public static final int GL_TEXTURE_BINDING_EXTERNAL_OES = 36199; // 0x8d67 field public static final int GL_TEXTURE_CROP_RECT_OES = 35741; // 0x8b9d field public static final int GL_TEXTURE_CUBE_MAP_NEGATIVE_X_OES = 34070; // 0x8516 field public static final int GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_OES = 34072; // 0x8518 @@ -13651,6 +13667,7 @@ package android.opengl { field public static final int GL_TEXTURE_CUBE_MAP_POSITIVE_X_OES = 34069; // 0x8515 field public static final int GL_TEXTURE_CUBE_MAP_POSITIVE_Y_OES = 34071; // 0x8517 field public static final int GL_TEXTURE_CUBE_MAP_POSITIVE_Z_OES = 34073; // 0x8519 + field public static final int GL_TEXTURE_EXTERNAL_OES = 36197; // 0x8d65 field public static final int GL_TEXTURE_GEN_MODE_OES = 9472; // 0x2500 field public static final int GL_TEXTURE_GEN_STR_OES = 36192; // 0x8d60 field public static final int GL_TEXTURE_MATRIX_FLOAT_AS_INT_BITS_OES = 35215; // 0x898f @@ -14239,13 +14256,6 @@ package android.opengl { method public static void texSubImage2D(int, int, int, int, android.graphics.Bitmap, int, int); } - public abstract class ManagedEGLContext { - ctor public ManagedEGLContext(javax.microedition.khronos.egl.EGLContext); - method public javax.microedition.khronos.egl.EGLContext getContext(); - method public abstract void onTerminate(javax.microedition.khronos.egl.EGLContext); - method public void terminate(); - } - public class Matrix { ctor public Matrix(); method public static void frustumM(float[], int, float, float, float, float, float, float); @@ -14781,6 +14791,7 @@ package android.os { field public static final int FLAG_ONEWAY = 1; // 0x1 field public static final int INTERFACE_TRANSACTION = 1598968902; // 0x5f4e5446 field public static final int LAST_CALL_TRANSACTION = 16777215; // 0xffffff + field public static final int LIKE_TRANSACTION = 1598835019; // 0x5f4c494b field public static final int PING_TRANSACTION = 1599098439; // 0x5f504e47 field public static final int TWEET_TRANSACTION = 1599362900; // 0x5f545754 } @@ -17059,7 +17070,7 @@ package android.provider { field public static final java.lang.String EXTRA_VIDEO_QUALITY = "android.intent.extra.videoQuality"; field public static final java.lang.String INTENT_ACTION_MEDIA_PLAY_FROM_SEARCH = "android.media.action.MEDIA_PLAY_FROM_SEARCH"; field public static final java.lang.String INTENT_ACTION_MEDIA_SEARCH = "android.intent.action.MEDIA_SEARCH"; - field public static final java.lang.String INTENT_ACTION_MUSIC_PLAYER = "android.intent.action.MUSIC_PLAYER"; + field public static final deprecated java.lang.String INTENT_ACTION_MUSIC_PLAYER = "android.intent.action.MUSIC_PLAYER"; field public static final java.lang.String INTENT_ACTION_STILL_IMAGE_CAMERA = "android.media.action.STILL_IMAGE_CAMERA"; field public static final java.lang.String INTENT_ACTION_VIDEO_CAMERA = "android.media.action.VIDEO_CAMERA"; field public static final java.lang.String MEDIA_IGNORE_FILENAME = ".nomedia"; @@ -17422,6 +17433,7 @@ package android.provider { method public static boolean putString(android.content.ContentResolver, java.lang.String, java.lang.String); method public static final void setLocationProviderEnabled(android.content.ContentResolver, java.lang.String, boolean); field public static final java.lang.String ACCESSIBILITY_ENABLED = "accessibility_enabled"; + field public static final java.lang.String ACCESSIBILITY_SPEAK_PASSWORD = "speak_password"; field public static final java.lang.String ADB_ENABLED = "adb_enabled"; field public static final java.lang.String ALLOWED_GEOLOCATION_ORIGINS = "allowed_geolocation_origins"; field public static final java.lang.String ALLOW_MOCK_LOCATION = "mock_location"; @@ -18428,14 +18440,14 @@ package android.renderscript { ctor public RSSurfaceView(android.content.Context); ctor public RSSurfaceView(android.content.Context, android.util.AttributeSet); method public android.renderscript.RenderScriptGL createRenderScriptGL(android.renderscript.RenderScriptGL.SurfaceConfig); - method public synchronized void destroyRenderScriptGL(); + method public void destroyRenderScriptGL(); method public android.renderscript.RenderScriptGL getRenderScriptGL(); method public void pause(); method public void resume(); method public void setRenderScriptGL(android.renderscript.RenderScriptGL); - method public synchronized void surfaceChanged(android.view.SurfaceHolder, int, int, int); + method public void surfaceChanged(android.view.SurfaceHolder, int, int, int); method public void surfaceCreated(android.view.SurfaceHolder); - method public synchronized void surfaceDestroyed(android.view.SurfaceHolder); + method public void surfaceDestroyed(android.view.SurfaceHolder); } public class RSTextureView extends android.view.TextureView implements android.view.TextureView.SurfaceTextureListener { @@ -22218,6 +22230,8 @@ package android.view { field public static final int KEYCODE_BUTTON_Y = 100; // 0x64 field public static final int KEYCODE_BUTTON_Z = 101; // 0x65 field public static final int KEYCODE_C = 31; // 0x1f + field public static final int KEYCODE_CALCULATOR = 210; // 0xd2 + field public static final int KEYCODE_CALENDAR = 208; // 0xd0 field public static final int KEYCODE_CALL = 5; // 0x5 field public static final int KEYCODE_CAMERA = 27; // 0x1b field public static final int KEYCODE_CAPS_LOCK = 115; // 0x73 @@ -22226,6 +22240,7 @@ package android.view { field public static final int KEYCODE_CHANNEL_UP = 166; // 0xa6 field public static final int KEYCODE_CLEAR = 28; // 0x1c field public static final int KEYCODE_COMMA = 55; // 0x37 + field public static final int KEYCODE_CONTACTS = 207; // 0xcf field public static final int KEYCODE_CTRL_LEFT = 113; // 0x71 field public static final int KEYCODE_CTRL_RIGHT = 114; // 0x72 field public static final int KEYCODE_D = 32; // 0x20 @@ -22293,6 +22308,7 @@ package android.view { field public static final int KEYCODE_MINUS = 69; // 0x45 field public static final int KEYCODE_MOVE_END = 123; // 0x7b field public static final int KEYCODE_MOVE_HOME = 122; // 0x7a + field public static final int KEYCODE_MUSIC = 209; // 0xd1 field public static final int KEYCODE_MUTE = 91; // 0x5b field public static final int KEYCODE_N = 42; // 0x2a field public static final int KEYCODE_NOTIFICATION = 83; // 0x53 diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java index 140222ee7130..fddb429d5ae5 100644 --- a/cmds/am/src/com/android/commands/am/Am.java +++ b/cmds/am/src/com/android/commands/am/Am.java @@ -131,6 +131,10 @@ public class Am { runScreenCompat(); } else if (op.equals("display-size")) { runDisplaySize(); + } else if (op.equals("to-uri")) { + runToUri(false); + } else if (op.equals("to-intent-uri")) { + runToUri(true); } else { throw new IllegalArgumentException("Unknown command: " + op); } @@ -138,6 +142,7 @@ public class Am { private Intent makeIntent() throws URISyntaxException { Intent intent = new Intent(); + Intent baseIntent = intent; boolean hasIntentInfo = false; mDebugOption = false; @@ -152,35 +157,39 @@ public class Am { while ((opt=nextOption()) != null) { if (opt.equals("-a")) { intent.setAction(nextArgRequired()); - hasIntentInfo = true; + if (intent == baseIntent) { + hasIntentInfo = true; + } } else if (opt.equals("-d")) { data = Uri.parse(nextArgRequired()); - hasIntentInfo = true; + if (intent == baseIntent) { + hasIntentInfo = true; + } } else if (opt.equals("-t")) { type = nextArgRequired(); - hasIntentInfo = true; + if (intent == baseIntent) { + hasIntentInfo = true; + } } else if (opt.equals("-c")) { intent.addCategory(nextArgRequired()); - hasIntentInfo = true; + if (intent == baseIntent) { + hasIntentInfo = true; + } } else if (opt.equals("-e") || opt.equals("--es")) { String key = nextArgRequired(); String value = nextArgRequired(); intent.putExtra(key, value); - hasIntentInfo = true; } else if (opt.equals("--esn")) { String key = nextArgRequired(); intent.putExtra(key, (String) null); - hasIntentInfo = true; } else if (opt.equals("--ei")) { String key = nextArgRequired(); String value = nextArgRequired(); intent.putExtra(key, Integer.valueOf(value)); - hasIntentInfo = true; } else if (opt.equals("--eu")) { String key = nextArgRequired(); String value = nextArgRequired(); intent.putExtra(key, Uri.parse(value)); - hasIntentInfo = true; } else if (opt.equals("--eia")) { String key = nextArgRequired(); String value = nextArgRequired(); @@ -190,12 +199,10 @@ public class Am { list[i] = Integer.valueOf(strings[i]); } intent.putExtra(key, list); - hasIntentInfo = true; } else if (opt.equals("--el")) { String key = nextArgRequired(); String value = nextArgRequired(); intent.putExtra(key, Long.valueOf(value)); - hasIntentInfo = true; } else if (opt.equals("--ela")) { String key = nextArgRequired(); String value = nextArgRequired(); @@ -205,18 +212,18 @@ public class Am { list[i] = Long.valueOf(strings[i]); } intent.putExtra(key, list); - hasIntentInfo = true; } else if (opt.equals("--ez")) { String key = nextArgRequired(); String value = nextArgRequired(); intent.putExtra(key, Boolean.valueOf(value)); - hasIntentInfo = true; } else if (opt.equals("-n")) { String str = nextArgRequired(); ComponentName cn = ComponentName.unflattenFromString(str); if (cn == null) throw new IllegalArgumentException("Bad component name: " + str); intent.setComponent(cn); - hasIntentInfo = true; + if (intent == baseIntent) { + hasIntentInfo = true; + } } else if (opt.equals("-f")) { String str = nextArgRequired(); intent.setFlags(Integer.decode(str).intValue()); @@ -264,6 +271,9 @@ public class Am { intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); } else if (opt.equals("--receiver-replace-pending")) { intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); + } else if (opt.equals("--selector")) { + intent.setDataAndType(data, type); + intent = new Intent(); } else if (opt.equals("-D")) { mDebugOption = true; } else if (opt.equals("-W")) { @@ -286,25 +296,42 @@ public class Am { } intent.setDataAndType(data, type); + final boolean hasSelector = intent != baseIntent; + if (hasSelector) { + // A selector was specified; fix up. + baseIntent.setSelector(intent); + intent = baseIntent; + } + String arg = nextArg(); - if (arg != null) { - Intent baseIntent; - if (arg.indexOf(':') >= 0) { - // The argument is a URI. Fully parse it, and use that result - // to fill in any data not specified so far. - baseIntent = Intent.parseUri(arg, Intent.URI_INTENT_SCHEME); - } else if (arg.indexOf('/') >= 0) { - // The argument is a component name. Build an Intent to launch - // it. - baseIntent = new Intent(Intent.ACTION_MAIN); - baseIntent.addCategory(Intent.CATEGORY_LAUNCHER); - baseIntent.setComponent(ComponentName.unflattenFromString(arg)); - } else { - // Assume the argument is a package name. + baseIntent = null; + if (arg == null) { + if (hasSelector) { + // If a selector has been specified, and no arguments + // have been supplied for the main Intent, then we can + // assume it is ACTION_MAIN CATEGORY_LAUNCHER; we don't + // need to have a component name specified yet, the + // selector will take care of that. baseIntent = new Intent(Intent.ACTION_MAIN); baseIntent.addCategory(Intent.CATEGORY_LAUNCHER); - baseIntent.setPackage(arg); } + } else if (arg.indexOf(':') >= 0) { + // The argument is a URI. Fully parse it, and use that result + // to fill in any data not specified so far. + baseIntent = Intent.parseUri(arg, Intent.URI_INTENT_SCHEME); + } else if (arg.indexOf('/') >= 0) { + // The argument is a component name. Build an Intent to launch + // it. + baseIntent = new Intent(Intent.ACTION_MAIN); + baseIntent.addCategory(Intent.CATEGORY_LAUNCHER); + baseIntent.setComponent(ComponentName.unflattenFromString(arg)); + } else { + // Assume the argument is a package name. + baseIntent = new Intent(Intent.ACTION_MAIN); + baseIntent.addCategory(Intent.CATEGORY_LAUNCHER); + baseIntent.setPackage(arg); + } + if (baseIntent != null) { Bundle extras = intent.getExtras(); intent.replaceExtras((Bundle)null); Bundle uriExtras = baseIntent.getExtras(); @@ -315,7 +342,7 @@ public class Am { baseIntent.removeCategory(c); } } - intent.fillIn(baseIntent, Intent.FILL_IN_COMPONENT); + intent.fillIn(baseIntent, Intent.FILL_IN_COMPONENT | Intent.FILL_IN_SELECTOR); if (extras == null) { extras = uriExtras; } else if (uriExtras != null) { @@ -1064,6 +1091,11 @@ public class Am { } } + private void runToUri(boolean intentScheme) throws Exception { + Intent intent = makeIntent(); + System.out.println(intent.toUri(intentScheme ? Intent.URI_INTENT_SCHEME : 0)); + } + private class IntentReceiver extends IIntentReceiver.Stub { private boolean mFinished = false; @@ -1233,6 +1265,8 @@ public class Am { " am monitor [--gdb <port>]\n" + " am screen-compat [on|off] <PACKAGE>\n" + " am display-size [reset|MxN]\n" + + " am to-uri [INTENT]\n" + + " am to-intent-uri [INTENT]\n" + "\n" + "am start: start an Activity. Options are:\n" + " -D: enable debugging\n" + @@ -1284,6 +1318,10 @@ public class Am { "\n" + "am display-size: override display size.\n" + "\n" + + "am to-uri: print the given Intent specification as a URI.\n" + + "\n" + + "am to-intent-uri: print the given Intent specification as an intent: URI.\n" + + "\n" + "<INTENT> specifications include these flags and arguments:\n" + " [-a <ACTION>] [-d <DATA_URI>] [-t <MIME_TYPE>]\n" + " [-c <CATEGORY> [-c <CATEGORY>] ...]\n" + @@ -1308,6 +1346,7 @@ public class Am { " [--activity-single-top] [--activity-clear-task]\n" + " [--activity-task-on-home]\n" + " [--receiver-registered-only] [--receiver-replace-pending]\n" + + " [--selector]\n" + " [<URI> | <PACKAGE> | <COMPONENT>]\n" ); } diff --git a/cmds/dumpstate/dumpstate.c b/cmds/dumpstate/dumpstate.c index fe81d2b36fca..395c28bbd89a 100644 --- a/cmds/dumpstate/dumpstate.c +++ b/cmds/dumpstate/dumpstate.c @@ -120,6 +120,12 @@ static void dumpstate() { dump_file("NETWORK ROUTES", "/proc/net/route"); dump_file("NETWORK ROUTES IPV6", "/proc/net/ipv6_route"); + run_command("IP RULES", 10, "ip", "rule", "show", NULL); + run_command("IP RULES v6", 10, "ip", "-6", "rule", "show", NULL); + run_command("ROUTE TABLE 60", 10, "ip", "route", "show", "table", "60", NULL); + run_command("ROUTE TABLE 61 v6", 10, "ip", "-6", "route", "show", "table", "60", NULL); + run_command("ROUTE TABLE 61", 10, "ip", "route", "show", "table", "61", NULL); + run_command("ROUTE TABLE 61 v6", 10, "ip", "-6", "route", "show", "table", "61", NULL); dump_file("ARP CACHE", "/proc/net/arp"); run_command("IPTABLES", 10, "su", "root", "iptables", "-L", "-nvx", NULL); run_command("IP6TABLES", 10, "su", "root", "ip6tables", "-L", "-nvx", NULL); diff --git a/cmds/installd/commands.c b/cmds/installd/commands.c index 26b911356699..4ede33f73daf 100644 --- a/cmds/installd/commands.c +++ b/cmds/installd/commands.c @@ -184,6 +184,7 @@ int free_cache(int64_t free_size) DIR *d; struct dirent *de; int64_t avail; + char datadir[PKG_PATH_MAX]; avail = disk_free(); if (avail < 0) return -1; @@ -191,9 +192,14 @@ int free_cache(int64_t free_size) LOGI("free_cache(%" PRId64 ") avail %" PRId64 "\n", free_size, avail); if (avail >= free_size) return 0; - d = opendir(android_data_dir.path); + if (create_persona_path(datadir, 0)) { + LOGE("couldn't get directory for persona 0"); + return -1; + } + + d = opendir(datadir); if (d == NULL) { - LOGE("cannot open %s: %s\n", android_data_dir.path, strerror(errno)); + LOGE("cannot open %s: %s\n", datadir, strerror(errno)); return -1; } dfd = dirfd(d); @@ -578,19 +584,6 @@ fail: return -1; } -int create_move_path(char path[PKG_PATH_MAX], - const char* pkgname, - const char* leaf, - uid_t persona) -{ - if ((android_data_dir.len + strlen(pkgname) + strlen(leaf) + 1) >= PKG_PATH_MAX) { - return -1; - } - - sprintf(path, "%s%s%s/%s", android_data_dir.path, PRIMARY_USER_PREFIX, pkgname, leaf); - return 0; -} - void mkinnerdirs(char* path, int basepos, mode_t mode, int uid, int gid, struct stat* statbuf) { diff --git a/cmds/installd/installd.h b/cmds/installd/installd.h index c5872b8efa09..173cabfb77a7 100644 --- a/cmds/installd/installd.h +++ b/cmds/installd/installd.h @@ -105,6 +105,11 @@ int create_pkg_path(char path[PKG_PATH_MAX], int create_persona_path(char path[PKG_PATH_MAX], uid_t persona); +int create_move_path(char path[PKG_PATH_MAX], + const char* pkgname, + const char* leaf, + uid_t persona); + int is_valid_package_name(const char* pkgname); int create_cache_path(char path[PKG_PATH_MAX], const char *src); diff --git a/cmds/installd/tests/installd_utils_test.cpp b/cmds/installd/tests/installd_utils_test.cpp index 1128fceca0af..7cb9b37fe038 100644 --- a/cmds/installd/tests/installd_utils_test.cpp +++ b/cmds/installd/tests/installd_utils_test.cpp @@ -34,6 +34,16 @@ extern "C" { #define TEST_SYSTEM_DIR1 "/system/app/" #define TEST_SYSTEM_DIR2 "/vendor/app/" +#define REALLY_LONG_APP_NAME "com.example." \ + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa." \ + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa." \ + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + +#define REALLY_LONG_LEAF_NAME "shared_prefs_shared_prefs_shared_prefs_shared_prefs_shared_prefs_" \ + "shared_prefs_shared_prefs_shared_prefs_shared_prefs_shared_prefs_shared_prefs_" \ + "shared_prefs_shared_prefs_shared_prefs_shared_prefs_shared_prefs_shared_prefs_" \ + "shared_prefs_shared_prefs_shared_prefs_shared_prefs_shared_prefs_shared_prefs_" + namespace android { class UtilsTest : public testing::Test { @@ -210,7 +220,7 @@ TEST_F(UtilsTest, CheckSystemApp_BadPathEscapeFail) { TEST_F(UtilsTest, GetPathFromString_NullPathFail) { dir_rec_t test1; - EXPECT_EQ(-1, get_path_from_string(&test1, NULL)) + EXPECT_EQ(-1, get_path_from_string(&test1, (const char *) NULL)) << "Should not allow NULL as a path."; } @@ -327,6 +337,50 @@ TEST_F(UtilsTest, CreatePkgPathInDir_ProtectedDir) { << "Package path should be in /data/app-private/"; } +TEST_F(UtilsTest, CreatePersonaPath_Primary) { + char path[PKG_PATH_MAX]; + + EXPECT_EQ(0, create_persona_path(path, 0)) + << "Should successfully build primary user path."; + + EXPECT_STREQ("/data/data/", path) + << "Primary user should have correct path"; +} + +TEST_F(UtilsTest, CreatePersonaPath_Secondary) { + char path[PKG_PATH_MAX]; + + EXPECT_EQ(0, create_persona_path(path, 1)) + << "Should successfully build primary user path."; + + EXPECT_STREQ("/data/user/1/", path) + << "Primary user should have correct path"; +} + +TEST_F(UtilsTest, CreateMovePath_Primary) { + char path[PKG_PATH_MAX]; + + EXPECT_EQ(0, create_move_path(path, "com.android.test", "shared_prefs", 0)) + << "Should be able to create move path for primary user"; + + EXPECT_STREQ("/data/data/com.android.test/shared_prefs", path) + << "Primary user package directory should be created correctly"; +} + +TEST_F(UtilsTest, CreateMovePath_Fail_AppTooLong) { + char path[PKG_PATH_MAX]; + + EXPECT_EQ(-1, create_move_path(path, REALLY_LONG_APP_NAME, "shared_prefs", 0)) + << "Should fail to create move path for primary user"; +} + +TEST_F(UtilsTest, CreateMovePath_Fail_LeafTooLong) { + char path[PKG_PATH_MAX]; + + EXPECT_EQ(-1, create_move_path(path, "com.android.test", REALLY_LONG_LEAF_NAME, 0)) + << "Should fail to create move path for primary user"; +} + TEST_F(UtilsTest, CopyAndAppend_Normal) { //int copy_and_append(dir_rec_t* dst, dir_rec_t* src, char* suffix) dir_rec_t dst; diff --git a/cmds/installd/utils.c b/cmds/installd/utils.c index 3099b8341f6e..a53a93ce1073 100644 --- a/cmds/installd/utils.c +++ b/cmds/installd/utils.c @@ -109,7 +109,7 @@ int create_persona_path(char path[PKG_PATH_MAX], uid_len = 0; } else { persona_prefix = SECONDARY_USER_PREFIX; - uid_len = snprintf(NULL, 0, "%d", persona); + uid_len = snprintf(NULL, 0, "%d/", persona); } char *dst = path; @@ -126,7 +126,7 @@ int create_persona_path(char path[PKG_PATH_MAX], LOGE("Error building user path"); return -1; } - int ret = snprintf(dst, dst_size, "%d", persona); + int ret = snprintf(dst, dst_size, "%d/", persona); if (ret < 0 || (size_t) ret != uid_len) { LOGE("Error appending persona id to path"); return -1; @@ -135,6 +135,20 @@ int create_persona_path(char path[PKG_PATH_MAX], return 0; } +int create_move_path(char path[PKG_PATH_MAX], + const char* pkgname, + const char* leaf, + uid_t persona) +{ + if ((android_data_dir.len + strlen(PRIMARY_USER_PREFIX) + strlen(pkgname) + strlen(leaf) + 1) + >= PKG_PATH_MAX) { + return -1; + } + + sprintf(path, "%s%s%s/%s", android_data_dir.path, PRIMARY_USER_PREFIX, pkgname, leaf); + return 0; +} + /** * Checks whether the package name is valid. Returns -1 on error and * 0 on success. diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java index 64a275553339..211be52e0622 100644 --- a/core/java/android/accessibilityservice/AccessibilityService.java +++ b/core/java/android/accessibilityservice/AccessibilityService.java @@ -16,8 +16,6 @@ package android.accessibilityservice; -import com.android.internal.os.HandlerCaller; - import android.app.Service; import android.content.Intent; import android.os.IBinder; @@ -25,8 +23,11 @@ import android.os.Message; import android.os.RemoteException; import android.util.Log; import android.view.accessibility.AccessibilityEvent; +import android.view.accessibility.AccessibilityInteractionClient; import android.view.accessibility.AccessibilityNodeInfo; +import com.android.internal.os.HandlerCaller; + /** * An accessibility service runs in the background and receives callbacks by the system * when {@link AccessibilityEvent}s are fired. Such events denote some state transition @@ -219,7 +220,7 @@ public abstract class AccessibilityService extends Service { private AccessibilityServiceInfo mInfo; - IAccessibilityServiceConnection mConnection; + private int mConnectionId; /** * Callback for {@link android.view.accessibility.AccessibilityEvent}s. @@ -264,9 +265,11 @@ public abstract class AccessibilityService extends Service { * AccessibilityManagerService. */ private void sendServiceInfo() { - if (mInfo != null && mConnection != null) { + IAccessibilityServiceConnection connection = + AccessibilityInteractionClient.getInstance().getConnection(mConnectionId); + if (mInfo != null && connection != null) { try { - mConnection.setServiceInfo(mInfo); + connection.setServiceInfo(mInfo); } catch (RemoteException re) { Log.w(LOG_TAG, "Error while setting AccessibilityServiceInfo", re); } @@ -302,8 +305,9 @@ public abstract class AccessibilityService extends Service { mCaller = new HandlerCaller(context, this); } - public void setConnection(IAccessibilityServiceConnection connection) { - Message message = mCaller.obtainMessageO(DO_SET_SET_CONNECTION, connection); + public void setConnection(IAccessibilityServiceConnection connection, int connectionId) { + Message message = mCaller.obtainMessageIO(DO_SET_SET_CONNECTION, connectionId, + connection); mCaller.sendMessage(message); } @@ -330,8 +334,19 @@ public abstract class AccessibilityService extends Service { mTarget.onInterrupt(); return; case DO_SET_SET_CONNECTION : - mConnection = ((IAccessibilityServiceConnection) message.obj); - mTarget.onServiceConnected(); + final int connectionId = message.arg1; + IAccessibilityServiceConnection connection = + (IAccessibilityServiceConnection) message.obj; + if (connection != null) { + AccessibilityInteractionClient.getInstance().addConnection(connectionId, + connection); + mConnectionId = connectionId; + mTarget.onServiceConnected(); + } else { + AccessibilityInteractionClient.getInstance().removeConnection(connectionId); + mConnectionId = AccessibilityInteractionClient.NO_ID; + // TODO: Do we need a onServiceDisconnected callback? + } return; default : Log.w(LOG_TAG, "Unknown message type " + message.what); diff --git a/core/java/android/accessibilityservice/IEventListener.aidl b/core/java/android/accessibilityservice/IEventListener.aidl index 5b849f1e40fd..5536b3c05446 100644 --- a/core/java/android/accessibilityservice/IEventListener.aidl +++ b/core/java/android/accessibilityservice/IEventListener.aidl @@ -26,7 +26,7 @@ import android.view.accessibility.AccessibilityEvent; */ oneway interface IEventListener { - void setConnection(in IAccessibilityServiceConnection connection); + void setConnection(in IAccessibilityServiceConnection connection, int connectionId); void onAccessibilityEvent(in AccessibilityEvent event); diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 303f81b4cd50..0c761fc4b7e3 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -175,11 +175,11 @@ public final class ActivityThread { // These can be accessed by multiple threads; mPackages is the lock. // XXX For now we keep around information about all packages we have // seen, not removing entries from this map. - // NOTE: The activity manager in its process needs to call in to + // NOTE: The activity and window managers need to call in to // ActivityThread to do things like update resource configurations, - // which means this lock gets held while the activity manager holds its - // own lock. Thus you MUST NEVER call back into the activity manager - // or anything that depends on it while holding this lock. + // 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 diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java index 8ed7481cddd1..180a442f52c1 100644 --- a/core/java/android/app/ApplicationPackageManager.java +++ b/core/java/android/app/ApplicationPackageManager.java @@ -625,7 +625,7 @@ final class ApplicationPackageManager extends PackageManager { return info.activityInfo.loadIcon(this); } - throw new NameNotFoundException(intent.toURI()); + throw new NameNotFoundException(intent.toUri(0)); } @Override public Drawable getDefaultActivityIcon() { @@ -728,15 +728,22 @@ final class ApplicationPackageManager extends PackageManager { private Drawable getCachedIcon(ResourceName name) { synchronized (sSync) { - WeakReference<Drawable> wr = sIconCache.get(name); + WeakReference<Drawable.ConstantState> wr = sIconCache.get(name); if (DEBUG_ICONS) Log.v(TAG, "Get cached weak drawable ref for " + name + ": " + wr); if (wr != null) { // we have the activity - Drawable dr = wr.get(); - if (dr != null) { - if (DEBUG_ICONS) Log.v(TAG, "Get cached drawable for " - + name + ": " + dr); - return dr; + Drawable.ConstantState state = wr.get(); + if (state != null) { + if (DEBUG_ICONS) { + Log.v(TAG, "Get cached drawable state for " + name + ": " + state); + } + // Note: It's okay here to not use the newDrawable(Resources) variant + // of the API. The ConstantState comes from a drawable that was + // originally created by passing the proper app Resources instance + // which means the state should already contain the proper + // resources specific information (like density.) See + // BitmapDrawable.BitmapState for instance. + return state.newDrawable(); } // our entry has been purged sIconCache.remove(name); @@ -747,14 +754,12 @@ final class ApplicationPackageManager extends PackageManager { private void putCachedIcon(ResourceName name, Drawable dr) { synchronized (sSync) { - sIconCache.put(name, new WeakReference<Drawable>(dr)); - if (DEBUG_ICONS) Log.v(TAG, "Added cached drawable for " - + name + ": " + dr); + sIconCache.put(name, new WeakReference<Drawable.ConstantState>(dr.getConstantState())); + if (DEBUG_ICONS) Log.v(TAG, "Added cached drawable state for " + name + ": " + dr); } } - static final void handlePackageBroadcast(int cmd, String[] pkgList, - boolean hasPkgInfo) { + static void handlePackageBroadcast(int cmd, String[] pkgList, boolean hasPkgInfo) { boolean immediateGc = false; if (cmd == IApplicationThread.EXTERNAL_STORAGE_UNAVAILABLE) { immediateGc = true; @@ -1226,8 +1231,8 @@ final class ApplicationPackageManager extends PackageManager { private final IPackageManager mPM; private static final Object sSync = new Object(); - private static HashMap<ResourceName, WeakReference<Drawable> > sIconCache - = new HashMap<ResourceName, WeakReference<Drawable> >(); - private static HashMap<ResourceName, WeakReference<CharSequence> > sStringCache - = new HashMap<ResourceName, WeakReference<CharSequence> >(); + 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>>(); } diff --git a/core/java/android/app/DatePickerDialog.java b/core/java/android/app/DatePickerDialog.java index 8b70370972cc..bf8fde00ed6e 100644 --- a/core/java/android/app/DatePickerDialog.java +++ b/core/java/android/app/DatePickerDialog.java @@ -91,13 +91,14 @@ public class DatePickerDialog extends AlertDialog implements OnClickListener, mCallBack = callBack; - setButton(BUTTON_POSITIVE, context.getText(R.string.date_time_set), this); - setButton(BUTTON_NEGATIVE, context.getText(R.string.cancel), (OnClickListener) null); + Context themeContext = getContext(); + setButton(BUTTON_POSITIVE, themeContext.getText(R.string.date_time_set), this); + setButton(BUTTON_NEGATIVE, themeContext.getText(R.string.cancel), (OnClickListener) null); setIcon(0); setTitle(R.string.date_picker_dialog_title); LayoutInflater inflater = - (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + (LayoutInflater) themeContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); View view = inflater.inflate(R.layout.date_picker_dialog, null); setView(view); mDatePicker = (DatePicker) view.findViewById(R.id.datePicker); diff --git a/core/java/android/app/TimePickerDialog.java b/core/java/android/app/TimePickerDialog.java index a990ee98de51..353b41522162 100644 --- a/core/java/android/app/TimePickerDialog.java +++ b/core/java/android/app/TimePickerDialog.java @@ -92,16 +92,16 @@ public class TimePickerDialog extends AlertDialog mInitialMinute = minute; mIs24HourView = is24HourView; - setCanceledOnTouchOutside(false); setIcon(0); setTitle(R.string.time_picker_dialog_title); - setButton(BUTTON_POSITIVE, context.getText(R.string.date_time_set), this); - setButton(BUTTON_NEGATIVE, context.getText(R.string.cancel), + Context themeContext = getContext(); + setButton(BUTTON_POSITIVE, themeContext.getText(R.string.date_time_set), this); + setButton(BUTTON_NEGATIVE, themeContext.getText(R.string.cancel), (OnClickListener) null); LayoutInflater inflater = - (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + (LayoutInflater) themeContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); View view = inflater.inflate(R.layout.time_picker_dialog, null); setView(view); mTimePicker = (TimePicker) view.findViewById(R.id.timePicker); diff --git a/core/java/android/bluetooth/BluetoothA2dp.java b/core/java/android/bluetooth/BluetoothA2dp.java index 96f3290160f0..7300107dd511 100644 --- a/core/java/android/bluetooth/BluetoothA2dp.java +++ b/core/java/android/bluetooth/BluetoothA2dp.java @@ -129,6 +129,10 @@ public final class BluetoothA2dp implements BluetoothProfile { } } + /*package*/ void close() { + mServiceListener = null; + } + /** * Initiate connection to a profile of the remote bluetooth device. * diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java index d97165256534..5f5ba5041333 100644 --- a/core/java/android/bluetooth/BluetoothAdapter.java +++ b/core/java/android/bluetooth/BluetoothAdapter.java @@ -1180,11 +1180,29 @@ public final class BluetoothAdapter { * @param proxy Profile proxy object */ public void closeProfileProxy(int profile, BluetoothProfile proxy) { - if (profile == BluetoothProfile.HEADSET) { - BluetoothHeadset headset = (BluetoothHeadset)proxy; - if (headset != null) { + if (proxy == null) return; + + switch (profile) { + case BluetoothProfile.HEADSET: + BluetoothHeadset headset = (BluetoothHeadset)proxy; headset.close(); - } + break; + case BluetoothProfile.A2DP: + BluetoothA2dp a2dp = (BluetoothA2dp)proxy; + a2dp.close(); + break; + case BluetoothProfile.INPUT_DEVICE: + BluetoothInputDevice iDev = (BluetoothInputDevice)proxy; + iDev.close(); + break; + case BluetoothProfile.PAN: + BluetoothPan pan = (BluetoothPan)proxy; + pan.close(); + break; + case BluetoothProfile.HEALTH: + BluetoothHealth health = (BluetoothHealth)proxy; + health.close(); + break; } } diff --git a/core/java/android/bluetooth/BluetoothDeviceProfileState.java b/core/java/android/bluetooth/BluetoothDeviceProfileState.java index b1d007071df8..c9603bf3ed55 100644 --- a/core/java/android/bluetooth/BluetoothDeviceProfileState.java +++ b/core/java/android/bluetooth/BluetoothDeviceProfileState.java @@ -109,6 +109,8 @@ public final class BluetoothDeviceProfileState extends StateMachine { private BluetoothA2dpService mA2dpService; private BluetoothHeadset mHeadsetService; private BluetoothPbap mPbapService; + private PbapServiceListener mPbap; + private BluetoothAdapter mAdapter; private boolean mPbapServiceConnected; private boolean mAutoConnectionPending; private static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN; @@ -249,11 +251,11 @@ public final class BluetoothDeviceProfileState extends StateMachine { mContext.registerReceiver(mBroadcastReceiver, filter); - BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); - adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener, + mAdapter = BluetoothAdapter.getDefaultAdapter(); + mAdapter.getProfileProxy(mContext, mBluetoothProfileServiceListener, BluetoothProfile.HEADSET); // TODO(): Convert PBAP to the new Profile APIs. - PbapServiceListener p = new PbapServiceListener(); + mPbap = new PbapServiceListener(); mIncomingConnections = mService.getIncomingState(address); mIncomingRejectTimer = readTimerValue(); @@ -414,6 +416,26 @@ public final class BluetoothDeviceProfileState extends StateMachine { case TRANSITION_TO_STABLE: // ignore. break; + case SM_QUIT_CMD: + mContext.unregisterReceiver(mBroadcastReceiver); + mBroadcastReceiver = null; + mAdapter.closeProfileProxy(BluetoothProfile.HEADSET, mHeadsetService); + mBluetoothProfileServiceListener = null; + mOutgoingHandsfree = null; + mPbap = null; + mPbapService.close(); + mPbapService = null; + mIncomingHid = null; + mOutgoingHid = null; + mIncomingHandsfree = null; + mOutgoingHandsfree = null; + mIncomingA2dp = null; + mOutgoingA2dp = null; + mBondedDevice = null; + // There is a problem in the State Machine code + // where things are not cleaned up properly, when quit message + // is handled so return NOT_HANDLED as a workaround. + return NOT_HANDLED; default: return NOT_HANDLED; } diff --git a/core/java/android/bluetooth/BluetoothHeadset.java b/core/java/android/bluetooth/BluetoothHeadset.java index 8f2b3d88c2eb..2bbf008a7694 100644 --- a/core/java/android/bluetooth/BluetoothHeadset.java +++ b/core/java/android/bluetooth/BluetoothHeadset.java @@ -245,6 +245,7 @@ public final class BluetoothHeadset implements BluetoothProfile { mContext.unbindService(mConnection); mConnection = null; } + mServiceListener = null; } /** diff --git a/core/java/android/bluetooth/BluetoothHealth.java b/core/java/android/bluetooth/BluetoothHealth.java index 9b2b8cad20fe..f850c0224a50 100644 --- a/core/java/android/bluetooth/BluetoothHealth.java +++ b/core/java/android/bluetooth/BluetoothHealth.java @@ -452,6 +452,10 @@ public final class BluetoothHealth implements BluetoothProfile { } } + /*package*/ void close() { + mServiceListener = null; + } + private boolean isEnabled() { BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); diff --git a/core/java/android/bluetooth/BluetoothInputDevice.java b/core/java/android/bluetooth/BluetoothInputDevice.java index 282b70a42c81..1a9e011ad7fe 100644 --- a/core/java/android/bluetooth/BluetoothInputDevice.java +++ b/core/java/android/bluetooth/BluetoothInputDevice.java @@ -118,6 +118,10 @@ public final class BluetoothInputDevice implements BluetoothProfile { } } + /*package*/ void close() { + mServiceListener = null; + } + /** * Initiate connection to a profile of the remote bluetooth device. * diff --git a/core/java/android/bluetooth/BluetoothPan.java b/core/java/android/bluetooth/BluetoothPan.java index 7490f9ee86b4..5d9d8bea8e0c 100644 --- a/core/java/android/bluetooth/BluetoothPan.java +++ b/core/java/android/bluetooth/BluetoothPan.java @@ -139,6 +139,10 @@ public final class BluetoothPan implements BluetoothProfile { } } + /*package*/ void close() { + mServiceListener = null; + } + /** * Initiate connection to a profile of the remote bluetooth device. * @@ -299,4 +303,4 @@ public final class BluetoothPan implements BluetoothProfile { private static void log(String msg) { Log.d(TAG, msg); } -}
\ No newline at end of file +} diff --git a/core/java/android/bluetooth/BluetoothPbap.java b/core/java/android/bluetooth/BluetoothPbap.java index 4be077c0e7b9..2683befeecdf 100644 --- a/core/java/android/bluetooth/BluetoothPbap.java +++ b/core/java/android/bluetooth/BluetoothPbap.java @@ -69,7 +69,7 @@ public class BluetoothPbap { private IBluetoothPbap mService; private final Context mContext; - private final ServiceListener mServiceListener; + private ServiceListener mServiceListener; /** There was an error trying to obtain the state */ public static final int STATE_ERROR = -1; @@ -138,6 +138,7 @@ public class BluetoothPbap { mContext.unbindService(mConnection); mConnection = null; } + mServiceListener = null; } /** diff --git a/core/java/android/content/ContentUris.java b/core/java/android/content/ContentUris.java index aa7603470b06..dbe8a7c322ae 100644 --- a/core/java/android/content/ContentUris.java +++ b/core/java/android/content/ContentUris.java @@ -19,9 +19,54 @@ package android.content; import android.net.Uri; /** - * Utility methods useful for working with content {@link android.net.Uri}s, - * those with a "content" scheme. - */ +* Utility methods useful for working with {@link android.net.Uri} objects +* that use the "content" (content://) scheme. +* +*<p> +* Content URIs have the syntax +*</p> +*<p> +* <code>content://<em>authority</em>/<em>path</em>/<em>id</em></code> +*</p> +*<dl> +* <dt> +* <code>content:</code> +* </dt> +* <dd> +* The scheme portion of the URI. This is always set to {@link +* android.content.ContentResolver#SCHEME_CONTENT ContentResolver.SCHEME_CONTENT} (value +* <code>content://</code>). +* </dd> +* <dt> +* <em>authority</em> +* </dt> +* <dd> +* A string that identifies the entire content provider. All the content URIs for the provider +* start with this string. To guarantee a unique authority, providers should consider +* using an authority that is the same as the provider class' package identifier. +* </dd> +* <dt> +* <em>path</em> +* </dt> +* <dd> +* Zero or more segments, separated by a forward slash (<code>/</code>), that identify +* some subset of the provider's data. Most providers use the path part to identify +* individual tables. Individual segments in the path are often called +* "directories" although they do not refer to file directories. The right-most +* segment in a path is often called a "twig" +* </dd> +* <dt> +* <em>id</em> +* </dt> +* <dd> +* A unique numeric identifier for a single row in the subset of data identified by the +* preceding path part. Most providers recognize content URIs that contain an id part +* and give them special handling. A table that contains a column named <code>_ID</code> +* often expects the id part to be a particular value for that column. +* </dd> +*</dl> +* +*/ public class ContentUris { /** diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index 45a42e44f1cd..4e5598b3a0a1 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -2310,6 +2310,120 @@ public class Intent implements Parcelable, Cloneable { // --------------------------------------------------------------------- // --------------------------------------------------------------------- + // Application launch intent categories (see addCategory()). + + /** + * Used with {@link #ACTION_MAIN} to launch the browser application. + * The activity should be able to browse the Internet. + * <p>NOTE: This should not be used as the primary key of an Intent, + * since it will not result in the app launching with the correct + * action and category. Instead, use this with + * {@link #makeMainSelectorActivity(String, String) to generate a main + * Intent with this category in the selector.</p> + */ + @SdkConstant(SdkConstantType.INTENT_CATEGORY) + public static final String CATEGORY_APP_BROWSER = "android.intent.category.APP_BROWSER"; + + /** + * Used with {@link #ACTION_MAIN} to launch the calculator application. + * The activity should be able to perform standard arithmetic operations. + * <p>NOTE: This should not be used as the primary key of an Intent, + * since it will not result in the app launching with the correct + * action and category. Instead, use this with + * {@link #makeMainSelectorActivity(String, String) to generate a main + * Intent with this category in the selector.</p> + */ + @SdkConstant(SdkConstantType.INTENT_CATEGORY) + public static final String CATEGORY_APP_CALCULATOR = "android.intent.category.APP_CALCULATOR"; + + /** + * Used with {@link #ACTION_MAIN} to launch the calendar application. + * The activity should be able to view and manipulate calendar entries. + * <p>NOTE: This should not be used as the primary key of an Intent, + * since it will not result in the app launching with the correct + * action and category. Instead, use this with + * {@link #makeMainSelectorActivity(String, String) to generate a main + * Intent with this category in the selector.</p> + */ + @SdkConstant(SdkConstantType.INTENT_CATEGORY) + public static final String CATEGORY_APP_CALENDAR = "android.intent.category.APP_CALENDAR"; + + /** + * Used with {@link #ACTION_MAIN} to launch the contacts application. + * The activity should be able to view and manipulate address book entries. + * <p>NOTE: This should not be used as the primary key of an Intent, + * since it will not result in the app launching with the correct + * action and category. Instead, use this with + * {@link #makeMainSelectorActivity(String, String) to generate a main + * Intent with this category in the selector.</p> + */ + @SdkConstant(SdkConstantType.INTENT_CATEGORY) + public static final String CATEGORY_APP_CONTACTS = "android.intent.category.APP_CONTACTS"; + + /** + * Used with {@link #ACTION_MAIN} to launch the email application. + * The activity should be able to send and receive email. + * <p>NOTE: This should not be used as the primary key of an Intent, + * since it will not result in the app launching with the correct + * action and category. Instead, use this with + * {@link #makeMainSelectorActivity(String, String) to generate a main + * Intent with this category in the selector.</p> + */ + @SdkConstant(SdkConstantType.INTENT_CATEGORY) + public static final String CATEGORY_APP_EMAIL = "android.intent.category.APP_EMAIL"; + + /** + * Used with {@link #ACTION_MAIN} to launch the gallery application. + * The activity should be able to view and manipulate image and video files + * stored on the device. + * <p>NOTE: This should not be used as the primary key of an Intent, + * since it will not result in the app launching with the correct + * action and category. Instead, use this with + * {@link #makeMainSelectorActivity(String, String) to generate a main + * Intent with this category in the selector.</p> + */ + @SdkConstant(SdkConstantType.INTENT_CATEGORY) + public static final String CATEGORY_APP_GALLERY = "android.intent.category.APP_GALLERY"; + + /** + * Used with {@link #ACTION_MAIN} to launch the maps application. + * The activity should be able to show the user's current location and surroundings. + * <p>NOTE: This should not be used as the primary key of an Intent, + * since it will not result in the app launching with the correct + * action and category. Instead, use this with + * {@link #makeMainSelectorActivity(String, String) to generate a main + * Intent with this category in the selector.</p> + */ + @SdkConstant(SdkConstantType.INTENT_CATEGORY) + public static final String CATEGORY_APP_MAPS = "android.intent.category.APP_MAPS"; + + /** + * Used with {@link #ACTION_MAIN} to launch the messaging application. + * The activity should be able to send and receive text messages. + * <p>NOTE: This should not be used as the primary key of an Intent, + * since it will not result in the app launching with the correct + * action and category. Instead, use this with + * {@link #makeMainSelectorActivity(String, String) to generate a main + * Intent with this category in the selector.</p> + */ + @SdkConstant(SdkConstantType.INTENT_CATEGORY) + public static final String CATEGORY_APP_MESSAGING = "android.intent.category.APP_MESSAGING"; + + /** + * Used with {@link #ACTION_MAIN} to launch the music application. + * The activity should be able to play, browse, or manipulate music files + * stored on the device. + * <p>NOTE: This should not be used as the primary key of an Intent, + * since it will not result in the app launching with the correct + * action and category. Instead, use this with + * {@link #makeMainSelectorActivity(String, String) to generate a main + * Intent with this category in the selector.</p> + */ + @SdkConstant(SdkConstantType.INTENT_CATEGORY) + public static final String CATEGORY_APP_MUSIC = "android.intent.category.APP_MUSIC"; + + // --------------------------------------------------------------------- + // --------------------------------------------------------------------- // Standard extra data keys. /** @@ -2895,6 +3009,7 @@ public class Intent implements Parcelable, Cloneable { private HashSet<String> mCategories; private Bundle mExtras; private Rect mSourceBounds; + private Intent mSelector; // --------------------------------------------------------------------- @@ -2923,6 +3038,9 @@ public class Intent implements Parcelable, Cloneable { if (o.mSourceBounds != null) { this.mSourceBounds = new Rect(o.mSourceBounds); } + if (o.mSelector != null) { + this.mSelector = new Intent(o.mSelector); + } } @Override @@ -3063,6 +3181,39 @@ public class Intent implements Parcelable, Cloneable { } /** + * Make an Intent for the main activity of an application, without + * specifying a specific activity to run but giving a selector to find + * the activity. This results in a final Intent that is structured + * the same as when the application is launched from + * Home. For anything else that wants to launch an application in the + * same way, it is important that they use an Intent structured the same + * way, and can use this function to ensure this is the case. + * + * <p>The returned Intent has {@link #ACTION_MAIN} as its action, and includes the + * category {@link #CATEGORY_LAUNCHER}. This does <em>not</em> have + * {@link #FLAG_ACTIVITY_NEW_TASK} set, though typically you will want + * to do that through {@link #addFlags(int)} on the returned Intent. + * + * @param selectorAction The action name of the Intent's selector. + * @param selectorCategory The name of a category to add to the Intent's + * selector. + * @return Returns a newly created Intent that can be used to launch the + * activity as a main application entry. + * + * @see #setSelector(Intent) + */ + public static Intent makeMainSelectorActivity(String selectorAction, + String selectorCategory) { + Intent intent = new Intent(ACTION_MAIN); + intent.addCategory(CATEGORY_LAUNCHER); + Intent selector = new Intent(); + selector.setAction(selectorAction); + selector.addCategory(selectorCategory); + intent.setSelector(selector); + return intent; + } + + /** * Make an Intent that can be used to re-launch an application's task * in its base state. This is like {@link #makeMainActivity(ComponentName)}, * but also sets the flags {@link #FLAG_ACTIVITY_NEW_TASK} and @@ -3137,6 +3288,7 @@ public class Intent implements Parcelable, Cloneable { // new format Intent intent = new Intent(ACTION_VIEW); + Intent baseIntent = intent; // fetch data part, if present String data = i >= 0 ? uri.substring(0, i) : null; @@ -3146,8 +3298,9 @@ public class Intent implements Parcelable, Cloneable { // loop over contents of Intent, all name=value; while (!uri.startsWith("end", i)) { int eq = uri.indexOf('=', i); - int semi = uri.indexOf(';', eq); - String value = Uri.decode(uri.substring(eq + 1, semi)); + if (eq < 0) eq = i-1; + int semi = uri.indexOf(';', i); + String value = eq < semi ? Uri.decode(uri.substring(eq + 1, semi)) : ""; // action if (uri.startsWith("action=", i)) { @@ -3189,6 +3342,11 @@ public class Intent implements Parcelable, Cloneable { intent.mSourceBounds = Rect.unflattenFromString(value); } + // selector + else if (semi == (i+3) && uri.startsWith("SEL", i)) { + intent = new Intent(); + } + // extra else { String key = Uri.decode(uri.substring(i + 2, eq)); @@ -3212,6 +3370,12 @@ public class Intent implements Parcelable, Cloneable { i = semi + 1; } + if (intent != baseIntent) { + // The Intent had a selector; fix it up. + baseIntent.setSelector(intent); + intent = baseIntent; + } + if (data != null) { if (data.startsWith("intent:")) { data = data.substring(7); @@ -3537,7 +3701,7 @@ public class Intent implements Parcelable, Cloneable { * Return the set of all categories in the intent. If there are no categories, * returns NULL. * - * @return Set The set of categories you can examine. Do not modify! + * @return The set of categories you can examine. Do not modify! * * @see #hasCategory * @see #addCategory @@ -3547,6 +3711,16 @@ public class Intent implements Parcelable, Cloneable { } /** + * Return the specific selector associated with this Intent. If there is + * none, returns null. See {@link #setSelector} for more information. + * + * @see #setSelector + */ + public Intent getSelector() { + return mSelector; + } + + /** * Sets the ClassLoader that will be used when unmarshalling * any Parcelable values from the extras of this Intent. * @@ -4365,6 +4539,49 @@ public class Intent implements Parcelable, Cloneable { } /** + * Set a selector for this Intent. This is a modification to the kinds of + * things the Intent will match. If the selector is set, it will be used + * when trying to find entities that can handle the Intent, instead of the + * main contents of the Intent. This allows you build an Intent containing + * a generic protocol while targeting it more specifically. + * + * <p>An example of where this may be used is with things like + * {@link #CATEGORY_APP_BROWSER}. This category allows you to build an + * Intent that will launch the Browser application. However, the correct + * main entry point of an application is actually {@link #ACTION_MAIN} + * {@link #CATEGORY_LAUNCHER} with {@link #setComponent(ComponentName)} + * used to specify the actual Activity to launch. If you launch the browser + * with something different, undesired behavior may happen if the user has + * previously or later launches it the normal way, since they do not match. + * Instead, you can build an Intent with the MAIN action (but no ComponentName + * yet specified) and set a selector with {@link #ACTION_MAIN} and + * {@link #CATEGORY_APP_BROWSER} to point it specifically to the browser activity. + * + * <p>Setting a selector does not impact the behavior of + * {@link #filterEquals(Intent)} and {@link #filterHashCode()}. This is part of the + * desired behavior of a selector -- it does not impact the base meaning + * of the Intent, just what kinds of things will be matched against it + * when determining who can handle it.</p> + * + * <p>You can not use both a selector and {@link #setPackage(String)} on + * the same base Intent.</p> + * + * @param selector The desired selector Intent; set to null to not use + * a special selector. + */ + public void setSelector(Intent selector) { + if (selector == this) { + throw new IllegalArgumentException( + "Intent being set as a selector of itself"); + } + if (selector != null && mPackage != null) { + throw new IllegalArgumentException( + "Can't set selector when package name is already set"); + } + mSelector = selector; + } + + /** * Add extended data to the intent. The name must include a package * prefix, for example the app com.android.contacts would use names * like "com.android.contacts.ShowAll". @@ -5191,6 +5408,10 @@ public class Intent implements Parcelable, Cloneable { * @see #resolveActivity */ public Intent setPackage(String packageName) { + if (packageName != null && mSelector != null) { + throw new IllegalArgumentException( + "Can't set package name when selector is already set"); + } mPackage = packageName; return this; } @@ -5326,12 +5547,18 @@ public class Intent implements Parcelable, Cloneable { public static final int FILL_IN_PACKAGE = 1<<4; /** - * Use with {@link #fillIn} to allow the current package value to be + * Use with {@link #fillIn} to allow the current bounds rectangle to be * overwritten, even if it is already set. */ public static final int FILL_IN_SOURCE_BOUNDS = 1<<5; /** + * Use with {@link #fillIn} to allow the current selector to be + * overwritten, even if it is already set. + */ + public static final int FILL_IN_SELECTOR = 1<<6; + + /** * Copy the contents of <var>other</var> in to this object, but only * where fields are not defined by this object. For purposes of a field * being defined, the following pieces of data in the Intent are @@ -5351,11 +5578,13 @@ public class Intent implements Parcelable, Cloneable { * * <p>In addition, you can use the {@link #FILL_IN_ACTION}, * {@link #FILL_IN_DATA}, {@link #FILL_IN_CATEGORIES}, {@link #FILL_IN_PACKAGE}, - * and {@link #FILL_IN_COMPONENT} to override the restriction where the + * {@link #FILL_IN_COMPONENT}, {@link #FILL_IN_SOURCE_BOUNDS}, and + * {@link #FILL_IN_SELECTOR} to override the restriction where the * corresponding field will not be replaced if it is already set. * * <p>Note: The component field will only be copied if {@link #FILL_IN_COMPONENT} is explicitly - * specified. + * specified. The selector will only be copied if {@link #FILL_IN_SELECTOR} is + * explicitly specified. * * <p>For example, consider Intent A with {data="foo", categories="bar"} * and Intent B with {action="gotit", data-type="some/thing", @@ -5371,7 +5600,8 @@ public class Intent implements Parcelable, Cloneable { * * @return Returns a bit mask of {@link #FILL_IN_ACTION}, * {@link #FILL_IN_DATA}, {@link #FILL_IN_CATEGORIES}, {@link #FILL_IN_PACKAGE}, - * and {@link #FILL_IN_COMPONENT} indicating which fields were changed. + * {@link #FILL_IN_COMPONENT}, {@link #FILL_IN_SOURCE_BOUNDS}, and + * {@link #FILL_IN_SELECTOR} indicating which fields were changed. */ public int fillIn(Intent other, int flags) { int changes = 0; @@ -5396,8 +5626,20 @@ public class Intent implements Parcelable, Cloneable { } if (other.mPackage != null && (mPackage == null || (flags&FILL_IN_PACKAGE) != 0)) { - mPackage = other.mPackage; - changes |= FILL_IN_PACKAGE; + // Only do this if mSelector is not set. + if (mSelector == null) { + mPackage = other.mPackage; + changes |= FILL_IN_PACKAGE; + } + } + // Selector is special: it can only be set if explicitly allowed, + // for the same reason as the component name. + if (other.mSelector != null && (flags&FILL_IN_SELECTOR) != 0) { + if (mPackage == null) { + mSelector = new Intent(other.mSelector); + mPackage = null; + changes |= FILL_IN_SELECTOR; + } } // Component is special: it can -only- be set if explicitly allowed, // since otherwise the sender could force the intent somewhere the @@ -5695,6 +5937,11 @@ public class Intent implements Parcelable, Cloneable { first = false; b.append("(has extras)"); } + if (mSelector != null) { + b.append(" sel={"); + mSelector.toShortString(b, secure, comp, extras); + b.append("}"); + } } /** @@ -5755,6 +6002,21 @@ public class Intent implements Parcelable, Cloneable { uri.append("#Intent;"); + toUriInner(uri, scheme, flags); + if (mSelector != null) { + uri.append("SEL;"); + // Note that for now we are not going to try to handle the + // data part; not clear how to represent this as a URI, and + // not much utility in it. + mSelector.toUriInner(uri, null, flags); + } + + uri.append("end"); + + return uri.toString(); + } + + private void toUriInner(StringBuilder uri, String scheme, int flags) { if (scheme != null) { uri.append("scheme=").append(scheme).append(';'); } @@ -5809,10 +6071,6 @@ public class Intent implements Parcelable, Cloneable { } } } - - uri.append("end"); - - return uri.toString(); } public int describeContents() { @@ -5843,6 +6101,13 @@ public class Intent implements Parcelable, Cloneable { out.writeInt(0); } + if (mSelector != null) { + out.writeInt(1); + mSelector.writeToParcel(out, flags); + } else { + out.writeInt(0); + } + out.writeBundle(mExtras); } @@ -5884,6 +6149,10 @@ public class Intent implements Parcelable, Cloneable { mCategories = null; } + if (in.readInt() != 0) { + mSelector = new Intent(in); + } + mExtras = in.readBundle(); } diff --git a/core/java/android/content/SyncManager.java b/core/java/android/content/SyncManager.java index b2909b322057..3c4e54533699 100644 --- a/core/java/android/content/SyncManager.java +++ b/core/java/android/content/SyncManager.java @@ -24,6 +24,7 @@ import com.google.android.collect.Maps; import android.accounts.Account; import android.accounts.AccountManager; import android.accounts.OnAccountsUpdateListener; +import android.app.ActivityManager; import android.app.AlarmManager; import android.app.Notification; import android.app.NotificationManager; @@ -86,8 +87,13 @@ public class SyncManager implements OnAccountsUpdateListener { private static final long MAX_TIME_PER_SYNC; static { - MAX_SIMULTANEOUS_INITIALIZATION_SYNCS = SystemProperties.getInt("sync.max_init_syncs", 5); - MAX_SIMULTANEOUS_REGULAR_SYNCS = SystemProperties.getInt("sync.max_regular_syncs", 2); + final boolean isLargeRAM = ActivityManager.isLargeRAM(); + int defaultMaxInitSyncs = isLargeRAM ? 5 : 2; + int defaultMaxRegularSyncs = isLargeRAM ? 2 : 1; + MAX_SIMULTANEOUS_INITIALIZATION_SYNCS = + SystemProperties.getInt("sync.max_init_syncs", defaultMaxInitSyncs); + MAX_SIMULTANEOUS_REGULAR_SYNCS = + SystemProperties.getInt("sync.max_regular_syncs", defaultMaxRegularSyncs); LOCAL_SYNC_DELAY = SystemProperties.getLong("sync.local_sync_delay", 30 * 1000 /* 30 seconds */); MAX_TIME_PER_SYNC = diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java index c2a757f06808..7ca615504934 100644 --- a/core/java/android/hardware/Camera.java +++ b/core/java/android/hardware/Camera.java @@ -22,12 +22,9 @@ import android.graphics.ImageFormat; import android.graphics.Point; import android.graphics.Rect; import android.graphics.SurfaceTexture; -import android.media.AudioManager; -import android.media.MediaPlayer; import android.os.Handler; import android.os.Looper; import android.os.Message; -import android.os.SystemProperties; import android.util.Log; import android.view.Surface; import android.view.SurfaceHolder; @@ -157,7 +154,6 @@ public class Camera { private boolean mOneShot; private boolean mWithBuffer; private boolean mFaceDetectionRunning = false; - private boolean mReleased = false; /** * Broadcast Action: A new picture is taken by the camera, and the entry of @@ -322,15 +318,6 @@ public class Camera { public final void release() { native_release(); mFaceDetectionRunning = false; - if (mCameraSoundPlayers != null) { - for (CameraSoundPlayer csp: mCameraSoundPlayers) { - if (csp != null) { - csp.release(); - } - } - mCameraSoundPlayers = null; - } - mReleased = true; } /** @@ -2512,13 +2499,16 @@ public class Camera { /** * Sets the white balance. Changing the setting will release the - * auto-white balance lock. + * auto-white balance lock. It is recommended not to change white + * balance and AWB lock at the same time. * * @param value new white balance. * @see #getWhiteBalance() * @see #setAutoWhiteBalanceLock(boolean) */ public void setWhiteBalance(String value) { + String oldValue = get(KEY_WHITE_BALANCE); + if (same(value, oldValue)) return; set(KEY_WHITE_BALANCE, value); set(KEY_AUTO_WHITEBALANCE_LOCK, FALSE); } @@ -3493,195 +3483,11 @@ public class Camera { return result; } - }; - - /** - * <p>The set of default system sounds for camera actions. Use this with - * {@link #playSound} to play an appropriate sound when implementing a - * custom still or video recording mechanism through the preview - * callbacks.</p> - * - * <p>There is no need to play sounds when using {@link #takePicture} or - * {@link android.media.MediaRecorder} for still images or video, - * respectively, as these play their own sounds when needed.</p> - * - * @see #playSound - * @hide - */ - public static class Sound { - /** - * The sound used by {@link android.hardware.Camera#takePicture} to - * indicate still image capture. - */ - public static final int SHUTTER_CLICK = 0; - - /** - * A sound to indicate that focusing has completed. Because deciding - * when this occurs is application-dependent, this sound is not used by - * any methods in the Camera class. - */ - public static final int FOCUS_COMPLETE = 1; - - /** - * The sound used by {@link android.media.MediaRecorder#start} to - * indicate the start of video recording. - */ - public static final int START_VIDEO_RECORDING = 2; - - /** - * The sound used by {@link android.media.MediaRecorder#stop} to - * indicate the end of video recording. - */ - public static final int STOP_VIDEO_RECORDING = 3; - - private static final int NUM_SOUNDS = 4; - }; - - /** - * <p>Play one of the predefined platform sounds for camera actions.</p> - * - * <p>Use this method to play a platform-specific sound for various camera - * actions. The sound playing is done asynchronously, with the same behavior - * and content as the sounds played by {@link #takePicture takePicture}, - * {@link android.media.MediaRecorder#start MediaRecorder.start}, and - * {@link android.media.MediaRecorder#stop MediaRecorder.stop}.</p> - * - * <p>Using this method makes it easy to match the default device sounds - * when recording or capturing data through the preview callbacks - * ({@link #setPreviewCallback setPreviewCallback}, - * {@link #setPreviewTexture setPreviewTexture}).</p> - * - * @param soundId The type of sound to play, selected from the options in - * {@link android.hardware.Camera.Sound} - * @see android.hardware.Camera.Sound - * @see #takePicture - * @see android.media.MediaRecorder - * @hide - */ - public void playSound(int soundId) { - if (mReleased) return; - if (mCameraSoundPlayers == null) { - mCameraSoundPlayers = new CameraSoundPlayer[Sound.NUM_SOUNDS]; - } - if (mCameraSoundPlayers[soundId] == null) { - mCameraSoundPlayers[soundId] = new CameraSoundPlayer(soundId); - } - mCameraSoundPlayers[soundId].play(); - } - - private CameraSoundPlayer[] mCameraSoundPlayers; - - private static class CameraSoundPlayer implements Runnable { - private int mSoundId; - private int mAudioStreamType; - private MediaPlayer mPlayer; - private Thread mThread; - private boolean mExit; - private int mPlayCount; - - private static final String mShutterSound = - "/system/media/audio/ui/camera_click.ogg"; - private static final String mFocusSound = - "/system/media/audio/ui/camera_focus.ogg"; - private static final String mVideoStartSound = - "/system/media/audio/ui/VideoRecord.ogg"; - private static final String mVideoStopSound = - "/system/media/audio/ui/VideoRecord.ogg"; - - @Override - public void run() { - String soundFilePath; - switch (mSoundId) { - case Sound.SHUTTER_CLICK: - soundFilePath = mShutterSound; - break; - case Sound.FOCUS_COMPLETE: - soundFilePath = mFocusSound; - break; - case Sound.START_VIDEO_RECORDING: - soundFilePath = mVideoStartSound; - break; - case Sound.STOP_VIDEO_RECORDING: - soundFilePath = mVideoStopSound; - break; - default: - Log.e(TAG, "Unknown sound " + mSoundId + " requested."); - return; - } - mPlayer = new MediaPlayer(); - try { - mPlayer.setAudioStreamType(mAudioStreamType); - mPlayer.setDataSource(soundFilePath); - mPlayer.setLooping(false); - mPlayer.prepare(); - } catch(IOException e) { - Log.e(TAG, "Error setting up sound " + mSoundId, e); - return; - } - - while(true) { - try { - synchronized (this) { - while(true) { - if (mExit) { - return; - } else if (mPlayCount <= 0) { - wait(); - } else { - mPlayCount--; - break; - } - } - } - mPlayer.start(); - } catch (Exception e) { - Log.e(TAG, "Error playing sound " + mSoundId, e); - } - } - } - - public CameraSoundPlayer(int soundId) { - mSoundId = soundId; - if (SystemProperties.get("ro.camera.sound.forced", "0").equals("0")) { - mAudioStreamType = AudioManager.STREAM_MUSIC; - } else { - mAudioStreamType = AudioManager.STREAM_SYSTEM_ENFORCED; - } - } - public void play() { - if (mThread == null) { - mThread = new Thread(this); - mThread.start(); - } - synchronized (this) { - mPlayCount++; - notifyAll(); - } + private boolean same(String s1, String s2) { + if (s1 == null && s2 == null) return true; + if (s1 != null && s1.equals(s2)) return true; + return false; } - - public void release() { - if (mThread != null) { - synchronized (this) { - mExit = true; - notifyAll(); - } - try { - mThread.join(); - } catch (InterruptedException e) { - } - mThread = null; - } - if (mPlayer != null) { - mPlayer.release(); - mPlayer = null; - } - } - - @Override - protected void finalize() { - release(); - } - } - + }; } diff --git a/core/java/android/hardware/CameraSound.java b/core/java/android/hardware/CameraSound.java new file mode 100644 index 000000000000..32de0cde5918 --- /dev/null +++ b/core/java/android/hardware/CameraSound.java @@ -0,0 +1,223 @@ +/* + * Copyright (C) 2011 The Android Open 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; + +import android.media.AudioManager; +import android.media.MediaPlayer; +import android.os.SystemProperties; +import android.util.Log; + +import java.io.IOException; + +/** + * <p>Use this class to play an appropriate sound when implementing a custom + * still or video recording mechanism through the preview callbacks.</p> + * + * <p>There is no need to play sounds when using {@link #android.hardware.Camera#takePicture} + * or {@link android.media.MediaRecorder} for still images or video, + * respectively, as these play their own sounds when needed.</p> + * + * @hide + */ +public class CameraSound { + private static final String TAG = "CameraSound"; + /** + * The sound used by {@link android.hardware.Camera#takePicture} to + * indicate still image capture. + */ + public static final int SHUTTER_CLICK = 0; + + /** + * A sound to indicate that focusing has completed. Because deciding + * when this occurs is application-dependent, this sound is not used by + * any methods in the Camera class. + */ + public static final int FOCUS_COMPLETE = 1; + + /** + * The sound used by {@link android.media.MediaRecorder#start} to + * indicate the start of video recording. + */ + public static final int START_VIDEO_RECORDING = 2; + + /** + * The sound used by {@link android.media.MediaRecorder#stop} to + * indicate the end of video recording. + */ + public static final int STOP_VIDEO_RECORDING = 3; + + private static final int NUM_SOUNDS = 4; + private CameraSoundPlayer[] mCameraSoundPlayers; + + public CameraSound() { + } + + /** + * <p>Play one of the predefined platform sounds for camera actions.</p> + * + * <p>Use this method to play a platform-specific sound for various camera + * actions. The sound playing is done asynchronously, with the same behavior + * and content as the sounds played by {@link #takePicture takePicture}, + * {@link android.media.MediaRecorder#start MediaRecorder.start}, and + * {@link android.media.MediaRecorder#stop MediaRecorder.stop}.</p> + * + * <p>Using this method makes it easy to match the default device sounds + * when recording or capturing data through the preview callbacks.</p> + * + * @param soundId The type of sound to play, selected from SHUTTER_CLICK, + * FOCUS_COMPLETE, START_VIDEO_RECORDING, or STOP_VIDEO_RECORDING. + * @see android.hardware#takePicture + * @see android.media.MediaRecorder + * @see #SHUTTER_CLICK + * @see #FOCUS_COMPLETE + * @see #START_VIDEO_RECORDING + * @see #STOP_VIDEO_RECORDING + */ + public void playSound(int soundId) { + if (mCameraSoundPlayers == null) { + mCameraSoundPlayers = new CameraSoundPlayer[NUM_SOUNDS]; + } + if (mCameraSoundPlayers[soundId] == null) { + mCameraSoundPlayers[soundId] = new CameraSoundPlayer(soundId); + } + mCameraSoundPlayers[soundId].play(); + } + + public void release() { + if (mCameraSoundPlayers != null) { + for (CameraSoundPlayer csp: mCameraSoundPlayers) { + if (csp != null) { + csp.release(); + } + } + mCameraSoundPlayers = null; + } + } + + private static class CameraSoundPlayer implements Runnable { + private int mSoundId; + private int mAudioStreamType; + private MediaPlayer mPlayer; + private Thread mThread; + private boolean mExit; + private int mPlayCount; + + private static final String mShutterSound = + "/system/media/audio/ui/camera_click.ogg"; + private static final String mFocusSound = + "/system/media/audio/ui/camera_focus.ogg"; + private static final String mVideoStartSound = + "/system/media/audio/ui/VideoRecord.ogg"; + private static final String mVideoStopSound = + "/system/media/audio/ui/VideoRecord.ogg"; + + @Override + public void run() { + String soundFilePath; + switch (mSoundId) { + case SHUTTER_CLICK: + soundFilePath = mShutterSound; + break; + case FOCUS_COMPLETE: + soundFilePath = mFocusSound; + break; + case START_VIDEO_RECORDING: + soundFilePath = mVideoStartSound; + break; + case STOP_VIDEO_RECORDING: + soundFilePath = mVideoStopSound; + break; + default: + Log.e(TAG, "Unknown sound " + mSoundId + " requested."); + return; + } + mPlayer = new MediaPlayer(); + try { + mPlayer.setAudioStreamType(mAudioStreamType); + mPlayer.setDataSource(soundFilePath); + mPlayer.setLooping(false); + mPlayer.prepare(); + } catch(IOException e) { + Log.e(TAG, "Error setting up sound " + mSoundId, e); + return; + } + + while(true) { + try { + synchronized (this) { + while(true) { + if (mExit) { + return; + } else if (mPlayCount <= 0) { + wait(); + } else { + mPlayCount--; + break; + } + } + } + mPlayer.start(); + } catch (Exception e) { + Log.e(TAG, "Error playing sound " + mSoundId, e); + } + } + } + + public CameraSoundPlayer(int soundId) { + mSoundId = soundId; + if (SystemProperties.get("ro.camera.sound.forced", "0").equals("0")) { + mAudioStreamType = AudioManager.STREAM_MUSIC; + } else { + mAudioStreamType = AudioManager.STREAM_SYSTEM_ENFORCED; + } + } + + public void play() { + if (mThread == null) { + mThread = new Thread(this); + mThread.start(); + } + synchronized (this) { + mPlayCount++; + notifyAll(); + } + } + + public void release() { + if (mThread != null) { + synchronized (this) { + mExit = true; + notifyAll(); + } + try { + mThread.join(); + } catch (InterruptedException e) { + } + mThread = null; + } + if (mPlayer != null) { + mPlayer.release(); + mPlayer = null; + } + } + + @Override + protected void finalize() { + release(); + } + } +}
\ No newline at end of file diff --git a/core/java/android/inputmethodservice/ExtractEditText.java b/core/java/android/inputmethodservice/ExtractEditText.java index 4fc63ed2d917..10c11958610b 100644 --- a/core/java/android/inputmethodservice/ExtractEditText.java +++ b/core/java/android/inputmethodservice/ExtractEditText.java @@ -156,4 +156,48 @@ public class ExtractEditText extends EditText { mIME.onViewClicked(false); } } + + /** + * {@inheritDoc} + * @hide + */ + @Override + protected void deleteText_internal(int start, int end) { + // Do not call the super method. + // This will change the source TextView instead, which will update the ExtractTextView. + mIME.onExtractedDeleteText(start, end); + } + + /** + * {@inheritDoc} + * @hide + */ + @Override + protected void replaceText_internal(int start, int end, CharSequence text) { + // Do not call the super method. + // This will change the source TextView instead, which will update the ExtractTextView. + mIME.onExtractedReplaceText(start, end, text); + } + + /** + * {@inheritDoc} + * @hide + */ + @Override + protected void setSpan_internal(Object span, int start, int end, int flags) { + // Do not call the super method. + // This will change the source TextView instead, which will update the ExtractTextView. + mIME.onExtractedSetSpan(span, start, end, flags); + } + + /** + * {@inheritDoc} + * @hide + */ + @Override + protected void setCursorPosition_internal(int start, int end) { + // Do not call the super method. + // This will change the source TextView instead, which will update the ExtractTextView. + mIME.onExtractedSelectionChanged(start, end); + } } diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java index 60188eab2250..53cdf2146011 100644 --- a/core/java/android/inputmethodservice/InputMethodService.java +++ b/core/java/android/inputmethodservice/InputMethodService.java @@ -1982,7 +1982,45 @@ public class InputMethodService extends AbstractInputMethodService { conn.setSelection(start, end); } } - + + /** + * @hide + */ + public void onExtractedDeleteText(int start, int end) { + InputConnection conn = getCurrentInputConnection(); + if (conn != null) { + conn.setSelection(start, start); + conn.deleteSurroundingText(0, end-start); + } + } + + /** + * @hide + */ + public void onExtractedReplaceText(int start, int end, CharSequence text) { + InputConnection conn = getCurrentInputConnection(); + if (conn != null) { + conn.setComposingRegion(start, end); + conn.commitText(text, 1); + } + } + + /** + * @hide + */ + public void onExtractedSetSpan(Object span, int start, int end, int flags) { + InputConnection conn = getCurrentInputConnection(); + if (conn != null) { + if (!conn.setSelection(start, end)) return; + CharSequence text = conn.getSelectedText(InputConnection.GET_TEXT_WITH_STYLES); + if (text instanceof Spannable) { + ((Spannable) text).setSpan(span, 0, text.length(), flags); + conn.setComposingRegion(start, end); + conn.commitText(text, 1); + } + } + } + /** * This is called when the user has clicked on the extracted text view, * when running in fullscreen mode. The default implementation hides @@ -1998,7 +2036,7 @@ public class InputMethodService extends AbstractInputMethodService { setCandidatesViewShown(false); } } - + /** * This is called when the user has performed a cursor movement in the * extracted text view, when it is running in fullscreen mode. The default diff --git a/core/java/android/inputmethodservice/KeyboardView.java b/core/java/android/inputmethodservice/KeyboardView.java index 5143f7f4712b..72575217fbd2 100644 --- a/core/java/android/inputmethodservice/KeyboardView.java +++ b/core/java/android/inputmethodservice/KeyboardView.java @@ -31,6 +31,7 @@ import android.inputmethodservice.Keyboard.Key; import android.media.AudioManager; import android.os.Handler; import android.os.Message; +import android.provider.Settings; import android.util.AttributeSet; import android.util.TypedValue; import android.view.GestureDetector; @@ -967,8 +968,13 @@ public class KeyboardView extends View implements View.OnClickListener { AccessibilityEvent event = AccessibilityEvent.obtain(eventType); onInitializeAccessibilityEvent(event); String text = null; - // Add text only if headset is used to avoid leaking passwords. - if (mAudioManager.isBluetoothA2dpOn() || mAudioManager.isWiredHeadsetOn()) { + // This is very efficient since the properties are cached. + final boolean speakPassword = Settings.Secure.getInt(mContext.getContentResolver(), + Settings.Secure.ACCESSIBILITY_SPEAK_PASSWORD, 0) != 0; + // Add text only if password announcement is enabled or if headset is + // used to avoid leaking passwords. + if (speakPassword || mAudioManager.isBluetoothA2dpOn() + || mAudioManager.isWiredHeadsetOn()) { switch (code) { case Keyboard.KEYCODE_ALT: text = mContext.getString(R.string.keyboardview_keycode_alt); diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java index e289fc15d0bb..d39e741efddc 100644 --- a/core/java/android/net/NetworkUtils.java +++ b/core/java/android/net/NetworkUtils.java @@ -250,4 +250,32 @@ public class NetworkUtils { } return result; } + + /** + * Trim leading zeros from IPv4 address strings + * Our base libraries will interpret that as octel.. + * Must leave non v4 addresses and host names alone. + * For example, 192.168.000.010 -> 192.168.0.10 + * TODO - fix base libraries and remove this function + * @param addr a string representing an ip addr + * @return a string propertly trimmed + */ + public static String trimV4AddrZeros(String addr) { + if (addr == null) return null; + String[] octets = addr.split("\\."); + if (octets.length != 4) return addr; + StringBuilder builder = new StringBuilder(16); + String result = null; + for (int i = 0; i < 4; i++) { + try { + if (octets[i].length() > 3) return addr; + builder.append(Integer.parseInt(octets[i])); + } catch (NumberFormatException e) { + return addr; + } + if (i < 3) builder.append('.'); + } + result = builder.toString(); + return result; + } } diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java index 7d034940fda2..88fea910395c 100644 --- a/core/java/android/os/Build.java +++ b/core/java/android/os/Build.java @@ -311,7 +311,7 @@ public class Build { public static final int ICE_CREAM_SANDWICH = 14; /** - * Android 4.1. + * Android 4.0.3. */ public static final int ICE_CREAM_SANDWICH_MR1 = 15; } diff --git a/core/java/android/os/IBinder.java b/core/java/android/os/IBinder.java index 81defd690af8..0586d9ed1eeb 100644 --- a/core/java/android/os/IBinder.java +++ b/core/java/android/os/IBinder.java @@ -128,6 +128,19 @@ public interface IBinder { int TWEET_TRANSACTION = ('_'<<24)|('T'<<16)|('W'<<8)|'T'; /** + * IBinder protocol transaction code: tell an app asynchronously that the + * caller likes it. The app is responsible for incrementing and maintaining + * its own like counter, and may display this value to the user to indicate the + * quality of the app. This is an optional command that applications do not + * need to handle, so the default implementation is to do nothing. + * + * <p>There is no response returned and nothing about the + * system will be functionally affected by it, but it will improve the + * app's self-esteem. + */ + int LIKE_TRANSACTION = ('_'<<24)|('L'<<16)|('I'<<8)|'K'; + + /** * Flag to {@link #transact}: this is a one-way call, meaning that the * caller returns immediately, without waiting for a result from the * callee. Applies only if the caller and callee are in different diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java index 33625755408c..e1bc275bc6f2 100644 --- a/core/java/android/os/Process.java +++ b/core/java/android/os/Process.java @@ -101,7 +101,7 @@ public class Process { * Defines the UID/GID for the NFC service process. * @hide */ - public static final int NFC_UID = 1025; + public static final int NFC_UID = 1027; /** * Defines the GID for the group that allows write access to the internal media storage. diff --git a/core/java/android/os/storage/package.html b/core/java/android/os/storage/package.html new file mode 100644 index 000000000000..a5f1e1c1e019 --- /dev/null +++ b/core/java/android/os/storage/package.html @@ -0,0 +1,8 @@ +<HTML> +<BODY> +<p> +Contains classes for the system storage service, which manages binary asset filesystems +known as Opaque Binary Blobs (OBBs). +</p> +</BODY> +</HTML> diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java index 5f111eb8e73c..4e016723eba3 100644 --- a/core/java/android/provider/MediaStore.java +++ b/core/java/android/provider/MediaStore.java @@ -40,8 +40,6 @@ import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.io.UnsupportedEncodingException; -import java.text.Collator; /** * The Media provider contains meta data for all available media on both internal @@ -66,7 +64,10 @@ public final class MediaStore { /** * Activity Action: Launch a music player. * The activity should be able to play, browse, or manipulate music files stored on the device. + * + * @deprecated Use {@link android.content.Intent#CATEGORY_APP_MUSIC} instead. */ + @Deprecated @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String INTENT_ACTION_MUSIC_PLAYER = "android.intent.action.MUSIC_PLAYER"; diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index b0321694c675..65b4e7ef4d96 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -2754,6 +2754,11 @@ public final class Settings { "enabled_accessibility_services"; /** + * Whether to speak passwords while in accessibility mode. + */ + public static final String ACCESSIBILITY_SPEAK_PASSWORD = "speak_password"; + + /** * If injection of accessibility enhancing JavaScript scripts * is enabled. * <p> @@ -3107,6 +3112,14 @@ public final class Settings { "wifi_watchdog_blacklist_followup_interval_ms"; /** + * Setting to turn off poor network avoidance on Wi-Fi. Feature is disabled by default and + * the setting needs to be set to 1 to enable it. + * @hide + */ + public static final String WIFI_WATCHDOG_POOR_NETWORK_TEST_ENABLED = + "wifi_watchdog_poor_network_test_enabled"; + + /** * Setting to turn off walled garden test on Wi-Fi. Feature is enabled by default and * the setting needs to be set to 0 to disable it. * @hide @@ -4019,23 +4032,6 @@ public final class Settings { public static final String SETUP_PREPAID_DETECTION_REDIR_HOST = "setup_prepaid_detection_redir_host"; - /** - * The user's preferred "dream" (interactive screensaver) component. - * - * This component will be launched by the PhoneWindowManager after the user's chosen idle - * timeout (specified by {@link #DREAM_TIMEOUT}). - * @hide - */ - public static final String DREAM_COMPONENT = - "dream_component"; - - /** - * The delay before a "dream" is started (set to 0 to disable). - * @hide - */ - public static final String DREAM_TIMEOUT = - "dream_timeout"; - /** {@hide} */ public static final String NETSTATS_ENABLED = "netstats_enabled"; /** {@hide} */ @@ -4096,6 +4092,7 @@ public final class Settings { ENABLED_ACCESSIBILITY_SERVICES, TOUCH_EXPLORATION_ENABLED, ACCESSIBILITY_ENABLED, + ACCESSIBILITY_SPEAK_PASSWORD, TTS_USE_DEFAULTS, TTS_DEFAULT_RATE, TTS_DEFAULT_PITCH, diff --git a/core/java/android/server/BluetoothAdapterStateMachine.java b/core/java/android/server/BluetoothAdapterStateMachine.java index da7c489960a4..f3f4174c57d1 100644 --- a/core/java/android/server/BluetoothAdapterStateMachine.java +++ b/core/java/android/server/BluetoothAdapterStateMachine.java @@ -175,8 +175,8 @@ final class BluetoothAdapterStateMachine extends StateMachine { switch(message.what) { case USER_TURN_ON: // starts turning on BT module, broadcast this out - transitionTo(mWarmUp); broadcastState(BluetoothAdapter.STATE_TURNING_ON); + transitionTo(mWarmUp); if (prepareBluetooth()) { // this is user request, save the setting if ((Boolean) message.obj) { @@ -198,8 +198,8 @@ final class BluetoothAdapterStateMachine extends StateMachine { case AIRPLANE_MODE_OFF: if (getBluetoothPersistedSetting()) { // starts turning on BT module, broadcast this out - transitionTo(mWarmUp); broadcastState(BluetoothAdapter.STATE_TURNING_ON); + transitionTo(mWarmUp); if (prepareBluetooth()) { // We will continue turn the BT on all the way to the BluetoothOn state deferMessage(obtainMessage(TURN_ON_CONTINUE)); @@ -355,9 +355,9 @@ final class BluetoothAdapterStateMachine extends StateMachine { // let it fall to TURN_ON_CONTINUE: //$FALL-THROUGH$ case TURN_ON_CONTINUE: + broadcastState(BluetoothAdapter.STATE_TURNING_ON); mBluetoothService.switchConnectable(true); transitionTo(mSwitching); - broadcastState(BluetoothAdapter.STATE_TURNING_ON); break; case AIRPLANE_MODE_ON: case TURN_COLD: @@ -367,9 +367,9 @@ final class BluetoothAdapterStateMachine extends StateMachine { break; case AIRPLANE_MODE_OFF: if (getBluetoothPersistedSetting()) { + broadcastState(BluetoothAdapter.STATE_TURNING_ON); transitionTo(mSwitching); mBluetoothService.switchConnectable(true); - broadcastState(BluetoothAdapter.STATE_TURNING_ON); } break; case PER_PROCESS_TURN_ON: @@ -515,8 +515,8 @@ final class BluetoothAdapterStateMachine extends StateMachine { } //$FALL-THROUGH$ to AIRPLANE_MODE_ON case AIRPLANE_MODE_ON: - transitionTo(mSwitching); broadcastState(BluetoothAdapter.STATE_TURNING_OFF); + transitionTo(mSwitching); if (mBluetoothService.getAdapterConnectionState() != BluetoothAdapter.STATE_DISCONNECTED) { mBluetoothService.disconnectDevices(); diff --git a/core/java/android/server/BluetoothService.java b/core/java/android/server/BluetoothService.java index 28e231e9d2a8..94fbbc8d33e2 100755 --- a/core/java/android/server/BluetoothService.java +++ b/core/java/android/server/BluetoothService.java @@ -145,7 +145,12 @@ public class BluetoothService extends IBluetooth.Stub { private final ArrayList<String> mUuidIntentTracker; private final HashMap<RemoteService, IBluetoothCallback> mUuidCallbackTracker; - private final HashMap<Integer, Pair<Integer, IBinder>> mServiceRecordToPid; + private static class ServiceRecordClient { + int pid; + IBinder binder; + IBinder.DeathRecipient death; + } + private final HashMap<Integer, ServiceRecordClient> mServiceRecordToPid; private final HashMap<String, BluetoothDeviceProfileState> mDeviceProfileState; private final BluetoothProfileState mA2dpProfileState; @@ -221,7 +226,7 @@ public class BluetoothService extends IBluetooth.Stub { mDeviceOobData = new HashMap<String, Pair<byte[], byte[]>>(); mUuidIntentTracker = new ArrayList<String>(); mUuidCallbackTracker = new HashMap<RemoteService, IBluetoothCallback>(); - mServiceRecordToPid = new HashMap<Integer, Pair<Integer, IBinder>>(); + mServiceRecordToPid = new HashMap<Integer, ServiceRecordClient>(); mDeviceProfileState = new HashMap<String, BluetoothDeviceProfileState>(); mA2dpProfileState = new BluetoothProfileState(mContext, BluetoothProfileState.A2DP); mHfpProfileState = new BluetoothProfileState(mContext, BluetoothProfileState.HFP); @@ -1528,11 +1533,17 @@ public class BluetoothService extends IBluetooth.Stub { return -1; } - int pid = Binder.getCallingPid(); - mServiceRecordToPid.put(new Integer(handle), new Pair<Integer, IBinder>(pid, b)); + ServiceRecordClient client = new ServiceRecordClient(); + client.pid = Binder.getCallingPid(); + client.binder = b; + client.death = new Reaper(handle, client.pid, RFCOMM_RECORD_REAPER); + mServiceRecordToPid.put(new Integer(handle), client); try { - b.linkToDeath(new Reaper(handle, pid, RFCOMM_RECORD_REAPER), 0); - } catch (RemoteException e) {Log.e(TAG, "", e);} + b.linkToDeath(client.death, 0); + } catch (RemoteException e) { + Log.e(TAG, "", e); + client.death = null; + } return handle; } @@ -1547,10 +1558,15 @@ public class BluetoothService extends IBluetooth.Stub { } private synchronized void checkAndRemoveRecord(int handle, int pid) { - Pair<Integer, IBinder> pidPair = mServiceRecordToPid.get(handle); - if (pidPair != null && pid == pidPair.first) { + ServiceRecordClient client = mServiceRecordToPid.get(handle); + if (client != null && pid == client.pid) { if (DBG) Log.d(TAG, "Removing service record " + Integer.toHexString(handle) + " for pid " + pid); + + if (client.death != null) { + client.binder.unlinkToDeath(client.death, 0); + } + mServiceRecordToPid.remove(handle); removeServiceRecordNative(handle); } @@ -1880,7 +1896,7 @@ public class BluetoothService extends IBluetooth.Stub { private void dumpApplicationServiceRecords(PrintWriter pw) { pw.println("\n--Application Service Records--"); for (Integer handle : mServiceRecordToPid.keySet()) { - Integer pid = mServiceRecordToPid.get(handle).first; + Integer pid = mServiceRecordToPid.get(handle).pid; pw.println("\tpid " + pid + " handle " + Integer.toHexString(handle)); } } @@ -2374,16 +2390,18 @@ public class BluetoothService extends IBluetooth.Stub { } BluetoothDeviceProfileState addProfileState(String address, boolean setTrust) { - BluetoothDeviceProfileState state = mDeviceProfileState.get(address); - if (state != null) return state; - - state = new BluetoothDeviceProfileState(mContext, address, this, mA2dpService, setTrust); + BluetoothDeviceProfileState state = + new BluetoothDeviceProfileState(mContext, address, this, mA2dpService, setTrust); mDeviceProfileState.put(address, state); state.start(); return state; } void removeProfileState(String address) { + BluetoothDeviceProfileState state = mDeviceProfileState.get(address); + if (state == null) return; + + state.quit(); mDeviceProfileState.remove(address); } diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java index a9a628a59a2e..18167b601d32 100644 --- a/core/java/android/service/wallpaper/WallpaperService.java +++ b/core/java/android/service/wallpaper/WallpaperService.java @@ -608,7 +608,7 @@ public abstract class WallpaperService extends Service { final int relayoutResult = mSession.relayout( mWindow, mWindow.mSeq, mLayout, mWidth, mHeight, - View.VISIBLE, false, mWinFrame, mContentInsets, + View.VISIBLE, 0, mWinFrame, mContentInsets, mVisibleInsets, mConfiguration, mSurfaceHolder.mSurface); if (DEBUG) Log.v(TAG, "New surface: " + mSurfaceHolder.mSurface @@ -654,7 +654,7 @@ public abstract class WallpaperService extends Service { } redrawNeeded |= creating - || (relayoutResult&WindowManagerImpl.RELAYOUT_FIRST_TIME) != 0; + || (relayoutResult&WindowManagerImpl.RELAYOUT_RES_FIRST_TIME) != 0; if (forceReport || creating || surfaceCreating || formatChanged || sizeChanged) { diff --git a/core/java/android/speech/tts/AudioPlaybackHandler.java b/core/java/android/speech/tts/AudioPlaybackHandler.java index 0194240adc29..46a78dc0d58a 100644 --- a/core/java/android/speech/tts/AudioPlaybackHandler.java +++ b/core/java/android/speech/tts/AudioPlaybackHandler.java @@ -118,12 +118,26 @@ class AudioPlaybackHandler { if (current != null && TextUtils.equals(callingApp, current.getCallingApp())) { stop(current); } + + final MessageParams lastSynthesis = mLastSynthesisRequest; + + if (lastSynthesis != null && lastSynthesis != current && + TextUtils.equals(callingApp, lastSynthesis.getCallingApp())) { + stop(lastSynthesis); + } } synchronized public void removeAllItems() { if (DBG_THREADING) Log.d(TAG, "Removing all items"); removeAllMessages(); - stop(getCurrentParams()); + + final MessageParams current = getCurrentParams(); + final MessageParams lastSynthesis = mLastSynthesisRequest; + stop(current); + + if (lastSynthesis != null && lastSynthesis != current) { + stop(lastSynthesis); + } } /** @@ -350,7 +364,7 @@ class AudioPlaybackHandler { // extra trouble to clean the data to prevent the AudioTrack resources // from being leaked. if (mLastSynthesisRequest != null) { - Log.w(TAG, "Error : Missing call to done() for request : " + + Log.e(TAG, "Error : Missing call to done() for request : " + mLastSynthesisRequest); handleSynthesisDone(mLastSynthesisRequest); } @@ -414,7 +428,8 @@ class AudioPlaybackHandler { final AudioTrack audioTrack = params.getAudioTrack(); if (audioTrack == null) { - params.getDispatcher().dispatchOnError(); + // There was already a call to handleSynthesisDone for + // this token. return; } @@ -443,7 +458,11 @@ class AudioPlaybackHandler { audioTrack.release(); params.setAudioTrack(null); } - params.getDispatcher().dispatchOnDone(); + if (params.isError()) { + params.getDispatcher().dispatchOnError(); + } else { + params.getDispatcher().dispatchOnDone(); + } mLastSynthesisRequest = null; params.mLogger.onWriteData(); } diff --git a/core/java/android/speech/tts/PlaybackSynthesisCallback.java b/core/java/android/speech/tts/PlaybackSynthesisCallback.java index ce3522be2d86..91a3452916cb 100644 --- a/core/java/android/speech/tts/PlaybackSynthesisCallback.java +++ b/core/java/android/speech/tts/PlaybackSynthesisCallback.java @@ -80,27 +80,23 @@ class PlaybackSynthesisCallback extends AbstractSynthesisCallback { @Override void stop() { + stopImpl(false); + } + + void stopImpl(boolean wasError) { if (DBG) Log.d(TAG, "stop()"); // Note that mLogger.mError might be true too at this point. mLogger.onStopped(); - SynthesisMessageParams token = null; + SynthesisMessageParams token; synchronized (mStateLock) { if (mStopped) { Log.w(TAG, "stop() called twice"); return; } - // mToken will be null if the engine encounters - // an error before it called start(). - if (mToken == null) { - // In all other cases, mAudioTrackHandler.stop() will - // result in onComplete being called. - mLogger.onWriteData(); - } else { - token = mToken; - } + token = mToken; mStopped = true; } @@ -109,7 +105,24 @@ class PlaybackSynthesisCallback extends AbstractSynthesisCallback { // point it will write an additional buffer to the token - but we // won't worry about that because the audio playback queue will be cleared // soon after (see SynthHandler#stop(String). + token.setIsError(wasError); token.clearBuffers(); + if (wasError) { + // Also clean up the audio track if an error occurs. + mAudioTrackHandler.enqueueSynthesisDone(token); + } + } else { + // This happens when stop() or error() were called before start() was. + + // In all other cases, mAudioTrackHandler.stop() will + // result in onSynthesisDone being called, and we will + // write data there. + mLogger.onWriteData(); + + if (wasError) { + // We have to dispatch the error ourselves. + mDispatcher.dispatchOnError(); + } } } @@ -219,7 +232,7 @@ class PlaybackSynthesisCallback extends AbstractSynthesisCallback { // Currently, this call will not be logged if error( ) is called // before start. mLogger.onError(); - stop(); + stopImpl(true); } } diff --git a/core/java/android/speech/tts/SynthesisMessageParams.java b/core/java/android/speech/tts/SynthesisMessageParams.java index 0c0f033fa066..ed66420df499 100644 --- a/core/java/android/speech/tts/SynthesisMessageParams.java +++ b/core/java/android/speech/tts/SynthesisMessageParams.java @@ -51,6 +51,7 @@ final class SynthesisMessageParams extends MessageParams { int mAudioBufferSize; // Always synchronized on "this". int mUnconsumedBytes; + volatile boolean mIsError; private final LinkedList<ListEntry> mDataBufferList = new LinkedList<ListEntry>(); @@ -74,6 +75,7 @@ final class SynthesisMessageParams extends MessageParams { mAudioTrack = null; mBytesWritten = 0; mAudioBufferSize = 0; + mIsError = false; } @Override @@ -120,6 +122,14 @@ final class SynthesisMessageParams extends MessageParams { return mAudioTrack; } + void setIsError(boolean isError) { + mIsError = isError; + } + + boolean isError() { + return mIsError; + } + // Must be called synchronized on this. private long getUnconsumedAudioLengthMs() { final int unconsumedFrames = mUnconsumedBytes / mBytesPerFrame; diff --git a/core/java/android/speech/tts/TextToSpeech.java b/core/java/android/speech/tts/TextToSpeech.java index 38699eaad44f..a220615c0079 100755 --- a/core/java/android/speech/tts/TextToSpeech.java +++ b/core/java/android/speech/tts/TextToSpeech.java @@ -490,6 +490,7 @@ public class TextToSpeech { private final Map<String, Uri> mUtterances; private final Bundle mParams = new Bundle(); private final TtsEngines mEnginesHelper; + private final String mPackageName; private volatile String mCurrentEngine = null; /** @@ -518,19 +519,36 @@ public class TextToSpeech { * @param engine Package name of the TTS engine to use. */ public TextToSpeech(Context context, OnInitListener listener, String engine) { + this(context, listener, engine, null); + } + + /** + * Used by the framework to instantiate TextToSpeech objects with a supplied + * package name, instead of using {@link android.content.Context#getPackageName()} + * + * @hide + */ + public TextToSpeech(Context context, OnInitListener listener, String engine, + String packageName) { mContext = context; mInitListener = listener; mRequestedEngine = engine; mEarcons = new HashMap<String, Uri>(); mUtterances = new HashMap<String, Uri>(); + mUtteranceProgressListener = null; mEnginesHelper = new TtsEngines(mContext); + if (packageName != null) { + mPackageName = packageName; + } else { + mPackageName = mContext.getPackageName(); + } initTts(); } private String getPackageName() { - return mContext.getPackageName(); + return mPackageName; } private <R> R runActionNoReconnect(Action<R> action, R errorResult, String method) { diff --git a/core/java/android/speech/tts/TextToSpeechService.java b/core/java/android/speech/tts/TextToSpeechService.java index 39922da68b34..aee678a2ffaa 100644 --- a/core/java/android/speech/tts/TextToSpeechService.java +++ b/core/java/android/speech/tts/TextToSpeechService.java @@ -450,7 +450,7 @@ public abstract class TextToSpeechService extends Service { @Override public void dispatchOnDone() { final String utteranceId = getUtteranceId(); - if (!TextUtils.isEmpty(utteranceId)) { + if (utteranceId != null) { mCallbacks.dispatchOnDone(getCallingApp(), utteranceId); } } @@ -458,7 +458,7 @@ public abstract class TextToSpeechService extends Service { @Override public void dispatchOnStart() { final String utteranceId = getUtteranceId(); - if (!TextUtils.isEmpty(utteranceId)) { + if (utteranceId != null) { mCallbacks.dispatchOnStart(getCallingApp(), utteranceId); } } @@ -466,7 +466,7 @@ public abstract class TextToSpeechService extends Service { @Override public void dispatchOnError() { final String utteranceId = getUtteranceId(); - if (!TextUtils.isEmpty(utteranceId)) { + if (utteranceId != null) { mCallbacks.dispatchOnError(getCallingApp(), utteranceId); } } @@ -509,6 +509,7 @@ public abstract class TextToSpeechService extends Service { } class SynthesisSpeechItem extends SpeechItem { + // Never null. private final String mText; private final SynthesisRequest mSynthesisRequest; private final String[] mDefaultLocale; @@ -532,8 +533,8 @@ public abstract class TextToSpeechService extends Service { @Override public boolean isValid() { - if (TextUtils.isEmpty(mText)) { - Log.w(TAG, "Got empty text"); + if (mText == null) { + Log.wtf(TAG, "Got null text"); return false; } if (mText.length() >= MAX_SPEECH_ITEM_CHAR_LENGTH) { diff --git a/core/java/android/speech/tts/UtteranceProgressListener.java b/core/java/android/speech/tts/UtteranceProgressListener.java index a04458a4ddf7..cf0d22cd0670 100644 --- a/core/java/android/speech/tts/UtteranceProgressListener.java +++ b/core/java/android/speech/tts/UtteranceProgressListener.java @@ -57,12 +57,16 @@ public abstract class UtteranceProgressListener { listener.onUtteranceCompleted(utteranceId); } - // The following methods are left unimplemented. @Override - public void onStart(String utteranceId) { } + public void onError(String utteranceId) { + listener.onUtteranceCompleted(utteranceId); + } @Override - public void onError(String utteranceId) { } + public void onStart(String utteranceId) { + // Left unimplemented, has no equivalent in the old + // API. + } }; } } diff --git a/core/java/android/text/SpannableStringBuilder.java b/core/java/android/text/SpannableStringBuilder.java index 231f9132e6ae..b70875060b30 100644 --- a/core/java/android/text/SpannableStringBuilder.java +++ b/core/java/android/text/SpannableStringBuilder.java @@ -863,6 +863,17 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable return new String(buf); } + /** + * Return a String containing a copy of the chars in this buffer, limited to the + * [start, end[ range. + * @hide + */ + public String substring(int start, int end) { + char[] buf = new char[end - start]; + getChars(start, end, buf, 0); + return new String(buf); + } + private TextWatcher[] sendTextWillChange(int start, int before, int after) { TextWatcher[] recip = getSpans(start, start + before, TextWatcher.class); int n = recip.length; diff --git a/core/java/android/text/TextLine.java b/core/java/android/text/TextLine.java index 68fea1907b87..b3df8ff5fbbc 100644 --- a/core/java/android/text/TextLine.java +++ b/core/java/android/text/TextLine.java @@ -59,6 +59,12 @@ class TextLine { private boolean mCharsValid; private Spanned mSpanned; private final TextPaint mWorkPaint = new TextPaint(); + private final SpanSet<MetricAffectingSpan> mMetricAffectingSpanSpanSet = + new SpanSet<MetricAffectingSpan>(MetricAffectingSpan.class); + private final SpanSet<CharacterStyle> mCharacterStyleSpanSet = + new SpanSet<CharacterStyle>(CharacterStyle.class); + private final SpanSet<ReplacementSpan> mReplacementSpanSpanSet = + new SpanSet<ReplacementSpan>(ReplacementSpan.class); private static final TextLine[] sCached = new TextLine[3]; @@ -136,9 +142,8 @@ class TextLine { boolean hasReplacement = false; if (text instanceof Spanned) { mSpanned = (Spanned) text; - ReplacementSpan[] spans = mSpanned.getSpans(start, limit, ReplacementSpan.class); - spans = TextUtils.removeEmptySpans(spans, mSpanned, ReplacementSpan.class); - hasReplacement = spans.length > 0; + mReplacementSpanSpanSet.init(mSpanned, start, limit); + hasReplacement = mReplacementSpanSpanSet.numberOfSpans > 0; } mCharsValid = hasReplacement || hasTabs || directions != Layout.DIRS_ALL_LEFT_TO_RIGHT; @@ -156,10 +161,8 @@ class TextLine { // zero-width characters. char[] chars = mChars; for (int i = start, inext; i < limit; i = inext) { - inext = mSpanned.nextSpanTransition(i, limit, ReplacementSpan.class); - ReplacementSpan[] spans = mSpanned.getSpans(i, inext, ReplacementSpan.class); - spans = TextUtils.removeEmptySpans(spans, mSpanned, ReplacementSpan.class); - if (spans.length > 0) { + inext = mReplacementSpanSpanSet.getNextTransition(i, limit); + if (mReplacementSpanSpanSet.hasSpansIntersecting(i, inext)) { // transition into a span chars[i - start] = '\ufffc'; for (int j = i - start + 1, e = inext - start; j < e; ++j) { @@ -853,21 +856,30 @@ class TextLine { } private static class SpanSet<E> { - final int numberOfSpans; - final E[] spans; - final int[] spanStarts; - final int[] spanEnds; - final int[] spanFlags; + int numberOfSpans; + E[] spans; + int[] spanStarts; + int[] spanEnds; + int[] spanFlags; + final Class<? extends E> classType; + + SpanSet(Class<? extends E> type) { + classType = type; + numberOfSpans = 0; + } @SuppressWarnings("unchecked") - SpanSet(Spanned spanned, int start, int limit, Class<? extends E> type) { - final E[] allSpans = spanned.getSpans(start, limit, type); + public void init(Spanned spanned, int start, int limit) { + final E[] allSpans = spanned.getSpans(start, limit, classType); final int length = allSpans.length; - // These arrays may end up being too large because of empty spans - spans = (E[]) Array.newInstance(type, length); - spanStarts = new int[length]; - spanEnds = new int[length]; - spanFlags = new int[length]; + + if (length > 0 && (spans == null || spans.length < length)) { + // These arrays may end up being too large because of empty spans + spans = (E[]) Array.newInstance(classType, length); + spanStarts = new int[length]; + spanEnds = new int[length]; + spanFlags = new int[length]; + } int count = 0; for (int i = 0; i < length; i++) { @@ -878,36 +890,26 @@ class TextLine { if (spanStart == spanEnd) continue; final int spanFlag = spanned.getSpanFlags(span); - final int priority = spanFlag & Spanned.SPAN_PRIORITY; - if (priority != 0 && count != 0) { - int j; - - for (j = 0; j < count; j++) { - final int otherPriority = spanFlags[j] & Spanned.SPAN_PRIORITY; - if (priority > otherPriority) break; - } - - System.arraycopy(spans, j, spans, j + 1, count - j); - System.arraycopy(spanStarts, j, spanStarts, j + 1, count - j); - System.arraycopy(spanEnds, j, spanEnds, j + 1, count - j); - System.arraycopy(spanFlags, j, spanFlags, j + 1, count - j); - spans[j] = span; - spanStarts[j] = spanStart; - spanEnds[j] = spanEnd; - spanFlags[j] = spanFlag; - } else { - spans[i] = span; - spanStarts[i] = spanStart; - spanEnds[i] = spanEnd; - spanFlags[i] = spanFlag; - } + spans[i] = span; + spanStarts[i] = spanStart; + spanEnds[i] = spanEnd; + spanFlags[i] = spanFlag; count++; } numberOfSpans = count; } + public boolean hasSpansIntersecting(int start, int end) { + for (int i = 0; i < numberOfSpans; i++) { + // equal test is valid since both intervals are not empty by construction + if (spanStarts[i] >= end || spanEnds[i] <= start) continue; + return true; + } + return false; + } + int getNextTransition(int start, int limit) { for (int i = 0; i < numberOfSpans; i++) { final int spanStart = spanStarts[i]; @@ -960,10 +962,8 @@ class TextLine { y, bottom, fmi, needWidth || mlimit < measureLimit); } - final SpanSet<MetricAffectingSpan> metricAffectingSpans = new SpanSet<MetricAffectingSpan>( - mSpanned, mStart + start, mStart + limit, MetricAffectingSpan.class); - final SpanSet<CharacterStyle> characterStyleSpans = new SpanSet<CharacterStyle>( - mSpanned, mStart + start, mStart + limit, CharacterStyle.class); + mMetricAffectingSpanSpanSet.init(mSpanned, mStart + start, mStart + limit); + mCharacterStyleSpanSet.init(mSpanned, mStart + start, mStart + limit); // Shaping needs to take into account context up to metric boundaries, // but rendering needs to take into account character style boundaries. @@ -975,17 +975,18 @@ class TextLine { TextPaint wp = mWorkPaint; wp.set(mPaint); - inext = metricAffectingSpans.getNextTransition(mStart + i, mStart + limit) - mStart; + inext = mMetricAffectingSpanSpanSet.getNextTransition(mStart + i, mStart + limit) - + mStart; int mlimit = Math.min(inext, measureLimit); ReplacementSpan replacement = null; - for (int j = 0; j < metricAffectingSpans.numberOfSpans; j++) { + for (int j = 0; j < mMetricAffectingSpanSpanSet.numberOfSpans; j++) { // Both intervals [spanStarts..spanEnds] and [mStart + i..mStart + mlimit] are NOT // empty by construction. This special case in getSpans() explains the >= & <= tests - if ((metricAffectingSpans.spanStarts[j] >= mStart + mlimit) || - (metricAffectingSpans.spanEnds[j] <= mStart + i)) continue; - MetricAffectingSpan span = metricAffectingSpans.spans[j]; + if ((mMetricAffectingSpanSpanSet.spanStarts[j] >= mStart + mlimit) || + (mMetricAffectingSpanSpanSet.spanEnds[j] <= mStart + i)) continue; + MetricAffectingSpan span = mMetricAffectingSpanSpanSet.spans[j]; if (span instanceof ReplacementSpan) { replacement = (ReplacementSpan)span; } else { @@ -1006,16 +1007,16 @@ class TextLine { y, bottom, fmi, needWidth || mlimit < measureLimit); } else { for (int j = i, jnext; j < mlimit; j = jnext) { - jnext = characterStyleSpans.getNextTransition(mStart + j, mStart + mlimit) - + jnext = mCharacterStyleSpanSet.getNextTransition(mStart + j, mStart + mlimit) - mStart; wp.set(mPaint); - for (int k = 0; k < characterStyleSpans.numberOfSpans; k++) { + for (int k = 0; k < mCharacterStyleSpanSet.numberOfSpans; k++) { // Intentionally using >= and <= as explained above - if ((characterStyleSpans.spanStarts[k] >= mStart + jnext) || - (characterStyleSpans.spanEnds[k] <= mStart + j)) continue; + if ((mCharacterStyleSpanSet.spanStarts[k] >= mStart + jnext) || + (mCharacterStyleSpanSet.spanEnds[k] <= mStart + j)) continue; - CharacterStyle span = characterStyleSpans.spans[k]; + CharacterStyle span = mCharacterStyleSpanSet.spans[k]; span.updateDrawState(wp); } diff --git a/core/java/android/text/format/DateUtils.java b/core/java/android/text/format/DateUtils.java index 353b628e7d70..7f8af7a4d543 100644 --- a/core/java/android/text/format/DateUtils.java +++ b/core/java/android/text/format/DateUtils.java @@ -1415,7 +1415,7 @@ public class DateUtils } } - if (noMonthDay && startMonthNum == endMonthNum) { + if (noMonthDay && startMonthNum == endMonthNum && startYear == endYear) { // Example: "January, 2008" return formatter.format("%s", startDate.format(defaultDateFormat)); } diff --git a/core/java/android/text/format/Formatter.java b/core/java/android/text/format/Formatter.java index 5ae65df9826a..121c6f2f9324 100644 --- a/core/java/android/text/format/Formatter.java +++ b/core/java/android/text/format/Formatter.java @@ -21,7 +21,7 @@ import android.net.NetworkUtils; /** * Utility class to aid in formatting common values that are not covered - * by {@link java.util.Formatter} + * by the {@link java.util.Formatter} class in {@link java.util} */ public final class Formatter { diff --git a/core/java/android/text/format/package.html b/core/java/android/text/format/package.html new file mode 100644 index 000000000000..b9e6a44f60e0 --- /dev/null +++ b/core/java/android/text/format/package.html @@ -0,0 +1,7 @@ +<HTML> +<BODY> +This package contains alternative classes for some text formatting classes +defined in {@link java.util} and {@link java.text}. It also contains additional text formatting +classes for situations not covered by {@link java.util} or {@link java.text}. +</BODY> +</HTML> diff --git a/core/java/android/text/method/Touch.java b/core/java/android/text/method/Touch.java index 106a80190b36..3dfd44d90e4d 100644 --- a/core/java/android/text/method/Touch.java +++ b/core/java/android/text/method/Touch.java @@ -35,22 +35,30 @@ public class Touch { * Y position. */ public static void scrollTo(TextView widget, Layout layout, int x, int y) { - final int verticalPadding = widget.getTotalPaddingTop() + widget.getTotalPaddingBottom(); - final int top = layout.getLineForVertical(y); - final int bottom = layout.getLineForVertical(y + widget.getHeight() - verticalPadding); + final int horizontalPadding = widget.getTotalPaddingLeft() + widget.getTotalPaddingRight(); + final int availableWidth = widget.getWidth() - horizontalPadding; - int left = Integer.MAX_VALUE; - int right = 0; + final int top = layout.getLineForVertical(y); Alignment a = layout.getParagraphAlignment(top); boolean ltr = layout.getParagraphDirection(top) > 0; - for (int i = top; i <= bottom; i++) { - left = (int) Math.min(left, layout.getLineLeft(i)); - right = (int) Math.max(right, layout.getLineRight(i)); + int left, right; + if (widget.getHorizontallyScrolling()) { + final int verticalPadding = widget.getTotalPaddingTop() + widget.getTotalPaddingBottom(); + final int bottom = layout.getLineForVertical(y + widget.getHeight() - verticalPadding); + + left = Integer.MAX_VALUE; + right = 0; + + for (int i = top; i <= bottom; i++) { + left = (int) Math.min(left, layout.getLineLeft(i)); + right = (int) Math.max(right, layout.getLineRight(i)); + } + } else { + left = 0; + right = availableWidth; } - final int hoizontalPadding = widget.getTotalPaddingLeft() + widget.getTotalPaddingRight(); - final int availableWidth = widget.getWidth() - hoizontalPadding; final int actualWidth = right - left; if (actualWidth < availableWidth) { @@ -166,16 +174,24 @@ public class Touch { return false; } + /** + * @param widget The text view. + * @param buffer The text buffer. + */ public static int getInitialScrollX(TextView widget, Spannable buffer) { DragState[] ds = buffer.getSpans(0, buffer.length(), DragState.class); return ds.length > 0 ? ds[0].mScrollX : -1; } - + + /** + * @param widget The text view. + * @param buffer The text buffer. + */ public static int getInitialScrollY(TextView widget, Spannable buffer) { DragState[] ds = buffer.getSpans(0, buffer.length(), DragState.class); return ds.length > 0 ? ds[0].mScrollY : -1; } - + private static class DragState implements NoCopySpan { public float mX; public float mY; diff --git a/core/java/android/text/method/WordIterator.java b/core/java/android/text/method/WordIterator.java index 239d9e8c5726..11226a98f753 100644 --- a/core/java/android/text/method/WordIterator.java +++ b/core/java/android/text/method/WordIterator.java @@ -18,6 +18,7 @@ package android.text.method; import android.text.Selection; +import android.text.SpannableStringBuilder; import java.text.BreakIterator; import java.util.Locale; @@ -58,7 +59,11 @@ public class WordIterator implements Selection.PositionIterator { mOffsetShift = Math.max(0, start - WINDOW_WIDTH); final int windowEnd = Math.min(charSequence.length(), end + WINDOW_WIDTH); - mString = charSequence.toString().substring(mOffsetShift, windowEnd); + if (charSequence instanceof SpannableStringBuilder) { + mString = ((SpannableStringBuilder) charSequence).substring(mOffsetShift, windowEnd); + } else { + mString = charSequence.subSequence(mOffsetShift, windowEnd).toString(); + } mIterator.setText(mString); } diff --git a/core/java/android/text/style/SuggestionSpan.java b/core/java/android/text/style/SuggestionSpan.java index ed2af10bcf03..0f26a34ece8d 100644 --- a/core/java/android/text/style/SuggestionSpan.java +++ b/core/java/android/text/style/SuggestionSpan.java @@ -92,11 +92,6 @@ public class SuggestionSpan extends CharacterStyle implements ParcelableSpan { private float mAutoCorrectionUnderlineThickness; private int mAutoCorrectionUnderlineColor; - /* - * TODO: If switching IME is required, needs to add parameters for ids of InputMethodInfo - * and InputMethodSubtype. - */ - /** * @param context Context for the application * @param suggestions Suggestions for the string under the span @@ -146,6 +141,16 @@ public class SuggestionSpan extends CharacterStyle implements ParcelableSpan { } private void initStyle(Context context) { + if (context == null) { + mMisspelledUnderlineThickness = 0; + mEasyCorrectUnderlineThickness = 0; + mAutoCorrectionUnderlineThickness = 0; + mMisspelledUnderlineColor = Color.BLACK; + mEasyCorrectUnderlineColor = Color.BLACK; + mAutoCorrectionUnderlineColor = Color.BLACK; + return; + } + int defStyle = com.android.internal.R.attr.textAppearanceMisspelledSuggestion; TypedArray typedArray = context.obtainStyledAttributes( null, com.android.internal.R.styleable.SuggestionSpan, defStyle, 0); @@ -169,7 +174,6 @@ public class SuggestionSpan extends CharacterStyle implements ParcelableSpan { com.android.internal.R.styleable.SuggestionSpan_textUnderlineThickness, 0); mAutoCorrectionUnderlineColor = typedArray.getColor( com.android.internal.R.styleable.SuggestionSpan_textUnderlineColor, Color.BLACK); - } public SuggestionSpan(Parcel src) { diff --git a/core/java/android/util/SparseArray.java b/core/java/android/util/SparseArray.java index 7cf45793fe7e..366abd36294d 100644 --- a/core/java/android/util/SparseArray.java +++ b/core/java/android/util/SparseArray.java @@ -134,6 +134,7 @@ public class SparseArray<E> implements Cloneable { if (i != o) { keys[o] = keys[i]; values[o] = val; + values[i] = null; } o++; diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java index d948ec28cbd2..4ca299fd140f 100644 --- a/core/java/android/view/GLES20Canvas.java +++ b/core/java/android/view/GLES20Canvas.java @@ -737,8 +737,21 @@ class GLES20Canvas extends HardwareCanvas { // Shaders are ignored when drawing bitmaps int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE; final int nativePaint = paint == null ? 0 : paint.mNativePaint; - nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, src.left, src.top, src.right, - src.bottom, dst.left, dst.top, dst.right, dst.bottom, nativePaint); + + float left, top, right, bottom; + if (src == null) { + left = top = 0; + right = bitmap.getWidth(); + bottom = bitmap.getHeight(); + } else { + left = src.left; + right = src.right; + top = src.top; + bottom = src.bottom; + } + + nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, left, top, right, bottom, + dst.left, dst.top, dst.right, dst.bottom, nativePaint); if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); } diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java index 8e39d6edf345..ccb64895703c 100644 --- a/core/java/android/view/HardwareRenderer.java +++ b/core/java/android/view/HardwareRenderer.java @@ -162,13 +162,21 @@ public abstract class HardwareRenderer { abstract void updateSurface(SurfaceHolder holder) throws Surface.OutOfResourcesException; /** - * Destoys the layers used by the specified view hierarchy. + * Destroys the layers used by the specified view hierarchy. * * @param view The root of the view hierarchy */ abstract void destroyLayers(View view); /** + * Destroys all hardware rendering resources associated with the specified + * view hierarchy. + * + * @param view The root of the view hierarchy + */ + abstract void destroyHardwareResources(View view); + + /** * This method should be invoked whenever the current hardware renderer * context should be reset. * @@ -211,6 +219,13 @@ public abstract class HardwareRenderer { abstract int getHeight(); /** + * Gets the current canvas associated with this HardwareRenderer. + * + * @return the current HardwareCanvas + */ + abstract HardwareCanvas getCanvas(); + + /** * Sets the directory to use as a persistent storage for hardware rendering * resources. * @@ -348,15 +363,6 @@ public abstract class HardwareRenderer { } /** - * Invoke this method when the system needs to clean up all resources - * associated with hardware rendering. - */ - static void terminate() { - Log.d(LOG_TAG, "Terminating hardware rendering"); - Gl20Renderer.terminate(); - } - - /** * Indicates whether hardware acceleration is currently enabled. * * @return True if hardware acceleration is in use, false otherwise. @@ -412,8 +418,8 @@ public abstract class HardwareRenderer { static final Object[] sEglLock = new Object[0]; int mWidth = -1, mHeight = -1; - static final ThreadLocal<Gl20Renderer.MyEGLContext> sEglContextStorage - = new ThreadLocal<Gl20Renderer.MyEGLContext>(); + static final ThreadLocal<Gl20Renderer.Gl20RendererEglContext> sEglContextStorage + = new ThreadLocal<Gl20Renderer.Gl20RendererEglContext>(); EGLContext mEglContext; Thread mEglThread; @@ -565,13 +571,13 @@ public abstract class HardwareRenderer { } } - Gl20Renderer.MyEGLContext managedContext = sEglContextStorage.get(); + Gl20Renderer.Gl20RendererEglContext managedContext = sEglContextStorage.get(); mEglContext = managedContext != null ? managedContext.getContext() : null; mEglThread = Thread.currentThread(); if (mEglContext == null) { mEglContext = createContext(sEgl, sEglDisplay, sEglConfig); - sEglContextStorage.set(new Gl20Renderer.MyEGLContext(mEglContext)); + sEglContextStorage.set(new Gl20Renderer.Gl20RendererEglContext(mEglContext)); } } @@ -784,6 +790,11 @@ public abstract class HardwareRenderer { return mHeight; } + @Override + HardwareCanvas getCanvas() { + return mCanvas; + } + boolean canDraw() { return mGl != null && mCanvas != null; } @@ -909,10 +920,10 @@ public abstract class HardwareRenderer { private static EGLSurface sPbuffer; private static final Object[] sPbufferLock = new Object[0]; - static class MyEGLContext extends ManagedEGLContext { + static class Gl20RendererEglContext extends ManagedEGLContext { final Handler mHandler = new Handler(); - public MyEGLContext(EGLContext context) { + public Gl20RendererEglContext(EGLContext context) { super(context); } @@ -939,7 +950,8 @@ public abstract class HardwareRenderer { sEglContextStorage.remove(); sEgl.eglDestroySurface(sEglDisplay, sPbuffer); - sEgl.eglMakeCurrent(sEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + sEgl.eglMakeCurrent(sEglDisplay, EGL_NO_SURFACE, + EGL_NO_SURFACE, EGL_NO_CONTEXT); sEgl.eglReleaseThread(); sEgl.eglTerminate(sEglDisplay); @@ -1046,10 +1058,9 @@ public abstract class HardwareRenderer { } } - private void destroyHardwareLayer(View view) { - if (view.destroyLayer()) { - view.invalidate(true); - } + private static void destroyHardwareLayer(View view) { + view.destroyLayer(); + if (view instanceof ViewGroup) { ViewGroup group = (ViewGroup) view; @@ -1059,6 +1070,36 @@ public abstract class HardwareRenderer { } } } + + @Override + void destroyHardwareResources(View view) { + if (view != null) { + boolean needsContext = true; + if (isEnabled() && checkCurrent() != SURFACE_STATE_ERROR) needsContext = false; + + if (needsContext) { + Gl20RendererEglContext managedContext = sEglContextStorage.get(); + if (managedContext == null) return; + usePbufferSurface(managedContext.getContext()); + } + + destroyResources(view); + GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_LAYERS); + } + } + + private static void destroyResources(View view) { + view.destroyHardwareResources(); + + if (view instanceof ViewGroup) { + ViewGroup group = (ViewGroup) view; + + int count = group.getChildCount(); + for (int i = 0; i < count; i++) { + destroyResources(group.getChildAt(i)); + } + } + } static HardwareRenderer create(boolean translucent) { if (GLES20Canvas.isAvailable()) { @@ -1070,7 +1111,7 @@ public abstract class HardwareRenderer { static void trimMemory(int level) { if (sEgl == null || sEglConfig == null) return; - Gl20Renderer.MyEGLContext managedContext = sEglContextStorage.get(); + Gl20RendererEglContext managedContext = sEglContextStorage.get(); // We do not have OpenGL objects if (managedContext == null) { return; diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl index 282d7be6d9fb..53d6e1f20281 100644 --- a/core/java/android/view/IWindowSession.aidl +++ b/core/java/android/view/IWindowSession.aidl @@ -54,9 +54,8 @@ interface IWindowSession { * @param requestedWidth The width the window wants to be. * @param requestedHeight The height the window wants to be. * @param viewVisibility Window root view's visibility. - * @param insetsPending Set to true if the client will be later giving - * internal insets; as a result, the window will not impact other window - * layouts until the insets are given. + * @param flags Request flags: {@link WindowManagerImpl#RELAYOUT_INSETS_PENDING}, + * {@link WindowManagerImpl#RELAYOUT_DEFER_SURFACE_DESTROY}. * @param outFrame Rect in which is placed the new position/size on * screen. * @param outContentInsets Rect in which is placed the offsets from @@ -80,11 +79,17 @@ interface IWindowSession { */ int relayout(IWindow window, int seq, in WindowManager.LayoutParams attrs, int requestedWidth, int requestedHeight, int viewVisibility, - boolean insetsPending, out Rect outFrame, out Rect outContentInsets, + int flags, out Rect outFrame, out Rect outContentInsets, out Rect outVisibleInsets, out Configuration outConfig, out Surface outSurface); /** + * If a call to relayout() asked to have the surface destroy deferred, + * it must call this once it is okay to destroy that surface. + */ + void performDeferredDestroy(IWindow window); + + /** * Called by a client to report that it ran out of graphics memory. */ boolean outOfMemory(IWindow window); diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java index 6c3d387a5fd7..f53e42cb4603 100755 --- a/core/java/android/view/KeyEvent.java +++ b/core/java/android/view/KeyEvent.java @@ -579,8 +579,20 @@ public class KeyEvent extends InputEvent implements Parcelable { /** Key code constant: 3D Mode key. * Toggles the display between 2D and 3D mode. */ public static final int KEYCODE_3D_MODE = 206; - - private static final int LAST_KEYCODE = KEYCODE_BUTTON_16; + /** Key code constant: Contacts special function key. + * Used to launch an address book application. */ + public static final int KEYCODE_CONTACTS = 207; + /** Key code constant: Calendar special function key. + * Used to launch a calendar application. */ + public static final int KEYCODE_CALENDAR = 208; + /** Key code constant: Music special function key. + * Used to launch a music player application. */ + public static final int KEYCODE_MUSIC = 209; + /** Key code constant: Calculator special function key. + * Used to launch a calculator application. */ + public static final int KEYCODE_CALCULATOR = 210; + + private static final int LAST_KEYCODE = KEYCODE_CALCULATOR; // NOTE: If you add a new keycode here you must also add it to: // isSystem() @@ -589,6 +601,8 @@ public class KeyEvent extends InputEvent implements Parcelable { // external/webkit/WebKit/android/plugins/ANPKeyCodes.h // frameworks/base/core/res/res/values/attrs.xml // emulator? + // LAST_KEYCODE + // KEYCODE_SYMBOLIC_NAMES // // Also Android currently does not reserve code ranges for vendor- // specific key codes. If you have new key codes to have, you @@ -807,6 +821,10 @@ public class KeyEvent extends InputEvent implements Parcelable { names.append(KEYCODE_LANGUAGE_SWITCH, "KEYCODE_LANGUAGE_SWITCH"); names.append(KEYCODE_MANNER_MODE, "KEYCODE_MANNER_MODE"); names.append(KEYCODE_3D_MODE, "KEYCODE_3D_MODE"); + names.append(KEYCODE_CONTACTS, "KEYCODE_CONTACTS"); + names.append(KEYCODE_CALENDAR, "KEYCODE_CALENDAR"); + names.append(KEYCODE_MUSIC, "KEYCODE_MUSIC"); + names.append(KEYCODE_CALCULATOR, "KEYCODE_CALCULATOR"); }; // Symbolic names of all metakeys in bit order from least significant to most significant. diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java index 2b254af414ab..edaa262d66dd 100644 --- a/core/java/android/view/Surface.java +++ b/core/java/android/view/Surface.java @@ -282,10 +282,24 @@ public class Surface implements Parcelable { /** * Copy another surface to this one. This surface now holds a reference * to the same data as the original surface, and is -not- the owner. + * This is for use by the window manager when returning a window surface + * back from a client, converting it from the representation being managed + * by the window manager to the representation the client uses to draw + * in to it. * @hide */ public native void copyFrom(Surface o); - + + /** + * Transfer the native state from 'o' to this surface, releasing it + * from 'o'. This is for use in the client side for drawing into a + * surface; not guaranteed to work on the window manager side. + * This is for use by the client to move the underlying surface from + * one Surface object to another, in particular in SurfaceFlinger. + * @hide. + */ + public native void transferFrom(Surface o); + /** @hide */ public int getGenerationId() { return mSurfaceGenerationId; diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java index 9a57ea0679c4..6726c56eb581 100644 --- a/core/java/android/view/SurfaceView.java +++ b/core/java/android/view/SurfaceView.java @@ -16,7 +16,6 @@ package android.view; -import android.util.DisplayMetrics; import com.android.internal.view.BaseIWindow; import android.content.Context; @@ -82,7 +81,6 @@ import java.util.concurrent.locks.ReentrantLock; public class SurfaceView extends View { static private final String TAG = "SurfaceView"; static private final boolean DEBUG = false; - static private final boolean localLOGV = DEBUG ? true : false; final ArrayList<SurfaceHolder.Callback> mCallbacks = new ArrayList<SurfaceHolder.Callback>(); @@ -90,7 +88,8 @@ public class SurfaceView extends View { final int[] mLocation = new int[2]; final ReentrantLock mSurfaceLock = new ReentrantLock(); - final Surface mSurface = new Surface(); + final Surface mSurface = new Surface(); // Current surface in use + final Surface mNewSurface = new Surface(); // New surface we are switching to boolean mDrawingStopped = true; final WindowManager.LayoutParams mLayout @@ -145,8 +144,7 @@ public class SurfaceView extends View { int mRequestedFormat = PixelFormat.RGB_565; boolean mHaveFrame = false; - boolean mDestroyReportNeeded = false; - boolean mNewSurfaceNeeded = false; + boolean mSurfaceCreated = false; long mLastLockTime = 0; boolean mVisible = false; @@ -236,46 +234,6 @@ public class SurfaceView extends View { updateWindow(false, false); } - /** - * This method is not intended for general use. It was created - * temporarily to improve performance of 3D layers in Launcher - * and should be removed and fixed properly. - * - * Do not call this method. Ever. - * - * @hide - */ - protected void showSurface() { - if (mSession != null) { - updateWindow(true, false); - } - } - - /** - * This method is not intended for general use. It was created - * temporarily to improve performance of 3D layers in Launcher - * and should be removed and fixed properly. - * - * Do not call this method. Ever. - * - * @hide - */ - protected void hideSurface() { - if (mSession != null && mWindow != null) { - mSurfaceLock.lock(); - try { - DisplayMetrics metrics = getResources().getDisplayMetrics(); - mLayout.x = metrics.widthPixels * 3; - mSession.relayout(mWindow, mWindow.mSeq, mLayout, mWidth, mHeight, VISIBLE, false, - mWinFrame, mContentInsets, mVisibleInsets, mConfiguration, mSurface); - } catch (RemoteException e) { - // Ignore - } finally { - mSurfaceLock.unlock(); - } - } - } - @Override protected void onDetachedFromWindow() { if (mGlobalListenersAdded) { @@ -444,14 +402,13 @@ public class SurfaceView extends View { final boolean creating = mWindow == null; final boolean formatChanged = mFormat != mRequestedFormat; final boolean sizeChanged = mWidth != myWidth || mHeight != myHeight; - final boolean visibleChanged = mVisible != mRequestedVisible - || mNewSurfaceNeeded; + final boolean visibleChanged = mVisible != mRequestedVisible; if (force || creating || formatChanged || sizeChanged || visibleChanged || mLeft != mLocation[0] || mTop != mLocation[1] || mUpdateWindowNeeded || mReportDrawNeeded || redrawNeeded) { - if (localLOGV) Log.i(TAG, "Changes: creating=" + creating + if (DEBUG) Log.i(TAG, "Changes: creating=" + creating + " format=" + formatChanged + " size=" + sizeChanged + " visible=" + visibleChanged + " left=" + (mLeft != mLocation[0]) @@ -496,15 +453,11 @@ public class SurfaceView extends View { mVisible ? VISIBLE : GONE, mContentInsets); } - if (visibleChanged && (!visible || mNewSurfaceNeeded)) { - reportSurfaceDestroyed(); - } - - mNewSurfaceNeeded = false; - boolean realSizeChanged; boolean reportDrawNeeded; - + + int relayoutResult; + mSurfaceLock.lock(); try { mUpdateWindowNeeded = false; @@ -512,17 +465,21 @@ public class SurfaceView extends View { mReportDrawNeeded = false; mDrawingStopped = !visible; - final int relayoutResult = mSession.relayout( + if (DEBUG) Log.i(TAG, "Cur surface: " + mSurface); + + relayoutResult = mSession.relayout( mWindow, mWindow.mSeq, mLayout, mWidth, mHeight, - visible ? VISIBLE : GONE, false, mWinFrame, mContentInsets, - mVisibleInsets, mConfiguration, mSurface); - if ((relayoutResult&WindowManagerImpl.RELAYOUT_FIRST_TIME) != 0) { + visible ? VISIBLE : GONE, + WindowManagerImpl.RELAYOUT_DEFER_SURFACE_DESTROY, + mWinFrame, mContentInsets, + mVisibleInsets, mConfiguration, mNewSurface); + if ((relayoutResult&WindowManagerImpl.RELAYOUT_RES_FIRST_TIME) != 0) { mReportDrawNeeded = true; } - - if (localLOGV) Log.i(TAG, "New surface: " + mSurface + + if (DEBUG) Log.i(TAG, "New surface: " + mNewSurface + ", vis=" + visible + ", frame=" + mWinFrame); - + mSurfaceFrame.left = 0; mSurfaceFrame.top = 0; if (mTranslator == null) { @@ -547,28 +504,51 @@ public class SurfaceView extends View { try { redrawNeeded |= creating | reportDrawNeeded; - if (visible) { - mDestroyReportNeeded = true; + SurfaceHolder.Callback callbacks[] = null; - SurfaceHolder.Callback callbacks[]; - synchronized (mCallbacks) { - callbacks = new SurfaceHolder.Callback[mCallbacks.size()]; - mCallbacks.toArray(callbacks); + final boolean surfaceChanged = + (relayoutResult&WindowManagerImpl.RELAYOUT_RES_SURFACE_CHANGED) != 0; + if (mSurfaceCreated && (surfaceChanged || (!visible && visibleChanged))) { + mSurfaceCreated = false; + if (mSurface.isValid()) { + if (DEBUG) Log.i(TAG, "visibleChanged -- surfaceDestroyed"); + callbacks = getSurfaceCallbacks(); + for (SurfaceHolder.Callback c : callbacks) { + c.surfaceDestroyed(mSurfaceHolder); + } } + } + + mSurface.transferFrom(mNewSurface); - if (visibleChanged) { + if (visible) { + if (!mSurfaceCreated && (surfaceChanged || visibleChanged)) { + mSurfaceCreated = true; mIsCreating = true; + if (DEBUG) Log.i(TAG, "visibleChanged -- surfaceCreated"); + if (callbacks == null) { + callbacks = getSurfaceCallbacks(); + } for (SurfaceHolder.Callback c : callbacks) { c.surfaceCreated(mSurfaceHolder); } } if (creating || formatChanged || sizeChanged || visibleChanged || realSizeChanged) { + if (DEBUG) Log.i(TAG, "surfaceChanged -- format=" + mFormat + + " w=" + myWidth + " h=" + myHeight); + if (callbacks == null) { + callbacks = getSurfaceCallbacks(); + } for (SurfaceHolder.Callback c : callbacks) { c.surfaceChanged(mSurfaceHolder, mFormat, myWidth, myHeight); } } if (redrawNeeded) { + if (DEBUG) Log.i(TAG, "surfaceRedrawNeeded"); + if (callbacks == null) { + callbacks = getSurfaceCallbacks(); + } for (SurfaceHolder.Callback c : callbacks) { if (c instanceof SurfaceHolder.Callback2) { ((SurfaceHolder.Callback2)c).surfaceRedrawNeeded( @@ -576,41 +556,34 @@ public class SurfaceView extends View { } } } - } else { - mSurface.release(); } } finally { mIsCreating = false; if (redrawNeeded) { + if (DEBUG) Log.i(TAG, "finishedDrawing"); mSession.finishDrawing(mWindow); } + mSession.performDeferredDestroy(mWindow); } } catch (RemoteException ex) { } - if (localLOGV) Log.v( + if (DEBUG) Log.v( TAG, "Layout: x=" + mLayout.x + " y=" + mLayout.y + " w=" + mLayout.width + " h=" + mLayout.height + ", frame=" + mSurfaceFrame); } } - private void reportSurfaceDestroyed() { - if (mDestroyReportNeeded) { - mDestroyReportNeeded = false; - SurfaceHolder.Callback callbacks[]; - synchronized (mCallbacks) { - callbacks = new SurfaceHolder.Callback[mCallbacks.size()]; - mCallbacks.toArray(callbacks); - } - for (SurfaceHolder.Callback c : callbacks) { - c.surfaceDestroyed(mSurfaceHolder); - } + private SurfaceHolder.Callback[] getSurfaceCallbacks() { + SurfaceHolder.Callback callbacks[]; + synchronized (mCallbacks) { + callbacks = new SurfaceHolder.Callback[mCallbacks.size()]; + mCallbacks.toArray(callbacks); } - super.onDetachedFromWindow(); + return callbacks; } void handleGetNewSurface() { - mNewSurfaceNeeded = true; updateWindow(false, false); } @@ -636,7 +609,7 @@ public class SurfaceView extends View { Rect visibleInsets, boolean reportDraw, Configuration newConfig) { SurfaceView surfaceView = mSurfaceView.get(); if (surfaceView != null) { - if (localLOGV) Log.v( + if (DEBUG) Log.v( "SurfaceView", surfaceView + " got resized: w=" + w + " h=" + h + ", cur w=" + mCurWidth + " h=" + mCurHeight); surfaceView.mSurfaceLock.lock(); @@ -754,7 +727,7 @@ public class SurfaceView extends View { private final Canvas internalLockCanvas(Rect dirty) { mSurfaceLock.lock(); - if (localLOGV) Log.i(TAG, "Locking canvas... stopped=" + if (DEBUG) Log.i(TAG, "Locking canvas... stopped=" + mDrawingStopped + ", win=" + mWindow); Canvas c = null; @@ -774,7 +747,7 @@ public class SurfaceView extends View { } } - if (localLOGV) Log.i(TAG, "Returned canvas: " + c); + if (DEBUG) Log.i(TAG, "Returned canvas: " + c); if (c != null) { mLastLockTime = SystemClock.uptimeMillis(); return c; diff --git a/core/java/android/view/TextureView.java b/core/java/android/view/TextureView.java index 169738257b3b..74916f051635 100644 --- a/core/java/android/view/TextureView.java +++ b/core/java/android/view/TextureView.java @@ -203,7 +203,10 @@ public class TextureView extends View { @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); + destroySurface(); + } + private void destroySurface() { if (mLayer != null) { boolean shouldRelease = true; if (mListener != null) { @@ -300,6 +303,17 @@ public class TextureView extends View { return false; } + /** + * @hide + */ + @Override + protected void destroyHardwareResources() { + super.destroyHardwareResources(); + destroySurface(); + invalidateParentCaches(); + invalidate(true); + } + @Override HardwareLayer getHardwareLayer() { if (mLayer == null) { diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index dc46d424450f..54bb056ab035 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -1487,7 +1487,8 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal | AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED | AccessibilityEvent.TYPE_VIEW_HOVER_ENTER | AccessibilityEvent.TYPE_VIEW_HOVER_EXIT - | AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED; + | AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED + | AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED; /** * Temporary Rect currently for use in setBackground(). This will probably @@ -8058,9 +8059,9 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal /** * If some part of this view is not clipped by any of its parents, then * return that area in r in global (root) coordinates. To convert r to local - * coordinates, offset it by -globalOffset (e.g. r.offset(-globalOffset.x, - * -globalOffset.y)) If the view is completely clipped or translated out, - * return false. + * coordinates (without taking possible View rotations into account), offset + * it by -globalOffset (e.g. r.offset(-globalOffset.x, -globalOffset.y)). + * If the view is completely clipped or translated out, return false. * * @param r If true is returned, r holds the global coordinates of the * visible portion of this view. @@ -10072,7 +10073,7 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal switch (mLayerType) { case LAYER_TYPE_HARDWARE: destroyLayer(); - // fall through - unaccelerated views may use software layer mechanism instead + // fall through - non-accelerated views may use software layer mechanism instead case LAYER_TYPE_SOFTWARE: destroyDrawingCache(); break; @@ -10139,7 +10140,11 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal switch (mLayerType) { case LAYER_TYPE_HARDWARE: - getHardwareLayer(); + if (mAttachInfo.mHardwareRenderer != null && + mAttachInfo.mHardwareRenderer.isEnabled() && + mAttachInfo.mHardwareRenderer.validate()) { + getHardwareLayer(); + } break; case LAYER_TYPE_SOFTWARE: buildDrawingCache(true); @@ -10234,12 +10239,31 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal if (mHardwareLayer != null) { mHardwareLayer.destroy(); mHardwareLayer = null; + + invalidate(true); + invalidateParentCaches(); + return true; } return false; } /** + * Destroys all hardware rendering resources. This method is invoked + * when the system needs to reclaim resources. Upon execution of this + * method, you should free any OpenGL resources created by the view. + * + * Note: you <strong>must</strong> call + * <code>super.destroyHardwareResources()</code> when overriding + * this method. + * + * @hide + */ + protected void destroyHardwareResources() { + destroyLayer(); + } + + /** * <p>Enables or disables the drawing cache. When the drawing cache is enabled, the next call * to {@link #getDrawingCache()} or {@link #buildDrawingCache()} will draw the view in a * bitmap. Calling {@link #draw(android.graphics.Canvas)} will not draw from the cache when @@ -12128,35 +12152,48 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal * @param location an array of two integers in which to hold the coordinates */ public void getLocationInWindow(int[] location) { + // When the view is not attached to a window, this method does not make sense + if (mAttachInfo == null) return; + if (location == null || location.length < 2) { - throw new IllegalArgumentException("location must be an array of " - + "two integers"); + throw new IllegalArgumentException("location must be an array of two integers"); } - location[0] = mLeft; - location[1] = mTop; - if (mTransformationInfo != null) { - location[0] += (int) (mTransformationInfo.mTranslationX + 0.5f); - location[1] += (int) (mTransformationInfo.mTranslationY + 0.5f); + float[] position = mAttachInfo.mTmpTransformLocation; + position[0] = position[1] = 0.0f; + + if (!hasIdentityMatrix()) { + getMatrix().mapPoints(position); } + position[0] += mLeft; + position[1] += mTop; + ViewParent viewParent = mParent; while (viewParent instanceof View) { - final View view = (View)viewParent; - location[0] += view.mLeft - view.mScrollX; - location[1] += view.mTop - view.mScrollY; - if (view.mTransformationInfo != null) { - location[0] += (int) (view.mTransformationInfo.mTranslationX + 0.5f); - location[1] += (int) (view.mTransformationInfo.mTranslationY + 0.5f); + final View view = (View) viewParent; + + position[0] -= view.mScrollX; + position[1] -= view.mScrollY; + + if (!view.hasIdentityMatrix()) { + view.getMatrix().mapPoints(position); } + + position[0] += view.mLeft; + position[1] += view.mTop; + viewParent = view.mParent; } if (viewParent instanceof ViewRootImpl) { // *cough* - final ViewRootImpl vr = (ViewRootImpl)viewParent; - location[1] -= vr.mCurScrollY; + final ViewRootImpl vr = (ViewRootImpl) viewParent; + position[1] -= vr.mCurScrollY; } + + location[0] = (int) (position[0] + 0.5f); + location[1] = (int) (position[1] + 0.5f); } /** diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java index 3441f7e57d7f..9bd42ef03511 100644 --- a/core/java/android/view/ViewConfiguration.java +++ b/core/java/android/view/ViewConfiguration.java @@ -139,13 +139,29 @@ public class ViewConfiguration { private static final int EDGE_SLOP = 12; /** - * Distance a touch can wander before we think the user is scrolling in pixels + * Distance a touch can wander before we think the user is scrolling in dips. + * Note that this value defined here is only used as a fallback by legacy/misbehaving + * applications that do not provide a Context for determining density/configuration-dependent + * values. + * + * To alter this value, see the configuration resource config_viewConfigurationTouchSlop + * in frameworks/base/core/res/res/values/config.xml or the appropriate device resource overlay. + * It may be appropriate to tweak this on a device-specific basis in an overlay based on + * the characteristics of the touch panel and firmware. */ - private static final int TOUCH_SLOP = 16; + private static final int TOUCH_SLOP = 8; /** * Distance a touch can wander before we think the user is attempting a paged scroll * (in dips) + * + * Note that this value defined here is only used as a fallback by legacy/misbehaving + * applications that do not provide a Context for determining density/configuration-dependent + * values. + * + * See the note above on {@link #TOUCH_SLOP} regarding the dimen resource + * config_viewConfigurationTouchSlop. ViewConfiguration will report a paging touch slop of + * config_viewConfigurationTouchSlop * 2 when provided with a Context. */ private static final int PAGING_TOUCH_SLOP = TOUCH_SLOP * 2; @@ -277,8 +293,6 @@ public class ViewConfiguration { mMinimumFlingVelocity = (int) (density * MINIMUM_FLING_VELOCITY + 0.5f); mMaximumFlingVelocity = (int) (density * MAXIMUM_FLING_VELOCITY + 0.5f); mScrollbarSize = (int) (density * SCROLL_BAR_SIZE + 0.5f); - mTouchSlop = (int) (sizeAndDensity * TOUCH_SLOP + 0.5f); - mPagingTouchSlop = (int) (sizeAndDensity * PAGING_TOUCH_SLOP + 0.5f); mDoubleTapSlop = (int) (sizeAndDensity * DOUBLE_TAP_SLOP + 0.5f); mScaledTouchExplorationTapSlop = (int) (density * TOUCH_EXPLORATION_TAP_SLOP + 0.5f); mWindowTouchSlop = (int) (sizeAndDensity * WINDOW_TOUCH_SLOP + 0.5f); @@ -301,6 +315,9 @@ public class ViewConfiguration { mFadingMarqueeEnabled = res.getBoolean( com.android.internal.R.bool.config_ui_enableFadingMarquee); + mTouchSlop = res.getDimensionPixelSize( + com.android.internal.R.dimen.config_viewConfigurationTouchSlop); + mPagingTouchSlop = mTouchSlop * 2; } /** diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index e366e72976c0..600bfe6c7e3a 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -79,7 +79,7 @@ import java.util.HashSet; public abstract class ViewGroup extends View implements ViewParent, ViewManager { private static final boolean DBG = false; - + /** * Views which have been hidden or removed which need to be animated on * their way out. @@ -2719,13 +2719,6 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager return more; } - float alpha = child.getAlpha(); - // Bail out early if the view does not need to be drawn - if (alpha <= ViewConfiguration.ALPHA_THRESHOLD && (child.mPrivateFlags & ALPHA_SET) == 0 && - !(child instanceof SurfaceView)) { - return more; - } - if (hardwareAccelerated) { // Clear INVALIDATED flag to allow invalidation to occur during rendering, but // retain the flag's value temporarily in the mRecreateDisplayList flag @@ -2779,6 +2772,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager } } + float alpha = child.getAlpha(); if (transformToApply != null || alpha < 1.0f || !child.hasIdentityMatrix()) { if (transformToApply != null || !childHasIdentityMatrix) { int transX = 0; @@ -4182,15 +4176,42 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager * {@inheritDoc} */ public boolean getChildVisibleRect(View child, Rect r, android.graphics.Point offset) { + // The View is not attached to a window, 'visible' does not make sense, return false + if (mAttachInfo == null) return false; + + final RectF rect = mAttachInfo.mTmpTransformRect; + rect.set(r); + + if (!child.hasIdentityMatrix()) { + child.getMatrix().mapRect(rect); + } + int dx = child.mLeft - mScrollX; int dy = child.mTop - mScrollY; + + rect.offset(dx, dy); + if (offset != null) { + if (!child.hasIdentityMatrix()) { + float[] position = mAttachInfo.mTmpTransformLocation; + position[0] = offset.x; + position[1] = offset.y; + child.getMatrix().mapPoints(position); + offset.x = (int) (position[0] + 0.5f); + offset.y = (int) (position[1] + 0.5f); + } offset.x += dx; offset.y += dy; } - r.offset(dx, dy); - return r.intersect(0, 0, mRight - mLeft, mBottom - mTop) && - (mParent == null || mParent.getChildVisibleRect(this, r, offset)); + + if (rect.intersect(0, 0, mRight - mLeft, mBottom - mTop)) { + if (mParent == null) return true; + r.set((int) (rect.left + 0.5f), (int) (rect.top + 0.5f), + (int) (rect.right + 0.5f), (int) (rect.bottom + 0.5f)); + return mParent.getChildVisibleRect(this, r, offset); + } + + return false; } /** diff --git a/core/java/android/view/ViewParent.java b/core/java/android/view/ViewParent.java index 655df391ed4f..873d4bbd63fd 100644 --- a/core/java/android/view/ViewParent.java +++ b/core/java/android/view/ViewParent.java @@ -63,16 +63,16 @@ public interface ViewParent { /** * All or part of a child is dirty and needs to be redrawn. * - * The location array is an array of two int values which respectively - * define the left and the top position of the dirty child. + * <p>The location array is an array of two int values which respectively + * define the left and the top position of the dirty child.</p> * - * This method must return the parent of this ViewParent if the specified + * <p>This method must return the parent of this ViewParent if the specified * rectangle must be invalidated in the parent. If the specified rectangle * does not require invalidation in the parent or if the parent does not - * exist, this method must return null. + * exist, this method must return null.</p> * - * When this method returns a non-null value, the location array must - * have been updated with the left and top coordinates of this ViewParent. + * <p>When this method returns a non-null value, the location array must + * have been updated with the left and top coordinates of this ViewParent.</p> * * @param location An array of 2 ints containing the left and top * coordinates of the child to invalidate @@ -115,6 +115,26 @@ public interface ViewParent { */ public void clearChildFocus(View child); + /** + * Compute the visible part of a rectangular region defined in terms of a child view's + * coordinates. + * + * <p>Returns the clipped visible part of the rectangle <code>r</code>, defined in the + * <code>child</code>'s local coordinate system. <code>r</code> is modified by this method to + * contain the result, expressed in the global (root) coordinate system.</p> + * + * <p>The resulting rectangle is always axis aligned. If a rotation is applied to a node in the + * View hierarchy, the result is the axis-aligned bounding box of the visible rectangle.</p> + * + * @param child A child View, whose rectangular visible region we want to compute + * @param r The input rectangle, defined in the child coordinate system. Will be overwritten to + * contain the resulting visible rectangle, expressed in global (root) coordinates + * @param offset The input coordinates of a point, defined in the child coordinate system. + * As with the <code>r</code> parameter, this will be overwritten to contain the global (root) + * coordinates of that point. + * A <code>null</code> value is valid (in case you are not interested in this result) + * @return true if the resulting rectangle is not empty, false otherwise + */ public boolean getChildVisibleRect(View child, Rect r, android.graphics.Point offset); /** @@ -143,11 +163,11 @@ public interface ViewParent { /** * Bring up a context menu for the specified view or its ancestors. - * <p> - * In most cases, a subclass does not need to override this. However, if + * + * <p>In most cases, a subclass does not need to override this. However, if * the subclass is added directly to the window manager (for example, * {@link ViewManager#addView(View, android.view.ViewGroup.LayoutParams)}) - * then it should override this and show the context menu. + * then it should override this and show the context menu.</p> * * @param originalView The source view where the context menu was first invoked * @return true if a context menu was displayed @@ -164,11 +184,11 @@ public interface ViewParent { /** * Start an action mode for the specified view. - * <p> - * In most cases, a subclass does not need to override this. However, if the + * + * <p>In most cases, a subclass does not need to override this. However, if the * subclass is added directly to the window manager (for example, * {@link ViewManager#addView(View, android.view.ViewGroup.LayoutParams)}) - * then it should override this and start the action mode. + * then it should override this and start the action mode.</p> * * @param originalView The source view where the action mode was first invoked * @param callback The callback that will handle lifecycle events for the action mode @@ -188,10 +208,10 @@ public interface ViewParent { * Called when a child does not want this parent and its ancestors to * intercept touch events with * {@link ViewGroup#onInterceptTouchEvent(MotionEvent)}. - * <p> - * This parent should pass this call onto its parents. This parent must obey + * + * <p>This parent should pass this call onto its parents. This parent must obey * this request for the duration of the touch (that is, only clear the flag - * after this parent has received an up or a cancel. + * after this parent has received an up or a cancel.</p> * * @param disallowIntercept True if the child does not want the parent to * intercept touch events. @@ -234,7 +254,7 @@ public interface ViewParent { * the sending. The parent can optionally add a record for itself before * dispatching the request to its parent. A parent can also choose not to * respect the request for sending the event. The accessibility event is sent - * by the topmost view in the view tree. + * by the topmost view in the view tree.</p> * * @param child The child which requests sending the event. * @param event The event to be sent. diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index b15b155d9bc1..6c982eb5d751 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -576,6 +576,13 @@ public final class ViewRootImpl extends Handler implements ViewParent, } } + void terminateHardwareResources() { + if (mAttachInfo.mHardwareRenderer != null) { + mAttachInfo.mHardwareRenderer.destroyHardwareResources(mView); + mAttachInfo.mHardwareRenderer.destroy(false); + } + } + void destroyHardwareLayers() { if (mThread != Thread.currentThread()) { if (mAttachInfo.mHardwareRenderer != null && @@ -1209,7 +1216,8 @@ public final class ViewRootImpl extends Handler implements ViewParent, disposeResizeBuffer(); boolean completed = false; - HardwareCanvas canvas = null; + HardwareCanvas hwRendererCanvas = mAttachInfo.mHardwareRenderer.getCanvas(); + HardwareCanvas layerCanvas = null; try { if (mResizeBuffer == null) { mResizeBuffer = mAttachInfo.mHardwareRenderer.createHardwareLayer( @@ -1218,12 +1226,12 @@ public final class ViewRootImpl extends Handler implements ViewParent, mResizeBuffer.getHeight() != mHeight) { mResizeBuffer.resize(mWidth, mHeight); } - canvas = mResizeBuffer.start(mAttachInfo.mHardwareCanvas); - canvas.setViewport(mWidth, mHeight); - canvas.onPreDraw(null); - final int restoreCount = canvas.save(); + layerCanvas = mResizeBuffer.start(hwRendererCanvas); + layerCanvas.setViewport(mWidth, mHeight); + layerCanvas.onPreDraw(null); + final int restoreCount = layerCanvas.save(); - canvas.drawColor(0xff000000, PorterDuff.Mode.SRC); + layerCanvas.drawColor(0xff000000, PorterDuff.Mode.SRC); int yoff; final boolean scrolling = mScroller != null @@ -1235,27 +1243,27 @@ public final class ViewRootImpl extends Handler implements ViewParent, yoff = mScrollY; } - canvas.translate(0, -yoff); + layerCanvas.translate(0, -yoff); if (mTranslator != null) { - mTranslator.translateCanvas(canvas); + mTranslator.translateCanvas(layerCanvas); } - mView.draw(canvas); + mView.draw(layerCanvas); mResizeBufferStartTime = SystemClock.uptimeMillis(); mResizeBufferDuration = mView.getResources().getInteger( com.android.internal.R.integer.config_mediumAnimTime); completed = true; - canvas.restoreToCount(restoreCount); + layerCanvas.restoreToCount(restoreCount); } catch (OutOfMemoryError e) { Log.w(TAG, "Not enough memory for content change anim buffer", e); } finally { - if (canvas != null) { - canvas.onPostDraw(); + if (layerCanvas != null) { + layerCanvas.onPostDraw(); } if (mResizeBuffer != null) { - mResizeBuffer.end(mAttachInfo.mHardwareCanvas); + mResizeBuffer.end(hwRendererCanvas); if (!completed) { mResizeBuffer.destroy(); mResizeBuffer = null; @@ -1418,7 +1426,7 @@ public final class ViewRootImpl extends Handler implements ViewParent, if (!mStopped) { boolean focusChangedDueToTouchMode = ensureTouchModeLocally( - (relayoutResult&WindowManagerImpl.RELAYOUT_IN_TOUCH_MODE) != 0); + (relayoutResult&WindowManagerImpl.RELAYOUT_RES_IN_TOUCH_MODE) != 0); if (focusChangedDueToTouchMode || mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight() || contentInsetsChanged) { childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width); @@ -1629,7 +1637,7 @@ public final class ViewRootImpl extends Handler implements ViewParent, mLastDrawDurationNanos = System.nanoTime() - drawStartTime; } - if ((relayoutResult&WindowManagerImpl.RELAYOUT_FIRST_TIME) != 0 + if ((relayoutResult&WindowManagerImpl.RELAYOUT_RES_FIRST_TIME) != 0 || mReportNextDraw) { if (LOCAL_LOGV) { Log.v(TAG, "FINISHED DRAWING: " + mWindowAttributes.getTitle()); @@ -1662,7 +1670,7 @@ public final class ViewRootImpl extends Handler implements ViewParent, } // We were supposed to report when we are done drawing. Since we canceled the // draw, remember it here. - if ((relayoutResult&WindowManagerImpl.RELAYOUT_FIRST_TIME) != 0) { + if ((relayoutResult&WindowManagerImpl.RELAYOUT_RES_FIRST_TIME) != 0) { mReportNextDraw = true; } if (fullRedrawNeeded) { @@ -3322,8 +3330,9 @@ public final class ViewRootImpl extends Handler implements ViewParent, } // If the Control modifier is held, try to interpret the key as a shortcut. - if (event.getAction() == KeyEvent.ACTION_UP + if (event.getAction() == KeyEvent.ACTION_DOWN && event.isCtrlPressed() + && event.getRepeatCount() == 0 && !KeyEvent.isModifierKey(event.getKeyCode())) { if (mView.dispatchKeyShortcutEvent(event)) { finishKeyEvent(event, sendDone, true); @@ -3578,8 +3587,8 @@ public final class ViewRootImpl extends Handler implements ViewParent, mWindow, mSeq, params, (int) (mView.getMeasuredWidth() * appScale + 0.5f), (int) (mView.getMeasuredHeight() * appScale + 0.5f), - viewVisibility, insetsPending, mWinFrame, - mPendingContentInsets, mPendingVisibleInsets, + viewVisibility, insetsPending ? WindowManagerImpl.RELAYOUT_INSETS_PENDING : 0, + mWinFrame, mPendingContentInsets, mPendingVisibleInsets, mPendingConfiguration, mSurface); //Log.d(TAG, "<<<<<< BACK FROM relayout"); if (restore) { @@ -3709,7 +3718,7 @@ public final class ViewRootImpl extends Handler implements ViewParent, // animation info. try { if ((relayoutWindow(mWindowAttributes, viewVisibility, false) - & WindowManagerImpl.RELAYOUT_FIRST_TIME) != 0) { + & WindowManagerImpl.RELAYOUT_RES_FIRST_TIME) != 0) { sWindowSession.finishDrawing(mWindow); } } catch (RemoteException e) { diff --git a/core/java/android/view/VolumePanel.java b/core/java/android/view/VolumePanel.java index b657204d02fa..48fe0df89577 100644 --- a/core/java/android/view/VolumePanel.java +++ b/core/java/android/view/VolumePanel.java @@ -278,10 +278,6 @@ public class VolumePanel extends Handler implements OnSeekBarChangeListener, Vie } private void createSliders() { - final int silentableStreams = System.getInt(mContext.getContentResolver(), - System.MODE_RINGER_STREAMS_AFFECTED, - ((1 << AudioSystem.STREAM_NOTIFICATION) | (1 << AudioSystem.STREAM_RING))); - LayoutInflater inflater = (LayoutInflater) mContext .getSystemService(Context.LAYOUT_INFLATER_SERVICE); mStreamControls = new HashMap<Integer, StreamControl>(STREAMS.length); @@ -297,9 +293,6 @@ public class VolumePanel extends Handler implements OnSeekBarChangeListener, Vie sc.group = (ViewGroup) inflater.inflate(R.layout.volume_adjust_item, null); sc.group.setTag(sc); sc.icon = (ImageView) sc.group.findViewById(R.id.stream_icon); - if ((silentableStreams & (1 << sc.streamType)) != 0) { - sc.icon.setOnClickListener(this); - } sc.icon.setTag(sc); sc.icon.setContentDescription(res.getString(streamRes.descRes)); sc.iconRes = streamRes.iconRes; @@ -356,7 +349,6 @@ public class VolumePanel extends Handler implements OnSeekBarChangeListener, Vie && mAudioManager.shouldVibrate(AudioManager.VIBRATE_TYPE_RINGER)) { sc.icon.setImageResource(R.drawable.ic_audio_ring_notif_vibrate); } - sc.seekbarView.setEnabled(!muted); } private boolean isExpanded() { @@ -436,8 +428,6 @@ public class VolumePanel extends Handler implements OnSeekBarChangeListener, Vie mAudioService.getLastAudibleStreamVolume(streamType) : mAudioService.getStreamVolume(streamType); -// int message = UNKNOWN_VOLUME_TEXT; -// int additionalMessage = 0; mRingIsSilent = false; if (LOGD) { @@ -697,18 +687,6 @@ public class VolumePanel extends Handler implements OnSeekBarChangeListener, Vie public void onClick(View v) { if (v == mMoreButton) { expand(); - } else if (v.getTag() instanceof StreamControl) { - StreamControl sc = (StreamControl) v.getTag(); - boolean vibeInSilent = Settings.System.getInt(mContext.getContentResolver(), - System.VIBRATE_IN_SILENT, 1) == 1; - int newMode = mAudioManager.isSilentMode() - ? AudioManager.RINGER_MODE_NORMAL - : (vibeInSilent - ? AudioManager.RINGER_MODE_VIBRATE - : AudioManager.RINGER_MODE_SILENT); - mAudioManager.setRingerMode(newMode); - // Expand the dialog if it hasn't been expanded yet. - if (mShowCombinedVolumes && !isExpanded()) expand(); } resetTimeout(); } diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java index 660e3f44f065..d7113374bdc3 100644 --- a/core/java/android/view/WindowManagerImpl.java +++ b/core/java/android/view/WindowManagerImpl.java @@ -63,15 +63,34 @@ public class WindowManagerImpl implements WindowManager { * The user is navigating with keys (not the touch screen), so * navigational focus should be shown. */ - public static final int RELAYOUT_IN_TOUCH_MODE = 0x1; + public static final int RELAYOUT_RES_IN_TOUCH_MODE = 0x1; /** * This is the first time the window is being drawn, * so the client must call drawingFinished() when done */ - public static final int RELAYOUT_FIRST_TIME = 0x2; - + public static final int RELAYOUT_RES_FIRST_TIME = 0x2; + /** + * The window manager has changed the surface from the last call. + */ + public static final int RELAYOUT_RES_SURFACE_CHANGED = 0x4; + + /** + * Flag for relayout: the client will be later giving + * internal insets; as a result, the window will not impact other window + * layouts until the insets are given. + */ + public static final int RELAYOUT_INSETS_PENDING = 0x1; + + /** + * Flag for relayout: the client may be currently using the current surface, + * so if it is to be destroyed as a part of the relayout the destroy must + * be deferred until later. The client will call performDeferredDestroy() + * when it is okay. + */ + public static final int RELAYOUT_DEFER_SURFACE_DESTROY = 0x2; + public static final int ADD_FLAG_APP_VISIBLE = 0x2; - public static final int ADD_FLAG_IN_TOUCH_MODE = RELAYOUT_IN_TOUCH_MODE; + public static final int ADD_FLAG_IN_TOUCH_MODE = RELAYOUT_RES_IN_TOUCH_MODE; public static final int ADD_OKAY = 0; public static final int ADD_BAD_APP_TOKEN = -1; @@ -425,7 +444,7 @@ public class WindowManagerImpl implements WindowManager { if (mViews == null) return; int count = mViews.length; for (int i = 0; i < count; i++) { - mRoots[i].destroyHardwareResources(); + mRoots[i].terminateHardwareResources(); } } // Terminate the hardware renderer to free all resources diff --git a/core/java/android/view/accessibility/AccessibilityEvent.java b/core/java/android/view/accessibility/AccessibilityEvent.java index 86dd9df0cb0a..91dcac8db548 100644 --- a/core/java/android/view/accessibility/AccessibilityEvent.java +++ b/core/java/android/view/accessibility/AccessibilityEvent.java @@ -16,7 +16,6 @@ package android.view.accessibility; -import android.accessibilityservice.IAccessibilityServiceConnection; import android.os.Parcel; import android.os.Parcelable; import android.text.TextUtils; @@ -220,15 +219,6 @@ import java.util.List; * <li>{@link #isEnabled()} - Whether the source is enabled.</li> * <li>{@link #getContentDescription()} - The content description of the source.</li> * </ul> - * <em>Note:</em> This event type is not dispatched to descendants though - * {@link android.view.View#dispatchPopulateAccessibilityEvent(AccessibilityEvent) - * View.dispatchPopulateAccessibilityEvent(AccessibilityEvent)}, hence the event - * source {@link android.view.View} and the sub-tree rooted at it will not receive - * calls to {@link android.view.View#onPopulateAccessibilityEvent(AccessibilityEvent) - * View.onPopulateAccessibilityEvent(AccessibilityEvent)}. The preferred way to add - * text content to such events is by setting the - * {@link android.R.styleable#View_contentDescription contentDescription} of the source - * view.</br> * </p> * <p> * <b>View scrolled</b> - represents the event of scrolling a view. If @@ -599,24 +589,6 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par } /** - * Sets the connection for interacting with the AccessibilityManagerService. - * - * @param connection The connection. - * - * @hide - */ - @Override - public void setConnection(IAccessibilityServiceConnection connection) { - super.setConnection(connection); - List<AccessibilityRecord> records = mRecords; - final int recordCount = records.size(); - for (int i = 0; i < recordCount; i++) { - AccessibilityRecord record = records.get(i); - record.setConnection(connection); - } - } - - /** * Sets if this instance is sealed. * * @param sealed Whether is sealed. @@ -830,23 +802,19 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par * @param parcel A parcel containing the state of a {@link AccessibilityEvent}. */ public void initFromParcel(Parcel parcel) { - if (parcel.readInt() == 1) { - mConnection = IAccessibilityServiceConnection.Stub.asInterface( - parcel.readStrongBinder()); - } - setSealed(parcel.readInt() == 1); + mSealed = (parcel.readInt() == 1); mEventType = parcel.readInt(); mPackageName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel); mEventTime = parcel.readLong(); + mConnectionId = parcel.readInt(); readAccessibilityRecordFromParcel(this, parcel); // Read the records. final int recordCount = parcel.readInt(); for (int i = 0; i < recordCount; i++) { AccessibilityRecord record = AccessibilityRecord.obtain(); - // Do this to write the connection only once. - record.setConnection(mConnection); readAccessibilityRecordFromParcel(record, parcel); + record.mConnectionId = mConnectionId; mRecords.add(record); } } @@ -884,16 +852,11 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par * {@inheritDoc} */ public void writeToParcel(Parcel parcel, int flags) { - if (mConnection == null) { - parcel.writeInt(0); - } else { - parcel.writeInt(1); - parcel.writeStrongBinder(mConnection.asBinder()); - } parcel.writeInt(isSealed() ? 1 : 0); parcel.writeInt(mEventType); TextUtils.writeToParcel(mPackageName, parcel, 0); parcel.writeLong(mEventTime); + parcel.writeInt(mConnectionId); writeAccessibilityRecordToParcel(this, parcel, flags); // Write the records. diff --git a/core/java/android/view/accessibility/AccessibilityInteractionClient.java b/core/java/android/view/accessibility/AccessibilityInteractionClient.java index 25b980bc966e..96653e5dd632 100644 --- a/core/java/android/view/accessibility/AccessibilityInteractionClient.java +++ b/core/java/android/view/accessibility/AccessibilityInteractionClient.java @@ -21,6 +21,8 @@ import android.graphics.Rect; import android.os.Message; import android.os.RemoteException; import android.os.SystemClock; +import android.util.Log; +import android.util.SparseArray; import java.util.Collections; import java.util.List; @@ -61,6 +63,12 @@ import java.util.concurrent.atomic.AtomicInteger; public final class AccessibilityInteractionClient extends IAccessibilityInteractionConnectionCallback.Stub { + public static final int NO_ID = -1; + + private static final String LOG_TAG = "AccessibilityInteractionClient"; + + private static final boolean DEBUG = false; + private static final long TIMEOUT_INTERACTION_MILLIS = 5000; private static final Object sStaticLock = new Object(); @@ -83,6 +91,10 @@ public final class AccessibilityInteractionClient private final Rect mTempBounds = new Rect(); + // The connection cache is shared between all interrogating threads. + private static final SparseArray<IAccessibilityServiceConnection> sConnectionCache = + new SparseArray<IAccessibilityServiceConnection>(); + /** * @return The singleton of this class. */ @@ -111,28 +123,37 @@ public final class AccessibilityInteractionClient /** * Finds an {@link AccessibilityNodeInfo} by accessibility id. * - * @param connection A connection for interacting with the system. + * @param connectionId The id of a connection for interacting with the system. * @param accessibilityWindowId A unique window id. * @param accessibilityViewId A unique View accessibility id. * @return An {@link AccessibilityNodeInfo} if found, null otherwise. */ - public AccessibilityNodeInfo findAccessibilityNodeInfoByAccessibilityId( - IAccessibilityServiceConnection connection, int accessibilityWindowId, - int accessibilityViewId) { + public AccessibilityNodeInfo findAccessibilityNodeInfoByAccessibilityId(int connectionId, + int accessibilityWindowId, int accessibilityViewId) { try { - final int interactionId = mInteractionIdCounter.getAndIncrement(); - final float windowScale = connection.findAccessibilityNodeInfoByAccessibilityId( - accessibilityWindowId, accessibilityViewId, interactionId, this, - Thread.currentThread().getId()); - // If the scale is zero the call has failed. - if (windowScale > 0) { - AccessibilityNodeInfo info = getFindAccessibilityNodeInfoResultAndClear( - interactionId); - finalizeAccessibilityNodeInfo(info, connection, windowScale); - return info; + IAccessibilityServiceConnection connection = getConnection(connectionId); + if (connection != null) { + final int interactionId = mInteractionIdCounter.getAndIncrement(); + final float windowScale = connection.findAccessibilityNodeInfoByAccessibilityId( + accessibilityWindowId, accessibilityViewId, interactionId, this, + Thread.currentThread().getId()); + // If the scale is zero the call has failed. + if (windowScale > 0) { + AccessibilityNodeInfo info = getFindAccessibilityNodeInfoResultAndClear( + interactionId); + finalizeAccessibilityNodeInfo(info, connectionId, windowScale); + return info; + } + } else { + if (DEBUG) { + Log.w(LOG_TAG, "No connection for connection id: " + connectionId); + } } } catch (RemoteException re) { - /* ignore */ + if (DEBUG) { + Log.w(LOG_TAG, "Error while calling remote" + + " findAccessibilityNodeInfoByAccessibilityId", re); + } } return null; } @@ -141,25 +162,36 @@ public final class AccessibilityInteractionClient * Finds an {@link AccessibilityNodeInfo} by View id. The search is performed * in the currently active window and starts from the root View in the window. * - * @param connection A connection for interacting with the system. + * @param connectionId The id of a connection for interacting with the system. * @param viewId The id of the view. * @return An {@link AccessibilityNodeInfo} if found, null otherwise. */ - public AccessibilityNodeInfo findAccessibilityNodeInfoByViewIdInActiveWindow( - IAccessibilityServiceConnection connection, int viewId) { + public AccessibilityNodeInfo findAccessibilityNodeInfoByViewIdInActiveWindow(int connectionId, + int viewId) { try { - final int interactionId = mInteractionIdCounter.getAndIncrement(); - final float windowScale = connection.findAccessibilityNodeInfoByViewIdInActiveWindow( - viewId, interactionId, this, Thread.currentThread().getId()); - // If the scale is zero the call has failed. - if (windowScale > 0) { - AccessibilityNodeInfo info = getFindAccessibilityNodeInfoResultAndClear( - interactionId); - finalizeAccessibilityNodeInfo(info, connection, windowScale); - return info; + IAccessibilityServiceConnection connection = getConnection(connectionId); + if (connection != null) { + final int interactionId = mInteractionIdCounter.getAndIncrement(); + final float windowScale = + connection.findAccessibilityNodeInfoByViewIdInActiveWindow(viewId, + interactionId, this, Thread.currentThread().getId()); + // If the scale is zero the call has failed. + if (windowScale > 0) { + AccessibilityNodeInfo info = getFindAccessibilityNodeInfoResultAndClear( + interactionId); + finalizeAccessibilityNodeInfo(info, connectionId, windowScale); + return info; + } + } else { + if (DEBUG) { + Log.w(LOG_TAG, "No connection for connection id: " + connectionId); + } } } catch (RemoteException re) { - /* ignore */ + if (DEBUG) { + Log.w(LOG_TAG, "Error while calling remote" + + " findAccessibilityNodeInfoByViewIdInActiveWindow", re); + } } return null; } @@ -169,25 +201,36 @@ public final class AccessibilityInteractionClient * insensitive containment. The search is performed in the currently * active window and starts from the root View in the window. * - * @param connection A connection for interacting with the system. + * @param connectionId The id of a connection for interacting with the system. * @param text The searched text. * @return A list of found {@link AccessibilityNodeInfo}s. */ public List<AccessibilityNodeInfo> findAccessibilityNodeInfosByViewTextInActiveWindow( - IAccessibilityServiceConnection connection, String text) { + int connectionId, String text) { try { - final int interactionId = mInteractionIdCounter.getAndIncrement(); - final float windowScale = connection.findAccessibilityNodeInfosByViewTextInActiveWindow( - text, interactionId, this, Thread.currentThread().getId()); - // If the scale is zero the call has failed. - if (windowScale > 0) { - List<AccessibilityNodeInfo> infos = getFindAccessibilityNodeInfosResultAndClear( - interactionId); - finalizeAccessibilityNodeInfos(infos, connection, windowScale); - return infos; + IAccessibilityServiceConnection connection = getConnection(connectionId); + if (connection != null) { + final int interactionId = mInteractionIdCounter.getAndIncrement(); + final float windowScale = + connection.findAccessibilityNodeInfosByViewTextInActiveWindow(text, + interactionId, this, Thread.currentThread().getId()); + // If the scale is zero the call has failed. + if (windowScale > 0) { + List<AccessibilityNodeInfo> infos = getFindAccessibilityNodeInfosResultAndClear( + interactionId); + finalizeAccessibilityNodeInfos(infos, connectionId, windowScale); + return infos; + } + } else { + if (DEBUG) { + Log.w(LOG_TAG, "No connection for connection id: " + connectionId); + } } } catch (RemoteException re) { - /* ignore */ + if (DEBUG) { + Log.w(LOG_TAG, "Error while calling remote" + + " findAccessibilityNodeInfosByViewTextInActiveWindow", re); + } } return null; } @@ -198,30 +241,39 @@ public final class AccessibilityInteractionClient * id is specified and starts from the View whose accessibility id is * specified. * - * @param connection A connection for interacting with the system. + * @param connectionId The id of a connection for interacting with the system. * @param text The searched text. * @param accessibilityWindowId A unique window id. * @param accessibilityViewId A unique View accessibility id from where to start the search. * Use {@link android.view.View#NO_ID} to start from the root. * @return A list of found {@link AccessibilityNodeInfo}s. */ - public List<AccessibilityNodeInfo> findAccessibilityNodeInfosByViewText( - IAccessibilityServiceConnection connection, String text, int accessibilityWindowId, - int accessibilityViewId) { + public List<AccessibilityNodeInfo> findAccessibilityNodeInfosByViewText(int connectionId, + String text, int accessibilityWindowId, int accessibilityViewId) { try { - final int interactionId = mInteractionIdCounter.getAndIncrement(); - final float windowScale = connection.findAccessibilityNodeInfosByViewText(text, - accessibilityWindowId, accessibilityViewId, interactionId, this, - Thread.currentThread().getId()); - // If the scale is zero the call has failed. - if (windowScale > 0) { - List<AccessibilityNodeInfo> infos = getFindAccessibilityNodeInfosResultAndClear( - interactionId); - finalizeAccessibilityNodeInfos(infos, connection, windowScale); - return infos; + IAccessibilityServiceConnection connection = getConnection(connectionId); + if (connection != null) { + final int interactionId = mInteractionIdCounter.getAndIncrement(); + final float windowScale = connection.findAccessibilityNodeInfosByViewText(text, + accessibilityWindowId, accessibilityViewId, interactionId, this, + Thread.currentThread().getId()); + // If the scale is zero the call has failed. + if (windowScale > 0) { + List<AccessibilityNodeInfo> infos = getFindAccessibilityNodeInfosResultAndClear( + interactionId); + finalizeAccessibilityNodeInfos(infos, connectionId, windowScale); + return infos; + } + } else { + if (DEBUG) { + Log.w(LOG_TAG, "No connection for connection id: " + connectionId); + } } } catch (RemoteException re) { - /* ignore */ + if (DEBUG) { + Log.w(LOG_TAG, "Error while calling remote" + + " findAccessibilityNodeInfosByViewText", re); + } } return Collections.emptyList(); } @@ -229,24 +281,33 @@ public final class AccessibilityInteractionClient /** * Performs an accessibility action on an {@link AccessibilityNodeInfo}. * - * @param connection A connection for interacting with the system. + * @param connectionId The id of a connection for interacting with the system. * @param accessibilityWindowId The id of the window. * @param accessibilityViewId A unique View accessibility id. * @param action The action to perform. * @return Whether the action was performed. */ - public boolean performAccessibilityAction(IAccessibilityServiceConnection connection, - int accessibilityWindowId, int accessibilityViewId, int action) { + public boolean performAccessibilityAction(int connectionId, int accessibilityWindowId, + int accessibilityViewId, int action) { try { - final int interactionId = mInteractionIdCounter.getAndIncrement(); - final boolean success = connection.performAccessibilityAction( - accessibilityWindowId, accessibilityViewId, action, interactionId, this, - Thread.currentThread().getId()); - if (success) { - return getPerformAccessibilityActionResult(interactionId); + IAccessibilityServiceConnection connection = getConnection(connectionId); + if (connection != null) { + final int interactionId = mInteractionIdCounter.getAndIncrement(); + final boolean success = connection.performAccessibilityAction( + accessibilityWindowId, accessibilityViewId, action, interactionId, this, + Thread.currentThread().getId()); + if (success) { + return getPerformAccessibilityActionResult(interactionId); + } + } else { + if (DEBUG) { + Log.w(LOG_TAG, "No connection for connection id: " + connectionId); + } } } catch (RemoteException re) { - /* ignore */ + if (DEBUG) { + Log.w(LOG_TAG, "Error while calling remote performAccessibilityAction", re); + } } return false; } @@ -406,14 +467,14 @@ public final class AccessibilityInteractionClient * Finalize an {@link AccessibilityNodeInfo} before passing it to the client. * * @param info The info. - * @param connection The current connection to the system. + * @param connectionId The id of the connection to the system. * @param windowScale The source window compatibility scale. */ - private void finalizeAccessibilityNodeInfo(AccessibilityNodeInfo info, - IAccessibilityServiceConnection connection, float windowScale) { + private void finalizeAccessibilityNodeInfo(AccessibilityNodeInfo info, int connectionId, + float windowScale) { if (info != null) { applyCompatibilityScaleIfNeeded(info, windowScale); - info.setConnection(connection); + info.setConnectionId(connectionId); info.setSealed(true); } } @@ -422,16 +483,16 @@ public final class AccessibilityInteractionClient * Finalize {@link AccessibilityNodeInfo}s before passing them to the client. * * @param infos The {@link AccessibilityNodeInfo}s. - * @param connection The current connection to the system. + * @param connectionId The id of the connection to the system. * @param windowScale The source window compatibility scale. */ private void finalizeAccessibilityNodeInfos(List<AccessibilityNodeInfo> infos, - IAccessibilityServiceConnection connection, float windowScale) { + int connectionId, float windowScale) { if (infos != null) { final int infosCount = infos.size(); for (int i = 0; i < infosCount; i++) { AccessibilityNodeInfo info = infos.get(i); - finalizeAccessibilityNodeInfo(info, connection, windowScale); + finalizeAccessibilityNodeInfo(info, connectionId, windowScale); } } } @@ -449,4 +510,39 @@ public final class AccessibilityInteractionClient return result; } } + + /** + * Gets a cached accessibility service connection. + * + * @param connectionId The connection id. + * @return The cached connection if such. + */ + public IAccessibilityServiceConnection getConnection(int connectionId) { + synchronized (sConnectionCache) { + return sConnectionCache.get(connectionId); + } + } + + /** + * Adds a cached accessibility service connection. + * + * @param connectionId The connection id. + * @param connection The connection. + */ + public void addConnection(int connectionId, IAccessibilityServiceConnection connection) { + synchronized (sConnectionCache) { + sConnectionCache.put(connectionId, connection); + } + } + + /** + * Removes a cached accessibility service connection. + * + * @param connectionId The connection id. + */ + public void removeConnection(int connectionId) { + synchronized (sConnectionCache) { + sConnectionCache.remove(connectionId); + } + } } diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java index fa34ee747bc4..9b0f44a55614 100644 --- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java +++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java @@ -16,7 +16,6 @@ package android.view.accessibility; -import android.accessibilityservice.IAccessibilityServiceConnection; import android.graphics.Rect; import android.os.Parcel; import android.os.Parcelable; @@ -53,6 +52,8 @@ public class AccessibilityNodeInfo implements Parcelable { private static final boolean DEBUG = false; + private static final int UNDEFINED = -1; + // Actions. /** @@ -107,9 +108,9 @@ public class AccessibilityNodeInfo implements Parcelable { private boolean mSealed; // Data. - private int mAccessibilityViewId = View.NO_ID; - private int mAccessibilityWindowId = View.NO_ID; - private int mParentAccessibilityViewId = View.NO_ID; + private int mAccessibilityViewId = UNDEFINED; + private int mAccessibilityWindowId = UNDEFINED; + private int mParentAccessibilityViewId = UNDEFINED; private int mBooleanProperties; private final Rect mBoundsInParent = new Rect(); private final Rect mBoundsInScreen = new Rect(); @@ -122,7 +123,7 @@ public class AccessibilityNodeInfo implements Parcelable { private SparseIntArray mChildAccessibilityIds = new SparseIntArray(); private int mActions; - private IAccessibilityServiceConnection mConnection; + private int mConnectionId = UNDEFINED; /** * Hide constructor from clients. @@ -181,7 +182,7 @@ public class AccessibilityNodeInfo implements Parcelable { return null; } AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance(); - return client.findAccessibilityNodeInfoByAccessibilityId(mConnection, + return client.findAccessibilityNodeInfoByAccessibilityId(mConnectionId, mAccessibilityWindowId, childAccessibilityViewId); } @@ -253,7 +254,7 @@ public class AccessibilityNodeInfo implements Parcelable { return false; } AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance(); - return client.performAccessibilityAction(mConnection, mAccessibilityWindowId, + return client.performAccessibilityAction(mConnectionId, mAccessibilityWindowId, mAccessibilityViewId, action); } @@ -277,7 +278,7 @@ public class AccessibilityNodeInfo implements Parcelable { return Collections.emptyList(); } AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance(); - return client.findAccessibilityNodeInfosByViewText(mConnection, text, + return client.findAccessibilityNodeInfosByViewText(mConnectionId, text, mAccessibilityWindowId, mAccessibilityViewId); } @@ -297,7 +298,7 @@ public class AccessibilityNodeInfo implements Parcelable { return null; } AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance(); - return client.findAccessibilityNodeInfoByAccessibilityId(mConnection, + return client.findAccessibilityNodeInfoByAccessibilityId(mConnectionId, mAccessibilityWindowId, mParentAccessibilityViewId); } @@ -755,15 +756,16 @@ public class AccessibilityNodeInfo implements Parcelable { } /** - * Sets the connection for interacting with the system. + * Sets the unique id of the IAccessibilityServiceConnection over which + * this instance can send requests to the system. * - * @param connection The client token. + * @param connectionId The connection id. * * @hide */ - public final void setConnection(IAccessibilityServiceConnection connection) { + public void setConnectionId(int connectionId) { enforceNotSealed(); - mConnection = connection; + mConnectionId = connectionId; } /** @@ -900,16 +902,11 @@ public class AccessibilityNodeInfo implements Parcelable { * </p> */ public void writeToParcel(Parcel parcel, int flags) { - if (mConnection == null) { - parcel.writeInt(0); - } else { - parcel.writeInt(1); - parcel.writeStrongBinder(mConnection.asBinder()); - } parcel.writeInt(isSealed() ? 1 : 0); parcel.writeInt(mAccessibilityViewId); parcel.writeInt(mAccessibilityWindowId); parcel.writeInt(mParentAccessibilityViewId); + parcel.writeInt(mConnectionId); SparseIntArray childIds = mChildAccessibilityIds; final int childIdsSize = childIds.size(); @@ -949,10 +946,10 @@ public class AccessibilityNodeInfo implements Parcelable { */ private void init(AccessibilityNodeInfo other) { mSealed = other.mSealed; - mConnection = other.mConnection; mAccessibilityViewId = other.mAccessibilityViewId; mParentAccessibilityViewId = other.mParentAccessibilityViewId; mAccessibilityWindowId = other.mAccessibilityWindowId; + mConnectionId = other.mConnectionId; mBoundsInParent.set(other.mBoundsInParent); mBoundsInScreen.set(other.mBoundsInScreen); mPackageName = other.mPackageName; @@ -970,14 +967,11 @@ public class AccessibilityNodeInfo implements Parcelable { * @param parcel A parcel containing the state of a {@link AccessibilityNodeInfo}. */ private void initFromParcel(Parcel parcel) { - if (parcel.readInt() == 1) { - mConnection = IAccessibilityServiceConnection.Stub.asInterface( - parcel.readStrongBinder()); - } mSealed = (parcel.readInt() == 1); mAccessibilityViewId = parcel.readInt(); mAccessibilityWindowId = parcel.readInt(); mParentAccessibilityViewId = parcel.readInt(); + mConnectionId = parcel.readInt(); SparseIntArray childIds = mChildAccessibilityIds; final int childrenSize = parcel.readInt(); @@ -1011,10 +1005,10 @@ public class AccessibilityNodeInfo implements Parcelable { */ private void clear() { mSealed = false; - mConnection = null; - mAccessibilityViewId = View.NO_ID; - mParentAccessibilityViewId = View.NO_ID; - mAccessibilityWindowId = View.NO_ID; + mAccessibilityViewId = UNDEFINED; + mParentAccessibilityViewId = UNDEFINED; + mAccessibilityWindowId = UNDEFINED; + mConnectionId = UNDEFINED; mChildAccessibilityIds.clear(); mBoundsInParent.set(0, 0, 0, 0); mBoundsInScreen.set(0, 0, 0, 0); @@ -1048,9 +1042,8 @@ public class AccessibilityNodeInfo implements Parcelable { } private boolean canPerformRequestOverConnection(int accessibilityViewId) { - return (mAccessibilityWindowId != View.NO_ID - && accessibilityViewId != View.NO_ID - && mConnection != null); + return (mConnectionId != UNDEFINED && mAccessibilityWindowId != UNDEFINED + && accessibilityViewId != UNDEFINED); } @Override diff --git a/core/java/android/view/accessibility/AccessibilityRecord.java b/core/java/android/view/accessibility/AccessibilityRecord.java index a4e0688e22fa..18d0f6fe8a27 100644 --- a/core/java/android/view/accessibility/AccessibilityRecord.java +++ b/core/java/android/view/accessibility/AccessibilityRecord.java @@ -16,7 +16,6 @@ package android.view.accessibility; -import android.accessibilityservice.IAccessibilityServiceConnection; import android.os.Parcelable; import android.view.View; @@ -78,8 +77,8 @@ public class AccessibilityRecord { int mAddedCount= UNDEFINED; int mRemovedCount = UNDEFINED; - int mSourceViewId = View.NO_ID; - int mSourceWindowId = View.NO_ID; + int mSourceViewId = UNDEFINED; + int mSourceWindowId = UNDEFINED; CharSequence mClassName; CharSequence mContentDescription; @@ -87,7 +86,8 @@ public class AccessibilityRecord { Parcelable mParcelableData; final List<CharSequence> mText = new ArrayList<CharSequence>(); - IAccessibilityServiceConnection mConnection; + + int mConnectionId = UNDEFINED; /* * Hide constructor. @@ -108,8 +108,8 @@ public class AccessibilityRecord { mSourceWindowId = source.getAccessibilityWindowId(); mSourceViewId = source.getAccessibilityViewId(); } else { - mSourceWindowId = View.NO_ID; - mSourceViewId = View.NO_ID; + mSourceWindowId = UNDEFINED; + mSourceViewId = UNDEFINED; } } @@ -119,33 +119,21 @@ public class AccessibilityRecord { * <strong>Note:</strong> It is a client responsibility to recycle the received info * by calling {@link AccessibilityNodeInfo#recycle() AccessibilityNodeInfo#recycle()} * to avoid creating of multiple instances. - * * </p> * @return The info of the source. */ public AccessibilityNodeInfo getSource() { enforceSealed(); - if (mSourceWindowId == View.NO_ID || mSourceViewId == View.NO_ID || mConnection == null) { + if (mConnectionId == UNDEFINED || mSourceWindowId == UNDEFINED + || mSourceViewId == UNDEFINED) { return null; } AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance(); - return client.findAccessibilityNodeInfoByAccessibilityId(mConnection, mSourceWindowId, + return client.findAccessibilityNodeInfoByAccessibilityId(mConnectionId, mSourceWindowId, mSourceViewId); } /** - * Sets the connection for interacting with the AccessibilityManagerService. - * - * @param connection The connection. - * - * @hide - */ - public void setConnection(IAccessibilityServiceConnection connection) { - enforceNotSealed(); - mConnection = connection; - } - - /** * Gets the id of the window from which the event comes from. * * @return The window id. @@ -561,6 +549,19 @@ public class AccessibilityRecord { } /** + * Sets the unique id of the IAccessibilityServiceConnection over which + * this instance can send requests to the system. + * + * @param connectionId The connection id. + * + * @hide + */ + public void setConnectionId(int connectionId) { + enforceNotSealed(); + mConnectionId = connectionId; + } + + /** * Sets if this instance is sealed. * * @param sealed Whether is sealed. @@ -708,7 +709,7 @@ public class AccessibilityRecord { mText.addAll(record.mText); mSourceWindowId = record.mSourceWindowId; mSourceViewId = record.mSourceViewId; - mConnection = record.mConnection; + mConnectionId = record.mConnectionId; } /** @@ -732,8 +733,9 @@ public class AccessibilityRecord { mBeforeText = null; mParcelableData = null; mText.clear(); - mSourceViewId = View.NO_ID; - mSourceWindowId = View.NO_ID; + mSourceViewId = UNDEFINED; + mSourceWindowId = UNDEFINED; + mConnectionId = UNDEFINED; } @Override diff --git a/core/java/android/view/accessibility/IAccessibilityManager.aidl b/core/java/android/view/accessibility/IAccessibilityManager.aidl index c621ff6d2d60..c3794bec3ef0 100644 --- a/core/java/android/view/accessibility/IAccessibilityManager.aidl +++ b/core/java/android/view/accessibility/IAccessibilityManager.aidl @@ -49,5 +49,5 @@ interface IAccessibilityManager { void removeAccessibilityInteractionConnection(IWindow windowToken); - IAccessibilityServiceConnection registerEventListener(IEventListener client); + void registerEventListener(IEventListener client); } diff --git a/core/java/android/webkit/CookieManager.java b/core/java/android/webkit/CookieManager.java index d6e36bb5eeb3..9fa5593e7ad9 100644 --- a/core/java/android/webkit/CookieManager.java +++ b/core/java/android/webkit/CookieManager.java @@ -345,6 +345,11 @@ public final class CookieManager { * a system private class. */ public synchronized void setCookie(WebAddress uri, String value) { + if (JniUtil.useChromiumHttpStack()) { + nativeSetCookie(uri.toString(), value, false); + return; + } + if (value != null && value.length() > MAX_COOKIE_LENGTH) { return; } @@ -500,6 +505,10 @@ public final class CookieManager { * is a system private class. */ public synchronized String getCookie(WebAddress uri) { + if (JniUtil.useChromiumHttpStack()) { + return nativeGetCookie(uri.toString(), false); + } + if (!mAcceptCookie || uri == null) { return null; } @@ -573,6 +582,8 @@ public final class CookieManager { * {@hide} Too late to release publically. */ public void waitForCookieOperationsToComplete() { + // Note that this function is applicable for both the java + // and native http stacks, and works correctly with either. synchronized (this) { while (pendingCookieOperations > 0) { try { diff --git a/core/java/android/webkit/HTML5VideoFullScreen.java b/core/java/android/webkit/HTML5VideoFullScreen.java index f29aff29bf05..e1eff58670d5 100644 --- a/core/java/android/webkit/HTML5VideoFullScreen.java +++ b/core/java/android/webkit/HTML5VideoFullScreen.java @@ -4,15 +4,12 @@ package android.webkit; import android.content.Context; import android.media.MediaPlayer; import android.media.Metadata; -import android.util.Log; import android.view.Gravity; import android.view.MotionEvent; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.view.View; import android.view.ViewGroup; -import android.webkit.HTML5VideoView; -import android.webkit.HTML5VideoViewProxy; import android.widget.FrameLayout; import android.widget.MediaController; import android.widget.MediaController.MediaPlayerControl; @@ -150,7 +147,7 @@ public class HTML5VideoFullScreen extends HTML5VideoView private void prepareForFullScreen() { // So in full screen, we reset the MediaPlayer mPlayer.reset(); - MediaController mc = new MediaController(mProxy.getContext()); + MediaController mc = new FullScreenMediaController(mProxy.getContext(), mLayout); mc.setSystemUiVisibility(mLayout.getSystemUiVisibility()); setMediaController(mc); mPlayer.setScreenOnWhilePlaying(true); @@ -261,7 +258,6 @@ public class HTML5VideoFullScreen extends HTML5VideoView mLayout.addView(getSurfaceView(), layoutParams); mLayout.setVisibility(View.VISIBLE); - WebChromeClient client = webView.getWebChromeClient(); if (client != null) { client.onShowCustomView(mLayout, mCallback); @@ -338,4 +334,33 @@ public class HTML5VideoFullScreen extends HTML5VideoView } return; } + + static class FullScreenMediaController extends MediaController { + + View mVideoView; + + public FullScreenMediaController(Context context, View video) { + super(context); + mVideoView = video; + } + + @Override + public void show() { + super.show(); + if (mVideoView != null) { + mVideoView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE); + } + } + + @Override + public void hide() { + if (mVideoView != null) { + mVideoView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE + | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION); + } + super.hide(); + } + + } + } diff --git a/core/java/android/webkit/WebTextView.java b/core/java/android/webkit/WebTextView.java index f18a39679c9b..2b59b80cd889 100644 --- a/core/java/android/webkit/WebTextView.java +++ b/core/java/android/webkit/WebTextView.java @@ -19,10 +19,13 @@ package android.webkit; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; +import android.graphics.ColorFilter; import android.graphics.Paint; import android.graphics.Paint.Style; +import android.graphics.PixelFormat; import android.graphics.Rect; import android.graphics.drawable.ColorDrawable; +import android.graphics.drawable.Drawable; import android.os.Bundle; import android.os.Handler; import android.os.Message; @@ -51,7 +54,6 @@ import android.view.ViewGroup; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputConnection; import android.view.inputmethod.InputMethodManager; -import android.widget.AbsoluteLayout; import android.widget.AbsoluteLayout.LayoutParams; import android.widget.AdapterView; import android.widget.ArrayAdapter; @@ -74,7 +76,6 @@ import java.util.ArrayList; static final String LOGTAG = "webtextview"; - private Paint mRingPaint; private int mRingInset; private WebView mWebView; @@ -207,13 +208,51 @@ import java.util.ArrayList; } } }; - float ringWidth = 4f * context.getResources().getDisplayMetrics().density; mReceiver = new MyResultReceiver(mHandler); - mRingPaint = new Paint(); - mRingPaint.setColor(0x6633b5e5); - mRingPaint.setStrokeWidth(ringWidth); - mRingPaint.setStyle(Style.FILL); + float ringWidth = 2f * context.getResources().getDisplayMetrics().density; mRingInset = (int) ringWidth; + setBackgroundDrawable(new BackgroundDrawable(mRingInset)); + setPadding(getPaddingLeft(), getPaddingTop(), getPaddingRight(), + getPaddingBottom()); + } + + private static class BackgroundDrawable extends Drawable { + + private Paint mPaint = new Paint(); + private int mBorderWidth; + private Rect mInsetRect = new Rect(); + + public BackgroundDrawable(int width) { + mPaint = new Paint(); + mPaint.setStrokeWidth(width); + mBorderWidth = width; + } + + @Override + public void draw(Canvas canvas) { + mPaint.setColor(0x6633b5e5); + canvas.drawRect(getBounds(), mPaint); + mInsetRect.left = getBounds().left + mBorderWidth; + mInsetRect.top = getBounds().top + mBorderWidth; + mInsetRect.right = getBounds().right - mBorderWidth; + mInsetRect.bottom = getBounds().bottom - mBorderWidth; + mPaint.setColor(Color.WHITE); + canvas.drawRect(mInsetRect, mPaint); + } + + @Override + public void setAlpha(int alpha) { + } + + @Override + public void setColorFilter(ColorFilter cf) { + } + + @Override + public int getOpacity() { + return PixelFormat.TRANSLUCENT; + } + } public void setAutoFillable(int queryId) { @@ -223,37 +262,9 @@ import java.util.ArrayList; } @Override - protected void onDraw(Canvas canvas) { - super.onDraw(canvas); - if (isFocused()) { - final int ib = getHeight() - mRingInset; - canvas.drawRect(0, 0, getWidth(), mRingInset, mRingPaint); - canvas.drawRect(0, ib, getWidth(), getHeight(), mRingPaint); - canvas.drawRect(0, mRingInset, mRingInset, ib, mRingPaint); - canvas.drawRect(getWidth() - mRingInset, mRingInset, getWidth(), ib, mRingPaint); - } - } - - private void growOrShrink(boolean grow) { - AbsoluteLayout.LayoutParams lp = (AbsoluteLayout.LayoutParams) getLayoutParams(); - if (grow) { - Log.i("webtextview", "grow"); - lp.x -= mRingInset; - lp.y -= mRingInset; - lp.width += 2 * mRingInset; - lp.height += 2 * mRingInset; - setPadding(getPaddingLeft() + mRingInset, getPaddingTop() + mRingInset, - getPaddingRight() + mRingInset, getPaddingBottom() + mRingInset); - } else { - Log.i("webtextview", "shrink"); - lp.x += mRingInset; - lp.y += mRingInset; - lp.width -= 2 * mRingInset; - lp.height -= 2 * mRingInset; - setPadding(getPaddingLeft() - mRingInset, getPaddingTop() - mRingInset, - getPaddingRight() - mRingInset, getPaddingBottom() - mRingInset); - } - setLayoutParams(lp); + public void setPadding(int left, int top, int right, int bottom) { + super.setPadding(left + mRingInset, top + mRingInset, + right + mRingInset, bottom + mRingInset); } @Override @@ -557,7 +568,6 @@ import java.util.ArrayList; } else if (!mInsideRemove) { mWebView.setActive(false); } - growOrShrink(focused); mFromFocusChange = false; } @@ -968,6 +978,10 @@ import java.util.ArrayList; */ /* package */ void setRect(int x, int y, int width, int height) { LayoutParams lp = (LayoutParams) getLayoutParams(); + x -= mRingInset; + y -= mRingInset; + width += 2 * mRingInset; + height += 2 * mRingInset; boolean needsUpdate = false; if (null == lp) { lp = new LayoutParams(width, height, x, y); diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java index 35fd945a76a0..24eebd7594b7 100644 --- a/core/java/android/webkit/WebView.java +++ b/core/java/android/webkit/WebView.java @@ -17,6 +17,7 @@ package android.webkit; import android.annotation.Widget; +import android.app.ActivityManager; import android.app.AlertDialog; import android.content.BroadcastReceiver; import android.content.ClipboardManager; @@ -61,6 +62,7 @@ import android.speech.tts.TextToSpeech; import android.util.AttributeSet; import android.util.EventLog; import android.util.Log; +import android.view.Display; import android.view.Gravity; import android.view.HapticFeedbackConstants; import android.view.HardwareCanvas; @@ -77,6 +79,7 @@ import android.view.ViewConfiguration; import android.view.ViewGroup; import android.view.ViewParent; import android.view.ViewTreeObserver; +import android.view.WindowManager; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityManager; import android.view.accessibility.AccessibilityNodeInfo; @@ -366,6 +369,7 @@ public class WebView extends AbsoluteLayout private final Rect mGLRectViewport = new Rect(); private final Rect mViewRectViewport = new Rect(); + private final RectF mVisibleContentRect = new RectF(); private boolean mGLViewportEmpty = false; /** @@ -503,7 +507,7 @@ public class WebView extends AbsoluteLayout private float mLastVelY; // The id of the native layer being scrolled. - private int mScrollingLayer; + private int mCurrentScrollingLayerId; private Rect mScrollingLayerRect = new Rect(); // only trigger accelerated fling if the new velocity is at least @@ -738,6 +742,7 @@ public class WebView extends AbsoluteLayout static final int SCREEN_ON = 136; static final int ENTER_FULLSCREEN_VIDEO = 137; static final int UPDATE_SELECTION = 138; + static final int UPDATE_ZOOM_DENSITY = 139; private static final int FIRST_PACKAGE_MSG_ID = SCROLL_TO_MSG_ID; private static final int LAST_PACKAGE_MSG_ID = SET_TOUCH_HIGHLIGHT_RECTS; @@ -793,7 +798,9 @@ public class WebView extends AbsoluteLayout "AUTOFILL_COMPLETE", // = 134; "SELECT_AT", // = 135; "SCREEN_ON", // = 136; - "ENTER_FULLSCREEN_VIDEO" // = 137; + "ENTER_FULLSCREEN_VIDEO", // = 137; + "UPDATE_SELECTION", // = 138; + "UPDATE_ZOOM_DENSITY" // = 139; }; // If the site doesn't use the viewport meta tag to specify the viewport, @@ -935,7 +942,11 @@ public class WebView extends AbsoluteLayout * Notify the listener that the picture has changed. * @param view The WebView that owns the picture. * @param picture The new picture. - * @deprecated This method is now obsolete. + * @deprecated Due to internal changes, the picture does not include + * composited layers such as fixed position elements or scrollable divs. + * While the PictureListener API can still be used to detect changes in + * the WebView content, you are advised against its usage until a replacement + * is provided in a future Android release */ @Deprecated public void onNewPicture(WebView view, Picture picture); @@ -1295,8 +1306,15 @@ public class WebView extends AbsoluteLayout if (AccessibilityManager.getInstance(mContext).isEnabled() && getSettings().getJavaScriptEnabled()) { // exposing the TTS for now ... - mTextToSpeech = new TextToSpeech(getContext(), null); - addJavascriptInterface(mTextToSpeech, ALIAS_ACCESSIBILITY_JS_INTERFACE); + final Context ctx = getContext(); + if (ctx != null) { + final String packageName = ctx.getPackageName(); + if (packageName != null) { + mTextToSpeech = new TextToSpeech(getContext(), null, null, + packageName + ".**webview**"); + addJavascriptInterface(mTextToSpeech, ALIAS_ACCESSIBILITY_JS_INTERFACE); + } + } } } @@ -1617,6 +1635,14 @@ public class WebView extends AbsoluteLayout clearTextEntry(); clearActionModes(); dismissFullScreenMode(); + cancelSelectDialog(); + } + + private void cancelSelectDialog() { + if (mListBoxDialog != null) { + mListBoxDialog.cancel(); + mListBoxDialog = null; + } } /** @@ -3268,6 +3294,8 @@ public class WebView extends AbsoluteLayout if (mNativeClass != 0) { nativeSetPauseDrawing(mNativeClass, true); } + + cancelSelectDialog(); } } @@ -3637,7 +3665,7 @@ public class WebView extends AbsoluteLayout if (x == mScrollingLayerRect.left && y == mScrollingLayerRect.top) { return; } - nativeScrollLayer(mScrollingLayer, x, y); + nativeScrollLayer(mCurrentScrollingLayerId, x, y); mScrollingLayerRect.left = x; mScrollingLayerRect.top = y; onScrollChanged(mScrollX, mScrollY, mScrollX, mScrollY); @@ -4442,6 +4470,7 @@ public class WebView extends AbsoluteLayout Rect vBox = contentToViewRect(contentBounds); Rect visibleRect = new Rect(); calcOurVisibleRect(visibleRect); + offsetByLayerScrollPosition(vBox); // If the textfield is on screen, place the WebTextView in // its new place, accounting for our new scroll/zoom values, // and adjust its textsize. @@ -4477,6 +4506,14 @@ public class WebView extends AbsoluteLayout } } + private void offsetByLayerScrollPosition(Rect box) { + if ((mCurrentScrollingLayerId != 0) + && (mCurrentScrollingLayerId == nativeFocusCandidateLayerId())) { + box.offsetTo(box.left - mScrollingLayerRect.left, + box.top - mScrollingLayerRect.top); + } + } + void setBaseLayer(int layer, Region invalRegion, boolean showVisualIndicator, boolean isPictureAfterFirstLayout, boolean registerPageSwapCallback) { if (mNativeClass == 0) @@ -4576,14 +4613,15 @@ public class WebView extends AbsoluteLayout boolean UIAnimationsRunning = false; // Currently for each draw we compute the animation values; // We may in the future decide to do that independently. - if (mNativeClass != 0 && nativeEvaluateLayersAnimations(mNativeClass)) { + if (mNativeClass != 0 && !canvas.isHardwareAccelerated() + && nativeEvaluateLayersAnimations(mNativeClass)) { UIAnimationsRunning = true; // If we have unfinished (or unstarted) animations, // we ask for a repaint. We only need to do this in software // rendering (with hardware rendering we already have a different // method of requesting a repaint) - if (!canvas.isHardwareAccelerated()) - invalidate(); + mWebViewCore.sendMessage(EventHub.NOTIFY_ANIMATION_STARTED); + invalidate(); } // decide which adornments to draw @@ -4607,11 +4645,14 @@ public class WebView extends AbsoluteLayout + " extras=" + extras); } + calcOurContentVisibleRectF(mVisibleContentRect); if (canvas.isHardwareAccelerated()) { - int functor = nativeGetDrawGLFunction(mNativeClass, - mGLViewportEmpty ? null : mGLRectViewport, mGLViewportEmpty ? null : mViewRectViewport, getScale(), extras); - ((HardwareCanvas) canvas).callDrawGLFunction(functor); + Rect glRectViewport = mGLViewportEmpty ? null : mGLRectViewport; + Rect viewRectViewport = mGLViewportEmpty ? null : mViewRectViewport; + int functor = nativeGetDrawGLFunction(mNativeClass, glRectViewport, + viewRectViewport, mVisibleContentRect, getScale(), extras); + ((HardwareCanvas) canvas).callDrawGLFunction(functor); if (mHardwareAccelSkia != getSettings().getHardwareAccelSkiaEnabled()) { mHardwareAccelSkia = getSettings().getHardwareAccelSkiaEnabled(); nativeUseHardwareAccelSkia(mHardwareAccelSkia); @@ -4627,7 +4668,8 @@ public class WebView extends AbsoluteLayout canvas.setDrawFilter(df); // XXX: Revisit splitting content. Right now it causes a // synchronization problem with layers. - int content = nativeDraw(canvas, color, extras, false); + int content = nativeDraw(canvas, mVisibleContentRect, color, + extras, false); canvas.setDrawFilter(null); if (!mBlockWebkitViewMessages && content != 0) { mWebViewCore.sendMessage(EventHub.SPLIT_PICTURE_SET, content, 0); @@ -4890,6 +4932,7 @@ public class WebView extends AbsoluteLayout // should be in content coordinates. Rect bounds = nativeFocusCandidateNodeBounds(); Rect vBox = contentToViewRect(bounds); + offsetByLayerScrollPosition(vBox); mWebTextView.setRect(vBox.left, vBox.top, vBox.width(), vBox.height()); if (!Rect.intersects(bounds, visibleRect)) { revealSelection(); @@ -5481,10 +5524,10 @@ public class WebView extends AbsoluteLayout mMaxAutoScrollX = getViewWidth(); mMinAutoScrollY = 0; mMaxAutoScrollY = getViewHeightWithTitle(); - mScrollingLayer = nativeScrollableLayer(viewToContentX(mSelectX), + mCurrentScrollingLayerId = nativeScrollableLayer(viewToContentX(mSelectX), viewToContentY(mSelectY), mScrollingLayerRect, mScrollingLayerBounds); - if (mScrollingLayer != 0) { + if (mCurrentScrollingLayerId != 0) { if (mScrollingLayerRect.left != mScrollingLayerRect.right) { mMinAutoScrollX = Math.max(mMinAutoScrollX, contentToViewX(mScrollingLayerBounds.left)); @@ -5797,8 +5840,9 @@ public class WebView extends AbsoluteLayout } else { mGLViewportEmpty = true; } + calcOurContentVisibleRectF(mVisibleContentRect); nativeUpdateDrawGLFunction(mGLViewportEmpty ? null : mGLRectViewport, - mGLViewportEmpty ? null : mViewRectViewport); + mGLViewportEmpty ? null : mViewRectViewport, mVisibleContentRect); } /** @@ -5969,9 +6013,9 @@ public class WebView extends AbsoluteLayout private void startScrollingLayer(float x, float y) { int contentX = viewToContentX((int) x + mScrollX); int contentY = viewToContentY((int) y + mScrollY); - mScrollingLayer = nativeScrollableLayer(contentX, contentY, + mCurrentScrollingLayerId = nativeScrollableLayer(contentX, contentY, mScrollingLayerRect, mScrollingLayerBounds); - if (mScrollingLayer != 0) { + if (mCurrentScrollingLayerId != 0) { mTouchMode = TOUCH_DRAG_LAYER_MODE; } } @@ -6202,7 +6246,7 @@ public class WebView extends AbsoluteLayout ted.mPointsInView[0] = new Point(x, y); ted.mMetaState = ev.getMetaState(); ted.mReprocess = mDeferTouchProcess; - ted.mNativeLayer = mScrollingLayer; + ted.mNativeLayer = mCurrentScrollingLayerId; ted.mNativeLayerRect.set(mScrollingLayerRect); ted.mSequence = mTouchEventQueue.nextTouchSequence(); mTouchEventQueue.preQueueTouchEventData(ted); @@ -6393,7 +6437,7 @@ public class WebView extends AbsoluteLayout ted.mPointsInView[0] = new Point(x, y); ted.mMetaState = ev.getMetaState(); ted.mReprocess = mDeferTouchProcess; - ted.mNativeLayer = mScrollingLayer; + ted.mNativeLayer = mCurrentScrollingLayerId; ted.mNativeLayerRect.set(mScrollingLayerRect); ted.mSequence = mTouchEventQueue.nextTouchSequence(); mTouchEventQueue.preQueueTouchEventData(ted); @@ -6702,7 +6746,7 @@ public class WebView extends AbsoluteLayout // directions. mTouchMode might be TOUCH_DRAG_MODE if we have // reached the edge of a layer but mScrollingLayer will be non-zero // if we initiated the drag on a layer. - if (mScrollingLayer != 0) { + if (mCurrentScrollingLayerId != 0) { final int contentX = viewToContentDimension(deltaX); final int contentY = viewToContentDimension(deltaY); @@ -7224,7 +7268,7 @@ public class WebView extends AbsoluteLayout + " vx=" + vx + " vy=" + vy + " maxX=" + maxX + " maxY=" + maxY + " scrollX=" + scrollX + " scrollY=" + scrollY - + " layer=" + mScrollingLayer); + + " layer=" + mCurrentScrollingLayerId); } // Allow sloppy flings without overscrolling at the edges. @@ -8333,7 +8377,7 @@ public class WebView extends AbsoluteLayout mSentAutoScrollMessage = false; break; } - if (mScrollingLayer == 0) { + if (mCurrentScrollingLayerId == 0) { pinScrollBy(mAutoScrollX, mAutoScrollY, true, 0); } else { scrollLayerTo(mScrollingLayerRect.left + mAutoScrollX, @@ -8431,6 +8475,11 @@ public class WebView extends AbsoluteLayout mZoomManager.updateZoomRange(viewState, getViewWidth(), viewState.mScrollX); break; } + case UPDATE_ZOOM_DENSITY: { + final float density = (Float) msg.obj; + mZoomManager.updateDefaultZoomDensity(density); + break; + } case REPLACE_BASE_CONTENT: { nativeReplaceBaseContent(msg.arg1); break; @@ -8445,7 +8494,11 @@ public class WebView extends AbsoluteLayout // nativeCreate sets mNativeClass to a non-zero value String drawableDir = BrowserFrame.getRawResFilename( BrowserFrame.DRAWABLEDIR, mContext); - nativeCreate(msg.arg1, drawableDir); + WindowManager windowManager = + (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); + Display display = windowManager.getDefaultDisplay(); + nativeCreate(msg.arg1, drawableDir, + ActivityManager.isHighEndGfx(display)); if (mDelaySetPicture != null) { setNewPicture(mDelaySetPicture, true); mDelaySetPicture = null; @@ -8754,10 +8807,13 @@ public class WebView extends AbsoluteLayout /** @hide Called by JNI when pages are swapped (only occurs with hardware * acceleration) */ - protected void pageSwapCallback() { + protected void pageSwapCallback(boolean notifyAnimationStarted) { if (inEditingMode()) { didUpdateWebTextViewDimensions(ANYWHERE); } + if (notifyAnimationStarted) { + mWebViewCore.sendMessage(EventHub.NOTIFY_ANIMATION_STARTED); + } } void setNewPicture(final WebViewCore.DrawData draw, boolean updateBaseLayer) { @@ -8795,7 +8851,6 @@ public class WebView extends AbsoluteLayout mSendScrollEvent = false; recordNewContentSize(draw.mContentSize.x, draw.mContentSize.y, updateLayout); - if (isPictureAfterFirstLayout) { // Reset the last sent data here since dealing with new page. mLastWidthSent = 0; @@ -9366,7 +9421,8 @@ public class WebView extends AbsoluteLayout * @hide only needs to be accessible to Browser and testing */ public void drawPage(Canvas canvas) { - nativeDraw(canvas, 0, 0, false); + calcOurContentVisibleRectF(mVisibleContentRect); + nativeDraw(canvas, mVisibleContentRect, 0, 0, false); } /** @@ -9474,7 +9530,7 @@ public class WebView extends AbsoluteLayout private native Rect nativeCacheHitNodeBounds(); private native int nativeCacheHitNodePointer(); /* package */ native void nativeClearCursor(); - private native void nativeCreate(int ptr, String drawableDir); + private native void nativeCreate(int ptr, String drawableDir, boolean isHighEndGfx); private native int nativeCursorFramePointer(); private native Rect nativeCursorNodeBounds(); private native int nativeCursorNodePointer(); @@ -9497,13 +9553,14 @@ public class WebView extends AbsoluteLayout * MUST be passed to WebViewCore with SPLIT_PICTURE_SET message so that the * native allocation can be freed. */ - private native int nativeDraw(Canvas canvas, int color, int extra, - boolean splitIfNeeded); + private native int nativeDraw(Canvas canvas, RectF visibleRect, + int color, int extra, boolean splitIfNeeded); private native void nativeDumpDisplayTree(String urlOrNull); private native boolean nativeEvaluateLayersAnimations(int nativeInstance); private native int nativeGetDrawGLFunction(int nativeInstance, Rect rect, - Rect viewRect, float scale, int extras); - private native void nativeUpdateDrawGLFunction(Rect rect, Rect viewRect); + Rect viewRect, RectF visibleRect, float scale, int extras); + private native void nativeUpdateDrawGLFunction(Rect rect, Rect viewRect, + RectF visibleRect); private native void nativeExtendSelection(int x, int y); private native int nativeFindAll(String findLower, String findUpper, boolean sameAsLastSearch); @@ -9534,6 +9591,7 @@ public class WebView extends AbsoluteLayout * See WebTextView.setType() */ private native int nativeFocusCandidateType(); + private native int nativeFocusCandidateLayerId(); private native boolean nativeFocusIsPlugin(); private native Rect nativeFocusNodeBounds(); /* package */ native int nativeFocusNodePointer(); diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java index a97f4dde535a..d13600438e9b 100644 --- a/core/java/android/webkit/WebViewCore.java +++ b/core/java/android/webkit/WebViewCore.java @@ -519,7 +519,12 @@ public final class WebViewCore { /** * Update the layers' content */ - private native boolean nativeUpdateLayers(int baseLayer); + private native boolean nativeUpdateLayers(int nativeClass, int baseLayer); + + /** + * Notify webkit that animations have begun (on the hardware accelerated content) + */ + private native void nativeNotifyAnimationStarted(int nativeClass); private native boolean nativeFocusBoundsChanged(); @@ -1035,6 +1040,8 @@ public final class WebViewCore { static final int PLUGIN_SURFACE_READY = 195; + static final int NOTIFY_ANIMATION_STARTED = 196; + // private message ids private static final int DESTROY = 200; @@ -1594,6 +1601,10 @@ public final class WebViewCore { nativePluginSurfaceReady(); break; + case NOTIFY_ANIMATION_STARTED: + nativeNotifyAnimationStarted(mNativeClass); + break; + case ADD_PACKAGE_NAMES: if (BrowserFrame.sJavaBridge == null) { throw new IllegalStateException("No WebView " + @@ -2015,7 +2026,7 @@ public final class WebViewCore { return; } // Directly update the layers we last passed to the UI side - if (nativeUpdateLayers(mLastDrawData.mBaseLayer)) { + if (nativeUpdateLayers(mNativeClass, mLastDrawData.mBaseLayer)) { // If anything more complex than position has been touched, let's do a full draw webkitDraw(); } @@ -2337,7 +2348,8 @@ public final class WebViewCore { / mViewportDensityDpi; } if (adjust != mWebView.getDefaultZoomScale()) { - mWebView.updateDefaultZoomDensity(adjust); + Message.obtain(mWebView.mPrivateHandler, + WebView.UPDATE_ZOOM_DENSITY, adjust).sendToTarget(); } int defaultScale = (int) (adjust * 100); diff --git a/core/java/android/webkit/ZoomManager.java b/core/java/android/webkit/ZoomManager.java index 84d00c90ef01..14bdc420eb45 100644 --- a/core/java/android/webkit/ZoomManager.java +++ b/core/java/android/webkit/ZoomManager.java @@ -493,11 +493,19 @@ class ZoomManager { if (mHardwareAccelerated) { mWebView.updateScrollCoordinates(mWebView.getScrollX() - tx, mWebView.getScrollY() - ty); + // By adding webView matrix, we need to offset the canvas a bit + // to make the animation smooth. + canvas.translate(tx, ty); setZoomScale(zoomScale, false); if (mZoomScale == 0) { // We've reached the end of the zoom animation. mInHWAcceleratedZoom = false; + + // Ensure that the zoom level is pushed to WebCore. This has not + // yet occurred because we prevent it from happening while + // mInHWAcceleratedZoom is true. + mWebView.sendViewSizeZoom(false); } } else { canvas.translate(tx, ty); @@ -514,11 +522,12 @@ class ZoomManager { } public void updateDoubleTapZoom(int doubleTapZoom) { - if (mInZoomOverview) { - mDoubleTapZoomFactor = doubleTapZoom / 100.0f; - mTextWrapScale = getReadingLevelScale(); - refreshZoomScale(true); - } + boolean zoomIn = (mTextWrapScale - mActualScale) < .1f; + mDoubleTapZoomFactor = doubleTapZoom / 100.0f; + mTextWrapScale = getReadingLevelScale(); + float newScale = zoomIn ? mTextWrapScale + : Math.min(mTextWrapScale, mActualScale); + setZoomScale(newScale, true, true); } public void refreshZoomScale(boolean reflowText) { diff --git a/core/java/android/widget/NumberPicker.java b/core/java/android/widget/NumberPicker.java index 1a1b8d04365f..13375bfd9502 100644 --- a/core/java/android/widget/NumberPicker.java +++ b/core/java/android/widget/NumberPicker.java @@ -165,6 +165,11 @@ public class NumberPicker extends LinearLayout { }; /** + * Constant for unspecified size. + */ + private static final int SIZE_UNSPECIFIED = -1; + + /** * Use a custom NumberPicker formatting callback to use two-digit minutes * strings like "01". Keeping a static formatter etc. is the most efficient * way to do this; it avoids creating temporary objects on every call to @@ -542,16 +547,20 @@ public class NumberPicker extends LinearLayout { getResources().getDisplayMetrics()); mSelectionDividerHeight = attributesArray.getDimensionPixelSize( R.styleable.NumberPicker_selectionDividerHeight, defSelectionDividerHeight); - mMinHeight = attributesArray.getDimensionPixelSize(R.styleable.NumberPicker_minHeight, 0); + mMinHeight = attributesArray.getDimensionPixelSize(R.styleable.NumberPicker_minHeight, + SIZE_UNSPECIFIED); mMaxHeight = attributesArray.getDimensionPixelSize(R.styleable.NumberPicker_maxHeight, - Integer.MAX_VALUE); - if (mMinHeight > mMaxHeight) { + SIZE_UNSPECIFIED); + if (mMinHeight != SIZE_UNSPECIFIED && mMaxHeight != SIZE_UNSPECIFIED + && mMinHeight > mMaxHeight) { throw new IllegalArgumentException("minHeight > maxHeight"); } - mMinWidth = attributesArray.getDimensionPixelSize(R.styleable.NumberPicker_minWidth, 0); + mMinWidth = attributesArray.getDimensionPixelSize(R.styleable.NumberPicker_minWidth, + SIZE_UNSPECIFIED); mMaxWidth = attributesArray.getDimensionPixelSize(R.styleable.NumberPicker_maxWidth, - Integer.MAX_VALUE); - if (mMinWidth > mMaxWidth) { + SIZE_UNSPECIFIED); + if (mMinWidth != SIZE_UNSPECIFIED && mMaxWidth != SIZE_UNSPECIFIED + && mMinWidth > mMaxWidth) { throw new IllegalArgumentException("minWidth > maxWidth"); } mComputeMaxWidth = (mMaxWidth == Integer.MAX_VALUE); @@ -746,10 +755,10 @@ public class NumberPicker extends LinearLayout { final int newHeightMeasureSpec = makeMeasureSpec(heightMeasureSpec, mMaxHeight); super.onMeasure(newWidthMeasureSpec, newHeightMeasureSpec); // Flag if we are measured with width or height less than the respective min. - final int desiredWidth = Math.max(mMinWidth, getMeasuredWidth()); - final int desiredHeight = Math.max(mMinHeight, getMeasuredHeight()); - final int widthSize = resolveSizeAndState(desiredWidth, newWidthMeasureSpec, 0); - final int heightSize = resolveSizeAndState(desiredHeight, newHeightMeasureSpec, 0); + final int widthSize = resolveSizeAndStateRespectingMinSize(mMinWidth, getMeasuredWidth(), + widthMeasureSpec); + final int heightSize = resolveSizeAndStateRespectingMinSize(mMinHeight, getMeasuredHeight(), + heightMeasureSpec); setMeasuredDimension(widthSize, heightSize); } @@ -767,6 +776,7 @@ public class NumberPicker extends LinearLayout { mBeginEditOnUpEvent = false; mAdjustScrollerOnUpEvent = true; if (mSelectorWheelState == SELECTOR_WHEEL_STATE_LARGE) { + mSelectorWheelPaint.setAlpha(SELECTOR_WHEEL_BRIGHT_ALPHA); boolean scrollersFinished = mFlingScroller.isFinished() && mAdjustScroller.isFinished(); if (!scrollersFinished) { @@ -1243,6 +1253,7 @@ public class NumberPicker extends LinearLayout { } updateInputTextView(); initializeSelectorWheelIndices(); + tryComputeMaxWidth(); } @Override @@ -1368,6 +1379,9 @@ public class NumberPicker extends LinearLayout { * @return A measure spec greedily imposing the max size. */ private int makeMeasureSpec(int measureSpec, int maxSize) { + if (maxSize == SIZE_UNSPECIFIED) { + return measureSpec; + } final int size = MeasureSpec.getSize(measureSpec); final int mode = MeasureSpec.getMode(measureSpec); switch (mode) { @@ -1383,6 +1397,26 @@ public class NumberPicker extends LinearLayout { } /** + * Utility to reconcile a desired size and state, with constraints imposed by + * a MeasureSpec. Tries to respect the min size, unless a different size is + * imposed by the constraints. + * + * @param minSize The minimal desired size. + * @param measuredSize The currently measured size. + * @param measureSpec The current measure spec. + * @return The resolved size and state. + */ + private int resolveSizeAndStateRespectingMinSize(int minSize, int measuredSize, + int measureSpec) { + if (minSize != SIZE_UNSPECIFIED) { + final int desiredWidth = Math.max(minSize, measuredSize); + return resolveSizeAndState(desiredWidth, measureSpec, 0); + } else { + return measuredSize; + } + } + + /** * Resets the selector indices and clear the cached * string representation of these indices. */ @@ -1564,23 +1598,11 @@ public class NumberPicker extends LinearLayout { */ private void fling(int velocityY) { mPreviousScrollerY = 0; - Scroller flingScroller = mFlingScroller; - if (mWrapSelectorWheel) { - if (velocityY > 0) { - flingScroller.fling(0, 0, 0, velocityY, 0, 0, 0, Integer.MAX_VALUE); - } else { - flingScroller.fling(0, Integer.MAX_VALUE, 0, velocityY, 0, 0, 0, Integer.MAX_VALUE); - } + if (velocityY > 0) { + mFlingScroller.fling(0, 0, 0, velocityY, 0, 0, 0, Integer.MAX_VALUE); } else { - if (velocityY > 0) { - int maxY = mTextSize * (mValue - mMinValue); - flingScroller.fling(0, 0, 0, velocityY, 0, 0, 0, maxY); - } else { - int startY = mTextSize * (mMaxValue - mValue); - int maxY = startY; - flingScroller.fling(0, startY, 0, velocityY, 0, 0, 0, maxY); - } + mFlingScroller.fling(0, Integer.MAX_VALUE, 0, velocityY, 0, 0, 0, Integer.MAX_VALUE); } invalidate(); diff --git a/core/java/android/widget/RemoteViewsService.java b/core/java/android/widget/RemoteViewsService.java index 7ba47777f970..07bd9188dca4 100644 --- a/core/java/android/widget/RemoteViewsService.java +++ b/core/java/android/widget/RemoteViewsService.java @@ -145,6 +145,9 @@ public abstract class RemoteViewsService extends Service { Thread.getDefaultUncaughtExceptionHandler().uncaughtException(t, ex); } } + public synchronized void onDataSetChangedAsync() { + onDataSetChanged(); + } public synchronized int getCount() { int count = 0; try { diff --git a/core/java/android/widget/SpellChecker.java b/core/java/android/widget/SpellChecker.java index ebb260428454..8f495c9bc301 100644 --- a/core/java/android/widget/SpellChecker.java +++ b/core/java/android/widget/SpellChecker.java @@ -19,6 +19,7 @@ package android.widget; import android.content.Context; import android.text.Editable; import android.text.Selection; +import android.text.SpannableStringBuilder; import android.text.Spanned; import android.text.method.WordIterator; import android.text.style.SpellCheckSpan; @@ -42,7 +43,18 @@ import java.util.Locale; */ public class SpellChecker implements SpellCheckerSessionListener { - private final static int MAX_SPELL_BATCH_SIZE = 50; + // No more than this number of words will be parsed on each iteration to ensure a minimum + // lock of the UI thread + public static final int MAX_NUMBER_OF_WORDS = 50; + + // Rough estimate, such that the word iterator interval usually does not need to be shifted + public static final int AVERAGE_WORD_LENGTH = 7; + + // When parsing, use a character window of that size. Will be shifted if needed + public static final int WORD_ITERATOR_INTERVAL = AVERAGE_WORD_LENGTH * MAX_NUMBER_OF_WORDS; + + // Pause between each spell check to keep the UI smooth + private final static int SPELL_PAUSE_DURATION = 400; // milliseconds private final TextView mTextView; @@ -68,6 +80,10 @@ public class SpellChecker implements SpellCheckerSessionListener { // concurrently due to the asynchronous nature of onGetSuggestions. private WordIterator mWordIterator; + private TextServicesManager mTextServicesManager; + + private Runnable mSpellRunnable; + public SpellChecker(TextView textView) { mTextView = textView; @@ -81,20 +97,19 @@ public class SpellChecker implements SpellCheckerSessionListener { mCookie = hashCode(); } - private void setLocale(Locale locale) { + private void resetSession() { closeSession(); - final TextServicesManager textServicesManager = (TextServicesManager) - mTextView.getContext().getSystemService(Context.TEXT_SERVICES_MANAGER_SERVICE); - if (!textServicesManager.isSpellCheckerEnabled()) { + mTextServicesManager = (TextServicesManager) mTextView.getContext(). + getSystemService(Context.TEXT_SERVICES_MANAGER_SERVICE); + if (!mTextServicesManager.isSpellCheckerEnabled()) { mSpellCheckerSession = null; } else { - mSpellCheckerSession = textServicesManager.newSpellCheckerSession( + mSpellCheckerSession = mTextServicesManager.newSpellCheckerSession( null /* Bundle not currently used by the textServicesManager */, - locale, this, + mCurrentLocale, this, false /* means any available languages from current spell checker */); } - mCurrentLocale = locale; // Restore SpellCheckSpans in pool for (int i = 0; i < mLength; i++) { @@ -103,9 +118,6 @@ public class SpellChecker implements SpellCheckerSessionListener { } mLength = 0; - // Change SpellParsers' wordIterator locale - mWordIterator = new WordIterator(locale); - // Remove existing misspelled SuggestionSpans mTextView.removeMisspelledSpans((Editable) mTextView.getText()); @@ -113,6 +125,18 @@ public class SpellChecker implements SpellCheckerSessionListener { mTextView.onLocaleChanged(); } + private void setLocale(Locale locale) { + mCurrentLocale = locale; + + resetSession(); + + // Change SpellParsers' wordIterator locale + mWordIterator = new WordIterator(locale); + + // This class is the listener for locale change: warn other locale-aware objects + mTextView.onLocaleChanged(); + } + /** * @return true if a spell checker session has successfully been created. Returns false if not, * for instance when spell checking has been disabled in settings. @@ -130,6 +154,10 @@ public class SpellChecker implements SpellCheckerSessionListener { for (int i = 0; i < length; i++) { mSpellParsers[i].finish(); } + + if (mSpellRunnable != null) { + mTextView.removeCallbacks(mSpellRunnable); + } } private int nextSpellCheckSpanIndex() { @@ -179,6 +207,12 @@ public class SpellChecker implements SpellCheckerSessionListener { // Re-check the entire text start = 0; end = mTextView.getText().length(); + } else { + final boolean spellCheckerActivated = mTextServicesManager.isSpellCheckerEnabled(); + if (isSessionActive() != spellCheckerActivated) { + // Spell checker has been turned of or off since last spellCheck + resetSession(); + } } if (!isSessionActive()) return; @@ -223,7 +257,9 @@ public class SpellChecker implements SpellCheckerSessionListener { // Do not check this word if the user is currently editing it if (start >= 0 && end > start && (selectionEnd < start || selectionStart > end)) { - final String word = editable.subSequence(start, end).toString(); + final String word = (editable instanceof SpannableStringBuilder) ? + ((SpannableStringBuilder) editable).substring(start, end) : + editable.subSequence(start, end).toString(); spellCheckSpan.setSpellCheckInProgress(true); textInfos[textInfosCount++] = new TextInfo(word, mCookie, mIds[i]); } @@ -235,6 +271,7 @@ public class SpellChecker implements SpellCheckerSessionListener { System.arraycopy(textInfos, 0, textInfosCopy, 0, textInfosCount); textInfos = textInfosCopy; } + mSpellCheckerSession.getSuggestions(textInfos, SuggestionSpan.SUGGESTIONS_MAX_SIZE, false /* TODO Set sequentialWords to true for initial spell check */); } @@ -258,38 +295,57 @@ public class SpellChecker implements SpellCheckerSessionListener { ((attributes & SuggestionsInfo.RESULT_ATTR_LOOKS_LIKE_TYPO) > 0); SpellCheckSpan spellCheckSpan = mSpellCheckSpans[j]; + if (!isInDictionary && looksLikeTypo) { createMisspelledSuggestionSpan(editable, suggestionsInfo, spellCheckSpan); } + editable.removeSpan(spellCheckSpan); break; } } } - final int length = mSpellParsers.length; - for (int i = 0; i < length; i++) { - final SpellParser spellParser = mSpellParsers[i]; - if (!spellParser.isFinished()) { - spellParser.parse(); - } + scheduleNewSpellCheck(); + } + + private void scheduleNewSpellCheck() { + if (mSpellRunnable == null) { + mSpellRunnable = new Runnable() { + @Override + public void run() { + final int length = mSpellParsers.length; + for (int i = 0; i < length; i++) { + final SpellParser spellParser = mSpellParsers[i]; + if (!spellParser.isFinished()) { + spellParser.parse(); + break; // run one spell parser at a time to bound running time + } + } + } + }; + } else { + mTextView.removeCallbacks(mSpellRunnable); } + + mTextView.postDelayed(mSpellRunnable, SPELL_PAUSE_DURATION); } - private void createMisspelledSuggestionSpan(Editable editable, - SuggestionsInfo suggestionsInfo, SpellCheckSpan spellCheckSpan) { + private void createMisspelledSuggestionSpan(Editable editable, SuggestionsInfo suggestionsInfo, + SpellCheckSpan spellCheckSpan) { final int start = editable.getSpanStart(spellCheckSpan); final int end = editable.getSpanEnd(spellCheckSpan); - if (start < 0 || end < 0) return; // span was removed in the meantime + if (start < 0 || end <= start) return; // span was removed in the meantime // Other suggestion spans may exist on that region, with identical suggestions, filter - // them out to avoid duplicates. First, filter suggestion spans on that exact region. + // them out to avoid duplicates. SuggestionSpan[] suggestionSpans = editable.getSpans(start, end, SuggestionSpan.class); final int length = suggestionSpans.length; for (int i = 0; i < length; i++) { final int spanStart = editable.getSpanStart(suggestionSpans[i]); final int spanEnd = editable.getSpanEnd(suggestionSpans[i]); if (spanStart != start || spanEnd != end) { + // Nulled (to avoid new array allocation) if not on that exact same region suggestionSpans[i] = null; } } @@ -337,8 +393,7 @@ public class SpellChecker implements SpellCheckerSessionListener { SuggestionSpan.FLAG_EASY_CORRECT | SuggestionSpan.FLAG_MISSPELLED); editable.setSpan(suggestionSpan, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); - // TODO limit to the word rectangle region - mTextView.invalidate(); + mTextView.invalidateRegion(start, end); } private class SpellParser { @@ -362,7 +417,9 @@ public class SpellChecker implements SpellCheckerSessionListener { // Iterate over the newly added text and schedule new SpellCheckSpans final int start = editable.getSpanStart(mRange); final int end = editable.getSpanEnd(mRange); - mWordIterator.setCharSequence(editable, start, end); + + int wordIteratorWindowEnd = Math.min(end, start + WORD_ITERATOR_INTERVAL); + mWordIterator.setCharSequence(editable, start, wordIteratorWindowEnd); // Move back to the beginning of the current word, if any int wordStart = mWordIterator.preceding(start); @@ -387,11 +444,16 @@ public class SpellChecker implements SpellCheckerSessionListener { SuggestionSpan[] suggestionSpans = editable.getSpans(start - 1, end + 1, SuggestionSpan.class); - int nbWordsChecked = 0; + int wordCount = 0; boolean scheduleOtherSpellCheck = false; while (wordStart <= end) { if (wordEnd >= start && wordEnd > wordStart) { + if (wordCount >= MAX_NUMBER_OF_WORDS) { + scheduleOtherSpellCheck = true; + break; + } + // A new word has been created across the interval boundaries with this edit. // Previous spans (ended on start / started on end) removed, not valid anymore if (wordStart < start && wordEnd > start) { @@ -427,17 +489,20 @@ public class SpellChecker implements SpellCheckerSessionListener { } if (createSpellCheckSpan) { - if (nbWordsChecked == MAX_SPELL_BATCH_SIZE) { - scheduleOtherSpellCheck = true; - break; - } addSpellCheckSpan(editable, wordStart, wordEnd); - nbWordsChecked++; } + wordCount++; } // iterate word by word + int originalWordEnd = wordEnd; wordEnd = mWordIterator.following(wordEnd); + if ((wordIteratorWindowEnd < end) && + (wordEnd == BreakIterator.DONE || wordEnd >= wordIteratorWindowEnd)) { + wordIteratorWindowEnd = Math.min(end, originalWordEnd + WORD_ITERATOR_INTERVAL); + mWordIterator.setCharSequence(editable, originalWordEnd, wordIteratorWindowEnd); + wordEnd = mWordIterator.following(originalWordEnd); + } if (wordEnd == BreakIterator.DONE) break; wordStart = mWordIterator.getBeginning(wordEnd); if (wordStart == BreakIterator.DONE) { diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 185cfa932c51..6722d1705314 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -1209,6 +1209,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener InputMethodManager imm = InputMethodManager.peekInstance(); if (imm != null) imm.restartInput(this); } + + // start or stop the cursor blinking as appropriate + makeBlink(); } /** @@ -2581,6 +2584,17 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } /** + * Returns whether the text is allowed to be wider than the View is. + * If false, the text will be wrapped to the width of the View. + * + * @attr ref android.R.styleable#TextView_scrollHorizontally + * @hide + */ + public boolean getHorizontallyScrolling() { + return mHorizontallyScrolling; + } + + /** * Makes the TextView at least this many lines tall. * * Setting this value overrides any other (minimum) height setting. A single line TextView will @@ -3196,7 +3210,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } boolean needEditableForNotification = false; - boolean startSpellCheck = false; if (mListeners != null && mListeners.size() != 0) { needEditableForNotification = true; @@ -3208,7 +3221,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener setFilters(t, mFilters); InputMethodManager imm = InputMethodManager.peekInstance(); if (imm != null) imm.restartInput(this); - startSpellCheck = true; } else if (type == BufferType.SPANNABLE || mMovement != null) { text = mSpannableFactory.newSpannable(text); } else if (!(text instanceof CharWrapper)) { @@ -3297,11 +3309,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener sendOnTextChanged(text, 0, oldlen, textLength); onTextChanged(text, 0, oldlen, textLength); - if (startSpellCheck && mSpellChecker != null) { - // This view has to have been previously attached for mSpellChecker to exist - updateSpellCheckSpans(0, textLength); - } - if (needEditableForNotification) { sendAfterTextChanged((Editable) text); } @@ -3816,7 +3823,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener if (imm != null && imm.isActive(this)) { imm.hideSoftInputFromWindow(getWindowToken(), 0); } - clearFocus(); return; } } @@ -3838,7 +3844,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener | KeyEvent.FLAG_EDITOR_ACTION))); } } - + /** * Set the private content type of the text, which is the * {@link EditorInfo#privateImeOptions EditorInfo.privateImeOptions} @@ -4313,15 +4319,24 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } private void invalidateCursor(int a, int b, int c) { + if (a >= 0 || b >= 0 || c >= 0) { + int start = Math.min(Math.min(a, b), c); + int end = Math.max(Math.max(a, b), c); + invalidateRegion(start, end); + } + } + + /** + * Invalidates the region of text enclosed between the start and end text offsets. + * + * @hide + */ + void invalidateRegion(int start, int end) { if (mLayout == null) { invalidate(); } else { - if (a >= 0 || b >= 0 || c >= 0) { - int first = Math.min(Math.min(a, b), c); - int last = Math.max(Math.max(a, b), c); - - int line = mLayout.getLineForOffset(first); - int top = mLayout.getLineTop(line); + int lineStart = mLayout.getLineForOffset(start); + int top = mLayout.getLineTop(lineStart); // This is ridiculous, but the descent from the line above // can hang down into the line we really want to redraw, @@ -4329,36 +4344,36 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener // sure everything that needs to be redrawn really is. // (But not the whole line above, because that would cause // the same problem with the descenders on the line above it!) - if (line > 0) { - top -= mLayout.getLineDescent(line - 1); + if (lineStart > 0) { + top -= mLayout.getLineDescent(lineStart - 1); } - int line2; + int lineEnd; - if (first == last) - line2 = line; + if (start == end) + lineEnd = lineStart; else - line2 = mLayout.getLineForOffset(last); + lineEnd = mLayout.getLineForOffset(end); - int bottom = mLayout.getLineTop(line2 + 1); + int bottom = mLayout.getLineBottom(lineEnd); - final int horizontalPadding = getCompoundPaddingLeft(); + final int compoundPaddingLeft = getCompoundPaddingLeft(); final int verticalPadding = getExtendedPaddingTop() + getVerticalOffset(true); - - // If used, the cursor drawables can have an arbitrary dimension that can go beyond - // the invalidated lines specified above. - for (int i = 0; i < mCursorCount; i++) { - Rect bounds = mCursorDrawable[i].getBounds(); - top = Math.min(top, bounds.top); - bottom = Math.max(bottom, bounds.bottom); - // Horizontal bounds are already full width, no need to update + + int left, right; + if (lineStart == lineEnd) { + left = (int) mLayout.getPrimaryHorizontal(start); + right = (int) (mLayout.getPrimaryHorizontal(end) + 1.0); + left += compoundPaddingLeft; + right += compoundPaddingLeft; + } else { + // Rectangle bounding box when the region spans several lines + left = compoundPaddingLeft; + right = getWidth() - getCompoundPaddingRight(); } - invalidate(horizontalPadding + mScrollX, top + verticalPadding, - horizontalPadding + mScrollX + getWidth() - - getCompoundPaddingLeft() - getCompoundPaddingRight(), - bottom + verticalPadding); - } + invalidate(mScrollX + left, verticalPadding + top, + mScrollX + right, verticalPadding + bottom); } } @@ -4460,8 +4475,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener // Resolve drawables as the layout direction has been resolved resolveDrawables(); - - updateSpellCheckSpans(0, mText.length()); + + updateSpellCheckSpans(0, mText.length(), true /* create the spell checker if needed */); } @Override @@ -5495,7 +5510,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener * call performClick(), but that won't do anything in * this case.) */ - if (hasOnClickListeners()) { + if (!hasOnClickListeners()) { if (mMovement != null && mText instanceof Editable && mLayout != null && onCheckIsTextEditor()) { InputMethodManager imm = InputMethodManager.peekInstance(); @@ -5532,7 +5547,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener * call performClick(), but that won't do anything in * this case.) */ - if (hasOnClickListeners()) { + if (!hasOnClickListeners()) { View v = focusSearch(FOCUS_DOWN); if (v != null) { @@ -5594,8 +5609,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener outAttrs.extras = mInputContentType.extras; } else { outAttrs.imeOptions = EditorInfo.IME_NULL; - // May not be defined otherwise and needed by onEditorAction - mInputContentType = new InputContentType(); } if (focusSearch(FOCUS_DOWN) != null) { outAttrs.imeOptions |= EditorInfo.IME_FLAG_NAVIGATE_NEXT; @@ -5893,10 +5906,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener if (cursorOffsetVertical != 0) { canvas.translate(0, -cursorOffsetVertical); } - invalidate(true); + invalidate(true); // TODO invalidate cursor region only } else { stopAnimation(); - invalidate(false); + invalidate(false); // TODO invalidate cursor region only } } @@ -7613,6 +7626,13 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener list.get(i).onTextChanged(text, start, before, after); } } + + updateSpellCheckSpans(start, start + after, false); + + // Hide the controllers as soon as text is modified (typing, procedural...) + // We do not hide the span controllers, since they can be added when a new text is + // inserted into the text view (voice IME). + hideCursorControllers(); } /** @@ -7652,15 +7672,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener sendOnTextChanged(buffer, start, before, after); onTextChanged(buffer, start, before, after); - - updateSpellCheckSpans(start, start + after); - - // Hide the controllers if the amount of content changed - if (before != after) { - // We do not hide the span controllers, as they can be added when a new text is - // inserted into the text view - hideCursorControllers(); - } } /** @@ -7718,10 +7729,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener onSelectionChanged(newSelStart, newSelEnd); } } - - if (what instanceof UpdateAppearance || what instanceof ParagraphStyle - || (what instanceof SuggestionSpan && (((SuggestionSpan)what).getFlags() - & SuggestionSpan.FLAG_AUTO_CORRECTION) != 0)) { + + if (what instanceof UpdateAppearance || what instanceof ParagraphStyle) { if (ims == null || ims.mBatchEditNesting == 0) { invalidate(); mHighlightPathBogus = true; @@ -7776,17 +7785,22 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } } - if (newStart < 0 && what instanceof SpellCheckSpan) { - getSpellChecker().removeSpellCheckSpan((SpellCheckSpan) what); + if (mSpellChecker != null && newStart < 0 && what instanceof SpellCheckSpan) { + mSpellChecker.removeSpellCheckSpan((SpellCheckSpan) what); } } /** * Create new SpellCheckSpans on the modified region. */ - private void updateSpellCheckSpans(int start, int end) { + private void updateSpellCheckSpans(int start, int end, boolean createSpellChecker) { if (isTextEditable() && isSuggestionsEnabled()) { - getSpellChecker().spellCheck(start, end); + if (mSpellChecker == null && createSpellChecker) { + mSpellChecker = new SpellChecker(this); + } + if (mSpellChecker != null) { + mSpellChecker.spellCheck(start, end); + } } } @@ -7963,16 +7977,12 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener @Override public void onClick(View view) { if (view == mDeleteTextView) { - deleteText(); - } - } - - private void deleteText() { - Editable editable = (Editable) mText; - int start = editable.getSpanStart(mEasyEditSpan); - int end = editable.getSpanEnd(mEasyEditSpan); - if (start >= 0 && end >= 0) { - editable.delete(start, end); + Editable editable = (Editable) mText; + int start = editable.getSpanStart(mEasyEditSpan); + int end = editable.getSpanEnd(mEasyEditSpan); + if (start >= 0 && end >= 0) { + deleteText_internal(start, end); + } } } @@ -8961,13 +8971,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener return packRangeInLong(offset, offset); } - private SpellChecker getSpellChecker() { - if (mSpellChecker == null) { - mSpellChecker = new SpellChecker(this); - } - return mSpellChecker; - } - private long getLastTouchOffsets() { SelectionModifierCursorController selectionController = getSelectionController(); final int minOffset = selectionController.getMinTouchOffset(); @@ -9096,7 +9099,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener case ID_CUT: setPrimaryClip(ClipData.newPlainText(null, getTransformedText(min, max))); - ((Editable) mText).delete(min, max); + deleteText_internal(min, max); stopSelectionActionMode(); return true; @@ -9127,7 +9130,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener if (Character.isSpaceChar(charBefore) && Character.isSpaceChar(charAfter)) { // Two spaces at beginning of paste: remove one final int originalLength = mText.length(); - ((Editable) mText).delete(min - 1, min); + deleteText_internal(min - 1, min); // Due to filters, there is no guarantee that exactly one character was // removed: count instead. final int delta = mText.length() - originalLength; @@ -9137,7 +9140,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener !Character.isSpaceChar(charAfter) && charAfter != '\n') { // No space at beginning of paste: add one final int originalLength = mText.length(); - ((Editable) mText).replace(min, min, " "); + replaceText_internal(min, min, " "); // Taking possible filters into account as above. final int delta = mText.length() - originalLength; min += delta; @@ -9151,11 +9154,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener if (Character.isSpaceChar(charBefore) && Character.isSpaceChar(charAfter)) { // Two spaces at end of paste: remove one - ((Editable) mText).delete(max, max + 1); + deleteText_internal(max, max + 1); } else if (!Character.isSpaceChar(charBefore) && charBefore != '\n' && !Character.isSpaceChar(charAfter) && charAfter != '\n') { // No space at end of paste: add one - ((Editable) mText).replace(max, max, " "); + replaceText_internal(max, max, " "); } } } @@ -9376,40 +9379,57 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener mPositionY = mTempCoords[1]; } - public boolean isVisible(int positionX, int positionY) { - final TextView textView = TextView.this; + public void onScrollChanged() { + mScrollHasChanged = true; + } + } - if (mTempRect == null) mTempRect = new Rect(); - final Rect clip = mTempRect; - clip.left = getCompoundPaddingLeft(); - clip.top = getExtendedPaddingTop(); - clip.right = textView.getWidth() - getCompoundPaddingRight(); - clip.bottom = textView.getHeight() - getExtendedPaddingBottom(); - - final ViewParent parent = textView.getParent(); - if (parent == null || !parent.getChildVisibleRect(textView, clip, null)) { - return false; - } + private boolean isPositionVisible(int positionX, int positionY) { + synchronized (sTmpPosition) { + final float[] position = sTmpPosition; + position[0] = positionX; + position[1] = positionY; + View view = this; - int posX = mPositionX + positionX; - int posY = mPositionY + positionY; + while (view != null) { + if (view != this) { + // Local scroll is already taken into account in positionX/Y + position[0] -= view.getScrollX(); + position[1] -= view.getScrollY(); + } - // Offset by 1 to take into account 0.5 and int rounding around getPrimaryHorizontal. - return posX >= clip.left - 1 && posX <= clip.right + 1 && - posY >= clip.top && posY <= clip.bottom; - } + if (position[0] < 0 || position[1] < 0 || + position[0] > view.getWidth() || position[1] > view.getHeight()) { + return false; + } - public boolean isOffsetVisible(int offset) { - final int line = mLayout.getLineForOffset(offset); - final int lineBottom = mLayout.getLineBottom(line); - final int primaryHorizontal = (int) mLayout.getPrimaryHorizontal(offset); - return isVisible(primaryHorizontal + viewportToContentHorizontalOffset(), - lineBottom + viewportToContentVerticalOffset()); - } + if (!view.getMatrix().isIdentity()) { + view.getMatrix().mapPoints(position); + } - public void onScrollChanged() { - mScrollHasChanged = true; + position[0] += view.getLeft(); + position[1] += view.getTop(); + + final ViewParent parent = view.getParent(); + if (parent instanceof View) { + view = (View) parent; + } else { + // We've reached the ViewRoot, stop iterating + view = null; + } + } } + + // We've been able to walk up the view hierarchy and the position was never clipped + return true; + } + + private boolean isOffsetVisible(int offset) { + final int line = mLayout.getLineForOffset(offset); + final int lineBottom = mLayout.getLineBottom(line); + final int primaryHorizontal = (int) mLayout.getPrimaryHorizontal(offset); + return isPositionVisible(primaryHorizontal + viewportToContentHorizontalOffset(), + lineBottom + viewportToContentVerticalOffset()); } @Override @@ -9510,7 +9530,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener public void updatePosition(int parentPositionX, int parentPositionY, boolean parentPositionChanged, boolean parentScrolled) { // Either parentPositionChanged or parentScrolled is true, check if still visible - if (isShowing() && getPositionListener().isOffsetVisible(getTextOffset())) { + if (isShowing() && isOffsetVisible(getTextOffset())) { if (parentScrolled) computeLocalPosition(); updatePosition(parentPositionX, parentPositionY); } else { @@ -9803,7 +9823,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener highlightTextDifferences(mSuggestionInfos[i], spanUnionStart, spanUnionEnd); } - // Add to dictionary item is there a span with the misspelled flag + // Add to dictionary item if there is a span with the misspelled flag if (misspelledSpan != null) { final int misspelledStart = spannable.getSpanStart(misspelledSpan); final int misspelledEnd = spannable.getSpanEnd(misspelledSpan); @@ -9867,9 +9887,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { - TextView textView = (TextView) view; Editable editable = (Editable) mText; - SuggestionInfo suggestionInfo = mSuggestionInfos[position]; if (suggestionInfo.suggestionIndex == DELETE_TEXT) { @@ -9883,7 +9901,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener Character.isSpaceChar(editable.charAt(spanUnionStart - 1)))) { spanUnionEnd = spanUnionEnd + 1; } - editable.replace(spanUnionStart, spanUnionEnd, ""); + deleteText_internal(spanUnionStart, spanUnionEnd); } hide(); return; @@ -9891,7 +9909,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener final int spanStart = editable.getSpanStart(suggestionInfo.suggestionSpan); final int spanEnd = editable.getSpanEnd(suggestionInfo.suggestionSpan); - if (spanStart < 0 || spanEnd < 0) { + if (spanStart < 0 || spanEnd <= spanStart) { // Span has been removed hide(); return; @@ -9901,11 +9919,13 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener if (suggestionInfo.suggestionIndex == ADD_TO_DICTIONARY) { Intent intent = new Intent(Settings.ACTION_USER_DICTIONARY_INSERT); intent.putExtra("word", originalText); + intent.putExtra("locale", getTextServicesLocale().toString()); intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK); getContext().startActivity(intent); // There is no way to know if the word was indeed added. Re-check. + // TODO The ExtractEditText should remove the span in the original text instead editable.removeSpan(suggestionInfo.suggestionSpan); - updateSpellCheckSpans(spanStart, spanEnd); + updateSpellCheckSpans(spanStart, spanEnd, false); } else { // SuggestionSpans are removed by replace: save them before SuggestionSpan[] suggestionSpans = editable.getSpans(spanStart, spanEnd, @@ -9931,9 +9951,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener final int suggestionStart = suggestionInfo.suggestionStart; final int suggestionEnd = suggestionInfo.suggestionEnd; - final String suggestion = textView.getText().subSequence( + final String suggestion = suggestionInfo.text.subSequence( suggestionStart, suggestionEnd).toString(); - editable.replace(spanStart, spanEnd, suggestion); + replaceText_internal(spanStart, spanEnd, suggestion); // Notify source IME of the suggestion pick. Do this before swaping texts. if (!TextUtils.isEmpty( @@ -9957,13 +9977,14 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener // way to assign them a valid range after replacement if (suggestionSpansStarts[i] <= spanStart && suggestionSpansEnds[i] >= spanEnd) { - editable.setSpan(suggestionSpans[i], suggestionSpansStarts[i], + setSpan_internal(suggestionSpans[i], suggestionSpansStarts[i], suggestionSpansEnds[i] + lengthDifference, suggestionSpansFlags[i]); } } // Move cursor at the end of the replaced word - Selection.setSelection(editable, spanEnd + lengthDifference); + final int newCursorPosition = spanEnd + lengthDifference; + setCursorPosition_internal(newCursorPosition, newCursorPosition); } hide(); @@ -10534,7 +10555,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener return false; } - return getPositionListener().isVisible(mPositionX + mHotspotX, mPositionY); + return TextView.this.isPositionVisible(mPositionX + mHotspotX, mPositionY); } public abstract int getCurrentCursorOffset(); @@ -10823,7 +10844,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener // Handles can not cross and selection is at least one character final int selectionEnd = getSelectionEnd(); - if (offset >= selectionEnd) offset = selectionEnd - 1; + if (offset >= selectionEnd) offset = Math.max(0, selectionEnd - 1); positionAtCursorOffset(offset, false); } @@ -10865,7 +10886,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener // Handles can not cross and selection is at least one character final int selectionStart = getSelectionStart(); - if (offset <= selectionStart) offset = selectionStart + 1; + if (offset <= selectionStart) offset = Math.min(selectionStart + 1, mText.length()); positionAtCursorOffset(offset, false); } @@ -11237,7 +11258,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener int max = extractRangeEndFromLong(minMax); Selection.setSelection((Spannable) mText, max); - ((Editable) mText).replace(min, max, content); + replaceText_internal(min, max, content); if (dragDropIntoItself) { int dragSourceStart = dragLocalState.start; @@ -11250,7 +11271,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } // Delete original selection - ((Editable) mText).delete(dragSourceStart, dragSourceEnd); + deleteText_internal(dragSourceStart, dragSourceEnd); // Make sure we do not leave two adjacent spaces. if ((dragSourceStart == 0 || @@ -11259,7 +11280,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener Character.isSpaceChar(mTransformed.charAt(dragSourceStart)))) { final int pos = dragSourceStart == mText.length() ? dragSourceStart - 1 : dragSourceStart; - ((Editable) mText).delete(pos, pos + 1); + deleteText_internal(pos, pos + 1); } } } @@ -11420,6 +11441,38 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } } + /** + * Deletes the range of text [start, end[. + * @hide + */ + protected void deleteText_internal(int start, int end) { + ((Editable) mText).delete(start, end); + } + + /** + * Replaces the range of text [start, end[ by replacement text + * @hide + */ + protected void replaceText_internal(int start, int end, CharSequence text) { + ((Editable) mText).replace(start, end, text); + } + + /** + * Sets a span on the specified range of text + * @hide + */ + protected void setSpan_internal(Object span, int start, int end, int flags) { + ((Editable) mText).setSpan(span, start, end, flags); + } + + /** + * Moves the cursor to the specified offset position in text + * @hide + */ + protected void setCursorPosition_internal(int start, int end) { + Selection.setSelection(((Editable) mText), start, end); + } + @ViewDebug.ExportedProperty(category = "text") private CharSequence mText; private CharSequence mTransformed; @@ -11500,6 +11553,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener private Path mHighlightPath; private boolean mHighlightPathBogus = true; private static final RectF sTempRect = new RectF(); + private static final float[] sTmpPosition = new float[2]; // XXX should be much larger private static final int VERY_WIDE = 1024*1024; diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java index 3e96c815e9b6..fec4cbc9d402 100644 --- a/core/java/com/android/internal/os/BatteryStatsImpl.java +++ b/core/java/com/android/internal/os/BatteryStatsImpl.java @@ -1275,7 +1275,7 @@ public final class BatteryStatsImpl extends BatteryStats { // record changes to the battery level. if (mHistoryLastWritten.batteryLevel == mHistoryCur.batteryLevel && (dataSize >= MAX_MAX_HISTORY_BUFFER - || ((mHistoryEnd.states^mHistoryCur.states) + || ((mHistoryLastWritten.states^mHistoryCur.states) & HistoryItem.MOST_INTERESTING_STATES) == 0)) { return; } diff --git a/core/java/com/android/internal/util/StateMachine.java b/core/java/com/android/internal/util/StateMachine.java index 36f02469ae6a..61c0c8e8cca5 100644 --- a/core/java/com/android/internal/util/StateMachine.java +++ b/core/java/com/android/internal/util/StateMachine.java @@ -418,7 +418,7 @@ public class StateMachine { public static final int SM_QUIT_CMD = -1; /** Message.what value when initializing */ - public static final int SM_INIT_CMD = -1; + public static final int SM_INIT_CMD = -2; /** * Convenience constant that maybe returned by processMessage @@ -569,6 +569,13 @@ public class StateMachine { } /** + * Clear the list of Processed Message Info. + */ + void cleanup() { + mMessages.clear(); + } + + /** * @return the information on a particular record. 0 is the oldest * record and size()-1 is the newest record. If the index is to * large null is returned. @@ -608,6 +615,7 @@ public class StateMachine { } } + private static class SmHandler extends Handler { /** The debug flag */ @@ -782,15 +790,8 @@ public class StateMachine { */ if (destState != null) { if (destState == mQuittingState) { - /** - * We are quitting so ignore all messages. - */ - mSm.quitting(); - if (mSm.mSmThread != null) { - // If we made the thread then quit looper which stops the thread. - getLooper().quit(); - mSm.mSmThread = null; - } + cleanupAfterQuitting(); + } else if (destState == mHaltingState) { /** * Call halting() if we've transitioned to the halting @@ -803,6 +804,29 @@ public class StateMachine { } /** + * Cleanup all the static variables and the looper after the SM has been quit. + */ + private final void cleanupAfterQuitting() { + mSm.quitting(); + if (mSm.mSmThread != null) { + // If we made the thread then quit looper which stops the thread. + getLooper().quit(); + mSm.mSmThread = null; + } + + mSm.mSmHandler = null; + mSm = null; + mMsg = null; + mProcessedMessages.cleanup(); + mStateStack = null; + mTempStateStack = null; + mStateInfo.clear(); + mInitialState = null; + mDestState = null; + mDeferredMessages.clear(); + } + + /** * Complete the construction of the state machine. */ private final void completeConstruction() { @@ -1343,10 +1367,12 @@ public class StateMachine { /** * Get a message and set Message.target = this. * - * @return message + * @return message or null if SM has quit */ public final Message obtainMessage() { + if (mSmHandler == null) return null; + return Message.obtain(mSmHandler); } @@ -1354,9 +1380,11 @@ public class StateMachine { * Get a message and set Message.target = this and what * * @param what is the assigned to Message.what. - * @return message + * @return message or null if SM has quit */ public final Message obtainMessage(int what) { + if (mSmHandler == null) return null; + return Message.obtain(mSmHandler, what); } @@ -1366,10 +1394,12 @@ public class StateMachine { * * @param what is the assigned to Message.what. * @param obj is assigned to Message.obj. - * @return message + * @return message or null if SM has quit */ public final Message obtainMessage(int what, Object obj) { + if (mSmHandler == null) return null; + return Message.obtain(mSmHandler, what, obj); } @@ -1380,10 +1410,13 @@ public class StateMachine { * @param what is assigned to Message.what * @param arg1 is assigned to Message.arg1 * @param arg2 is assigned to Message.arg2 - * @return A Message object from the global pool. + * @return A Message object from the global pool or null if + * SM has quit */ public final Message obtainMessage(int what, int arg1, int arg2) { + if (mSmHandler == null) return null; + return Message.obtain(mSmHandler, what, arg1, arg2); } @@ -1395,10 +1428,13 @@ public class StateMachine { * @param arg1 is assigned to Message.arg1 * @param arg2 is assigned to Message.arg2 * @param obj is assigned to Message.obj - * @return A Message object from the global pool. + * @return A Message object from the global pool or null if + * SM has quit */ public final Message obtainMessage(int what, int arg1, int arg2, Object obj) { + if (mSmHandler == null) return null; + return Message.obtain(mSmHandler, what, arg1, arg2, obj); } @@ -1406,6 +1442,9 @@ public class StateMachine { * Enqueue a message to this state machine. */ public final void sendMessage(int what) { + // mSmHandler can be null if the state machine has quit. + if (mSmHandler == null) return; + mSmHandler.sendMessage(obtainMessage(what)); } @@ -1413,6 +1452,9 @@ public class StateMachine { * Enqueue a message to this state machine. */ public final void sendMessage(int what, Object obj) { + // mSmHandler can be null if the state machine has quit. + if (mSmHandler == null) return; + mSmHandler.sendMessage(obtainMessage(what,obj)); } @@ -1420,6 +1462,9 @@ public class StateMachine { * Enqueue a message to this state machine. */ public final void sendMessage(Message msg) { + // mSmHandler can be null if the state machine has quit. + if (mSmHandler == null) return; + mSmHandler.sendMessage(msg); } @@ -1427,6 +1472,9 @@ public class StateMachine { * Enqueue a message to this state machine after a delay. */ public final void sendMessageDelayed(int what, long delayMillis) { + // mSmHandler can be null if the state machine has quit. + if (mSmHandler == null) return; + mSmHandler.sendMessageDelayed(obtainMessage(what), delayMillis); } @@ -1434,6 +1482,9 @@ public class StateMachine { * Enqueue a message to this state machine after a delay. */ public final void sendMessageDelayed(int what, Object obj, long delayMillis) { + // mSmHandler can be null if the state machine has quit. + if (mSmHandler == null) return; + mSmHandler.sendMessageDelayed(obtainMessage(what, obj), delayMillis); } @@ -1441,6 +1492,9 @@ public class StateMachine { * Enqueue a message to this state machine after a delay. */ public final void sendMessageDelayed(Message msg, long delayMillis) { + // mSmHandler can be null if the state machine has quit. + if (mSmHandler == null) return; + mSmHandler.sendMessageDelayed(msg, delayMillis); } @@ -1485,6 +1539,9 @@ public class StateMachine { * will be processed. */ public final void quit() { + // mSmHandler can be null if the state machine has quit. + if (mSmHandler == null) return; + mSmHandler.quit(); } @@ -1499,6 +1556,9 @@ public class StateMachine { * @return if debugging is enabled */ public boolean isDbg() { + // mSmHandler can be null if the state machine has quit. + if (mSmHandler == null) return false; + return mSmHandler.isDbg(); } @@ -1508,6 +1568,9 @@ public class StateMachine { * @param dbg is true to enable debugging. */ public void setDbg(boolean dbg) { + // mSmHandler can be null if the state machine has quit. + if (mSmHandler == null) return; + mSmHandler.setDbg(dbg); } @@ -1515,6 +1578,9 @@ public class StateMachine { * Start the state machine. */ public void start() { + // mSmHandler can be null if the state machine has quit. + if (mSmHandler == null) return; + /** Send the complete construction message */ mSmHandler.completeConstruction(); } diff --git a/core/java/com/android/internal/widget/IRemoteViewsFactory.aidl b/core/java/com/android/internal/widget/IRemoteViewsFactory.aidl index 18076c462c03..7317ecf68fe9 100644 --- a/core/java/com/android/internal/widget/IRemoteViewsFactory.aidl +++ b/core/java/com/android/internal/widget/IRemoteViewsFactory.aidl @@ -22,6 +22,7 @@ import android.widget.RemoteViews; /** {@hide} */ interface IRemoteViewsFactory { void onDataSetChanged(); + oneway void onDataSetChangedAsync(); oneway void onDestroy(in Intent intent); int getCount(); RemoteViews getViewAt(int position); diff --git a/core/java/com/android/internal/widget/ScrollingTabContainerView.java b/core/java/com/android/internal/widget/ScrollingTabContainerView.java index b7bc36644cb6..25b0065fd7fe 100644 --- a/core/java/com/android/internal/widget/ScrollingTabContainerView.java +++ b/core/java/com/android/internal/widget/ScrollingTabContainerView.java @@ -29,6 +29,7 @@ import android.text.TextUtils.TruncateAt; import android.view.Gravity; import android.view.View; import android.view.ViewGroup; +import android.view.ViewParent; import android.view.animation.DecelerateInterpolator; import android.widget.AdapterView; import android.widget.BaseAdapter; @@ -392,7 +393,11 @@ public class ScrollingTabContainerView extends HorizontalScrollView final ActionBar.Tab tab = mTab; final View custom = tab.getCustomView(); if (custom != null) { - addView(custom); + final ViewParent customParent = custom.getParent(); + if (customParent != this) { + if (customParent != null) ((ViewGroup) customParent).removeView(custom); + addView(custom); + } mCustomView = custom; if (mTextView != null) mTextView.setVisibility(GONE); if (mIconView != null) { diff --git a/core/jni/android/graphics/HarfbuzzSkia.cpp b/core/jni/android/graphics/HarfbuzzSkia.cpp index 92c743fe482f..f6f7b452468e 100644 --- a/core/jni/android/graphics/HarfbuzzSkia.cpp +++ b/core/jni/android/graphics/HarfbuzzSkia.cpp @@ -211,22 +211,7 @@ const HB_FontClass harfbuzzSkiaClass = { HB_Error harfbuzzSkiaGetTable(void* voidface, const HB_Tag tag, HB_Byte* buffer, HB_UInt* len) { - FontData* data = reinterpret_cast<FontData*>(voidface); - SkTypeface* typeface = data->typeFace; - - const size_t tableSize = SkFontHost::GetTableSize(typeface->uniqueID(), tag); - if (!tableSize) - return HB_Err_Invalid_Argument; - // If Harfbuzz specified a NULL buffer then it's asking for the size of the table. - if (!buffer) { - *len = tableSize; - return HB_Err_Ok; - } - - if (*len < tableSize) - return HB_Err_Invalid_Argument; - SkFontHost::GetTableData(typeface->uniqueID(), tag, 0, tableSize, buffer); - return HB_Err_Ok; + return HB_Err_Invalid_Argument; } } // namespace android diff --git a/core/jni/android/graphics/TextLayoutCache.cpp b/core/jni/android/graphics/TextLayoutCache.cpp index 7076e2a84eb3..662d9187ed90 100644 --- a/core/jni/android/graphics/TextLayoutCache.cpp +++ b/core/jni/android/graphics/TextLayoutCache.cpp @@ -346,9 +346,6 @@ void TextLayoutCacheValue::initShaperItem(HB_ShaperItem& shaperItem, HB_FontRec* font->x_scale = 1; font->y_scale = 1; - shaperItem.font = font; - shaperItem.face = HB_NewFace(shaperItem.font, harfbuzzSkiaGetTable); - // Reset kerning shaperItem.kerning_applied = false; @@ -360,17 +357,17 @@ void TextLayoutCacheValue::initShaperItem(HB_ShaperItem& shaperItem, HB_FontRec* fontData->flags = paint->getFlags(); fontData->hinting = paint->getHinting(); + shaperItem.font = font; shaperItem.font->userData = fontData; + shaperItem.face = HB_NewFace(NULL, harfbuzzSkiaGetTable); + // We cannot know, ahead of time, how many glyphs a given script run // will produce. We take a guess that script runs will not produce more // than twice as many glyphs as there are code points plus a bit of // padding and fallback if we find that we are wrong. createGlyphArrays(shaperItem, (contextCount + 2) * 2); - // Create log clusters array - shaperItem.log_clusters = new unsigned short[contextCount]; - // Set the string properties shaperItem.string = chars; shaperItem.stringLength = contextCount; @@ -378,7 +375,6 @@ void TextLayoutCacheValue::initShaperItem(HB_ShaperItem& shaperItem, HB_FontRec* void TextLayoutCacheValue::freeShaperItem(HB_ShaperItem& shaperItem) { deleteGlyphArrays(shaperItem); - delete[] shaperItem.log_clusters; HB_FreeFace(shaperItem.face); } @@ -392,6 +388,7 @@ void TextLayoutCacheValue::shapeRun(HB_ShaperItem& shaperItem, size_t start, siz shaperItem.item.script = isRTL ? HB_Script_Arabic : HB_Script_Common; // Shape + assert(shaperItem.item.length > 0); // Harfbuzz will overwrite other memory if length is 0. while (!HB_ShapeItem(&shaperItem)) { // We overflowed our arrays. Resize and retry. // HB_ShapeItem fills in shaperItem.num_glyphs with the needed size. @@ -404,6 +401,10 @@ void TextLayoutCacheValue::computeValuesWithHarfbuzz(SkPaint* paint, const UChar size_t start, size_t count, size_t contextCount, int dirFlags, Vector<jfloat>* const outAdvances, jfloat* outTotalAdvance, Vector<jchar>* const outGlyphs) { + if (!count) { + *outTotalAdvance = 0; + return; + } UBiDiLevel bidiReq = 0; bool forceLTR = false; @@ -544,6 +545,10 @@ void TextLayoutCacheValue::computeRunValuesWithHarfbuzz(HB_ShaperItem& shaperIte size_t start, size_t count, bool isRTL, Vector<jfloat>* const outAdvances, jfloat* outTotalAdvance, Vector<jchar>* const outGlyphs) { + if (!count) { + *outTotalAdvance = 0; + return; + } shapeRun(shaperItem, start, count, isRTL); @@ -607,14 +612,22 @@ void TextLayoutCacheValue::deleteGlyphArrays(HB_ShaperItem& shaperItem) { delete[] shaperItem.attributes; delete[] shaperItem.advances; delete[] shaperItem.offsets; + delete[] shaperItem.log_clusters; } void TextLayoutCacheValue::createGlyphArrays(HB_ShaperItem& shaperItem, int size) { + shaperItem.num_glyphs = size; + + // These arrays are all indexed by glyph shaperItem.glyphs = new HB_Glyph[size]; shaperItem.attributes = new HB_GlyphAttributes[size]; shaperItem.advances = new HB_Fixed[size]; shaperItem.offsets = new HB_FixedPoint[size]; - shaperItem.num_glyphs = size; + + // Although the log_clusters array is indexed by character, Harfbuzz expects that + // it is big enough to hold one element per glyph. So we allocate log_clusters along + // with the other glyph arrays above. + shaperItem.log_clusters = new unsigned short[size]; } } // namespace android diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp index 4f75fad684f3..426f4f7cbb59 100644 --- a/core/jni/android_view_GLES20Canvas.cpp +++ b/core/jni/android_view_GLES20Canvas.cpp @@ -23,6 +23,7 @@ #include <nativehelper/JNIHelp.h> #include <android_runtime/AndroidRuntime.h> #include <android_runtime/android_graphics_SurfaceTexture.h> +#include <cutils/properties.h> #include <utils/ResourceTypes.h> #include <gui/SurfaceTexture.h> @@ -736,7 +737,15 @@ static jboolean android_view_GLES20Canvas_copyLayer(JNIEnv* env, jobject clazz, static jboolean android_view_GLES20Canvas_isAvailable(JNIEnv* env, jobject clazz) { #ifdef USE_OPENGL_RENDERER - return JNI_TRUE; + char prop[PROPERTY_VALUE_MAX]; + if (property_get("ro.kernel.qemu", prop, NULL) == 0) { + // not in the emulator + return JNI_TRUE; + } + // In the emulator this property will be set to 1 when hardware GLES is + // enabled, 0 otherwise. On old emulator versions it will be undefined. + property_get("ro.kernel.qemu.gles", prop, "0"); + return atoi(prop) == 1 ? JNI_TRUE : JNI_FALSE; #else return JNI_FALSE; #endif diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp index 49441ebc9f7c..bba4b4714979 100644 --- a/core/jni/android_view_Surface.cpp +++ b/core/jni/android_view_Surface.cpp @@ -752,6 +752,25 @@ static void Surface_copyFrom( } } +static void Surface_transferFrom( + JNIEnv* env, jobject clazz, jobject other) +{ + if (clazz == other) + return; + + if (other == NULL) { + doThrowNPE(env); + return; + } + + sp<SurfaceControl> control(getSurfaceControl(env, other)); + sp<Surface> surface(Surface_getSurface(env, other)); + setSurfaceControl(env, clazz, control); + setSurface(env, clazz, surface); + setSurfaceControl(env, other, 0); + setSurface(env, other, 0); +} + static void Surface_readFromParcel( JNIEnv* env, jobject clazz, jobject argParcel) { @@ -820,6 +839,7 @@ static JNINativeMethod gSurfaceMethods[] = { {"destroy", "()V", (void*)Surface_destroy }, {"release", "()V", (void*)Surface_release }, {"copyFrom", "(Landroid/view/Surface;)V", (void*)Surface_copyFrom }, + {"transferFrom", "(Landroid/view/Surface;)V", (void*)Surface_transferFrom }, {"isValid", "()Z", (void*)Surface_isValid }, {"lockCanvasNative", "(Landroid/graphics/Rect;)Landroid/graphics/Canvas;", (void*)Surface_lockCanvas }, {"unlockCanvasAndPost", "(Landroid/graphics/Canvas;)V", (void*)Surface_unlockCanvasAndPost }, diff --git a/core/res/res/anim/app_starting_exit.xml b/core/res/res/anim/app_starting_exit.xml index ee8d80bb0a74..60e4109837d4 100644 --- a/core/res/res/anim/app_starting_exit.xml +++ b/core/res/res/anim/app_starting_exit.xml @@ -18,7 +18,8 @@ */ --> -<set xmlns:android="http://schemas.android.com/apk/res/android" android:interpolator="@interpolator/decelerate_quad"> +<set xmlns:android="http://schemas.android.com/apk/res/android" + android:detachWallpaper="true" android:interpolator="@interpolator/decelerate_quad"> <alpha android:fromAlpha="1.0" android:toAlpha="0.0" android:duration="160" /> </set> diff --git a/core/res/res/drawable/silent_mode_indicator.xml b/core/res/res/drawable/silent_mode_indicator.xml new file mode 100644 index 000000000000..c4e129f9fb8e --- /dev/null +++ b/core/res/res/drawable/silent_mode_indicator.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2011 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_selected="false" android:drawable="@android:color/transparent" /> + <item android:state_selected="true" android:drawable="@drawable/tab_selected_holo" /> +</selector> diff --git a/core/res/res/layout-sw600dp/keyguard_screen_password_landscape.xml b/core/res/res/layout-sw600dp/keyguard_screen_password_landscape.xml index f9728434a838..7a5bb6a915b1 100644 --- a/core/res/res/layout-sw600dp/keyguard_screen_password_landscape.xml +++ b/core/res/res/layout-sw600dp/keyguard_screen_password_landscape.xml @@ -134,6 +134,7 @@ android:layout_marginTop="5dip" android:keyBackground="@drawable/btn_keyboard_key_ics" android:visibility="gone" + android:clickable="true" /> <!-- Emergency call button. Generally not used on tablet devices. --> diff --git a/core/res/res/layout-sw600dp/keyguard_screen_password_portrait.xml b/core/res/res/layout-sw600dp/keyguard_screen_password_portrait.xml index 8b65b223e4e6..6df22cae5fcd 100644 --- a/core/res/res/layout-sw600dp/keyguard_screen_password_portrait.xml +++ b/core/res/res/layout-sw600dp/keyguard_screen_password_portrait.xml @@ -133,6 +133,7 @@ android:background="#40000000" android:keyBackground="@drawable/btn_keyboard_key_ics" android:layout_marginBottom="80dip" + android:clickable="true" /> <!-- emergency call button --> diff --git a/core/res/res/layout-sw600dp/keyguard_screen_sim_pin_landscape.xml b/core/res/res/layout-sw600dp/keyguard_screen_sim_pin_landscape.xml index c65dd83a0387..0b94fc16fd2d 100644 --- a/core/res/res/layout-sw600dp/keyguard_screen_sim_pin_landscape.xml +++ b/core/res/res/layout-sw600dp/keyguard_screen_sim_pin_landscape.xml @@ -93,29 +93,29 @@ android:layout_marginLeft="8dip" android:layout_marginRight="8dip"> - <Button android:id="@+id/ok" - android:text="@android:string/ok" + <Button android:id="@+id/emergencyCallButton" + android:text="@android:string/lockscreen_emergency_call" android:layout_alignParentBottom="true" + android:layout_centerHorizontal="true" android:layout_width="0dip" android:layout_height="wrap_content" android:layout_weight="1.0" android:layout_marginBottom="8dip" android:layout_marginRight="8dip" android:textSize="18sp" - /> + android:drawableLeft="@drawable/ic_emergency" + android:drawablePadding="8dip" + /> - <Button android:id="@+id/emergencyCallButton" - android:text="@android:string/lockscreen_emergency_call" + <Button android:id="@+id/ok" + android:text="@android:string/ok" android:layout_alignParentBottom="true" - android:layout_centerHorizontal="true" android:layout_width="0dip" android:layout_height="wrap_content" android:layout_weight="1.0" android:layout_marginBottom="8dip" android:layout_marginLeft="8dip" android:textSize="18sp" - android:drawableLeft="@drawable/ic_emergency" - android:drawablePadding="8dip" /> </LinearLayout> diff --git a/core/res/res/layout/date_picker.xml b/core/res/res/layout/date_picker.xml index 6f0517da30e6..9c1def2be6ef 100644 --- a/core/res/res/layout/date_picker.xml +++ b/core/res/res/layout/date_picker.xml @@ -32,7 +32,6 @@ <LinearLayout android:id="@+id/pickers" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_marginRight="22dip" android:layout_weight="1" android:orientation="horizontal" android:gravity="center"> @@ -77,7 +76,7 @@ android:id="@+id/calendar_view" android:layout_width="245dip" android:layout_height="280dip" - android:layout_marginLeft="22dip" + android:layout_marginLeft="44dip" android:layout_weight="1" android:focusable="true" android:focusableInTouchMode="true" diff --git a/core/res/res/layout/global_actions_item.xml b/core/res/res/layout/global_actions_item.xml index 67b164479cbe..694301ea590a 100644 --- a/core/res/res/layout/global_actions_item.xml +++ b/core/res/res/layout/global_actions_item.xml @@ -14,48 +14,46 @@ limitations under the License. --> -<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" +<!-- RelativeLayouts have an issue enforcing minimum heights, so just + work around this for now with LinearLayouts. --> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" - android:layout_height="?android:attr/listPreferredItemHeight" + android:layout_height="wrap_content" + android:minHeight="?android:attr/listPreferredItemHeight" + android:orientation="horizontal" - android:paddingLeft="11dip" + android:paddingLeft="16dip" android:paddingTop="6dip" android:paddingBottom="6dip" > - <ImageView android:id="@+id/icon" android:layout_width="wrap_content" android:layout_height="match_parent" - android:layout_alignParentTop="true" - android:layout_alignParentBottom="true" - android:layout_marginRight="9dip" - /> - - - <TextView android:id="@+id/status" - android:layout_width="match_parent" - android:layout_height="26dip" - - android:layout_toRightOf="@id/icon" - android:layout_alignParentBottom="true" - android:layout_alignParentRight="true" - - android:textAppearance="?android:attr/textAppearanceSmall" + android:layout_gravity="center" + android:layout_marginRight="16dip" /> - - <TextView android:id="@+id/message" + <LinearLayout + android:orientation="vertical" android:layout_width="match_parent" android:layout_height="wrap_content" + android:layout_gravity="center_vertical" + > + <TextView android:id="@+id/message" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_gravity="top" + + android:gravity="center_vertical" + android:textAppearance="?android:attr/textAppearanceLarge" + /> + <TextView android:id="@+id/status" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_gravity="bottom" + android:minHeight="26dp" - android:layout_toRightOf="@id/icon" - android:layout_alignParentRight="true" - android:layout_alignParentTop="true" - android:layout_above="@id/status" - android:layout_alignWithParentIfMissing="true" - android:gravity="center_vertical" - android:textAppearance="?android:attr/textAppearanceLarge" - /> - - -</RelativeLayout> + android:textAppearance="?android:attr/textAppearanceSmall" + /> + </LinearLayout> +</LinearLayout>
\ No newline at end of file diff --git a/core/res/res/layout/global_actions_silent_mode.xml b/core/res/res/layout/global_actions_silent_mode.xml new file mode 100644 index 000000000000..18b471523065 --- /dev/null +++ b/core/res/res/layout/global_actions_silent_mode.xml @@ -0,0 +1,103 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2011 The Android Open 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="wrap_content" + android:layout_height="wrap_content" + android:minHeight="?android:attr/listPreferredItemHeight" + android:orientation="horizontal" + > + + <LinearLayout + android:id="@+id/option1" + android:layout_width="64dp" + android:layout_height="match_parent" + android:background="?android:attr/actionBarItemBackground" + android:contentDescription="@string/silent_mode_silent" + android:focusable="true" + > + <ImageView + android:layout_width="48dp" + android:layout_height="match_parent" + android:layout_gravity="center" + android:layout_marginLeft="8dp" + android:layout_marginRight="8dp" + android:layout_marginTop="6dp" + android:layout_marginBottom="6dp" + android:src="@drawable/ic_audio_vol_mute" + android:scaleType="center" + android:duplicateParentState="true" + android:background="@drawable/silent_mode_indicator" + /> + </LinearLayout> + <!-- Spacer --> + <View android:layout_width="0dp" + android:layout_height="match_parent" + android:layout_weight="1" + android:visibility="invisible"/> + + <LinearLayout + android:id="@+id/option2" + android:layout_width="64dp" + android:layout_height="match_parent" + android:background="?android:attr/actionBarItemBackground" + android:contentDescription="@string/silent_mode_vibrate" + android:focusable="true" + > + <ImageView + android:layout_width="48dp" + android:layout_height="match_parent" + android:layout_gravity="center" + android:layout_marginLeft="8dp" + android:layout_marginRight="8dp" + android:layout_marginTop="6dp" + android:layout_marginBottom="6dp" + android:src="@drawable/ic_audio_ring_notif_vibrate" + android:scaleType="center" + android:duplicateParentState="true" + android:background="@drawable/silent_mode_indicator" + /> + </LinearLayout> + + <!-- Spacer --> + <View android:layout_width="0dp" + android:layout_height="match_parent" + android:layout_weight="1" + android:visibility="invisible"/> + + <LinearLayout + android:id="@+id/option3" + android:layout_width="64dp" + android:layout_height="match_parent" + android:background="?android:attr/actionBarItemBackground" + android:contentDescription="@string/silent_mode_ring" + android:focusable="true" + > + <ImageView + android:layout_width="48dp" + android:layout_height="match_parent" + android:layout_gravity="center" + android:layout_marginLeft="8dp" + android:layout_marginRight="8dp" + android:layout_marginTop="6dp" + android:layout_marginBottom="6dp" + android:src="@drawable/ic_audio_vol" + android:scaleType="center" + android:duplicateParentState="true" + android:background="@drawable/silent_mode_indicator" + /> + </LinearLayout> +</LinearLayout>
\ No newline at end of file diff --git a/core/res/res/layout/keyguard_screen_password_landscape.xml b/core/res/res/layout/keyguard_screen_password_landscape.xml index ba0c22f10041..e95553f882ec 100644 --- a/core/res/res/layout/keyguard_screen_password_landscape.xml +++ b/core/res/res/layout/keyguard_screen_password_landscape.xml @@ -193,6 +193,7 @@ android:keyBackground="@*android:drawable/btn_keyboard_key_ics" android:visibility="gone" android:layout_rowSpan="7" + android:clickable="true" /> <!-- Music transport control --> diff --git a/core/res/res/layout/keyguard_screen_password_portrait.xml b/core/res/res/layout/keyguard_screen_password_portrait.xml index f6933c3924de..053acb24c8d8 100644 --- a/core/res/res/layout/keyguard_screen_password_portrait.xml +++ b/core/res/res/layout/keyguard_screen_password_portrait.xml @@ -157,6 +157,7 @@ android:background="#40000000" android:keyBackground="@*android:drawable/btn_keyboard_key_ics" android:visibility="gone" + android:clickable="true" /> <TextView diff --git a/core/res/res/layout/keyguard_screen_sim_pin_landscape.xml b/core/res/res/layout/keyguard_screen_sim_pin_landscape.xml index 59065e11cbfc..3cb19c39390f 100644 --- a/core/res/res/layout/keyguard_screen_sim_pin_landscape.xml +++ b/core/res/res/layout/keyguard_screen_sim_pin_landscape.xml @@ -91,29 +91,29 @@ android:layout_marginLeft="8dip" android:layout_marginRight="8dip"> - <Button android:id="@+id/ok" - android:text="@android:string/ok" + <Button android:id="@+id/emergencyCallButton" + android:text="@android:string/lockscreen_emergency_call" android:layout_alignParentBottom="true" + android:layout_centerHorizontal="true" android:layout_width="0dip" android:layout_height="wrap_content" android:layout_weight="1.0" android:layout_marginBottom="8dip" android:layout_marginRight="8dip" android:textSize="18sp" - /> + android:drawableLeft="@drawable/ic_emergency" + android:drawablePadding="4dip" + /> - <Button android:id="@+id/emergencyCallButton" - android:text="@android:string/lockscreen_emergency_call" + <Button android:id="@+id/ok" + android:text="@android:string/ok" android:layout_alignParentBottom="true" - android:layout_centerHorizontal="true" android:layout_width="0dip" android:layout_height="wrap_content" android:layout_weight="1.0" android:layout_marginBottom="8dip" android:layout_marginLeft="8dip" android:textSize="18sp" - android:drawableLeft="@drawable/ic_emergency" - android:drawablePadding="4dip" /> </LinearLayout> diff --git a/core/res/res/layout/keyguard_screen_sim_puk_landscape.xml b/core/res/res/layout/keyguard_screen_sim_puk_landscape.xml index b662e8278b32..722dc262349a 100644 --- a/core/res/res/layout/keyguard_screen_sim_puk_landscape.xml +++ b/core/res/res/layout/keyguard_screen_sim_puk_landscape.xml @@ -153,29 +153,29 @@ android:layout_marginLeft="8dip" android:layout_marginRight="8dip"> - <Button android:id="@+id/ok" - android:text="@android:string/ok" + <Button android:id="@+id/emergencyCallButton" + android:text="@android:string/lockscreen_emergency_call" android:layout_alignParentBottom="true" + android:layout_centerHorizontal="true" android:layout_width="0dip" android:layout_height="wrap_content" android:layout_weight="1.0" android:layout_marginBottom="8dip" android:layout_marginRight="8dip" android:textSize="18sp" - /> + android:drawableLeft="@drawable/ic_emergency" + android:drawablePadding="4dip" + /> - <Button android:id="@+id/emergencyCallButton" - android:text="@android:string/lockscreen_emergency_call" + <Button android:id="@+id/ok" + android:text="@android:string/ok" android:layout_alignParentBottom="true" - android:layout_centerHorizontal="true" android:layout_width="0dip" android:layout_height="wrap_content" android:layout_weight="1.0" android:layout_marginBottom="8dip" android:layout_marginLeft="8dip" android:textSize="18sp" - android:drawableLeft="@drawable/ic_emergency" - android:drawablePadding="4dip" /> </LinearLayout> diff --git a/core/res/res/layout/twelve_key_entry.xml b/core/res/res/layout/twelve_key_entry.xml index 46301cd46a2d..09c749d451ff 100644 --- a/core/res/res/layout/twelve_key_entry.xml +++ b/core/res/res/layout/twelve_key_entry.xml @@ -144,7 +144,7 @@ android:layout_marginRight="2dip" android:orientation="horizontal"> - <Button android:id="@+id/ok" + <Button android:id="@+id/cancel" android:layout_width="0sp" android:layout_height="fill_parent" android:layout_weight="1" @@ -152,7 +152,7 @@ android:layout_marginRight="2dip" android:textAppearance="?android:attr/textAppearanceMedium" android:textStyle="bold" - android:text="@android:string/ok" + android:text="@android:string/cancel" /> <Button android:id="@+id/zero" @@ -165,7 +165,7 @@ android:textStyle="bold" /> - <Button android:id="@+id/cancel" + <Button android:id="@+id/ok" android:layout_width="0sp" android:layout_height="fill_parent" android:layout_weight="1" @@ -173,7 +173,7 @@ android:layout_marginRight="2dip" android:textAppearance="?android:attr/textAppearanceMedium" android:textStyle="bold" - android:text="@android:string/cancel" + android:text="@android:string/ok" /> </LinearLayout> diff --git a/core/res/res/values-af/donottranslate-cldr.xml b/core/res/res/values-af/donottranslate-cldr.xml new file mode 100644 index 000000000000..9d38717a5731 --- /dev/null +++ b/core/res/res/values-af/donottranslate-cldr.xml @@ -0,0 +1,146 @@ +<?xml version="1.0" encoding="UTF-8"?> +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="month_long_standalone_january">Januarie</string> + <string name="month_long_standalone_february">Februarie</string> + <string name="month_long_standalone_march">Maart</string> + <string name="month_long_standalone_april">April</string> + <string name="month_long_standalone_may">Mei</string> + <string name="month_long_standalone_june">Junie</string> + <string name="month_long_standalone_july">Julie</string> + <string name="month_long_standalone_august">Augustus</string> + <string name="month_long_standalone_september">September</string> + <string name="month_long_standalone_october">Oktober</string> + <string name="month_long_standalone_november">November</string> + <string name="month_long_standalone_december">Desember</string> + + <string name="month_long_january">Januarie</string> + <string name="month_long_february">Februarie</string> + <string name="month_long_march">Maart</string> + <string name="month_long_april">April</string> + <string name="month_long_may">Mei</string> + <string name="month_long_june">Junie</string> + <string name="month_long_july">Julie</string> + <string name="month_long_august">Augustus</string> + <string name="month_long_september">September</string> + <string name="month_long_october">Oktober</string> + <string name="month_long_november">November</string> + <string name="month_long_december">Desember</string> + + <string name="month_medium_january">Jan</string> + <string name="month_medium_february">Feb</string> + <string name="month_medium_march">Mar</string> + <string name="month_medium_april">Apr</string> + <string name="month_medium_may">Mei</string> + <string name="month_medium_june">Jun</string> + <string name="month_medium_july">Jul</string> + <string name="month_medium_august">Aug</string> + <string name="month_medium_september">Sep</string> + <string name="month_medium_october">Okt</string> + <string name="month_medium_november">Nov</string> + <string name="month_medium_december">Des</string> + + <string name="month_shortest_january">1</string> + <string name="month_shortest_february">2</string> + <string name="month_shortest_march">3</string> + <string name="month_shortest_april">4</string> + <string name="month_shortest_may">5</string> + <string name="month_shortest_june">6</string> + <string name="month_shortest_july">7</string> + <string name="month_shortest_august">8</string> + <string name="month_shortest_september">9</string> + <string name="month_shortest_october">10</string> + <string name="month_shortest_november">11</string> + <string name="month_shortest_december">12</string> + + <string name="day_of_week_long_sunday">Sondag</string> + <string name="day_of_week_long_monday">Maandag</string> + <string name="day_of_week_long_tuesday">Dinsdag</string> + <string name="day_of_week_long_wednesday">Woensdag</string> + <string name="day_of_week_long_thursday">Donderdag</string> + <string name="day_of_week_long_friday">Vrydag</string> + <string name="day_of_week_long_saturday">Saterdag</string> + + <string name="day_of_week_medium_sunday">So</string> + <string name="day_of_week_medium_monday">Ma</string> + <string name="day_of_week_medium_tuesday">Di</string> + <string name="day_of_week_medium_wednesday">Wo</string> + <string name="day_of_week_medium_thursday">Do</string> + <string name="day_of_week_medium_friday">Vr</string> + <string name="day_of_week_medium_saturday">Sa</string> + + <string name="day_of_week_short_sunday">So</string> + <string name="day_of_week_short_monday">Ma</string> + <string name="day_of_week_short_tuesday">Di</string> + <string name="day_of_week_short_wednesday">Wo</string> + <string name="day_of_week_short_thursday">Do</string> + <string name="day_of_week_short_friday">Vr</string> + <string name="day_of_week_short_saturday">Sa</string> + + <string name="day_of_week_shortest_sunday">1</string> + <string name="day_of_week_shortest_monday">2</string> + <string name="day_of_week_shortest_tuesday">3</string> + <string name="day_of_week_shortest_wednesday">4</string> + <string name="day_of_week_shortest_thursday">5</string> + <string name="day_of_week_shortest_friday">6</string> + <string name="day_of_week_shortest_saturday">7</string> + + <string name="am">vm.</string> + <string name="pm">nm.</string> + + <string name="hour_minute_24">%-k:%M</string> + <string name="hour_minute_ampm">%-l:%M %p</string> + <string name="hour_minute_cap_ampm">%-l:%M %^p</string> + <string name="twelve_hour_time_format">h:mm a</string> + <string name="twenty_four_hour_time_format">H:mm</string> + <string name="numeric_date">%Y/%m/%d</string> + <string name="numeric_date_format">yyyy/MM/dd</string> + <string name="numeric_date_template">"%s/%s/%s"</string> + <string name="month_day_year">%d %B %Y</string> + <string name="time_of_day">%-l:%M:%S %p</string> + <string name="date_and_time">%-l:%M:%S %p %d %b %Y</string> + <string name="date_time">%2$s %1$s</string> + <string name="time_date">%1$s %3$s</string> + <string name="abbrev_month_day_year">%d %b %Y</string> + <string name="month_day">%-e %B</string> + <string name="month">%-B</string> + <string name="month_year">%B %Y</string> + <string name="abbrev_month_day">%b %-e</string> + <string name="abbrev_month">%b</string> + <string name="abbrev_month_year">%Y %b</string> + <string name="time1_time2">%1$s - %2$s</string> + <string name="date1_date2">%2$s - %5$s</string> + <string name="numeric_md1_md2">%2$s-%3$s - %7$s-%8$s</string> + <string name="numeric_wday1_md1_wday2_md2">%1$s, %2$s-%3$s - %6$s, %7$s-%8$s</string> + <string name="numeric_mdy1_mdy2">%4$s-%2$s-%3$s - %9$s-%7$s-%8$s</string> + <string name="numeric_wday1_mdy1_wday2_mdy2">%1$s, %4$s-%2$s-%3$s - %6$s, %9$s-%7$s-%8$s</string> + <string name="numeric_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %4$s-%2$s-%3$s - %10$s %6$s, %9$s-%7$s-%8$s</string> + <string name="numeric_md1_time1_md2_time2">%5$s %2$s-%3$s - %10$s %7$s-%8$s</string> + <string name="numeric_wday1_md1_time1_wday2_md2_time2">%5$s %1$s, %2$s-%3$s - %10$s %6$s, %7$s-%8$s</string> + <string name="numeric_mdy1_time1_mdy2_time2">%5$s %4$s/%2$s/%3$s - %10$s %9$s/%7$s/%8$s</string> + <string name="wday1_date1_time1_wday2_date2_time2">%3$s %1$s, %2$s - %6$s %4$s, %5$s</string> + <string name="wday1_date1_wday2_date2">%1$s, %2$s - %4$s, %5$s</string> + <string name="date1_time1_date2_time2">%3$s %2$s - %6$s %5$s</string> + <string name="time_wday_date">%1$s %2$s, %3$s</string> + <string name="wday_date">%2$s, %3$s</string> + <string name="time_wday">%1$s %2$s</string> + <string name="same_year_md1_md2">%3$s %2$s - %8$s %7$s</string> + <string name="same_year_wday1_md1_wday2_md2">%1$s %2$s %3$s - %6$s %7$s %8$s</string> + <string name="same_year_md1_time1_md2_time2">%5$s %3$s %2$s - %10$s %8$s %7$s</string> + <string name="same_month_md1_time1_md2_time2">%5$s %3$s %2$s - %10$s %8$s %7$s</string> + <string name="same_year_wday1_md1_time1_wday2_md2_time2">%5$s %1$s %2$s %3$s - %10$s %6$s %7$s %8$s</string> + <string name="same_month_wday1_md1_time1_wday2_md2_time2">%5$s %1$s %2$s %3$s - %10$s %6$s %7$s %8$s</string> + <string name="same_year_mdy1_time1_mdy2_time2">%5$s %4$s %2$s %3$s - %10$s %9$s %7$s %8$s</string> + <string name="same_month_mdy1_time1_mdy2_time2">%5$s %4$s %2$s %3$s - %10$s %9$s %7$s %8$s</string> + <string name="same_year_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %4$s %2$s %3$s - %10$s %6$s, %9$s %7$s %8$s</string> + <string name="same_month_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %4$s %2$s %3$s - %10$s %6$s, %9$s %7$s %8$s</string> + <string name="same_month_wday1_mdy1_wday2_mdy2">%1$s, %4$s %2$s %3$s - %6$s, %9$s %7$s %8$s</string> + <string name="same_month_md1_md2">%2$s %3$s-%8$s</string> + <string name="same_month_wday1_md1_wday2_md2">%1$s %2$s %3$s - %6$s %7$s %8$s</string> + <string name="same_year_mdy1_mdy2">%9$s %2$s %3$s - %7$s %8$s</string> + <string name="same_month_mdy1_mdy2">%9$s %2$s %3$s-%8$s</string> + <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %9$s %2$s %3$s - %6$s, y %7$s %8$s</string> + <string name="short_format_month">%b</string> + <string name="full_wday_month_day_no_year">E MMMM d</string> + <string name="abbrev_wday_month_day_year">E, y MMM dd</string> +</resources> diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml index 168030c3b95a..cb235ba048b0 100644 --- a/core/res/res/values-af/strings.xml +++ b/core/res/res/values-af/strings.xml @@ -634,7 +634,7 @@ <string name="relationTypeParent" msgid="4755635567562925226">"Ouer"</string> <string name="relationTypePartner" msgid="7266490285120262781">"Vennoot"</string> <string name="relationTypeReferredBy" msgid="101573059844135524">"Verwys deur"</string> - <string name="relationTypeRelative" msgid="1799819930085610271">"Relatief"</string> + <string name="relationTypeRelative" msgid="1799819930085610271">"Familielid"</string> <string name="relationTypeSister" msgid="1735983554479076481">"Suster"</string> <string name="relationTypeSpouse" msgid="394136939428698117">"Eggenoot"</string> <string name="sipAddressTypeCustom" msgid="2473580593111590945">"Gepasmaakte"</string> @@ -959,6 +959,9 @@ <item quantity="one" msgid="1634101450343277345">"Oop Wi-Fi-netwerke beskikbaar"</item> <item quantity="other" msgid="7915895323644292768">"Oop Wi-Fi-netwerke beskikbaar"</item> </plurals> + <string name="wifi_available_sign_in" msgid="9157196203958866662">"Meld aan by Wi-Fi-netwerk"</string> + <!-- no translation found for wifi_available_sign_in_detailed (6797764740339907572) --> + <skip /> <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Kon nie aan Wi-Fikoppel nie"</string> <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" het \'n swak internetverbinding."</string> <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string> @@ -1219,6 +1222,6 @@ <string name="status_bar_device_locked" msgid="3092703448690669768">"Toestel gesluit."</string> <string name="list_delimeter" msgid="3975117572185494152">", "</string> <string name="sending" msgid="8715108995741758718">"Stuur tans..."</string> - <string name="launchBrowserDefault" msgid="2057951947297614725">"Begin Browser?"</string> - <string name="SetupCallDefault" msgid="6870275517518479651">"Aanvaar Bel?"</string> + <string name="launchBrowserDefault" msgid="2057951947297614725">"Begin webblaaier?"</string> + <string name="SetupCallDefault" msgid="6870275517518479651">"Aanvaar oproep?"</string> </resources> diff --git a/core/res/res/values-am/donottranslate-cldr.xml b/core/res/res/values-am/donottranslate-cldr.xml new file mode 100644 index 000000000000..2319fbf50b4b --- /dev/null +++ b/core/res/res/values-am/donottranslate-cldr.xml @@ -0,0 +1,146 @@ +<?xml version="1.0" encoding="UTF-8"?> +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="month_long_standalone_january">ጃንዩወሪ</string> + <string name="month_long_standalone_february">ፌብሩወሪ</string> + <string name="month_long_standalone_march">ማርች</string> + <string name="month_long_standalone_april">ኤፕረል</string> + <string name="month_long_standalone_may">ሜይ</string> + <string name="month_long_standalone_june">ጁን</string> + <string name="month_long_standalone_july">ጁላይ</string> + <string name="month_long_standalone_august">ኦገስት</string> + <string name="month_long_standalone_september">ሴፕቴምበር</string> + <string name="month_long_standalone_october">ኦክተውበር</string> + <string name="month_long_standalone_november">ኖቬምበር</string> + <string name="month_long_standalone_december">ዲሴምበር</string> + + <string name="month_long_january">ጃንዩወሪ</string> + <string name="month_long_february">ፌብሩወሪ</string> + <string name="month_long_march">ማርች</string> + <string name="month_long_april">ኤፕረል</string> + <string name="month_long_may">ሜይ</string> + <string name="month_long_june">ጁን</string> + <string name="month_long_july">ጁላይ</string> + <string name="month_long_august">ኦገስት</string> + <string name="month_long_september">ሴፕቴምበር</string> + <string name="month_long_october">ኦክተውበር</string> + <string name="month_long_november">ኖቬምበር</string> + <string name="month_long_december">ዲሴምበር</string> + + <string name="month_medium_january">ጃንዩ</string> + <string name="month_medium_february">ፌብሩ</string> + <string name="month_medium_march">ማርች</string> + <string name="month_medium_april">ኤፕረ</string> + <string name="month_medium_may">ሜይ</string> + <string name="month_medium_june">ጁን</string> + <string name="month_medium_july">ጁላይ</string> + <string name="month_medium_august">ኦገስ</string> + <string name="month_medium_september">ሴፕቴ</string> + <string name="month_medium_october">ኦክተ</string> + <string name="month_medium_november">ኖቬም</string> + <string name="month_medium_december">ዲሴም</string> + + <string name="month_shortest_january">ጃ</string> + <string name="month_shortest_february">ፌ</string> + <string name="month_shortest_march">ማ</string> + <string name="month_shortest_april">ኤ</string> + <string name="month_shortest_may">ሜ</string> + <string name="month_shortest_june">ጁ</string> + <string name="month_shortest_july">ጁ</string> + <string name="month_shortest_august">ኦ</string> + <string name="month_shortest_september">ሴ</string> + <string name="month_shortest_october">ኦ</string> + <string name="month_shortest_november">ኖ</string> + <string name="month_shortest_december">ዲ</string> + + <string name="day_of_week_long_sunday">እሑድ</string> + <string name="day_of_week_long_monday">ሰኞ</string> + <string name="day_of_week_long_tuesday">ማክሰኞ</string> + <string name="day_of_week_long_wednesday">ረቡዕ</string> + <string name="day_of_week_long_thursday">ሐሙስ</string> + <string name="day_of_week_long_friday">ዓርብ</string> + <string name="day_of_week_long_saturday">ቅዳሜ</string> + + <string name="day_of_week_medium_sunday">እሑድ</string> + <string name="day_of_week_medium_monday">ሰኞ</string> + <string name="day_of_week_medium_tuesday">ማክሰ</string> + <string name="day_of_week_medium_wednesday">ረቡዕ</string> + <string name="day_of_week_medium_thursday">ሐሙስ</string> + <string name="day_of_week_medium_friday">ዓርብ</string> + <string name="day_of_week_medium_saturday">ቅዳሜ</string> + + <string name="day_of_week_short_sunday">እሑድ</string> + <string name="day_of_week_short_monday">ሰኞ</string> + <string name="day_of_week_short_tuesday">ማክሰ</string> + <string name="day_of_week_short_wednesday">ረቡዕ</string> + <string name="day_of_week_short_thursday">ሐሙስ</string> + <string name="day_of_week_short_friday">ዓርብ</string> + <string name="day_of_week_short_saturday">ቅዳሜ</string> + + <string name="day_of_week_shortest_sunday">እ</string> + <string name="day_of_week_shortest_monday">ሰ</string> + <string name="day_of_week_shortest_tuesday">ማ</string> + <string name="day_of_week_shortest_wednesday">ረ</string> + <string name="day_of_week_shortest_thursday">ሐ</string> + <string name="day_of_week_shortest_friday">ዓ</string> + <string name="day_of_week_shortest_saturday">ቅ</string> + + <string name="am">ጡዋት</string> + <string name="pm">ከሳዓት</string> + + <string name="hour_minute_24">%-k:%M</string> + <string name="hour_minute_ampm">%-l:%M %p</string> + <string name="hour_minute_cap_ampm">%-l:%M %p</string> + <string name="twelve_hour_time_format">h:mm a</string> + <string name="twenty_four_hour_time_format">H:mm</string> + <string name="numeric_date">%d/%m/%Y</string> + <string name="numeric_date_format">dd/MM/yyyy</string> + <string name="numeric_date_template">"%s/%s/%s"</string> + <string name="month_day_year">%d %B %Y</string> + <string name="time_of_day">%-l:%M:%S %p</string> + <string name="date_and_time">%-l:%M:%S %p %b %-e %Y</string> + <string name="date_time">%2$s %1$s</string> + <string name="time_date">%1$s %3$s</string> + <string name="abbrev_month_day_year">%b %-e %Y</string> + <string name="month_day">%B %-e</string> + <string name="month">%-B</string> + <string name="month_year">%B %Y</string> + <string name="abbrev_month_day">%b %-e</string> + <string name="abbrev_month">%b</string> + <string name="abbrev_month_year">%Y %b</string> + <string name="time1_time2">%1$s - %2$s</string> + <string name="date1_date2">%2$s - %5$s</string> + <string name="numeric_md1_md2">%2$s-%3$s - %7$s-%8$s</string> + <string name="numeric_wday1_md1_wday2_md2">%1$s, %2$s-%3$s - %6$s, %7$s-%8$s</string> + <string name="numeric_mdy1_mdy2">%4$s-%2$s-%3$s - %9$s-%7$s-%8$s</string> + <string name="numeric_wday1_mdy1_wday2_mdy2">%1$s, %4$s-%2$s-%3$s - %6$s, %9$s-%7$s-%8$s</string> + <string name="numeric_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %4$s-%2$s-%3$s - %10$s %6$s, %9$s-%7$s-%8$s</string> + <string name="numeric_md1_time1_md2_time2">%5$s %2$s-%3$s - %10$s %7$s-%8$s</string> + <string name="numeric_wday1_md1_time1_wday2_md2_time2">%5$s %1$s, %2$s-%3$s - %10$s %6$s, %7$s-%8$s</string> + <string name="numeric_mdy1_time1_mdy2_time2">%5$s %3$s/%2$s/%4$s - %10$s %8$s/%7$s/%9$s</string> + <string name="wday1_date1_time1_wday2_date2_time2">%3$s %1$s, %2$s - %6$s %4$s, %5$s</string> + <string name="wday1_date1_wday2_date2">%1$s, %2$s - %4$s, %5$s</string> + <string name="date1_time1_date2_time2">%3$s %2$s - %6$s %5$s</string> + <string name="time_wday_date">%1$s %2$s, %3$s</string> + <string name="wday_date">%2$s, %3$s</string> + <string name="time_wday">%1$s %2$s</string> + <string name="same_year_md1_md2">%2$s %3$s - %7$s %8$s</string> + <string name="same_year_wday1_md1_wday2_md2">%1$s %2$s %3$s - %6$s %7$s %8$s</string> + <string name="same_year_md1_time1_md2_time2">%5$s %2$s %3$s - %10$s %7$s %8$s</string> + <string name="same_month_md1_time1_md2_time2">%5$s %2$s %3$s - %10$s %7$s %8$s</string> + <string name="same_year_wday1_md1_time1_wday2_md2_time2">%5$s %1$s %2$s %3$s - %10$s %6$s %7$s %8$s</string> + <string name="same_month_wday1_md1_time1_wday2_md2_time2">%5$s %1$s %2$s %3$s - %10$s %6$s %7$s %8$s</string> + <string name="same_year_mdy1_time1_mdy2_time2">%5$s %4$s %2$s %3$s - %10$s %9$s %7$s %8$s</string> + <string name="same_month_mdy1_time1_mdy2_time2">%5$s %4$s %2$s %3$s - %10$s %9$s %7$s %8$s</string> + <string name="same_year_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %4$s %2$s %3$s - %10$s %6$s, %9$s %7$s %8$s</string> + <string name="same_month_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %4$s %2$s %3$s - %10$s %6$s, %9$s %7$s %8$s</string> + <string name="same_month_wday1_mdy1_wday2_mdy2">%1$s, %4$s %2$s %3$s - %6$s, %9$s %7$s %8$s</string> + <string name="same_month_md1_md2">%2$s %3$s-%8$s</string> + <string name="same_month_wday1_md1_wday2_md2">%1$s %2$s %3$s - %6$s %7$s %8$s</string> + <string name="same_year_mdy1_mdy2">%9$s %2$s %3$s - %7$s %8$s</string> + <string name="same_month_mdy1_mdy2">%9$s %2$s %3$s-%8$s</string> + <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %9$s %2$s %3$s - %6$s, y %7$s %8$s</string> + <string name="short_format_month">%b</string> + <string name="full_wday_month_day_no_year">E MMMM d</string> + <string name="abbrev_wday_month_day_year">E, y MMM dd</string> +</resources> diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml index 728ef4cea3da..c51ca35fc536 100644 --- a/core/res/res/values-am/strings.xml +++ b/core/res/res/values-am/strings.xml @@ -959,6 +959,9 @@ <item quantity="one" msgid="1634101450343277345">"አውታረ መረብ ሲኖር Wi-Fi ክፈት"</item> <item quantity="other" msgid="7915895323644292768">"አውታረ መረቦች ሲኖሩ Wi-Fi ክፈት"</item> </plurals> + <string name="wifi_available_sign_in" msgid="9157196203958866662">"ወደ Wi-Fi አውታረ መረብ በመለያ ግባ"</string> + <!-- no translation found for wifi_available_sign_in_detailed (6797764740339907572) --> + <skip /> <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"ወደ Wi-Fi ለማያያዝ አልተቻለም"</string> <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" ደካማ የበይነመረብ ግንኙነት ኣለው፡፡"</string> <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi ቀጥታ"</string> diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml index a07106bb8a3d..120a0015bd1e 100644 --- a/core/res/res/values-ar/strings.xml +++ b/core/res/res/values-ar/strings.xml @@ -959,6 +959,9 @@ <item quantity="one" msgid="1634101450343277345">"هناك شبكة Wi-Fi مفتوحة متاحة"</item> <item quantity="other" msgid="7915895323644292768">"هناك شبكات Wi-Fi مفتوحة متاحة"</item> </plurals> + <string name="wifi_available_sign_in" msgid="9157196203958866662">"تسجيل الدخول إلى شبكة Wi-Fi"</string> + <!-- no translation found for wifi_available_sign_in_detailed (6797764740339907572) --> + <skip /> <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"تعذر الاتصال بـ Wi-Fi"</string> <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" تحتوي على اتصال إنترنت ضعيف."</string> <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"اتصال Wi-Fi مباشر"</string> diff --git a/core/res/res/values-be/donottranslate-cldr.xml b/core/res/res/values-be/donottranslate-cldr.xml new file mode 100644 index 000000000000..365e60d1f8dc --- /dev/null +++ b/core/res/res/values-be/donottranslate-cldr.xml @@ -0,0 +1,138 @@ +<?xml version="1.0" encoding="UTF-8"?> +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="month_long_standalone_may">травень</string> + + <string name="month_long_january">студзень</string> + <string name="month_long_february">люты</string> + <string name="month_long_march">сакавік</string> + <string name="month_long_april">красавік</string> + <string name="month_long_may">май</string> + <string name="month_long_june">чэрвень</string> + <string name="month_long_july">ліпень</string> + <string name="month_long_august">жнівень</string> + <string name="month_long_september">верасень</string> + <string name="month_long_october">кастрычнік</string> + <string name="month_long_november">лістапад</string> + <string name="month_long_december">снежань</string> + + <string name="month_medium_january">сту</string> + <string name="month_medium_february">лют</string> + <string name="month_medium_march">сак</string> + <string name="month_medium_april">кра</string> + <string name="month_medium_may">май</string> + <string name="month_medium_june">чэр</string> + <string name="month_medium_july">ліп</string> + <string name="month_medium_august">жні</string> + <string name="month_medium_september">вер</string> + <string name="month_medium_october">кас</string> + <string name="month_medium_november">ліс</string> + <string name="month_medium_december">сне</string> + + <string name="month_shortest_january">с</string> + <string name="month_shortest_february">л</string> + <string name="month_shortest_march">с</string> + <string name="month_shortest_april">к</string> + <string name="month_shortest_may">м</string> + <string name="month_shortest_june">ч</string> + <string name="month_shortest_july">л</string> + <string name="month_shortest_august">ж</string> + <string name="month_shortest_september">в</string> + <string name="month_shortest_october">к</string> + <string name="month_shortest_november">л</string> + <string name="month_shortest_december">с</string> + + <string name="day_of_week_long_sunday">нядзеля</string> + <string name="day_of_week_long_monday">панядзелак</string> + <string name="day_of_week_long_tuesday">аўторак</string> + <string name="day_of_week_long_wednesday">серада</string> + <string name="day_of_week_long_thursday">чацвер</string> + <string name="day_of_week_long_friday">пятніца</string> + <string name="day_of_week_long_saturday">субота</string> + + <string name="day_of_week_medium_sunday">нд</string> + <string name="day_of_week_medium_monday">пн</string> + <string name="day_of_week_medium_tuesday">аў</string> + <string name="day_of_week_medium_wednesday">ср</string> + <string name="day_of_week_medium_thursday">чц</string> + <string name="day_of_week_medium_friday">пт</string> + <string name="day_of_week_medium_saturday">сб</string> + + <string name="day_of_week_short_sunday">нд</string> + <string name="day_of_week_short_monday">пн</string> + <string name="day_of_week_short_tuesday">аў</string> + <string name="day_of_week_short_wednesday">ср</string> + <string name="day_of_week_short_thursday">чц</string> + <string name="day_of_week_short_friday">пт</string> + <string name="day_of_week_short_saturday">сб</string> + + <string name="day_of_week_shortest_sunday">н</string> + <string name="day_of_week_shortest_monday">п</string> + <string name="day_of_week_shortest_tuesday">а</string> + <string name="day_of_week_shortest_wednesday">с</string> + <string name="day_of_week_shortest_thursday">ч</string> + <string name="day_of_week_shortest_friday">п</string> + <string name="day_of_week_shortest_saturday">с</string> + + <string name="am">да палудня</string> + <string name="pm">пасля палудня</string> + <string name="yesterday">учора</string> + <string name="today">сёння</string> + <string name="tomorrow">заўтра</string> + + <string name="hour_minute_24">%-k.%M</string> + <string name="hour_minute_ampm">%-l.%M %p</string> + <string name="hour_minute_cap_ampm">%-l.%M %p</string> + <string name="twelve_hour_time_format">h.mm a</string> + <string name="twenty_four_hour_time_format">H.mm</string> + <string name="numeric_date">%-e.%-m.%Y</string> + <string name="numeric_date_format">d.M.yyyy</string> + <string name="numeric_date_template">"%s.%s.%s"</string> + <string name="month_day_year">%-e %B %Y</string> + <string name="time_of_day">%H.%M.%S</string> + <string name="date_and_time">%H.%M.%S %-e.%-m.%Y</string> + <string name="date_time">%2$s %1$s</string> + <string name="time_date">%1$s %3$s</string> + <string name="abbrev_month_day_year">%-e.%-m.%Y</string> + <string name="month_day">%B %-e</string> + <string name="month">%-B</string> + <string name="month_year">%B %Y</string> + <string name="abbrev_month_day">%-e %b</string> + <string name="abbrev_month">%-b</string> + <string name="abbrev_month_year">%b %Y</string> + <string name="time1_time2">%1$s - %2$s</string> + <string name="date1_date2">%2$s - %5$s</string> + <string name="numeric_md1_md2">%3$s.%2$s - %8$s.%7$s</string> + <string name="numeric_wday1_md1_wday2_md2">%1$s, %3$s.%2$s - %6$s, %8$s.%7$s</string> + <string name="numeric_mdy1_mdy2">%3$s.%2$s.%4$s - %8$s.%7$s.%9$s</string> + <string name="numeric_wday1_mdy1_wday2_mdy2">%1$s, %3$s.%2$s.%4$s - %6$s, %8$s.%7$s.%9$s</string> + <string name="numeric_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %3$s/%2$s/%4$s - %10$s %6$s, %8$s/%7$s/%9$s</string> + <string name="numeric_md1_time1_md2_time2">%5$s %3$s.%2$s - %10$s %8$s.%7$s</string> + <string name="numeric_wday1_md1_time1_wday2_md2_time2">%5$s %1$s, %3$s %2$s - %10$s %6$s, %8$s %7$s</string> + <string name="numeric_mdy1_time1_mdy2_time2">%5$s %3$s.%2$s.%4$s - %10$s %8$s.%7$s.%9$s</string> + <string name="wday1_date1_time1_wday2_date2_time2">%3$s %1$s, %2$s - %6$s %4$s, %5$s</string> + <string name="wday1_date1_wday2_date2">%1$s, %2$s - %4$s, %5$s</string> + <string name="date1_time1_date2_time2">%3$s %2$s - %6$s %5$s</string> + <string name="time_wday_date">%1$s %2$s, %3$s</string> + <string name="wday_date">%2$s, %3$s</string> + <string name="time_wday">%1$s %2$s</string> + <string name="same_year_md1_md2">%2$s %3$s - %7$s %8$s</string> + <string name="same_year_wday1_md1_wday2_md2">%2$s %3$s, %1$s - %7$s %8$s, %6$s</string> + <string name="same_year_md1_time1_md2_time2">%5$s %2$s %3$s - %10$s %7$s %8$s</string> + <string name="same_month_md1_time1_md2_time2">%5$s %2$s %3$s - %10$s %7$s %8$s</string> + <string name="same_year_wday1_md1_time1_wday2_md2_time2">%5$s %2$s %3$s, %1$s - %10$s %7$s %8$s, %6$s</string> + <string name="same_month_wday1_md1_time1_wday2_md2_time2">%5$s %2$s %3$s, %1$s - %10$s %7$s %8$s, %6$s</string> + <string name="same_year_mdy1_time1_mdy2_time2">%5$s %3$s %2$s %4$s - %10$s %8$s %7$s %9$s</string> + <string name="same_month_mdy1_time1_mdy2_time2">%5$s %3$s %2$s %4$s - %10$s %8$s %7$s %9$s</string> + <string name="same_year_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %3$s %2$s %4$s - %10$s %6$s, %8$s %7$s %9$s</string> + <string name="same_month_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %3$s %2$s %4$s - %10$s %6$s, %8$s %7$s %9$s</string> + <string name="same_month_wday1_mdy1_wday2_mdy2">%1$s, %3$s %2$s %4$s - %6$s, %8$s %7$s %9$s</string> + <string name="same_month_md1_md2">%3$s-%8$s %2$s</string> + <string name="same_month_wday1_md1_wday2_md2">%2$s %3$s, %1$s - %7$s %8$s, %6$s</string> + <string name="same_year_mdy1_mdy2">%3$s %2$s - %8$s %7$s %9$s</string> + <string name="same_month_mdy1_mdy2">%3$s-%8$s %2$s %9$s</string> + <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %3$s %2$s - %6$s, %8$s %7$s %9$s</string> + <string name="short_format_month">%b</string> + <string name="full_wday_month_day_no_year">MMMM d, EEEE</string> + <string name="abbrev_wday_month_day_year">EEE, d MMM y</string> +</resources> diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml index 97996abad44c..8045b400ebd0 100644 --- a/core/res/res/values-be/strings.xml +++ b/core/res/res/values-be/strings.xml @@ -959,6 +959,9 @@ <item quantity="one" msgid="1634101450343277345">"Адкрытая сетка Wi-Fi даступная"</item> <item quantity="other" msgid="7915895323644292768">"Даступны адкрытыя сеткі Wi-Fi"</item> </plurals> + <string name="wifi_available_sign_in" msgid="9157196203958866662">"Уваход у сетку Wi-Fi"</string> + <!-- no translation found for wifi_available_sign_in_detailed (6797764740339907572) --> + <skip /> <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Немагчыма падключыцца да Wi-Fi"</string> <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" дрэннае падключэнне да Інтэрнэту."</string> <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string> @@ -1218,10 +1221,7 @@ <string name="share_action_provider_share_with" msgid="1791316789651185229">"Апублікаваць праз..."</string> <string name="status_bar_device_locked" msgid="3092703448690669768">"Прылада заблакаваная."</string> <string name="list_delimeter" msgid="3975117572185494152">", "</string> - <!-- no translation found for sending (8715108995741758718) --> - <skip /> - <!-- no translation found for launchBrowserDefault (2057951947297614725) --> - <skip /> - <!-- no translation found for SetupCallDefault (6870275517518479651) --> - <skip /> + <string name="sending" msgid="8715108995741758718">"Адпраўка..."</string> + <string name="launchBrowserDefault" msgid="2057951947297614725">"Запусцiць браўзер?"</string> + <string name="SetupCallDefault" msgid="6870275517518479651">"Адказаць?"</string> </resources> diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml index 66b5cae6145d..0a0748f19c5e 100644 --- a/core/res/res/values-bg/strings.xml +++ b/core/res/res/values-bg/strings.xml @@ -959,6 +959,9 @@ <item quantity="one" msgid="1634101450343277345">"Има достъпна отворена Wi-Fi мрежа"</item> <item quantity="other" msgid="7915895323644292768">"Има достъпни отворени Wi-Fi мрежи"</item> </plurals> + <string name="wifi_available_sign_in" msgid="9157196203958866662">"Влизане в Wi-Fi мрежа"</string> + <!-- no translation found for wifi_available_sign_in_detailed (6797764740339907572) --> + <skip /> <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Не можа да се свърже с Wi-Fi"</string> <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" има лоша връзка с интернет."</string> <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string> @@ -1218,10 +1221,7 @@ <string name="share_action_provider_share_with" msgid="1791316789651185229">"Споделяне със..."</string> <string name="status_bar_device_locked" msgid="3092703448690669768">"Устройството е заключено."</string> <string name="list_delimeter" msgid="3975117572185494152">", "</string> - <!-- no translation found for sending (8715108995741758718) --> - <skip /> - <!-- no translation found for launchBrowserDefault (2057951947297614725) --> - <skip /> - <!-- no translation found for SetupCallDefault (6870275517518479651) --> - <skip /> + <string name="sending" msgid="8715108995741758718">"Изпраща се..."</string> + <string name="launchBrowserDefault" msgid="2057951947297614725">"Да се стартира ли браузърът?"</string> + <string name="SetupCallDefault" msgid="6870275517518479651">"Да се приеме ли обаждането?"</string> </resources> diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml index 09ee9cfa2973..8563e1d3dfa3 100644 --- a/core/res/res/values-ca/strings.xml +++ b/core/res/res/values-ca/strings.xml @@ -959,6 +959,9 @@ <item quantity="one" msgid="1634101450343277345">"Xarxa Wi-fi oberta disponible"</item> <item quantity="other" msgid="7915895323644292768">"Xarxes Wi-fi obertes disponibles"</item> </plurals> + <string name="wifi_available_sign_in" msgid="9157196203958866662">"Inicia la sessió a la xarxa Wi-Fi"</string> + <!-- no translation found for wifi_available_sign_in_detailed (6797764740339907572) --> + <skip /> <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"No s\'ha pogut connectar a la Wi-Fi"</string> <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" té una mala connexió a Internet."</string> <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string> diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml index 74ee1561ede6..b45c6d6400bc 100644 --- a/core/res/res/values-cs/strings.xml +++ b/core/res/res/values-cs/strings.xml @@ -959,6 +959,9 @@ <item quantity="one" msgid="1634101450343277345">"K dispozici je veřejná síť WiFi"</item> <item quantity="other" msgid="7915895323644292768">"Jsou k dispozici veřejné sítě WiFi"</item> </plurals> + <string name="wifi_available_sign_in" msgid="9157196203958866662">"Přihlásit se k síti Wi-Fi"</string> + <!-- no translation found for wifi_available_sign_in_detailed (6797764740339907572) --> + <skip /> <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Připojení k síti Wi-Fi se nezdařilo"</string> <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" má pomalé připojení k internetu."</string> <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Přímé připojení sítě Wi-Fi"</string> @@ -1218,10 +1221,7 @@ <string name="share_action_provider_share_with" msgid="1791316789651185229">"Sdílet s..."</string> <string name="status_bar_device_locked" msgid="3092703448690669768">"Zařízení je uzamčeno."</string> <string name="list_delimeter" msgid="3975117572185494152">", "</string> - <!-- no translation found for sending (8715108995741758718) --> - <skip /> - <!-- no translation found for launchBrowserDefault (2057951947297614725) --> - <skip /> - <!-- no translation found for SetupCallDefault (6870275517518479651) --> - <skip /> + <string name="sending" msgid="8715108995741758718">"Odesílání..."</string> + <string name="launchBrowserDefault" msgid="2057951947297614725">"Spustit prohlížeč?"</string> + <string name="SetupCallDefault" msgid="6870275517518479651">"Přijmout hovor?"</string> </resources> diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml index 465ec4eaf9bf..5e40ea02d4c5 100644 --- a/core/res/res/values-da/strings.xml +++ b/core/res/res/values-da/strings.xml @@ -959,6 +959,9 @@ <item quantity="one" msgid="1634101450343277345">"Åbent Wi-Fi-netværk tilgængeligt"</item> <item quantity="other" msgid="7915895323644292768">"Der er åbne Wi-Fi-netværk tilgængelige"</item> </plurals> + <string name="wifi_available_sign_in" msgid="9157196203958866662">"Log ind på Wi-Fi-netværk"</string> + <!-- no translation found for wifi_available_sign_in_detailed (6797764740339907572) --> + <skip /> <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Kunne ikke oprette forbindelse til Wi-Fi"</string> <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" har en dårlig internetforbindelse."</string> <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string> @@ -1218,10 +1221,7 @@ <string name="share_action_provider_share_with" msgid="1791316789651185229">"Del med:"</string> <string name="status_bar_device_locked" msgid="3092703448690669768">"Enhed låst."</string> <string name="list_delimeter" msgid="3975117572185494152">", "</string> - <!-- no translation found for sending (8715108995741758718) --> - <skip /> - <!-- no translation found for launchBrowserDefault (2057951947297614725) --> - <skip /> - <!-- no translation found for SetupCallDefault (6870275517518479651) --> - <skip /> + <string name="sending" msgid="8715108995741758718">"Sender..."</string> + <string name="launchBrowserDefault" msgid="2057951947297614725">"Vil du starte browseren?"</string> + <string name="SetupCallDefault" msgid="6870275517518479651">"Vil du besvare opkaldet?"</string> </resources> diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml index f77187c469d1..98e3e80d1bb6 100644 --- a/core/res/res/values-de/strings.xml +++ b/core/res/res/values-de/strings.xml @@ -160,14 +160,14 @@ <string name="permgroupdesc_costMoney" msgid="8193824940620517189">"Ermöglicht Anwendungen die Ausführung eventuell kostenpflichtiger Aktionen"</string> <string name="permgrouplab_messages" msgid="7521249148445456662">"Ihre Nachrichten"</string> <string name="permgroupdesc_messages" msgid="7045736972019211994">"Lesen und schreiben Sie Ihre SMS, E-Mails und anderen Nachrichten."</string> - <string name="permgrouplab_personalInfo" msgid="3519163141070533474">"Meine persönlichen Informationen"</string> + <string name="permgrouplab_personalInfo" msgid="3519163141070533474">"Ihre persönlichen Informationen"</string> <string name="permgroupdesc_personalInfo" product="tablet" msgid="6975389054186265786">"Direkter Zugriff auf die Kontakte und den Kalender Ihres Tablets"</string> <string name="permgroupdesc_personalInfo" product="default" msgid="5488050357388806068">"Direkter Zugriff auf die Kontakte und den Kalender Ihres Telefons"</string> <string name="permgrouplab_location" msgid="635149742436692049">"Ihren Standort"</string> <string name="permgroupdesc_location" msgid="2430258821648348660">"Ihren physischen Standort überwachen"</string> - <string name="permgrouplab_network" msgid="5808983377727109831">"Netzwerkkommunikation"</string> + <string name="permgrouplab_network" msgid="5808983377727109831">"Netzkommunikation"</string> <string name="permgroupdesc_network" msgid="5035763698958415998">"Ermöglicht Anwendungen den Zugriff auf verschiedene Netzwerkfunktionen"</string> - <string name="permgrouplab_accounts" msgid="3359646291125325519">"Meine Konten"</string> + <string name="permgrouplab_accounts" msgid="3359646291125325519">"Ihre Konten"</string> <string name="permgroupdesc_accounts" msgid="4948732641827091312">"Zugriff auf verfügbare Konten"</string> <string name="permgrouplab_hardwareControls" msgid="7998214968791599326">"Hardware-Steuerelemente"</string> <string name="permgroupdesc_hardwareControls" msgid="4357057861225462702">"Direkter Zugriff auf Hardware über Headset"</string> @@ -209,7 +209,7 @@ <string name="permlab_getTasks" msgid="5005277531132573353">"laufende Apps abrufen"</string> <string name="permdesc_getTasks" msgid="7048711358713443341">"Ermöglicht der App, Informationen zu aktuellen und kürzlich ausführten Aufgaben abzurufen. Schädliche Anwendungen können so eventuell geheime Informationen zu anderen Anwendungen entdecken."</string> <string name="permlab_reorderTasks" msgid="5669588525059921549">"Laufende Apps neu ordnen"</string> - <string name="permdesc_reorderTasks" msgid="126252774270522835">"Ermöglicht einer App, Aufgaben in den Vorder- und Hintergrund zu verschieben. Schädliche Anwendungen können so ohne Ihr Zutun eine Anzeige im Vordergrund erzwingen."</string> + <string name="permdesc_reorderTasks" msgid="126252774270522835">"Ermöglicht einer App, Aufgaben in den Vorder- und Hintergrund zu verschieben. Schädliche Apps können so ohne Ihr Zutun eine Anzeige im Vordergrund erzwingen."</string> <string name="permlab_removeTasks" msgid="4802740047161700683">"Aktive Apps beenden"</string> <string name="permdesc_removeTasks" msgid="2000332928514575461">"Ermöglicht einer App das Entfernen von Aufgaben und Beenden der entsprechenden Apps. Schädliche Apps können das Verhalten anderer Apps stören."</string> <string name="permlab_setDebugApp" msgid="4339730312925176742">"Fehlerbeseitigung für App aktivieren"</string> @@ -223,7 +223,7 @@ <string name="permlab_forceStopPackages" msgid="1447830113260156236">"Beenden anderer Anwendungen erzwingen"</string> <string name="permdesc_forceStopPackages" msgid="7263036616161367402">"Ermöglicht einer App, das Beenden anderer Anwendungen zu erzwingen"</string> <string name="permlab_forceBack" msgid="1804196839880393631">"Schließen der App erzwingen"</string> - <string name="permdesc_forceBack" msgid="6534109744159919013">"Ermöglicht einer App, alle Aktivitäten, die im Vordergrund ablaufen, zu beenden und in den Hintergrund zu schieben. Sollte nicht für normale Anwendungen benötigt werden."</string> + <string name="permdesc_forceBack" msgid="6534109744159919013">"Ermöglicht einer App, alle Aktivitäten, die im Vordergrund ablaufen, zu beenden und in den Hintergrund zu schieben. Sollte nicht für normale Apps benötigt werden."</string> <string name="permlab_dump" msgid="1681799862438954752">"Systeminternen Status abrufen"</string> <string name="permdesc_dump" msgid="2198776174276275220">"Ermöglicht einer App, den internen Status des Systems abzurufen. Schädliche Apps rufen hierbei möglicherweise eine Vielzahl an privaten und geschützten Daten ab, die Sie in der Regel nicht benötigen würden."</string> <string name="permlab_retrieve_window_content" msgid="8022588608994589938">"Bildschirminhalt abrufen"</string> @@ -298,7 +298,7 @@ <string name="permdesc_clearAppCache" product="default" msgid="7740465694193671402">"Ermöglicht einer App, Telefonspeicher durch das Löschen von Dateien im Cache-Verzeichnis der Anwendung freizugeben. Der Zugriff beschränkt sich in der Regel auf Systemprozesse."</string> <string name="permlab_movePackage" msgid="728454979946503926">"Anwendungsressourcen verschieben"</string> <string name="permdesc_movePackage" msgid="6323049291923925277">"Ermöglicht einer App, Anwendungsressourcen von internen auf externe Medien zu verschieben und umgekehrt"</string> - <string name="permlab_readLogs" msgid="6615778543198967614">"Lesen vertraulicher Protokolldaten"</string> + <string name="permlab_readLogs" msgid="6615778543198967614">"Vertrauliche Protokolldaten lesen"</string> <string name="permdesc_readLogs" product="tablet" msgid="4077356893924755294">"Ermöglicht einer App, die verschiedenen Protokolldateien des Systems zu lesen. So können allgemeine Informationen zu den auf Ihrem Tablet durchgeführten Aktionen eingesehen werden. Diese können persönliche oder geheime Daten enthalten."</string> <string name="permdesc_readLogs" product="default" msgid="8896449437464867766">"Ermöglicht einer App, die verschiedenen Protokolldateien des Systems zu lesen. So können allgemeine Informationen zu den auf Ihrem Telefon durchgeführten Aktionen eingesehen werden. Diese können persönliche oder geheime Daten enthalten."</string> <string name="permlab_anyCodecForPlayback" msgid="715805555823881818">"Für Wiedergabe beliebigen Mediendecodierer verwenden"</string> @@ -409,9 +409,9 @@ <string name="permlab_bindGadget" msgid="776905339015863471">"Widgets auswählen"</string> <string name="permdesc_bindGadget" msgid="2098697834497452046">"Ermöglicht der App, dem System zu melden, welche Widgets von welcher Anwendung verwendet werden können. Mit dieser Berechtigung können Anwendungen anderen Anwendungen Zugriff auf persönliche Daten gewähren. Nicht für normale Apps vorgesehen."</string> <string name="permlab_modifyPhoneState" msgid="8423923777659292228">"Telefonstatus ändern"</string> - <string name="permdesc_modifyPhoneState" msgid="3302284561346956587">"Ermöglicht einer App, die Telefonfunktionen des Gerätes zu steuern. Eine Anwendung mit dieser Berechtigung kann unter anderem das Netzwerk wechseln oder die Mobilfunkverbindung des Telefons ein- und ausschalten, ohne Sie darüber zu informieren."</string> + <string name="permdesc_modifyPhoneState" msgid="3302284561346956587">"Ermöglicht einer App, die Telefonfunktionen des Geräts zu steuern. Eine Anwendung mit dieser Berechtigung kann unter anderem das Netzwerk wechseln oder die Mobilfunkverbindung des Telefons ein- und ausschalten, ohne Sie darüber zu informieren."</string> <string name="permlab_readPhoneState" msgid="2326172951448691631">"Telefonstatus lesen und identifizieren"</string> - <string name="permdesc_readPhoneState" msgid="188877305147626781">"Ermöglicht der App, auf die Telefonfunktionen des Gerätes zuzugreifen. Eine Anwendung mit dieser Berechtigung kann unter anderem bestimmen, welche Telefonnummer dieses Telefon verwendet, ob ein Anruf aktiv ist oder mit welcher Nummer der Anrufer verbunden ist."</string> + <string name="permdesc_readPhoneState" msgid="188877305147626781">"Ermöglicht der App, auf die Telefonfunktionen des Geräts zuzugreifen. Eine App mit dieser Berechtigung kann unter anderem bestimmen, welche Telefonnummer dieses Telefon verwendet, ob ein Anruf aktiv ist oder mit welcher Nummer der Anrufer verbunden ist."</string> <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"Standby-Modus des Tablets deaktivieren"</string> <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"Standby-Modus deaktivieren"</string> <string name="permdesc_wakeLock" product="tablet" msgid="4032181488045338551">"Ermöglicht einer App, den Standby-Modus des Tablets zu deaktivieren."</string> @@ -444,7 +444,7 @@ <string name="permdesc_authenticateAccounts" msgid="4006839406474208874">"Ermöglicht einer App, die Kontoauthentifizierungsfunktionen des Konto-Managers zu verwenden, einschließlich die Funktionen zum Erstellen von Konten und zum Abrufen und Einstellen der entsprechenden Passwörter"</string> <string name="permlab_manageAccounts" msgid="4440380488312204365">"Kontoliste verwalten"</string> <string name="permdesc_manageAccounts" msgid="8804114016661104517">"Ermöglicht einer App, Konten hinzuzufügen und zu entfernen oder deren Passwörter zu löschen"</string> - <string name="permlab_useCredentials" msgid="6401886092818819856">"Authentifizierungsinformationen eines Kontos verwenden"</string> + <string name="permlab_useCredentials" msgid="6401886092818819856">"Informationen zur Authentifizierung eines Kontos verwenden"</string> <string name="permdesc_useCredentials" msgid="7416570544619546974">"Ermöglicht einer App, Authentifizierungs-Token anzufordern"</string> <string name="permlab_accessNetworkState" msgid="6865575199464405769">"Netzwerkstatus anzeigen"</string> <string name="permdesc_accessNetworkState" msgid="558721128707712766">"Ermöglicht einer App, den Status aller Netzwerke anzuzeigen"</string> @@ -905,9 +905,9 @@ <string name="aerr_process" msgid="4507058997035697579">"Leider wurde der Prozess <xliff:g id="PROCESS">%1$s</xliff:g> beendet."</string> <string name="anr_title" msgid="4351948481459135709"></string> <string name="anr_activity_application" msgid="8339738283149696827">"<xliff:g id="APPLICATION">%2$s</xliff:g> reagiert nicht."\n\n"Möchten Sie sie schließen?"</string> - <string name="anr_activity_process" msgid="7018289416670457797">"Aktivität <xliff:g id="ACTIVITY">%1$s</xliff:g> reagiert nicht."\n\n"Möchten Sie sie beenden?"</string> + <string name="anr_activity_process" msgid="7018289416670457797">"Aktivität \"<xliff:g id="ACTIVITY">%1$s</xliff:g>\" reagiert nicht."\n\n"Möchten Sie sie beenden?"</string> <string name="anr_application_process" msgid="7208175830253210526">"<xliff:g id="APPLICATION">%1$s</xliff:g> reagiert nicht. Möchten Sie sie schließen?"</string> - <string name="anr_process" msgid="306819947562555821">"Prozess <xliff:g id="PROCESS">%1$s</xliff:g> reagiert nicht."\n\n"Möchten Sie ihn beenden?"</string> + <string name="anr_process" msgid="306819947562555821">"Prozess \"<xliff:g id="PROCESS">%1$s</xliff:g>\" reagiert nicht."\n\n"Möchten Sie ihn beenden?"</string> <string name="force_close" msgid="8346072094521265605">"OK"</string> <string name="report" msgid="4060218260984795706">"Bericht"</string> <string name="wait" msgid="7147118217226317732">"Warten"</string> @@ -959,6 +959,9 @@ <item quantity="one" msgid="1634101450343277345">"Verfügbares WLAN-Netzwerk öffnen"</item> <item quantity="other" msgid="7915895323644292768">"Verfügbare WLAN-Netzwerke öffnen"</item> </plurals> + <string name="wifi_available_sign_in" msgid="9157196203958866662">"In WLAN-Netzwerk anmelden"</string> + <!-- no translation found for wifi_available_sign_in_detailed (6797764740339907572) --> + <skip /> <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Es konnte keine WLAN-Verbindung hergestellt werden."</string> <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" hat eine schlechte Internetverbindung."</string> <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string> @@ -1096,7 +1099,7 @@ <string name="throttled_notification_title" msgid="6269541897729781332">"Mobildatenlimit überschritten"</string> <string name="throttled_notification_message" msgid="4712369856601275146">"Durch Berühren weitere Informationen zur Mobildatennutzung aufrufen"</string> <string name="no_matches" msgid="8129421908915840737">"Keine Treffer"</string> - <string name="find_on_page" msgid="1946799233822820384">"Auf Seite suchen"</string> + <string name="find_on_page" msgid="1946799233822820384">"Suchen"</string> <plurals name="matches_found"> <item quantity="one" msgid="8167147081136579439">"1 Treffer"</item> <item quantity="other" msgid="4641872797067609177">"<xliff:g id="INDEX">%d</xliff:g> von <xliff:g id="TOTAL">%d</xliff:g>"</item> @@ -1218,10 +1221,7 @@ <string name="share_action_provider_share_with" msgid="1791316789651185229">"Teilen mit..."</string> <string name="status_bar_device_locked" msgid="3092703448690669768">"Gerät gesperrt"</string> <string name="list_delimeter" msgid="3975117572185494152">", "</string> - <!-- no translation found for sending (8715108995741758718) --> - <skip /> - <!-- no translation found for launchBrowserDefault (2057951947297614725) --> - <skip /> - <!-- no translation found for SetupCallDefault (6870275517518479651) --> - <skip /> + <string name="sending" msgid="8715108995741758718">"Wird gesendet..."</string> + <string name="launchBrowserDefault" msgid="2057951947297614725">"Browser starten?"</string> + <string name="SetupCallDefault" msgid="6870275517518479651">"Anruf annehmen?"</string> </resources> diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml index 54980a5550ae..f5704a95590e 100644 --- a/core/res/res/values-el/strings.xml +++ b/core/res/res/values-el/strings.xml @@ -959,6 +959,9 @@ <item quantity="one" msgid="1634101450343277345">"Υπάρχει διαθέσιμο ανοικτό δίκτυο Wi-Fi"</item> <item quantity="other" msgid="7915895323644292768">"Υπάρχουν διαθέσιμα ανοικτά δίκτυα Wi-Fi"</item> </plurals> + <string name="wifi_available_sign_in" msgid="9157196203958866662">"Συνδεθείτε στο δίκτυο Wi-Fi"</string> + <!-- no translation found for wifi_available_sign_in_detailed (6797764740339907572) --> + <skip /> <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Δεν είναι δυνατή η σύνδεση στο Wi-Fi"</string> <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" έχει κακή σύνδεση Διαδικτύου."</string> <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string> @@ -1218,10 +1221,7 @@ <string name="share_action_provider_share_with" msgid="1791316789651185229">"Κοινή χρήση με..."</string> <string name="status_bar_device_locked" msgid="3092703448690669768">"Η συσκευή κλειδώθηκε."</string> <string name="list_delimeter" msgid="3975117572185494152">", "</string> - <!-- no translation found for sending (8715108995741758718) --> - <skip /> - <!-- no translation found for launchBrowserDefault (2057951947297614725) --> - <skip /> - <!-- no translation found for SetupCallDefault (6870275517518479651) --> - <skip /> + <string name="sending" msgid="8715108995741758718">"Αποστολή..."</string> + <string name="launchBrowserDefault" msgid="2057951947297614725">"Εκκίνηση προγράμματος περιήγησης;"</string> + <string name="SetupCallDefault" msgid="6870275517518479651">"Αποδοχή κλήσης;"</string> </resources> diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml index 7981b523074c..86f81bbb6e68 100644 --- a/core/res/res/values-en-rGB/strings.xml +++ b/core/res/res/values-en-rGB/strings.xml @@ -40,7 +40,7 @@ <string name="serviceEnabledFor" msgid="6856228140453471041">"Service was enabled for:"</string> <string name="serviceDisabled" msgid="1937553226592516411">"Service has been disabled."</string> <string name="serviceRegistered" msgid="6275019082598102493">"Registration was successful."</string> - <string name="serviceErased" msgid="1288584695297200972">"Erasure was successful."</string> + <string name="serviceErased" msgid="1288584695297200972">"Erase successful."</string> <string name="passwordIncorrect" msgid="7612208839450128715">"Incorrect password."</string> <string name="mmiComplete" msgid="8232527495411698359">"MMI complete."</string> <string name="badPin" msgid="5085454289896032547">"The old PIN that you typed is not correct."</string> @@ -150,9 +150,9 @@ <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Silent mode"</string> <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Sound is OFF"</string> <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"Sound is ON"</string> - <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Airplane mode"</string> - <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Airplane mode is ON"</string> - <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Airplane mode is OFF"</string> + <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Aeroplane mode"</string> + <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Aeroplane mode is ON"</string> + <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Aeroplane mode is OFF"</string> <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string> <string name="safeMode" msgid="2788228061547930246">"Safe mode"</string> <string name="android_system_label" msgid="6577375335728551336">"Android System"</string> @@ -959,6 +959,9 @@ <item quantity="one" msgid="1634101450343277345">"Open available Wi-Fi network"</item> <item quantity="other" msgid="7915895323644292768">"Open Wi-Fi networks available"</item> </plurals> + <string name="wifi_available_sign_in" msgid="9157196203958866662">"Sign in to a Wi-Fi network"</string> + <!-- no translation found for wifi_available_sign_in_detailed (6797764740339907572) --> + <skip /> <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Couldn\'t connect to Wi-Fi"</string> <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" has a poor Internet connection."</string> <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string> diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml index ba79143775d8..6d4067c794ce 100644 --- a/core/res/res/values-es-rUS/strings.xml +++ b/core/res/res/values-es-rUS/strings.xml @@ -959,6 +959,9 @@ <item quantity="one" msgid="1634101450343277345">"Abrir red disponible de Wi-Fi"</item> <item quantity="other" msgid="7915895323644292768">"Abrir redes disponibles de Wi-Fi"</item> </plurals> + <string name="wifi_available_sign_in" msgid="9157196203958866662">"Accede a una red Wi-Fi."</string> + <!-- no translation found for wifi_available_sign_in_detailed (6797764740339907572) --> + <skip /> <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"No se pudo conectar a la red Wi-Fi."</string> <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" tiene una mala conexión a Internet."</string> <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string> @@ -1218,10 +1221,7 @@ <string name="share_action_provider_share_with" msgid="1791316789651185229">"Compartir con..."</string> <string name="status_bar_device_locked" msgid="3092703448690669768">"Dispositivo bloqueado"</string> <string name="list_delimeter" msgid="3975117572185494152">", "</string> - <!-- no translation found for sending (8715108995741758718) --> - <skip /> - <!-- no translation found for launchBrowserDefault (2057951947297614725) --> - <skip /> - <!-- no translation found for SetupCallDefault (6870275517518479651) --> - <skip /> + <string name="sending" msgid="8715108995741758718">"Envío en curso..."</string> + <string name="launchBrowserDefault" msgid="2057951947297614725">"¿Deseas iniciar el navegador?"</string> + <string name="SetupCallDefault" msgid="6870275517518479651">"¿Deseas aceptar la llamada?"</string> </resources> diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml index a7aeb01c1185..bfd64a270917 100644 --- a/core/res/res/values-es/strings.xml +++ b/core/res/res/values-es/strings.xml @@ -793,7 +793,7 @@ <string name="last_month" msgid="3959346739979055432">"El mes pasado"</string> <string name="older" msgid="5211975022815554840">"Anterior"</string> <plurals name="num_days_ago"> - <item quantity="one" msgid="861358534398115820">"ayer"</item> + <item quantity="one" msgid="861358534398115820">"Ayer"</item> <item quantity="other" msgid="2479586466153314633">"Hace <xliff:g id="COUNT">%d</xliff:g> días"</item> </plurals> <plurals name="in_num_seconds"> @@ -825,7 +825,7 @@ <item quantity="other" msgid="6889970745748538901">"hace <xliff:g id="COUNT">%d</xliff:g> horas"</item> </plurals> <plurals name="abbrev_num_days_ago"> - <item quantity="one" msgid="8463161711492680309">"ayer"</item> + <item quantity="one" msgid="8463161711492680309">"Ayer"</item> <item quantity="other" msgid="3453342639616481191">"hace <xliff:g id="COUNT">%d</xliff:g> días"</item> </plurals> <plurals name="abbrev_in_num_seconds"> @@ -919,10 +919,10 @@ <string name="screen_compat_mode_hint" msgid="2953716574198046484">"Vuelve a habilitar esta opción en Ajustes > Aplicaciones > Administrar aplicaciones."</string> <string name="smv_application" msgid="295583804361236288">"La aplicación <xliff:g id="APPLICATION">%1$s</xliff:g> (proceso <xliff:g id="PROCESS">%2$s</xliff:g>) ha infringido su política StrictMode autoaplicable."</string> <string name="smv_process" msgid="5120397012047462446">"El proceso <xliff:g id="PROCESS">%1$s</xliff:g> ha infringido su política StrictMode autoaplicable."</string> - <string name="android_upgrading_title" msgid="378740715658358071">"Actualizando Android..."</string> - <string name="android_upgrading_apk" msgid="274409861603566003">"Optimizando aplicación <xliff:g id="NUMBER_0">%1$d</xliff:g> de <xliff:g id="NUMBER_1">%2$d</xliff:g>"</string> + <string name="android_upgrading_title" msgid="378740715658358071">"Actualizando Android"</string> + <string name="android_upgrading_apk" msgid="274409861603566003">"Optimizando aplicación <xliff:g id="NUMBER_0">%1$d</xliff:g> de <xliff:g id="NUMBER_1">%2$d</xliff:g>..."</string> <string name="android_upgrading_starting_apps" msgid="7959542881906488763">"Iniciando aplicaciones"</string> - <string name="android_upgrading_complete" msgid="1405954754112999229">"Finalizando arranque"</string> + <string name="android_upgrading_complete" msgid="1405954754112999229">"Finalizando inicio..."</string> <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> en ejecución"</string> <string name="heavy_weight_notification_detail" msgid="2423977499339403402">"Seleccionar para cambiar a la aplicación"</string> <string name="heavy_weight_switcher_title" msgid="1135403633766694316">"¿Cambiar de aplicación?"</string> @@ -959,6 +959,9 @@ <item quantity="one" msgid="1634101450343277345">"Red Wi-Fi abierta disponible"</item> <item quantity="other" msgid="7915895323644292768">"Redes Wi-Fi abiertas disponibles"</item> </plurals> + <string name="wifi_available_sign_in" msgid="9157196203958866662">"Iniciar sesión en red Wi-Fi"</string> + <!-- no translation found for wifi_available_sign_in_detailed (6797764740339907572) --> + <skip /> <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"No se ha podido establecer conexión con la red Wi-Fi."</string> <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" tiene una mala conexión a Internet."</string> <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string> @@ -1218,10 +1221,7 @@ <string name="share_action_provider_share_with" msgid="1791316789651185229">"Compartir con..."</string> <string name="status_bar_device_locked" msgid="3092703448690669768">"Dispositivo bloqueado"</string> <string name="list_delimeter" msgid="3975117572185494152">", "</string> - <!-- no translation found for sending (8715108995741758718) --> - <skip /> - <!-- no translation found for launchBrowserDefault (2057951947297614725) --> - <skip /> - <!-- no translation found for SetupCallDefault (6870275517518479651) --> - <skip /> + <string name="sending" msgid="8715108995741758718">"Enviando..."</string> + <string name="launchBrowserDefault" msgid="2057951947297614725">"¿Iniciar el navegador?"</string> + <string name="SetupCallDefault" msgid="6870275517518479651">"¿Aceptar la llamada?"</string> </resources> diff --git a/core/res/res/values-et/donottranslate-cldr.xml b/core/res/res/values-et/donottranslate-cldr.xml new file mode 100644 index 000000000000..d50d0415d8e5 --- /dev/null +++ b/core/res/res/values-et/donottranslate-cldr.xml @@ -0,0 +1,149 @@ +<?xml version="1.0" encoding="UTF-8"?> +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="month_long_standalone_january">jaanuar</string> + <string name="month_long_standalone_february">veebruar</string> + <string name="month_long_standalone_march">märts</string> + <string name="month_long_standalone_april">aprill</string> + <string name="month_long_standalone_may">mai</string> + <string name="month_long_standalone_june">juuni</string> + <string name="month_long_standalone_july">juuli</string> + <string name="month_long_standalone_august">august</string> + <string name="month_long_standalone_september">september</string> + <string name="month_long_standalone_october">oktoober</string> + <string name="month_long_standalone_november">november</string> + <string name="month_long_standalone_december">detsember</string> + + <string name="month_long_january">jaanuar</string> + <string name="month_long_february">veebruar</string> + <string name="month_long_march">märts</string> + <string name="month_long_april">aprill</string> + <string name="month_long_may">mai</string> + <string name="month_long_june">juuni</string> + <string name="month_long_july">juuli</string> + <string name="month_long_august">august</string> + <string name="month_long_september">september</string> + <string name="month_long_october">oktoober</string> + <string name="month_long_november">november</string> + <string name="month_long_december">detsember</string> + + <string name="month_medium_january">jaan</string> + <string name="month_medium_february">veebr</string> + <string name="month_medium_march">märts</string> + <string name="month_medium_april">apr</string> + <string name="month_medium_may">mai</string> + <string name="month_medium_june">juuni</string> + <string name="month_medium_july">juuli</string> + <string name="month_medium_august">aug</string> + <string name="month_medium_september">sept</string> + <string name="month_medium_october">okt</string> + <string name="month_medium_november">nov</string> + <string name="month_medium_december">dets</string> + + <string name="month_shortest_january">1</string> + <string name="month_shortest_february">2</string> + <string name="month_shortest_march">3</string> + <string name="month_shortest_april">4</string> + <string name="month_shortest_may">5</string> + <string name="month_shortest_june">6</string> + <string name="month_shortest_july">7</string> + <string name="month_shortest_august">8</string> + <string name="month_shortest_september">9</string> + <string name="month_shortest_october">10</string> + <string name="month_shortest_november">11</string> + <string name="month_shortest_december">12</string> + + <string name="day_of_week_long_sunday">pühapäev</string> + <string name="day_of_week_long_monday">esmaspäev</string> + <string name="day_of_week_long_tuesday">teisipäev</string> + <string name="day_of_week_long_wednesday">kolmapäev</string> + <string name="day_of_week_long_thursday">neljapäev</string> + <string name="day_of_week_long_friday">reede</string> + <string name="day_of_week_long_saturday">laupäev</string> + + <string name="day_of_week_medium_sunday">P</string> + <string name="day_of_week_medium_monday">E</string> + <string name="day_of_week_medium_tuesday">T</string> + <string name="day_of_week_medium_wednesday">K</string> + <string name="day_of_week_medium_thursday">N</string> + <string name="day_of_week_medium_friday">R</string> + <string name="day_of_week_medium_saturday">L</string> + + <string name="day_of_week_short_sunday">P</string> + <string name="day_of_week_short_monday">E</string> + <string name="day_of_week_short_tuesday">T</string> + <string name="day_of_week_short_wednesday">K</string> + <string name="day_of_week_short_thursday">N</string> + <string name="day_of_week_short_friday">R</string> + <string name="day_of_week_short_saturday">L</string> + + <string name="day_of_week_shortest_sunday">1</string> + <string name="day_of_week_shortest_monday">2</string> + <string name="day_of_week_shortest_tuesday">3</string> + <string name="day_of_week_shortest_wednesday">4</string> + <string name="day_of_week_shortest_thursday">5</string> + <string name="day_of_week_shortest_friday">6</string> + <string name="day_of_week_shortest_saturday">7</string> + + <string name="am">AM</string> + <string name="pm">PM</string> + <string name="yesterday">Yesterday</string> + <string name="today">Today</string> + <string name="tomorrow">Tomorrow</string> + + <string name="hour_minute_24">%-k:%M</string> + <string name="hour_minute_ampm">%-l:%M %p</string> + <string name="hour_minute_cap_ampm">%-l:%M %^p</string> + <string name="twelve_hour_time_format">h:mm a</string> + <string name="twenty_four_hour_time_format">H:mm</string> + <string name="numeric_date">%d.%m.%Y</string> + <string name="numeric_date_format">dd.MM.yyyy</string> + <string name="numeric_date_template">"%s.%s.%s"</string> + <string name="month_day_year">%-e %B %Y</string> + <string name="time_of_day">%-k:%M:%S</string> + <string name="date_and_time">%-k:%M:%S %d.%m.%Y</string> + <string name="date_time">%2$s %1$s</string> + <string name="time_date">%1$s %3$s</string> + <string name="abbrev_month_day_year">%d.%m.%Y</string> + <string name="month_day">%-e %B</string> + <string name="month">%-B</string> + <string name="month_year">%B %Y</string> + <string name="abbrev_month_day">%-e %b</string> + <string name="abbrev_month">%b</string> + <string name="abbrev_month_year">%b %Y</string> + <string name="time1_time2">%1$s - %2$s</string> + <string name="date1_date2">%2$s - %5$s</string> + <string name="numeric_md1_md2">%3$s.%2$s - %8$s.%7$s</string> + <string name="numeric_wday1_md1_wday2_md2">%1$s, %3$s.%2$s - %6$s, %8$s.%7$s</string> + <string name="numeric_mdy1_mdy2">%3$s.%2$s.%4$s - %8$s.%7$s.%9$s</string> + <string name="numeric_wday1_mdy1_wday2_mdy2">%1$s, %3$s.%2$s.%4$s - %6$s, %8$s.%7$s.%9$s</string> + <string name="numeric_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %3$s.%2$s.%4$s - %10$s %6$s, %8$s.%7$s.%9$s</string> + <string name="numeric_md1_time1_md2_time2">%5$s %3$s.%2$s - %10$s %8$s.%7$s</string> + <string name="numeric_wday1_md1_time1_wday2_md2_time2">%5$s %1$s, %3$s.%2$s - %10$s %6$s, %8$s.%7$s</string> + <string name="numeric_mdy1_time1_mdy2_time2">%5$s %3$s.%2$s.%4$s - %10$s %8$s.%7$s.%9$s</string> + <string name="wday1_date1_time1_wday2_date2_time2">%3$s %1$s, %2$s - %6$s %4$s, %5$s</string> + <string name="wday1_date1_wday2_date2">%1$s, %2$s - %4$s, %5$s</string> + <string name="date1_time1_date2_time2">%3$s %2$s - %6$s %5$s</string> + <string name="time_wday_date">%1$s %2$s, %3$s</string> + <string name="wday_date">%2$s, %3$s</string> + <string name="time_wday">%1$s %2$s</string> + <string name="same_year_md1_md2">%3$s %2$s - %8$s %7$s</string> + <string name="same_year_wday1_md1_wday2_md2">%1$s %2$s %3$s - %6$s %7$s %8$s</string> + <string name="same_year_md1_time1_md2_time2">%5$s %3$s %2$s - %10$s %8$s %7$s</string> + <string name="same_month_md1_time1_md2_time2">%5$s %3$s %2$s - %10$s %8$s %7$s</string> + <string name="same_year_wday1_md1_time1_wday2_md2_time2">%5$s %1$s %2$s %3$s - %10$s %6$s %7$s %8$s</string> + <string name="same_month_wday1_md1_time1_wday2_md2_time2">%5$s %1$s %2$s %3$s - %10$s %6$s %7$s %8$s</string> + <string name="same_year_mdy1_time1_mdy2_time2">%5$s %3$s %2$s %4$s - %10$s %8$s %7$s %9$s</string> + <string name="same_month_mdy1_time1_mdy2_time2">%5$s %3$s %2$s %4$s - %10$s %8$s %7$s %9$s</string> + <string name="same_year_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %3$s, %2$s %4$s - %10$s %6$s, %8$s, %7$s %9$s</string> + <string name="same_month_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %3$s, %2$s %4$s - %10$s %6$s, %8$s, %7$s %9$s</string> + <string name="same_month_wday1_mdy1_wday2_mdy2">%1$s, %3$s, %2$s %4$s - %6$s, %8$s, %7$s %9$s</string> + <string name="same_month_md1_md2">%3$s-%8$s %2$s</string> + <string name="same_month_wday1_md1_wday2_md2">%1$s %2$s %3$s - %6$s %7$s %8$s</string> + <string name="same_year_mdy1_mdy2">%3$s %2$s - %8$s %7$s %9$s</string> + <string name="same_month_mdy1_mdy2">%3$s-%8$s %2$s %9$s</string> + <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %3$s, %2$s - %6$s, %8$s, %7$s %9$s</string> + <string name="short_format_month">%b</string> + <string name="full_wday_month_day_no_year">E MMMM d</string> + <string name="abbrev_wday_month_day_year">E, d, MMM y</string> +</resources> diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml index 4801b323dd55..5870c86f0e36 100644 --- a/core/res/res/values-et/strings.xml +++ b/core/res/res/values-et/strings.xml @@ -959,6 +959,9 @@ <item quantity="one" msgid="1634101450343277345">"Avatud WiFi võrk on saadaval"</item> <item quantity="other" msgid="7915895323644292768">"Avatud WiFi-võrgud on saadaval"</item> </plurals> + <string name="wifi_available_sign_in" msgid="9157196203958866662">"Logi sisse WiFi-võrku"</string> + <!-- no translation found for wifi_available_sign_in_detailed (6797764740339907572) --> + <skip /> <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Ei saanud WiFi-ga ühendust"</string> <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" on halb Interneti-ühendus."</string> <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"WiFi Direct"</string> @@ -1218,10 +1221,7 @@ <string name="share_action_provider_share_with" msgid="1791316789651185229">"Jaga kasutaja(te)ga ..."</string> <string name="status_bar_device_locked" msgid="3092703448690669768">"Seade lukustatud."</string> <string name="list_delimeter" msgid="3975117572185494152">", "</string> - <!-- no translation found for sending (8715108995741758718) --> - <skip /> - <!-- no translation found for launchBrowserDefault (2057951947297614725) --> - <skip /> - <!-- no translation found for SetupCallDefault (6870275517518479651) --> - <skip /> + <string name="sending" msgid="8715108995741758718">"Saatmine ..."</string> + <string name="launchBrowserDefault" msgid="2057951947297614725">"Kas käivitada brauser?"</string> + <string name="SetupCallDefault" msgid="6870275517518479651">"Kas vastata kõnele?"</string> </resources> diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml index 02ce1b8e1361..cb4e615aaf4c 100644 --- a/core/res/res/values-fa/strings.xml +++ b/core/res/res/values-fa/strings.xml @@ -959,6 +959,9 @@ <item quantity="one" msgid="1634101450343277345">"شبکه Wi-Fi موجود را باز کنید"</item> <item quantity="other" msgid="7915895323644292768">"شبکه های Wi-Fi موجود را باز کنید"</item> </plurals> + <string name="wifi_available_sign_in" msgid="9157196203958866662">"ورود به شبکه Wi-Fi"</string> + <!-- no translation found for wifi_available_sign_in_detailed (6797764740339907572) --> + <skip /> <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"اتصال به Wi-Fi ممکن نیست"</string> <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" اتصال اینترنتی ضعیفی دارد."</string> <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string> diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml index 49cae5042611..5c4e1d77b072 100644 --- a/core/res/res/values-fi/strings.xml +++ b/core/res/res/values-fi/strings.xml @@ -959,6 +959,9 @@ <item quantity="one" msgid="1634101450343277345">"Avoin wifi-verkko käytettävissä"</item> <item quantity="other" msgid="7915895323644292768">"Avoimia wifi-verkkoja käytettävissä"</item> </plurals> + <string name="wifi_available_sign_in" msgid="9157196203958866662">"Kirjaudu wifi-verkkoon"</string> + <!-- no translation found for wifi_available_sign_in_detailed (6797764740339907572) --> + <skip /> <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wifi-yhteyden muodostaminen epäonnistui"</string> <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" : huono internetyhteys."</string> <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Suora wifi-yhteys"</string> @@ -1218,10 +1221,7 @@ <string name="share_action_provider_share_with" msgid="1791316789651185229">"Jaa seuraavien kautta:"</string> <string name="status_bar_device_locked" msgid="3092703448690669768">"Laite lukittu."</string> <string name="list_delimeter" msgid="3975117572185494152">", "</string> - <!-- no translation found for sending (8715108995741758718) --> - <skip /> - <!-- no translation found for launchBrowserDefault (2057951947297614725) --> - <skip /> - <!-- no translation found for SetupCallDefault (6870275517518479651) --> - <skip /> + <string name="sending" msgid="8715108995741758718">"Lähetetään..."</string> + <string name="launchBrowserDefault" msgid="2057951947297614725">"Käynnistetäänkö selain?"</string> + <string name="SetupCallDefault" msgid="6870275517518479651">"Vastataanko puheluun?"</string> </resources> diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml index 4b3399865416..c04550b881f8 100644 --- a/core/res/res/values-fr/strings.xml +++ b/core/res/res/values-fr/strings.xml @@ -20,7 +20,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="byteShort" msgid="8340973892742019101">"O"</string> + <string name="byteShort" msgid="8340973892742019101">"o"</string> <string name="kilobyteShort" msgid="5973789783504771878">"Ko"</string> <string name="megabyteShort" msgid="6355851576770428922">"Mo"</string> <string name="gigabyteShort" msgid="3259882455212193214">"Go"</string> @@ -959,6 +959,9 @@ <item quantity="one" msgid="1634101450343277345">"Réseau Wi-Fi ouvert disponible"</item> <item quantity="other" msgid="7915895323644292768">"Réseaux Wi-Fi ouverts disponibles"</item> </plurals> + <string name="wifi_available_sign_in" msgid="9157196203958866662">"Connectez-vous au réseau Wi-Fi"</string> + <!-- no translation found for wifi_available_sign_in_detailed (6797764740339907572) --> + <skip /> <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Impossible de se connecter au Wi-Fi."</string> <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" dispose d\'une mauvaise connexion Internet."</string> <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string> @@ -1218,10 +1221,7 @@ <string name="share_action_provider_share_with" msgid="1791316789651185229">"Partager avec..."</string> <string name="status_bar_device_locked" msgid="3092703448690669768">"Appareil verrouillé"</string> <string name="list_delimeter" msgid="3975117572185494152">", "</string> - <!-- no translation found for sending (8715108995741758718) --> - <skip /> - <!-- no translation found for launchBrowserDefault (2057951947297614725) --> - <skip /> - <!-- no translation found for SetupCallDefault (6870275517518479651) --> - <skip /> + <string name="sending" msgid="8715108995741758718">"Envoi en cours…"</string> + <string name="launchBrowserDefault" msgid="2057951947297614725">"Lancer le navigateur ?"</string> + <string name="SetupCallDefault" msgid="6870275517518479651">"Prendre l\'appel ?"</string> </resources> diff --git a/core/res/res/values-hi/donottranslate-cldr.xml b/core/res/res/values-hi/donottranslate-cldr.xml new file mode 100644 index 000000000000..d9405d83aa11 --- /dev/null +++ b/core/res/res/values-hi/donottranslate-cldr.xml @@ -0,0 +1,149 @@ +<?xml version="1.0" encoding="UTF-8"?> +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="month_long_standalone_january">जनवरी</string> + <string name="month_long_standalone_february">फरवरी</string> + <string name="month_long_standalone_march">मार्च</string> + <string name="month_long_standalone_april">अप्रैल</string> + <string name="month_long_standalone_may">मई</string> + <string name="month_long_standalone_june">जून</string> + <string name="month_long_standalone_july">जुलाई</string> + <string name="month_long_standalone_august">अगस्त</string> + <string name="month_long_standalone_september">सितम्बर</string> + <string name="month_long_standalone_october">अक्तूबर</string> + <string name="month_long_standalone_november">नवम्बर</string> + <string name="month_long_standalone_december">दिसम्बर</string> + + <string name="month_long_january">जनवरी</string> + <string name="month_long_february">फरवरी</string> + <string name="month_long_march">मार्च</string> + <string name="month_long_april">अप्रैल</string> + <string name="month_long_may">मई</string> + <string name="month_long_june">जून</string> + <string name="month_long_july">जुलाई</string> + <string name="month_long_august">अगस्त</string> + <string name="month_long_september">सितम्बर</string> + <string name="month_long_october">अक्तूबर</string> + <string name="month_long_november">नवम्बर</string> + <string name="month_long_december">दिसम्बर</string> + + <string name="month_medium_january">जनवरी</string> + <string name="month_medium_february">फरवरी</string> + <string name="month_medium_march">मार्च</string> + <string name="month_medium_april">अप्रैल</string> + <string name="month_medium_may">मई</string> + <string name="month_medium_june">जून</string> + <string name="month_medium_july">जुलाई</string> + <string name="month_medium_august">अगस्त</string> + <string name="month_medium_september">सितम्बर</string> + <string name="month_medium_october">अक्तूबर</string> + <string name="month_medium_november">नवम्बर</string> + <string name="month_medium_december">दिसम्बर</string> + + <string name="month_shortest_january">ज</string> + <string name="month_shortest_february">फ़</string> + <string name="month_shortest_march">मा</string> + <string name="month_shortest_april">अ</string> + <string name="month_shortest_may">म</string> + <string name="month_shortest_june">जू</string> + <string name="month_shortest_july">जु</string> + <string name="month_shortest_august">अ</string> + <string name="month_shortest_september">सि</string> + <string name="month_shortest_october">अ</string> + <string name="month_shortest_november">न</string> + <string name="month_shortest_december">दि</string> + + <string name="day_of_week_long_sunday">रविवार</string> + <string name="day_of_week_long_monday">सोमवार</string> + <string name="day_of_week_long_tuesday">मंगलवार</string> + <string name="day_of_week_long_wednesday">बुधवार</string> + <string name="day_of_week_long_thursday">गुरुवार</string> + <string name="day_of_week_long_friday">शुक्रवार</string> + <string name="day_of_week_long_saturday">शनिवार</string> + + <string name="day_of_week_medium_sunday">रवि</string> + <string name="day_of_week_medium_monday">सोम</string> + <string name="day_of_week_medium_tuesday">मंगल</string> + <string name="day_of_week_medium_wednesday">बुध</string> + <string name="day_of_week_medium_thursday">गुरु</string> + <string name="day_of_week_medium_friday">शुक्र</string> + <string name="day_of_week_medium_saturday">शनि</string> + + <string name="day_of_week_short_sunday">रवि</string> + <string name="day_of_week_short_monday">सोम</string> + <string name="day_of_week_short_tuesday">मंगल</string> + <string name="day_of_week_short_wednesday">बुध</string> + <string name="day_of_week_short_thursday">गुरु</string> + <string name="day_of_week_short_friday">शुक्र</string> + <string name="day_of_week_short_saturday">शनि</string> + + <string name="day_of_week_shortest_sunday">र</string> + <string name="day_of_week_shortest_monday">सो</string> + <string name="day_of_week_shortest_tuesday">मं</string> + <string name="day_of_week_shortest_wednesday">बु</string> + <string name="day_of_week_shortest_thursday">गु</string> + <string name="day_of_week_shortest_friday">शु</string> + <string name="day_of_week_shortest_saturday">श</string> + + <string name="am">AM</string> + <string name="pm">PM</string> + <string name="yesterday">Yesterday</string> + <string name="today">Today</string> + <string name="tomorrow">Tomorrow</string> + + <string name="hour_minute_24">%-k:%M</string> + <string name="hour_minute_ampm">%-l:%M %p</string> + <string name="hour_minute_cap_ampm">%-l:%M %^p</string> + <string name="twelve_hour_time_format">h:mm a</string> + <string name="twenty_four_hour_time_format">H:mm</string> + <string name="numeric_date">%-e-%-m-%Y</string> + <string name="numeric_date_format">d-M-yyyy</string> + <string name="numeric_date_template">"%s-%s-%s"</string> + <string name="month_day_year">%-e %B %Y</string> + <string name="time_of_day">%-l:%M:%S %p</string> + <string name="date_and_time">%-l:%M:%S %p %d-%m-%Y</string> + <string name="date_time">%2$s %1$s</string> + <string name="time_date">%1$s %3$s</string> + <string name="abbrev_month_day_year">%d-%m-%Y</string> + <string name="month_day">%-e %B</string> + <string name="month">%-B</string> + <string name="month_year">%B %Y</string> + <string name="abbrev_month_day">%-e %b</string> + <string name="abbrev_month">%-b</string> + <string name="abbrev_month_year">%b %Y</string> + <string name="time1_time2">%1$s – %2$s</string> + <string name="date1_date2">%2$s – %5$s</string> + <string name="numeric_md1_md2">%2$s-%3$s – %7$s-%8$s</string> + <string name="numeric_wday1_md1_wday2_md2">%1$s, %2$s-%3$s – %6$s, %7$s-%8$s</string> + <string name="numeric_mdy1_mdy2">%4$s-%2$s-%3$s – %9$s-%7$s-%8$s</string> + <string name="numeric_wday1_mdy1_wday2_mdy2">%1$s, %4$s-%2$s-%3$s – %6$s, %9$s-%7$s-%8$s</string> + <string name="numeric_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %4$s-%2$s-%3$s – %10$s %6$s, %9$s-%7$s-%8$s</string> + <string name="numeric_md1_time1_md2_time2">%5$s %3$s/%2$s – %10$s %8$s/%7$s</string> + <string name="numeric_wday1_md1_time1_wday2_md2_time2">%5$s %1$s, %3$s/%2$s – %10$s %6$s, %8$s/%7$s</string> + <string name="numeric_mdy1_time1_mdy2_time2">%5$s %3$s-%2$s-%4$s – %10$s %8$s-%7$s-%9$s</string> + <string name="wday1_date1_time1_wday2_date2_time2">%3$s %1$s, %2$s – %6$s %4$s, %5$s</string> + <string name="wday1_date1_wday2_date2">%1$s, %2$s – %4$s, %5$s</string> + <string name="date1_time1_date2_time2">%3$s %2$s – %6$s %5$s</string> + <string name="time_wday_date">%1$s %2$s, %3$s</string> + <string name="wday_date">%2$s, %3$s</string> + <string name="time_wday">%1$s %2$s</string> + <string name="same_year_md1_md2">%3$s %2$s – %8$s %7$s</string> + <string name="same_year_wday1_md1_wday2_md2">%1$s, %3$s %2$s – %6$s, %8$s %7$s</string> + <string name="same_year_md1_time1_md2_time2">%5$s %3$s %2$s – %10$s %8$s %7$s</string> + <string name="same_month_md1_time1_md2_time2">%5$s %3$s %2$s – %10$s %8$s %7$s</string> + <string name="same_year_wday1_md1_time1_wday2_md2_time2">%5$s %1$s, %3$s %2$s – %10$s %6$s, %8$s %7$s</string> + <string name="same_month_wday1_md1_time1_wday2_md2_time2">%5$s %1$s, %3$s %2$s – %10$s %6$s, %8$s %7$s</string> + <string name="same_year_mdy1_time1_mdy2_time2">%5$s %4$s-%2$s-%3$s – %10$s %9$s-%7$s-%8$s</string> + <string name="same_month_mdy1_time1_mdy2_time2">%5$s %4$s-%2$s-%3$s – %10$s %9$s-%7$s-%8$s</string> + <string name="same_year_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %3$s %2$s %4$s – %10$s %6$s, %8$s %7$s %9$s</string> + <string name="same_month_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %3$s %2$s %4$s – %10$s %6$s, %8$s %7$s %9$s</string> + <string name="same_month_wday1_mdy1_wday2_mdy2">%1$s, %3$s %2$s %4$s – %6$s, %8$s %7$s %9$s</string> + <string name="same_month_md1_md2">%2$s-%3$s – %8$s</string> + <string name="same_month_wday1_md1_wday2_md2">%1$s, %3$s %2$s – %6$s, %8$s %7$s</string> + <string name="same_year_mdy1_mdy2">%9$s-%2$s-%3$s – %7$s-%8$s</string> + <string name="same_month_mdy1_mdy2">%9$s-%2$s-%3$s – %8$s</string> + <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %9$s-%2$s-%3$s – %6$s, yyyy-%7$s-%8$s</string> + <string name="short_format_month">%b</string> + <string name="full_wday_month_day_no_year">E, d MMMM</string> + <string name="abbrev_wday_month_day_year">EEE, d MMM y</string> +</resources> diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml index 7f140f195915..6aeb2c150d50 100644 --- a/core/res/res/values-hi/strings.xml +++ b/core/res/res/values-hi/strings.xml @@ -959,6 +959,9 @@ <item quantity="one" msgid="1634101450343277345">"उपलब्ध Wi-Fi नेटवर्क खोलें"</item> <item quantity="other" msgid="7915895323644292768">"खुले Wi-Fi नेटवर्क उपलब्ध है"</item> </plurals> + <string name="wifi_available_sign_in" msgid="9157196203958866662">"Wi-Fi नेटवर्क में साइन इन करें"</string> + <!-- no translation found for wifi_available_sign_in_detailed (6797764740339907572) --> + <skip /> <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fi से कनेक्ट नहीं हो सका"</string> <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" के पास एक कमज़ोर इंटरनेट कनेक्शन है."</string> <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi प्रत्यक्ष"</string> @@ -1218,10 +1221,7 @@ <string name="share_action_provider_share_with" msgid="1791316789651185229">"इससे साझा करें..."</string> <string name="status_bar_device_locked" msgid="3092703448690669768">"उपकरण लॉक कर दिया गया."</string> <string name="list_delimeter" msgid="3975117572185494152">", "</string> - <!-- no translation found for sending (8715108995741758718) --> - <skip /> - <!-- no translation found for launchBrowserDefault (2057951947297614725) --> - <skip /> - <!-- no translation found for SetupCallDefault (6870275517518479651) --> - <skip /> + <string name="sending" msgid="8715108995741758718">"भेज रहा है..."</string> + <string name="launchBrowserDefault" msgid="2057951947297614725">"ब्राउज़र लॉन्च करें?"</string> + <string name="SetupCallDefault" msgid="6870275517518479651">"कॉल स्वीकार करें?"</string> </resources> diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml index 0599a6b5f9f9..f8177e9c0906 100644 --- a/core/res/res/values-hr/strings.xml +++ b/core/res/res/values-hr/strings.xml @@ -959,6 +959,9 @@ <item quantity="one" msgid="1634101450343277345">"Omogućavanje otvaranja Wi-Fi mreže"</item> <item quantity="other" msgid="7915895323644292768">"Omogućavanje otvaranja Wi-Fi mreža"</item> </plurals> + <string name="wifi_available_sign_in" msgid="9157196203958866662">"Prijava na WiFi mrežu"</string> + <!-- no translation found for wifi_available_sign_in_detailed (6797764740339907572) --> + <skip /> <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Ne može se spojiti na Wi-Fi"</string> <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" ima lošu internetsku vezu."</string> <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Izravni Wi-Fi"</string> @@ -1218,10 +1221,7 @@ <string name="share_action_provider_share_with" msgid="1791316789651185229">"Dijeli sa..."</string> <string name="status_bar_device_locked" msgid="3092703448690669768">"Uređaj zaključan."</string> <string name="list_delimeter" msgid="3975117572185494152">", "</string> - <!-- no translation found for sending (8715108995741758718) --> - <skip /> - <!-- no translation found for launchBrowserDefault (2057951947297614725) --> - <skip /> - <!-- no translation found for SetupCallDefault (6870275517518479651) --> - <skip /> + <string name="sending" msgid="8715108995741758718">"Slanje u tijeku..."</string> + <string name="launchBrowserDefault" msgid="2057951947297614725">"Pokrenuti preglednik?"</string> + <string name="SetupCallDefault" msgid="6870275517518479651">"Prihvatiti poziv?"</string> </resources> diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml index 6e395f3059c8..6ce743feef80 100644 --- a/core/res/res/values-hu/strings.xml +++ b/core/res/res/values-hu/strings.xml @@ -959,6 +959,9 @@ <item quantity="one" msgid="1634101450343277345">"Nyílt Wi-Fi hálózat elérhető"</item> <item quantity="other" msgid="7915895323644292768">"Nyílt Wi-Fi hálózatok elérhetők"</item> </plurals> + <string name="wifi_available_sign_in" msgid="9157196203958866662">"Bejelentkezés Wi-Fi hálózatba"</string> + <!-- no translation found for wifi_available_sign_in_detailed (6797764740339907572) --> + <skip /> <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Nem sikerült csatlakozni a Wi-Fi hálózathoz"</string> <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" rossz internetkapcsolattal rendelkezik."</string> <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string> @@ -1218,10 +1221,7 @@ <string name="share_action_provider_share_with" msgid="1791316789651185229">"Megosztás..."</string> <string name="status_bar_device_locked" msgid="3092703448690669768">"Az eszköz le van zárva."</string> <string name="list_delimeter" msgid="3975117572185494152">", "</string> - <!-- no translation found for sending (8715108995741758718) --> - <skip /> - <!-- no translation found for launchBrowserDefault (2057951947297614725) --> - <skip /> - <!-- no translation found for SetupCallDefault (6870275517518479651) --> - <skip /> + <string name="sending" msgid="8715108995741758718">"Küldés..."</string> + <string name="launchBrowserDefault" msgid="2057951947297614725">"Böngésző indítása?"</string> + <string name="SetupCallDefault" msgid="6870275517518479651">"Hívás fogadása?"</string> </resources> diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml index 930c89e363dc..5ab544335314 100644 --- a/core/res/res/values-in/strings.xml +++ b/core/res/res/values-in/strings.xml @@ -959,6 +959,9 @@ <item quantity="one" msgid="1634101450343277345">"Jaringan Wi-Fi terbuka tersedia"</item> <item quantity="other" msgid="7915895323644292768">"Jaringan Wi-Fi terbuka tersedia"</item> </plurals> + <string name="wifi_available_sign_in" msgid="9157196203958866662">"Masuk ke jaringan Wi-Fi"</string> + <!-- no translation found for wifi_available_sign_in_detailed (6797764740339907572) --> + <skip /> <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Tidak dapat tersambung ke Wi-Fi"</string> <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" memiliki sambungan internet yang buruk."</string> <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Langsung"</string> @@ -1218,10 +1221,7 @@ <string name="share_action_provider_share_with" msgid="1791316789651185229">"Berbagi dengan..."</string> <string name="status_bar_device_locked" msgid="3092703448690669768">"Perangkat tergembok."</string> <string name="list_delimeter" msgid="3975117572185494152">", "</string> - <!-- no translation found for sending (8715108995741758718) --> - <skip /> - <!-- no translation found for launchBrowserDefault (2057951947297614725) --> - <skip /> - <!-- no translation found for SetupCallDefault (6870275517518479651) --> - <skip /> + <string name="sending" msgid="8715108995741758718">"Mengirim..."</string> + <string name="launchBrowserDefault" msgid="2057951947297614725">"Luncurkan Peramban?"</string> + <string name="SetupCallDefault" msgid="6870275517518479651">"Terima Panggilan?"</string> </resources> diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml index bd7350d26acc..e56bc1e89891 100644 --- a/core/res/res/values-it/strings.xml +++ b/core/res/res/values-it/strings.xml @@ -959,6 +959,9 @@ <item quantity="one" msgid="1634101450343277345">"Rete Wi-Fi aperta disponibile"</item> <item quantity="other" msgid="7915895323644292768">"Reti Wi-Fi aperte disponibili"</item> </plurals> + <string name="wifi_available_sign_in" msgid="9157196203958866662">"Accedi a rete Wi-Fi"</string> + <!-- no translation found for wifi_available_sign_in_detailed (6797764740339907572) --> + <skip /> <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Impossibile connettersi alla rete Wi-Fi"</string> <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" ha una connessione Internet debole."</string> <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string> @@ -1218,10 +1221,7 @@ <string name="share_action_provider_share_with" msgid="1791316789651185229">"Condividi con..."</string> <string name="status_bar_device_locked" msgid="3092703448690669768">"Dispositivo bloccato."</string> <string name="list_delimeter" msgid="3975117572185494152">", "</string> - <!-- no translation found for sending (8715108995741758718) --> - <skip /> - <!-- no translation found for launchBrowserDefault (2057951947297614725) --> - <skip /> - <!-- no translation found for SetupCallDefault (6870275517518479651) --> - <skip /> + <string name="sending" msgid="8715108995741758718">"Invio..."</string> + <string name="launchBrowserDefault" msgid="2057951947297614725">"Avviare l\'applicazione Browser?"</string> + <string name="SetupCallDefault" msgid="6870275517518479651">"Accettare la chiamata?"</string> </resources> diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml index 7b315c2081f5..2c30c9cb3f1c 100644 --- a/core/res/res/values-iw/strings.xml +++ b/core/res/res/values-iw/strings.xml @@ -901,7 +901,7 @@ <string name="chooseUsbActivity" msgid="7892597146032121735">"בחר יישום עבור מכשיר ה-USB"</string> <string name="noApplications" msgid="1691104391758345586">"אין יישומים שיכולים לבצע פעולה זו."</string> <string name="aerr_title" msgid="1905800560317137752"></string> - <string name="aerr_application" msgid="932628488013092776">"לצערנו ה<xliff:g id="APPLICATION">%1$s</xliff:g> הפסיק לפעול."</string> + <string name="aerr_application" msgid="932628488013092776">"לצערנו, פעולת ה<xliff:g id="APPLICATION">%1$s</xliff:g> הופסקה."</string> <string name="aerr_process" msgid="4507058997035697579">"לצערנו, התהליך <xliff:g id="PROCESS">%1$s</xliff:g> הופסק."</string> <string name="anr_title" msgid="4351948481459135709"></string> <string name="anr_activity_application" msgid="8339738283149696827">"<xliff:g id="APPLICATION">%2$s</xliff:g> אינו מגיב."\n\n" האם ברצונך לסגור אותו?"</string> @@ -959,6 +959,9 @@ <item quantity="one" msgid="1634101450343277345">"רשת Wi-Fi פתוחה זמינה"</item> <item quantity="other" msgid="7915895323644292768">"רשתות Wi-Fi פתוחות זמינות"</item> </plurals> + <string name="wifi_available_sign_in" msgid="9157196203958866662">"היכנס לרשת WiFi"</string> + <!-- no translation found for wifi_available_sign_in_detailed (6797764740339907572) --> + <skip /> <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"אין אפשרות להתחבר ל-Wi-Fi"</string> <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" בעל חיבור גרוע לאינטרנט."</string> <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi ישיר"</string> diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml index d0e94c81eb24..b8726d92bd58 100644 --- a/core/res/res/values-ja/strings.xml +++ b/core/res/res/values-ja/strings.xml @@ -959,6 +959,9 @@ <item quantity="one" msgid="1634101450343277345">"Wi-Fiオープンネットワークが利用できます"</item> <item quantity="other" msgid="7915895323644292768">"Wi-Fiオープンネットワークが利用できます"</item> </plurals> + <string name="wifi_available_sign_in" msgid="9157196203958866662">"Wi-Fiネットワークにログイン"</string> + <!-- no translation found for wifi_available_sign_in_detailed (6797764740339907572) --> + <skip /> <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fiに接続できませんでした"</string> <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" はインターネット接続に問題があります。"</string> <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string> @@ -1218,10 +1221,7 @@ <string name="share_action_provider_share_with" msgid="1791316789651185229">"共有相手..."</string> <string name="status_bar_device_locked" msgid="3092703448690669768">"端末がロックされています。"</string> <string name="list_delimeter" msgid="3975117572185494152">"、 "</string> - <!-- no translation found for sending (8715108995741758718) --> - <skip /> - <!-- no translation found for launchBrowserDefault (2057951947297614725) --> - <skip /> - <!-- no translation found for SetupCallDefault (6870275517518479651) --> - <skip /> + <string name="sending" msgid="8715108995741758718">"送信しています..."</string> + <string name="launchBrowserDefault" msgid="2057951947297614725">"ブラウザを起動しますか?"</string> + <string name="SetupCallDefault" msgid="6870275517518479651">"通話を受けますか?"</string> </resources> diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml index fe048be049a2..af2264cd5e44 100644 --- a/core/res/res/values-ko/strings.xml +++ b/core/res/res/values-ko/strings.xml @@ -959,6 +959,9 @@ <item quantity="one" msgid="1634101450343277345">"개방형 Wi-Fi 네트워크 사용 가능"</item> <item quantity="other" msgid="7915895323644292768">"개방형 Wi-Fi 네트워크 사용 가능"</item> </plurals> + <string name="wifi_available_sign_in" msgid="9157196203958866662">"Wi-Fi 네트워크에 로그인"</string> + <!-- no translation found for wifi_available_sign_in_detailed (6797764740339907572) --> + <skip /> <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fi에 연결할 수 없습니다"</string> <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" 인터넷 연결 상태가 좋지 않습니다."</string> <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string> @@ -1218,10 +1221,7 @@ <string name="share_action_provider_share_with" msgid="1791316789651185229">"공유 대상..."</string> <string name="status_bar_device_locked" msgid="3092703448690669768">"기기가 잠겼습니다."</string> <string name="list_delimeter" msgid="3975117572185494152">", "</string> - <!-- no translation found for sending (8715108995741758718) --> - <skip /> - <!-- no translation found for launchBrowserDefault (2057951947297614725) --> - <skip /> - <!-- no translation found for SetupCallDefault (6870275517518479651) --> - <skip /> + <string name="sending" msgid="8715108995741758718">"보내는 중..."</string> + <string name="launchBrowserDefault" msgid="2057951947297614725">"브라우저를 실행하시겠습니까?"</string> + <string name="SetupCallDefault" msgid="6870275517518479651">"통화를 수락하시겠습니까?"</string> </resources> diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml index bb3b04420a3e..c2c03e68f504 100644 --- a/core/res/res/values-lt/strings.xml +++ b/core/res/res/values-lt/strings.xml @@ -959,6 +959,9 @@ <item quantity="one" msgid="1634101450343277345">"Atidaryti galimą „Wi-Fi“ tinklą"</item> <item quantity="other" msgid="7915895323644292768">"Atidaryti galimus „Wi-Fi“ tinklus"</item> </plurals> + <string name="wifi_available_sign_in" msgid="9157196203958866662">"Prisijungti prie „Wi-Fi“ tinklo"</string> + <!-- no translation found for wifi_available_sign_in_detailed (6797764740339907572) --> + <skip /> <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Nepavyko prisijungti prie „Wi-Fi“"</string> <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" turi prastą interneto ryšį."</string> <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Tiesioginis „Wi-Fi“ ryšys"</string> @@ -1218,10 +1221,7 @@ <string name="share_action_provider_share_with" msgid="1791316789651185229">"Bendrinti su..."</string> <string name="status_bar_device_locked" msgid="3092703448690669768">"Įrenginys užrakintas."</string> <string name="list_delimeter" msgid="3975117572185494152">", "</string> - <!-- no translation found for sending (8715108995741758718) --> - <skip /> - <!-- no translation found for launchBrowserDefault (2057951947297614725) --> - <skip /> - <!-- no translation found for SetupCallDefault (6870275517518479651) --> - <skip /> + <string name="sending" msgid="8715108995741758718">"Siunčiama..."</string> + <string name="launchBrowserDefault" msgid="2057951947297614725">"Paleisti naršyklę?"</string> + <string name="SetupCallDefault" msgid="6870275517518479651">"Priimti skambutį?"</string> </resources> diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml index dc60a355f1e6..bd63bb3531af 100644 --- a/core/res/res/values-lv/strings.xml +++ b/core/res/res/values-lv/strings.xml @@ -959,6 +959,9 @@ <item quantity="one" msgid="1634101450343277345">"Ir pieejams atvērts Wi-Fi tīkls"</item> <item quantity="other" msgid="7915895323644292768">"Ir pieejami atvērti Wi-Fi tīkli."</item> </plurals> + <string name="wifi_available_sign_in" msgid="9157196203958866662">"Pierakstieties Wi-Fi tīklā"</string> + <!-- no translation found for wifi_available_sign_in_detailed (6797764740339907572) --> + <skip /> <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Nevarēja izveidot savienojumu ar Wi-Fi."</string> <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" ir slikts interneta savienojums."</string> <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string> @@ -1218,10 +1221,7 @@ <string name="share_action_provider_share_with" msgid="1791316789651185229">"Koplietot ar..."</string> <string name="status_bar_device_locked" msgid="3092703448690669768">"Ierīce ir bloķēta."</string> <string name="list_delimeter" msgid="3975117572185494152">", "</string> - <!-- no translation found for sending (8715108995741758718) --> - <skip /> - <!-- no translation found for launchBrowserDefault (2057951947297614725) --> - <skip /> - <!-- no translation found for SetupCallDefault (6870275517518479651) --> - <skip /> + <string name="sending" msgid="8715108995741758718">"Notiek sūtīšana..."</string> + <string name="launchBrowserDefault" msgid="2057951947297614725">"Vai palaist pārlūkprogrammu?"</string> + <string name="SetupCallDefault" msgid="6870275517518479651">"Vai pieņemt zvanu?"</string> </resources> diff --git a/core/res/res/values-ms/donottranslate-cldr.xml b/core/res/res/values-ms/donottranslate-cldr.xml new file mode 100644 index 000000000000..09d461cc8b84 --- /dev/null +++ b/core/res/res/values-ms/donottranslate-cldr.xml @@ -0,0 +1,149 @@ +<?xml version="1.0" encoding="UTF-8"?> +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="month_long_standalone_january">Januari</string> + <string name="month_long_standalone_february">Februari</string> + <string name="month_long_standalone_march">Mac</string> + <string name="month_long_standalone_april">April</string> + <string name="month_long_standalone_may">Mei</string> + <string name="month_long_standalone_june">Jun</string> + <string name="month_long_standalone_july">Julai</string> + <string name="month_long_standalone_august">Ogos</string> + <string name="month_long_standalone_september">September</string> + <string name="month_long_standalone_october">Oktober</string> + <string name="month_long_standalone_november">November</string> + <string name="month_long_standalone_december">Disember</string> + + <string name="month_long_january">Januari</string> + <string name="month_long_february">Februari</string> + <string name="month_long_march">Mac</string> + <string name="month_long_april">April</string> + <string name="month_long_may">Mei</string> + <string name="month_long_june">Jun</string> + <string name="month_long_july">Julai</string> + <string name="month_long_august">Ogos</string> + <string name="month_long_september">September</string> + <string name="month_long_october">Oktober</string> + <string name="month_long_november">November</string> + <string name="month_long_december">Disember</string> + + <string name="month_medium_january">Jan</string> + <string name="month_medium_february">Feb</string> + <string name="month_medium_march">Mac</string> + <string name="month_medium_april">Apr</string> + <string name="month_medium_may">Mei</string> + <string name="month_medium_june">Jun</string> + <string name="month_medium_july">Jul</string> + <string name="month_medium_august">Ogos</string> + <string name="month_medium_september">Sep</string> + <string name="month_medium_october">Okt</string> + <string name="month_medium_november">Nov</string> + <string name="month_medium_december">Dis</string> + + <string name="month_shortest_january">1</string> + <string name="month_shortest_february">2</string> + <string name="month_shortest_march">3</string> + <string name="month_shortest_april">4</string> + <string name="month_shortest_may">5</string> + <string name="month_shortest_june">6</string> + <string name="month_shortest_july">7</string> + <string name="month_shortest_august">8</string> + <string name="month_shortest_september">9</string> + <string name="month_shortest_october">10</string> + <string name="month_shortest_november">11</string> + <string name="month_shortest_december">12</string> + + <string name="day_of_week_long_sunday">Ahad</string> + <string name="day_of_week_long_monday">Isnin</string> + <string name="day_of_week_long_tuesday">Selasa</string> + <string name="day_of_week_long_wednesday">Rabu</string> + <string name="day_of_week_long_thursday">Khamis</string> + <string name="day_of_week_long_friday">Jumaat</string> + <string name="day_of_week_long_saturday">Sabtu</string> + + <string name="day_of_week_medium_sunday">Ahd</string> + <string name="day_of_week_medium_monday">Isn</string> + <string name="day_of_week_medium_tuesday">Sel</string> + <string name="day_of_week_medium_wednesday">Rab</string> + <string name="day_of_week_medium_thursday">Kha</string> + <string name="day_of_week_medium_friday">Jum</string> + <string name="day_of_week_medium_saturday">Sab</string> + + <string name="day_of_week_short_sunday">Ahd</string> + <string name="day_of_week_short_monday">Isn</string> + <string name="day_of_week_short_tuesday">Sel</string> + <string name="day_of_week_short_wednesday">Rab</string> + <string name="day_of_week_short_thursday">Kha</string> + <string name="day_of_week_short_friday">Jum</string> + <string name="day_of_week_short_saturday">Sab</string> + + <string name="day_of_week_shortest_sunday">1</string> + <string name="day_of_week_shortest_monday">2</string> + <string name="day_of_week_shortest_tuesday">3</string> + <string name="day_of_week_shortest_wednesday">4</string> + <string name="day_of_week_shortest_thursday">5</string> + <string name="day_of_week_shortest_friday">6</string> + <string name="day_of_week_shortest_saturday">7</string> + + <string name="am">AM</string> + <string name="pm">PM</string> + <string name="yesterday">Yesterday</string> + <string name="today">Today</string> + <string name="tomorrow">Tomorrow</string> + + <string name="hour_minute_24">%-k:%M</string> + <string name="hour_minute_ampm">%-l:%M %p</string> + <string name="hour_minute_cap_ampm">%-l:%M %^p</string> + <string name="twelve_hour_time_format">h:mm a</string> + <string name="twenty_four_hour_time_format">H:mm</string> + <string name="numeric_date">%d/%m/%Y</string> + <string name="numeric_date_format">dd/MM/yyyy</string> + <string name="numeric_date_template">"%s/%s/%s"</string> + <string name="month_day_year">%d %B %Y</string> + <string name="time_of_day">%-l:%M:%S %p</string> + <string name="date_and_time">%-l:%M:%S %p %d %b %Y</string> + <string name="date_time">%2$s %1$s</string> + <string name="time_date">%1$s %3$s</string> + <string name="abbrev_month_day_year">%d %b %Y</string> + <string name="month_day">%B %-e</string> + <string name="month">%-B</string> + <string name="month_year">%B %Y</string> + <string name="abbrev_month_day">%b %-e</string> + <string name="abbrev_month">%-b</string> + <string name="abbrev_month_year">%Y %b</string> + <string name="time1_time2">%1$s – %2$s</string> + <string name="date1_date2">%2$s – %5$s</string> + <string name="numeric_md1_md2">%2$s-%3$s – %7$s-%8$s</string> + <string name="numeric_wday1_md1_wday2_md2">%1$s, %2$s-%3$s – %6$s, %7$s-%8$s</string> + <string name="numeric_mdy1_mdy2">%4$s-%2$s-%3$s – %9$s-%7$s-%8$s</string> + <string name="numeric_wday1_mdy1_wday2_mdy2">%1$s, %4$s-%2$s-%3$s – %6$s, %9$s-%7$s-%8$s</string> + <string name="numeric_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %4$s-%2$s-%3$s – %10$s %6$s, %9$s-%7$s-%8$s</string> + <string name="numeric_md1_time1_md2_time2">%5$s %2$s-%3$s – %10$s %7$s-%8$s</string> + <string name="numeric_wday1_md1_time1_wday2_md2_time2">%5$s %1$s, %2$s-%3$s – %10$s %6$s, %7$s-%8$s</string> + <string name="numeric_mdy1_time1_mdy2_time2">%5$s %3$s/%2$s/%4$s – %10$s %8$s/%7$s/%9$s</string> + <string name="wday1_date1_time1_wday2_date2_time2">%3$s %1$s %2$s – %6$s %4$s %5$s</string> + <string name="wday1_date1_wday2_date2">%1$s %2$s – %4$s %5$s</string> + <string name="date1_time1_date2_time2">%3$s %2$s – %6$s %5$s</string> + <string name="time_wday_date">%1$s %2$s %3$s</string> + <string name="wday_date">%2$s %3$s</string> + <string name="time_wday">%1$s %2$s</string> + <string name="same_year_md1_md2">%2$s %3$s – %7$s %8$s</string> + <string name="same_year_wday1_md1_wday2_md2">%1$s %2$s %3$s – %6$s %7$s %8$s</string> + <string name="same_year_md1_time1_md2_time2">%5$s %2$s %3$s – %10$s %7$s %8$s</string> + <string name="same_month_md1_time1_md2_time2">%5$s %2$s %3$s – %10$s %7$s %8$s</string> + <string name="same_year_wday1_md1_time1_wday2_md2_time2">%5$s %1$s %2$s %3$s – %10$s %6$s %7$s %8$s</string> + <string name="same_month_wday1_md1_time1_wday2_md2_time2">%5$s %1$s %2$s %3$s – %10$s %6$s %7$s %8$s</string> + <string name="same_year_mdy1_time1_mdy2_time2">%5$s %4$s-%2$s-%3$s – %10$s %9$s-%7$s-%8$s</string> + <string name="same_month_mdy1_time1_mdy2_time2">%5$s %4$s-%2$s-%3$s – %10$s %9$s-%7$s-%8$s</string> + <string name="same_year_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %4$s %2$s %3$s – %10$s %6$s, %9$s %7$s %8$s</string> + <string name="same_month_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %4$s %2$s %3$s – %10$s %6$s, %9$s %7$s %8$s</string> + <string name="same_month_wday1_mdy1_wday2_mdy2">%1$s, %4$s %2$s %3$s – %6$s, %9$s %7$s %8$s</string> + <string name="same_month_md1_md2">%2$s-%3$s – %8$s</string> + <string name="same_month_wday1_md1_wday2_md2">%1$s %2$s %3$s – %6$s %7$s %8$s</string> + <string name="same_year_mdy1_mdy2">%9$s-%2$s-%3$s – %7$s-%8$s</string> + <string name="same_month_mdy1_mdy2">%9$s-%2$s-%3$s – %8$s</string> + <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %9$s-%2$s-%3$s – %6$s, yyyy-%7$s-%8$s</string> + <string name="short_format_month">%b</string> + <string name="full_wday_month_day_no_year">E MMMM d</string> + <string name="abbrev_wday_month_day_year">EEE, y MMM d</string> +</resources> diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml index b26857508706..b8a47d9c0400 100644 --- a/core/res/res/values-ms/strings.xml +++ b/core/res/res/values-ms/strings.xml @@ -959,6 +959,9 @@ <item quantity="one" msgid="1634101450343277345">"Rangkaian Wi-Fi terbuka tersedia"</item> <item quantity="other" msgid="7915895323644292768">"Rangkaian Wi-Fi terbuka tersedia"</item> </plurals> + <string name="wifi_available_sign_in" msgid="9157196203958866662">"Log masuk ke rangkaian Wi-Fi"</string> + <!-- no translation found for wifi_available_sign_in_detailed (6797764740339907572) --> + <skip /> <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Tidak boleh menyambung kepada Wi-Fi"</string> <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" mempunyai sambungan internet yang kurang baik."</string> <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Langsung"</string> @@ -1218,10 +1221,7 @@ <string name="share_action_provider_share_with" msgid="1791316789651185229">"Kongsi dengan..."</string> <string name="status_bar_device_locked" msgid="3092703448690669768">"Peranti dikunci."</string> <string name="list_delimeter" msgid="3975117572185494152">", "</string> - <!-- no translation found for sending (8715108995741758718) --> - <skip /> - <!-- no translation found for launchBrowserDefault (2057951947297614725) --> - <skip /> - <!-- no translation found for SetupCallDefault (6870275517518479651) --> - <skip /> + <string name="sending" msgid="8715108995741758718">"Menghantar..."</string> + <string name="launchBrowserDefault" msgid="2057951947297614725">"Lancarkan Penyemak Imbas?"</string> + <string name="SetupCallDefault" msgid="6870275517518479651">"Terima Panggilan?"</string> </resources> diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml index e9c0965555c1..b01d27526b65 100644 --- a/core/res/res/values-nb/strings.xml +++ b/core/res/res/values-nb/strings.xml @@ -302,7 +302,7 @@ <string name="permdesc_readLogs" product="tablet" msgid="4077356893924755294">"Lar appen lese fra diverse loggfiler på systemet. Disse inneholder generell informasjon om hva som gjøres med nettbrettet, og kan inneholde personlig eller privat informasjon."</string> <string name="permdesc_readLogs" product="default" msgid="8896449437464867766">"Lar appen lese fra diverse loggfiler på systemet. Disse inneholder generell informasjon om hva som gjøres med telefonen, og kan inneholde personlig eller privat informasjon."</string> <string name="permlab_anyCodecForPlayback" msgid="715805555823881818">"bruke en hvilken som helst mediedekoder for avspilling"</string> - <string name="permdesc_anyCodecForPlayback" msgid="2101444559995480174">"Gir en app tillatelse til å bruke en hvilken som helst installert mediedekoder for å dekode for avspilling."</string> + <string name="permdesc_anyCodecForPlayback" msgid="2101444559995480174">"Lar apper bruke en hvilken som helst installert mediedekoder for å dekode for avspilling."</string> <string name="permlab_diagnostic" msgid="8076743953908000342">"lese/skrive ressurser eid av diag"</string> <string name="permdesc_diagnostic" msgid="3121238373951637049">"Lar applikasjonen lese og skrive enhver ressurs eid av gruppen diag; for eksempel, filer i /dev. Dette kan potensielt påvirke systemets sikkerhet og stabilitet. Dette bør KUN brukes for maskinvarespesifikke diagnoseverktøy laget av operatøren eller produsenten."</string> <string name="permlab_changeComponentState" msgid="79425198834329406">"aktivere eller deaktigere applikasjonskomponenter"</string> @@ -959,6 +959,9 @@ <item quantity="one" msgid="1634101450343277345">"Åpent trådløsnett i nærheten"</item> <item quantity="other" msgid="7915895323644292768">"Åpne trådløsnett i nærheten"</item> </plurals> + <string name="wifi_available_sign_in" msgid="9157196203958866662">"Logg deg på Wi-Fi-nettverket"</string> + <!-- no translation found for wifi_available_sign_in_detailed (6797764740339907572) --> + <skip /> <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Kan ikke koble til Wi-Fi"</string> <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" har en dårlig Internett-tilkobling."</string> <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string> @@ -1218,10 +1221,7 @@ <string name="share_action_provider_share_with" msgid="1791316789651185229">"Del med"</string> <string name="status_bar_device_locked" msgid="3092703448690669768">"Enheten er låst."</string> <string name="list_delimeter" msgid="3975117572185494152">", "</string> - <!-- no translation found for sending (8715108995741758718) --> - <skip /> - <!-- no translation found for launchBrowserDefault (2057951947297614725) --> - <skip /> - <!-- no translation found for SetupCallDefault (6870275517518479651) --> - <skip /> + <string name="sending" msgid="8715108995741758718">"Sender …"</string> + <string name="launchBrowserDefault" msgid="2057951947297614725">"Vil du starte nettleseren?"</string> + <string name="SetupCallDefault" msgid="6870275517518479651">"Vil du besvare anropet?"</string> </resources> diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml index 1ab6b3f3a616..84c181704989 100644 --- a/core/res/res/values-nl/strings.xml +++ b/core/res/res/values-nl/strings.xml @@ -959,6 +959,9 @@ <item quantity="one" msgid="1634101450343277345">"Open Wi-Fi-netwerk beschikbaar"</item> <item quantity="other" msgid="7915895323644292768">"Open Wi-Fi-netwerken beschikbaar"</item> </plurals> + <string name="wifi_available_sign_in" msgid="9157196203958866662">"Aanmelden bij wifi-netwerk"</string> + <!-- no translation found for wifi_available_sign_in_detailed (6797764740339907572) --> + <skip /> <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Kan geen verbinding maken met Wi-Fi"</string> <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" heeft een slechte internetverbinding."</string> <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string> diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml index cc04e9c3c888..46f50270a14a 100644 --- a/core/res/res/values-pl/strings.xml +++ b/core/res/res/values-pl/strings.xml @@ -36,7 +36,7 @@ <string name="defaultMsisdnAlphaTag" msgid="2850889754919584674">"MSISDN1"</string> <string name="mmiError" msgid="5154499457739052907">"Problem z połączeniem lub błędny kod MMI."</string> <string name="mmiFdnError" msgid="5224398216385316471">"Operacja jest ograniczona wyłącznie do numerów ustalonych."</string> - <string name="serviceEnabled" msgid="8147278346414714315">"Usługa była włączona."</string> + <string name="serviceEnabled" msgid="8147278346414714315">"Usługa została włączona."</string> <string name="serviceEnabledFor" msgid="6856228140453471041">"Usługa została włączona dla:"</string> <string name="serviceDisabled" msgid="1937553226592516411">"Usługa została wyłączona."</string> <string name="serviceRegistered" msgid="6275019082598102493">"Rejestracja powiodła się."</string> @@ -959,6 +959,9 @@ <item quantity="one" msgid="1634101450343277345">"Otwórz dostępne sieci Wi-Fi"</item> <item quantity="other" msgid="7915895323644292768">"Otwórz dostępne sieci Wi-Fi"</item> </plurals> + <string name="wifi_available_sign_in" msgid="9157196203958866662">"Zaloguj się w sieci Wi-Fi"</string> + <!-- no translation found for wifi_available_sign_in_detailed (6797764740339907572) --> + <skip /> <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Nie można połączyć się z siecią Wi-Fi."</string> <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" ma powolne połączenie internetowe."</string> <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string> @@ -1218,10 +1221,7 @@ <string name="share_action_provider_share_with" msgid="1791316789651185229">"Udostępnij..."</string> <string name="status_bar_device_locked" msgid="3092703448690669768">"Urządzenie zablokowane."</string> <string name="list_delimeter" msgid="3975117572185494152">", "</string> - <!-- no translation found for sending (8715108995741758718) --> - <skip /> - <!-- no translation found for launchBrowserDefault (2057951947297614725) --> - <skip /> - <!-- no translation found for SetupCallDefault (6870275517518479651) --> - <skip /> + <string name="sending" msgid="8715108995741758718">"Wysyłanie..."</string> + <string name="launchBrowserDefault" msgid="2057951947297614725">"Uruchomić przeglądarkę?"</string> + <string name="SetupCallDefault" msgid="6870275517518479651">"Odebrać połączenie?"</string> </resources> diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml index 16e128218c84..55d9106cca23 100644 --- a/core/res/res/values-pt-rPT/strings.xml +++ b/core/res/res/values-pt-rPT/strings.xml @@ -51,7 +51,7 @@ <string name="needPuk" msgid="919668385956251611">"O seu cartão SIM está bloqueado com PUK. Introduza o código PUK para desbloqueá-lo."</string> <string name="needPuk2" msgid="4526033371987193070">"Introduza o PUK2 para desbloquear o cartão SIM."</string> <string name="ClipMmi" msgid="6952821216480289285">"ID do Autor da Chamada"</string> - <string name="ClirMmi" msgid="7784673673446833091">"ID do autor da chamada efectuada"</string> + <string name="ClirMmi" msgid="7784673673446833091">"ID do autor da chamada efetuada"</string> <string name="CfMmi" msgid="5123218989141573515">"Encaminhamento de chamadas"</string> <string name="CwMmi" msgid="9129678056795016867">"Chamada em espera"</string> <string name="BaMmi" msgid="455193067926770581">"Barramento de chamadas"</string> @@ -170,7 +170,7 @@ <string name="permgrouplab_accounts" msgid="3359646291125325519">"As suas contas"</string> <string name="permgroupdesc_accounts" msgid="4948732641827091312">"Aceda às contas disponíveis."</string> <string name="permgrouplab_hardwareControls" msgid="7998214968791599326">"Controlos de hardware"</string> - <string name="permgroupdesc_hardwareControls" msgid="4357057861225462702">"Aceda directamente ao hardware no telefone."</string> + <string name="permgroupdesc_hardwareControls" msgid="4357057861225462702">"Aceda diretamente ao hardware no telefone."</string> <string name="permgrouplab_phoneCalls" msgid="9067173988325865923">"Chamadas telefónicas"</string> <string name="permgroupdesc_phoneCalls" msgid="7489701620446183770">"Monitorize, grave e processe chamadas telefónicas."</string> <string name="permgrouplab_systemTools" msgid="4652191644082714048">"Ferramentas do sistema"</string> @@ -291,7 +291,7 @@ <string name="permdesc_deleteCacheFiles" msgid="2283074077168165971">"Permite a uma aplicação eliminar ficheiros em cache."</string> <string name="permlab_getPackageSize" msgid="4799785352306641460">"medir espaço de armazenamento da aplicação"</string> <string name="permdesc_getPackageSize" msgid="5557253039670753437">"Permite a uma aplicação obter os respectivos código, dados e tamanhos de cache"</string> - <string name="permlab_installPackages" msgid="335800214119051089">"instalar aplicações directamente"</string> + <string name="permlab_installPackages" msgid="335800214119051089">"instalar aplicações diretamente"</string> <string name="permdesc_installPackages" msgid="526669220850066132">"Permite a uma aplicação instalar pacotes novos ou actualizados do Android. Algumas aplicações maliciosas podem utilizar este item para adicionar novas aplicações com autorizações arbitrariamente fortes."</string> <string name="permlab_clearAppCache" msgid="4747698311163766540">"eliminar todos os dados da aplicações"</string> <string name="permdesc_clearAppCache" product="tablet" msgid="3097119797652477973">"Permite a uma aplicação libertar espaço de armazenamento no tablet eliminando ficheiros no directório da cache da aplicação. Geralmente, o acesso é muito limitado para processamento do sistema."</string> @@ -395,12 +395,12 @@ <string name="permdesc_accessMtp" msgid="6532961200486791570">"Permite o acesso ao controlador MTP de kernel para implementar o protocolo MTP USB."</string> <string name="permlab_hardware_test" msgid="4148290860400659146">"testar hardware"</string> <string name="permdesc_hardware_test" msgid="3668894686500081699">"Permite à aplicação controlar vários periféricos para fins de teste de hardware."</string> - <string name="permlab_callPhone" msgid="3925836347681847954">"marcar números de telefone directamente"</string> + <string name="permlab_callPhone" msgid="3925836347681847954">"marcar números de telefone diretamente"</string> <string name="permdesc_callPhone" msgid="3369867353692722456">"Permite à aplicação marcar números de telefone sem a intervenção do utilizador. Algumas aplicações maliciosas podem provocar o aparecimento de chamadas inesperadas na sua conta telefónica. Tenha em atenção que isto não permite à aplicação marcar números de emergência."</string> - <string name="permlab_callPrivileged" msgid="4198349211108497879">"marcar directamente quaisquer números de telefone"</string> + <string name="permlab_callPrivileged" msgid="4198349211108497879">"marcar diretamente quaisquer números de telefone"</string> <string name="permdesc_callPrivileged" msgid="244405067160028452">"Permite à aplicação marcar qualquer número de telefone, incluindo números de emergência, sem a intervenção do utilizador. Algumas aplicações maliciosas podem efectuar chamadas desnecessárias e ilegais para serviços de emergência."</string> - <string name="permlab_performCdmaProvisioning" product="tablet" msgid="4842576994144604821">"iniciar directamente a configuração do tablet CDMA"</string> - <string name="permlab_performCdmaProvisioning" product="default" msgid="5604848095315421425">"iniciar directamente a configuração do telefone CDMA"</string> + <string name="permlab_performCdmaProvisioning" product="tablet" msgid="4842576994144604821">"iniciar diretamente a configuração do tablet CDMA"</string> + <string name="permlab_performCdmaProvisioning" product="default" msgid="5604848095315421425">"iniciar diretamente a configuração do telefone CDMA"</string> <string name="permdesc_performCdmaProvisioning" msgid="6457447676108355905">"Permite que a aplicação inicie o aprovisionamento CDMA. As aplicações mal intencionadas podem iniciar o aprovisionamento CDMA desnecessariamente"</string> <string name="permlab_locationUpdates" msgid="7785408253364335740">"controlar notificações de actualização de localização"</string> <string name="permdesc_locationUpdates" msgid="2300018303720930256">"Permite a activação/desactivação de notificações de actualização de localização a partir do rádio. Não se destina a utilização por aplicações normais."</string> @@ -463,7 +463,7 @@ <string name="permlab_changeWifiState" msgid="7280632711057112137">"alterar estado de Wi-Fi"</string> <string name="permdesc_changeWifiState" msgid="2950383153656873267">"Permite a uma aplicação ligar e desligar de pontos de acesso de Wi-Fi, bem como efectuar alterações a redes Wi-Fi configuradas."</string> <string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"permitir recepção Multicast Wi-Fi"</string> - <string name="permdesc_changeWifiMulticastState" msgid="8199464507656067553">"Permite que uma aplicação receba pacotes não enviados directamente para o dispositivo. Esta opção pode ser útil para descobrir serviços oferecidos na vizinhança. Utiliza mais energia do que o modo não multicast."</string> + <string name="permdesc_changeWifiMulticastState" msgid="8199464507656067553">"Permite que uma aplicação receba pacotes não enviados diretamente para o dispositivo. Esta opção pode ser útil para descobrir serviços oferecidos na vizinhança. Utiliza mais energia do que o modo não multicast."</string> <string name="permlab_accessWimaxState" msgid="2800410363171809280">"ver estado do WiMAX"</string> <string name="permdesc_accessWimaxState" msgid="8298035866227524023">"Permite a uma aplicação ver as informações acerca do estado do Wi-Fi."</string> <string name="permlab_changeWimaxState" msgid="340465839241528618">"alterar estado do WiMAX"</string> @@ -935,7 +935,7 @@ <string name="volume_ringtone" msgid="6885421406845734650">"Volume da campainha"</string> <string name="volume_music" msgid="5421651157138628171">"Volume de multimédia"</string> <string name="volume_music_hint_playing_through_bluetooth" msgid="9165984379394601533">"A reproduzir através de Bluetooth"</string> - <string name="volume_music_hint_silent_ringtone_selected" msgid="6158339745293431194">"Toque silencioso seleccionado"</string> + <string name="volume_music_hint_silent_ringtone_selected" msgid="6158339745293431194">"Toque silencioso selecionado"</string> <string name="volume_call" msgid="3941680041282788711">"Volume da chamada recebida"</string> <string name="volume_bluetooth_call" msgid="2002891926351151534">"Volume de chamada recebida em Bluetooth"</string> <string name="volume_alarm" msgid="1985191616042689100">"Volume do alarme"</string> @@ -959,6 +959,9 @@ <item quantity="one" msgid="1634101450343277345">"Rede Wi-Fi aberta disponível"</item> <item quantity="other" msgid="7915895323644292768">"Abrir redes Wi-Fi disponíveis"</item> </plurals> + <string name="wifi_available_sign_in" msgid="9157196203958866662">"Iniciar sessão na rede Wi-Fi"</string> + <!-- no translation found for wifi_available_sign_in_detailed (6797764740339907572) --> + <skip /> <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Não foi possível ligar a Wi-Fi"</string> <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" tem uma ligação à internet fraca."</string> <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string> @@ -1020,7 +1023,7 @@ <string name="extmedia_format_button_format" msgid="4131064560127478695">"Formatar"</string> <string name="adb_active_notification_title" msgid="6729044778949189918">"Depuração USB ligada"</string> <string name="adb_active_notification_message" msgid="8470296818270110396">"Seleccione para desactivar depuração USB."</string> - <string name="select_input_method" msgid="6865512749462072765">"Selecionar método de entrada"</string> + <string name="select_input_method" msgid="6865512749462072765"></string> <string name="configure_input_methods" msgid="6324843080254191535">"Configurar métodos de entrada"</string> <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> @@ -1081,7 +1084,7 @@ <string name="vpn_text" msgid="1610714069627824309">"Toque para gerir a rede."</string> <string name="vpn_text_long" msgid="4907843483284977618">"Ligado a <xliff:g id="SESSION">%s</xliff:g>. Toque para gerir a rede."</string> <string name="upload_file" msgid="2897957172366730416">"Escolher ficheiro"</string> - <string name="no_file_chosen" msgid="6363648562170759465">"Não foi seleccionado nenhum ficheiro"</string> + <string name="no_file_chosen" msgid="6363648562170759465">"Não foi selecionado nenhum ficheiro"</string> <string name="reset" msgid="2448168080964209908">"Repor"</string> <string name="submit" msgid="1602335572089911941">"Enviar"</string> <string name="car_mode_disable_notification_title" msgid="3164768212003864316">"Modo automóvel activado"</string> @@ -1218,10 +1221,7 @@ <string name="share_action_provider_share_with" msgid="1791316789651185229">"Partilhar com..."</string> <string name="status_bar_device_locked" msgid="3092703448690669768">"Aparelho bloqueado."</string> <string name="list_delimeter" msgid="3975117572185494152">", "</string> - <!-- no translation found for sending (8715108995741758718) --> - <skip /> - <!-- no translation found for launchBrowserDefault (2057951947297614725) --> - <skip /> - <!-- no translation found for SetupCallDefault (6870275517518479651) --> - <skip /> + <string name="sending" msgid="8715108995741758718">"A enviar..."</string> + <string name="launchBrowserDefault" msgid="2057951947297614725">"Iniciar Navegador?"</string> + <string name="SetupCallDefault" msgid="6870275517518479651">"Aceitar Chamada?"</string> </resources> diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml index 77c52f79c995..5a0d43d9ea0e 100644 --- a/core/res/res/values-pt/strings.xml +++ b/core/res/res/values-pt/strings.xml @@ -959,6 +959,9 @@ <item quantity="one" msgid="1634101450343277345">"Rede Wi-Fi aberta disponível"</item> <item quantity="other" msgid="7915895323644292768">"Redes Wi-Fi abertas disponíveis"</item> </plurals> + <string name="wifi_available_sign_in" msgid="9157196203958866662">"Fazer login na rede Wi-Fi"</string> + <!-- no translation found for wifi_available_sign_in_detailed (6797764740339907572) --> + <skip /> <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Não foi possível se conectar a redes Wi-Fi"</string> <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" tem uma conexão de baixa qualidade com a Internet."</string> <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string> diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml index 86492fad9ddc..e9e6e92beafe 100644 --- a/core/res/res/values-ro/strings.xml +++ b/core/res/res/values-ro/strings.xml @@ -959,6 +959,9 @@ <item quantity="one" msgid="1634101450343277345">"Reţea Wi-Fi deschisă disponibilă"</item> <item quantity="other" msgid="7915895323644292768">"Reţele Wi-Fi deschise disponibile"</item> </plurals> + <string name="wifi_available_sign_in" msgid="9157196203958866662">"Conectaţi-vă la reţeaua Wi-Fi"</string> + <!-- no translation found for wifi_available_sign_in_detailed (6797764740339907572) --> + <skip /> <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Nu se poate conecta la Wi-Fi"</string> <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" are o conexiune la internet slabă."</string> <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string> @@ -1218,10 +1221,7 @@ <string name="share_action_provider_share_with" msgid="1791316789651185229">"Distribuiţi cu..."</string> <string name="status_bar_device_locked" msgid="3092703448690669768">"Dispozitiv blocat."</string> <string name="list_delimeter" msgid="3975117572185494152">", "</string> - <!-- no translation found for sending (8715108995741758718) --> - <skip /> - <!-- no translation found for launchBrowserDefault (2057951947297614725) --> - <skip /> - <!-- no translation found for SetupCallDefault (6870275517518479651) --> - <skip /> + <string name="sending" msgid="8715108995741758718">"Se trimite..."</string> + <string name="launchBrowserDefault" msgid="2057951947297614725">"Lansaţi browserul?"</string> + <string name="SetupCallDefault" msgid="6870275517518479651">"Acceptaţi apelul?"</string> </resources> diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml index d0a409543426..65028dc54bc2 100644 --- a/core/res/res/values-ru/strings.xml +++ b/core/res/res/values-ru/strings.xml @@ -959,6 +959,9 @@ <item quantity="one" msgid="1634101450343277345">"Найдена доступная сеть Wi-Fi"</item> <item quantity="other" msgid="7915895323644292768">"Найдены доступные сети Wi-Fi"</item> </plurals> + <string name="wifi_available_sign_in" msgid="9157196203958866662">"Подключение к Wi-Fi"</string> + <!-- no translation found for wifi_available_sign_in_detailed (6797764740339907572) --> + <skip /> <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Не удалось подключиться к сети Wi-Fi"</string> <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" – плохое интернет-соединение."</string> <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string> @@ -1189,7 +1192,7 @@ <string name="data_usage_warning_body" msgid="7217480745540055170">"Проверить трафик и настройки"</string> <string name="data_usage_3g_limit_title" msgid="7093334419518706686">"Передача данных 2G/3G отключена"</string> <string name="data_usage_4g_limit_title" msgid="7636489436819470761">"Передача данных 4G отключена"</string> - <string name="data_usage_mobile_limit_title" msgid="7869402519391631884">"Мобильный Интернет отключен"</string> + <string name="data_usage_mobile_limit_title" msgid="7869402519391631884">"Моб. Интернет отключен"</string> <string name="data_usage_wifi_limit_title" msgid="8992154736441284865">"Передача данных через Wi-Fi отключена"</string> <string name="data_usage_limit_body" msgid="4313857592916426843">"Нажмите, чтобы включить"</string> <string name="data_usage_3g_limit_snoozed_title" msgid="7026739121138005231">"Превышен лимита трафика 2G и 3G"</string> @@ -1218,10 +1221,7 @@ <string name="share_action_provider_share_with" msgid="1791316789651185229">"Настройка доступа"</string> <string name="status_bar_device_locked" msgid="3092703448690669768">"Устройство заблокировано."</string> <string name="list_delimeter" msgid="3975117572185494152">", "</string> - <!-- no translation found for sending (8715108995741758718) --> - <skip /> - <!-- no translation found for launchBrowserDefault (2057951947297614725) --> - <skip /> - <!-- no translation found for SetupCallDefault (6870275517518479651) --> - <skip /> + <string name="sending" msgid="8715108995741758718">"Отправка..."</string> + <string name="launchBrowserDefault" msgid="2057951947297614725">"Запустить браузер?"</string> + <string name="SetupCallDefault" msgid="6870275517518479651">"Принять вызов?"</string> </resources> diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml index f075d27ff581..a8fb3ebe53b5 100644 --- a/core/res/res/values-sk/strings.xml +++ b/core/res/res/values-sk/strings.xml @@ -959,6 +959,9 @@ <item quantity="one" msgid="1634101450343277345">"K dispozícii je verejná sieť Wi-Fi"</item> <item quantity="other" msgid="7915895323644292768">"K dispozícii sú verejné siete Wi-Fi"</item> </plurals> + <string name="wifi_available_sign_in" msgid="9157196203958866662">"Prihlásiť sa do siete Wi-Fi"</string> + <!-- no translation found for wifi_available_sign_in_detailed (6797764740339907572) --> + <skip /> <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Nepodarilo sa pripojiť k sieti Wi-Fi"</string> <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" má nekvalitné internetové pripojenie."</string> <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Priame pripojenie Wi-Fi"</string> @@ -1218,10 +1221,7 @@ <string name="share_action_provider_share_with" msgid="1791316789651185229">"Zdieľať s..."</string> <string name="status_bar_device_locked" msgid="3092703448690669768">"Zariadenie je zamknuté."</string> <string name="list_delimeter" msgid="3975117572185494152">", "</string> - <!-- no translation found for sending (8715108995741758718) --> - <skip /> - <!-- no translation found for launchBrowserDefault (2057951947297614725) --> - <skip /> - <!-- no translation found for SetupCallDefault (6870275517518479651) --> - <skip /> + <string name="sending" msgid="8715108995741758718">"Prebieha odosielanie..."</string> + <string name="launchBrowserDefault" msgid="2057951947297614725">"Spustiť prehliadač?"</string> + <string name="SetupCallDefault" msgid="6870275517518479651">"Prijať hovor?"</string> </resources> diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml index e29881915bb4..a66a7699f8b7 100644 --- a/core/res/res/values-sl/strings.xml +++ b/core/res/res/values-sl/strings.xml @@ -959,6 +959,9 @@ <item quantity="one" msgid="1634101450343277345">"Odpiranje razpoložljivega brezžičnega omrežja"</item> <item quantity="other" msgid="7915895323644292768">"Odpiranje razpoložljivih brezžičnih omrežij"</item> </plurals> + <string name="wifi_available_sign_in" msgid="9157196203958866662">"Prijavite se v omrežje Wi-Fi"</string> + <!-- no translation found for wifi_available_sign_in_detailed (6797764740339907572) --> + <skip /> <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Z omrežjem Wi-Fi se ni mogoče povezati"</string> <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" ima slabo internetno povezavo."</string> <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string> @@ -1218,10 +1221,7 @@ <string name="share_action_provider_share_with" msgid="1791316789651185229">"Skupna raba z ..."</string> <string name="status_bar_device_locked" msgid="3092703448690669768">"Naprava zaklenjena."</string> <string name="list_delimeter" msgid="3975117572185494152">", "</string> - <!-- no translation found for sending (8715108995741758718) --> - <skip /> - <!-- no translation found for launchBrowserDefault (2057951947297614725) --> - <skip /> - <!-- no translation found for SetupCallDefault (6870275517518479651) --> - <skip /> + <string name="sending" msgid="8715108995741758718">"Pošiljanje ..."</string> + <string name="launchBrowserDefault" msgid="2057951947297614725">"Ali želite odpreti brskalnik?"</string> + <string name="SetupCallDefault" msgid="6870275517518479651">"Ali želite sprejeti klic?"</string> </resources> diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml index f083a6de4689..f24cc03ac28c 100644 --- a/core/res/res/values-sr/strings.xml +++ b/core/res/res/values-sr/strings.xml @@ -959,6 +959,9 @@ <item quantity="one" msgid="1634101450343277345">"Доступна је отворена Wi-Fi мрежа"</item> <item quantity="other" msgid="7915895323644292768">"Доступне су отворене Wi-Fi мреже"</item> </plurals> + <string name="wifi_available_sign_in" msgid="9157196203958866662">"Пријављивање на Wi-Fi мрежу"</string> + <!-- no translation found for wifi_available_sign_in_detailed (6797764740339907572) --> + <skip /> <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Није било могуће повезати са Wi-Fi мрежом"</string> <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" има лошу интернет везу."</string> <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string> @@ -1218,10 +1221,7 @@ <string name="share_action_provider_share_with" msgid="1791316789651185229">"Дељење са..."</string> <string name="status_bar_device_locked" msgid="3092703448690669768">"Уређај је закључан."</string> <string name="list_delimeter" msgid="3975117572185494152">", "</string> - <!-- no translation found for sending (8715108995741758718) --> - <skip /> - <!-- no translation found for launchBrowserDefault (2057951947297614725) --> - <skip /> - <!-- no translation found for SetupCallDefault (6870275517518479651) --> - <skip /> + <string name="sending" msgid="8715108995741758718">"Слање..."</string> + <string name="launchBrowserDefault" msgid="2057951947297614725">"Желите ли да покренете прегледач?"</string> + <string name="SetupCallDefault" msgid="6870275517518479651">"Желите ли да прихватите позив?"</string> </resources> diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml index 2e04d8fa15d2..2620efb9d44a 100644 --- a/core/res/res/values-sv/strings.xml +++ b/core/res/res/values-sv/strings.xml @@ -959,6 +959,9 @@ <item quantity="one" msgid="1634101450343277345">"Öppna Wi-Fi-nätverk är tillgängliga"</item> <item quantity="other" msgid="7915895323644292768">"Öppna Wi-Fi-nätverk är tillgängliga"</item> </plurals> + <string name="wifi_available_sign_in" msgid="9157196203958866662">"Logga in på ett Wi-Fi-nätverk"</string> + <!-- no translation found for wifi_available_sign_in_detailed (6797764740339907572) --> + <skip /> <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Det gick inte att ansluta till Wi-Fi"</string> <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" har en dålig Internetanslutning."</string> <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi direkt"</string> @@ -1218,10 +1221,7 @@ <string name="share_action_provider_share_with" msgid="1791316789651185229">"Dela med..."</string> <string name="status_bar_device_locked" msgid="3092703448690669768">"Enheten är låst."</string> <string name="list_delimeter" msgid="3975117572185494152">", "</string> - <!-- no translation found for sending (8715108995741758718) --> - <skip /> - <!-- no translation found for launchBrowserDefault (2057951947297614725) --> - <skip /> - <!-- no translation found for SetupCallDefault (6870275517518479651) --> - <skip /> + <string name="sending" msgid="8715108995741758718">"Skickas ..."</string> + <string name="launchBrowserDefault" msgid="2057951947297614725">"Vill du öppna webbläsaren?"</string> + <string name="SetupCallDefault" msgid="6870275517518479651">"Vill du ta emot samtal?"</string> </resources> diff --git a/core/res/res/values-sw/donottranslate-cldr.xml b/core/res/res/values-sw/donottranslate-cldr.xml new file mode 100644 index 000000000000..2bc07c14266a --- /dev/null +++ b/core/res/res/values-sw/donottranslate-cldr.xml @@ -0,0 +1,149 @@ +<?xml version="1.0" encoding="UTF-8"?> +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="month_long_standalone_january">Januari</string> + <string name="month_long_standalone_february">Februari</string> + <string name="month_long_standalone_march">Machi</string> + <string name="month_long_standalone_april">Aprili</string> + <string name="month_long_standalone_may">Mei</string> + <string name="month_long_standalone_june">Juni</string> + <string name="month_long_standalone_july">Julai</string> + <string name="month_long_standalone_august">Agosti</string> + <string name="month_long_standalone_september">Septemba</string> + <string name="month_long_standalone_october">Oktoba</string> + <string name="month_long_standalone_november">Novemba</string> + <string name="month_long_standalone_december">Desemba</string> + + <string name="month_long_january">Januari</string> + <string name="month_long_february">Februari</string> + <string name="month_long_march">Machi</string> + <string name="month_long_april">Aprili</string> + <string name="month_long_may">Mei</string> + <string name="month_long_june">Juni</string> + <string name="month_long_july">Julai</string> + <string name="month_long_august">Agosti</string> + <string name="month_long_september">Septemba</string> + <string name="month_long_october">Oktoba</string> + <string name="month_long_november">Novemba</string> + <string name="month_long_december">Desemba</string> + + <string name="month_medium_january">Jan</string> + <string name="month_medium_february">Feb</string> + <string name="month_medium_march">Mac</string> + <string name="month_medium_april">Apr</string> + <string name="month_medium_may">Mei</string> + <string name="month_medium_june">Jun</string> + <string name="month_medium_july">Jul</string> + <string name="month_medium_august">Ago</string> + <string name="month_medium_september">Sep</string> + <string name="month_medium_october">Okt</string> + <string name="month_medium_november">Nov</string> + <string name="month_medium_december">Des</string> + + <string name="month_shortest_january">1</string> + <string name="month_shortest_february">2</string> + <string name="month_shortest_march">3</string> + <string name="month_shortest_april">4</string> + <string name="month_shortest_may">5</string> + <string name="month_shortest_june">6</string> + <string name="month_shortest_july">7</string> + <string name="month_shortest_august">8</string> + <string name="month_shortest_september">9</string> + <string name="month_shortest_october">10</string> + <string name="month_shortest_november">11</string> + <string name="month_shortest_december">12</string> + + <string name="day_of_week_long_sunday">Jumapili</string> + <string name="day_of_week_long_monday">Jumatatu</string> + <string name="day_of_week_long_tuesday">Jumanne</string> + <string name="day_of_week_long_wednesday">Jumatano</string> + <string name="day_of_week_long_thursday">Alhamisi</string> + <string name="day_of_week_long_friday">Ijumaa</string> + <string name="day_of_week_long_saturday">Jumamosi</string> + + <string name="day_of_week_medium_sunday">Jpi</string> + <string name="day_of_week_medium_monday">Jtt</string> + <string name="day_of_week_medium_tuesday">Jnn</string> + <string name="day_of_week_medium_wednesday">Jtn</string> + <string name="day_of_week_medium_thursday">Alh</string> + <string name="day_of_week_medium_friday">Iju</string> + <string name="day_of_week_medium_saturday">Jmo</string> + + <string name="day_of_week_short_sunday">Jpi</string> + <string name="day_of_week_short_monday">Jtt</string> + <string name="day_of_week_short_tuesday">Jnn</string> + <string name="day_of_week_short_wednesday">Jtn</string> + <string name="day_of_week_short_thursday">Alh</string> + <string name="day_of_week_short_friday">Iju</string> + <string name="day_of_week_short_saturday">Jmo</string> + + <string name="day_of_week_shortest_sunday">1</string> + <string name="day_of_week_shortest_monday">2</string> + <string name="day_of_week_shortest_tuesday">3</string> + <string name="day_of_week_shortest_wednesday">4</string> + <string name="day_of_week_shortest_thursday">5</string> + <string name="day_of_week_shortest_friday">6</string> + <string name="day_of_week_shortest_saturday">7</string> + + <string name="am">AM</string> + <string name="pm">PM</string> + <string name="yesterday">Yesterday</string> + <string name="today">Today</string> + <string name="tomorrow">Tomorrow</string> + + <string name="hour_minute_24">%-k:%M</string> + <string name="hour_minute_ampm">%-l:%M %p</string> + <string name="hour_minute_cap_ampm">%-l:%M %^p</string> + <string name="twelve_hour_time_format">h:mm a</string> + <string name="twenty_four_hour_time_format">H:mm</string> + <string name="numeric_date">%Y/%m/%d</string> + <string name="numeric_date_format">yyyy/MM/dd</string> + <string name="numeric_date_template">"%s/%s/%s"</string> + <string name="month_day_year">%Y %B %-e</string> + <string name="time_of_day">%H:%M:%S</string> + <string name="date_and_time">%H:%M:%S %Y %b %-e</string> + <string name="date_time">%2$s %1$s</string> + <string name="time_date">%1$s %3$s</string> + <string name="abbrev_month_day_year">%Y %b %-e</string> + <string name="month_day">%B %-e</string> + <string name="month">%-B</string> + <string name="month_year">%Y %B</string> + <string name="abbrev_month_day">%b %-e</string> + <string name="abbrev_month">%-b</string> + <string name="abbrev_month_year">%Y %b</string> + <string name="time1_time2">%1$s – %2$s</string> + <string name="date1_date2">%2$s – %5$s</string> + <string name="numeric_md1_md2">%2$s-%3$s – %7$s-%8$s</string> + <string name="numeric_wday1_md1_wday2_md2">%1$s, %2$s-%3$s – %6$s, %7$s-%8$s</string> + <string name="numeric_mdy1_mdy2">%4$s-%2$s-%3$s – %9$s-%7$s-%8$s</string> + <string name="numeric_wday1_mdy1_wday2_mdy2">%1$s, %4$s-%2$s-%3$s – %6$s, %9$s-%7$s-%8$s</string> + <string name="numeric_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %4$s-%2$s-%3$s – %10$s %6$s, %9$s-%7$s-%8$s</string> + <string name="numeric_md1_time1_md2_time2">%5$s %2$s-%3$s – %10$s %7$s-%8$s</string> + <string name="numeric_wday1_md1_time1_wday2_md2_time2">%5$s %1$s, %2$s-%3$s – %10$s %6$s, %7$s-%8$s</string> + <string name="numeric_mdy1_time1_mdy2_time2">%5$s %4$s/%2$s/%3$s – %10$s %9$s/%7$s/%8$s</string> + <string name="wday1_date1_time1_wday2_date2_time2">%3$s %1$s %2$s – %6$s %4$s %5$s</string> + <string name="wday1_date1_wday2_date2">%1$s %2$s – %4$s %5$s</string> + <string name="date1_time1_date2_time2">%3$s %2$s – %6$s %5$s</string> + <string name="time_wday_date">%1$s %2$s %3$s</string> + <string name="wday_date">%2$s %3$s</string> + <string name="time_wday">%1$s %2$s</string> + <string name="same_year_md1_md2">%2$s %3$s – %7$s %8$s</string> + <string name="same_year_wday1_md1_wday2_md2">%1$s %2$s %3$s – %6$s %7$s %8$s</string> + <string name="same_year_md1_time1_md2_time2">%5$s %2$s %3$s – %10$s %7$s %8$s</string> + <string name="same_month_md1_time1_md2_time2">%5$s %2$s %3$s – %10$s %7$s %8$s</string> + <string name="same_year_wday1_md1_time1_wday2_md2_time2">%5$s %1$s %2$s %3$s – %10$s %6$s %7$s %8$s</string> + <string name="same_month_wday1_md1_time1_wday2_md2_time2">%5$s %1$s %2$s %3$s – %10$s %6$s %7$s %8$s</string> + <string name="same_year_mdy1_time1_mdy2_time2">%5$s %4$s-%2$s-%3$s – %10$s %9$s-%7$s-%8$s</string> + <string name="same_month_mdy1_time1_mdy2_time2">%5$s %4$s-%2$s-%3$s – %10$s %9$s-%7$s-%8$s</string> + <string name="same_year_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %4$s %2$s %3$s – %10$s %6$s, %9$s %7$s %8$s</string> + <string name="same_month_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %4$s %2$s %3$s – %10$s %6$s, %9$s %7$s %8$s</string> + <string name="same_month_wday1_mdy1_wday2_mdy2">%1$s, %4$s %2$s %3$s – %6$s, %9$s %7$s %8$s</string> + <string name="same_month_md1_md2">%2$s-%3$s – %8$s</string> + <string name="same_month_wday1_md1_wday2_md2">%1$s %2$s %3$s – %6$s %7$s %8$s</string> + <string name="same_year_mdy1_mdy2">%9$s-%2$s-%3$s – %7$s-%8$s</string> + <string name="same_month_mdy1_mdy2">%9$s-%2$s-%3$s – %8$s</string> + <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %9$s-%2$s-%3$s – %6$s, yyyy-%7$s-%8$s</string> + <string name="short_format_month">%b</string> + <string name="full_wday_month_day_no_year">E MMMM d</string> + <string name="abbrev_wday_month_day_year">EEE, y MMM d</string> +</resources> diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml index d1287d888653..d1d4fff12263 100644 --- a/core/res/res/values-sw/strings.xml +++ b/core/res/res/values-sw/strings.xml @@ -49,7 +49,7 @@ <string name="invalidPin" msgid="3850018445187475377">"Chapisha PIN ambayo ina nambari 4 hadi 8."</string> <string name="invalidPuk" msgid="8761456210898036513">"Andika PUK ambayo ina urefu wa nambari 8 au zaidi."</string> <string name="needPuk" msgid="919668385956251611">"Kadi yako ya SIM imefungwa na PUK. Anika msimbo wa PUK ili kuifungua."</string> - <string name="needPuk2" msgid="4526033371987193070">"Chapisha PUK2 ili kufungua kadi ya SIM."</string> + <string name="needPuk2" msgid="4526033371987193070">"Chapisha PUK2 ili kufungua SIM kadi."</string> <string name="ClipMmi" msgid="6952821216480289285">"Kitambulisho cha Mpigaji wa Simu Inayoingia"</string> <string name="ClirMmi" msgid="7784673673446833091">"ID ya Mpigaji simu Inayotoka nje"</string> <string name="CfMmi" msgid="5123218989141573515">"Kusambaza simu"</string> @@ -199,11 +199,11 @@ <string name="permlab_sendSmsNoConfirmation" msgid="4781483105951730228">"Tuma ujumbe wa SMS bila ya thibitisho"</string> <string name="permdesc_sendSmsNoConfirmation" msgid="4477752891276276168">"Huruhusu programu kutuma ujumbe wa SMS. Programu hatari huenda zikagharimu pesa kwa kutuma ujumbe bila ya uthibitishaji wako."</string> <string name="permlab_readSms" msgid="4085333708122372256">"soma SMS au MMS"</string> - <string name="permdesc_readSms" product="tablet" msgid="5836710350295631545">"Huruhusu programu kusoma SMS zilizohifadhiwa kwenye kompyuta yako ndogo au kadi ya SIM. Huenda programu hasidi zikasoma SMS zako za siri."</string> - <string name="permdesc_readSms" product="default" msgid="3002170087197294591">"Huruhusu programu kusoma ujumbe wa SMS uliohifadhiwa kwenye simu yako au kadi ya SIM. Programu mbaya za kompyuta huenda zikasoma ujumbe wako wa siri."</string> + <string name="permdesc_readSms" product="tablet" msgid="5836710350295631545">"Huruhusu programu kusoma SMS zilizohifadhiwa kwenye kompyuta yako ndogo au SIM kadi. Huenda programu hasidi zikasoma SMS zako za siri."</string> + <string name="permdesc_readSms" product="default" msgid="3002170087197294591">"Huruhusu programu kusoma ujumbe wa SMS uliohifadhiwa kwenye simu yako au SIM kadi. Programu mbaya za kompyuta huenda zikasoma ujumbe wako wa siri."</string> <string name="permlab_writeSms" msgid="6881122575154940744">"hariri SMS au MMS"</string> - <string name="permdesc_writeSms" product="tablet" msgid="5332124772918835437">"Huruhusu programu kuandika ujumbe wa SMS uliohifadhiwa kwenye kompyuta yako au kadi ya SIM. Huenda programu hasidi zikafuta ujumbe wako."</string> - <string name="permdesc_writeSms" product="default" msgid="6299398896177548095">"Huruhusu programu kuandika kwa ujumbe wa SMS uliohifadhiwa kwenye simu yako au kadi ya SIM. Programu mbaya za kompyuta huenda zikafuta ujumbe wako."</string> + <string name="permdesc_writeSms" product="tablet" msgid="5332124772918835437">"Huruhusu programu kuandika ujumbe wa SMS uliohifadhiwa kwenye kompyuta yako au SIM kadi. Huenda programu hasidi zikafuta ujumbe wako."</string> + <string name="permdesc_writeSms" product="default" msgid="6299398896177548095">"Huruhusu programu kuandika kwa ujumbe wa SMS uliohifadhiwa kwenye simu yako au SIM kadi. Programu mbaya za kompyuta huenda zikafuta ujumbe wako."</string> <string name="permlab_receiveWapPush" msgid="8258226427716551388">"pokea WAP"</string> <string name="permdesc_receiveWapPush" msgid="5979623826128082171">"Huruhusu programu kupokea na kuchakata ujumbe wa WAP. Programu mbaya za kompyuta huenda zikafuatilia ujumbe wako au kuzifuta bila kukuonyesha."</string> <string name="permlab_getTasks" msgid="5005277531132573353">"epua programu zinazoendeshwa"</string> @@ -266,11 +266,11 @@ <string name="permlab_bindInputMethod" msgid="3360064620230515776">"funganisha kwa mbinu ya uingizaji"</string> <string name="permdesc_bindInputMethod" msgid="3734838321027317228">"Huruhusu kishikiliaji kufunga kiolesura cha kiwango cha juu cha mbinu ya uingizaji. Haipaswi kuhitajika kwa programu za kawaida za kompyuta."</string> <string name="permlab_bindTextService" msgid="7358378401915287938">"Imefungwa kwa huduma ya maandishi"</string> - <string name="permdesc_bindTextService" msgid="172508880651909350">"Huruhusu kishikiliaji kufunga kiolesura cha kiwango cha juu cha pazia cha huduma ya maandishi (k.m.SpellCheckerService). Haipaswi kuhitajika kwa programu za kawaida."</string> + <string name="permdesc_bindTextService" msgid="172508880651909350">"Huruhusu kishikiliaji kufunga kiolesura cha kiwango cha juu cha mandhari cha huduma ya maandishi (k.m.SpellCheckerService). Haipaswi kuhitajika kwa programu za kawaida."</string> <string name="permlab_bindVpnService" msgid="4708596021161473255">"funga kwa huduma ya VPN"</string> <string name="permdesc_bindVpnService" msgid="6011554199384584151">"Huruhusu kishikiliaji kufunga kusano cha kiwango cha juu cha huduma ya Vpn. Haipaswi kamwe kuhitajika kwa programu za kawaida."</string> - <string name="permlab_bindWallpaper" msgid="8716400279937856462">"funga kwa pazia"</string> - <string name="permdesc_bindWallpaper" msgid="5287754520361915347">"Huruhusu kishikiliaji kufunga kiolesura cha kiwango cha juu cha pazia. Haipaswi kuhitajika kwa programu za kawaida za kompyuta."</string> + <string name="permlab_bindWallpaper" msgid="8716400279937856462">"funga kwa mandhari"</string> + <string name="permdesc_bindWallpaper" msgid="5287754520361915347">"Huruhusu kishikiliaji kufunga kiolesura cha kiwango cha juu cha mandhari. Haipaswi kuhitajika kwa programu za kawaida za kompyuta."</string> <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"funga kwenye huduma ya widget"</string> <string name="permdesc_bindRemoteViews" msgid="2930855984822926963">"Huruhusu kishikiliaji kufunga kiolesura cha kiwango cha juu cha huduma ya wiji. Haipaswi kuhitajika kwa programu za kawaida."</string> <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"jiunge na msimamizi wa kifaa"</string> @@ -423,10 +423,10 @@ <string name="permlab_factoryTest" msgid="3715225492696416187">"endesha katika hali ya jaribio ya kiwanda"</string> <string name="permdesc_factoryTest" product="tablet" msgid="3952059318359653091">"Endesha kama jaribio la mtengenezaji la kiwango cha chini, kwa hivyo kuruhusu ufikiaji kamili wa maunzi ya kompyuta ndogo. Inapatikana tu wakati kompyuta ndogo inaendeshwa katika hali ya jaribio la mtengenezaji."</string> <string name="permdesc_factoryTest" product="default" msgid="8136644990319244802">"Endesha kama jaribio la kiwango cha chini cha mtengenezaji, kwa hivyo kuruhusu ufikiaji kamili wa maunzi ya simu. Inapatikana tu wakati simu inaendeshwa katika gumzo ya jaribio ya mtengenezaji."</string> - <string name="permlab_setWallpaper" msgid="6627192333373465143">"weka pazia"</string> - <string name="permdesc_setWallpaper" msgid="6417041752170585837">"Huruhusu programu kuweka pazia ya mfumo."</string> - <string name="permlab_setWallpaperHints" msgid="3600721069353106851">"weka vidokezo vya ukubwa wa pazia"</string> - <string name="permdesc_setWallpaperHints" msgid="6019479164008079626">"Huruhusu programu kuweka vidokezo vya ukubwa wa pazia ya mfumo."</string> + <string name="permlab_setWallpaper" msgid="6627192333373465143">"weka mandhari"</string> + <string name="permdesc_setWallpaper" msgid="6417041752170585837">"Huruhusu programu kuweka mandhari ya mfumo."</string> + <string name="permlab_setWallpaperHints" msgid="3600721069353106851">"weka vidokezo vya ukubwa wa mandhari"</string> + <string name="permdesc_setWallpaperHints" msgid="6019479164008079626">"Huruhusu programu kuweka vidokezo vya ukubwa wa mandhari ya mfumo."</string> <string name="permlab_masterClear" msgid="2315750423139697397">"weka upya mfumo kwa chaguo-msingi za kiwanda"</string> <string name="permdesc_masterClear" msgid="5033465107545174514">"Huruhusu programu kuweka upya kabisa mfumo kwa mipangilio yake ya kiwanda, kwa hivyo kufuta data zote, usanidi, na programu za kompyuta zilizosanidiwa."</string> <string name="permlab_setTime" msgid="2021614829591775646">"weka muda"</string> @@ -665,11 +665,11 @@ <string name="lockscreen_charged" msgid="4938930459620989972">"Imechajiwa."</string> <string name="lockscreen_battery_short" msgid="3617549178603354656">"Kishika nafasi<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string> <string name="lockscreen_low_battery" msgid="1482873981919249740">"Unganisha chaja yako"</string> - <string name="lockscreen_missing_sim_message_short" msgid="7381499217732227295">"Hakuna kadi ya SIM."</string> - <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"Hakuna kadi ya SIM katika kompyuta ndogo."</string> - <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"Hakuna kadi ya SIM kwenye simu."</string> - <string name="lockscreen_missing_sim_instructions" msgid="8874620818937719067">"Tafadhali ingiza kadi ya SIM."</string> - <string name="lockscreen_missing_sim_instructions_long" msgid="7138450788301444298">"Kadi ya SIM inakosekana au haisomekani. Tafadhali ingiza kadi ya SIM."</string> + <string name="lockscreen_missing_sim_message_short" msgid="7381499217732227295">"Hakuna SIM kadi."</string> + <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"Hakuna SIM kadi katika kompyuta ndogo."</string> + <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"Hakuna SIM kadi kwenye simu."</string> + <string name="lockscreen_missing_sim_instructions" msgid="8874620818937719067">"Tafadhali ingiza SIM kadi."</string> + <string name="lockscreen_missing_sim_instructions_long" msgid="7138450788301444298">"Kadi ya SIM inakosekana au haisomekani. Tafadhali ingiza SIM kadi."</string> <string name="lockscreen_permanent_disabled_sim_instructions" msgid="1631853574702335453">"Kadi yako ya SIM imelemazwa kabisa. "\n" tafadhali wasiliana na mtoa huduma wako wa psiwaya ili kupata kadi nyingine ya SIM."</string> <string name="lockscreen_transport_prev_description" msgid="201594905152746886">"Kitufe cha awali cha wimbo"</string> <string name="lockscreen_transport_next_description" msgid="6089297650481292363">"Kitufe cha wimbo unaofuata"</string> @@ -681,7 +681,7 @@ <string name="lockscreen_sim_puk_locked_message" msgid="7441797339976230">"Kadi ya SIM imefungwa na PUK."</string> <string name="lockscreen_sim_puk_locked_instructions" msgid="635967534992394321">"Tafadhali angalia Mwongozo wa Mtumiaji au wasiliana na Huduma kwa Wateja."</string> <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"Kadi ya SIM imefungwa."</string> - <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"Inafungua kadi ya SIM..."</string> + <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"Inafungua SIM kadi..."</string> <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="3514742106066877476">"Umechora vibaya ruwaza yako ya kufungua mara <xliff:g id="NUMBER_0">%d</xliff:g>. "\n\n" Tafadhali jaribu tena kati ya sekunde <xliff:g id="NUMBER_1">%d</xliff:g>."</string> <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="4906034376425175381">"Haujaingiza nenosiri yako kwa usahihi mara<xliff:g id="NUMBER_0">%d</xliff:g>Tafadhali jaribu tena. "\n\n"baada ya sekunde<xliff:g id="NUMBER_1">%d</xliff:g>."</string> <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6827749231465145590">"Haujaingiza PIN yako kwa usahihi mara<xliff:g id="NUMBER_0">%d</xliff:g>tafadhali jaribu tena. "\n\n"baada ya sekunde<xliff:g id="NUMBER_1">%d</xliff:g>."</string> @@ -844,7 +844,7 @@ <item quantity="one" msgid="2178576254385739855">"kesho"</item> <item quantity="other" msgid="2973062968038355991">"kati ya siku <xliff:g id="COUNT">%d</xliff:g>"</item> </plurals> - <string name="preposition_for_date" msgid="9093949757757445117">"mnamo <xliff:g id="DATE">%s</xliff:g>"</string> + <string name="preposition_for_date" msgid="9093949757757445117">"tarehe <xliff:g id="DATE">%s</xliff:g>"</string> <string name="preposition_for_time" msgid="5506831244263083793">"Saa <xliff:g id="TIME">%s</xliff:g>"</string> <string name="preposition_for_year" msgid="5040395640711867177">"ndani ya <xliff:g id="YEAR">%s</xliff:g>"</string> <string name="day" msgid="8144195776058119424">"siku"</string> @@ -892,7 +892,7 @@ <string name="no" msgid="5141531044935541497">"Ghairi"</string> <string name="dialog_alert_title" msgid="2049658708609043103">"Zingatia"</string> <string name="loading" msgid="1760724998928255250">"Inapakia..."</string> - <string name="capital_on" msgid="1544682755514494298">"Mnamo"</string> + <string name="capital_on" msgid="1544682755514494298">"Washa"</string> <string name="capital_off" msgid="6815870386972805832">"ZIMA"</string> <string name="whichApplication" msgid="4533185947064773386">"Kamilisha kitendo kwa kutumia"</string> <string name="alwaysUse" msgid="4583018368000610438">"Tumia kama chaguo-msingi la kitendo hiki."</string> @@ -959,6 +959,9 @@ <item quantity="one" msgid="1634101450343277345">"Fungua mtandao wa Wi-Fi unaopatikana"</item> <item quantity="other" msgid="7915895323644292768">"Fungua mitandao ya Wi-Fi inayopatikana"</item> </plurals> + <string name="wifi_available_sign_in" msgid="9157196203958866662">"Ingia kwa mtandao wa Wi-Fi"</string> + <!-- no translation found for wifi_available_sign_in_detailed (6797764740339907572) --> + <skip /> <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Haikuweza kuunganisha kwa Mtandao-Hewa"</string> <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" inao muunganisho duni wa wavuti."</string> <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Mtandao hewa Moja kwa moja"</string> @@ -976,7 +979,7 @@ <string name="sms_control_yes" msgid="2532062172402615953">"Sawa"</string> <string name="sms_control_no" msgid="1715320703137199869">"Ghairi"</string> <string name="sim_removed_title" msgid="6227712319223226185">"Kadi ya SIM imeondolewa"</string> - <string name="sim_removed_message" msgid="2333164559970958645">"mtandao wa simu hutapatika hadi uanzishe upya na kadi ya SIM halali iliyoingizwa."</string> + <string name="sim_removed_message" msgid="2333164559970958645">"mtandao wa simu hutapatika hadi uanzishe upya na SIM kadi halali iliyoingizwa."</string> <string name="sim_done_button" msgid="827949989369963775">"Kwisha"</string> <string name="sim_added_title" msgid="3719670512889674693">"Kadi ya SIM imeongezwa"</string> <string name="sim_added_message" msgid="1209265974048554242">"Lazima uwashe upya kifaa chako ili kufikia mtandao wa simu."</string> @@ -1074,8 +1077,8 @@ <string name="input_method_binding_label" msgid="1283557179944992649">"Mbinu ya uingizaji"</string> <string name="sync_binding_label" msgid="3687969138375092423">"Sawazisha"</string> <string name="accessibility_binding_label" msgid="4148120742096474641">"Ufikiaji"</string> - <string name="wallpaper_binding_label" msgid="1240087844304687662">"Pazia"</string> - <string name="chooser_wallpaper" msgid="7873476199295190279">"Badilisha pazia"</string> + <string name="wallpaper_binding_label" msgid="1240087844304687662">"Mandhari"</string> + <string name="chooser_wallpaper" msgid="7873476199295190279">"Badilisha mandhari"</string> <string name="vpn_title" msgid="8219003246858087489">"VPN imeamilishwa."</string> <string name="vpn_title_long" msgid="6400714798049252294">"VPN imeamilishwa na <xliff:g id="APP">%s</xliff:g>"</string> <string name="vpn_text" msgid="1610714069627824309">"Gonga ili kudhibiti mtandao."</string> @@ -1130,7 +1133,7 @@ <string name="sync_do_nothing" msgid="8717589462945226869">"Usifanye chochote kwa sasa."</string> <string name="choose_account_label" msgid="4191313562041125787">"Chagua akaunti"</string> <string name="add_account_label" msgid="2935267344849993553">"Ongeza akaunti"</string> - <string name="choose_account_text" msgid="6891230675141555481">"Akaunti gani ungependa kutumia?"</string> + <string name="choose_account_text" msgid="6891230675141555481">"Ungependa kutumia akaunti gani?"</string> <string name="add_account_button_label" msgid="3611982894853435874">"Ongeza akaunti"</string> <string name="number_picker_increment_button" msgid="4830170763103463443">"Ongezeko"</string> <string name="number_picker_decrement_button" msgid="2576606679160067262">"Punguza"</string> @@ -1152,7 +1155,7 @@ <string name="checkbox_not_checked" msgid="5174639551134444056">"haijakaguliwa"</string> <string name="radiobutton_selected" msgid="8603599808486581511">"Iliyochaguliwa"</string> <string name="radiobutton_not_selected" msgid="2908760184307722393">"Haijachaguliwa"</string> - <string name="switch_on" msgid="551417728476977311">"Mnamo"</string> + <string name="switch_on" msgid="551417728476977311">"Washa"</string> <string name="switch_off" msgid="7249798614327155088">"zima"</string> <string name="togglebutton_pressed" msgid="4180411746647422233">"iliyobonyezwa"</string> <string name="togglebutton_not_pressed" msgid="4495147725636134425">"Haijabonyezwa"</string> @@ -1218,10 +1221,7 @@ <string name="share_action_provider_share_with" msgid="1791316789651185229">"Shiriki na..."</string> <string name="status_bar_device_locked" msgid="3092703448690669768">"Kifaa kimefungwa."</string> <string name="list_delimeter" msgid="3975117572185494152">", "</string> - <!-- no translation found for sending (8715108995741758718) --> - <skip /> - <!-- no translation found for launchBrowserDefault (2057951947297614725) --> - <skip /> - <!-- no translation found for SetupCallDefault (6870275517518479651) --> - <skip /> + <string name="sending" msgid="8715108995741758718">"Inatuma..."</string> + <string name="launchBrowserDefault" msgid="2057951947297614725">"Zindua Kivinjari?"</string> + <string name="SetupCallDefault" msgid="6870275517518479651">"Kubali Simu?"</string> </resources> diff --git a/core/res/res/values-sw600dp/dimens.xml b/core/res/res/values-sw600dp/dimens.xml index 921bcf4d6e57..431a502bd937 100644 --- a/core/res/res/values-sw600dp/dimens.xml +++ b/core/res/res/values-sw600dp/dimens.xml @@ -62,8 +62,8 @@ <!-- Default padding to apply to AppWidgetHostViews containing widgets targeting API level 14 and up. --> <dimen name="default_app_widget_padding_left">12dp</dimen> - <dimen name="default_app_widget_padding_top">12dp</dimen> - <dimen name="default_app_widget_padding_right">4dp</dimen> + <dimen name="default_app_widget_padding_top">4dp</dimen> + <dimen name="default_app_widget_padding_right">12dp</dimen> <dimen name="default_app_widget_padding_bottom">20dp</dimen> <!-- Minimum width for an action button in the menu area of an action bar --> diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml index abd1208a6aaf..0e933bef9053 100644 --- a/core/res/res/values-th/strings.xml +++ b/core/res/res/values-th/strings.xml @@ -959,6 +959,9 @@ <item quantity="one" msgid="1634101450343277345">"เปิดเครือข่าย Wi-Fi ที่ใช้งานได้"</item> <item quantity="other" msgid="7915895323644292768">"เปิดเครือข่าย Wi-Fi ที่ใช้งานได้"</item> </plurals> + <string name="wifi_available_sign_in" msgid="9157196203958866662">"ลงชื่อเข้าใช้เครือข่าย WiFi"</string> + <!-- no translation found for wifi_available_sign_in_detailed (6797764740339907572) --> + <skip /> <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"ไม่สามารถเชื่อมต่อ Wi-Fi"</string> <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" มีสัญญาณอินเทอร์เน็ตไม่ดี"</string> <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string> @@ -1218,10 +1221,7 @@ <string name="share_action_provider_share_with" msgid="1791316789651185229">"แบ่งปันกับ..."</string> <string name="status_bar_device_locked" msgid="3092703448690669768">"ล็อกอุปกรณ์อยู่"</string> <string name="list_delimeter" msgid="3975117572185494152">", "</string> - <!-- no translation found for sending (8715108995741758718) --> - <skip /> - <!-- no translation found for launchBrowserDefault (2057951947297614725) --> - <skip /> - <!-- no translation found for SetupCallDefault (6870275517518479651) --> - <skip /> + <string name="sending" msgid="8715108995741758718">"กำลังส่ง..."</string> + <string name="launchBrowserDefault" msgid="2057951947297614725">"เปิดเบราว์เซอร์หรือไม่"</string> + <string name="SetupCallDefault" msgid="6870275517518479651">"รับสายหรือไม่"</string> </resources> diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml index bc47b0adfe67..dc33146fa58c 100644 --- a/core/res/res/values-tl/strings.xml +++ b/core/res/res/values-tl/strings.xml @@ -959,6 +959,9 @@ <item quantity="one" msgid="1634101450343277345">"Available ang bukas na Wi-Fi network"</item> <item quantity="other" msgid="7915895323644292768">"Buksan ang mga available na Wi-Fi network"</item> </plurals> + <string name="wifi_available_sign_in" msgid="9157196203958866662">"Mag-sign in sa Wi-Fi network"</string> + <!-- no translation found for wifi_available_sign_in_detailed (6797764740339907572) --> + <skip /> <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Hindi makakonekta sa Wi-Fi"</string> <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" ay mayroong mahinang koneksyon sa internet."</string> <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string> @@ -1218,10 +1221,7 @@ <string name="share_action_provider_share_with" msgid="1791316789651185229">"Ibahagi kay..."</string> <string name="status_bar_device_locked" msgid="3092703448690669768">"Naka-lock ang device."</string> <string name="list_delimeter" msgid="3975117572185494152">", "</string> - <!-- no translation found for sending (8715108995741758718) --> - <skip /> - <!-- no translation found for launchBrowserDefault (2057951947297614725) --> - <skip /> - <!-- no translation found for SetupCallDefault (6870275517518479651) --> - <skip /> + <string name="sending" msgid="8715108995741758718">"Ipinapadala..."</string> + <string name="launchBrowserDefault" msgid="2057951947297614725">"Ilunsad ang Browser?"</string> + <string name="SetupCallDefault" msgid="6870275517518479651">"Tanggapin ang Tawag?"</string> </resources> diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml index d27d95bfe2c5..cdd2ad76c359 100644 --- a/core/res/res/values-tr/strings.xml +++ b/core/res/res/values-tr/strings.xml @@ -959,6 +959,9 @@ <item quantity="one" msgid="1634101450343277345">"Kullanılabilir kablosuz ağı aç"</item> <item quantity="other" msgid="7915895323644292768">"Kullanılabilir kablosuz ağları aç"</item> </plurals> + <string name="wifi_available_sign_in" msgid="9157196203958866662">"Kablosuz ağda oturum açın"</string> + <!-- no translation found for wifi_available_sign_in_detailed (6797764740339907572) --> + <skip /> <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Kablosuz bağlantısı kurulamadı"</string> <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" internet bağlantısı zayıf."</string> <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Kablosuz Doğrudan Bağlantı"</string> @@ -1218,10 +1221,7 @@ <string name="share_action_provider_share_with" msgid="1791316789651185229">"Şununla paylaş..."</string> <string name="status_bar_device_locked" msgid="3092703448690669768">"Cihaz kilitli."</string> <string name="list_delimeter" msgid="3975117572185494152">", "</string> - <!-- no translation found for sending (8715108995741758718) --> - <skip /> - <!-- no translation found for launchBrowserDefault (2057951947297614725) --> - <skip /> - <!-- no translation found for SetupCallDefault (6870275517518479651) --> - <skip /> + <string name="sending" msgid="8715108995741758718">"Gönderiliyor..."</string> + <string name="launchBrowserDefault" msgid="2057951947297614725">"Tarayıcı Başlatılsın mı?"</string> + <string name="SetupCallDefault" msgid="6870275517518479651">"Çağrı Kabul Edilsin mi?"</string> </resources> diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml index fae9aad0abec..2ea5fd58882f 100644 --- a/core/res/res/values-uk/strings.xml +++ b/core/res/res/values-uk/strings.xml @@ -959,6 +959,9 @@ <item quantity="one" msgid="1634101450343277345">"Відкрита Wi-Fi мережа доступна"</item> <item quantity="other" msgid="7915895323644292768">"Відкриті Wi-Fi мережі доступні"</item> </plurals> + <string name="wifi_available_sign_in" msgid="9157196203958866662">"Вхід у мережу Wi-Fi"</string> + <!-- no translation found for wifi_available_sign_in_detailed (6797764740339907572) --> + <skip /> <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Не вдалося під’єднатися до мережі Wi-Fi"</string> <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" має погане з’єднання з Інтернетом."</string> <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string> diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml index 72b91fcb6160..ebfffb0cb390 100644 --- a/core/res/res/values-vi/strings.xml +++ b/core/res/res/values-vi/strings.xml @@ -38,9 +38,9 @@ <string name="mmiFdnError" msgid="5224398216385316471">"Chỉ hạn chế thao tác đối với số quay số định sẵn."</string> <string name="serviceEnabled" msgid="8147278346414714315">"Dịch vụ đã được bật."</string> <string name="serviceEnabledFor" msgid="6856228140453471041">"Dịch vụ đã được bật cho:"</string> - <string name="serviceDisabled" msgid="1937553226592516411">"Dịch vụ đã bị vô hiệu hoá."</string> + <string name="serviceDisabled" msgid="1937553226592516411">"Dịch vụ đã bị vô hiệu hóa."</string> <string name="serviceRegistered" msgid="6275019082598102493">"Đăng ký thành công."</string> - <string name="serviceErased" msgid="1288584695297200972">"Xoá thành công."</string> + <string name="serviceErased" msgid="1288584695297200972">"Xóa thành công."</string> <string name="passwordIncorrect" msgid="7612208839450128715">"Mật khẩu không chính xác."</string> <string name="mmiComplete" msgid="8232527495411698359">"MMI hoàn tất."</string> <string name="badPin" msgid="5085454289896032547">"Mã PIN cũ bạn đã nhập không chính xác."</string> @@ -48,7 +48,7 @@ <string name="mismatchPin" msgid="3695902225843339274">"Mã PIN bạn đã nhập không khớp."</string> <string name="invalidPin" msgid="3850018445187475377">"Nhập mã PIN có từ 4 đến 8 số."</string> <string name="invalidPuk" msgid="8761456210898036513">"Nhập PUK có từ 8 số trở lên."</string> - <string name="needPuk" msgid="919668385956251611">"Thẻ SIM của bạn đã bị khoá PUK. Nhập mã PUK để mở khoá thẻ SIM đó."</string> + <string name="needPuk" msgid="919668385956251611">"Thẻ SIM của bạn đã bị khóa PUK. Nhập mã PUK để mở khóa thẻ SIM đó."</string> <string name="needPuk2" msgid="4526033371987193070">"Nhập mã PUK2 để bỏ chặn thẻ SIM."</string> <string name="ClipMmi" msgid="6952821216480289285">"Số gọi đến"</string> <string name="ClirMmi" msgid="7784673673446833091">"Số gọi đi"</string> @@ -83,7 +83,7 @@ <string name="serviceClassFAX" msgid="5566624998840486475">"FAX"</string> <string name="serviceClassSMS" msgid="2015460373701527489">"SMS"</string> <string name="serviceClassDataAsync" msgid="4523454783498551468">"Không đồng bộ"</string> - <string name="serviceClassDataSync" msgid="7530000519646054776">"Đồng bộ hoá"</string> + <string name="serviceClassDataSync" msgid="7530000519646054776">"Đồng bộ hóa"</string> <string name="serviceClassPacket" msgid="6991006557993423453">"Gói"</string> <string name="serviceClassPAD" msgid="3235259085648271037">"PAD"</string> <string name="roamingText0" msgid="7170335472198694945">"Chỉ báo Chuyển vùng Bật"</string> @@ -124,11 +124,11 @@ <string name="httpErrorFileNotFound" msgid="5588380756326017105">"Không tìm thấy tệp được yêu cầu."</string> <string name="httpErrorTooManyRequests" msgid="1235396927087188253">"Quá nhiều yêu cầu đang được xử lý. Hãy thử lại sau."</string> <string name="notification_title" msgid="1259940370369187045">"Lỗi đăng nhập đối với <xliff:g id="ACCOUNT">%1$s</xliff:g>"</string> - <string name="contentServiceSync" msgid="8353523060269335667">"Đồng bộ hoá"</string> - <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Đồng bộ hoá"</string> - <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Quá nhiều lần xoá <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string> + <string name="contentServiceSync" msgid="8353523060269335667">"Đồng bộ hóa"</string> + <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Đồng bộ hóa"</string> + <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Quá nhiều lần xóa <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string> <string name="low_memory" product="tablet" msgid="2292820184396262278">"Bộ nhớ máy tính bảng đã đầy! Hãy xóa một số tệp để giải phóng dung lượng."</string> - <string name="low_memory" product="default" msgid="6632412458436461203">"Bộ nhớ điện thoại đã đầy! Hãy xoá một số tệp để tạo thêm dung lượng."</string> + <string name="low_memory" product="default" msgid="6632412458436461203">"Bộ nhớ điện thoại đã đầy! Hãy xóa một số tệp để tạo thêm dung lượng."</string> <string name="me" msgid="6545696007631404292">"Tôi"</string> <string name="power_dialog" product="tablet" msgid="8545351420865202853">"Tùy chọn máy tính bảng"</string> <string name="power_dialog" product="default" msgid="1319919075463988638">"Tùy chọn điện thoại"</string> @@ -180,8 +180,8 @@ <string name="permgrouplab_storage" msgid="1971118770546336966">"Dung lượng"</string> <string name="permgroupdesc_storage" product="nosdcard" msgid="7442318502446874999">"Truy cập bộ nhớ USB."</string> <string name="permgroupdesc_storage" product="default" msgid="9203302214915355774">"Truy cập thẻ SD."</string> - <string name="permlab_statusBar" msgid="7417192629601890791">"vô hiệu hoá hoặc sửa đổi thanh trạng thái"</string> - <string name="permdesc_statusBar" msgid="1365473595331989732">"Cho phép ứng dụng vô hiệu hoá thanh trạng thái hoặc thêm và xoá biểu tượng hệ thống."</string> + <string name="permlab_statusBar" msgid="7417192629601890791">"vô hiệu hóa hoặc sửa đổi thanh trạng thái"</string> + <string name="permdesc_statusBar" msgid="1365473595331989732">"Cho phép ứng dụng vô hiệu hóa thanh trạng thái hoặc thêm và xóa biểu tượng hệ thống."</string> <string name="permlab_statusBarService" msgid="7247281911387931485">"thanh trạng thái"</string> <string name="permdesc_statusBarService" msgid="4097605867643520920">"Cho phép ứng dụng là thanh trạng thái."</string> <string name="permlab_expandStatusBar" msgid="1148198785937489264">"mở rộng/thu gọn thanh trạng thái"</string> @@ -189,9 +189,9 @@ <string name="permlab_processOutgoingCalls" msgid="1136262550878335980">"chặn các cuộc gọi đi"</string> <string name="permdesc_processOutgoingCalls" msgid="2228988201852654461">"Cho phép ứng dụng xử lý cuộc gọi đi và thay đổi số đã được quay số. Các ứng dụng độc hại có thể giám sát, chuyển hướng hoặc chặn các cuộc gọi đi."</string> <string name="permlab_receiveSms" msgid="2697628268086208535">"nhận SMS"</string> - <string name="permdesc_receiveSms" msgid="6298292335965966117">"Cho phép ứng dụng nhận và xử lý tin nhắn SMS. Các ứng dụng độc hại có thể giám sát tin nhắn của bạn hoặc xoá chúng mà không cần hiển thị tin nhắn đó cho bạn."</string> + <string name="permdesc_receiveSms" msgid="6298292335965966117">"Cho phép ứng dụng nhận và xử lý tin nhắn SMS. Các ứng dụng độc hại có thể giám sát tin nhắn của bạn hoặc xóa chúng mà không cần hiển thị tin nhắn đó cho bạn."</string> <string name="permlab_receiveMms" msgid="8894700916188083287">"nhận MMS"</string> - <string name="permdesc_receiveMms" msgid="4563346832000174373">"Cho phép ứng dụng nhận và xử lý tin nhắn MMS. Các ứng dụng độc hại có thể giám sát tin nhắn của bạn hoặc xoá chúng mà không cần hiển thị tin nhắn đó cho bạn."</string> + <string name="permdesc_receiveMms" msgid="4563346832000174373">"Cho phép ứng dụng nhận và xử lý tin nhắn MMS. Các ứng dụng độc hại có thể giám sát tin nhắn của bạn hoặc xóa chúng mà không cần hiển thị tin nhắn đó cho bạn."</string> <string name="permlab_receiveEmergencyBroadcast" msgid="1803477660846288089">"nhận các truyền phát khẩn cấp"</string> <string name="permdesc_receiveEmergencyBroadcast" msgid="7118393393716546131">"Cho phép ứng dụng truy xuất và xử lý các thư phát khẩn cấp. Quyền này chỉ khả dụng đối với các ứng dụng hệ thống."</string> <string name="permlab_sendSms" msgid="5600830612147671529">"gửi tin nhắn SMS"</string> @@ -203,9 +203,9 @@ <string name="permdesc_readSms" product="default" msgid="3002170087197294591">"Cho phép ứng dụng đọc tin nhắn SMS được lưu trữ trên điện thoại hoặc thẻ SIM của bạn. Các ứng dụng độc hại có thể đọc tin nhắn bí mật của bạn."</string> <string name="permlab_writeSms" msgid="6881122575154940744">"chỉnh sửa SMS hoặc MMS"</string> <string name="permdesc_writeSms" product="tablet" msgid="5332124772918835437">"Cho phép ứng dụng ghi vào tin nhắn SMS được lưu trữ trên máy tính bảng hoặc thẻ SIM của bạn. Các ứng dụng độc hại có thể xóa tin nhắn của bạn."</string> - <string name="permdesc_writeSms" product="default" msgid="6299398896177548095">"Cho phép ứng dụng ghi vào tin nhắn SMS được lưu trữ trên điện thoại hoặc thẻ SIM của bạn. Các ứng dụng độc hại có thể xoá tin nhắn của bạn."</string> + <string name="permdesc_writeSms" product="default" msgid="6299398896177548095">"Cho phép ứng dụng ghi vào tin nhắn SMS được lưu trữ trên điện thoại hoặc thẻ SIM của bạn. Các ứng dụng độc hại có thể xóa tin nhắn của bạn."</string> <string name="permlab_receiveWapPush" msgid="8258226427716551388">"nhận WAP"</string> - <string name="permdesc_receiveWapPush" msgid="5979623826128082171">"Cho phép ứng dụng nhận và xử lý tin nhắn WAP. Các ứng dụng độc hại có thể giám sát tin nhắn của bạn hoặc xoá chúng mà không cần hiển thị tin nhắn đó cho bạn."</string> + <string name="permdesc_receiveWapPush" msgid="5979623826128082171">"Cho phép ứng dụng nhận và xử lý tin nhắn WAP. Các ứng dụng độc hại có thể giám sát tin nhắn của bạn hoặc xóa chúng mà không cần hiển thị tin nhắn đó cho bạn."</string> <string name="permlab_getTasks" msgid="5005277531132573353">"truy xuất các ứng dụng đang chạy"</string> <string name="permdesc_getTasks" msgid="7048711358713443341">"Cho phép ứng dụng truy xuất thông tin về các công việc hiện đang chạy. Có thể cho phép các ứng dụng độc hại phát hiện thông tin riêng tư về các ứng dụng khác."</string> <string name="permlab_reorderTasks" msgid="5669588525059921549">"sắp xếp lại các ứng dụng đang chạy"</string> @@ -234,8 +234,8 @@ <string name="permdesc_stopAppSwitches" msgid="3857886086919033794">"Ngăn người dùng chuyển sang ứng dụng khác."</string> <string name="permlab_runSetActivityWatcher" msgid="7811586187574696296">"giám sát và kiểm soát tất cả khởi chạy ứng dụng"</string> <string name="permdesc_runSetActivityWatcher" msgid="2149363027173451218">"Cho phép ứng dụng giám sát và kiểm soát cách hệ thống khởi chạy các hoạt động. Các ứng dụng độc hại có thể làm tổn hại hoàn toàn hệ thống. Quyền này chỉ cần cho việc phát triển, không bao giờ dùng cho việc sử dụng thông thường."</string> - <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"gửi truyền phát đã xoá của gói"</string> - <string name="permdesc_broadcastPackageRemoved" msgid="3453286591439891260">"Cho phép ứng dụng truyền phát thông báo rằng gói ứng dụng đã bị xoá. Các ứng dụng độc hại có thể sử dụng quyền này để loại bỏ mọi ứng dụng đang chạy khác."</string> + <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"gửi truyền phát đã xóa của gói"</string> + <string name="permdesc_broadcastPackageRemoved" msgid="3453286591439891260">"Cho phép ứng dụng truyền phát thông báo rằng gói ứng dụng đã bị xóa. Các ứng dụng độc hại có thể sử dụng quyền này để loại bỏ mọi ứng dụng đang chạy khác."</string> <string name="permlab_broadcastSmsReceived" msgid="5689095009030336593">"gửi truyền phát SMS nhận được"</string> <string name="permdesc_broadcastSmsReceived" msgid="9122419277306740155">"Cho phép ứng dụng truyền phát thông báo rằng đã nhận được tin nhắn SMS. Các ứng dụng độc hại có thẻ sử dụng quyền này để giả mạo tin nhắn SMS đến."</string> <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"gửi truyền phát WAP-PUSH nhận được"</string> @@ -283,19 +283,19 @@ <string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Cho phép ứng dụng yêu cầu tín hiệu đã cung cấp được gửi đến tất cả các quá trình liên tục."</string> <string name="permlab_persistentActivity" msgid="8659652042401085862">"đặt ứng dụng luôn chạy"</string> <string name="permdesc_persistentActivity" msgid="5037199778265006008">"Cho phép ứng dụng tạo sự đồng nhất cho các phần của mình để hệ thống không thể sử dụng ứng dụng đó cho các ứng dụng khác."</string> - <string name="permlab_deletePackages" msgid="3343439331576348805">"xoá ứng dụng"</string> - <string name="permdesc_deletePackages" msgid="3634943677518723314">"Cho phép ứng dụng xoá các gói Android. Các ứng dụng độc hại có thể sử dụng quyền này để xoá các ứng dụng quan trọng."</string> - <string name="permlab_clearAppUserData" msgid="2192134353540277878">"xoá dữ liệu của ứng dụng khác"</string> - <string name="permdesc_clearAppUserData" msgid="7546345080434325456">"Cho phép ứng dụng xoá dữ liệu của người dùng."</string> - <string name="permlab_deleteCacheFiles" msgid="1518556602634276725">"xoá bộ nhớ cache của các ứng dụng khác"</string> - <string name="permdesc_deleteCacheFiles" msgid="2283074077168165971">"Cho phép ứng dụng xoá các tệp bộ nhớ cache."</string> + <string name="permlab_deletePackages" msgid="3343439331576348805">"xóa ứng dụng"</string> + <string name="permdesc_deletePackages" msgid="3634943677518723314">"Cho phép ứng dụng xóa các gói Android. Các ứng dụng độc hại có thể sử dụng quyền này để xóa các ứng dụng quan trọng."</string> + <string name="permlab_clearAppUserData" msgid="2192134353540277878">"xóa dữ liệu của ứng dụng khác"</string> + <string name="permdesc_clearAppUserData" msgid="7546345080434325456">"Cho phép ứng dụng xóa dữ liệu của người dùng."</string> + <string name="permlab_deleteCacheFiles" msgid="1518556602634276725">"xóa bộ nhớ cache của các ứng dụng khác"</string> + <string name="permdesc_deleteCacheFiles" msgid="2283074077168165971">"Cho phép ứng dụng xóa các tệp bộ nhớ cache."</string> <string name="permlab_getPackageSize" msgid="4799785352306641460">"đo dung lượng lưu trữ ứng dụng"</string> <string name="permdesc_getPackageSize" msgid="5557253039670753437">"Cho phép ứng dụng truy xuất mã, dữ liệu và kích thước bộ nhớ cache của nó"</string> <string name="permlab_installPackages" msgid="335800214119051089">"cài đặt trực tiếp ứng dụng"</string> <string name="permdesc_installPackages" msgid="526669220850066132">"Cho phép ứng dụng cài đặt các gói Android mới hoặc đã được cập nhật. Các ứng dụng độc hại có thể sử dụng quyền này để thêm ứng dụng mới có quyền mạnh mẽ tùy ý."</string> - <string name="permlab_clearAppCache" msgid="4747698311163766540">"xoá tất cả dữ liệu bộ nhớ cache của ứng dụng"</string> + <string name="permlab_clearAppCache" msgid="4747698311163766540">"xóa tất cả dữ liệu bộ nhớ cache của ứng dụng"</string> <string name="permdesc_clearAppCache" product="tablet" msgid="3097119797652477973">"Cho phép ứng dụng giải phóng bộ nhớ máy tính bảng bằng cách xóa các tệp trong thư mục bộ nhớ cache ứng dụng. Quyền truy cập thường rất hạn chế đối với quy trình hệ thống."</string> - <string name="permdesc_clearAppCache" product="default" msgid="7740465694193671402">"Cho phép ứng dụng tạo thêm dung lượng điện thoại bằng cách xoá các tệp trong thư mục bộ nhớ cache ứng dụng. Quyền truy cập thường rất hạn chế đối với quy trình hệ thống."</string> + <string name="permdesc_clearAppCache" product="default" msgid="7740465694193671402">"Cho phép ứng dụng tạo thêm dung lượng điện thoại bằng cách xóa các tệp trong thư mục bộ nhớ cache ứng dụng. Quyền truy cập thường rất hạn chế đối với quy trình hệ thống."</string> <string name="permlab_movePackage" msgid="728454979946503926">"Chuyển tài nguyên của ứng dụng"</string> <string name="permdesc_movePackage" msgid="6323049291923925277">"Cho phép ứng dụng di chuyển các tài nguyên của ứng dụng từ phương tiện truyền thông bên trong ra phương tiện bên ngoài và ngược lại."</string> <string name="permlab_readLogs" msgid="6615778543198967614">"đọc dữ liệu nhật ký nhạy cảm"</string> @@ -305,7 +305,7 @@ <string name="permdesc_anyCodecForPlayback" msgid="2101444559995480174">"Cho phép ứng dụng sử dụng bất kỳ bộ giải mã phương tiện đã cài đặt nào để giải mã phát lại."</string> <string name="permlab_diagnostic" msgid="8076743953908000342">"đọc/ghi vào tài nguyên do chẩn đoán sở hữu"</string> <string name="permdesc_diagnostic" msgid="3121238373951637049">"Cho phép ứng dụng đọc và ghi vào bất kỳ tài nguyên nào do nhóm chẩn đoán sở hữu; ví dụ: các tệp trong /dev. Quyền này có thể ảnh hưởng đến sự ổn định và bảo mật của hệ thống. CHỈ nên sử dụng quyền này cho các chẩn đoán phần cứng cụ thể bởi nhà sản xuất hoặc nhà cung cấp dịch vụ."</string> - <string name="permlab_changeComponentState" msgid="79425198834329406">"bật hoặc vô hiệu hoá các thành phần ứng dụng"</string> + <string name="permlab_changeComponentState" msgid="79425198834329406">"bật hoặc vô hiệu hóa các thành phần ứng dụng"</string> <string name="permdesc_changeComponentState" product="tablet" msgid="4647419365510068321">"Cho phép ứng dụng thay đổi việc có nên bật thành phần của ứng dụng khác hay không. Các ứng dụng độc hại có thể sử dụng quyền này để vô hiệu hóa các tính năng quan trọng của máy tính bảng. Phải cẩn thận khi sử dụng quyền này vì nó có thể khiến các thành phần rơi vào trạng thái không sử dụng được, không đồng nhất hoặc không ổn định."</string> <string name="permdesc_changeComponentState" product="default" msgid="3443473726140080761">"Cho phép ứng dụng thay đổi việc có nên bật thành phần của ứng dụng khác hay không. Các ứng dụng độc hại có thể sử dụng quyền này để vô hiệu hóa các tính năng quan trọng của điện thoại. Phải cẩn thận khi sử dụng quyền này vì quyền này có thể khiến các thành phần ứng dụng rơi vào trạng thái không sử dụng được, không đồng nhất hoặc không ổn định."</string> <string name="permlab_setPreferredApplications" msgid="3393305202145172005">"đặt ứng dụng ưa thích"</string> @@ -327,7 +327,7 @@ <string name="permdesc_readContacts" product="default" msgid="3371591512896545975">"Cho phép ứng dụng đọc tất cả dữ liệu liên hệ (địa chỉ) được lưu trữ trên điện thoại của bạn. Các ứng dụng độc hại có thể sử dụng quyền này để gửi dữ liệu của bạn cho những người khác."</string> <string name="permlab_writeContacts" msgid="644616215860933284">"ghi dữ liệu liên hệ"</string> <string name="permdesc_writeContacts" product="tablet" msgid="7782689510038568495">"Cho phép ứng dụng sửa đổi dữ liệu (địa chỉ) liên hệ được lưu trữ trên máy tính bảng của bạn. Các ứng dụng độc hại có thể sử dụng quyền này để xóa hoặc sửa đổi dữ liệu liên hệ của bạn."</string> - <string name="permdesc_writeContacts" product="default" msgid="3924383579108183601">"Cho phép ứng dụng sửa đổi dữ liệu liên hệ (địa chỉ) được lưu trữ trên điện thoại của bạn. Các ứng dụng độc hại có thể sử dụng quyền này để xoá hoặc sửa đổi dữ liệu liên hệ của bạn."</string> + <string name="permdesc_writeContacts" product="default" msgid="3924383579108183601">"Cho phép ứng dụng sửa đổi dữ liệu liên hệ (địa chỉ) được lưu trữ trên điện thoại của bạn. Các ứng dụng độc hại có thể sử dụng quyền này để xóa hoặc sửa đổi dữ liệu liên hệ của bạn."</string> <string name="permlab_readProfile" msgid="6824681438529842282">"đọc d.liệu t.sử của bạn"</string> <string name="permdesc_readProfile" product="default" msgid="6335739730324727203">"Cho phép ứng dụng đọc thông tin tiểu sử cá nhân được lưu trên thiết bị của bạn, ví dụ như tên và thông tin liên hệ của bạn. Điều này nghĩa là ứng dụng có thể nhận dạng bạn và gửi thông tin tiểu sử của bạn cho những người khác."</string> <string name="permlab_writeProfile" msgid="4679878325177177400">"ghi dữ liệu t.sử của bạn"</string> @@ -359,14 +359,14 @@ <string name="permdesc_readFrameBuffer" msgid="7530020370469942528">"Cho phép ứng dụng đọc nội dung của bộ đệm khung."</string> <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"thay đổi cài đặt âm thanh của bạn"</string> <string name="permdesc_modifyAudioSettings" msgid="5793461287365991922">"Cho phép ứng dụng sửa đổi cài đặt âm thanh chung chẳng hạn như âm lượng và định tuyến."</string> - <string name="permlab_recordAudio" msgid="3876049771427466323">"ghi âm thanh"</string> - <string name="permdesc_recordAudio" msgid="6493228261176552356">"Cho phép ứng dụng truy cập vào đường dẫn bản ghi âm thanh."</string> + <string name="permlab_recordAudio" msgid="3876049771427466323">"ghi âm"</string> + <string name="permdesc_recordAudio" msgid="6493228261176552356">"Cho phép ứng dụng truy cập vào đường dẫn bản ghi âm."</string> <string name="permlab_camera" msgid="3616391919559751192">"chụp ảnh và quay video"</string> <string name="permdesc_camera" msgid="6004878235852154239">"Cho phép ứng dụng chụp ảnh và quay video bằng máy ảnh. Quyền này cho phép ứng dụng thu thập ảnh mà máy ảnh chụp vào bất kỳ thời điểm nào."</string> <string name="permlab_brick" product="tablet" msgid="2961292205764488304">"vô hiệu hóa vĩnh viễn máy tính bảng"</string> - <string name="permlab_brick" product="default" msgid="8337817093326370537">"vĩnh viễn vô hiệu hoá điện thoại"</string> + <string name="permlab_brick" product="default" msgid="8337817093326370537">"vĩnh viễn vô hiệu hóa điện thoại"</string> <string name="permdesc_brick" product="tablet" msgid="7379164636920817963">"Cho phép ứng dụng vô hiệu hóa vĩnh viễn toàn bộ máy tính bảng. Việc này rất nguy hiểm."</string> - <string name="permdesc_brick" product="default" msgid="5569526552607599221">"Cho phép ứng dụng vô hiệu hoá vĩnh viễn toàn bộ điện thoại. Việc này rất nguy hiểm."</string> + <string name="permdesc_brick" product="default" msgid="5569526552607599221">"Cho phép ứng dụng vô hiệu hóa vĩnh viễn toàn bộ điện thoại. Việc này rất nguy hiểm."</string> <string name="permlab_reboot" product="tablet" msgid="3436634972561795002">"buộc máy tính bảng khởi động lại"</string> <string name="permlab_reboot" product="default" msgid="2898560872462638242">"buộc khởi động lại điện thoại"</string> <string name="permdesc_reboot" product="tablet" msgid="4555793623560701557">"Cho phép ứng dụng buộc máy tính bảng khởi động lại."</string> @@ -396,7 +396,7 @@ <string name="permlab_hardware_test" msgid="4148290860400659146">"kiểm tra phần cứng"</string> <string name="permdesc_hardware_test" msgid="3668894686500081699">"Cho phép ứng dụng kiểm soát các thiết bị ngoại vi khác nhau nhằm mục đích kiểm tra phần cứng."</string> <string name="permlab_callPhone" msgid="3925836347681847954">"gọi trực tiếp số điện thoại"</string> - <string name="permdesc_callPhone" msgid="3369867353692722456">"Cho phép ứng dụng gọi các số điện thoại mà không cần sự can thiệp của bạn. Các ứng dụng độc hại có thể dẫn đến các cuộc gọi không mong muốn trên hoá đơn điện thoại của bạn. Lưu ý rằng quyền này không cho phép ứng dụng gọi các số khẩn cấp."</string> + <string name="permdesc_callPhone" msgid="3369867353692722456">"Cho phép ứng dụng gọi các số điện thoại mà không cần sự can thiệp của bạn. Các ứng dụng độc hại có thể dẫn đến các cuộc gọi không mong muốn trên hóa đơn điện thoại của bạn. Lưu ý rằng quyền này không cho phép ứng dụng gọi các số khẩn cấp."</string> <string name="permlab_callPrivileged" msgid="4198349211108497879">"gọi trực tiếp số điện thoại bất kỳ"</string> <string name="permdesc_callPrivileged" msgid="244405067160028452">"Cho phép ứng dụng gọi bất kỳ số điện thoại nào, kể cả số khẩn cấp mà không cần sự can thiệp của bạn. Các ứng dụng độc hại có thể thực hiện các cuộc gọi không cần thiết và bất hợp pháp vào dịch vụ khẩn cấp."</string> <string name="permlab_performCdmaProvisioning" product="tablet" msgid="4842576994144604821">"trực tiếp bắt đầu thiết lập máy tính bảng CDMA"</string> @@ -428,7 +428,7 @@ <string name="permlab_setWallpaperHints" msgid="3600721069353106851">"Đặt gợi ý kích thước hình nền"</string> <string name="permdesc_setWallpaperHints" msgid="6019479164008079626">"Cho phép ứng dụng đặt gợi ý kích thước hình nền của hệ thống."</string> <string name="permlab_masterClear" msgid="2315750423139697397">"đặt lại hệ thống về mặc định ban đầu"</string> - <string name="permdesc_masterClear" msgid="5033465107545174514">"Cho phép ứng dụng đặt lại toàn bộ hệ thống về cài đặt ban đầu, xoá tất cả dữ liệu, cấu hình và ứng dụng đã cài đặt."</string> + <string name="permdesc_masterClear" msgid="5033465107545174514">"Cho phép ứng dụng đặt lại toàn bộ hệ thống về cài đặt ban đầu, xóa tất cả dữ liệu, cấu hình và ứng dụng đã cài đặt."</string> <string name="permlab_setTime" msgid="2021614829591775646">"đặt giờ"</string> <string name="permdesc_setTime" product="tablet" msgid="209693136361006073">"Cho phép ứng dụng thay đổi giờ trên đồng hồ của máy tính bảng."</string> <string name="permdesc_setTime" product="default" msgid="667294309287080045">"Cho phép ứng dụng thay đổi giờ trên đồng hồ của điện thoại."</string> @@ -443,7 +443,7 @@ <string name="permlab_authenticateAccounts" msgid="3940505577982882450">"hoạt động như trình xác thực tài khoản"</string> <string name="permdesc_authenticateAccounts" msgid="4006839406474208874">"Cho phép ứng dụng sử dụng các tính năng của trình xác thực tài khoản của AccountManager, bao gồm tạo tài khoản, nhận và đặt mật khẩu của các tài khoản đó."</string> <string name="permlab_manageAccounts" msgid="4440380488312204365">"quản lý danh sách tài khoản"</string> - <string name="permdesc_manageAccounts" msgid="8804114016661104517">"Cho phép ứng dụng thực hiện các thao tác như thêm và xoá tài khoản cũng như xoá mật khẩu của các tài khoản đó."</string> + <string name="permdesc_manageAccounts" msgid="8804114016661104517">"Cho phép ứng dụng thực hiện các thao tác như thêm và xóa tài khoản cũng như xóa mật khẩu của các tài khoản đó."</string> <string name="permlab_useCredentials" msgid="6401886092818819856">"sử dụng thông tin xác thực tài khoản"</string> <string name="permdesc_useCredentials" msgid="7416570544619546974">"Cho phép ứng dụng yêu cầu mã thông báo xác thực."</string> <string name="permlab_accessNetworkState" msgid="6865575199464405769">"xem trạng thái mạng"</string> @@ -476,24 +476,24 @@ <string name="permdesc_bluetooth" product="default" msgid="762515380679392945">"Cho phép ứng dụng xem cấu hình của điện thoại Bluetooth nội hạt cũng như tạo và chấp nhận các kết nối với các thiết bị được ghép nối."</string> <string name="permlab_nfc" msgid="4423351274757876953">"kiểm soát Liên lạc trường gần"</string> <string name="permdesc_nfc" msgid="9171401851954407226">"Cho phép ứng dụng liên lạc với thẻ Liên lạc trường gần (NFC), thẻ và trình đọc."</string> - <string name="permlab_disableKeyguard" msgid="4977406164311535092">"vô hiệu hoá khoá phím"</string> - <string name="permdesc_disableKeyguard" msgid="3189763479326302017">"Cho phép ứng dụng vô hiệu hoá khoá phím và bất kỳ bảo mật mật khẩu được liên kết nào. Ví dụ thích hợp của việc này là điện thoại vô hiệu hoá khoá phím khi nhận được cuộc gọi đến sau đó bật lại khoá phím khi cuộc gọi kết thúc."</string> - <string name="permlab_readSyncSettings" msgid="6201810008230503052">"đọc cài đặt đồng bộ hoá"</string> - <string name="permdesc_readSyncSettings" msgid="5315925706353341823">"Cho phép ứng dụng đọc cài đặt đồng bộ hoá, chẳng hạn như liệu đồng bộ hoá đã được bật cho Danh bạ hay chưa."</string> - <string name="permlab_writeSyncSettings" msgid="6297138566442486462">"ghi cài đặt đồng bộ hoá"</string> - <string name="permdesc_writeSyncSettings" msgid="2498201614431360044">"Cho phép ứng dụng sửa đổi cài đặt đồng bộ hoá, chẳng hạn như liệu đồng bộ hoá đã được bật cho Danh bạ chưa."</string> - <string name="permlab_readSyncStats" msgid="7396577451360202448">"đọc thống kê đồng bộ hoá"</string> - <string name="permdesc_readSyncStats" msgid="7511448343374465000">"Cho phép ứng dụng đọc thống kê đồng bộ hoá, ví dụ: lịch sử đồng bộ hoá đã diễn ra."</string> + <string name="permlab_disableKeyguard" msgid="4977406164311535092">"vô hiệu hóa khóa phím"</string> + <string name="permdesc_disableKeyguard" msgid="3189763479326302017">"Cho phép ứng dụng vô hiệu hóa khóa phím và bất kỳ bảo mật mật khẩu được liên kết nào. Ví dụ thích hợp của việc này là điện thoại vô hiệu hóa khóa phím khi nhận được cuộc gọi đến sau đó bật lại khóa phím khi cuộc gọi kết thúc."</string> + <string name="permlab_readSyncSettings" msgid="6201810008230503052">"đọc cài đặt đồng bộ hóa"</string> + <string name="permdesc_readSyncSettings" msgid="5315925706353341823">"Cho phép ứng dụng đọc cài đặt đồng bộ hóa, chẳng hạn như liệu đồng bộ hóa đã được bật cho Danh bạ hay chưa."</string> + <string name="permlab_writeSyncSettings" msgid="6297138566442486462">"ghi cài đặt đồng bộ hóa"</string> + <string name="permdesc_writeSyncSettings" msgid="2498201614431360044">"Cho phép ứng dụng sửa đổi cài đặt đồng bộ hóa, chẳng hạn như liệu đồng bộ hóa đã được bật cho Danh bạ chưa."</string> + <string name="permlab_readSyncStats" msgid="7396577451360202448">"đọc thống kê đồng bộ hóa"</string> + <string name="permdesc_readSyncStats" msgid="7511448343374465000">"Cho phép ứng dụng đọc thống kê đồng bộ hóa, ví dụ: lịch sử đồng bộ hóa đã diễn ra."</string> <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"đọc nguồn cấp dữ liệu đã đăng ký"</string> - <string name="permdesc_subscribedFeedsRead" msgid="3622200625634207660">"Cho phép ứng dụng nhận các chi tiết về nguồn cấp dữ liệu hiện đã được đồng bộ hoá."</string> + <string name="permdesc_subscribedFeedsRead" msgid="3622200625634207660">"Cho phép ứng dụng nhận các chi tiết về nguồn cấp dữ liệu hiện đã được đồng bộ hóa."</string> <string name="permlab_subscribedFeedsWrite" msgid="9015246325408209296">"ghi nguồn cấp dữ liệu đã đăng ký"</string> - <string name="permdesc_subscribedFeedsWrite" msgid="8121607099326533878">"Cho phép ứng dụng sửa đổi nguồn cấp dữ liệu hiện đã được đồng bộ hoá. Quyền này có thể cho phép ứng dụng độc hại thay đổi nguồn cấp dữ liệu đã đồng bộ hoá của bạn."</string> + <string name="permdesc_subscribedFeedsWrite" msgid="8121607099326533878">"Cho phép ứng dụng sửa đổi nguồn cấp dữ liệu hiện đã được đồng bộ hóa. Quyền này có thể cho phép ứng dụng độc hại thay đổi nguồn cấp dữ liệu đã đồng bộ hóa của bạn."</string> <string name="permlab_readDictionary" msgid="432535716804748781">"đọc từ điển do người dùng xác định"</string> <string name="permdesc_readDictionary" msgid="1082972603576360690">"Cho phép ứng dụng đọc bất kỳ từ, tên và cụm từ riêng nào mà người dùng có thể đã lưu trữ trong từ điển của người dùng."</string> <string name="permlab_writeDictionary" msgid="6703109511836343341">"ghi vào từ điển do người dùng xác định"</string> <string name="permdesc_writeDictionary" msgid="2241256206524082880">"Cho phép ứng dụng ghi từ mới vào từ điển của người dùng."</string> <string name="permlab_sdcardWrite" product="nosdcard" msgid="85430876310764752">"sửa đổi/xóa nội dung bộ nhớ USB"</string> - <string name="permlab_sdcardWrite" product="default" msgid="8079403759001777291">"sửa đổi/xoá nội dung thẻ SD"</string> + <string name="permlab_sdcardWrite" product="default" msgid="8079403759001777291">"sửa đổi/xóa nội dung thẻ SD"</string> <string name="permdesc_sdcardWrite" product="nosdcard" msgid="6594393334785738252">"C.phép ứ.dụng ghi vào b.nhớ USB."</string> <string name="permdesc_sdcardWrite" product="default" msgid="6643963204976471878">"Cho phép ứng dụng ghi vào thẻ SD."</string> <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"sửa đổi/xóa nội dung trên bộ nhớ phương tiện cục bộ"</string> @@ -517,7 +517,7 @@ <string name="policydesc_resetPassword" msgid="5391240616981297361">"Thay đổi mật khẩu mở khóa màn hình"</string> <string name="policylab_forceLock" msgid="2274085384704248431">"Khóa màn hình"</string> <string name="policydesc_forceLock" msgid="5696964126226028442">"Kiểm tra cách và thời điểm khóa màn hình"</string> - <string name="policylab_wipeData" msgid="3910545446758639713">"Xoá tất cả dữ liệu"</string> + <string name="policylab_wipeData" msgid="3910545446758639713">"Xóa tất cả dữ liệu"</string> <string name="policydesc_wipeData" product="tablet" msgid="314455232799486222">"Xóa dữ liệu trên máy tính bảng mà không cần cảnh báo, bằng cách thực hiện đặt lại về dữ liệu gốc"</string> <string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Xóa dữ liệu trên điện thoại mà không cần cảnh báo, bằng cách thực hiện đặt lại về dữ liệu gốc"</string> <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Đặt proxy chung của điện thoại"</string> @@ -646,16 +646,16 @@ <string name="keyguard_password_enter_puk_prompt" msgid="1341112146710087048">"Mã PUK"</string> <string name="keyguard_password_enter_pin_prompt" msgid="2987350144349051286">"Mã Pin mới"</string> <string name="keyguard_password_entry_touch_hint" msgid="7906561917570259833"><font size="17">"Chạm để nhập mật khẩu"</font></string> - <string name="keyguard_password_enter_password_code" msgid="9138158344813213754">"Nhập mật khẩu để mở khoá"</string> + <string name="keyguard_password_enter_password_code" msgid="9138158344813213754">"Nhập mật khẩu để mở khóa"</string> <string name="keyguard_password_enter_pin_password_code" msgid="638347075625491514">"Nhập PIN để mở khóa"</string> <string name="keyguard_password_wrong_pin_code" msgid="1295984114338107718">"Mã PIN không chính xác!"</string> - <string name="keyguard_label_text" msgid="861796461028298424">"Để mở khoá, hãy nhấn vào Trình đơn sau đó nhấn 0."</string> + <string name="keyguard_label_text" msgid="861796461028298424">"Để mở khóa, hãy nhấn vào Trình đơn sau đó nhấn 0."</string> <string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Số khẩn cấp"</string> <string name="lockscreen_carrier_default" msgid="8963839242565653192">"Không có dịch vụ nào."</string> - <string name="lockscreen_screen_locked" msgid="7288443074806832904">"Màn hình đã khoá."</string> - <string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Nhấn vào Trình đơn để mở khoá hoặc thực hiện cuộc gọi khẩn cấp."</string> - <string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Nhấn vào Trình đơn để mở khoá."</string> - <string name="lockscreen_pattern_instructions" msgid="7478703254964810302">"Vẽ hình để mở khoá"</string> + <string name="lockscreen_screen_locked" msgid="7288443074806832904">"Màn hình đã khóa."</string> + <string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Nhấn vào Trình đơn để mở khóa hoặc thực hiện cuộc gọi khẩn cấp."</string> + <string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Nhấn vào Trình đơn để mở khóa."</string> + <string name="lockscreen_pattern_instructions" msgid="7478703254964810302">"Vẽ hình để mở khóa"</string> <string name="lockscreen_emergency_call" msgid="5347633784401285225">"Cuộc gọi khẩn cấp"</string> <string name="lockscreen_return_to_call" msgid="5244259785500040021">"Quay lại cuộc gọi"</string> <string name="lockscreen_pattern_correct" msgid="9039008650362261237">"Chính xác!"</string> @@ -677,32 +677,32 @@ <string name="lockscreen_transport_play_description" msgid="5888422938351019426">"Nút phát"</string> <string name="lockscreen_transport_stop_description" msgid="4562318378766987601">"Nút dừng"</string> <string name="emergency_calls_only" msgid="6733978304386365407">"Chỉ cuộc gọi khẩn cấp"</string> - <string name="lockscreen_network_locked_message" msgid="143389224986028501">"Mạng đã khoá"</string> - <string name="lockscreen_sim_puk_locked_message" msgid="7441797339976230">"Thẻ SIM đã bị khoá PUK."</string> + <string name="lockscreen_network_locked_message" msgid="143389224986028501">"Mạng đã khóa"</string> + <string name="lockscreen_sim_puk_locked_message" msgid="7441797339976230">"Thẻ SIM đã bị khóa PUK."</string> <string name="lockscreen_sim_puk_locked_instructions" msgid="635967534992394321">"Vui lòng xem Hướng dẫn Người dùng hoặc liên hệ với Trung tâm Chăm sóc Khách hàng."</string> - <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"Thẻ SIM đã bị khoá."</string> - <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"Đang mở khoá thẻ SIM…"</string> - <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="3514742106066877476">"Bạn đã vẽ không chính xác hình mở khoá của mình <xliff:g id="NUMBER_0">%d</xliff:g> lần. "\n\n"Vui lòng thử lại sau <xliff:g id="NUMBER_1">%d</xliff:g> giây."</string> + <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"Thẻ SIM đã bị khóa."</string> + <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"Đang mở khóa thẻ SIM…"</string> + <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="3514742106066877476">"Bạn đã vẽ không chính xác hình mở khóa của mình <xliff:g id="NUMBER_0">%d</xliff:g> lần. "\n\n"Vui lòng thử lại sau <xliff:g id="NUMBER_1">%d</xliff:g> giây."</string> <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="4906034376425175381">"Bạn đã nhập sai mật khẩu <xliff:g id="NUMBER_0">%d</xliff:g> lần. "\n\n"Vui lòng thử lại trong <xliff:g id="NUMBER_1">%d</xliff:g> giấy."</string> <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6827749231465145590">"Bạn đã nhập sai PIN <xliff:g id="NUMBER_0">%d</xliff:g> lần. "\n\n"Vui lòng thử lại trong <xliff:g id="NUMBER_1">%d</xliff:g> giây."</string> <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="8687762517114904651">"Bạn đã vẽ không chính xác hình mở khóa của mình <xliff:g id="NUMBER_0">%d</xliff:g> lần. Sau <xliff:g id="NUMBER_1">%d</xliff:g> lần thử không thành công khác, bạn sẽ được yêu cầu mở khóa máy tính bảng bằng thông tin đăng nhập Google của mình."\n\n" Vui lòng thử lại trong <xliff:g id="NUMBER_2">%d</xliff:g> giây."</string> - <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="3351013842320127827">"Bạn đã vẽ không chính xác hình mở khoá của mình <xliff:g id="NUMBER_0">%d</xliff:g> lần. Sau <xliff:g id="NUMBER_1">%d</xliff:g> lần thử không thành công khác, bạn sẽ được yêu cầu mở khoá điện thoại bằng thông tin đăng nhập Google của mình."\n\n" Vui lòng thử lại trong <xliff:g id="NUMBER_2">%d</xliff:g> giây."</string> + <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="3351013842320127827">"Bạn đã vẽ không chính xác hình mở khóa của mình <xliff:g id="NUMBER_0">%d</xliff:g> lần. Sau <xliff:g id="NUMBER_1">%d</xliff:g> lần thử không thành công khác, bạn sẽ được yêu cầu mở khóa điện thoại bằng thông tin đăng nhập Google của mình."\n\n" Vui lòng thử lại trong <xliff:g id="NUMBER_2">%d</xliff:g> giây."</string> <string name="lockscreen_failed_attempts_almost_at_wipe" product="tablet" msgid="6128106399745755604">"Bạn đã mở khóa máy tính bảng không đúng cách <xliff:g id="NUMBER_0">%d</xliff:g> lần. Sau <xliff:g id="NUMBER_1">%d</xliff:g> lần mở khóa không thành công nữa, máy tính bảng sẽ được đặt lại về mặc định ban đầu và tất cả dữ liệu người dùng sẽ bị mất."</string> <string name="lockscreen_failed_attempts_almost_at_wipe" product="default" msgid="8603565142156826565">"Bạn đã mở khóa điện thoại không đúng cách <xliff:g id="NUMBER_0">%d</xliff:g> lần. Sau <xliff:g id="NUMBER_1">%d</xliff:g> lần mở khóa không thành công nữa, điện thoại sẽ được đặt lại về mặc định ban đầu và tất cả dữ liệu người dùng sẽ bị mất."</string> <string name="lockscreen_failed_attempts_now_wiping" product="tablet" msgid="280873516493934365">"Bạn đã mở khóa máy tính bảng không đúng cách <xliff:g id="NUMBER">%d</xliff:g> lần. Bây giờ, máy tính bảng sẽ được đặt lại về mặc định ban đầu."</string> <string name="lockscreen_failed_attempts_now_wiping" product="default" msgid="3025504721764922246">"Bạn đã mở khóa điện thoại không đúng cách <xliff:g id="NUMBER">%d</xliff:g> lần. Bây giờ, điện thoại sẽ được đặt lại về mặc định ban đầu."</string> <string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"Hãy thử lại sau <xliff:g id="NUMBER">%d</xliff:g> giây."</string> <string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"Đã quên hình?"</string> - <string name="lockscreen_glogin_forgot_pattern" msgid="2588521501166032747">"Mở khoá tài khoản"</string> + <string name="lockscreen_glogin_forgot_pattern" msgid="2588521501166032747">"Mở khóa tài khoản"</string> <string name="lockscreen_glogin_too_many_attempts" msgid="2446246026221678244">"Quá nhiều lần nhập hình!"</string> - <string name="lockscreen_glogin_instructions" msgid="1816635201812207709">"Để mở khoá, hãy đăng nhập bằng tài khoản Google của bạn"</string> + <string name="lockscreen_glogin_instructions" msgid="1816635201812207709">"Để mở khóa, hãy đăng nhập bằng tài khoản Google của bạn"</string> <string name="lockscreen_glogin_username_hint" msgid="8846881424106484447">"Tên người dùng (email)"</string> <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"Mật khẩu"</string> <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Đăng nhập"</string> <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"Tên người dùng hoặc mật khẩu không hợp lệ."</string> <string name="lockscreen_glogin_account_recovery_hint" msgid="8253152905532900548">"Bạn quên tên người dùng hoặc mật khẩu?"\n"Hãy truy cập "<b>"google.com/accounts/recovery"</b></string> <string name="lockscreen_glogin_checking_password" msgid="6758890536332363322">"Đang kiểm tra..."</string> - <string name="lockscreen_unlock_label" msgid="737440483220667054">"Mở khoá"</string> + <string name="lockscreen_unlock_label" msgid="737440483220667054">"Mở khóa"</string> <string name="lockscreen_sound_on_label" msgid="9068877576513425970">"Bật âm thanh"</string> <string name="lockscreen_sound_off_label" msgid="996822825154319026">"Tắt âm thanh"</string> <string name="lockscreen_access_pattern_start" msgid="3941045502933142847">"Đã bắt đầu vẽ hình"</string> @@ -745,7 +745,7 @@ <string name="permdesc_readHistoryBookmarks" msgid="4981489815467617191">"Cho phép ứng dụng đọc tất cả các URL mà Trình duyệt đã truy cập và tất cả các dấu trang của Trình duyệt."</string> <string name="permlab_writeHistoryBookmarks" msgid="9009434109836280374">"xem lịch sử và dấu trang của Trình duyệt"</string> <string name="permdesc_writeHistoryBookmarks" product="tablet" msgid="7193514090469945307">"Cho phép ứng dụng sửa đổi lịch sử hoặc dấu trang của Trình duyệt được lưu trữ trên máy tính bảng của bạn. Các ứng dụng độc hại có thể sử dụng quyền này để xóa hoặc sửa đổi dữ liệu Trình duyệt của bạn."</string> - <string name="permdesc_writeHistoryBookmarks" product="default" msgid="945571990357114950">"Cho phép ứng dụng sửa đổi lịch sử hoặc dấu trang của Trình duyệt được lưu trữ trên điện thoại của bạn. Các ứng dụng độc hại có thể sử dụng quyền này để xoá hoặc sửa đổi dữ liệu Trình duyệt của bạn."</string> + <string name="permdesc_writeHistoryBookmarks" product="default" msgid="945571990357114950">"Cho phép ứng dụng sửa đổi lịch sử hoặc dấu trang của Trình duyệt được lưu trữ trên điện thoại của bạn. Các ứng dụng độc hại có thể sử dụng quyền này để xóa hoặc sửa đổi dữ liệu Trình duyệt của bạn."</string> <string name="permlab_setAlarm" msgid="5924401328803615165">"đặt báo thức trong đồng hồ báo thức"</string> <string name="permdesc_setAlarm" msgid="5966966598149875082">"Cho phép ứng dụng đặt báo thức trong ứng dụng đồng hồ báo thức được cài đặt. Một số ứng dụng đồng hồ báo thức có thể không sử dụng tính năng này."</string> <string name="permlab_addVoicemail" msgid="5525660026090959044">"thêm thư thoại"</string> @@ -766,7 +766,7 @@ <string name="prepend_shortcut_label" msgid="2572214461676015642">"Trình đơn+"</string> <string name="menu_space_shortcut_label" msgid="2410328639272162537">"dấu cách"</string> <string name="menu_enter_shortcut_label" msgid="2743362785111309668">"nhập"</string> - <string name="menu_delete_shortcut_label" msgid="3658178007202748164">"xoá"</string> + <string name="menu_delete_shortcut_label" msgid="3658178007202748164">"xóa"</string> <string name="search_go" msgid="8298016669822141719">"Tìm kiếm"</string> <string name="searchview_description_search" msgid="6749826639098512120">"Tìm kiếm"</string> <string name="searchview_description_query" msgid="5911778593125355124">"Truy vấn tìm kiếm"</string> @@ -896,7 +896,7 @@ <string name="capital_off" msgid="6815870386972805832">"TẮT"</string> <string name="whichApplication" msgid="4533185947064773386">"Hoàn tất tác vụ đang sử dụng"</string> <string name="alwaysUse" msgid="4583018368000610438">"Sử dụng theo mặc định đối với tác vụ này."</string> - <string name="clearDefaultHintMsg" msgid="4815455344600932173">"Xoá mặc định trong Cài đặt Màn hình trang chủ > Ứng dụng> Quản lý ứng dụng."</string> + <string name="clearDefaultHintMsg" msgid="4815455344600932173">"Xóa mặc định trong Cài đặt Màn hình trang chủ > Ứng dụng> Quản lý ứng dụng."</string> <string name="chooseActivity" msgid="1009246475582238425">"Chọn tác vụ"</string> <string name="chooseUsbActivity" msgid="7892597146032121735">"Chọn ứng dụng cho thiết bị USB"</string> <string name="noApplications" msgid="1691104391758345586">"Không ứng dụng nào có thể thực hiện tác vụ này."</string> @@ -959,6 +959,9 @@ <item quantity="one" msgid="1634101450343277345">"Mở mạng Wi-Fi khả dụng"</item> <item quantity="other" msgid="7915895323644292768">"Mở mạng Wi-Fi khả dụng"</item> </plurals> + <string name="wifi_available_sign_in" msgid="9157196203958866662">"Đăng nhập vào mạng Wi-Fi"</string> + <!-- no translation found for wifi_available_sign_in_detailed (6797764740339907572) --> + <skip /> <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Không thể kết nối với Wi-Fi"</string> <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" có kết nối internet kém."</string> <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string> @@ -1019,7 +1022,7 @@ <string name="extmedia_format_message" product="default" msgid="3621369962433523619">"Bạn có chắc chắn muốn định dạng thẻ SD không? Tất cả dữ liệu trên thẻ của bạn sẽ bị mất."</string> <string name="extmedia_format_button_format" msgid="4131064560127478695">"Định dạng"</string> <string name="adb_active_notification_title" msgid="6729044778949189918">"Gỡ lỗi USB đã được kết nối"</string> - <string name="adb_active_notification_message" msgid="8470296818270110396">"Chọn để vô hiệu hoá gỡ lỗi USB."</string> + <string name="adb_active_notification_message" msgid="8470296818270110396">"Chọn để vô hiệu hóa gỡ lỗi USB."</string> <string name="select_input_method" msgid="6865512749462072765">"Chọn phương thức nhập"</string> <string name="configure_input_methods" msgid="6324843080254191535">"Định cấu hình phương thức nhập liệu"</string> <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> @@ -1072,7 +1075,7 @@ <string name="permission_request_notification_title" msgid="5390555465778213840">"Yêu cầu Quyền"</string> <string name="permission_request_notification_with_subtitle" msgid="4325409589686688000">"Yêu cầu Quyền"\n"cho tài khoản <xliff:g id="ACCOUNT">%s</xliff:g>"</string> <string name="input_method_binding_label" msgid="1283557179944992649">"Phương thức nhập"</string> - <string name="sync_binding_label" msgid="3687969138375092423">"Đồng bộ hoá"</string> + <string name="sync_binding_label" msgid="3687969138375092423">"Đồng bộ hóa"</string> <string name="accessibility_binding_label" msgid="4148120742096474641">"Khả năng truy cập"</string> <string name="wallpaper_binding_label" msgid="1240087844304687662">"Hình nền"</string> <string name="chooser_wallpaper" msgid="7873476199295190279">"Thay đổi hình nền"</string> @@ -1218,10 +1221,7 @@ <string name="share_action_provider_share_with" msgid="1791316789651185229">"Chia sẻ với..."</string> <string name="status_bar_device_locked" msgid="3092703448690669768">"Thiết bị đã bị khóa."</string> <string name="list_delimeter" msgid="3975117572185494152">", "</string> - <!-- no translation found for sending (8715108995741758718) --> - <skip /> - <!-- no translation found for launchBrowserDefault (2057951947297614725) --> - <skip /> - <!-- no translation found for SetupCallDefault (6870275517518479651) --> - <skip /> + <string name="sending" msgid="8715108995741758718">"Đang gửi..."</string> + <string name="launchBrowserDefault" msgid="2057951947297614725">"Khởi chạy trình duyệt?"</string> + <string name="SetupCallDefault" msgid="6870275517518479651">"Chấp nhận cuộc gọi?"</string> </resources> diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml index b92008fe0b7a..f3ff28fe941a 100644 --- a/core/res/res/values-zh-rCN/strings.xml +++ b/core/res/res/values-zh-rCN/strings.xml @@ -319,7 +319,7 @@ <string name="permlab_receiveBootCompleted" msgid="7776779842866993377">"开机时自动启动"</string> <string name="permdesc_receiveBootCompleted" product="tablet" msgid="7530977064379338199">"允许应用程序在系统完成启动后立即自行启动。这样会延长平板电脑的启动时间,而且如果应用程序一直运行,会降低平板电脑的整体速度。"</string> <string name="permdesc_receiveBootCompleted" product="default" msgid="698336728415008796">"允许应用程序在系统完成启动后即自行启动。这样会延长手机的启动时间,而且如果应用程序一直运行,会降低手机的整体速度。"</string> - <string name="permlab_broadcastSticky" msgid="7919126372606881614">"发送置顶广播"</string> + <string name="permlab_broadcastSticky" msgid="7919126372606881614">"发送持久广播"</string> <string name="permdesc_broadcastSticky" product="tablet" msgid="6322249605930062595">"允许应用程序发送顽固广播,这些广播在结束后仍会保留。恶意应用程序可借此让平板电脑耗用太多内存,从而降低其速度或稳定性。"</string> <string name="permdesc_broadcastSticky" product="default" msgid="1920045289234052219">"允许应用程序发送顽固广播,这些广播在结束后仍会保留。恶意应用程序可能会借此使手机耗用太多内存,从而降低其速度或稳定性。"</string> <string name="permlab_readContacts" msgid="6219652189510218240">"读取联系人数据"</string> @@ -904,9 +904,9 @@ <string name="aerr_application" msgid="932628488013092776">"很抱歉,“<xliff:g id="APPLICATION">%1$s</xliff:g>”已停止运行。"</string> <string name="aerr_process" msgid="4507058997035697579">"抱歉,进程“<xliff:g id="PROCESS">%1$s</xliff:g>”已停止运行。"</string> <string name="anr_title" msgid="4351948481459135709"></string> - <string name="anr_activity_application" msgid="8339738283149696827">"“<xliff:g id="APPLICATION">%2$s</xliff:g>”无响应。"\n\n"要将它关闭吗?"</string> - <string name="anr_activity_process" msgid="7018289416670457797">"活动“<xliff:g id="ACTIVITY">%1$s</xliff:g>”无响应。"\n\n"要将它关闭吗?"</string> - <string name="anr_application_process" msgid="7208175830253210526">"“<xliff:g id="APPLICATION">%1$s</xliff:g>”无响应。要将它关闭吗?"</string> + <string name="anr_activity_application" msgid="8339738283149696827">"<xliff:g id="APPLICATION">%2$s</xliff:g> 无响应。"\n\n"要将它关闭吗?"</string> + <string name="anr_activity_process" msgid="7018289416670457797">"活动 <xliff:g id="ACTIVITY">%1$s</xliff:g> 无响应。"\n\n"要将它关闭吗?"</string> + <string name="anr_application_process" msgid="7208175830253210526">"<xliff:g id="APPLICATION">%1$s</xliff:g> 无响应。要将它关闭吗?"</string> <string name="anr_process" msgid="306819947562555821">"进程 <xliff:g id="PROCESS">%1$s</xliff:g> 无响应。"\n\n"要将它关闭吗?"</string> <string name="force_close" msgid="8346072094521265605">"确定"</string> <string name="report" msgid="4060218260984795706">"报告"</string> @@ -959,6 +959,9 @@ <item quantity="one" msgid="1634101450343277345">"打开可用的 Wi-Fi 网络"</item> <item quantity="other" msgid="7915895323644292768">"打开可用的 Wi-Fi 网络"</item> </plurals> + <string name="wifi_available_sign_in" msgid="9157196203958866662">"连接到 Wi-Fi 网络"</string> + <!-- no translation found for wifi_available_sign_in_detailed (6797764740339907572) --> + <skip /> <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"无法连接到 Wi-Fi"</string> <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" 互联网连接状况不佳。"</string> <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string> @@ -1181,7 +1184,7 @@ <string name="action_bar_home_description" msgid="5293600496601490216">"导航首页"</string> <string name="action_bar_up_description" msgid="2237496562952152589">"向上导航"</string> <string name="action_menu_overflow_description" msgid="2295659037509008453">"更多选项"</string> - <string name="storage_internal" msgid="7556050805474115618">"内存空间"</string> + <string name="storage_internal" msgid="7556050805474115618">"内部存储空间"</string> <string name="storage_sd_card" msgid="8921771478629812343">"SD 卡"</string> <string name="storage_usb" msgid="3017954059538517278">"USB 存储器"</string> <string name="extract_edit_menu_button" msgid="302060189057163906">"编辑..."</string> @@ -1218,10 +1221,7 @@ <string name="share_action_provider_share_with" msgid="1791316789651185229">"分享方式..."</string> <string name="status_bar_device_locked" msgid="3092703448690669768">"设备已锁定。"</string> <string name="list_delimeter" msgid="3975117572185494152">"、 "</string> - <!-- no translation found for sending (8715108995741758718) --> - <skip /> - <!-- no translation found for launchBrowserDefault (2057951947297614725) --> - <skip /> - <!-- no translation found for SetupCallDefault (6870275517518479651) --> - <skip /> + <string name="sending" msgid="8715108995741758718">"正在发送..."</string> + <string name="launchBrowserDefault" msgid="2057951947297614725">"要启动浏览器吗?"</string> + <string name="SetupCallDefault" msgid="6870275517518479651">"要接听电话吗?"</string> </resources> diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml index 80c3ee51900d..335df1345ba9 100644 --- a/core/res/res/values-zh-rTW/strings.xml +++ b/core/res/res/values-zh-rTW/strings.xml @@ -959,6 +959,9 @@ <item quantity="one" msgid="1634101450343277345">"開啟可用 Wi-Fi 網路"</item> <item quantity="other" msgid="7915895323644292768">"開啟可用 Wi-Fi 網路"</item> </plurals> + <string name="wifi_available_sign_in" msgid="9157196203958866662">"登入 WiFi 網路"</string> + <!-- no translation found for wifi_available_sign_in_detailed (6797764740339907572) --> + <skip /> <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"無法連線至 Wi-Fi"</string> <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" 網際網路連線狀況不佳。"</string> <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string> @@ -1218,10 +1221,7 @@ <string name="share_action_provider_share_with" msgid="1791316789651185229">"分享活動..."</string> <string name="status_bar_device_locked" msgid="3092703448690669768">"裝置已鎖定。"</string> <string name="list_delimeter" msgid="3975117572185494152">"、 "</string> - <!-- no translation found for sending (8715108995741758718) --> - <skip /> - <!-- no translation found for launchBrowserDefault (2057951947297614725) --> - <skip /> - <!-- no translation found for SetupCallDefault (6870275517518479651) --> - <skip /> + <string name="sending" msgid="8715108995741758718">"傳送中..."</string> + <string name="launchBrowserDefault" msgid="2057951947297614725">"啟動「瀏覽器」嗎?"</string> + <string name="SetupCallDefault" msgid="6870275517518479651">"接聽電話嗎?"</string> </resources> diff --git a/core/res/res/values-zu/donottranslate-cldr.xml b/core/res/res/values-zu/donottranslate-cldr.xml new file mode 100644 index 000000000000..df578edb8f0d --- /dev/null +++ b/core/res/res/values-zu/donottranslate-cldr.xml @@ -0,0 +1,149 @@ +<?xml version="1.0" encoding="UTF-8"?> +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="month_long_standalone_january">uJanuwari</string> + <string name="month_long_standalone_february">uFebruwari</string> + <string name="month_long_standalone_march">uMashi</string> + <string name="month_long_standalone_april">u-Apreli</string> + <string name="month_long_standalone_may">uMeyi</string> + <string name="month_long_standalone_june">uJuni</string> + <string name="month_long_standalone_july">uJulayi</string> + <string name="month_long_standalone_august">uAgasti</string> + <string name="month_long_standalone_september">uSepthemba</string> + <string name="month_long_standalone_october">u-Okthoba</string> + <string name="month_long_standalone_november">uNovemba</string> + <string name="month_long_standalone_december">uDisemba</string> + + <string name="month_long_january">Januwari</string> + <string name="month_long_february">Februwari</string> + <string name="month_long_march">Mashi</string> + <string name="month_long_april">Apreli</string> + <string name="month_long_may">Meyi</string> + <string name="month_long_june">Juni</string> + <string name="month_long_july">Julayi</string> + <string name="month_long_august">Agasti</string> + <string name="month_long_september">Septhemba</string> + <string name="month_long_october">Okthoba</string> + <string name="month_long_november">Novemba</string> + <string name="month_long_december">Disemba</string> + + <string name="month_medium_january">Jan</string> + <string name="month_medium_february">Feb</string> + <string name="month_medium_march">Mas</string> + <string name="month_medium_april">Apr</string> + <string name="month_medium_may">Mey</string> + <string name="month_medium_june">Jun</string> + <string name="month_medium_july">Jul</string> + <string name="month_medium_august">Aga</string> + <string name="month_medium_september">Sep</string> + <string name="month_medium_october">Okt</string> + <string name="month_medium_november">Nov</string> + <string name="month_medium_december">Dis</string> + + <string name="month_shortest_january">J</string> + <string name="month_shortest_february">F</string> + <string name="month_shortest_march">M</string> + <string name="month_shortest_april">A</string> + <string name="month_shortest_may">M</string> + <string name="month_shortest_june">J</string> + <string name="month_shortest_july">J</string> + <string name="month_shortest_august">A</string> + <string name="month_shortest_september">S</string> + <string name="month_shortest_october">O</string> + <string name="month_shortest_november">N</string> + <string name="month_shortest_december">D</string> + + <string name="day_of_week_long_sunday">Sonto</string> + <string name="day_of_week_long_monday">Msombuluko</string> + <string name="day_of_week_long_tuesday">Lwesibili</string> + <string name="day_of_week_long_wednesday">Lwesithathu</string> + <string name="day_of_week_long_thursday">uLwesine</string> + <string name="day_of_week_long_friday">Lwesihlanu</string> + <string name="day_of_week_long_saturday">Mgqibelo</string> + + <string name="day_of_week_medium_sunday">Son</string> + <string name="day_of_week_medium_monday">Mso</string> + <string name="day_of_week_medium_tuesday">Bil</string> + <string name="day_of_week_medium_wednesday">Tha</string> + <string name="day_of_week_medium_thursday">Sin</string> + <string name="day_of_week_medium_friday">Hla</string> + <string name="day_of_week_medium_saturday">Mgq</string> + + <string name="day_of_week_short_sunday">Son</string> + <string name="day_of_week_short_monday">Mso</string> + <string name="day_of_week_short_tuesday">Bil</string> + <string name="day_of_week_short_wednesday">Tha</string> + <string name="day_of_week_short_thursday">Sin</string> + <string name="day_of_week_short_friday">Hla</string> + <string name="day_of_week_short_saturday">Mgq</string> + + <string name="day_of_week_shortest_sunday">S</string> + <string name="day_of_week_shortest_monday">M</string> + <string name="day_of_week_shortest_tuesday">B</string> + <string name="day_of_week_shortest_wednesday">T</string> + <string name="day_of_week_shortest_thursday">S</string> + <string name="day_of_week_shortest_friday">H</string> + <string name="day_of_week_shortest_saturday">M</string> + + <string name="am">AM</string> + <string name="pm">PM</string> + <string name="yesterday">Yesterday</string> + <string name="today">Today</string> + <string name="tomorrow">Tomorrow</string> + + <string name="hour_minute_24">%-k:%M</string> + <string name="hour_minute_ampm">%-l:%M %p</string> + <string name="hour_minute_cap_ampm">%-l:%M %^p</string> + <string name="twelve_hour_time_format">h:mm a</string> + <string name="twenty_four_hour_time_format">H:mm</string> + <string name="numeric_date">%Y-%m-%d</string> + <string name="numeric_date_format">yyyy-MM-dd</string> + <string name="numeric_date_template">"%s-%s-%s"</string> + <string name="month_day_year">%-e %B %Y</string> + <string name="time_of_day">%-l:%M:%S %p</string> + <string name="date_and_time">%-l:%M:%S %p %-e %b %Y</string> + <string name="date_time">%2$s %1$s</string> + <string name="time_date">%1$s %3$s</string> + <string name="abbrev_month_day_year">%-e %b %Y</string> + <string name="month_day">%B %-e</string> + <string name="month">%-B</string> + <string name="month_year">%Y %B</string> + <string name="abbrev_month_day">%b %-e</string> + <string name="abbrev_month">%-b</string> + <string name="abbrev_month_year">%Y %b</string> + <string name="time1_time2">%1$s – %2$s</string> + <string name="date1_date2">%2$s – %5$s</string> + <string name="numeric_md1_md2">%2$s-%3$s – %7$s-%8$s</string> + <string name="numeric_wday1_md1_wday2_md2">%1$s, %2$s-%3$s – %6$s, %7$s-%8$s</string> + <string name="numeric_mdy1_mdy2">%4$s-%2$s-%3$s – %9$s-%7$s-%8$s</string> + <string name="numeric_wday1_mdy1_wday2_mdy2">%1$s, %4$s-%2$s-%3$s – %6$s, %9$s-%7$s-%8$s</string> + <string name="numeric_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %4$s-%2$s-%3$s – %10$s %6$s, %9$s-%7$s-%8$s</string> + <string name="numeric_md1_time1_md2_time2">%5$s %2$s-%3$s – %10$s %7$s-%8$s</string> + <string name="numeric_wday1_md1_time1_wday2_md2_time2">%5$s %1$s, %2$s-%3$s – %10$s %6$s, %7$s-%8$s</string> + <string name="numeric_mdy1_time1_mdy2_time2">%5$s %4$s-%2$s-%3$s – %10$s %9$s-%7$s-%8$s</string> + <string name="wday1_date1_time1_wday2_date2_time2">%3$s %1$s %2$s – %6$s %4$s %5$s</string> + <string name="wday1_date1_wday2_date2">%1$s %2$s – %4$s %5$s</string> + <string name="date1_time1_date2_time2">%3$s %2$s – %6$s %5$s</string> + <string name="time_wday_date">%1$s %2$s %3$s</string> + <string name="wday_date">%2$s %3$s</string> + <string name="time_wday">%1$s %2$s</string> + <string name="same_year_md1_md2">%2$s %3$s – %7$s %8$s</string> + <string name="same_year_wday1_md1_wday2_md2">%1$s %2$s %3$s – %6$s %7$s %8$s</string> + <string name="same_year_md1_time1_md2_time2">%5$s %2$s %3$s – %10$s %7$s %8$s</string> + <string name="same_month_md1_time1_md2_time2">%5$s %2$s %3$s – %10$s %7$s %8$s</string> + <string name="same_year_wday1_md1_time1_wday2_md2_time2">%5$s %1$s %2$s %3$s – %10$s %6$s %7$s %8$s</string> + <string name="same_month_wday1_md1_time1_wday2_md2_time2">%5$s %1$s %2$s %3$s – %10$s %6$s %7$s %8$s</string> + <string name="same_year_mdy1_time1_mdy2_time2">%5$s %4$s-%2$s-%3$s – %10$s %9$s-%7$s-%8$s</string> + <string name="same_month_mdy1_time1_mdy2_time2">%5$s %4$s-%2$s-%3$s – %10$s %9$s-%7$s-%8$s</string> + <string name="same_year_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %4$s %2$s %3$s – %10$s %6$s, %9$s %7$s %8$s</string> + <string name="same_month_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %4$s %2$s %3$s – %10$s %6$s, %9$s %7$s %8$s</string> + <string name="same_month_wday1_mdy1_wday2_mdy2">%1$s, %4$s %2$s %3$s – %6$s, %9$s %7$s %8$s</string> + <string name="same_month_md1_md2">%2$s-%3$s – %8$s</string> + <string name="same_month_wday1_md1_wday2_md2">%1$s %2$s %3$s – %6$s %7$s %8$s</string> + <string name="same_year_mdy1_mdy2">%9$s-%2$s-%3$s – %7$s-%8$s</string> + <string name="same_month_mdy1_mdy2">%9$s-%2$s-%3$s – %8$s</string> + <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %9$s-%2$s-%3$s – %6$s, yyyy-%7$s-%8$s</string> + <string name="short_format_month">%b</string> + <string name="full_wday_month_day_no_year">E MMMM d</string> + <string name="abbrev_wday_month_day_year">EEE, y MMM d</string> +</resources> diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml index eadb0ea9f25f..e9321a4671cb 100644 --- a/core/res/res/values-zu/strings.xml +++ b/core/res/res/values-zu/strings.xml @@ -73,11 +73,11 @@ <string name="RestrictedOnData" msgid="8653794784690065540">"Insizakalo yedatha ivaliwe."</string> <string name="RestrictedOnEmergency" msgid="6581163779072833665">"Insizakalo ephuthumayo ivimbelwe."</string> <string name="RestrictedOnNormal" msgid="4953867011389750673">"Insizakalo yezwi ivimbelwe."</string> - <string name="RestrictedOnAllVoice" msgid="1459318899842232234">"Zonke izinsizakalo Zezwi zivimbelwe."</string> + <string name="RestrictedOnAllVoice" msgid="1459318899842232234">"Wonke amasevisi Wezwi avimbelwe."</string> <string name="RestrictedOnSms" msgid="8314352327461638897">"Insizakalo ye-SMS ivaliwe."</string> - <string name="RestrictedOnVoiceData" msgid="8244438624660371717">"Izinsizakalo Zezwi/Idatha zivimbelwe."</string> - <string name="RestrictedOnVoiceSms" msgid="1888588152792023873">"Izinsizakalo Zezwi/SMS zivimbelwe."</string> - <string name="RestrictedOnAll" msgid="2714924667937117304">"Zonke izinsizakalo Zezwi/Idatha/SMS zivimbelwe."</string> + <string name="RestrictedOnVoiceData" msgid="8244438624660371717">"Amasevisi Wezwi/Idatha avimbelwe."</string> + <string name="RestrictedOnVoiceSms" msgid="1888588152792023873">"Amasevisi Wezwi/SMS avimbelwe."</string> + <string name="RestrictedOnAll" msgid="2714924667937117304">"Wonke amasevisi Wezwi/Idatha/SMS avimbelwe."</string> <string name="serviceClassVoice" msgid="1258393812335258019">"Izwi"</string> <string name="serviceClassData" msgid="872456782077937893">"Idatha"</string> <string name="serviceClassFAX" msgid="5566624998840486475">"Ifeksi"</string> @@ -99,7 +99,7 @@ <string name="roamingText10" msgid="3992906999815316417">"Iyazulazula - Isici Sensizakalo Eyingxenye"</string> <string name="roamingText11" msgid="4154476854426920970">"Ibhena Yokuzulazula Ivuliwe"</string> <string name="roamingText12" msgid="1189071119992726320">"Ibhena yokuzulazula ivaliwe"</string> - <string name="roamingTextSearching" msgid="8360141885972279963">"Iseshela Izinsizakalo"</string> + <string name="roamingTextSearching" msgid="8360141885972279963">"Iseshela Isevisi"</string> <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Akudlulisiwe"</string> <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string> <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> emuva kwamasekhondi angu-<xliff:g id="TIME_DELAY">{2}</xliff:g>"</string> @@ -463,7 +463,7 @@ <string name="permlab_changeWifiState" msgid="7280632711057112137">"shintsha isimo se-WiFi"</string> <string name="permdesc_changeWifiState" msgid="2950383153656873267">"Ivumela uhlelo lokusebena ukuxhuma futhi ingaxhumeki kumaphoyinti e-Wi-Fi, nokwenza izinguquko kumanethiwekhi e-Wi-Fi amisiwe."</string> <string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"ivumela isamukeli se-Wi-Fi Multicast"</string> - <string name="permdesc_changeWifiMulticastState" msgid="8199464507656067553">"Ivumela uhlelo lokusebenza ukuthola amaphakhethe ngokungaqondile angeyona awedivaysi yakho. Lokhu kungaba usizo lapho uthola izinsizakalo ezinikezwa eduze. Kusebenzisa amandla amaninigi kunemodi yokungajikijeli okuningi."</string> + <string name="permdesc_changeWifiMulticastState" msgid="8199464507656067553">"Ivumela uhlelo lokusebenza ukuthola amaphakhethe ngokungaqondile angeyona awedivaysi yakho. Lokhu kungaba usizo lapho uthola amasevisi anikezwa eduze. Kusebenzisa amandla amaninigi kunemodi yokungajikijeli okuningi."</string> <string name="permlab_accessWimaxState" msgid="2800410363171809280">"Buka isimo se-WiMAX"</string> <string name="permdesc_accessWimaxState" msgid="8298035866227524023">"Ivumela uhlelo lokusebenza ukubuka ulwazi mayelana nesimo se-WiMAX."</string> <string name="permlab_changeWimaxState" msgid="340465839241528618">"shintsha isimo se-WiMAX"</string> @@ -504,7 +504,7 @@ <string name="permdesc_use_sip" msgid="6320376185606661843">"Ivumela uhlelo lokusebenza ukusebenzisa insizakalo ye-SIP ukwenza/ukuthola amakholi e-Inthanethi."</string> <string name="permlab_readNetworkUsageHistory" msgid="7862593283611493232">"funda ukusetshenziswa komlando wohleloxhumano"</string> <string name="permdesc_readNetworkUsageHistory" msgid="6040738474779135653">"Ivumela uhlelo lokusebenza ukufunda umlando wokusebenza kohleloxhumano kwezinhleloxhumano eziqondile nezinhlelo zokusebenza."</string> - <string name="permlab_manageNetworkPolicy" msgid="2562053592339859990">"phatha uhleloxhumano lwenqubomgomo"</string> + <string name="permlab_manageNetworkPolicy" msgid="2562053592339859990">"phatha inqubomgomo yenethiwekhi"</string> <string name="permdesc_manageNetworkPolicy" msgid="3723795285132803958">"Ivumela uhlelo lokusebenza ukuthi liphathe amapholisi wohleloxhumano kanye nokuchaza imithetho eqondile yohlelo lokusebenza."</string> <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"lungisa ukubala kokusebenza kohleloxhumano"</string> <string name="permdesc_modifyNetworkAccounting" msgid="8702285686629184404">"Ivumela ukulungisa kokuthi ukusebenza kohleloxhumano aluvumelwe kuhlelo lokusebenza. Ayisetshenziswa izinhlelo zokusebenza ezivamile."</string> @@ -698,7 +698,7 @@ <string name="lockscreen_glogin_instructions" msgid="1816635201812207709">"Ukuvula, ngena ngemvumekwi-akhawunti ye-Google"</string> <string name="lockscreen_glogin_username_hint" msgid="8846881424106484447">"Igama lomsebenzisi (i-imeyli)"</string> <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"Iphasiwedi"</string> - <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Ngena ngemvume"</string> + <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Ngena"</string> <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"Igama lomsebezisi elingalungile noma iphasiwedi."</string> <string name="lockscreen_glogin_account_recovery_hint" msgid="8253152905532900548">"Ukhohlwe igama lomsebenzisi noma iphasiwedi?"\n"Vakashela"<b>"google.com/accounts/recovery"</b></string> <string name="lockscreen_glogin_checking_password" msgid="6758890536332363322">"Iyahlola..."</string> @@ -768,8 +768,8 @@ <string name="menu_enter_shortcut_label" msgid="2743362785111309668">"faka"</string> <string name="menu_delete_shortcut_label" msgid="3658178007202748164">"susa"</string> <string name="search_go" msgid="8298016669822141719">"Sesha"</string> - <string name="searchview_description_search" msgid="6749826639098512120">"Cinga"</string> - <string name="searchview_description_query" msgid="5911778593125355124">"Cinga umbuzo"</string> + <string name="searchview_description_search" msgid="6749826639098512120">"Sesha"</string> + <string name="searchview_description_query" msgid="5911778593125355124">"Umbuzo wosesho"</string> <string name="searchview_description_clear" msgid="1330281990951833033">"xazulula umbuzo"</string> <string name="searchview_description_submit" msgid="2688450133297983542">"Thumela umbuzo"</string> <string name="searchview_description_voice" msgid="2453203695674994440">"Ukusesha ngezwi"</string> @@ -852,7 +852,7 @@ <string name="hour" msgid="2126771916426189481">"ihora"</string> <string name="hours" msgid="894424005266852993">"amahora"</string> <string name="minute" msgid="9148878657703769868">"Okuncane"</string> - <string name="minutes" msgid="5646001005827034509">"imizuzu"</string> + <string name="minutes" msgid="5646001005827034509">"amaminithi"</string> <string name="second" msgid="3184235808021478">"isekhondi"</string> <string name="seconds" msgid="3161515347216589235">"amasekhondi"</string> <string name="week" msgid="5617961537173061583">"iviki"</string> @@ -959,6 +959,9 @@ <item quantity="one" msgid="1634101450343277345">"Vula inethiwekhi ye-Wi-Fi etholakalayo"</item> <item quantity="other" msgid="7915895323644292768">"Vula amanethiwekhi we-Wi-Fi atholakalayo"</item> </plurals> + <string name="wifi_available_sign_in" msgid="9157196203958866662">"Ngena ngemvume kunethiwekhi ye-Wi-Fi"</string> + <!-- no translation found for wifi_available_sign_in_detailed (6797764740339907572) --> + <skip /> <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Ayikwazanga ukuxhuma kwi-Wi-Fi"</string> <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" inoxhumano oluphansi lwe-inthanethi."</string> <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"I-WiFi Eqondile"</string> @@ -968,7 +971,7 @@ <string name="wifi_p2p_pin_go_negotiation_request_message" msgid="5177412094633377308">"Isethaphu yoheloxhumano oluqondile lwe-WiFi lwesicelo kusuka ku <xliff:g id="P2P_DEVICE_ADDRESS">%1$s</xliff:g>. Faka i-pin ukuze uqhubeke"</string> <string name="wifi_p2p_pin_display_message" msgid="2834049169114922902">"i-pin ye-WPS <xliff:g id="P2P_WPS_PIN">%1$s</xliff:g> idinga ukufakiwa kudivayisi ye-peer <xliff:g id="P2P_CLIENT_ADDRESS">%2$s</xliff:g> ukuze isethaphu yohleloxhumano iqhubeke"</string> <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"I-Wi-Fi Direct ivulekile"</string> - <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Thinta ze uthole izisetho"</string> + <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Thinta ukuze uthole izilungiselelo"</string> <string name="select_character" msgid="3365550120617701745">"Faka uhlamvu"</string> <string name="sms_control_default_app_name" msgid="7630529934366549163">"Uhlelo lokusebenza olungaziwa"</string> <string name="sms_control_title" msgid="7296612781128917719">"Ithumela imiyalezo ye-SMS"</string> @@ -976,7 +979,7 @@ <string name="sms_control_yes" msgid="2532062172402615953">"KULUNGILE"</string> <string name="sms_control_no" msgid="1715320703137199869">"Khansela"</string> <string name="sim_removed_title" msgid="6227712319223226185">"Ikhadi le-SIM likhishiwe"</string> - <string name="sim_removed_message" msgid="2333164559970958645">"Uhleloxhumano lweselula aluzutholakala kuwena kuze kube uqala kabusha ufake i-SIM card efanele."</string> + <string name="sim_removed_message" msgid="2333164559970958645">"Inethiwekhi yeselula ngeke itholakale kuwena kuze kube uqala kabusha ufake ikhadi le-SIM elifanele."</string> <string name="sim_done_button" msgid="827949989369963775">"Kwenziwe"</string> <string name="sim_added_title" msgid="3719670512889674693">"Ikhadi le-SIM lengeziwe"</string> <string name="sim_added_message" msgid="1209265974048554242">"Kufanele uqalise kabusha idivaysi yakho ukuze ungene kuhleloxhumano yeselula."</string> @@ -1078,8 +1081,8 @@ <string name="chooser_wallpaper" msgid="7873476199295190279">"Shintsha iphephadonga"</string> <string name="vpn_title" msgid="8219003246858087489">"i-VPN ivuselelwe"</string> <string name="vpn_title_long" msgid="6400714798049252294">"i-VPN ivuswe ngu <xliff:g id="APP">%s</xliff:g>"</string> - <string name="vpn_text" msgid="1610714069627824309">"Thepha ukuphatha uhleloxhumano."</string> - <string name="vpn_text_long" msgid="4907843483284977618">"Ixhume ku-<xliff:g id="SESSION">%s</xliff:g>. Thepha ukuphatha uhleloxhumano."</string> + <string name="vpn_text" msgid="1610714069627824309">"Thepha ukuphatha inethiwekhi."</string> + <string name="vpn_text_long" msgid="4907843483284977618">"Ixhume ku-<xliff:g id="SESSION">%s</xliff:g>. Thepha ukuphatha inethiwekhi."</string> <string name="upload_file" msgid="2897957172366730416">"Khetha ifayela"</string> <string name="no_file_chosen" msgid="6363648562170759465">"Ayikho ifayela ekhethiwe"</string> <string name="reset" msgid="2448168080964209908">"Setha kabusha"</string> diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index d0ab8b116d06..af59198fcef1 100755 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -1493,6 +1493,10 @@ <enum name="KEYCODE_LANGUAGE_SWITCH" value="204" /> <enum name="KEYCODE_MANNER_MODE" value="205" /> <enum name="KEYCODE_3D_MODE" value="206" /> + <enum name="KEYCODE_CONTACTS" value="207" /> + <enum name="KEYCODE_CALENDAR" value="208" /> + <enum name="KEYCODE_MUSIC" value="209" /> + <enum name="KEYCODE_CALCULATOR" value="210" /> </attr> <!-- ***************************************************************** --> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 25f7d2565c92..30002c540cc6 100755 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -742,6 +742,7 @@ <!-- Name of the wimax state tracker clas --> <string name="config_wimaxStateTrackerClassname"></string> - <!-- Name of screensaver components to look for if none has been chosen by the user --> - <string name="config_defaultDreamComponent">com.google.android.deskclock/com.android.deskclock.Screensaver</string> + <!-- Base "touch slop" value used by ViewConfiguration as a + movement threshold where scrolling should begin. --> + <dimen name="config_viewConfigurationTouchSlop">8dp</dimen> </resources> diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index c8ba26a336a7..7b785ec5d9e8 100755 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -1,4 +1,4 @@ -<?xml version="1.0" encoding="utf-8"?> +<?xml version="1.0" encoding="utf-8"?> <!-- /* //device/apps/common/assets/res/any/strings.xml ** @@ -286,6 +286,12 @@ <string name="screen_lock">Screen lock</string> <!-- Button to turn off the phone, within the Phone Options dialog --> <string name="power_off">Power off</string> + <!-- Spoken description for ringer silent option. [CHAR LIMIT=NONE] --> + <string name="silent_mode_silent">Ringer off</string> + <!-- Spoken description for ringer vibrate option. [CHAR LIMIT=NONE] --> + <string name="silent_mode_vibrate">Ringer vibrate</string> + <!-- Spoken description for ringer normal option. [CHAR LIMIT=NONE] --> + <string name="silent_mode_ring">Ringer on</string> <!-- Shutdown Progress Dialog. This is shown if the user chooses to power off the phone. --> <string name="shutdown_progress">Shutting down\u2026</string> @@ -2721,6 +2727,12 @@ <item quantity="other">Open Wi-Fi networks available</item> </plurals> + <!-- A notification is shown when a captive portal network is detected. This is the notification's title. --> + <string name="wifi_available_sign_in">Sign in to Wi-Fi network</string> + + <!-- A notification is shown when a captive portal network is detected. This is the notification's message. --> + <string name="wifi_available_sign_in_detailed"><xliff:g id="wifi_network_ssid">%1$s</xliff:g></string> + <!-- A notification is shown when a user's selected SSID is later disabled due to connectivity problems. This is the notification's title / ticker. --> <string name="wifi_watchdog_network_disabled">Couldn\'t connect to Wi-Fi</string> <!-- A notification is shown when a user's selected SSID is later disabled due to connectivity problems. The complete alert msg is: <hotspot name> + this string, i.e. "Linksys has a poor internet connection" --> diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml index b18d88f69a9a..fe5388bdcd83 100644 --- a/core/res/res/values/themes.xml +++ b/core/res/res/values/themes.xml @@ -810,7 +810,7 @@ please see themes_device_defaults.xml. <!-- Special theme for the recent apps dialog, to allow customization with overlays. --> - <style name="Theme.Dialog.RecentApplications"> + <style name="Theme.Dialog.RecentApplications" parent="Theme.DeviceDefault.Dialog"> <item name="windowFrame">@null</item> <item name="windowBackground">@android:color/transparent</item> <item name="android:windowAnimationStyle">@android:style/Animation.RecentApplications</item> diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerStressTestRunner.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerStressTestRunner.java index d23dfd32705a..3ffa085ae0b7 100644 --- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerStressTestRunner.java +++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerStressTestRunner.java @@ -38,7 +38,8 @@ public class ConnectivityManagerStressTestRunner extends InstrumentationTestRunn public int mSoftapIterations = 100; public int mScanIterations = 100; public int mReconnectIterations = 100; - public int mSleepTime = 30 * 1000; // default sleep time is 30 seconds + // sleep time before restart wifi, default is set to 2 minutes + public int mSleepTime = 2 * 60 * 1000; public String mReconnectSsid = "securenetdhcp"; public String mReconnectPassword = "androidwifi"; diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestActivity.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestActivity.java index adf1883c8a5e..0580ebcd5a75 100644 --- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestActivity.java +++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestActivity.java @@ -62,6 +62,8 @@ public class ConnectivityManagerTestActivity extends Activity { public static final int WIFI_SCAN_TIMEOUT = 50 * 1000; public static final int SHORT_TIMEOUT = 5 * 1000; public static final long LONG_TIMEOUT = 50 * 1000; + // 2 minutes timer between wifi stop and start + public static final long WIFI_STOP_START_INTERVAL = 2 * 60 * 1000; public static final int SUCCESS = 0; // for Wifi tethering state change public static final int FAILURE = 1; public static final int INIT = -1; @@ -247,6 +249,8 @@ public class ConnectivityManagerTestActivity extends Activity { sleep(SHORT_TIMEOUT); removeConfiguredNetworksAndDisableWifi(); mWifiRegexs = mCM.getTetherableWifiRegexs(); + // after wifi is shutdown, wait for 2 minute to enable wifi + sleep(WIFI_STOP_START_INTERVAL); } public List<WifiConfiguration> loadNetworkConfigurations() throws Exception { diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/NetworkState.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/NetworkState.java index d586396dc19b..5a4a2d0ba8d3 100644 --- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/NetworkState.java +++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/NetworkState.java @@ -77,10 +77,13 @@ public class NetworkState { mReason = "no state is recorded."; return false; } else if (mStateDepository.size() > 1) { - Log.v(LOG_TAG, "no broadcast is expected, " + - "instead broadcast is probably received"); - mReason = "no broadcast is expected, instead broadcast is probably received"; - return false; + for (int i = 0; i < mStateDepository.size(); i++) { + if (mStateDepository.get(i) != mTransitionTarget) { + Log.v(LOG_TAG, "state changed."); + mReason = "Unexpected state change"; + return false; + } + } } else if (mStateDepository.get(0) != mTransitionTarget) { Log.v(LOG_TAG, mTransitionTarget + " is expected, but it is " + mStateDepository.get(0)); diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java index d9b770a384b5..b1f4bf122a4f 100644 --- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java +++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java @@ -66,7 +66,7 @@ public class ConnectivityManagerMobileTest // Each test case will start with cellular connection if (Settings.System.getInt(getInstrumentation().getContext().getContentResolver(), Settings.System.AIRPLANE_MODE_ON) == 1) { - Log.v(LOG_TAG, "airplane is not disabled, disable it."); + log("airplane is not disabled, disable it."); cmActivity.setAirplaneMode(getInstrumentation().getContext(), false); } if (!UtilHelper.isWifiOnly()) { @@ -84,13 +84,13 @@ public class ConnectivityManagerMobileTest @Override public void tearDown() throws Exception { cmActivity.finish(); - Log.v(LOG_TAG, "tear down ConnectivityManagerTestActivity"); + log("tear down ConnectivityManagerTestActivity"); wl.release(); cmActivity.removeConfiguredNetworksAndDisableWifi(); // if airplane mode is set, disable it. if (Settings.System.getInt(getInstrumentation().getContext().getContentResolver(), Settings.System.AIRPLANE_MODE_ON) == 1) { - Log.v(LOG_TAG, "disable airplane mode if it is enabled"); + log("disable airplane mode if it is enabled"); cmActivity.setAirplaneMode(getInstrumentation().getContext(), false); } super.tearDown(); @@ -104,17 +104,24 @@ public class ConnectivityManagerMobileTest assertTrue("not connected to cellular network", extraNetInfo.isConnected()); } + private void log(String message) { + Log.v(LOG_TAG, message); + } + + private void sleep(long sleeptime) { + try { + Thread.sleep(sleeptime); + } catch (InterruptedException e) {} + } + // Test case 1: Test enabling Wifi without associating with any AP, no broadcast on network // event should be expected. @LargeTest public void test3GToWifiNotification() { // Enable Wi-Fi to avoid initial UNKNOWN state cmActivity.enableWifi(); - try { - Thread.sleep(2 * ConnectivityManagerTestActivity.SHORT_TIMEOUT); - } catch (Exception e) { - Log.v(LOG_TAG, "exception: " + e.toString()); - } + sleep(2 * ConnectivityManagerTestActivity.SHORT_TIMEOUT); + // Wi-Fi is disabled cmActivity.disableWifi(); @@ -123,11 +130,8 @@ public class ConnectivityManagerMobileTest assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_MOBILE, State.CONNECTED, ConnectivityManagerTestActivity.LONG_TIMEOUT)); // Wait for 10 seconds for broadcasts to be sent out - try { - Thread.sleep(10 * 1000); - } catch (Exception e) { - fail("thread in sleep is interrupted."); - } + sleep(10 * 1000); + // As Wifi stays in DISCONNETED, Mobile statys in CONNECTED, // the connectivity manager will not broadcast any network connectivity event for Wifi NetworkInfo networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE); @@ -138,22 +142,18 @@ public class ConnectivityManagerMobileTest NetworkState.DO_NOTHING, State.DISCONNECTED); // Eanble Wifi without associating with any AP cmActivity.enableWifi(); - try { - Thread.sleep(2 * ConnectivityManagerTestActivity.SHORT_TIMEOUT); - } catch (Exception e) { - Log.v(LOG_TAG, "exception: " + e.toString()); - } + sleep(2 * ConnectivityManagerTestActivity.SHORT_TIMEOUT); // validate state and broadcast if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_WIFI)) { - Log.v(LOG_TAG, "the state for WIFI is changed"); - Log.v(LOG_TAG, "reason: " + + log("the state for WIFI is changed"); + log("reason: " + cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_WIFI)); assertTrue("state validation fail", false); } if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_MOBILE)) { - Log.v(LOG_TAG, "the state for MOBILE is changed"); - Log.v(LOG_TAG, "reason: " + + log("the state for MOBILE is changed"); + log("reason: " + cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_MOBILE)); assertTrue("state validation fail", false); } @@ -182,7 +182,7 @@ public class ConnectivityManagerMobileTest assertTrue(cmActivity.waitForWifiState(WifiManager.WIFI_STATE_ENABLED, ConnectivityManagerTestActivity.LONG_TIMEOUT)); - Log.v(LOG_TAG, "wifi state is enabled"); + log("wifi state is enabled"); assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED, ConnectivityManagerTestActivity.LONG_TIMEOUT)); if (!UtilHelper.isWifiOnly()) { @@ -192,15 +192,15 @@ public class ConnectivityManagerMobileTest // validate states if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_WIFI)) { - Log.v(LOG_TAG, "Wifi state transition validation failed."); - Log.v(LOG_TAG, "reason: " + + log("Wifi state transition validation failed."); + log("reason: " + cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_WIFI)); assertTrue(false); } if (!UtilHelper.isWifiOnly()) { if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_MOBILE)) { - Log.v(LOG_TAG, "Mobile state transition validation failed."); - Log.v(LOG_TAG, "reason: " + + log("Mobile state transition validation failed."); + log("reason: " + cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_MOBILE)); assertTrue(false); } @@ -219,16 +219,11 @@ public class ConnectivityManagerMobileTest assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED, ConnectivityManagerTestActivity.LONG_TIMEOUT)); - try { - Thread.sleep(ConnectivityManagerTestActivity.SHORT_TIMEOUT); - } catch (Exception e) { - Log.v(LOG_TAG, "exception: " + e.toString()); - } - + sleep(ConnectivityManagerTestActivity.SHORT_TIMEOUT); // Disable Wifi - Log.v(LOG_TAG, "Disable Wifi"); + log("Disable Wifi"); if (!cmActivity.disableWifi()) { - Log.v(LOG_TAG, "disable Wifi failed"); + log("disable Wifi failed"); return; } @@ -254,8 +249,10 @@ public class ConnectivityManagerMobileTest cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_WIFI, networkInfo.getState(), NetworkState.TO_CONNECTION, State.CONNECTED); + // wait for 2 minutes before restart wifi + sleep(ConnectivityManagerTestActivity.WIFI_STOP_START_INTERVAL); // Enable Wifi again - Log.v(LOG_TAG, "Enable Wifi again"); + log("Enable Wifi again"); cmActivity.enableWifi(); // Wait for Wifi to be connected and mobile to be disconnected @@ -268,8 +265,8 @@ public class ConnectivityManagerMobileTest // validate wifi states if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_WIFI)) { - Log.v(LOG_TAG, "Wifi state transition validation failed."); - Log.v(LOG_TAG, "reason: " + + log("Wifi state transition validation failed."); + log("reason: " + cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_WIFI)); assertTrue(false); } @@ -288,11 +285,7 @@ public class ConnectivityManagerMobileTest ConnectivityManagerTestActivity.LONG_TIMEOUT)); // Wait for a few seconds to avoid the state that both Mobile and Wifi is connected - try { - Thread.sleep(ConnectivityManagerTestActivity.SHORT_TIMEOUT); - } catch (Exception e) { - Log.v(LOG_TAG, "exception: " + e.toString()); - } + sleep(ConnectivityManagerTestActivity.SHORT_TIMEOUT); NetworkInfo networkInfo; if (!UtilHelper.isWifiOnly()) { @@ -318,15 +311,15 @@ public class ConnectivityManagerMobileTest // validate states if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_WIFI)) { - Log.v(LOG_TAG, "Wifi state transition validation failed."); - Log.v(LOG_TAG, "reason: " + + log("Wifi state transition validation failed."); + log("reason: " + cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_WIFI)); assertTrue(false); } if (!UtilHelper.isWifiOnly()) { if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_MOBILE)) { - Log.v(LOG_TAG, "Mobile state transition validation failed."); - Log.v(LOG_TAG, "reason: " + + log("Mobile state transition validation failed."); + log("reason: " + cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_MOBILE)); assertTrue(false); } @@ -346,19 +339,16 @@ public class ConnectivityManagerMobileTest assertEquals(State.DISCONNECTED, networkInfo.getState()); // Enable airplane mode + log("Enable airplane mode"); cmActivity.setAirplaneMode(getInstrumentation().getContext(), true); - try { - Thread.sleep(ConnectivityManagerTestActivity.SHORT_TIMEOUT); - } catch (Exception e) { - Log.v(LOG_TAG, "exception: " + e.toString()); - } + sleep(ConnectivityManagerTestActivity.SHORT_TIMEOUT); networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI); assertEquals(State.DISCONNECTED, networkInfo.getState()); if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_MOBILE)) { - Log.v(LOG_TAG, "Mobile state transition validation failed."); - Log.v(LOG_TAG, "reason: " + + log("Mobile state transition validation failed."); + log("reason: " + cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_MOBILE)); assertTrue(false); } @@ -381,14 +371,14 @@ public class ConnectivityManagerMobileTest // Validate the state transition if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_MOBILE)) { - Log.v(LOG_TAG, "Mobile state transition validation failed."); - Log.v(LOG_TAG, "reason: " + + log("Mobile state transition validation failed."); + log("reason: " + cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_MOBILE)); assertTrue(false); } if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_WIFI)) { - Log.v(LOG_TAG, "Wifi state transition validation failed."); - Log.v(LOG_TAG, "reason: " + + log("Wifi state transition validation failed."); + log("reason: " + cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_WIFI)); assertTrue(false); } @@ -399,6 +389,7 @@ public class ConnectivityManagerMobileTest public void testDataConnectionOverAMWithWifi() { assertNotNull("SSID is null", TEST_ACCESS_POINT); // Eanble airplane mode + log("Enable airplane mode"); cmActivity.setAirplaneMode(getInstrumentation().getContext(), true); NetworkInfo networkInfo; @@ -423,15 +414,15 @@ public class ConnectivityManagerMobileTest // validate state and broadcast if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_WIFI)) { - Log.v(LOG_TAG, "state validate for Wifi failed"); - Log.v(LOG_TAG, "reason: " + + log("state validate for Wifi failed"); + log("reason: " + cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_WIFI)); assertTrue("State validation failed", false); } if (!UtilHelper.isWifiOnly()) { if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_MOBILE)) { - Log.v(LOG_TAG, "state validation for Mobile failed"); - Log.v(LOG_TAG, "reason: " + + log("state validation for Mobile failed"); + log("reason: " + cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_MOBILE)); assertTrue("state validation failed", false); } @@ -454,7 +445,7 @@ public class ConnectivityManagerMobileTest try { Thread.sleep(ConnectivityManagerTestActivity.SHORT_TIMEOUT); } catch (Exception e) { - Log.v(LOG_TAG, "exception: " + e.toString()); + log("exception: " + e.toString()); } // Enable airplane mode without clearing Wifi @@ -466,7 +457,7 @@ public class ConnectivityManagerMobileTest try { Thread.sleep(ConnectivityManagerTestActivity.SHORT_TIMEOUT); } catch (Exception e) { - Log.v(LOG_TAG, "exception: " + e.toString()); + log("exception: " + e.toString()); } // Prepare for state validation @@ -487,8 +478,8 @@ public class ConnectivityManagerMobileTest // validate the state transition if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_WIFI)) { - Log.v(LOG_TAG, "Wifi state transition validation failed."); - Log.v(LOG_TAG, "reason: " + + log("Wifi state transition validation failed."); + log("reason: " + cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_WIFI)); assertTrue(false); } @@ -511,13 +502,13 @@ public class ConnectivityManagerMobileTest try { Thread.sleep(ConnectivityManagerTestActivity.SHORT_TIMEOUT); } catch (Exception e) { - Log.v(LOG_TAG, "exception: " + e.toString()); + log("exception: " + e.toString()); } // Disconnect from the current AP - Log.v(LOG_TAG, "disconnect from the AP"); + log("disconnect from the AP"); if (!cmActivity.disconnectAP()) { - Log.v(LOG_TAG, "failed to disconnect from " + TEST_ACCESS_POINT); + log("failed to disconnect from " + TEST_ACCESS_POINT); } // Verify the connectivity state for Wifi is DISCONNECTED @@ -525,7 +516,7 @@ public class ConnectivityManagerMobileTest ConnectivityManagerTestActivity.LONG_TIMEOUT)); if (!cmActivity.disableWifi()) { - Log.v(LOG_TAG, "disable Wifi failed"); + log("disable Wifi failed"); return; } assertTrue(cmActivity.waitForWifiState(WifiManager.WIFI_STATE_DISABLED, diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiConnectionTest.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiConnectionTest.java index 22b17597bc24..d33a445e244c 100644 --- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiConnectionTest.java +++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiConnectionTest.java @@ -136,7 +136,7 @@ public class WifiConnectionTest // step 2: verify Wifi state and network state; assertTrue(mAct.waitForNetworkState(ConnectivityManager.TYPE_WIFI, - State.CONNECTED, 2 * ConnectivityManagerTestActivity.LONG_TIMEOUT)); + State.CONNECTED, 6 * ConnectivityManagerTestActivity.LONG_TIMEOUT)); // step 3: verify the current connected network is the given SSID assertNotNull("Wifi connection returns null", mAct.mWifiManager.getConnectionInfo()); @@ -166,8 +166,9 @@ public class WifiConnectionTest String ssid = networks.get(i).SSID; log("-- START Wi-Fi connection test to : " + ssid + " --"); connectToWifi(networks.get(i)); - sleep(2 * ConnectivityManagerTestActivity.SHORT_TIMEOUT, - "interruped while waiting for wifi disabled."); + // wait for 2 minutes between wifi stop and start + sleep(ConnectivityManagerTestActivity.WIFI_STOP_START_INTERVAL, + "interruped while connected to wifi"); log("-- END Wi-Fi connection test to " + ssid + " -- "); } } diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java index 7578e675b4eb..2069789c37c6 100644 --- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java +++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java @@ -63,10 +63,12 @@ public class WifiStressTest private final static long WIFI_IDLE_MS = 60 * 1000; /** - * The delay for Wi-Fi to get into idle, after screen off + WIFI_IDEL_MS + WIFI_IDLE_DELAY - * the Wi-Fi should be in idle mode and device should be in cellular mode. + * Delay after issuing wifi shutdown. + * The framework keep driver up for at leat 2 minutes to avoid problems + * that a quick shutdown could cause on wext driver and protentially + * on cfg based driver */ - private final static long WIFI_IDLE_DELAY = 3 * 1000; + private final static long WIFI_SHUTDOWN_DELAY = 2 * 60 * 1000; private final static String OUTPUT_FILE = "WifiStressTestOutput.txt"; private ConnectivityManagerTestActivity mAct; @@ -92,6 +94,9 @@ public class WifiStressTest mPassword = mRunner.mReconnectPassword; mScanIterations = mRunner.mScanIterations; mWifiSleepTime = mRunner.mSleepTime; + log(String.format("mReconnectIterations(%d), mSsid(%s), mPassword(%s)," + + "mScanIterations(%d), mWifiSleepTime(%d)", mReconnectIterations, mSsid, + mPassword, mScanIterations, mWifiSleepTime)); mOutputWriter = new BufferedWriter(new FileWriter(new File( Environment.getExternalStorageDirectory(), OUTPUT_FILE), true)); mAct.turnScreenOn(); @@ -248,6 +253,7 @@ public class WifiStressTest assertTrue("Wi-Fi is connected, but no data connection.", mAct.pingTest(null)); int i; + long sum = 0; for (i = 0; i < mReconnectIterations; i++) { // 1. Put device into sleep mode // 2. Wait for the device to sleep for sometime, verify wi-fi is off and mobile is on. @@ -261,7 +267,7 @@ public class WifiStressTest PowerManager pm = (PowerManager)mRunner.getContext().getSystemService(Context.POWER_SERVICE); assertFalse(pm.isScreenOn()); - sleep(WIFI_IDLE_MS, "Interruped while wait for wifi to be idle"); + sleep(WIFI_IDLE_MS + WIFI_SHUTDOWN_DELAY, "Interruped while wait for wifi to be idle"); assertTrue("Wait for Wi-Fi to idle timeout", mAct.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.DISCONNECTED, 6 * ConnectivityManagerTestActivity.SHORT_TIMEOUT)); @@ -269,9 +275,9 @@ public class WifiStressTest // use long timeout as the pppd startup may take several retries. assertTrue("Wait for cellular connection timeout", mAct.waitForNetworkState(ConnectivityManager.TYPE_MOBILE, State.CONNECTED, - ConnectivityManagerTestActivity.LONG_TIMEOUT)); + 2 * ConnectivityManagerTestActivity.LONG_TIMEOUT)); } - sleep(mWifiSleepTime + WIFI_IDLE_DELAY, "Interrupted while device is in sleep mode"); + sleep(mWifiSleepTime, "Interrupted while device is in sleep mode"); // Verify the wi-fi is still off and data connection is on assertEquals("Wi-Fi is reconnected", State.DISCONNECTED, mAct.mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI).getState()); @@ -284,12 +290,18 @@ public class WifiStressTest // Turn screen on again mAct.turnScreenOn(); + // Measure the time for Wi-Fi to get connected + long startTime = System.currentTimeMillis(); assertTrue("Wait for Wi-Fi enable timeout after wake up", mAct.waitForWifiState(WifiManager.WIFI_STATE_ENABLED, ConnectivityManagerTestActivity.SHORT_TIMEOUT)); assertTrue("Wait for Wi-Fi connection timeout after wake up", mAct.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED, - ConnectivityManagerTestActivity.LONG_TIMEOUT)); + 6 * ConnectivityManagerTestActivity.LONG_TIMEOUT)); + long connectionTime = System.currentTimeMillis() - startTime; + sum += connectionTime; + log("average reconnection time is: " + sum/(i+1)); + assertTrue("Reconnect to Wi-Fi network, but no data connection.", mAct.pingTest(null)); } if (i == mReconnectIterations) { diff --git a/core/tests/bluetoothtests/AndroidManifest.xml b/core/tests/bluetoothtests/AndroidManifest.xml index 58f158ce410f..60b6dc18f0c4 100644 --- a/core/tests/bluetoothtests/AndroidManifest.xml +++ b/core/tests/bluetoothtests/AndroidManifest.xml @@ -19,6 +19,8 @@ <uses-permission android:name="android.permission.BLUETOOTH" /> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /> + <uses-permission android:name="android.permission.BROADCAST_STICKY" /> + <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_SETTINGS" /> <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" /> diff --git a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothStressTest.java b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothStressTest.java index abd7d9af224a..755e7c4504c8 100644 --- a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothStressTest.java +++ b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothStressTest.java @@ -32,6 +32,8 @@ import android.test.InstrumentationTestCase; public class BluetoothStressTest extends InstrumentationTestCase { private static final String TAG = "BluetoothStressTest"; private static final String OUTPUT_FILE = "BluetoothStressTestOutput.txt"; + /** The amount of time to sleep between issuing start/stop SCO in ms. */ + private static final long SCO_SLEEP_TIME = 2 * 1000; private BluetoothTestUtils mTestUtils; @@ -380,11 +382,20 @@ public class BluetoothStressTest extends InstrumentationTestCase { for (int i = 0; i < iterations; i++) { mTestUtils.writeOutput("startStopSco iteration " + (i + 1) + " of " + iterations); mTestUtils.startSco(adapter, device); + sleep(SCO_SLEEP_TIME); mTestUtils.stopSco(adapter, device); + sleep(SCO_SLEEP_TIME); } mTestUtils.disconnectProfile(adapter, device, BluetoothProfile.HEADSET, null); mTestUtils.unpair(adapter, device); mTestUtils.disable(adapter); } + + private void sleep(long time) { + try { + Thread.sleep(time); + } catch (InterruptedException e) { + } + } } diff --git a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothTestUtils.java b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothTestUtils.java index 42e5cd17f2a7..4858be8c2a8e 100644 --- a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothTestUtils.java +++ b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothTestUtils.java @@ -1425,7 +1425,7 @@ public class BluetoothTestUtils extends Assert { } private StartStopScoReceiver getStartStopScoReceiver(int expectedFlags) { - String[] actions = {AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED}; + String[] actions = {AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED}; StartStopScoReceiver receiver = new StartStopScoReceiver(expectedFlags); addReceiver(receiver, actions); return receiver; diff --git a/core/tests/coretests/src/android/accessibilityservice/InterrogationActivityTest.java b/core/tests/coretests/src/android/accessibilityservice/InterrogationActivityTest.java index 3521296713e1..ec1212425491 100644 --- a/core/tests/coretests/src/android/accessibilityservice/InterrogationActivityTest.java +++ b/core/tests/coretests/src/android/accessibilityservice/InterrogationActivityTest.java @@ -26,6 +26,7 @@ import android.os.SystemClock; import android.test.ActivityInstrumentationTestCase2; import android.test.suitebuilder.annotation.LargeTest; import android.util.Log; +import android.view.View; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityInteractionClient; import android.view.accessibility.AccessibilityManager; @@ -54,28 +55,31 @@ public class InterrogationActivityTest // Timeout before give up wait for the system to process an accessibility setting change. private static final int TIMEOUT_PROPAGATE_ACCESSIBLITY_SETTING = 2000; + // Timeout for the accessibility state of an Activity to be fully initialized. + private static final int TIMEOUT_ACCESSIBLITY_STATE_INITIALIZED_MILLIS = 100; + // Handle to a connection to the AccessibilityManagerService - private static IAccessibilityServiceConnection sConnection; + private static int sConnectionId = View.NO_ID; // The last received accessibility event - private static volatile AccessibilityEvent sLastFocusAccessibilityEvent; + private volatile AccessibilityEvent mLastAccessibilityEvent; public InterrogationActivityTest() { super(InterrogationActivity.class); } + @Override + public void setUp() throws Exception { + ensureConnection(); + bringUpActivityWithInitalizedAccessbility(); + } + @LargeTest public void testFindAccessibilityNodeInfoByViewId() throws Exception { final long startTimeMillis = SystemClock.uptimeMillis(); try { - // hook into the system first - IAccessibilityServiceConnection connection = getConnection(); - - // bring up the activity - getActivity(); - AccessibilityNodeInfo button = AccessibilityInteractionClient.getInstance() - .findAccessibilityNodeInfoByViewIdInActiveWindow(connection, R.id.button5); + .findAccessibilityNodeInfoByViewIdInActiveWindow(sConnectionId, R.id.button5); assertNotNull(button); assertEquals(0, button.getChildCount()); @@ -120,15 +124,9 @@ public class InterrogationActivityTest public void testFindAccessibilityNodeInfoByViewText() throws Exception { final long startTimeMillis = SystemClock.uptimeMillis(); try { - // hook into the system first - IAccessibilityServiceConnection connection = getConnection(); - - // bring up the activity - getActivity(); - // find a view by text - List<AccessibilityNodeInfo> buttons = AccessibilityInteractionClient.getInstance() - .findAccessibilityNodeInfosByViewTextInActiveWindow(connection, "butto"); + List<AccessibilityNodeInfo> buttons = AccessibilityInteractionClient.getInstance() + .findAccessibilityNodeInfosByViewTextInActiveWindow(sConnectionId, "butto"); assertEquals(9, buttons.size()); } finally { if (DEBUG) { @@ -143,15 +141,11 @@ public class InterrogationActivityTest public void testFindAccessibilityNodeInfoByViewTextContentDescription() throws Exception { final long startTimeMillis = SystemClock.uptimeMillis(); try { - // hook into the system first - IAccessibilityServiceConnection connection = getConnection(); - - // bring up the activity - getActivity(); + bringUpActivityWithInitalizedAccessbility(); // find a view by text - List<AccessibilityNodeInfo> buttons = AccessibilityInteractionClient.getInstance() - .findAccessibilityNodeInfosByViewTextInActiveWindow(connection, + List<AccessibilityNodeInfo> buttons = AccessibilityInteractionClient.getInstance() + .findAccessibilityNodeInfosByViewTextInActiveWindow(sConnectionId, "contentDescription"); assertEquals(1, buttons.size()); } finally { @@ -167,12 +161,6 @@ public class InterrogationActivityTest public void testTraverseAllViews() throws Exception { final long startTimeMillis = SystemClock.uptimeMillis(); try { - // hook into the system first - IAccessibilityServiceConnection connection = getConnection(); - - // bring up the activity - getActivity(); - // make list of expected nodes List<String> classNameAndTextList = new ArrayList<String>(); classNameAndTextList.add("android.widget.LinearLayout"); @@ -190,7 +178,7 @@ public class InterrogationActivityTest classNameAndTextList.add("android.widget.ButtonButton9"); AccessibilityNodeInfo root = AccessibilityInteractionClient.getInstance() - .findAccessibilityNodeInfoByViewIdInActiveWindow(connection, R.id.root); + .findAccessibilityNodeInfoByViewIdInActiveWindow(sConnectionId, R.id.root); assertNotNull("We must find the existing root.", root); Queue<AccessibilityNodeInfo> fringe = new LinkedList<AccessibilityNodeInfo>(); @@ -227,23 +215,17 @@ public class InterrogationActivityTest public void testPerformAccessibilityActionFocus() throws Exception { final long startTimeMillis = SystemClock.uptimeMillis(); try { - // hook into the system first - IAccessibilityServiceConnection connection = getConnection(); - - // bring up the activity - getActivity(); - // find a view and make sure it is not focused AccessibilityNodeInfo button = AccessibilityInteractionClient.getInstance() - .findAccessibilityNodeInfoByViewIdInActiveWindow(connection, R.id.button5); + .findAccessibilityNodeInfoByViewIdInActiveWindow(sConnectionId, R.id.button5); assertFalse(button.isFocused()); // focus the view assertTrue(button.performAction(ACTION_FOCUS)); // find the view again and make sure it is focused - button = AccessibilityInteractionClient.getInstance() - .findAccessibilityNodeInfoByViewIdInActiveWindow(connection, R.id.button5); + button = AccessibilityInteractionClient.getInstance() + .findAccessibilityNodeInfoByViewIdInActiveWindow(sConnectionId, R.id.button5); assertTrue(button.isFocused()); } finally { if (DEBUG) { @@ -257,15 +239,9 @@ public class InterrogationActivityTest public void testPerformAccessibilityActionClearFocus() throws Exception { final long startTimeMillis = SystemClock.uptimeMillis(); try { - // hook into the system first - IAccessibilityServiceConnection connection = getConnection(); - - // bring up the activity - getActivity(); - // find a view and make sure it is not focused AccessibilityNodeInfo button = AccessibilityInteractionClient.getInstance() - .findAccessibilityNodeInfoByViewIdInActiveWindow(connection, R.id.button5); + .findAccessibilityNodeInfoByViewIdInActiveWindow(sConnectionId, R.id.button5); assertFalse(button.isFocused()); // focus the view @@ -273,7 +249,7 @@ public class InterrogationActivityTest // find the view again and make sure it is focused button = AccessibilityInteractionClient.getInstance() - .findAccessibilityNodeInfoByViewIdInActiveWindow(connection, R.id.button5); + .findAccessibilityNodeInfoByViewIdInActiveWindow(sConnectionId, R.id.button5); assertTrue(button.isFocused()); // unfocus the view @@ -281,7 +257,7 @@ public class InterrogationActivityTest // find the view again and make sure it is not focused button = AccessibilityInteractionClient.getInstance() - .findAccessibilityNodeInfoByViewIdInActiveWindow(connection, R.id.button5); + .findAccessibilityNodeInfoByViewIdInActiveWindow(sConnectionId, R.id.button5); assertFalse(button.isFocused()); } finally { if (DEBUG) { @@ -296,15 +272,9 @@ public class InterrogationActivityTest public void testPerformAccessibilityActionSelect() throws Exception { final long startTimeMillis = SystemClock.uptimeMillis(); try { - // hook into the system first - IAccessibilityServiceConnection connection = getConnection(); - - // bring up the activity - getActivity(); - // find a view and make sure it is not selected AccessibilityNodeInfo button = AccessibilityInteractionClient.getInstance() - .findAccessibilityNodeInfoByViewIdInActiveWindow(connection, R.id.button5); + .findAccessibilityNodeInfoByViewIdInActiveWindow(sConnectionId, R.id.button5); assertFalse(button.isSelected()); // select the view @@ -312,7 +282,7 @@ public class InterrogationActivityTest // find the view again and make sure it is selected button = AccessibilityInteractionClient.getInstance() - .findAccessibilityNodeInfoByViewIdInActiveWindow(connection, R.id.button5); + .findAccessibilityNodeInfoByViewIdInActiveWindow(sConnectionId, R.id.button5); assertTrue(button.isSelected()); } finally { if (DEBUG) { @@ -326,15 +296,9 @@ public class InterrogationActivityTest public void testPerformAccessibilityActionClearSelection() throws Exception { final long startTimeMillis = SystemClock.uptimeMillis(); try { - // hook into the system first - IAccessibilityServiceConnection connection = getConnection(); - - // bring up the activity - getActivity(); - // find a view and make sure it is not selected AccessibilityNodeInfo button = AccessibilityInteractionClient.getInstance() - .findAccessibilityNodeInfoByViewIdInActiveWindow(connection, R.id.button5); + .findAccessibilityNodeInfoByViewIdInActiveWindow(sConnectionId, R.id.button5); assertFalse(button.isSelected()); // select the view @@ -342,15 +306,15 @@ public class InterrogationActivityTest // find the view again and make sure it is selected button = AccessibilityInteractionClient.getInstance() - .findAccessibilityNodeInfoByViewIdInActiveWindow(connection, R.id.button5); + .findAccessibilityNodeInfoByViewIdInActiveWindow(sConnectionId, R.id.button5); assertTrue(button.isSelected()); // unselect the view assertTrue(button.performAction(ACTION_CLEAR_SELECTION)); // find the view again and make sure it is not selected - button = AccessibilityInteractionClient.getInstance() - .findAccessibilityNodeInfoByViewIdInActiveWindow(connection, R.id.button5); + button = AccessibilityInteractionClient.getInstance() + .findAccessibilityNodeInfoByViewIdInActiveWindow(sConnectionId, R.id.button5); assertFalse(button.isSelected()); } finally { if (DEBUG) { @@ -365,30 +329,24 @@ public class InterrogationActivityTest public void testAccessibilityEventGetSource() throws Exception { final long startTimeMillis = SystemClock.uptimeMillis(); try { - // hook into the system first - IAccessibilityServiceConnection connection = getConnection(); - - // bring up the activity - getActivity(); - // find a view and make sure it is not focused AccessibilityNodeInfo button = AccessibilityInteractionClient.getInstance() - .findAccessibilityNodeInfoByViewIdInActiveWindow(connection, R.id.button5); + .findAccessibilityNodeInfoByViewIdInActiveWindow(sConnectionId, R.id.button5); assertFalse(button.isSelected()); // focus the view assertTrue(button.performAction(ACTION_FOCUS)); - synchronized (sConnection) { + synchronized (this) { try { - sConnection.wait(500); + wait(TIMEOUT_ACCESSIBLITY_STATE_INITIALIZED_MILLIS); } catch (InterruptedException ie) { /* ignore */ } } // check that last event source - AccessibilityNodeInfo source = sLastFocusAccessibilityEvent.getSource(); + AccessibilityNodeInfo source = mLastAccessibilityEvent.getSource(); assertNotNull(source); // bounds @@ -430,15 +388,9 @@ public class InterrogationActivityTest public void testObjectContract() throws Exception { final long startTimeMillis = SystemClock.uptimeMillis(); try { - // hook into the system first - IAccessibilityServiceConnection connection = getConnection(); - - // bring up the activity - getActivity(); - // find a view and make sure it is not focused AccessibilityNodeInfo button = AccessibilityInteractionClient.getInstance() - .findAccessibilityNodeInfoByViewIdInActiveWindow(connection, R.id.button5); + .findAccessibilityNodeInfoByViewIdInActiveWindow(sConnectionId, R.id.button5); AccessibilityNodeInfo parent = button.getParent(); final int childCount = parent.getChildCount(); for (int i = 0; i < childCount; i++) { @@ -459,24 +411,57 @@ public class InterrogationActivityTest } } - @Override - protected void scrubClass(Class<?> testCaseClass) { - /* intentionally do not scrub */ + private void bringUpActivityWithInitalizedAccessbility() { + mLastAccessibilityEvent = null; + // bring up the activity + getActivity(); + + final long startTimeMillis = SystemClock.uptimeMillis(); + while (true) { + if (mLastAccessibilityEvent != null) { + final int eventType = mLastAccessibilityEvent.getEventType(); + if (eventType == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) { + return; + } + } + final long remainingTimeMillis = TIMEOUT_ACCESSIBLITY_STATE_INITIALIZED_MILLIS + - (SystemClock.uptimeMillis() - startTimeMillis); + if (remainingTimeMillis <= 0) { + return; + } + synchronized (this) { + try { + wait(remainingTimeMillis); + } catch (InterruptedException e) { + /* ignore */ + } + } + } } - private IAccessibilityServiceConnection getConnection() throws Exception { - if (sConnection == null) { + private void ensureConnection() throws Exception { + if (sConnectionId == View.NO_ID) { IEventListener listener = new IEventListener.Stub() { - public void setConnection(IAccessibilityServiceConnection connection) {} + public void setConnection(IAccessibilityServiceConnection connection, + int connectionId) { + sConnectionId = connectionId; + if (connection != null) { + AccessibilityInteractionClient.getInstance().addConnection(connectionId, + connection); + } else { + AccessibilityInteractionClient.getInstance().removeConnection(connectionId); + } + synchronized (this) { + notifyAll(); + } + } public void onInterrupt() {} public void onAccessibilityEvent(AccessibilityEvent event) { - if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_FOCUSED) { - sLastFocusAccessibilityEvent = AccessibilityEvent.obtain(event); - } - synchronized (sConnection) { - sConnection.notifyAll(); + mLastAccessibilityEvent = AccessibilityEvent.obtain(event); + synchronized (this) { + notifyAll(); } } }; @@ -485,28 +470,11 @@ public class InterrogationActivityTest AccessibilityManager.getInstance(getInstrumentation().getContext()); synchronized (this) { - if (!accessibilityManager.isEnabled()) { - // Make sure we wake ourselves as the desired state is propagated. - accessibilityManager.addAccessibilityStateChangeListener( - new AccessibilityManager.AccessibilityStateChangeListener() { - public void onAccessibilityStateChanged(boolean enabled) { - synchronized (this) { - notifyAll(); - } - } - }); - IAccessibilityManager manager = IAccessibilityManager.Stub.asInterface( + IAccessibilityManager manager = IAccessibilityManager.Stub.asInterface( ServiceManager.getService(Context.ACCESSIBILITY_SERVICE)); - sConnection = manager.registerEventListener(listener); - - wait(TIMEOUT_PROPAGATE_ACCESSIBLITY_SETTING); - } else { - IAccessibilityManager manager = IAccessibilityManager.Stub.asInterface( - ServiceManager.getService(Context.ACCESSIBILITY_SERVICE)); - sConnection = manager.registerEventListener(listener); - } + manager.registerEventListener(listener); + wait(TIMEOUT_PROPAGATE_ACCESSIBLITY_SETTING); } } - return sConnection; } } diff --git a/data/fonts/DroidSansArmenian.ttf b/data/fonts/DroidSansArmenian.ttf Binary files differindex 62f67e081d77..6fafa5411e9a 100644 --- a/data/fonts/DroidSansArmenian.ttf +++ b/data/fonts/DroidSansArmenian.ttf diff --git a/data/fonts/DroidSansGeorgian.ttf b/data/fonts/DroidSansGeorgian.ttf Binary files differindex 743ae667d458..3a2e9fbc839a 100644 --- a/data/fonts/DroidSansGeorgian.ttf +++ b/data/fonts/DroidSansGeorgian.ttf diff --git a/data/keyboards/Generic.kl b/data/keyboards/Generic.kl index 10de6ac9cf12..fdd9040d7348 100644 --- a/data/keyboards/Generic.kl +++ b/data/keyboards/Generic.kl @@ -159,7 +159,7 @@ key 128 MEDIA_STOP # key 137 "KEY_CUT" # key 138 "KEY_HELP" key 139 MENU WAKE_DROPPED -# key 140 "KEY_CALC" +key 140 CALCULATOR # key 141 "KEY_SETUP" key 142 POWER WAKE key 143 POWER WAKE @@ -190,7 +190,7 @@ key 167 MEDIA_RECORD key 168 MEDIA_REWIND key 169 CALL # key 170 "KEY_ISO" -# key 171 "KEY_CONFIG" +key 171 MUSIC key 172 HOME # key 173 "KEY_REFRESH" # key 174 "KEY_EXIT" @@ -232,7 +232,7 @@ key 208 MEDIA_FAST_FORWARD # key 210 "KEY_PRINT" # key 211 "KEY_HP" key 212 CAMERA -# key 213 "KEY_SOUND" +key 213 MUSIC # key 214 "KEY_QUESTION" key 215 ENVELOPE # key 216 "KEY_CHAT" @@ -344,7 +344,7 @@ key 377 TV # key 394 "KEY_DIRECTORY" # key 395 "KEY_LIST" # key 396 "KEY_MEMO" -# key 397 "KEY_CALENDAR" +key 397 CALENDAR # key 398 "KEY_RED" # key 399 "KEY_GREEN" # key 400 "KEY_YELLOW" @@ -364,6 +364,7 @@ key 403 CHANNEL_DOWN # key 414 "KEY_TEEN" # key 415 "KEY_TWEN" +key 429 CONTACTS # key 448 "KEY_DEL_EOL" # key 449 "KEY_DEL_EOS" diff --git a/docs/html/guide/market/billing/billing_admin.jd b/docs/html/guide/market/billing/billing_admin.jd index cbb4b29cfc47..a84eb4e88139 100755 --- a/docs/html/guide/market/billing/billing_admin.jd +++ b/docs/html/guide/market/billing/billing_admin.jd @@ -39,12 +39,12 @@ few administrative tasks, including setting up and maintaining your product list site, registering test accounts, and handling refunds when necessary.</p> <p>You must have an Android Market publisher account to register test accounts. And you must have a -Google Checkout Merchant account to create a product list and issue refunds to your users. If you +Google Checkout merchant account to create a product list and issue refunds to your users. If you already have a publisher account on Android Market, you can use your existing account. You do not need to register for a new account to support in-app billing. If you do not have a publisher account, you can register as an Android Market developer and set up a publisher account at the Android Market <a href="http://market.android.com/publish">publisher site</a>. If you do not have a -Google Checkout Merchant account, you can register for one at the <a +Google Checkout merchant account, you can register for one at the <a href="http://checkout.google.com">Google Checkout site</a>.</p> <h2 id="billing-list-setup">Creating a Product List</h2> @@ -57,7 +57,7 @@ items that are listed in another application's product list.</p> <p>You can access an application's product list by clicking the <strong>In-App Products</strong> link that appears under each of the applications that are listed for your publisher account (see figure 1). The <strong>In-App Products</strong> link appears only if you have a Google Checkout -Merchant account and an application's manifest includes the <code>com.android.vending.BILLING</code> +merchant account and an application's manifest includes the <code>com.android.vending.BILLING</code> permission.</p> <img src="{@docRoot}images/billing_product_list_entry.png" height="548" id="figure1" /> @@ -71,20 +71,37 @@ product description, and price (see figure 2). The product list stores only meta you are selling in your application. It does not store any digital content. You are responsible for storing and delivering the digital content that you sell in your applications.</p> -<img src="{@docRoot}images/billing_product_list.png" height="560" id="figure2" /> +<img src="{@docRoot}images/billing_product_list.png" height="658" id="figure2" /> <p class="img-caption"> <strong>Figure 2.</strong> An application's product list. </p> -<p>You can create a product list for a published application or a draft application that's been -uploaded and saved to the Android Market site. However, you must have a Google Checkout Merchant +<p>You can create a product list for any published application or any draft application that's been +uploaded and saved to the Android Market site. However, you must have a Google Checkout merchant account and the application's manifest must include the <code>com.android.vending.BILLING</code> permission. If an application's manifest does not include this permission, you will be able to edit existing items in the product list but you will not be able to add new items to the list. For more -information, see <a href="#billing-permission">Modifying your application's AndroidManifest.xml -file</a>.</p> +information about this permission, see +<a href="{@docRoot}guide/market/billing/billing_integrate.html#billing-permission">Updating Your +Application's Manifest</a>.</p> -<p>To create a product list for an application, follow these steps:</p> +<p>In addition, an application package can have only one product list. If you create a product +list for an application, and you use the <a +href="{@docRoot}guide/market/publishing/multiple-apks.html">multiple APK feature</a> to distribute +more than one APK for that application, the product list applies to all APK versions that are +associated with the application listing. You cannot create individual product lists for each APK if +you are using the multiple APK feature.</p> + +<p>You can add items to a product list two ways: you can add items one at a time by using the In-app +Products UI (see figure 3), or you can add a batch of items by importing the items from a +comma-separated values (CSV) file (see figure 2). Adding items one at a time is useful if your +application has only a few in-app items or you are adding only a few items to a +product list for testing purposes. The CSV file method is useful if your application has a large +number of in-app items.</p> + +<h3 id="billing-form-add">Adding items one at a time to a product list</h3> + +<p>To add an item to a product list using the In-app Products UI, follow these steps:</p> <ol> <li><a href="http://market.android.com/publish">Log in</a> to your publisher account.</li> @@ -92,7 +109,7 @@ file</a>.</p> <strong>In-app Products</strong>.</li> <li>On the In-app Products List page, click <strong>Add in-app product</strong>.</li> <li>On the Create New In-app Product page (see figure 3), provide details about the item you are - selling and then click <strong>Save</strong>.</li> + selling and then click <strong>Save</strong> or <strong>Publish</strong>.</li> </ol> <img src="{@docRoot}images/billing_list_form.png" height="840" id="figure3" /> @@ -109,25 +126,31 @@ file</a>.</p> (0-9), underlines (_), and dots (.). The product ID "android.test" is reserved, as are all product IDs that start with "android.test."</p> <p>In addition, you cannot modify an item's product ID after it is created, and you cannot reuse - a product ID, even if you delete the item previously using the product ID.</p> + a product ID.</p> </li> - <li><strong>Purchase type</strong> - <p>The purchase type can be "managed per user account" or "unmanaged." You can specify an item's - purchase type only through the publisher site and you can never change an item's purchase type - once you specify it. For more information, see <a href="#billing_purchase_type">Choosing a - purchase type</a> later in this document.</p> + <li><strong>Purchase Type</strong> + <p>The purchase type can be <strong>Managed per user account</strong> or <strong> + Unmanaged</strong>. You can never change an item's purchase type after you set it. For more + information, see <a href="#billing-purchase-type">Choosing a purchase type</a> later in this + document.</p> </li> <li><strong>Publishing State</strong> - <p>An item's publishing state can be "published" or "unpublished." However, to be visible to a - user during checkout, an item's publishing state must be set to "published" and the item's - application must be published on Android Market.</p> + <p>An item's publishing state can be <strong>Published</strong> or <strong>Unpublished + </strong>. To be visible to a user during checkout, an item's publishing state must be set to + <strong>Published</strong> and the item's application must be published on Android Market.</p> <p class="note"><strong>Note:</strong> This is not true for test accounts. An item is visible to a test account if the application is not published and the item is published. See <a href="{@docRoot}guide/market/billing/billing_testing.html#billing-testing-real">Testing In-app Billing</a> for more information.</p> </li> <li><strong>Language</strong> - <p>A product list inherits its language from the parent application.</p> + <p>The language setting determines which languages are used to display the item title and + item description during checkout. A product list inherits its default language from the + parent application. You can add more languages by clicking <strong>add language</strong>. You + can also choose to have the title and description automatically translated from the default + language by selecting the <strong>Fill fields with auto translation</strong> checkbox (see + figure 4). If you do not use the auto translation feature, you must provide the translated + versions of the title and description.</p> </li> <li><strong>Title</strong> <p>The title is a short descriptor for the item. For example, "Sleeping potion." Titles must be @@ -141,9 +164,20 @@ file</a>.</p> visible to users during checkout. Descriptions can be up to 80 characters in length.</p> </li> <li><strong>Price</strong> - <p>Every item must have a price greater than zero; you cannot set a price of "0" (free).</p> + <p>You must provide a default price in your home currency. You can also provide prices in other + currencies, but you can do this only if a currency's corresponding country is listed as a + target country for your application. You can specify target countries on the Edit Application + page in the Android Market developer console.</p> + <p>To specify prices in other currencies, you can manually enter the price for each + currency or you can click <strong>Auto Fill</strong> and let Android Market do a one-time + conversion from your home currency to the currencies you are targeting (see figure 4).</p> </li> </ul> +<img src="{@docRoot}images/billing_list_form_2.png" height="1226" id="figure4" /> +<p class="img-caption"> + <strong>Figure 4.</strong> Specifying additional currencies and additional languages for the + item title and description. +</p> <p>For more information about product IDs and product lists, see <a href="http://market.android.com/support/bin/answer.py?answer=1072599">Creating In-App Product @@ -154,6 +188,197 @@ Pricing</a>.</p> <p class="note"><strong>Note</strong>: Be sure to plan your product ID namespace. You cannot reuse or modify product IDs after you save them.</p> +<h3 id="billing-bulk-add">Adding a batch of items to a product list</h3> + +<p>To add a batch of items to a product list using a CSV file, you first need to create your CSV +file. The data values that you specify in the CSV file represent the same data values you specify +manually through the In-app Products UI (see <a href="#billing-form-add">Adding items one at a time +to a product list</a>). The CSV file uses commas (,) and semi-colons (;) to separate data values. +Commas are used to separate primary data values, and semi-colons are used to separate subvalues. For +example, the syntax for the CSV file is as follows:</p> + +<p>"<em>product_id</em>","<em>publish_state</em>","<em>purchase_type</em>","<em>autotranslate</em> +","<em>locale</em>; <em>title</em>; <em>description</em>","<em>autofill</em>","<em>country</em>; +<em>price</em>" +</p> + +<p>Descriptions and usage details are provided below.</p> + +<ul> + <li><em>product_id</em> + <p>This is equivalent to the In-app Product ID setting in the In-app Products UI. If you specify + a <em>product_id</em> that already exists in a product list, and you choose to overwrite + the product list while importing the CSV file, the data for the existing item is overwritten with + the values specified in the CSV file. The overwrite feature does not delete items that are on a + product list but not present in the CSV file.</p> + </li> + <li><em>publish_state</em> + <p>This is equivalent to the Publishing State setting in the In-app Products UI. Can be <code> + published</code> or <code>unpublished</code>.</p> + </li> + <li><em>purchase_type</em> + <p>This is equivalent to the Purchase Type setting in the In-app Products UI. Can be <code> + managed_by_android</code>, which is equivalent to <strong>Managed per user account + </strong> in the In-app Products UI, or <code>managed_by_publisher</code>, which is equivalent + to <strong>Unmanaged</strong> in the In-app Products UI.</p> + </li> + <li><em>autotranslate</em> + <p>This is equivalent to selecting the <strong>Fill fields with auto translation</strong> + checkbox in the In-app Products UI. Can be <code>true</code> or <code>false</code>.</p> + </li> + <li><em>locale</em> + <p>This is equivalent to the Language setting in the In-app Products UI. You must have an entry + for the default locale. The default locale must be the first entry in the list of + locales, and it must include a <em>title</em> and <em>description</em>. If you want to provide + translated versions of the <em>title</em> and <em>description</em> in addition to the default, + you must use the following syntax rules:</p> + <p>If <em>autotranslate</em> is <code>true</code>, you must specify the default locale, + default title, default description, and other locales using the following format:</p> + <p>"true,"<em>default_locale</em>; <em>default_locale_title</em>; + <em>default_locale_description</em>; <em>locale_2</em>; <em>locale_3</em>, ..."</p> + <p>If <em>autotranslate</em> is <code>false</code>, you must specify the default locale, + default title, and default description as well as the translated titles and descriptions using + the following format:</p> + <p>"false,"<em>default_locale</em>; <em>default_locale_title</em>; + <em>default_locale_description</em>; <em>locale_2</em>; <em>locale_2_title</em>; + <em>local_2_description</em>; <em>locale_3</em>; <em>locale_3_title</em>; + <em>locale_3_description</em>; ..."</p> + <p>See table 1 for a list of the language codes you can use with the <em>locale</em> field.</p> + </li> + <li><em>title</em> + <p>This is equivalent to the Title setting in the In-app Products UI. If the <em>title</em> + contains a semicolon, it must be escaped with a backslash (for example, "\;"). A backslash + should also be escaped with a backslash (for example, "\\">.</p> + </li> + <li><em>description</em> + <p>This is equivalent to the Description in the In-app Products UI. If the <em>description</em> + contains a semicolon, it must be escaped with a backslash (for example, "\;"). A backslash + should also be escaped with a backslash (for example, "\\">.</p> + </li> + <li><em>autofill</em> + <p>This is equivalent to clicking <strong>Auto Fill</strong> in the In-app Products UI. Can be + <code>true</code> or <code>false</code>. The syntax for specifying the <em>country</em> + and <em>price</em> varies depending on which <em>autofill</em> setting you use.</p> + <p>If <em>autofill</em> is set to <code>true</code>, you need to specify only the default + price in your home currency and you must use this syntax:</p> + <p>"true","<em>default_price_in_home_currency</em>" + <p>If <em>autofill</em> is set to <code>false</code>, you need to specify a <em>country</em> + and a <em>price</em> for each currency and you must use the following syntax:</p> + <p>"false", "<em>home_country</em>; <em>default_price_in_home_currency</em>; <em>country_2</em>; + <em>country_2_price</em>; <em>country_3</em>; <em>country_3_price</em>; ..."</p> + </li> + <li><em>country</em> + <p>The country for which you are specifying a price. You can only list countries that your + application is targeting. The country codes are two-letter uppercase + ISO country codes (such as "US") as defined by + <a href="http://en.wikipedia.org/wiki/ISO_3166-1_alpha-2">ISO 3166-2</a>.</p> + </li> + <li><em>price</em> + <p>This is equivalent to the Price in the In-app Products UI. The price must be specified in + micro-units. To convert a currency value to micro-units, you multiply the real value by 1,000,000. + For example, if you want to sell an in-app item for $1.99 you specify 1990000 in the + <em>price</em> field.</p> + </li> +</ul> + +<p class="table-caption" id="language-table"><strong>Table 1.</strong> Language codes you can use +with the <em>locale</em> field.</p> + +<table> + +<tr> +<th>Language</th> +<th>Code</th> +<th>Language</th> +<th>Code</th> +</tr> +<tr> +<td>Chinese</td> +<td>zh_TW</td> +<td>Italian</td> +<td>it_IT</td> +</tr> +<tr> +<td>Czech</td> +<td>cs_CZ</td> +<td>Japanese</td> +<td>ja_JP</td> +</tr> +<tr> +<td>Danish</td> +<td>da_DK</td> +<td>Korean</td> +<td>ko_KR</td> +</tr> +<tr> +<td>Dutch</td> +<td>nl_NL</td> +<td>Norwegian</td> +<td>no_NO</td> +</tr> +<tr> +<td>English</td> +<td>en_US</td> +<td>Polish</td> +<td>pl_PL</td> +</tr> +<tr> +<td>French</td> +<td>fr_FR</td> +<td>Portuguese</td> +<td>pt_PT</td> +</tr> +<tr> +<td>Finnish</td> +<td>fi_FI</td> +<td>Russian</td> +<td>ru_RU</td> +</tr> +<tr> +<td>German</td> +<td>de_DE</td> +<td>Spanish</td> +<td>es_ES</td> +</tr> +<tr> +<td>Hebrew</td> +<td>iw_IL</td> +<td>Swedish</td> +<td>sv_SE</td> +</tr> +<tr> +<td>Hindi</td> +<td>hi_IN</td> +<td>--</td> +<td>--</td> +</tr> +</table> + +<p>To import the items that are specified in your CSV file, do the following:</p> + +<ol> + <li><a href="http://market.android.com/publish">Log in</a> to your publisher account.</li> + <li>In the <strong>All Android Market listings</strong> panel, under the application name, click + <strong>In-app Products</strong>.</li> + <li>On the In-app Products List page, click <strong>Choose File</strong> and select your CSV +file. + <p>The CSV file must be on your local computer or on a local disk that is connected to your + computer.</p> + </li> + <li>Select the <strong>Overwrite</strong> checkbox if you want to overwrite existing items in + your product list. + <p>This option overwrites values of existing items only if the value of the <em>product_id</em> + in the CSV file matches the In-app Product ID for an existing item in the product list. + Overwriting does not delete items that are on a product list but not present in the CSV + file.</p> + </li> + <li>On the In-app Products List page, click <strong>Import from CSV</strong>.</li> +</ol> + +<p>You can also export an existing product list to a CSV file by clicking <strong>Export to CSV +</strong> on the In-app Product List page. This is useful if you have manually added items to +a product list and you want to start managing the product list through a CSV file.</p> + <h3 id="billing-purchase-type">Choosing a Purchase Type</h3> <p>An item's purchase type controls how Android Market manages the purchase of the item. There are @@ -194,7 +419,7 @@ times.</p> <p>In-app billing does not allow users to send a refund request to Android Market. Refunds for in-app purchases must be directed to you (the application developer). You can then process the -refund through your Google Checkout Merchant account. When you do this, Android Market receives a +refund through your Google Checkout merchant account. When you do this, Android Market receives a refund notification from Google Checkout, and Android Market sends a refund message to your application. For more information, see <a href="{@docRoot}guide/market/billing/billing_overview.html#billing-action-notify">Handling @@ -236,15 +461,15 @@ accounts yourself and distribute the credentials to your developers or testers.< <li><a href="http://market.android.com/publish">Log in</a> to your publisher account.</li> <li>On the upper left part of the page, under your name, click <strong>Edit profile</strong>.</li> <li>On the Edit Profile page, scroll down to the Licensing & In-app Billing panel (see figure - 4).</li> + 5).</li> <li>In Test Accounts, add the email addresses for the test accounts you want to register, separating each account with a comma.</li> <li>Click <strong>Save</strong> to save your profile changes.</li> </ol> -<img src="{@docRoot}images/billing_public_key.png" height="510" id="figure4" /> +<img src="{@docRoot}images/billing_public_key.png" height="510" id="figure5" /> <p class="img-caption"> - <strong>Figure 4.</strong> The Licensing and In-app Billing panel of your account's Edit Profile + <strong>Figure 5.</strong> The Licensing and In-app Billing panel of your account's Edit Profile page lets you register test accounts. </p> diff --git a/docs/html/guide/practices/ui_guidelines/widget_design.jd b/docs/html/guide/practices/ui_guidelines/widget_design.jd index de20e007f393..f63f3c4a8a76 100644 --- a/docs/html/guide/practices/ui_guidelines/widget_design.jd +++ b/docs/html/guide/practices/ui_guidelines/widget_design.jd @@ -250,13 +250,15 @@ android.widget.FrameLayout}. Just as your activity layouts must adapt to differe sizes, widget layouts must adapt to different Home screen grid cell sizes.</p> <p>Below is an example layout that a music widget showing text information and two buttons can use. -It builds upon the previous discussion of adding margins depending on OS version.</p> +It builds upon the previous discussion of adding margins depending on OS version. Note that the +most robust and resilient way to add margins to the widget is to wrap the widget frame and contents +in a padded {@link android.widget.FrameLayout}.</p> <pre> <FrameLayout android:layout_width="match_parent" android:layout_height="match_parent" - android:layout_margin="@dimen/widget_margin"> + android:padding="@dimen/widget_margin"> <LinearLayout android:layout_width="match_parent" @@ -295,16 +297,16 @@ use flexible layouts attributes like so:</p> <p>When a user adds the widget to their home screen, on an example Android 4.0 device where each -grid cell is 80dp × 100dp in size and 16dp of margins are automatically applied on all sizes, +grid cell is 80dp × 100dp in size and 8dp of margins are automatically applied on all sizes, the widget will be stretched, like so:</p> <img src="{@docRoot}images/widget_design/music_example_stretched.png" - alt="Music widget sitting on an example 80dp x 100dp grid with 16dp of automatic margins + alt="Music widget sitting on an example 80dp x 100dp grid with 8dp of automatic margins added by the system" id="music_example_stretched"> <p class="img-caption"><strong>Figure 7.</strong> Music widget sitting on an example 80dp x 100dp -grid with 16dp of automatic margins added by the system.</p> +grid with 8dp of automatic margins added by the system.</p> <h2 id="templates">Using the App Widget Templates Pack</h2> diff --git a/docs/html/guide/topics/appwidgets/index.jd b/docs/html/guide/topics/appwidgets/index.jd index 61337b782a75..2cb23c1cdbba 100644 --- a/docs/html/guide/topics/appwidgets/index.jd +++ b/docs/html/guide/topics/appwidgets/index.jd @@ -346,7 +346,7 @@ following layout classes:</p> <FrameLayout android:layout_width="match_parent" android:layout_height="match_parent" - <strong>android:layout_margin="@dimen/widget_margin"></strong> + <strong>android:padding="@dimen/widget_margin"></strong> <LinearLayout android:layout_width="match_parent" @@ -363,7 +363,7 @@ following layout classes:</p> <li>Create two dimensions resources, one in <code>res/values/</code> to provide the pre-Android 4.0 custom margins, and one in <code>res/values-v14/</code> to provide no extra padding for Android 4.0 widgets: <p><strong>res/values/dimens.xml</strong>:<br> - <pre><dimen name="widget_margin">15dp</dimen></pre></p> + <pre><dimen name="widget_margin">8dp</dimen></pre></p> <p><strong>res/values-v14/dimens.xml</strong>:<br> <pre><dimen name="widget_margin">0dp</dimen></pre></p> diff --git a/docs/html/guide/topics/graphics/2d-graphics.jd b/docs/html/guide/topics/graphics/2d-graphics.jd index 5abffb39cee8..5cf1a59b2232 100644 --- a/docs/html/guide/topics/graphics/2d-graphics.jd +++ b/docs/html/guide/topics/graphics/2d-graphics.jd @@ -130,9 +130,8 @@ use your Canvas to draw a Bitmap handled by the system.</p> <p class="note"><strong>Note: </strong> In order to request an invalidate from a thread other than your main Activity's thread, you must call <code>{@link android.view.View#postInvalidate()}</code>.</p> -<p>Also read <a href="{@docRoot}guide/topics/ui/custom-components.html">Building Custom Components</a> -for a guide to extending a View class, and <a href="2d-graphics.html">2D Graphics: Drawables</a> for -information on using Drawable objects like images from your resources and other primitive shapes.</p> +<p>For information about extending the {@link android.view.View} class, read +<a href="{@docRoot}guide/topics/ui/custom-components.html">Building Custom Components</a>.</p> <p>For a sample application, see the Snake game, in the SDK samples folder: <code><your-sdk-directory>/samples/Snake/</code>.</p> @@ -188,7 +187,7 @@ browse the source in the <a href="{@docRoot}guide/samples/index.html">Sample Cod <p>This document discusses the basics of using Drawable objects to draw graphics and how to use a couple subclasses of the Drawable class. For information on using Drawables to do frame-by-frame -animation, see <a href="{@docRoot}guide/topics/animation/drawable-animation.html">Drawable +animation, see <a href="{@docRoot}guide/topics/graphics/drawable-animation.html">Drawable Animation</a>.</p> <p>A {@link android.graphics.drawable.Drawable} is a general abstraction for "something that can be diff --git a/docs/html/guide/topics/media/camera.jd b/docs/html/guide/topics/media/camera.jd index 877bded96393..b962f9686e89 100644 --- a/docs/html/guide/topics/media/camera.jd +++ b/docs/html/guide/topics/media/camera.jd @@ -29,6 +29,15 @@ parent.link=index.html </ol> </li> <li><a href="#saving-media">Saving Media Files</a></li> + <li><a href="#camera-features">Camera Features</a> + <ol> + <li><a href="#check-feature">Checking feature availability</a></li> + <li><a href="#using-features">Using camera features</a></li> + <li><a href="#metering-focus-areas">Metering and focus areas</a></li> + <li><a href="#face-detection">Face detection</a></li> + <li><a href="#time-lapse-video">Time lapse video</a></li> + </ol> + </li> </ol> <h2>Key Classes</h2> <ol> @@ -39,8 +48,7 @@ parent.link=index.html </ol> <h2>See also</h2> <ol> - <li><a href="{@docRoot}reference/android/hardware/Camera.html">Camera</a></li> - <li><a href="{@docRoot}reference/android/media/MediaRecorder.html">MediaRecorder</a></li> + <li><a href="{@docRoot}guide/topics/media/mediaplayer.html">Media Playback</a></li> <li><a href="{@docRoot}guide/topics/data/data-storage.html">Data Storage</a></li> </ol> </div> @@ -64,7 +72,7 @@ manifest</a>.</li> <li><strong>Quick Picture or Customized Camera</strong> - How will your application use the camera? Are you just interested in snapping a quick picture or video clip, or will your application -provide a new way to use cameras? For a getting a quick snap or clip, consider +provide a new way to use cameras? For a getting a quick snap or clip, consider <a href="#intents">Using Existing Camera Apps</a>. For developing a customized camera feature, check out the <a href="#custom-camera">Building a Camera App</a> section.</li> @@ -85,7 +93,7 @@ classes:</p> <dl> <dt>{@link android.hardware.Camera}</dt> <dd>This class is the primary API for controlling device cameras. This class is used to take -pictures or videos when you are building a camera application.</a>.</dd> +pictures or videos when you are building a camera application.</dd> <dt>{@link android.view.SurfaceView}</dt> <dd>This class is used to present a live camera preview to the user.</dd> @@ -120,8 +128,8 @@ for example: <pre> <uses-feature android:name="android.hardware.camera" /> </pre> - <p>For a list of camera features, see the manifest <a -href="{@docRoot}guide/topics/manifest/uses-feature-element.html#features-reference">Features + <p>For a list of camera features, see the manifest +<a href="{@docRoot}guide/topics/manifest/uses-feature-element.html#hw-features">Features Reference</a>.</p> <p>Adding camera features to your manifest causes Android Market to prevent your application from being installed to devices that do not include a camera or do not support the camera features you @@ -148,6 +156,15 @@ application must request the audio capture permission. <uses-permission android:name="android.permission.RECORD_AUDIO" /> </pre> </li> + <li><strong>Location Permission</strong> - If your application tags images with GPS location +information, you must request location permission: +<pre> +<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> +</pre> +<p>For more information about getting user location, see +<a href="{@docRoot}guide/topics/location/obtaining-user-location.html">Obtaining User +Location</a>.</p> + </li> </ul> @@ -224,8 +241,8 @@ After the user finishes taking a picture (or cancels the operation), the user in your application, and you must intercept the {@link android.app.Activity#onActivityResult(int, int, android.content.Intent) onActivityResult()} method to receive the result of the intent and continue your application execution. For information -on how to receive the completed intent, see <a href="#intent-receive">Receiving Camera Intent -Result</a>.</p> +on how to receive the completed intent, see <a href="#intent-receive">Receiving camera intent +result</a>.</p> <h3 id="intent-video">Video capture intent</h3> @@ -360,8 +377,8 @@ properly release it for use by other applications.</li> <p>Camera hardware is a shared resource that must be carefully managed so your application does not collide with other applications that may also want to use it. The following sections discusses -how to detect camera hardware, how to request access to a camera and how to release it when your -application is done using it.</p> +how to detect camera hardware, how to request access to a camera, how to capture pictures or video +and how to release the camera when your application is done using it.</p> <p class="caution"><strong>Caution:</strong> Remember to release the {@link android.hardware.Camera} object by calling the {@link android.hardware.Camera#release() Camera.release()} when your @@ -492,7 +509,8 @@ public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback // ignore: tried to stop a non-existent preview } - // make any resize, rotate or reformatting changes here + // set preview size and make any resize, rotate or + // reformatting changes here // start preview with new settings try { @@ -506,6 +524,12 @@ public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback } </pre> +<p>If you want to set a specific size for your camera preview, set this in the {@code +surfaceChanged()} method as noted in the comments above. When setting preview size, you +<em>must use</em> values from {@link android.hardware.Camera.Parameters#getSupportedPreviewSizes}. +<em>Do not</em> set arbitrary values in the {@link +android.hardware.Camera.Parameters#setPreviewSize setPreviewSize()} method.</p> + <h3 id="preview-layout">Placing preview in a layout</h3> <p>A camera preview class, such as the example shown in the previous section, must be placed in the @@ -780,6 +804,10 @@ without creating a camera preview first and skip the first few steps of this pro since users typically prefer to see a preview before starting a recording, that process is not discussed here.</p> +<p class="note"><strong>Tip:</strong> If your application is typically used for recording video, set +{@link android.hardware.Camera.Parameters#setRecordingHint} to {@code true} prior to starting your +preview. This setting can help reduce the time it takes to start recording.</p> + <h4 id="configuring-mediarecorder">Configuring MediaRecorder</h4> <p>When using the {@link android.media.MediaRecorder} class to record video, you must perform configuration steps in a <em>specific order</em> and then call the {@link @@ -851,7 +879,7 @@ setAudioChannels()}</li> <li>{@link android.media.MediaRecorder#setAudioSamplingRate(int) setAudioSamplingRate()}</li> </ul> -<h4 id="start-stop-mediarecorder">Starting and Stopping MediaRecorder</h4> +<h4 id="start-stop-mediarecorder">Starting and stopping MediaRecorder</h4> <p>When starting and stopping video recording using the {@link android.media.MediaRecorder} class, you must follow a specific order, as listed below.</p> @@ -938,7 +966,7 @@ public class CameraActivity extends Activity { private MediaRecorder mMediaRecorder; ... - + @Override protected void onPause() { super.onPause(); @@ -1052,4 +1080,425 @@ instead. For more information, see <a href="{@docRoot}guide/topics/data/data-storage.html#SavingSharedFiles">Saving Shared Files</a>.</p> <p>For more information about saving files on an Android device, see <a -href="{@docRoot}guide/topics/data/data-storage.html">Data Storage</a>.</p>
\ No newline at end of file +href="{@docRoot}guide/topics/data/data-storage.html">Data Storage</a>.</p> + + +<h2 id="camera-features">Camera Features</h2> +<p>Android supports a wide array of camera features you can control with your camera application, +such as picture format, flash mode, focus settings, and many more. This section lists the common +camera features, and briefly discusses how to use them. Most camera features can be accessed and set +using the through {@link android.hardware.Camera.Parameters} object. However, there are several +important features that require more than simple settings in {@link +android.hardware.Camera.Parameters}. These features are covered in the following sections:<p> + +<ul> + <li><a href="#metering-focus-areas">Metering and focus areas</a></li> + <li><a href="#face-detection">Face detection</a></li> + <li><a href="#time-lapse-video">Time lapse video</a></li> +</ul> + +<p>For general information about how to use features that are controlled through {@link +android.hardware.Camera.Parameters}, review the <a href="#using-features">Using camera +features</a> section. For more detailed information about how to use features controlled through the +camera parameters object, follow the links in the feature list below to the API reference +documentation.</p> + +<p class="table-caption" id="table1"> + <strong>Table 1.</strong> Common camera features sorted by the Android API Level in which they +were introduced.</p> +<table> + <tr> + <th>Feature</th> <th>API Level</th> <th>Description</th> + </tr> + <tr> + <td><a href="#face-detection">Face Detection</a></td> + <td>14</td> + <td>Identify human faces within a picture and use them for focus, metering and white +balance</td> + </tr> + <tr> + <td><a href="#metering-focus-areas">Metering Areas</a></td> + <td>14</td> + <td>Specify one or more areas within an image for calculating white balance</td> + </tr> + <tr> + <td><a href="#metering-focus-areas">Focus Areas</a></td> + <td>14</td> + <td>Set one or more areas within an image to use for focus</td> + </tr> + <tr> + <td>{@link android.hardware.Camera.Parameters#setAutoWhiteBalanceLock White Balance Lock}</td> + <td>14</td> + <td>Stop or start automatic white balance adjustments</td> + </tr> + <tr> + <td>{@link android.hardware.Camera.Parameters#setAutoExposureLock Exposure Lock}</td> + <td>14</td> + <td>Stop or start automatic exposure adjustments</td> + </tr> + <tr> + <td>{@link android.hardware.Camera#takePicture Video Snapshot}</td> + <td>14</td> + <td>Take a picture while shooting video (frame grab)</td> + </tr> + <tr> + <td><a href="#time-lapse-video">Time Lapse Video</a></td> + <td>11</td> + <td>Record frames with set delays to record a time lapse video</td> + </tr> + <tr> + <td>{@link android.hardware.Camera#open(int) Multiple Cameras}</td> + <td>9</td> + <td>Support for more than one camera on a device, including front-facing and back-facing +cameras</td> + </tr> + <tr> + <td>{@link android.hardware.Camera.Parameters#getFocusDistances Focus Distance}</td> + <td>9</td> + <td>Reports distances between the camera and objects that appear to be in focus</td> + </tr> + <tr> + <td>{@link android.hardware.Camera.Parameters#setZoom Zoom}</td> + <td>8</td> + <td>Set image magnification</td> + </tr> + <tr> + <td>{@link android.hardware.Camera.Parameters#setExposureCompensation Exposure +Compensation}</td> + <td>8</td> + <td>Increase or decrease the light exposure level</td> + </tr> + <tr> + <td>{@link android.hardware.Camera.Parameters#setGpsLatitude GPS Data}</td> + <td>5</td> + <td>Include or omit geographic location data with the image</td> + </tr> + <tr> + <td>{@link android.hardware.Camera.Parameters#setWhiteBalance White Balance}</td> + <td>5</td> + <td>Set the white balance mode, which affects color values in the captured image</td> + </tr> + <tr> + <td>{@link android.hardware.Camera.Parameters#setFocusMode Focus Mode}</td> + <td>5</td> + <td>Set how the camera focuses on a subject such as automatic, fixed, macro or infinity</td> + </tr> + <tr> + <td>{@link android.hardware.Camera.Parameters#setSceneMode Scene Mode}</td> + <td>5</td> + <td>Apply a preset mode for specific types of photography situations such as night, beach, snow +or candlelight scenes</td> + </tr> + <tr> + <td>{@link android.hardware.Camera.Parameters#setJpegQuality JPEG Quality}</td> + <td>5</td> + <td>Set the compression level for a JPEG image, which increases or decreases image output file +quality and size</td> + </tr> + <tr> + <td>{@link android.hardware.Camera.Parameters#setFlashMode Flash Mode}</td> + <td>5</td> + <td>Turn flash on, off, or use automatic setting</td> + </tr> + <tr> + <td>{@link android.hardware.Camera.Parameters#setColorEffect Color Effects}</td> + <td>5</td> + <td>Apply a color effect to the captured image such as black and white, sepia tone or negative. +</td> + </tr> + <tr> + <td>{@link android.hardware.Camera.Parameters#setAntibanding Anti-Banding}</td> + <td>5</td> + <td>Reduces the effect of banding in color gradients due to JPEG compression</td> + </tr> + <tr> + <td>{@link android.hardware.Camera.Parameters#setPictureFormat Picture Format}</td> + <td>1</td> + <td>Specify the file format for the picture</td> + </tr> + <tr> + <td>{@link android.hardware.Camera.Parameters#setPictureSize Picture Size}</td> + <td>1</td> + <td>Specify the pixel dimensions of the saved picture</td> + </tr> +</table> + +<p class="note"><strong>Note:</strong> These features are not supported on all devices due to +hardware differences and software implementation. For information on checking the availability +of features on the device where your application is running, see <a href="#check-feature">Checking +feature availability</a>.</p> + + +<h3 id="check-feature">Checking feature availability</h3> +<p>The first thing to understand when setting out to use camera features on Android devices is that +not all camera features are supported on all devices. In addition, devices that support a particular +feature may support them to different levels or with different options. Therefore, part of your +decision process as you develop a camera application is to decide what camera features you want to +support and to what level. After making that decision, you should plan on including code in your +camera application that checks to see if device hardware supports those features and fails +gracefully if a feature is not available.</p> + +<p>You can check the availabilty of camera features by getting an instance of a camera’s parameters +object, and checking the relevant methods. The following code sample shows you how to obtain a +{@link android.hardware.Camera.Parameters} object and check if the camera supports the autofocus +feature:</p> + +<pre> +// get Camera parameters +Camera.Parameters params = mCamera.getParameters(); + +List<String> focusModes = params.getSupportedFocusModes(); +if (focusModes.contains(Camera.Parameters.FOCUS_MODE_AUTO)) { + // Autofocus mode is supported +} +</pre> + +<p>You can use the technique shown above for most camera features. The +{@link android.hardware.Camera.Parameters} object provides a {@code getSupported...()}, {@code +is...Supported()} or {@code getMax...()} method to determine if (and to what extent) a feature is +supported.</p> + +<p>If your application requires certain camera features in order to function properly, you can +require them through additions to your application manifest. When you declare the use of specific +camera features, such as flash and auto-focus, the Android Market restricts your application from +being installed on devices which do not support these features. For a list of camera features that +can be declared in your app manifest, see the manifest +<a href="{@docRoot}guide/topics/manifest/uses-feature-element.html#hw-features"> Features +Reference</a>.</p> + +<h3 id="using-features">Using camera features</h3> +<p>Most camera features are activated and controlled using a {@link +android.hardware.Camera.Parameters} object. You obtain this object by first getting an instance of +the {@link android.hardware.Camera} object, calling the {@link +android.hardware.Camera#getParameters getParameters()} method, changing the returned parameter +object and then setting it back into the camera object, as demonstrated in the following example +code:</p> + +<pre> +// get Camera parameters +Camera.Parameters params = mCamera.getParameters(); +// set the focus mode +params.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO); +// set Camera parameters +mCamera.setParameters(params); +</pre> + +<p>This technique works for nearly all camera features, and most parameters can be changed at any +time after you have obtained an instance of the {@link android.hardware.Camera} object. Changes to +parameters are typically visible to the user immediately in the application’s camera preview. +On the software side, parameter changes may take several frames to actually take effect as the +camera hardware processes the new instructions and then sends updated image data.</p> + +<p class="caution"><strong>Important:</strong> Some camera features cannot be changed at will. In +particular, changing the size or orientation of the camera preview requires that you first stop the +preview, change the preview size, and then restart the preview. Starting with Android 4.0 (API +Level 14) preview orientation can be changed without restarting the preview.</p> + +<p>Other camera features require more code in order to implement, including:</p> +<ul> + <li>Metering and focus areas</li> + <li>Face detection</li> + <li>Time lapse video</li> +</ul> +<p>A quick outline of how to implement these features is provided in the following sections.</p> + + +<h3 id="metering-focus-areas">Metering and focus areas</h3> +<p>In some photographic scenarios, automatic focusing and light metering may not produce the +desired results. Starting with Android 4.0 (API Level 14), your camera application can provide +additional controls to allow your app or users to specify areas in an image to use for determining +focus or light level settings and pass these values to the camera hardware for use in capturing +images or video.</p> + +<p>Areas for metering and focus work very similarly to other camera features, in that you control +them through methods in the {@link android.hardware.Camera.Parameters} object. The following code +demonstrates setting two light metering areas for an instance of +{@link android.hardware.Camera}:</p> + +<pre> +// Create an instance of Camera +mCamera = getCameraInstance(); + +// set Camera parameters +Camera.Parameters params = mCamera.getParameters(); + +if (params.getMaxNumMeteringAreas() > 0){ // check that metering areas are supported + List<Camera.Area> meteringAreas = new ArrayList<Camera.Area>(); + + Rect areaRect1 = new Rect(-100, -100, 100, 100); // specify an area in center of image + meteringAreas.add(new Camera.Area(areaRect1, 600)); // set weight to 60% + Rect areaRect2 = new Rect(800, -1000, 1000, -800); // specify an area in upper right of image + meteringAreas.add(new Camera.Area(areaRect2, 400)); // set weight to 40% + params.setMeteringAreas(meteringAreas); +} + +mCamera.setParameters(params); +</pre> + +<p>The {@link android.hardware.Camera.Area} object contains two data parameters: A {@link +android.graphics.Rect} object for specifying an area within the camera’s field of view and a weight +value, which tells the camera what level of importance this area should be given in light metering +or focus calculations.</p> + +<p>The {@link android.graphics.Rect} field in a {@link android.hardware.Camera.Area} object +describes a rectangular shape mapped on a 2000 x 2000 unit grid. The coordinates -1000, -1000 +represent the top, left corner of the camera image, and coordinates 1000, 1000 represent the +bottom, right corner of the camera image, as shown in the illustration below.</p> + +<img src='images/camera-area-coordinates.png' /> +<p class="img-caption"> + <strong>Figure 1.</strong> The red lines illustrate the coordinate system for specifying a +{@link android.hardware.Camera.Area} within a camera preview. The blue box shows the location and +shape of an camera area with the {@link android.graphics.Rect} values 333,333,667,667. +</p> + +<p>The bounds of this coordinate system always correspond to the outer edge of the image visible in +the camera preview and do not shrink or expand with the zoom level. Similarly, rotation of the image +preview using {@link android.hardware.Camera#setDisplayOrientation Camera.setDisplayOrientation()} +does not remap the coordinate system.</p> + + +<h3 id="face-detection">Face detection</h3> +<p>For pictures that include people, faces are usually the most important part of the picture, and +should be used for determining both focus and white balance when capturing an image. The Android 4.0 +(API Level 14) framework provides APIs for identifying faces and calculating picture settings using +face recognition technology.</p> + +<p class="note"><strong>Note:</strong> While the face detection feature is running, +{@link android.hardware.Camera.Parameters#setWhiteBalance}, +{@link android.hardware.Camera.Parameters#setFocusAreas} and +{@link android.hardware.Camera.Parameters#setMeteringAreas} have no effect.</p> + +<p>Using the face detection feature in your camera application requires a few general steps:</p> +<ul> + <li>Check that face detection is supported on the device</li> + <li>Create a face detection listener</li> + <li>Add the face detection listener to your camera object</li> + <li>Start face detection after preview (and after <em>every</em> preview restart)</li> +</ul> + +<p>The face detection feature is not supported on all devices. You can check that this feature is +supported by calling {@link android.hardware.Camera.Parameters#getMaxNumDetectedFaces}. An +example of this check is shown in the {@code startFaceDetection()} sample method below.</p> + +<p>In order to be notified and respond to the detection of a face, your camera application must set +a listener for face detection events. In order to do this, you must create a listener class that +implements the {@link android.hardware.Camera.FaceDetectionListener} interface as shown in the +example code below.</p> + +<pre> +class MyFaceDetectionListener implements Camera.FaceDetectionListener { + + @Override + public void onFaceDetection(Face[] faces, Camera camera) { + if (faces.length > 0){ + Log.d("FaceDetection", "face detected: "+ faces.length + + " Face 1 Location X: " + faces[0].rect.centerX() + + "Y: " + faces[0].rect.centerY() ); + } + } +} +</pre> + +<p>After creating this class, you then set it into your application’s +{@link android.hardware.Camera} object, as shown in the example code below:</p> + +<pre> +mCamera.setFaceDetectionListener(new MyFaceDetectionListener()); +</pre> + +<p>Your application must start the face detection function each time you start (or restart) the +camera preview. Create a method for starting face detection so you can call it as needed, as shown +in the example code below.</p> + +<pre> +public void startFaceDetection(){ + // Try starting Face Detection + Camera.Parameters params = mCamera.getParameters(); + + // start face detection only *after* preview has started + if (params.getMaxNumDetectedFaces() > 0){ + // camera supports face detection, so can start it: + mCamera.startFaceDetection(); + } +} +</pre> + +<p>You must start face detection <em>each time</em> you start (or restart) the camera preview. If +you use the preview class shown in <a href="#camera-preview">Creating a preview class</a>, add your +{@link android.hardware.Camera#startFaceDetection startFaceDetection()} method to both the +{@link android.view.SurfaceHolder.Callback#surfaceCreated surfaceCreated()} and {@link +android.view.SurfaceHolder.Callback#surfaceChanged surfaceChanged()} methods in your preview class, +as shown in the sample code below.</p> + +<pre> +public void surfaceCreated(SurfaceHolder holder) { + try { + mCamera.setPreviewDisplay(holder); + mCamera.startPreview(); + + startFaceDetection(); // start face detection feature + + } catch (IOException e) { + Log.d(TAG, "Error setting camera preview: " + e.getMessage()); + } +} + +public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { + + if (mHolder.getSurface() == null){ + // preview surface does not exist + Log.d(TAG, "mHolder.getSurface() == null"); + return; + } + + try { + mCamera.stopPreview(); + + } catch (Exception e){ + // ignore: tried to stop a non-existent preview + Log.d(TAG, "Error stopping camera preview: " + e.getMessage()); + } + + try { + mCamera.setPreviewDisplay(mHolder); + mCamera.startPreview(); + + startFaceDetection(); // re-start face detection feature + + } catch (Exception e){ + // ignore: tried to stop a non-existent preview + Log.d(TAG, "Error starting camera preview: " + e.getMessage()); + } +} +</pre> + +<p class="note"><strong>Note:</strong> Remember to call this method <em>after</em> calling +{@link android.hardware.Camera#startPreview startPreview()}. Do not attempt to start face detection +in the {@link android.app.Activity#onCreate onCreate()} method of your camera app’s main activity, +as the preview is not available by this point in your application's the execution.</p> + + +<h3 id="time-lapse-video">Time lapse video</h3> +<p>Time lapse video allows users to create video clips that combine pictures taken a few seconds or +minutes apart. This feature uses {@link android.media.MediaRecorder} to record the images for a time +lapse sequence. </p> + +<p>To record a time lapse video with {@link android.media.MediaRecorder}, you must configure the +recorder object as if you are recording a normal video, setting the captured frames per second to a +low number and using one of the time lapse quality settings, as shown in the code example below.</p> + +<pre> +// Step 3: Set a CamcorderProfile (requires API Level 8 or higher) +mMediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_TIME_LAPSE_HIGH)); +... +// Step 5.5: Set the video capture rate to a low number +mMediaRecorder.setCaptureRate(0.1); // capture a frame every 10 seconds +</pre> + +<p>These settings must be done as part of a larger configuration procedure for {@link +android.media.MediaRecorder}. For a full configuration code example, see <a +href="#configuring-mediarecorder">Configuring MediaRecorder</a>. Once the configuration is complete, +you start the video recording as if you were recording a normal video clip. For more information +about configuring and running {@link android.media.MediaRecorder}, see <a +href="#capture-video">Capturing videos</a>.</p> diff --git a/docs/html/guide/topics/media/images/camera-area-coordinates.png b/docs/html/guide/topics/media/images/camera-area-coordinates.png Binary files differnew file mode 100644 index 000000000000..9876453921c8 --- /dev/null +++ b/docs/html/guide/topics/media/images/camera-area-coordinates.png diff --git a/docs/html/guide/topics/media/index.jd b/docs/html/guide/topics/media/index.jd index 7c1754feb94f..0e0412a10d52 100644 --- a/docs/html/guide/topics/media/index.jd +++ b/docs/html/guide/topics/media/index.jd @@ -6,7 +6,7 @@ page.title=Multimedia and Camera <h2>Topics</h2> <ol> -<li><a href="{@docRoot}guide/topics/media/mediaplayer.html">MediaPlayer</a></li> +<li><a href="{@docRoot}guide/topics/media/mediaplayer.html">Media Playback</a></li> <li><a href="{@docRoot}guide/topics/media/jetplayer.html">JetPlayer</a></li> <li><a href="{@docRoot}guide/topics/media/camera.html">Camera</a></li> <li><a href="{@docRoot}guide/topics/media/audio-capture.html">Audio Capture</a></li> @@ -46,7 +46,8 @@ hardware.</p> and playback.</p> <dl> - <dt><strong><a href="{@docRoot}guide/topics/media/mediaplayer.html">MediaPlayer</a></strong></dt> + <dt><strong><a href="{@docRoot}guide/topics/media/mediaplayer.html">Media Playback</a></strong> + </dt> <dd>How to play audio and video in your application.</dd> <dt><strong><a href="{@docRoot}guide/topics/media/jetplayer.html">JetPlayer</a></strong></dt> diff --git a/docs/html/guide/topics/providers/calendar-provider.jd b/docs/html/guide/topics/providers/calendar-provider.jd index 3ab51259a518..d30dda423ec5 100644 --- a/docs/html/guide/topics/providers/calendar-provider.jd +++ b/docs/html/guide/topics/providers/calendar-provider.jd @@ -280,11 +280,9 @@ Calendars.ACCOUNT_NAME}, you must also include {@link android.provider.CalendarContract.Calendars#ACCOUNT_TYPE Calendars.ACCOUNT_TYPE} in the selection. That is because a given account is only considered unique given both its <code>ACCOUNT_NAME</code> and its -<code>ACCOUNT_TYPE</code>. The <code>ACCOUNT_TYPE</code> refers to the way that -the account is being synced. It is often but not always the domain. For -example, an account could be synced through a corporate pop3 sync adapter, in which -case the <code>ACCOUNT_TYPE</code> would not be a domain. There is also a -special type of account called {@link +<code>ACCOUNT_TYPE</code>. The <code>ACCOUNT_TYPE</code> is the string corresponding to the +account authenticator that was used when the account was registered with the +{@link android.accounts.AccountManager}. There is also a special type of account called {@link android.provider.CalendarContract#ACCOUNT_TYPE_LOCAL} for calendars not associated with a device account. {@link android.provider.CalendarContract#ACCOUNT_TYPE_LOCAL} accounts do not get diff --git a/docs/html/guide/topics/renderscript/index.jd b/docs/html/guide/topics/renderscript/index.jd index eb773109e427..148705cfbca1 100644 --- a/docs/html/guide/topics/renderscript/index.jd +++ b/docs/html/guide/topics/renderscript/index.jd @@ -151,10 +151,9 @@ page.title=RenderScript defining two-, three-, or four-vectors.</li> </ul> - <p>The <a href="{@docRoot}guide/topics/renderscript/rs-api/files.html">RenderScript header files</a> - and LLVM front-end libraries are located in the <code>include</code> and - <code>clang-include</code> directories in the - <code><sdk_root>/platforms/android-11/renderscript</code> directory of the Android SDK. The + <p>The RenderScript header files and LLVM front-end libraries are located in the <code>include/</code> and + <code>clang-include/</code> directories in the + <code><sdk_root>/platforms/android-11/renderscript/</code> directory of the Android SDK. The headers are automatically included for you, except for the RenderScript graphics specific header file, which you can include as follows:</p> <pre> diff --git a/docs/html/guide/topics/ui/menus.jd b/docs/html/guide/topics/ui/menus.jd index 29482444d8e8..7b5b3dc2f3c1 100644 --- a/docs/html/guide/topics/ui/menus.jd +++ b/docs/html/guide/topics/ui/menus.jd @@ -198,10 +198,11 @@ public boolean onCreateOptionsMenu(Menu menu) { } </pre> -<div class="figure" style="width:500px"> -<img src="{@docRoot}images/ui/actionbar.png" height="34" alt="" /> -<p class="img-caption"><strong>Figure 2.</strong> Screenshot of the Action Bar in the Email -application, with two action items from the Options Menu, plus the overflow menu.</p> +<div class="figure" style="width:450px"> +<img src="{@docRoot}images/ui/actionbar.png" alt="" /> +<p class="img-caption"><strong>Figure 2.</strong> Action bar from the <a +href="{@docRoot}resources/samples/HoneycombGallery/index.html">Honeycomb Gallery</a> app, including +navigation tabs and a camera action item (plus the overflow menu button).</p> </div> <p>You can also populate the menu in code, using {@link android.view.Menu#add(int,int,int,int) diff --git a/docs/html/images/billing_list_form_2.png b/docs/html/images/billing_list_form_2.png Binary files differnew file mode 100755 index 000000000000..d321a2068a09 --- /dev/null +++ b/docs/html/images/billing_list_form_2.png diff --git a/docs/html/images/billing_product_list.png b/docs/html/images/billing_product_list.png Binary files differindex 49a7e796817e..a89f21b53b35 100755 --- a/docs/html/images/billing_product_list.png +++ b/docs/html/images/billing_product_list.png diff --git a/docs/html/resources/dashboard/opengl.jd b/docs/html/resources/dashboard/opengl.jd index 07a0e431a807..4d0abeceac61 100644 --- a/docs/html/resources/dashboard/opengl.jd +++ b/docs/html/resources/dashboard/opengl.jd @@ -57,7 +57,7 @@ ending on the data collection date noted below.</p> <div class="dashboard-panel"> <img alt="" width="400" height="250" -src="http://chart.googleapis.com/chart?cht=p&chs=400x250&chco=c4df9b,6fad0c&chl=GL%201.1|GL%202.0%20%26%201.1&chd=t%3A9.8,90.2" /> +src="http://chart.googleapis.com/chart?cht=p&chs=400x250&chco=c4df9b,6fad0c&chl=GL%201.1|GL%202.0%20%26%201.1&chd=t%3A10.1,89.9" /> <table> <tr> @@ -66,14 +66,14 @@ src="http://chart.googleapis.com/chart?cht=p&chs=400x250&chco=c4df9b,6fad0c&chl= </tr> <tr> <td>1.1</th> -<td>9.8%</td> +<td>10.1%</td> </tr> <tr> <td>2.0</th> -<td>90.2%</td> +<td>89.9%</td> </tr> </table> -<p><em>Data collected during a 7-day period ending on November 3, 2011</em></p> +<p><em>Data collected during a 7-day period ending on December 1, 2011</em></p> </div> diff --git a/docs/html/resources/dashboard/platform-versions.jd b/docs/html/resources/dashboard/platform-versions.jd index 8041096b21cf..72370bb4ead8 100644 --- a/docs/html/resources/dashboard/platform-versions.jd +++ b/docs/html/resources/dashboard/platform-versions.jd @@ -52,7 +52,7 @@ Android Market within a 14-day period ending on the data collection date noted b <div class="dashboard-panel"> <img alt="" height="250" width="470" -src="http://chart.apis.google.com/chart?&cht=p&chs=460x250&chd=t:0.9,1.4,10.7,40.7,0.5,43.9,0.1,0.9,0.9&chl=Android%201.5|Android%201.6|Android%202.1|Android%202.2|Android%202.3|Android%202.3.3|Android%203.0|Android%203.1|Android%203.2&chco=c4df9b,6fad0c" /> +src="http://chart.apis.google.com/chart?&cht=p&chs=460x250&chd=t:0.8,1.3,9.6,35.3,0.5,50.1,0.1,1.1,1.2&chl=Android%201.5|Android%201.6|Android%202.1|Android%202.2|Android%202.3|Android%202.3.3|Android%203.0|Android%203.1|Android%203.2&chco=c4df9b,6fad0c" /> <table> <tr> @@ -61,21 +61,21 @@ src="http://chart.apis.google.com/chart?&cht=p&chs=460x250&chd=t:0.9,1.4,10.7,40 <th>API Level</th> <th>Distribution</th> </tr> -<tr><td><a href="{@docRoot}sdk/android-1.5.html">Android 1.5</a></td><td>Cupcake</td> <td>3</td><td>0.9%</td></tr> -<tr><td><a href="{@docRoot}sdk/android-1.6.html">Android 1.6</a></td><td>Donut</td> <td>4</td><td>1.4%</td></tr> -<tr><td><a href="{@docRoot}sdk/android-2.1.html">Android 2.1</a></td><td>Eclair</td> <td>7</td><td>10.7%</td></tr> -<tr><td><a href="{@docRoot}sdk/android-2.2.html">Android 2.2</a></td><td>Froyo</td> <td>8</td><td>40.7%</td></tr> +<tr><td><a href="{@docRoot}sdk/android-1.5.html">Android 1.5</a></td><td>Cupcake</td> <td>3</td><td>0.8%</td></tr> +<tr><td><a href="{@docRoot}sdk/android-1.6.html">Android 1.6</a></td><td>Donut</td> <td>4</td><td>1.3%</td></tr> +<tr><td><a href="{@docRoot}sdk/android-2.1.html">Android 2.1</a></td><td>Eclair</td> <td>7</td><td>9.6%</td></tr> +<tr><td><a href="{@docRoot}sdk/android-2.2.html">Android 2.2</a></td><td>Froyo</td> <td>8</td><td>35.3%</td></tr> <tr><td><a href="{@docRoot}sdk/android-2.3.html">Android 2.3 -<br/> Android 2.3.2</a></td><td rowspan="2">Gingerbread</td> <td>9</td><td>0.5%</td></tr> <tr><td><a href="{@docRoot}sdk/android-2.3.3.html">Android 2.3.3 -<br/> - Android 2.3.7</a></td><!-- Gingerbread --> <td>10</td><td>43.9%</td></tr> + Android 2.3.7</a></td><!-- Gingerbread --> <td>10</td><td>50.1%</td></tr> <tr><td><a href="{@docRoot}sdk/android-3.0.html">Android 3.0</a></td> <td rowspan="3">Honeycomb</td> <td>11</td><td>0.1%</td></tr> -<tr><td><a href="{@docRoot}sdk/android-3.1.html">Android 3.1</a></td><!-- Honeycomb --><td>12</td><td>0.9%</td></tr> -<tr><td><a href="{@docRoot}sdk/android-3.2.html">Android 3.2</a></td><!-- Honeycomb --><td>13</td><td>0.9%</td></tr> +<tr><td><a href="{@docRoot}sdk/android-3.1.html">Android 3.1</a></td><!-- Honeycomb --><td>12</td><td>1.1%</td></tr> +<tr><td><a href="{@docRoot}sdk/android-3.2.html">Android 3.2</a></td><!-- Honeycomb --><td>13</td><td>1.2%</td></tr> </table> -<p><em>Data collected during a 14-day period ending on November 3, 2011</em></p> +<p><em>Data collected during a 14-day period ending on December 1, 2011</em></p> <!-- <p style="font-size:.9em">* <em>Other: 0.1% of devices running obsolete versions</em></p> --> @@ -104,9 +104,9 @@ Android Market within a 14-day period ending on the date indicated on the x-axis <div class="dashboard-panel"> <img alt="" height="250" width="660" style="padding:5px;background:#fff" -src="http://chart.apis.google.com/chart?&cht=lc&chs=660x250&chxt=x,x,y,r&chxr=0,0,12|1,0,12|2,0,100|3,0,100&chxl=0%3A%7C05/01%7C05/15%7C06/01%7C06/15%7C07/01%7C07/15%7C08/01%7C08/15%7C09/01%7C09/15%7C10/01%7C10/15%7C11/01%7C1%3A%7C2011%7C%7C%7C%7C%7C%7C%7C%7C%7C%7C%7C%7C2011%7C2%3A%7C0%25%7C25%25%7C50%25%7C75%25%7C100%25%7C3%3A%7C0%25%7C25%25%7C50%25%7C75%25%7C100%25&chxp=0,0,1,2,3,4,5,6,7,8,9,10,11,12&chxtc=0,5&chd=t:99.6,99.5,99.4,99.3,99.2,99.0,98.8,98.7,98.5,98.5,98.2,98.1,98.0|97.3,97.5,97.5,97.5,97.7,97.6,97.5,97.5,97.5,97.5,97.1,97.1,97.1|94.3,94.8,95.0,95.2,95.5,95.5,95.5,95.6,95.7,95.8,95.6,95.9,95.7|69.8,71.5,73.9,75.4,77.6,79.0,80.2,81.1,82.4,83.3,83.8,84.9,85.0|4.0,6.1,9.5,13.6,17.8,20.6,24.3,27.5,31.2,34.7,38.3,41.3,44.0|3.0,5.1,8.4,12.6,16.8,20.0,23.7,26.9,30.6,34.1,37.8,40.8,43.5&chm=b,c3df9b,0,1,0|b,b4db77,1,2,0|tAndroid 2.1,547a19,2,0,15,,t::-5|b,a5db51,2,3,0|tAndroid 2.2,3f5e0e,3,0,15,,t::-5|b,96dd28,3,4,0|b,83c916,4,5,0|tAndroid 2.3.3,131d02,5,3,15,,t::-5|B,6fad0c,5,6,0&chg=7,25&chdl=Android 1.5|Android 1.6|Android 2.1|Android 2.2|Android 2.3|Android 2.3.3&chco=add274,9dd14f,8ece2a,7ab61c,659b11,507d08" /> +src="http://chart.apis.google.com/chart?&cht=lc&chs=660x250&chxt=x,x,y,r&chxr=0,0,12|1,0,12|2,0,100|3,0,100&chxl=0%3A|06/01|06/15|07/01|07/15|08/01|08/15|09/01|09/15|10/01|10/15|11/01|11/15|12/01|1%3A|2011||||||||||||2011|2%3A|0%25|25%25|50%25|75%25|100%25|3%3A|0%25|25%25|50%25|75%25|100%25&chxp=0,0,1,2,3,4,5,6,7,8,9,10,11,12&chxtc=0,5&chd=t:99.4,99.3,99.2,99.0,98.8,98.7,98.5,98.5,98.2,98.1,98.0,99.9,99.9|97.5,97.5,97.7,97.6,97.5,97.5,97.5,97.5,97.1,97.1,97.0,99.1,99.1|95.0,95.2,95.5,95.5,95.5,95.6,95.7,95.8,95.6,95.9,95.7,97.7,97.8|73.9,75.4,77.6,79.0,80.2,81.1,82.4,83.3,83.8,84.9,85.1,87.5,88.2|9.5,13.6,17.8,20.6,24.3,27.5,31.2,34.7,38.3,41.3,44.0,48.9,52.9|8.4,12.6,16.8,20.0,23.7,26.9,30.6,34.1,37.8,40.8,43.5,48.4,52.4|0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.0,2.3|0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0,1.2&chm=b,c3df9b,0,1,0|b,b8dc82,1,2,0|tAndroid%202.1,608920,2,0,15,,t::-5|b,addb67,2,3,0|tAndroid%202.2,517617,3,0,15,,t::-5|b,a3db4b,3,4,0|b,98dc2e,4,5,0|tAndroid%202.3.3,334d0a,5,1,15,,t::-5|b,8cd41b,5,6,0|b,7ec113,6,7,0|B,6fad0c,7,8,0&chg=7,25&chdl=Android%201.5|Android%201.6|Android%202.1|Android%202.2|Android%202.3|Android%202.3.3|Android%203.1|Android%203.2&chco=add274,a2d15a,97d13e,8bcb28,7dba1e,6ea715,5f920e,507d08" /> -<p><em>Last historical dataset collected during a 14-day period ending on November 3, 2011</em></p> +<p><em>Last historical dataset collected during a 14-day period ending on December 1, 2011</em></p> </div><!-- end dashboard-panel --> diff --git a/docs/html/resources/dashboard/screens.jd b/docs/html/resources/dashboard/screens.jd index ec3034dbcfc2..79d59d91aa7b 100644 --- a/docs/html/resources/dashboard/screens.jd +++ b/docs/html/resources/dashboard/screens.jd @@ -60,7 +60,7 @@ ending on the data collection date noted below.</p> <div class="dashboard-panel"> <img alt="" width="400" height="250" -src="http://chart.googleapis.com/chart?cht=p&chs=400x250&chco=c4df9b,6fad0c&chl=Xlarge%20/%20mdpi|Large%20/%20ldpi|Large%20/%20mdpi|Normal%20/%20hdpi|Normal%20/%20ldpi|Normal%20/%20mdpi|Small%20/%20hdpi|Small%20/%20ldpi&chd=t%3A2.9,0.1,3.1,70.8,1.0,17.7,3.0,1.3" /> +src="http://chart.googleapis.com/chart?cht=p&chs=400x250&chco=c4df9b,6fad0c&chl=Xlarge%20/%20mdpi|Large%20/%20ldpi|Large%20/%20mdpi|Normal%20/%20hdpi|Normal%20/%20ldpi|Normal%20/%20mdpi|Small%20/%20hdpi|Small%20/%20ldpi&chd=t%3A3.1,0.1,3.1,71.0,1.0,17.5,2.9,1.3" /> <table> <tr> @@ -73,13 +73,13 @@ src="http://chart.googleapis.com/chart?cht=p&chs=400x250&chco=c4df9b,6fad0c&chl= <tr><th scope="row">small</th> <td>1.3%</td> <!-- small/ldpi --> <td></td> <!-- small/mdpi --> -<td>3.0%</td> <!-- small/hdpi --> +<td>2.9%</td> <!-- small/hdpi --> <td></td> <!-- small/xhdpi --> </tr> <tr><th scope="row">normal</th> <td>1.0%</td> <!-- normal/ldpi --> -<td>17.7%</td> <!-- normal/mdpi --> -<td>70.8%</td> <!-- normal/hdpi --> +<td>17.5%</td> <!-- normal/mdpi --> +<td>71%</td> <!-- normal/hdpi --> <td></td> <!-- normal/xhdpi --> </tr> <tr><th scope="row">large</th> @@ -90,12 +90,12 @@ src="http://chart.googleapis.com/chart?cht=p&chs=400x250&chco=c4df9b,6fad0c&chl= </tr> <tr><th scope="row">xlarge</th> <td></td> <!-- xlarge/ldpi --> -<td>2.9%</td> <!-- xlarge/mdpi --> +<td>3.1%</td> <!-- xlarge/mdpi --> <td></td> <!-- xlarge/hdpi --> <td></td> <!-- xlarge/xhdpi --> </tr> </table> -<p><em>Data collected during a 7-day period ending on November 3, 2011</em></p> +<p><em>Data collected during a 7-day period ending on December 1, 2011</em></p> </div> diff --git a/docs/html/resources/resources-data.js b/docs/html/resources/resources-data.js index a35e6848f1b9..18f1547d0ed9 100644 --- a/docs/html/resources/resources-data.js +++ b/docs/html/resources/resources-data.js @@ -718,6 +718,16 @@ var ANDROID_RESOURCES = [ } }, { + tags: ['sample', 'communication', 'new'], + path: 'samples/ToyVpn/index.html', + title: { + en: 'Toy VPN Client' + }, + description: { + en: 'A sample application that illustrates the creation of a custom VPN client.' + } + }, + { tags: ['sample', 'newfeature'], path: 'samples/USB/index.html', title: { diff --git a/docs/html/resources/samples/images/vpn-confirmation.png b/docs/html/resources/samples/images/vpn-confirmation.png Binary files differnew file mode 100755 index 000000000000..ae2e58332089 --- /dev/null +++ b/docs/html/resources/samples/images/vpn-confirmation.png diff --git a/docs/html/sdk/android-4.0.jd b/docs/html/sdk/android-4.0.jd index e886bdf9ff74..7161b03708b5 100644 --- a/docs/html/sdk/android-4.0.jd +++ b/docs/html/sdk/android-4.0.jd @@ -65,26 +65,42 @@ experience possible on the latest Android-powered devices.</p> <p>To determine what revision of the Android {@sdkPlatformVersion} platform you have installed, refer to the "Installed Packages" listing in the Android SDK Manager.</p> +<p class="caution"><strong>Important:</strong> To download the new Android +4.0 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 system components will not be available for download.</p> <div class="toggle-content opened" style="padding-left:1em;"> <p><a href="#" onclick="return toggleContent(this)"> <img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-content-img" alt="" /> - Android {@sdkPlatformVersion}, Revision 1</a> <em>(October 2011)</em> + Android {@sdkPlatformVersion}, Revision 2</a> <em>(December 2011)</em> </a></p> <div class="toggle-content-toggleme" style="padding-left:2em;"> + <p>Maintenance update. The system version is 4.0.2.</p> + <dl> + <dt>Dependencies:</dt> + <dd>SDK Tools r14 or higher is required.</dd> + </dl> + </div> +</div> -<dl> -<dt>Initial release. SDK Tools r14 or higher is required. - <p class="caution"><strong>Important:</strong> To download the new Android - 4.0 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 system components will not be available for download.</p> -</dt> -</dl> +<div class="toggle-content closed" style="padding-left:1em;"> + <p><a href="#" onclick="return toggleContent(this)"> + <img src="{@docRoot}assets/images/triangle-closed.png" +class="toggle-content-img" alt="" /> + Android {@sdkPlatformVersion}, Revision 1</a> <em>(October 2011)</em> + </a></p> + + <div class="toggle-content-toggleme" style="padding-left:2em;"> + <p>Initial release. The system version is 4.0.1.</p> + <dl> + <dt>Dependencies:</dt> + <dd>SDK Tools r14 or higher is required.</dd> + </dl> </div> </div> diff --git a/docs/html/sdk/eclipse-adt.jd b/docs/html/sdk/eclipse-adt.jd index 50b20cea9e64..2445bffa92a2 100644 --- a/docs/html/sdk/eclipse-adt.jd +++ b/docs/html/sdk/eclipse-adt.jd @@ -1,8 +1,8 @@ page.title=ADT Plugin for Eclipse -adt.zip.version=15.0.1 -adt.zip.download=ADT-15.0.1.zip -adt.zip.bytes=6752327 -adt.zip.checksum=2c12a71d7124aa512b8ee016e19c0e69 +adt.zip.version=16.0.0 +adt.zip.download=ADT-16.0.0.zip +adt.zip.bytes=6999205 +adt.zip.checksum=b7e512572580291279469845386b31b6 @jd:body @@ -109,18 +109,49 @@ padding: .25em 1em; </style> - <div class="toggleable opened"> <a href="#" onclick="return toggleDiv(this)"> <img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-img" height="9px" width="9px" /> +ADT 16.0.0</a> <em>(December 2011)</em> + <div class="toggleme"> +<dl> + <dt>Dependencies:</dt> + + <dd> + <ul> + <li>Eclipse Helios (Version 3.6) or higher is required for ADT +16.0.0.</li> + <li>ADT 16.0.0 is designed for use with <a +href="{@docRoot}sdk/tools-notes.html">SDK Tools r16</a>. If you haven't already installed SDK Tools +r16 into your SDK, use the Android SDK Manager to do so.</li> + </ul> + </dd> + + <dt>General improvements:</dt> + <dd> + <ul> + <li>Added Lint tools to detect common errors in Android projects. (<a +href="http://tools.android.com/recent/lint">more info</a>)</li> + </ul> + </dd> +</dl> + +</div> +</div> + + +<div class="toggleable closed"> + <a href="#" onclick="return toggleDiv(this)"> + <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-img" height="9px" +width="9px" /> ADT 15.0.1</a> <em>(November 2011)</em> <div class="toggleme"> <dl> <dt>Dependencies:</dt> <dd>ADT 15.0.1 is designed for use with <a href="{@docRoot}sdk/tools-notes.html">SDK Tools r15</a>. - If you haven't already installed SDK Tools r15 into your SDK, use the Android SDK and AVD Manager to + If you haven't already installed SDK Tools r15 into your SDK, use the Android SDK Manager to do so.</dd> <dt>Bug fixes:</dt> @@ -154,7 +185,7 @@ ADT 15.0.0</a> <em>(October 2011)</em> <dt>Dependencies:</dt> <dd>ADT 15.0.0 is designed for use with <a href="{@docRoot}sdk/tools-notes.html">SDK Tools r15</a>. -If you haven't already installed SDK Tools r15 into your SDK, use the Android SDK and AVD Manager to +If you haven't already installed SDK Tools r15 into your SDK, use the Android SDK Manager to do so.</dd> <dt>Bug fixes:</dt> @@ -185,10 +216,10 @@ ADT 14.0.0</a> <em>(October 2011)</em> <dt>Dependencies:</dt> <dd>ADT 14.0.0 is designed for use with <a href="{@docRoot}sdk/tools-notes.html">SDK Tools r14</a>. -If you haven't already installed SDK Tools r14 into your SDK, use the Android SDK and AVD Manager to +If you haven't already installed SDK Tools r14 into your SDK, use the Android SDK Manager to do so.</dd> -<dt>Build system</dt> +<dt>Build system:</dt> <dd> <ul> <li>Changed <code>default.properties</code> to <code>project.properties</code> and @@ -211,7 +242,7 @@ see the <a href="http://tools.android.com/recent/buildchangesinrevision14">Andro site</a>.</p> </dd> -<dt>General improvements</dt> +<dt>General improvements:</dt> <dd> <ul> @@ -236,7 +267,7 @@ and deleted without affecting the master copy </ul> </dd> -<dt>XML and Java editors</dt> +<dt>XML and Java editors:</dt> <dd> <ul> <li>Added a new XML formatter that formats all XML files according to the @@ -255,7 +286,7 @@ href="http://tools.android.com/recent/xmleditingimprovements">more info</a>).</l </ul> </dd> -<dt>Layout editor</dt> +<dt>Layout editor:</dt> <dd> <ul> <li>Added tooltip feedback for dragging and resizing operations. For @@ -281,7 +312,7 @@ href="http://tools.android.com/recent/layouteditorcontextmenuimprovements">more </ul> </dd> -<dt>Bug fixes</dt> +<dt>Bug fixes:</dt> <dd>Fixed many bugs and added <a href="http://tools.android.com/recent/miscellaneousrecentfixes">minor improvements</a>, in particular some <a href="http://tools.android.com/recent/linuxfixes">critical bug fixes on @@ -324,7 +355,7 @@ the Android SDK and AVD Manager to do so.</dd> </ul> </dd> -<dt>Build system</dt> +<dt>Build system:</dt> <dd> <ul> <li id="build-option">A new option lets you disable the packaging step in the automatic @@ -336,7 +367,7 @@ the Android SDK and AVD Manager to do so.</dd> </ul> </dd> -<dt>Bug fixes</dt> +<dt>Bug fixes:</dt> <dd>Many bug fixes are part of this release (<a href="http://tools.android.com/recent/adt12bugfixroundup">more info</a>).</dd> @@ -928,7 +959,7 @@ Manager to download the latest SDK Tools into your SDK. For more information, see <a href="{@docRoot}sdk/adding-components.html">Adding SDK Components</a>.</p> </dd> -<dt>General Notes:</dt> +<dt>General notes:</dt> <dd> <ul> <li>AVD Launch dialog now shows scale value.</li> @@ -974,7 +1005,7 @@ bigger than the screen.</li> </ul> </dd> -<dt>DDMS Integration:</dt> +<dt>DDMS integration:</dt> <dd> <ul> <li>Includes the improvements from the standlone DDMS, revision 3.</li> diff --git a/docs/html/sdk/index.jd b/docs/html/sdk/index.jd index 193066bab310..65a1f465c475 100644 --- a/docs/html/sdk/index.jd +++ b/docs/html/sdk/index.jd @@ -1,21 +1,21 @@ page.title=Android SDK sdk.redirect=0 -sdk.win_installer=installer_r15-windows.exe -sdk.win_installer_bytes=33902520 -sdk.win_installer_checksum=ee8481cb86a6646a4d963d5142902c5c +sdk.win_installer=installer_r16-windows.exe +sdk.win_installer_bytes=29561554 +sdk.win_installer_checksum=3521dda4904886b05980590f83cf3469 -sdk.win_download=android-sdk_r15-windows.zip -sdk.win_bytes=33895447 -sdk.win_checksum=cc2aadf7120d12b574981461736a96e9 +sdk.win_download=android-sdk_r16-windows.zip +sdk.win_bytes=29562413 +sdk.win_checksum=6b926d0c0a871f1a946e65259984701a -sdk.mac_download=android-sdk_r15-macosx.zip -sdk.mac_bytes=30469921 -sdk.mac_checksum=03d2cdd3565771e8c7a438f1c40cc8a5 +sdk.mac_download=android-sdk_r16-macosx.zip +sdk.mac_bytes=26158334 +sdk.mac_checksum=d1dc2b6f13eed5e3ce5cf26c4e4c47aa -sdk.linux_download=android-sdk_r15-linux.tgz -sdk.linux_bytes=26124434 -sdk.linux_checksum=f529681fd1eda11c6e1e1d44b42c1432 +sdk.linux_download=android-sdk_r16-linux.tgz +sdk.linux_bytes=22048174 +sdk.linux_checksum=3ba457f731d51da3741c29c8830a4583 @jd:body diff --git a/docs/html/sdk/requirements.jd b/docs/html/sdk/requirements.jd index f12d0aa68ed9..c970f6c9c0be 100644 --- a/docs/html/sdk/requirements.jd +++ b/docs/html/sdk/requirements.jd @@ -24,8 +24,8 @@ Android applications using the Android SDK. </p> <h4 style="margin-top:.25em"><em>Eclipse IDE</em></h4> <ul> - <li>Eclipse 3.5 (Galileo) or greater -<p class="note"><strong>Note:</strong> Eclipse 3.4 (Ganymede) is no longer + <li>Eclipse 3.6 (Helios) or greater +<p class="note"><strong>Note:</strong> Eclipse 3.5 (Galileo) is no longer supported with the latest version of ADT.</p></li> <li>Eclipse <a href="http://www.eclipse.org/jdt">JDT</a> plugin (included in most Eclipse IDE packages) </li> @@ -37,7 +37,7 @@ developing Android applications, we recommend that you install one of these packages: </p> <ul> <li>Eclipse IDE for Java Developers</li> - <li>Eclipse Classic (versions 3.5.1 and higher)</li> + <li>Eclipse Classic</li> <li>Eclipse IDE for Java EE Developers</li> </ul> </li> diff --git a/docs/html/sdk/sdk_toc.cs b/docs/html/sdk/sdk_toc.cs index 0ae2c6dba37b..791e7aa201f7 100644 --- a/docs/html/sdk/sdk_toc.cs +++ b/docs/html/sdk/sdk_toc.cs @@ -150,7 +150,7 @@ class="new">new!</span></li> </li> </ul> <ul> - <li><a href="<?cs var:toroot ?>sdk/tools-notes.html">SDK Tools, r15</a> <span + <li><a href="<?cs var:toroot ?>sdk/tools-notes.html">SDK Tools, r16</a> <span class="new">new!</span></li> <li><a href="<?cs var:toroot ?>sdk/win-usb.html">Google USB Driver, r4</a></li> <li><a href="<?cs var:toroot ?>sdk/compatibility-library.html">Support Package, r4</a> @@ -169,7 +169,7 @@ class="new">new!</span></li> <span style="display:none" class="zh-TW"></span> </h2> <ul> - <li><a href="<?cs var:toroot ?>sdk/eclipse-adt.html">ADT 15.0.1 + <li><a href="<?cs var:toroot ?>sdk/eclipse-adt.html">ADT 16.0.0 <span style="display:none" class="de"></span> <span style="display:none" class="es"></span> <span style="display:none" class="fr"></span> diff --git a/docs/html/sdk/tools-notes.jd b/docs/html/sdk/tools-notes.jd index cd03d9fa800d..9a63467274cb 100644 --- a/docs/html/sdk/tools-notes.jd +++ b/docs/html/sdk/tools-notes.jd @@ -9,7 +9,7 @@ href="{@docRoot}sdk/index.html">SDK starter package</a> installs the latest revision of the SDK Tools in the <code><sdk>/tools</code> directory.</p> <p>If you are already using the SDK and you want to update to the latest version -of the SDK Tools, use the <em>Android SDK and AVD Manager</em> to get the +of the SDK Tools, use the <em>Android SDK Manager</em> to get the update, rather than downloading a new SDK starter package. For more information about how to update, see <a href="{@docRoot}sdk/adding-components.html#UpdatingComponents">Updating SDK @@ -20,8 +20,7 @@ Components</a>.</p> <p>The sections below provide notes about successive releases of the SDK Tools, as denoted by revision number. To determine what revision of the SDK -Tools you are using, refer to the "Installed Packages" listing in the Android SDK -and AVD Manager. </p> +Tools you are using, refer to the "Installed Packages" listing in the Android SDK Manager. </p> <p>For a summary of all known issues in SDK Tools, see <a href="http://tools.android.com/knownissues">http://tools.android.com/knownissues</a>.</p> @@ -69,7 +68,57 @@ padding: .25em 1em; <div class="toggleable opened"> <a href="#" onclick="return toggleDiv(this)"> <img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-img" height="9px" - width="9px" />SDK Tools, Revision 15</a> <em>(October 2011)</em> + width="9px" /> + SDK Tools, Revision 16</a> <em>(December 2011)</em> + + <div class="toggleme"> + <p class="caution"><strong>Important:</strong> To download the new Android + 4.0 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 system components will not be available for download.</p> + +<dl> +<dt>Dependencies:</dt> +<dd> + <ul> + <li>Android SDK Platform-tools revision 9 or later.</li> + <li>If you are developing in Eclipse with ADT, note that the SDK Tools r16 is designed for use + with ADT 16.0.0 and later. If you haven't already, we highly recommend updating your + <a href="{@docRoot}sdk/eclipse-adt.html">ADT Plugin</a> to 16.0.0.</li> + <li>If you are developing outside Eclipse, 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>Added Lint tools to detect common errors in Android projects. (<a +href="http://tools.android.com/recent/lint">more info</a>)</li> + <li>Added sensor emulation support, which allows the emulator to read sensor data from a +physical Android device.</li> + <li>Added support for using a webcam to emulate a camera on Mac OS X.</li> + </ul> +</dd> +<dt>Bug fixes:</dt> +<dd> + <ul> + <li>Snapshots now work for Android 4.0 system images.</li> + <li>Fixed several small issues for the build file. + (<a href="http://code.google.com/p/android/issues/detail?id=21023">Issue 21023</a>, + <a href="http://code.google.com/p/android/issues/detail?id=21267">Issue 21267</a>, + <a href="http://code.google.com/p/android/issues/detail?id=21465">Issue 21465</a>, + <a href="http://code.google.com/p/android/issues/detail?id=21525">Issue 21525</a>).</li> + </ul> +</dd> +</dl> +</div> +</div> + +<div class="toggleable closed"> + <a href="#" onclick="return toggleDiv(this)"> + <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-img" height="9px" + width="9px" /> + SDK Tools, Revision 15</a> <em>(October 2011)</em> <div class="toggleme"> <p class="caution"><strong>Important:</strong> To download the new Android @@ -116,7 +165,8 @@ padding: .25em 1em; <div class="toggleable closed"> <a href="#" onclick="return toggleDiv(this)"> <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-img" height="9px" - width="9px" />SDK Tools, Revision 14</a> <em>(October 2011)</em> + width="9px" /> + SDK Tools, Revision 14</a> <em>(October 2011)</em> <div class="toggleme"> <p class="note"><strong>Important:</strong> To download the new Android @@ -137,10 +187,11 @@ padding: .25em 1em; <dt>General notes:</dt> <dd> <ul> - <li>Added webcam support to Android 4.0 or later platforms to emulate rear-facing cameras when one webcam is present, - and to emulate both rear-facing and front-facing cameras when two webcams are present. Webcam suport is for Windows and Linux only. + <li>Added webcam support to Android 4.0 or later platforms to emulate rear-facing cameras when + one webcam is present, and to emulate both rear-facing and front-facing cameras when two + webcams are present. Webcam support is for Windows and Linux only. Mac support will come in a later release.</li> - <li>Changed <code>default.properties</code> to <code>project.properties</code> and + <li>Changed <code>default.properties</code> to <code>project.properties</code> and <code>build.properties</code> to <code>ant.properties</code>. Any existing projects that you build with Ant must be updated with the <code>android update project</code> command.</li> @@ -428,7 +479,7 @@ normal tasks: <code>-pre-build</code>, <code>-pre-compile</code>, and for more information.</li> <li>Fixes location control in DDMS to work in any locale not using '.' as a decimal point.</li> -</li> +</ul> </ul> </dd> </dl> diff --git a/docs/html/shareables/adl/2011Q3_Introduction_to_Honeycomb_APIs.pdf b/docs/html/shareables/adl/2011Q3_Introduction_to_Honeycomb_APIs.pdf Binary files differindex da954d80c53e..e56d23779dff 100644..100755 --- a/docs/html/shareables/adl/2011Q3_Introduction_to_Honeycomb_APIs.pdf +++ b/docs/html/shareables/adl/2011Q3_Introduction_to_Honeycomb_APIs.pdf diff --git a/include/gui/SurfaceTexture.h b/include/gui/SurfaceTexture.h index 27d863de58ae..a8c76725e7c9 100644 --- a/include/gui/SurfaceTexture.h +++ b/include/gui/SurfaceTexture.h @@ -60,10 +60,16 @@ public: virtual void onFrameAvailable() = 0; }; - // tex indicates the name OpenGL texture to which images are to be streamed. - // This texture name cannot be changed once the SurfaceTexture is created. + // SurfaceTexture constructs a new SurfaceTexture object. tex indicates the + // name of the OpenGL ES texture to which images are to be streamed. This + // texture name cannot be changed once the SurfaceTexture is created. + // allowSynchronousMode specifies whether or not synchronous mode can be + // enabled. texTarget specifies the OpenGL ES texture target to which the + // texture will be bound in updateTexImage. useFenceSync specifies whether + // fences should be used to synchronize access to buffers if that behavior + // is enabled at compile-time. SurfaceTexture(GLuint tex, bool allowSynchronousMode = true, - GLenum texTarget = GL_TEXTURE_EXTERNAL_OES); + GLenum texTarget = GL_TEXTURE_EXTERNAL_OES, bool useFenceSync = true); virtual ~SurfaceTexture(); @@ -202,6 +208,10 @@ public: // getCurrentScalingMode returns the scaling mode of the current buffer uint32_t getCurrentScalingMode() const; + // isSynchronousMode returns whether the SurfaceTexture is currently in + // synchronous mode. + bool isSynchronousMode() const; + // abandon frees all the buffers and puts the SurfaceTexture into the // 'abandoned' state. Once put in this state the SurfaceTexture can never // leave it. When in the 'abandoned' state, all methods of the @@ -272,7 +282,8 @@ private: mTransform(0), mScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE), mTimestamp(0), - mFrameNumber(0) { + mFrameNumber(0), + mFence(EGL_NO_SYNC_KHR) { mCrop.makeInvalid(); } @@ -345,6 +356,11 @@ private: // mFrameNumber is the number of the queued frame for this slot. uint64_t mFrameNumber; + // mFence is the EGL sync object that must signal before the buffer + // associated with this buffer slot may be dequeued. It is initialized + // to EGL_NO_SYNC_KHR when the buffer is created and (optionally, based + // on a compile-time option) set to a new sync object in updateTexImage. + EGLSyncKHR mFence; }; // mSlots is the array of buffer slots that must be mirrored on the client @@ -468,6 +484,12 @@ private: // It is set by the setName method. String8 mName; + // mUseFenceSync indicates whether creation of the EGL_KHR_fence_sync + // extension should be used to prevent buffers from being dequeued before + // it's safe for them to be written. It gets set at construction time and + // never changes. + const bool mUseFenceSync; + // mMutex is the mutex used to prevent concurrent access to the member // variables of SurfaceTexture objects. It must be locked whenever the // member variables are accessed. diff --git a/include/gui/SurfaceTextureClient.h b/include/gui/SurfaceTextureClient.h index 57f9e151deee..971a1b80dc88 100644 --- a/include/gui/SurfaceTextureClient.h +++ b/include/gui/SurfaceTextureClient.h @@ -40,6 +40,7 @@ public: protected: SurfaceTextureClient(); + virtual ~SurfaceTextureClient(); void setISurfaceTexture(const sp<ISurfaceTexture>& surfaceTexture); private: diff --git a/include/media/IStreamSource.h b/include/media/IStreamSource.h index cc63356803df..19646b0c9d06 100644 --- a/include/media/IStreamSource.h +++ b/include/media/IStreamSource.h @@ -52,15 +52,20 @@ struct IStreamListener : public IInterface { static const char *const kKeyResumeAtPTS; // When signalling a discontinuity you can optionally - // signal that this is a "hard" discontinuity, i.e. the format - // or configuration of subsequent stream data differs from that - // currently active. To do so, include a non-zero int32_t value - // under the key "kKeyFormatChange" when issuing the DISCONTINUITY + // specify the type(s) of discontinuity, i.e. if the + // audio format has changed, the video format has changed, + // time has jumped or any combination thereof. + // To do so, include a non-zero int32_t value + // under the key "kKeyDiscontinuityMask" when issuing the DISCONTINUITY // command. - // The new logical stream must start with proper codec initialization + // If there is a change in audio/video format, The new logical stream + // must start with proper codec initialization // information for playback to continue, i.e. SPS and PPS in the case // of AVC video etc. - static const char *const kKeyFormatChange; + // If this key is not present, only a time discontinuity is assumed. + // The value should be a bitmask of values from + // ATSParser::DiscontinuityType. + static const char *const kKeyDiscontinuityMask; virtual void issueCommand( Command cmd, bool synchronous, const sp<AMessage> &msg = NULL) = 0; diff --git a/include/media/stagefright/ACodec.h b/include/media/stagefright/ACodec.h index 5822877217c0..3963d9cf5909 100644 --- a/include/media/stagefright/ACodec.h +++ b/include/media/stagefright/ACodec.h @@ -166,6 +166,8 @@ private: bool allYourBuffersAreBelongToUs(); + size_t countBuffersOwnedByComponent(OMX_U32 portIndex) const; + void deferMessage(const sp<AMessage> &msg); void processDeferredMessages(); diff --git a/include/media/stagefright/CameraSource.h b/include/media/stagefright/CameraSource.h index 8c1c59351e90..446720b88cd5 100644 --- a/include/media/stagefright/CameraSource.h +++ b/include/media/stagefright/CameraSource.h @@ -153,6 +153,9 @@ protected: bool mStarted; int32_t mNumFramesEncoded; + // Time between capture of two frames. + int64_t mTimeBetweenFrameCaptureUs; + CameraSource(const sp<ICamera>& camera, const sp<ICameraRecordingProxy>& proxy, int32_t cameraId, Size videoSize, int32_t frameRate, diff --git a/include/media/stagefright/CameraSourceTimeLapse.h b/include/media/stagefright/CameraSourceTimeLapse.h index 0e264c7be02a..b0606914c11d 100644 --- a/include/media/stagefright/CameraSourceTimeLapse.h +++ b/include/media/stagefright/CameraSourceTimeLapse.h @@ -57,10 +57,6 @@ private: int32_t mVideoWidth; int32_t mVideoHeight; - // Time between capture of two frames during time lapse recording - // Negative value indicates that timelapse is disabled. - int64_t mTimeBetweenTimeLapseFrameCaptureUs; - // Time between two frames in final video (1/frameRate) int64_t mTimeBetweenTimeLapseVideoFramesUs; diff --git a/include/media/stagefright/OMXCodec.h b/include/media/stagefright/OMXCodec.h index c21d19d45851..84f8282f64b7 100644 --- a/include/media/stagefright/OMXCodec.h +++ b/include/media/stagefright/OMXCodec.h @@ -336,6 +336,10 @@ private: int64_t retrieveDecodingTimeUs(bool isCodecSpecific); + status_t parseAVCCodecSpecificData( + const void *data, size_t size, + unsigned *profile, unsigned *level); + OMXCodec(const OMXCodec &); OMXCodec &operator=(const OMXCodec &); }; diff --git a/include/ui/GraphicBuffer.h b/include/ui/GraphicBuffer.h index b9deafcd3baf..6ab01f4c98ef 100644 --- a/include/ui/GraphicBuffer.h +++ b/include/ui/GraphicBuffer.h @@ -63,6 +63,7 @@ public: USAGE_HW_RENDER = GRALLOC_USAGE_HW_RENDER, USAGE_HW_2D = GRALLOC_USAGE_HW_2D, USAGE_HW_COMPOSER = GRALLOC_USAGE_HW_COMPOSER, + USAGE_HW_VIDEO_ENCODER = GRALLOC_USAGE_HW_VIDEO_ENCODER, USAGE_HW_MASK = GRALLOC_USAGE_HW_MASK }; diff --git a/include/ui/KeycodeLabels.h b/include/ui/KeycodeLabels.h index 2efe8ca0ee50..c5bd0c544673 100755 --- a/include/ui/KeycodeLabels.h +++ b/include/ui/KeycodeLabels.h @@ -231,6 +231,10 @@ static const KeycodeLabel KEYCODES[] = { { "LANGUAGE_SWITCH", 204 }, { "MANNER_MODE", 205 }, { "3D_MODE", 206 }, + { "CONTACTS", 207 }, + { "CALENDAR", 208 }, + { "MUSIC", 209 }, + { "CALCULATOR", 210 }, // NOTE: If you add a new keycode here you must also add it to several other files. // Refer to frameworks/base/core/java/android/view/KeyEvent.java for the full list. diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp index 5ccf87f2cbd3..5d34787d6cec 100644 --- a/libs/binder/IPCThreadState.cpp +++ b/libs/binder/IPCThreadState.cpp @@ -773,6 +773,7 @@ status_t IPCThreadState::talkWithDriver(bool doReceive) bwr.read_buffer = (long unsigned int)mIn.data(); } else { bwr.read_size = 0; + bwr.read_buffer = 0; } IF_LOG_COMMANDS() { diff --git a/libs/gui/Android.mk b/libs/gui/Android.mk index ed319f5e9381..9767568bed35 100644 --- a/libs/gui/Android.mk +++ b/libs/gui/Android.mk @@ -32,6 +32,10 @@ LOCAL_SHARED_LIBRARIES := \ LOCAL_MODULE:= libgui +ifeq ($(TARGET_BOARD_PLATFORM), tegra) + LOCAL_CFLAGS += -DALLOW_DEQUEUE_CURRENT_BUFFER +endif + include $(BUILD_SHARED_LIBRARY) ifeq (,$(ONE_SHOT_MAKEFILE)) diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp index 3c0d4756ff6c..fcd287c02276 100644 --- a/libs/gui/SurfaceTexture.cpp +++ b/libs/gui/SurfaceTexture.cpp @@ -36,8 +36,28 @@ #include <utils/Log.h> #include <utils/String8.h> - -#define ALLOW_DEQUEUE_CURRENT_BUFFER false +// This compile option causes SurfaceTexture to return the buffer that is currently +// attached to the GL texture from dequeueBuffer when no other buffers are +// available. It requires the drivers (Gralloc, GL, OMX IL, and Camera) to do +// implicit cross-process synchronization to prevent the buffer from being +// written to before the buffer has (a) been detached from the GL texture and +// (b) all GL reads from the buffer have completed. +#ifdef ALLOW_DEQUEUE_CURRENT_BUFFER +#define FLAG_ALLOW_DEQUEUE_CURRENT_BUFFER true +#warning "ALLOW_DEQUEUE_CURRENT_BUFFER enabled" +#else +#define FLAG_ALLOW_DEQUEUE_CURRENT_BUFFER false +#endif + +// This compile option makes SurfaceTexture use the EGL_KHR_fence_sync extension +// to synchronize access to the buffers. It will cause dequeueBuffer to stall, +// waiting for the GL reads for the buffer being dequeued to complete before +// allowing the buffer to be dequeued. +#ifdef USE_FENCE_SYNC +#ifdef ALLOW_DEQUEUE_CURRENT_BUFFER +#error "USE_FENCE_SYNC and ALLOW_DEQUEUE_CURRENT_BUFFER are incompatible" +#endif +#endif // Macros for including the SurfaceTexture name in log messages #define ST_LOGV(x, ...) LOGV("[%s] "x, mName.string(), ##__VA_ARGS__) @@ -95,7 +115,7 @@ static int32_t createProcessUniqueId() { } SurfaceTexture::SurfaceTexture(GLuint tex, bool allowSynchronousMode, - GLenum texTarget) : + GLenum texTarget, bool useFenceSync) : mDefaultWidth(1), mDefaultHeight(1), mPixelFormat(PIXEL_FORMAT_RGBA_8888), @@ -112,6 +132,11 @@ SurfaceTexture::SurfaceTexture(GLuint tex, bool allowSynchronousMode, mAllowSynchronousMode(allowSynchronousMode), mConnectedApi(NO_CONNECTED_API), mAbandoned(false), +#ifdef USE_FENCE_SYNC + mUseFenceSync(useFenceSync), +#else + mUseFenceSync(false), +#endif mTexTarget(texTarget), mFrameCounter(0) { // Choose a name using the PID and a process-unique ID. @@ -257,190 +282,225 @@ status_t SurfaceTexture::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h, return BAD_VALUE; } - Mutex::Autolock lock(mMutex); - status_t returnFlags(OK); + EGLDisplay dpy = EGL_NO_DISPLAY; + EGLSyncKHR fence = EGL_NO_SYNC_KHR; - int found = -1; - int foundSync = -1; - int dequeuedCount = 0; - bool tryAgain = true; - while (tryAgain) { - if (mAbandoned) { - ST_LOGE("dequeueBuffer: SurfaceTexture has been abandoned!"); - return NO_INIT; - } - - // We need to wait for the FIFO to drain if the number of buffer - // needs to change. - // - // The condition "number of buffers needs to change" is true if - // - the client doesn't care about how many buffers there are - // - AND the actual number of buffer is different from what was - // set in the last setBufferCountServer() - // - OR - - // setBufferCountServer() was set to a value incompatible with - // the synchronization mode (for instance because the sync mode - // changed since) - // - // As long as this condition is true AND the FIFO is not empty, we - // wait on mDequeueCondition. - - const int minBufferCountNeeded = mSynchronousMode ? - MIN_SYNC_BUFFER_SLOTS : MIN_ASYNC_BUFFER_SLOTS; - - const bool numberOfBuffersNeedsToChange = !mClientBufferCount && - ((mServerBufferCount != mBufferCount) || - (mServerBufferCount < minBufferCountNeeded)); - - if (!mQueue.isEmpty() && numberOfBuffersNeedsToChange) { - // wait for the FIFO to drain - mDequeueCondition.wait(mMutex); - // NOTE: we continue here because we need to reevaluate our - // whole state (eg: we could be abandoned or disconnected) - continue; - } + { // Scope for the lock + Mutex::Autolock lock(mMutex); - if (numberOfBuffersNeedsToChange) { - // here we're guaranteed that mQueue is empty - freeAllBuffersLocked(); - mBufferCount = mServerBufferCount; - if (mBufferCount < minBufferCountNeeded) - mBufferCount = minBufferCountNeeded; - mCurrentTexture = INVALID_BUFFER_SLOT; - returnFlags |= ISurfaceTexture::RELEASE_ALL_BUFFERS; - } + int found = -1; + int foundSync = -1; + int dequeuedCount = 0; + bool tryAgain = true; + while (tryAgain) { + if (mAbandoned) { + ST_LOGE("dequeueBuffer: SurfaceTexture has been abandoned!"); + return NO_INIT; + } - // look for a free buffer to give to the client - found = INVALID_BUFFER_SLOT; - foundSync = INVALID_BUFFER_SLOT; - dequeuedCount = 0; - for (int i = 0; i < mBufferCount; i++) { - const int state = mSlots[i].mBufferState; - if (state == BufferSlot::DEQUEUED) { - dequeuedCount++; + // We need to wait for the FIFO to drain if the number of buffer + // needs to change. + // + // The condition "number of buffers needs to change" is true if + // - the client doesn't care about how many buffers there are + // - AND the actual number of buffer is different from what was + // set in the last setBufferCountServer() + // - OR - + // setBufferCountServer() was set to a value incompatible with + // the synchronization mode (for instance because the sync mode + // changed since) + // + // As long as this condition is true AND the FIFO is not empty, we + // wait on mDequeueCondition. + + const int minBufferCountNeeded = mSynchronousMode ? + MIN_SYNC_BUFFER_SLOTS : MIN_ASYNC_BUFFER_SLOTS; + + const bool numberOfBuffersNeedsToChange = !mClientBufferCount && + ((mServerBufferCount != mBufferCount) || + (mServerBufferCount < minBufferCountNeeded)); + + if (!mQueue.isEmpty() && numberOfBuffersNeedsToChange) { + // wait for the FIFO to drain + mDequeueCondition.wait(mMutex); + // NOTE: we continue here because we need to reevaluate our + // whole state (eg: we could be abandoned or disconnected) + continue; } - // if buffer is FREE it CANNOT be current - LOGW_IF((state == BufferSlot::FREE) && (mCurrentTexture==i), - "dequeueBuffer: buffer %d is both FREE and current!", i); + if (numberOfBuffersNeedsToChange) { + // here we're guaranteed that mQueue is empty + freeAllBuffersLocked(); + mBufferCount = mServerBufferCount; + if (mBufferCount < minBufferCountNeeded) + mBufferCount = minBufferCountNeeded; + mCurrentTexture = INVALID_BUFFER_SLOT; + returnFlags |= ISurfaceTexture::RELEASE_ALL_BUFFERS; + } - if (ALLOW_DEQUEUE_CURRENT_BUFFER) { - if (state == BufferSlot::FREE || i == mCurrentTexture) { - foundSync = i; - if (i != mCurrentTexture) { - found = i; - break; - } + // look for a free buffer to give to the client + found = INVALID_BUFFER_SLOT; + foundSync = INVALID_BUFFER_SLOT; + dequeuedCount = 0; + for (int i = 0; i < mBufferCount; i++) { + const int state = mSlots[i].mBufferState; + if (state == BufferSlot::DEQUEUED) { + dequeuedCount++; } - } else { - if (state == BufferSlot::FREE) { - /** For Asynchronous mode, we need to return the oldest of free buffers - * There is only one instance when the Framecounter overflows, this logic - * might return the earlier buffer to client. Which is a negligible impact - **/ - if (found < 0 || mSlots[i].mFrameNumber < mSlots[found].mFrameNumber) { + + // if buffer is FREE it CANNOT be current + LOGW_IF((state == BufferSlot::FREE) && (mCurrentTexture==i), + "dequeueBuffer: buffer %d is both FREE and current!", + i); + + if (FLAG_ALLOW_DEQUEUE_CURRENT_BUFFER) { + if (state == BufferSlot::FREE || i == mCurrentTexture) { foundSync = i; - found = i; + if (i != mCurrentTexture) { + found = i; + break; + } + } + } else { + if (state == BufferSlot::FREE) { + /* We return the oldest of the free buffers to avoid + * stalling the producer if possible. This is because + * the consumer may still have pending reads of the + * buffers in flight. + */ + bool isOlder = mSlots[i].mFrameNumber < + mSlots[found].mFrameNumber; + if (found < 0 || isOlder) { + foundSync = i; + found = i; + } } } } - } - // clients are not allowed to dequeue more than one buffer - // if they didn't set a buffer count. - if (!mClientBufferCount && dequeuedCount) { - ST_LOGE("dequeueBuffer: can't dequeue multiple buffers without " - "setting the buffer count"); - return -EINVAL; - } + // clients are not allowed to dequeue more than one buffer + // if they didn't set a buffer count. + if (!mClientBufferCount && dequeuedCount) { + ST_LOGE("dequeueBuffer: can't dequeue multiple buffers without " + "setting the buffer count"); + return -EINVAL; + } + + // See whether a buffer has been queued since the last + // setBufferCount so we know whether to perform the + // MIN_UNDEQUEUED_BUFFERS check below. + bool bufferHasBeenQueued = mCurrentTexture != INVALID_BUFFER_SLOT; + if (bufferHasBeenQueued) { + // make sure the client is not trying to dequeue more buffers + // than allowed. + const int avail = mBufferCount - (dequeuedCount+1); + if (avail < (MIN_UNDEQUEUED_BUFFERS-int(mSynchronousMode))) { + ST_LOGE("dequeueBuffer: MIN_UNDEQUEUED_BUFFERS=%d exceeded " + "(dequeued=%d)", + MIN_UNDEQUEUED_BUFFERS-int(mSynchronousMode), + dequeuedCount); + return -EBUSY; + } + } - // See whether a buffer has been queued since the last setBufferCount so - // we know whether to perform the MIN_UNDEQUEUED_BUFFERS check below. - bool bufferHasBeenQueued = mCurrentTexture != INVALID_BUFFER_SLOT; - if (bufferHasBeenQueued) { - // make sure the client is not trying to dequeue more buffers - // than allowed. - const int avail = mBufferCount - (dequeuedCount+1); - if (avail < (MIN_UNDEQUEUED_BUFFERS-int(mSynchronousMode))) { - ST_LOGE("dequeueBuffer: MIN_UNDEQUEUED_BUFFERS=%d exceeded " - "(dequeued=%d)", - MIN_UNDEQUEUED_BUFFERS-int(mSynchronousMode), - dequeuedCount); - return -EBUSY; + // we're in synchronous mode and didn't find a buffer, we need to + // wait for some buffers to be consumed + tryAgain = mSynchronousMode && (foundSync == INVALID_BUFFER_SLOT); + if (tryAgain) { + mDequeueCondition.wait(mMutex); } } - // we're in synchronous mode and didn't find a buffer, we need to wait - // for some buffers to be consumed - tryAgain = mSynchronousMode && (foundSync == INVALID_BUFFER_SLOT); - if (tryAgain) { - mDequeueCondition.wait(mMutex); + if (mSynchronousMode && found == INVALID_BUFFER_SLOT) { + // foundSync guaranteed to be != INVALID_BUFFER_SLOT + found = foundSync; } - } - if (mSynchronousMode && found == INVALID_BUFFER_SLOT) { - // foundSync guaranteed to be != INVALID_BUFFER_SLOT - found = foundSync; - } + if (found == INVALID_BUFFER_SLOT) { + // This should not happen. + ST_LOGE("dequeueBuffer: no available buffer slots"); + return -EBUSY; + } - if (found == INVALID_BUFFER_SLOT) { - // This should not happen. - ST_LOGE("dequeueBuffer: no available buffer slots"); - return -EBUSY; - } + const int buf = found; + *outBuf = found; - const int buf = found; - *outBuf = found; + const bool useDefaultSize = !w && !h; + if (useDefaultSize) { + // use the default size + w = mDefaultWidth; + h = mDefaultHeight; + } - const bool useDefaultSize = !w && !h; - if (useDefaultSize) { - // use the default size - w = mDefaultWidth; - h = mDefaultHeight; - } + const bool updateFormat = (format != 0); + if (!updateFormat) { + // keep the current (or default) format + format = mPixelFormat; + } - const bool updateFormat = (format != 0); - if (!updateFormat) { - // keep the current (or default) format - format = mPixelFormat; + // buffer is now in DEQUEUED (but can also be current at the same time, + // if we're in synchronous mode) + mSlots[buf].mBufferState = BufferSlot::DEQUEUED; + + const sp<GraphicBuffer>& buffer(mSlots[buf].mGraphicBuffer); + if ((buffer == NULL) || + (uint32_t(buffer->width) != w) || + (uint32_t(buffer->height) != h) || + (uint32_t(buffer->format) != format) || + ((uint32_t(buffer->usage) & usage) != usage)) + { + usage |= GraphicBuffer::USAGE_HW_TEXTURE; + status_t error; + sp<GraphicBuffer> graphicBuffer( + mGraphicBufferAlloc->createGraphicBuffer( + w, h, format, usage, &error)); + if (graphicBuffer == 0) { + ST_LOGE("dequeueBuffer: SurfaceComposer::createGraphicBuffer " + "failed"); + return error; + } + if (updateFormat) { + mPixelFormat = format; + } + mSlots[buf].mGraphicBuffer = graphicBuffer; + mSlots[buf].mRequestBufferCalled = false; + mSlots[buf].mFence = EGL_NO_SYNC_KHR; + if (mSlots[buf].mEglImage != EGL_NO_IMAGE_KHR) { + eglDestroyImageKHR(mSlots[buf].mEglDisplay, + mSlots[buf].mEglImage); + mSlots[buf].mEglImage = EGL_NO_IMAGE_KHR; + mSlots[buf].mEglDisplay = EGL_NO_DISPLAY; + } + if (mCurrentTexture == buf) { + // The current texture no longer references the buffer in this slot + // since we just allocated a new buffer. + mCurrentTexture = INVALID_BUFFER_SLOT; + } + returnFlags |= ISurfaceTexture::BUFFER_NEEDS_REALLOCATION; + } + + dpy = mSlots[buf].mEglDisplay; + fence = mSlots[buf].mFence; + mSlots[buf].mFence = EGL_NO_SYNC_KHR; } - // buffer is now in DEQUEUED (but can also be current at the same time, - // if we're in synchronous mode) - mSlots[buf].mBufferState = BufferSlot::DEQUEUED; - - const sp<GraphicBuffer>& buffer(mSlots[buf].mGraphicBuffer); - if ((buffer == NULL) || - (uint32_t(buffer->width) != w) || - (uint32_t(buffer->height) != h) || - (uint32_t(buffer->format) != format) || - ((uint32_t(buffer->usage) & usage) != usage)) - { - usage |= GraphicBuffer::USAGE_HW_TEXTURE; - status_t error; - sp<GraphicBuffer> graphicBuffer( - mGraphicBufferAlloc->createGraphicBuffer( - w, h, format, usage, &error)); - if (graphicBuffer == 0) { - ST_LOGE("dequeueBuffer: SurfaceComposer::createGraphicBuffer " - "failed"); - return error; - } - if (updateFormat) { - mPixelFormat = format; + if (fence != EGL_NO_SYNC_KHR) { + EGLint result = eglClientWaitSyncKHR(dpy, fence, 0, 1000000000); + // If something goes wrong, log the error, but return the buffer without + // synchronizing access to it. It's too late at this point to abort the + // dequeue operation. + if (result == EGL_FALSE) { + LOGE("dequeueBuffer: error waiting for fence: %#x", eglGetError()); + } else if (result == EGL_TIMEOUT_EXPIRED_KHR) { + LOGE("dequeueBuffer: timeout waiting for fence"); } - mSlots[buf].mGraphicBuffer = graphicBuffer; - mSlots[buf].mRequestBufferCalled = false; - if (mSlots[buf].mEglImage != EGL_NO_IMAGE_KHR) { - eglDestroyImageKHR(mSlots[buf].mEglDisplay, mSlots[buf].mEglImage); - mSlots[buf].mEglImage = EGL_NO_IMAGE_KHR; - mSlots[buf].mEglDisplay = EGL_NO_DISPLAY; - } - returnFlags |= ISurfaceTexture::BUFFER_NEEDS_REALLOCATION; + eglDestroySyncKHR(dpy, fence); } + ST_LOGV("dequeueBuffer: returning slot=%d buf=%p flags=%#x", buf, mSlots[buf].mGraphicBuffer->handle, returnFlags); + return returnFlags; } @@ -637,8 +697,9 @@ status_t SurfaceTexture::disconnect(int api) { Mutex::Autolock lock(mMutex); if (mAbandoned) { - ST_LOGE("disconnect: SurfaceTexture has been abandoned!"); - return NO_INIT; + // it is not really an error to disconnect after the surface + // has been abandoned, it should just be a no-op. + return NO_ERROR; } int err = NO_ERROR; @@ -702,8 +763,8 @@ status_t SurfaceTexture::updateTexImage() { // Update the GL texture object. EGLImageKHR image = mSlots[buf].mEglImage; + EGLDisplay dpy = eglGetCurrentDisplay(); if (image == EGL_NO_IMAGE_KHR) { - EGLDisplay dpy = eglGetCurrentDisplay(); if (mSlots[buf].mGraphicBuffer == 0) { ST_LOGE("buffer at slot %d is null", buf); return BAD_VALUE; @@ -736,16 +797,32 @@ status_t SurfaceTexture::updateTexImage() { return -EINVAL; } - ST_LOGV("updateTexImage: (slot=%d buf=%p) -> (slot=%d buf=%p)", mCurrentTexture, - mCurrentTextureBuf != NULL ? mCurrentTextureBuf->handle : 0, buf, - mSlots[buf].mGraphicBuffer->handle); + if (mCurrentTexture != INVALID_BUFFER_SLOT) { + if (mUseFenceSync) { + EGLSyncKHR fence = eglCreateSyncKHR(dpy, EGL_SYNC_FENCE_KHR, + NULL); + if (fence == EGL_NO_SYNC_KHR) { + LOGE("updateTexImage: error creating fence: %#x", + eglGetError()); + return -EINVAL; + } + glFlush(); + mSlots[mCurrentTexture].mFence = fence; + } + } + + ST_LOGV("updateTexImage: (slot=%d buf=%p) -> (slot=%d buf=%p)", + mCurrentTexture, + mCurrentTextureBuf != NULL ? mCurrentTextureBuf->handle : 0, + buf, mSlots[buf].mGraphicBuffer->handle); if (mCurrentTexture != INVALID_BUFFER_SLOT) { // The current buffer becomes FREE if it was still in the queued // state. If it has already been given to the client // (synchronous mode), then it stays in DEQUEUED state. - if (mSlots[mCurrentTexture].mBufferState == BufferSlot::QUEUED) + if (mSlots[mCurrentTexture].mBufferState == BufferSlot::QUEUED) { mSlots[mCurrentTexture].mBufferState = BufferSlot::FREE; + } } // Update the SurfaceTexture state. @@ -1000,6 +1077,11 @@ uint32_t SurfaceTexture::getCurrentScalingMode() const { return mCurrentScalingMode; } +bool SurfaceTexture::isSynchronousMode() const { + Mutex::Autolock lock(mMutex); + return mSynchronousMode; +} + int SurfaceTexture::query(int what, int* outValue) { Mutex::Autolock lock(mMutex); diff --git a/libs/gui/SurfaceTextureClient.cpp b/libs/gui/SurfaceTextureClient.cpp index 98fa17174ea1..48070d67c322 100644 --- a/libs/gui/SurfaceTextureClient.cpp +++ b/libs/gui/SurfaceTextureClient.cpp @@ -36,6 +36,12 @@ SurfaceTextureClient::SurfaceTextureClient() { SurfaceTextureClient::init(); } +SurfaceTextureClient::~SurfaceTextureClient() { + if (mConnectedToCpu) { + SurfaceTextureClient::disconnect(NATIVE_WINDOW_API_CPU); + } +} + void SurfaceTextureClient::init() { // Initialize the ANativeWindow function pointers. ANativeWindow::setSwapInterval = hook_setSwapInterval; diff --git a/libs/gui/tests/SurfaceTexture_test.cpp b/libs/gui/tests/SurfaceTexture_test.cpp index 93ebfb99ff6f..c3139042836d 100644 --- a/libs/gui/tests/SurfaceTexture_test.cpp +++ b/libs/gui/tests/SurfaceTexture_test.cpp @@ -396,7 +396,8 @@ protected: 1.0f, 1.0f, }; - glVertexAttribPointer(mPositionHandle, 2, GL_FLOAT, GL_FALSE, 0, triangleVertices); + glVertexAttribPointer(mPositionHandle, 2, GL_FLOAT, GL_FALSE, 0, + triangleVertices); ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError()); glEnableVertexAttribArray(mPositionHandle); ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError()); @@ -410,13 +411,17 @@ protected: // XXX: These calls are not needed for GL_TEXTURE_EXTERNAL_OES as // they're setting the defautls for that target, but when hacking things // to use GL_TEXTURE_2D they are needed to achieve the same behavior. - glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, + GL_LINEAR); ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError()); - glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, + GL_LINEAR); ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError()); - glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, + GL_CLAMP_TO_EDGE); ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError()); - glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, + GL_CLAMP_TO_EDGE); ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError()); GLfloat texMatrix[16]; @@ -531,6 +536,20 @@ void fillRGBA8Buffer(uint8_t* buf, int w, int h, int stride) { } } +void fillRGBA8BufferSolid(uint8_t* buf, int w, int h, int stride, uint8_t r, + uint8_t g, uint8_t b, uint8_t a) { + const size_t PIXEL_SIZE = 4; + for (int y = 0; y < h; y++) { + for (int x = 0; x < h; x++) { + off_t offset = (y * stride + x) * PIXEL_SIZE; + buf[offset + 0] = r; + buf[offset + 1] = g; + buf[offset + 2] = b; + buf[offset + 3] = a; + } + } +} + TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BufferNpot) { const int texWidth = 64; const int texHeight = 66; @@ -640,8 +659,8 @@ TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BufferWithCrop) { for (int i = 0; i < 5; i++) { const android_native_rect_t& crop(crops[i]); - SCOPED_TRACE(String8::format("rect{ l: %d t: %d r: %d b: %d }", crop.left, - crop.top, crop.right, crop.bottom).string()); + SCOPED_TRACE(String8::format("rect{ l: %d t: %d r: %d b: %d }", + crop.left, crop.top, crop.right, crop.bottom).string()); ASSERT_EQ(NO_ERROR, native_window_set_crop(mANW.get(), &crop)); @@ -650,13 +669,15 @@ TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BufferWithCrop) { ASSERT_TRUE(anb != NULL); sp<GraphicBuffer> buf(new GraphicBuffer(anb, false)); - ASSERT_EQ(NO_ERROR, mANW->lockBuffer(mANW.get(), buf->getNativeBuffer())); + ASSERT_EQ(NO_ERROR, mANW->lockBuffer(mANW.get(), + buf->getNativeBuffer())); uint8_t* img = NULL; buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img)); fillYV12BufferRect(img, texWidth, texHeight, buf->getStride(), crop); buf->unlock(); - ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), buf->getNativeBuffer())); + ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), + buf->getNativeBuffer())); mST->updateTexImage(); @@ -708,7 +729,8 @@ TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BuffersRepeatedly) { class ProducerThread : public Thread { public: - ProducerThread(const sp<ANativeWindow>& anw, const TestPixel* testPixels): + ProducerThread(const sp<ANativeWindow>& anw, + const TestPixel* testPixels): mANW(anw), mTestPixels(testPixels) { } @@ -940,21 +962,173 @@ TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledRGBABufferPow2) { EXPECT_TRUE(checkPixel( 3, 52, 35, 231, 35, 35)); } -TEST_F(SurfaceTextureGLTest, TexturingFromGLFilledRGBABufferPow2) { +TEST_F(SurfaceTextureGLTest, AbandonUnblocksDequeueBuffer) { + class ProducerThread : public Thread { + public: + ProducerThread(const sp<ANativeWindow>& anw): + mANW(anw), + mDequeueError(NO_ERROR) { + } + + virtual ~ProducerThread() { + } + + virtual bool threadLoop() { + Mutex::Autolock lock(mMutex); + ANativeWindowBuffer* anb; + + // Frame 1 + if (mANW->dequeueBuffer(mANW.get(), &anb) != NO_ERROR) { + return false; + } + if (anb == NULL) { + return false; + } + if (mANW->queueBuffer(mANW.get(), anb) + != NO_ERROR) { + return false; + } + + // Frame 2 + if (mANW->dequeueBuffer(mANW.get(), &anb) != NO_ERROR) { + return false; + } + if (anb == NULL) { + return false; + } + if (mANW->queueBuffer(mANW.get(), anb) + != NO_ERROR) { + return false; + } + + // Frame 3 - error expected + mDequeueError = mANW->dequeueBuffer(mANW.get(), &anb); + return false; + } + + status_t getDequeueError() { + Mutex::Autolock lock(mMutex); + return mDequeueError; + } + + private: + sp<ANativeWindow> mANW; + status_t mDequeueError; + Mutex mMutex; + }; + + sp<FrameWaiter> fw(new FrameWaiter); + mST->setFrameAvailableListener(fw); + ASSERT_EQ(OK, mST->setSynchronousMode(true)); + ASSERT_EQ(OK, mST->setBufferCountServer(2)); + + sp<Thread> pt(new ProducerThread(mANW)); + pt->run(); + + fw->waitForFrame(); + fw->waitForFrame(); + + // Sleep for 100ms to allow the producer thread's dequeueBuffer call to + // block waiting for a buffer to become available. + usleep(100000); + + mST->abandon(); + + pt->requestExitAndWait(); + ASSERT_EQ(NO_INIT, + reinterpret_cast<ProducerThread*>(pt.get())->getDequeueError()); +} + +TEST_F(SurfaceTextureGLTest, InvalidWidthOrHeightFails) { + int texHeight = 16; + ANativeWindowBuffer* anb; + + GLint maxTextureSize; + glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize); + + // make sure it works with small textures + mST->setDefaultBufferSize(16, texHeight); + EXPECT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb)); + EXPECT_EQ(16, anb->width); + EXPECT_EQ(texHeight, anb->height); + EXPECT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), anb)); + EXPECT_EQ(NO_ERROR, mST->updateTexImage()); + + // make sure it works with GL_MAX_TEXTURE_SIZE + mST->setDefaultBufferSize(maxTextureSize, texHeight); + EXPECT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb)); + EXPECT_EQ(maxTextureSize, anb->width); + EXPECT_EQ(texHeight, anb->height); + EXPECT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), anb)); + EXPECT_EQ(NO_ERROR, mST->updateTexImage()); + + // make sure it fails with GL_MAX_TEXTURE_SIZE+1 + mST->setDefaultBufferSize(maxTextureSize+1, texHeight); + EXPECT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb)); + EXPECT_EQ(maxTextureSize+1, anb->width); + EXPECT_EQ(texHeight, anb->height); + EXPECT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), anb)); + ASSERT_NE(NO_ERROR, mST->updateTexImage()); +} + +/* + * This test fixture is for testing GL -> GL texture streaming. It creates an + * EGLSurface and an EGLContext for the image producer to use. + */ +class SurfaceTextureGLToGLTest : public SurfaceTextureGLTest { +protected: + SurfaceTextureGLToGLTest(): + mProducerEglSurface(EGL_NO_SURFACE), + mProducerEglContext(EGL_NO_CONTEXT) { + } + + virtual void SetUp() { + SurfaceTextureGLTest::SetUp(); + + EGLConfig myConfig = {0}; + EGLint numConfigs = 0; + EXPECT_TRUE(eglChooseConfig(mEglDisplay, getConfigAttribs(), &myConfig, + 1, &numConfigs)); + ASSERT_EQ(EGL_SUCCESS, eglGetError()); + + mProducerEglSurface = eglCreateWindowSurface(mEglDisplay, myConfig, + mANW.get(), NULL); + ASSERT_EQ(EGL_SUCCESS, eglGetError()); + ASSERT_NE(EGL_NO_SURFACE, mProducerEglSurface); + + mProducerEglContext = eglCreateContext(mEglDisplay, myConfig, + EGL_NO_CONTEXT, getContextAttribs()); + ASSERT_EQ(EGL_SUCCESS, eglGetError()); + ASSERT_NE(EGL_NO_CONTEXT, mProducerEglContext); + } + + virtual void TearDown() { + if (mProducerEglContext != EGL_NO_CONTEXT) { + eglDestroyContext(mEglDisplay, mProducerEglContext); + } + if (mProducerEglSurface != EGL_NO_SURFACE) { + eglDestroySurface(mEglDisplay, mProducerEglSurface); + } + SurfaceTextureGLTest::TearDown(); + } + + EGLSurface mProducerEglSurface; + EGLContext mProducerEglContext; +}; + +TEST_F(SurfaceTextureGLToGLTest, TexturingFromGLFilledRGBABufferPow2) { const int texWidth = 64; const int texHeight = 64; mST->setDefaultBufferSize(texWidth, texHeight); // Do the producer side of things - EGLSurface stcEglSurface = eglCreateWindowSurface(mEglDisplay, mGlConfig, - mANW.get(), NULL); + EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mProducerEglSurface, + mProducerEglSurface, mProducerEglContext)); ASSERT_EQ(EGL_SUCCESS, eglGetError()); - ASSERT_NE(EGL_NO_SURFACE, stcEglSurface); - EXPECT_TRUE(eglMakeCurrent(mEglDisplay, stcEglSurface, stcEglSurface, - mEglContext)); - ASSERT_EQ(EGL_SUCCESS, eglGetError()); + // This is needed to ensure we pick up a buffer of the correct size. + eglSwapBuffers(mEglDisplay, mProducerEglSurface); glClearColor(0.6, 0.6, 0.6, 0.6); glClear(GL_COLOR_BUFFER_BIT); @@ -972,7 +1146,7 @@ TEST_F(SurfaceTextureGLTest, TexturingFromGLFilledRGBABufferPow2) { glClearColor(0.0, 0.0, 1.0, 1.0); glClear(GL_COLOR_BUFFER_BIT); - eglSwapBuffers(mEglDisplay, stcEglSurface); + eglSwapBuffers(mEglDisplay, mProducerEglSurface); // Do the consumer side of things EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, @@ -981,12 +1155,9 @@ TEST_F(SurfaceTextureGLTest, TexturingFromGLFilledRGBABufferPow2) { glDisable(GL_SCISSOR_TEST); + mST->updateTexImage(); // Skip the first frame, which was empty mST->updateTexImage(); - // We must wait until updateTexImage has been called to destroy the - // EGLSurface because we're in synchronous mode. - eglDestroySurface(mEglDisplay, stcEglSurface); - glClearColor(0.2, 0.2, 0.2, 0.2); glClear(GL_COLOR_BUFFER_BIT); @@ -1016,90 +1187,136 @@ TEST_F(SurfaceTextureGLTest, TexturingFromGLFilledRGBABufferPow2) { EXPECT_TRUE(checkPixel( 3, 52, 153, 153, 153, 153)); } -TEST_F(SurfaceTextureGLTest, AbandonUnblocksDequeueBuffer) { - class ProducerThread : public Thread { - public: - ProducerThread(const sp<ANativeWindow>& anw): - mANW(anw), - mDequeueError(NO_ERROR) { - } +TEST_F(SurfaceTextureGLToGLTest, EglDestroySurfaceUnrefsBuffers) { + sp<GraphicBuffer> buffers[3]; - virtual ~ProducerThread() { - } + // This test requires async mode to run on a single thread. + EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mProducerEglSurface, + mProducerEglSurface, mProducerEglContext)); + ASSERT_EQ(EGL_SUCCESS, eglGetError()); + EXPECT_TRUE(eglSwapInterval(mEglDisplay, 0)); + ASSERT_EQ(EGL_SUCCESS, eglGetError()); - virtual bool threadLoop() { - Mutex::Autolock lock(mMutex); - ANativeWindowBuffer* anb; + for (int i = 0; i < 3; i++) { + // Produce a frame + EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mProducerEglSurface, + mProducerEglSurface, mProducerEglContext)); + ASSERT_EQ(EGL_SUCCESS, eglGetError()); + glClear(GL_COLOR_BUFFER_BIT); + eglSwapBuffers(mEglDisplay, mProducerEglSurface); - // Frame 1 - if (mANW->dequeueBuffer(mANW.get(), &anb) != NO_ERROR) { - return false; - } - if (anb == NULL) { - return false; - } - if (mANW->queueBuffer(mANW.get(), anb) - != NO_ERROR) { - return false; - } + // Consume a frame + EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, + mEglContext)); + ASSERT_EQ(EGL_SUCCESS, eglGetError()); + mST->updateTexImage(); + buffers[i] = mST->getCurrentBuffer(); + } - // Frame 2 - if (mANW->dequeueBuffer(mANW.get(), &anb) != NO_ERROR) { - return false; - } - if (anb == NULL) { - return false; - } - if (mANW->queueBuffer(mANW.get(), anb) - != NO_ERROR) { - return false; - } + // Destroy the GL texture object to release its ref on buffers[2]. + GLuint texID = TEX_ID; + glDeleteTextures(1, &texID); - // Frame 3 - error expected - mDequeueError = mANW->dequeueBuffer(mANW.get(), &anb); - return false; - } + // Destroy the EGLSurface + EXPECT_TRUE(eglDestroySurface(mEglDisplay, mProducerEglSurface)); + ASSERT_EQ(EGL_SUCCESS, eglGetError()); - status_t getDequeueError() { - Mutex::Autolock lock(mMutex); - return mDequeueError; - } + // Release the ref that the SurfaceTexture has on buffers[2]. + mST->abandon(); - private: - sp<ANativeWindow> mANW; - status_t mDequeueError; - Mutex mMutex; - }; + EXPECT_EQ(1, buffers[0]->getStrongCount()); + EXPECT_EQ(1, buffers[1]->getStrongCount()); - sp<FrameWaiter> fw(new FrameWaiter); - mST->setFrameAvailableListener(fw); - ASSERT_EQ(OK, mST->setSynchronousMode(true)); - ASSERT_EQ(OK, mST->setBufferCountServer(2)); + // Depending on how lazily the GL driver dequeues buffers, we may end up + // with either two or three total buffers. If there are three, make sure + // the last one was properly down-ref'd. + if (buffers[2] != buffers[0]) { + EXPECT_EQ(1, buffers[2]->getStrongCount()); + } +} - sp<Thread> pt(new ProducerThread(mANW)); - pt->run(); +TEST_F(SurfaceTextureGLToGLTest, EglDestroySurfaceAfterAbandonUnrefsBuffers) { + sp<GraphicBuffer> buffers[3]; - fw->waitForFrame(); - fw->waitForFrame(); + // This test requires async mode to run on a single thread. + EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mProducerEglSurface, + mProducerEglSurface, mProducerEglContext)); + ASSERT_EQ(EGL_SUCCESS, eglGetError()); + EXPECT_TRUE(eglSwapInterval(mEglDisplay, 0)); + ASSERT_EQ(EGL_SUCCESS, eglGetError()); - // Sleep for 100ms to allow the producer thread's dequeueBuffer call to - // block waiting for a buffer to become available. - usleep(100000); + for (int i = 0; i < 3; i++) { + // Produce a frame + EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mProducerEglSurface, + mProducerEglSurface, mProducerEglContext)); + ASSERT_EQ(EGL_SUCCESS, eglGetError()); + glClear(GL_COLOR_BUFFER_BIT); + EXPECT_TRUE(eglSwapBuffers(mEglDisplay, mProducerEglSurface)); + ASSERT_EQ(EGL_SUCCESS, eglGetError()); + + // Consume a frame + EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, + mEglContext)); + ASSERT_EQ(EGL_SUCCESS, eglGetError()); + ASSERT_EQ(NO_ERROR, mST->updateTexImage()); + buffers[i] = mST->getCurrentBuffer(); + } + // Abandon the SurfaceTexture, releasing the ref that the SurfaceTexture has + // on buffers[2]. mST->abandon(); - pt->requestExitAndWait(); - ASSERT_EQ(NO_INIT, - reinterpret_cast<ProducerThread*>(pt.get())->getDequeueError()); + // Destroy the GL texture object to release its ref on buffers[2]. + GLuint texID = TEX_ID; + glDeleteTextures(1, &texID); + + // Destroy the EGLSurface. + EXPECT_TRUE(eglDestroySurface(mEglDisplay, mProducerEglSurface)); + ASSERT_EQ(EGL_SUCCESS, eglGetError()); + + EXPECT_EQ(1, buffers[0]->getStrongCount()); + EXPECT_EQ(1, buffers[1]->getStrongCount()); + + // Depending on how lazily the GL driver dequeues buffers, we may end up + // with either two or three total buffers. If there are three, make sure + // the last one was properly down-ref'd. + if (buffers[2] != buffers[0]) { + EXPECT_EQ(1, buffers[2]->getStrongCount()); + } +} + +TEST_F(SurfaceTextureGLToGLTest, EglSurfaceDefaultsToSynchronousMode) { + // This test requires 3 buffers to run on a single thread. + mST->setBufferCountServer(3); + + ASSERT_TRUE(mST->isSynchronousMode()); + + for (int i = 0; i < 10; i++) { + // Produce a frame + EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mProducerEglSurface, + mProducerEglSurface, mProducerEglContext)); + ASSERT_EQ(EGL_SUCCESS, eglGetError()); + glClear(GL_COLOR_BUFFER_BIT); + EXPECT_TRUE(eglSwapBuffers(mEglDisplay, mProducerEglSurface)); + ASSERT_EQ(EGL_SUCCESS, eglGetError()); + + // Consume a frame + EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, + mEglContext)); + ASSERT_EQ(EGL_SUCCESS, eglGetError()); + ASSERT_EQ(NO_ERROR, mST->updateTexImage()); + } + + ASSERT_TRUE(mST->isSynchronousMode()); } /* - * This test is for testing GL -> GL texture streaming via SurfaceTexture. It - * contains functionality to create a producer thread that will perform GL - * rendering to an ANativeWindow that feeds frames to a SurfaceTexture. - * Additionally it supports interlocking the producer and consumer threads so - * that a specific sequence of calls can be deterministically created by the - * test. + * This test fixture is for testing GL -> GL texture streaming from one thread + * to another. It contains functionality to create a producer thread that will + * perform GL rendering to an ANativeWindow that feeds frames to a + * SurfaceTexture. Additionally it supports interlocking the producer and + * consumer threads so that a specific sequence of calls can be + * deterministically created by the test. * * The intended usage is as follows: * @@ -1122,7 +1339,7 @@ TEST_F(SurfaceTextureGLTest, AbandonUnblocksDequeueBuffer) { * } * */ -class SurfaceTextureGLToGLTest : public SurfaceTextureGLTest { +class SurfaceTextureGLThreadToGLTest : public SurfaceTextureGLToGLTest { protected: // ProducerThread is an abstract base class to simplify the creation of @@ -1223,30 +1440,8 @@ protected: Condition mFrameFinishCondition; }; - SurfaceTextureGLToGLTest(): - mProducerEglSurface(EGL_NO_SURFACE), - mProducerEglContext(EGL_NO_CONTEXT) { - } - virtual void SetUp() { - SurfaceTextureGLTest::SetUp(); - - EGLConfig myConfig = {0}; - EGLint numConfigs = 0; - EXPECT_TRUE(eglChooseConfig(mEglDisplay, getConfigAttribs(), &myConfig, - 1, &numConfigs)); - ASSERT_EQ(EGL_SUCCESS, eglGetError()); - - mProducerEglSurface = eglCreateWindowSurface(mEglDisplay, myConfig, - mANW.get(), NULL); - ASSERT_EQ(EGL_SUCCESS, eglGetError()); - ASSERT_NE(EGL_NO_SURFACE, mProducerEglSurface); - - mProducerEglContext = eglCreateContext(mEglDisplay, myConfig, - EGL_NO_CONTEXT, getContextAttribs()); - ASSERT_EQ(EGL_SUCCESS, eglGetError()); - ASSERT_NE(EGL_NO_CONTEXT, mProducerEglContext); - + SurfaceTextureGLToGLTest::SetUp(); mFC = new FrameCondition(); mST->setFrameAvailableListener(mFC); } @@ -1255,15 +1450,9 @@ protected: if (mProducerThread != NULL) { mProducerThread->requestExitAndWait(); } - if (mProducerEglContext != EGL_NO_CONTEXT) { - eglDestroyContext(mEglDisplay, mProducerEglContext); - } - if (mProducerEglSurface != EGL_NO_SURFACE) { - eglDestroySurface(mEglDisplay, mProducerEglSurface); - } mProducerThread.clear(); mFC.clear(); - SurfaceTextureGLTest::TearDown(); + SurfaceTextureGLToGLTest::TearDown(); } void runProducerThread(const sp<ProducerThread> producerThread) { @@ -1274,13 +1463,12 @@ protected: producerThread->run(); } - EGLSurface mProducerEglSurface; - EGLContext mProducerEglContext; sp<ProducerThread> mProducerThread; sp<FrameCondition> mFC; }; -TEST_F(SurfaceTextureGLToGLTest, UpdateTexImageBeforeFrameFinishedCompletes) { +TEST_F(SurfaceTextureGLThreadToGLTest, + UpdateTexImageBeforeFrameFinishedCompletes) { class PT : public ProducerThread { virtual void render() { glClearColor(0.0f, 1.0f, 0.0f, 1.0f); @@ -1298,7 +1486,8 @@ TEST_F(SurfaceTextureGLToGLTest, UpdateTexImageBeforeFrameFinishedCompletes) { // TODO: Add frame verification once RGB TEX_EXTERNAL_OES is supported! } -TEST_F(SurfaceTextureGLToGLTest, UpdateTexImageAfterFrameFinishedCompletes) { +TEST_F(SurfaceTextureGLThreadToGLTest, + UpdateTexImageAfterFrameFinishedCompletes) { class PT : public ProducerThread { virtual void render() { glClearColor(0.0f, 1.0f, 0.0f, 1.0f); @@ -1316,7 +1505,8 @@ TEST_F(SurfaceTextureGLToGLTest, UpdateTexImageAfterFrameFinishedCompletes) { // TODO: Add frame verification once RGB TEX_EXTERNAL_OES is supported! } -TEST_F(SurfaceTextureGLToGLTest, RepeatedUpdateTexImageBeforeFrameFinishedCompletes) { +TEST_F(SurfaceTextureGLThreadToGLTest, + RepeatedUpdateTexImageBeforeFrameFinishedCompletes) { enum { NUM_ITERATIONS = 1024 }; class PT : public ProducerThread { @@ -1344,7 +1534,8 @@ TEST_F(SurfaceTextureGLToGLTest, RepeatedUpdateTexImageBeforeFrameFinishedComple } } -TEST_F(SurfaceTextureGLToGLTest, RepeatedUpdateTexImageAfterFrameFinishedCompletes) { +TEST_F(SurfaceTextureGLThreadToGLTest, + RepeatedUpdateTexImageAfterFrameFinishedCompletes) { enum { NUM_ITERATIONS = 1024 }; class PT : public ProducerThread { @@ -1373,7 +1564,8 @@ TEST_F(SurfaceTextureGLToGLTest, RepeatedUpdateTexImageAfterFrameFinishedComplet } // XXX: This test is disabled because it is currently hanging on some devices. -TEST_F(SurfaceTextureGLToGLTest, DISABLED_RepeatedSwapBuffersWhileDequeueStalledCompletes) { +TEST_F(SurfaceTextureGLThreadToGLTest, + DISABLED_RepeatedSwapBuffersWhileDequeueStalledCompletes) { enum { NUM_ITERATIONS = 64 }; class PT : public ProducerThread { @@ -1438,118 +1630,101 @@ TEST_F(SurfaceTextureGLToGLTest, DISABLED_RepeatedSwapBuffersWhileDequeueStalled } } -TEST_F(SurfaceTextureGLTest, EglDestroySurfaceUnrefsBuffers) { - EGLSurface stcEglSurface = eglCreateWindowSurface(mEglDisplay, mGlConfig, - mANW.get(), NULL); - ASSERT_EQ(EGL_SUCCESS, eglGetError()); - ASSERT_NE(EGL_NO_SURFACE, stcEglSurface); +class SurfaceTextureFBOTest : public SurfaceTextureGLTest { +protected: - sp<GraphicBuffer> buffers[3]; + virtual void SetUp() { + SurfaceTextureGLTest::SetUp(); - for (int i = 0; i < 3; i++) { - // Produce a frame - EXPECT_TRUE(eglMakeCurrent(mEglDisplay, stcEglSurface, stcEglSurface, - mEglContext)); - ASSERT_EQ(EGL_SUCCESS, eglGetError()); - glClear(GL_COLOR_BUFFER_BIT); - eglSwapBuffers(mEglDisplay, stcEglSurface); + glGenFramebuffers(1, &mFbo); + ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError()); - // Consume a frame - EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, - mEglContext)); - ASSERT_EQ(EGL_SUCCESS, eglGetError()); - mST->updateTexImage(); - buffers[i] = mST->getCurrentBuffer(); + glGenTextures(1, &mFboTex); + glBindTexture(GL_TEXTURE_2D, mFboTex); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, getSurfaceWidth(), + getSurfaceHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + glBindTexture(GL_TEXTURE_2D, 0); + ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError()); + + glBindFramebuffer(GL_FRAMEBUFFER, mFbo); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + GL_TEXTURE_2D, mFboTex, 0); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError()); } - // Destroy the GL texture object to release its ref on buffers[2]. - GLuint texID = TEX_ID; - glDeleteTextures(1, &texID); + virtual void TearDown() { + SurfaceTextureGLTest::TearDown(); - // Destroy the EGLSurface - EXPECT_TRUE(eglDestroySurface(mEglDisplay, stcEglSurface)); - ASSERT_EQ(EGL_SUCCESS, eglGetError()); + glDeleteTextures(1, &mFboTex); + glDeleteFramebuffers(1, &mFbo); + } - // Release the ref that the SurfaceTexture has on buffers[2]. - mST->abandon(); + GLuint mFbo; + GLuint mFboTex; +}; - EXPECT_EQ(1, buffers[0]->getStrongCount()); - EXPECT_EQ(1, buffers[1]->getStrongCount()); - EXPECT_EQ(1, buffers[2]->getStrongCount()); -} +// This test is intended to verify that proper synchronization is done when +// rendering into an FBO. +TEST_F(SurfaceTextureFBOTest, BlitFromCpuFilledBufferToFbo) { + const int texWidth = 64; + const int texHeight = 64; -TEST_F(SurfaceTextureGLTest, EglDestroySurfaceAfterAbandonUnrefsBuffers) { - EGLSurface stcEglSurface = eglCreateWindowSurface(mEglDisplay, mGlConfig, - mANW.get(), NULL); - ASSERT_EQ(EGL_SUCCESS, eglGetError()); - ASSERT_NE(EGL_NO_SURFACE, stcEglSurface); + ASSERT_EQ(NO_ERROR, native_window_set_buffers_geometry(mANW.get(), + texWidth, texHeight, HAL_PIXEL_FORMAT_RGBA_8888)); + ASSERT_EQ(NO_ERROR, native_window_set_usage(mANW.get(), + GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN)); - sp<GraphicBuffer> buffers[3]; + android_native_buffer_t* anb; + ASSERT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb)); + ASSERT_TRUE(anb != NULL); - for (int i = 0; i < 3; i++) { - // Produce a frame - EXPECT_TRUE(eglMakeCurrent(mEglDisplay, stcEglSurface, stcEglSurface, - mEglContext)); - ASSERT_EQ(EGL_SUCCESS, eglGetError()); - glClear(GL_COLOR_BUFFER_BIT); - EXPECT_TRUE(eglSwapBuffers(mEglDisplay, stcEglSurface)); - ASSERT_EQ(EGL_SUCCESS, eglGetError()); + sp<GraphicBuffer> buf(new GraphicBuffer(anb, false)); + ASSERT_EQ(NO_ERROR, mANW->lockBuffer(mANW.get(), buf->getNativeBuffer())); - // Consume a frame - EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, - mEglContext)); - ASSERT_EQ(EGL_SUCCESS, eglGetError()); - ASSERT_EQ(NO_ERROR, mST->updateTexImage()); - buffers[i] = mST->getCurrentBuffer(); - } + // Fill the buffer with green + uint8_t* img = NULL; + buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img)); + fillRGBA8BufferSolid(img, texWidth, texHeight, buf->getStride(), 0, 255, + 0, 255); + buf->unlock(); + ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), buf->getNativeBuffer())); - // Abandon the SurfaceTexture, releasing the ref that the SurfaceTexture has - // on buffers[2]. - mST->abandon(); + ASSERT_EQ(NO_ERROR, mST->updateTexImage()); - // Destroy the GL texture object to release its ref on buffers[2]. - GLuint texID = TEX_ID; - glDeleteTextures(1, &texID); + glBindFramebuffer(GL_FRAMEBUFFER, mFbo); + drawTexture(); + glBindFramebuffer(GL_FRAMEBUFFER, 0); - // Destroy the EGLSurface. - EXPECT_TRUE(eglDestroySurface(mEglDisplay, stcEglSurface)); - ASSERT_EQ(EGL_SUCCESS, eglGetError()); + for (int i = 0; i < 4; i++) { + SCOPED_TRACE(String8::format("frame %d", i).string()); - EXPECT_EQ(1, buffers[0]->getStrongCount()); - EXPECT_EQ(1, buffers[1]->getStrongCount()); - EXPECT_EQ(1, buffers[2]->getStrongCount()); -} + ASSERT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb)); + ASSERT_TRUE(anb != NULL); -TEST_F(SurfaceTextureGLTest, InvalidWidthOrHeightFails) { - int texHeight = 16; - ANativeWindowBuffer* anb; + buf = new GraphicBuffer(anb, false); + ASSERT_EQ(NO_ERROR, mANW->lockBuffer(mANW.get(), + buf->getNativeBuffer())); - GLint maxTextureSize; - glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize); + // Fill the buffer with red + ASSERT_EQ(NO_ERROR, buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, + (void**)(&img))); + fillRGBA8BufferSolid(img, texWidth, texHeight, buf->getStride(), 255, 0, + 0, 255); + ASSERT_EQ(NO_ERROR, buf->unlock()); + ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), + buf->getNativeBuffer())); - // make sure it works with small textures - mST->setDefaultBufferSize(16, texHeight); - EXPECT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb)); - EXPECT_EQ(16, anb->width); - EXPECT_EQ(texHeight, anb->height); - EXPECT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), anb)); - EXPECT_EQ(NO_ERROR, mST->updateTexImage()); + ASSERT_EQ(NO_ERROR, mST->updateTexImage()); - // make sure it works with GL_MAX_TEXTURE_SIZE - mST->setDefaultBufferSize(maxTextureSize, texHeight); - EXPECT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb)); - EXPECT_EQ(maxTextureSize, anb->width); - EXPECT_EQ(texHeight, anb->height); - EXPECT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), anb)); - EXPECT_EQ(NO_ERROR, mST->updateTexImage()); + drawTexture(); - // make sure it fails with GL_MAX_TEXTURE_SIZE+1 - mST->setDefaultBufferSize(maxTextureSize+1, texHeight); - EXPECT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb)); - EXPECT_EQ(maxTextureSize+1, anb->width); - EXPECT_EQ(texHeight, anb->height); - EXPECT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), anb)); - ASSERT_NE(NO_ERROR, mST->updateTexImage()); + EXPECT_TRUE(checkPixel( 24, 39, 255, 0, 0, 255)); + } + + glBindFramebuffer(GL_FRAMEBUFFER, mFbo); + + EXPECT_TRUE(checkPixel( 24, 39, 0, 255, 0, 255)); } } // namespace android diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp index a077cbc55f34..158f78503689 100644 --- a/libs/hwui/FontRenderer.cpp +++ b/libs/hwui/FontRenderer.cpp @@ -163,7 +163,6 @@ void Font::render(SkPaint* paint, const char* text, uint32_t start, uint32_t len render(paint, text, start, len, numGlyphs, x, y, FRAMEBUFFER, NULL, 0, 0, NULL); } - } void Font::measure(SkPaint* paint, const char* text, uint32_t start, uint32_t len, @@ -615,7 +614,8 @@ void FontRenderer::issueDrawCommand() { void FontRenderer::appendMeshQuad(float x1, float y1, float z1, float u1, float v1, float x2, float y2, float z2, float u2, float v2, float x3, float y3, float z3, float u3, float v3, float x4, float y4, float z4, float u4, float v4) { - if (x1 > mClip->right || y1 < mClip->top || x2 < mClip->left || y4 > mClip->bottom) { + if (mClip && + (x1 > mClip->right || y1 < mClip->top || x2 < mClip->left || y4 > mClip->bottom)) { return; } @@ -723,11 +723,16 @@ FontRenderer::DropShadow FontRenderer::renderDropShadow(SkPaint* paint, const ch return image; } + mClip = NULL; + mBounds = NULL; + Rect bounds; mCurrentFont->measure(paint, text, startIndex, len, numGlyphs, &bounds); + uint32_t paddedWidth = (uint32_t) (bounds.right - bounds.left) + 2 * radius; uint32_t paddedHeight = (uint32_t) (bounds.top - bounds.bottom) + 2 * radius; uint8_t* dataBuffer = new uint8_t[paddedWidth * paddedHeight]; + for (uint32_t i = 0; i < paddedWidth * paddedHeight; i++) { dataBuffer[i] = 0; } @@ -765,8 +770,11 @@ bool FontRenderer::renderText(SkPaint* paint, const Rect* clip, const char *text mDrawn = false; mBounds = bounds; mClip = clip; + mCurrentFont->render(paint, text, startIndex, len, numGlyphs, x, y); + mBounds = NULL; + mClip = NULL; if (mCurrentQuadIndex != 0) { issueDrawCommand(); diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index 32595e4a55ae..4d226461a02a 100644 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -201,14 +201,16 @@ void OpenGLRenderer::interrupt() { } void OpenGLRenderer::resume() { - glViewport(0, 0, mSnapshot->viewport.getWidth(), mSnapshot->viewport.getHeight()); + sp<Snapshot> snapshot = (mSnapshot != NULL) ? mSnapshot : mFirstSnapshot; + + glViewport(0, 0, snapshot->viewport.getWidth(), snapshot->viewport.getHeight()); glEnable(GL_SCISSOR_TEST); dirtyClip(); glDisable(GL_DITHER); - glBindFramebuffer(GL_FRAMEBUFFER, getTargetFbo()); + glBindFramebuffer(GL_FRAMEBUFFER, snapshot->fbo); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); mCaches.blend = true; diff --git a/libs/hwui/Snapshot.h b/libs/hwui/Snapshot.h index d51154d0710f..aff7b9364a90 100644 --- a/libs/hwui/Snapshot.h +++ b/libs/hwui/Snapshot.h @@ -213,7 +213,8 @@ public: Layer* layer; /** - * Only set when the flag kFlagIsFboLayer is set. + * Target FBO used for rendering. Set to 0 when rendering directly + * into the framebuffer. */ GLuint fbo; diff --git a/libs/rs/rsScriptC.cpp b/libs/rs/rsScriptC.cpp index 2e7f2134fbaa..cd7b3a72ffef 100644 --- a/libs/rs/rsScriptC.cpp +++ b/libs/rs/rsScriptC.cpp @@ -21,6 +21,7 @@ #ifndef ANDROID_RS_SERIALIZE #include <bcinfo/BitcodeTranslator.h> +#include <bcinfo/BitcodeWrapper.h> #endif using namespace android; @@ -196,7 +197,24 @@ bool ScriptC::runCompiler(Context *rsc, //LOGE("runCompiler %p %p %p %p %p %i", rsc, this, resName, cacheDir, bitcode, bitcodeLen); #ifndef ANDROID_RS_SERIALIZE - uint32_t sdkVersion = rsc->getTargetSdkVersion(); + uint32_t sdkVersion = 0; + bcinfo::BitcodeWrapper bcWrapper((const char *)bitcode, bitcodeLen); + if (!bcWrapper.unwrap()) { + LOGE("Bitcode is not in proper container format (raw or wrapper)"); + return false; + } + + rsAssert(bcWrapper.getHeaderVersion() == 0); + if (bcWrapper.getBCFileType() == bcinfo::BC_WRAPPER) { + sdkVersion = bcWrapper.getTargetAPI(); + } + + if (sdkVersion == 0) { + // This signals that we didn't have a wrapper containing information + // about the bitcode. + sdkVersion = rsc->getTargetSdkVersion(); + } + if (BT) { delete BT; } diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java index 5e7a7ebd42ed..37aacabff241 100644 --- a/media/java/android/media/AudioService.java +++ b/media/java/android/media/AudioService.java @@ -508,8 +508,8 @@ public class AudioService extends IAudioService.Stub { // Play sounds on STREAM_RING only and if lock screen is not on. if ((flags & AudioManager.FLAG_PLAY_SOUND) != 0 && - ((STREAM_VOLUME_ALIAS[streamType] != AudioSystem.STREAM_RING) || - (mKeyguardManager != null && mKeyguardManager.isKeyguardLocked()))) { + ((STREAM_VOLUME_ALIAS[streamType] != AudioSystem.STREAM_RING) + || (mKeyguardManager != null && mKeyguardManager.isKeyguardLocked()))) { flags &= ~AudioManager.FLAG_PLAY_SOUND; } @@ -1576,49 +1576,83 @@ public class AudioService extends IAudioService.Stub { private BluetoothProfile.ServiceListener mBluetoothProfileServiceListener = new BluetoothProfile.ServiceListener() { public void onServiceConnected(int profile, BluetoothProfile proxy) { - synchronized (mScoClients) { - // Discard timeout message - mAudioHandler.removeMessages(MSG_BT_HEADSET_CNCT_FAILED); - mBluetoothHeadset = (BluetoothHeadset) proxy; - List<BluetoothDevice> deviceList = mBluetoothHeadset.getConnectedDevices(); + BluetoothDevice btDevice; + List<BluetoothDevice> deviceList; + switch(profile) { + case BluetoothProfile.A2DP: + BluetoothA2dp a2dp = (BluetoothA2dp) proxy; + deviceList = a2dp.getConnectedDevices(); if (deviceList.size() > 0) { - mBluetoothHeadsetDevice = deviceList.get(0); - } else { - mBluetoothHeadsetDevice = null; - } - // Refresh SCO audio state - checkScoAudioState(); - // Continue pending action if any - if (mScoAudioState == SCO_STATE_ACTIVATE_REQ || - mScoAudioState == SCO_STATE_DEACTIVATE_REQ || - mScoAudioState == SCO_STATE_DEACTIVATE_EXT_REQ) { - boolean status = false; - if (mBluetoothHeadsetDevice != null) { - switch (mScoAudioState) { - case SCO_STATE_ACTIVATE_REQ: - mScoAudioState = SCO_STATE_ACTIVE_INTERNAL; - status = mBluetoothHeadset.startScoUsingVirtualVoiceCall( - mBluetoothHeadsetDevice); - break; - case SCO_STATE_DEACTIVATE_REQ: - status = mBluetoothHeadset.stopScoUsingVirtualVoiceCall( - mBluetoothHeadsetDevice); - break; - case SCO_STATE_DEACTIVATE_EXT_REQ: - status = mBluetoothHeadset.stopVoiceRecognition( - mBluetoothHeadsetDevice); - } + btDevice = deviceList.get(0); + handleA2dpConnectionStateChange(btDevice, a2dp.getConnectionState(btDevice)); + } + break; + + case BluetoothProfile.HEADSET: + synchronized (mScoClients) { + // Discard timeout message + mAudioHandler.removeMessages(MSG_BT_HEADSET_CNCT_FAILED); + mBluetoothHeadset = (BluetoothHeadset) proxy; + deviceList = mBluetoothHeadset.getConnectedDevices(); + if (deviceList.size() > 0) { + mBluetoothHeadsetDevice = deviceList.get(0); + } else { + mBluetoothHeadsetDevice = null; } - if (!status) { - sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED, 0, - SENDMSG_REPLACE, 0, 0, null, 0); + // Refresh SCO audio state + checkScoAudioState(); + // Continue pending action if any + if (mScoAudioState == SCO_STATE_ACTIVATE_REQ || + mScoAudioState == SCO_STATE_DEACTIVATE_REQ || + mScoAudioState == SCO_STATE_DEACTIVATE_EXT_REQ) { + boolean status = false; + if (mBluetoothHeadsetDevice != null) { + switch (mScoAudioState) { + case SCO_STATE_ACTIVATE_REQ: + mScoAudioState = SCO_STATE_ACTIVE_INTERNAL; + status = mBluetoothHeadset.startScoUsingVirtualVoiceCall( + mBluetoothHeadsetDevice); + break; + case SCO_STATE_DEACTIVATE_REQ: + status = mBluetoothHeadset.stopScoUsingVirtualVoiceCall( + mBluetoothHeadsetDevice); + break; + case SCO_STATE_DEACTIVATE_EXT_REQ: + status = mBluetoothHeadset.stopVoiceRecognition( + mBluetoothHeadsetDevice); + } + } + if (!status) { + sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED, 0, + SENDMSG_REPLACE, 0, 0, null, 0); + } } } + break; + + default: + break; } } public void onServiceDisconnected(int profile) { - synchronized (mScoClients) { - mBluetoothHeadset = null; + switch(profile) { + case BluetoothProfile.A2DP: + synchronized (mConnectedDevices) { + if (mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP)) { + makeA2dpDeviceUnavailableNow( + mConnectedDevices.get(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP)); + } + } + break; + + case BluetoothProfile.HEADSET: + synchronized (mScoClients) { + mBluetoothHeadset = null; + } + break; + + default: + break; } } }; @@ -2197,15 +2231,17 @@ public class AudioService extends IAudioService.Stub { AudioSystem.setParameters("restarting=true"); // Restore device connection states - Set set = mConnectedDevices.entrySet(); - Iterator i = set.iterator(); - while(i.hasNext()){ - Map.Entry device = (Map.Entry)i.next(); - AudioSystem.setDeviceConnectionState(((Integer)device.getKey()).intValue(), - AudioSystem.DEVICE_STATE_AVAILABLE, - (String)device.getValue()); + synchronized (mConnectedDevices) { + Set set = mConnectedDevices.entrySet(); + Iterator i = set.iterator(); + while(i.hasNext()){ + Map.Entry device = (Map.Entry)i.next(); + AudioSystem.setDeviceConnectionState( + ((Integer)device.getKey()).intValue(), + AudioSystem.DEVICE_STATE_AVAILABLE, + (String)device.getValue()); + } } - // Restore call state AudioSystem.setPhoneState(mMode); @@ -2244,7 +2280,9 @@ public class AudioService extends IAudioService.Stub { case MSG_BTA2DP_DOCK_TIMEOUT: // msg.obj == address of BTA2DP device - makeA2dpDeviceUnavailableNow( (String) msg.obj ); + synchronized (mConnectedDevices) { + makeA2dpDeviceUnavailableNow( (String) msg.obj ); + } break; case MSG_SET_FORCE_USE: @@ -2304,6 +2342,7 @@ public class AudioService extends IAudioService.Stub { } } + // must be called synchronized on mConnectedDevices private void makeA2dpDeviceAvailable(String address) { AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, AudioSystem.DEVICE_STATE_AVAILABLE, @@ -2314,6 +2353,7 @@ public class AudioService extends IAudioService.Stub { address); } + // must be called synchronized on mConnectedDevices private void makeA2dpDeviceUnavailableNow(String address) { Intent noisyIntent = new Intent(AudioManager.ACTION_AUDIO_BECOMING_NOISY); mContext.sendBroadcast(noisyIntent); @@ -2323,6 +2363,7 @@ public class AudioService extends IAudioService.Stub { mConnectedDevices.remove(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP); } + // must be called synchronized on mConnectedDevices private void makeA2dpDeviceUnavailableLater(String address) { // prevent any activity on the A2DP audio output to avoid unwanted // reconnection of the sink. @@ -2335,14 +2376,60 @@ public class AudioService extends IAudioService.Stub { } + // must be called synchronized on mConnectedDevices private void cancelA2dpDeviceTimeout() { mAudioHandler.removeMessages(MSG_BTA2DP_DOCK_TIMEOUT); } + // must be called synchronized on mConnectedDevices private boolean hasScheduledA2dpDockTimeout() { return mAudioHandler.hasMessages(MSG_BTA2DP_DOCK_TIMEOUT); } + private void handleA2dpConnectionStateChange(BluetoothDevice btDevice, int state) + { + if (btDevice == null) { + return; + } + String address = btDevice.getAddress(); + if (!BluetoothAdapter.checkBluetoothAddress(address)) { + address = ""; + } + synchronized (mConnectedDevices) { + boolean isConnected = + (mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) && + mConnectedDevices.get(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP).equals(address)); + + if (isConnected && state != BluetoothProfile.STATE_CONNECTED) { + if (btDevice.isBluetoothDock()) { + if (state == BluetoothProfile.STATE_DISCONNECTED) { + // introduction of a delay for transient disconnections of docks when + // power is rapidly turned off/on, this message will be canceled if + // we reconnect the dock under a preset delay + makeA2dpDeviceUnavailableLater(address); + // the next time isConnected is evaluated, it will be false for the dock + } + } else { + makeA2dpDeviceUnavailableNow(address); + } + } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) { + if (btDevice.isBluetoothDock()) { + // this could be a reconnection after a transient disconnection + cancelA2dpDeviceTimeout(); + mDockAddress = address; + } else { + // this could be a connection of another A2DP device before the timeout of + // a dock: cancel the dock timeout, and make the dock unavailable now + if(hasScheduledA2dpDockTimeout()) { + cancelA2dpDeviceTimeout(); + makeA2dpDeviceUnavailableNow(mDockAddress); + } + } + makeA2dpDeviceAvailable(address); + } + } + } + /* cache of the address of the last dock the device was connected to */ private String mDockAddress; @@ -2380,44 +2467,8 @@ public class AudioService extends IAudioService.Stub { int state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, BluetoothProfile.STATE_DISCONNECTED); BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); - if (btDevice == null) { - return; - } - String address = btDevice.getAddress(); - if (!BluetoothAdapter.checkBluetoothAddress(address)) { - address = ""; - } - boolean isConnected = - (mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) && - mConnectedDevices.get(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP).equals(address)); - - if (isConnected && state != BluetoothProfile.STATE_CONNECTED) { - if (btDevice.isBluetoothDock()) { - if (state == BluetoothProfile.STATE_DISCONNECTED) { - // introduction of a delay for transient disconnections of docks when - // power is rapidly turned off/on, this message will be canceled if - // we reconnect the dock under a preset delay - makeA2dpDeviceUnavailableLater(address); - // the next time isConnected is evaluated, it will be false for the dock - } - } else { - makeA2dpDeviceUnavailableNow(address); - } - } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) { - if (btDevice.isBluetoothDock()) { - // this could be a reconnection after a transient disconnection - cancelA2dpDeviceTimeout(); - mDockAddress = address; - } else { - // this could be a connection of another A2DP device before the timeout of - // a dock: cancel the dock timeout, and make the dock unavailable now - if(hasScheduledA2dpDockTimeout()) { - cancelA2dpDeviceTimeout(); - makeA2dpDeviceUnavailableNow(mDockAddress); - } - } - makeA2dpDeviceAvailable(address); - } + + handleA2dpConnectionStateChange(btDevice, state); } else if (action.equals(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED)) { int state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, BluetoothProfile.STATE_DISCONNECTED); @@ -2446,103 +2497,126 @@ public class AudioService extends IAudioService.Stub { if (!BluetoothAdapter.checkBluetoothAddress(address)) { address = ""; } - boolean isConnected = (mConnectedDevices.containsKey(device) && - mConnectedDevices.get(device).equals(address)); - synchronized (mScoClients) { - if (isConnected && state != BluetoothProfile.STATE_CONNECTED) { - AudioSystem.setDeviceConnectionState(device, + synchronized (mConnectedDevices) { + boolean isConnected = (mConnectedDevices.containsKey(device) && + mConnectedDevices.get(device).equals(address)); + + synchronized (mScoClients) { + if (isConnected && state != BluetoothProfile.STATE_CONNECTED) { + AudioSystem.setDeviceConnectionState(device, AudioSystem.DEVICE_STATE_UNAVAILABLE, address); - mConnectedDevices.remove(device); - mBluetoothHeadsetDevice = null; - resetBluetoothSco(); - } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) { - AudioSystem.setDeviceConnectionState(device, - AudioSystem.DEVICE_STATE_AVAILABLE, - address); - mConnectedDevices.put(new Integer(device), address); - mBluetoothHeadsetDevice = btDevice; + mConnectedDevices.remove(device); + mBluetoothHeadsetDevice = null; + resetBluetoothSco(); + } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) { + AudioSystem.setDeviceConnectionState(device, + AudioSystem.DEVICE_STATE_AVAILABLE, + address); + mConnectedDevices.put(new Integer(device), address); + mBluetoothHeadsetDevice = btDevice; + } } } } else if (action.equals(Intent.ACTION_HEADSET_PLUG)) { int state = intent.getIntExtra("state", 0); int microphone = intent.getIntExtra("microphone", 0); - if (microphone != 0) { - boolean isConnected = - mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_WIRED_HEADSET); - if (state == 0 && isConnected) { - AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_WIRED_HEADSET, - AudioSystem.DEVICE_STATE_UNAVAILABLE, - ""); - mConnectedDevices.remove(AudioSystem.DEVICE_OUT_WIRED_HEADSET); - } else if (state == 1 && !isConnected) { - AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_WIRED_HEADSET, - AudioSystem.DEVICE_STATE_AVAILABLE, - ""); - mConnectedDevices.put( - new Integer(AudioSystem.DEVICE_OUT_WIRED_HEADSET), ""); + synchronized (mConnectedDevices) { + if (microphone != 0) { + boolean isConnected = + mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_WIRED_HEADSET); + if (state == 0 && isConnected) { + AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_WIRED_HEADSET, + AudioSystem.DEVICE_STATE_UNAVAILABLE, + ""); + mConnectedDevices.remove(AudioSystem.DEVICE_OUT_WIRED_HEADSET); + } else if (state == 1 && !isConnected) { + AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_WIRED_HEADSET, + AudioSystem.DEVICE_STATE_AVAILABLE, + ""); + mConnectedDevices.put( + new Integer(AudioSystem.DEVICE_OUT_WIRED_HEADSET), ""); + } + } else { + boolean isConnected = + mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_WIRED_HEADPHONE); + if (state == 0 && isConnected) { + AudioSystem.setDeviceConnectionState( + AudioSystem.DEVICE_OUT_WIRED_HEADPHONE, + AudioSystem.DEVICE_STATE_UNAVAILABLE, + ""); + mConnectedDevices.remove(AudioSystem.DEVICE_OUT_WIRED_HEADPHONE); + } else if (state == 1 && !isConnected) { + AudioSystem.setDeviceConnectionState( + AudioSystem.DEVICE_OUT_WIRED_HEADPHONE, + AudioSystem.DEVICE_STATE_AVAILABLE, + ""); + mConnectedDevices.put( + new Integer(AudioSystem.DEVICE_OUT_WIRED_HEADPHONE), ""); + } } - } else { + } + } else if (action.equals(Intent.ACTION_USB_ANLG_HEADSET_PLUG)) { + int state = intent.getIntExtra("state", 0); + Log.v(TAG, "Broadcast Receiver: Got ACTION_USB_ANLG_HEADSET_PLUG, state = "+state); + synchronized (mConnectedDevices) { boolean isConnected = - mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_WIRED_HEADPHONE); + mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET); if (state == 0 && isConnected) { - AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_WIRED_HEADPHONE, - AudioSystem.DEVICE_STATE_UNAVAILABLE, - ""); - mConnectedDevices.remove(AudioSystem.DEVICE_OUT_WIRED_HEADPHONE); + AudioSystem.setDeviceConnectionState( + AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET, + AudioSystem.DEVICE_STATE_UNAVAILABLE, + ""); + mConnectedDevices.remove(AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET); } else if (state == 1 && !isConnected) { - AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_WIRED_HEADPHONE, - AudioSystem.DEVICE_STATE_AVAILABLE, - ""); + AudioSystem.setDeviceConnectionState( + AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET, + AudioSystem.DEVICE_STATE_AVAILABLE, + ""); mConnectedDevices.put( - new Integer(AudioSystem.DEVICE_OUT_WIRED_HEADPHONE), ""); + new Integer(AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET), ""); } } - } else if (action.equals(Intent.ACTION_USB_ANLG_HEADSET_PLUG)) { - int state = intent.getIntExtra("state", 0); - Log.v(TAG, "Broadcast Receiver: Got ACTION_USB_ANLG_HEADSET_PLUG, state = "+state); - boolean isConnected = - mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET); - if (state == 0 && isConnected) { - AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET, - AudioSystem.DEVICE_STATE_UNAVAILABLE, ""); - mConnectedDevices.remove(AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET); - } else if (state == 1 && !isConnected) { - AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET, - AudioSystem.DEVICE_STATE_AVAILABLE, ""); - mConnectedDevices.put( - new Integer(AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET), ""); - } } else if (action.equals(Intent.ACTION_HDMI_AUDIO_PLUG)) { int state = intent.getIntExtra("state", 0); Log.v(TAG, "Broadcast Receiver: Got ACTION_HDMI_AUDIO_PLUG, state = "+state); - boolean isConnected = - mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_AUX_DIGITAL); - if (state == 0 && isConnected) { - AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_AUX_DIGITAL, - AudioSystem.DEVICE_STATE_UNAVAILABLE, ""); - mConnectedDevices.remove(AudioSystem.DEVICE_OUT_AUX_DIGITAL); - } else if (state == 1 && !isConnected) { - AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_AUX_DIGITAL, - AudioSystem.DEVICE_STATE_AVAILABLE, ""); - mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_AUX_DIGITAL), ""); + synchronized (mConnectedDevices) { + boolean isConnected = + mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_AUX_DIGITAL); + if (state == 0 && isConnected) { + AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_AUX_DIGITAL, + AudioSystem.DEVICE_STATE_UNAVAILABLE, + ""); + mConnectedDevices.remove(AudioSystem.DEVICE_OUT_AUX_DIGITAL); + } else if (state == 1 && !isConnected) { + AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_AUX_DIGITAL, + AudioSystem.DEVICE_STATE_AVAILABLE, + ""); + mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_AUX_DIGITAL), ""); + } } } else if (action.equals(Intent.ACTION_USB_DGTL_HEADSET_PLUG)) { int state = intent.getIntExtra("state", 0); Log.v(TAG, "Broadcast Receiver: Got ACTION_USB_DGTL_HEADSET_PLUG, state = "+state); - boolean isConnected = - mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET); - if (state == 0 && isConnected) { - AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET, - AudioSystem.DEVICE_STATE_UNAVAILABLE, ""); - mConnectedDevices.remove(AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET); - } else if (state == 1 && !isConnected) { - AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET, - AudioSystem.DEVICE_STATE_AVAILABLE, ""); - mConnectedDevices.put( - new Integer(AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET), ""); + synchronized (mConnectedDevices) { + boolean isConnected = + mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET); + if (state == 0 && isConnected) { + AudioSystem.setDeviceConnectionState( + AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET, + AudioSystem.DEVICE_STATE_UNAVAILABLE, + ""); + mConnectedDevices.remove(AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET); + } else if (state == 1 && !isConnected) { + AudioSystem.setDeviceConnectionState( + AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET, + AudioSystem.DEVICE_STATE_AVAILABLE, + ""); + mConnectedDevices.put( + new Integer(AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET), ""); + } } } else if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) { boolean broadcast = false; @@ -2596,7 +2670,7 @@ public class AudioService extends IAudioService.Stub { 0, 0, null, 0); mKeyguardManager = - (KeyguardManager)mContext.getSystemService(Context.KEYGUARD_SERVICE); + (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE); mScoConnectionState = AudioManager.SCO_AUDIO_STATE_ERROR; resetBluetoothSco(); getBluetoothHeadset(); @@ -2606,6 +2680,12 @@ public class AudioService extends IAudioService.Stub { newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, AudioManager.SCO_AUDIO_STATE_DISCONNECTED); mContext.sendStickyBroadcast(newIntent); + + BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); + if (adapter != null) { + adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener, + BluetoothProfile.A2DP); + } } else if (action.equals(Intent.ACTION_PACKAGE_REMOVED)) { if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) { // a package is being removed, not replaced @@ -3407,7 +3487,7 @@ public class AudioService extends IAudioService.Stub { updateRemoteControlDisplay_syncAfRcs(infoChangedFlags); } - /** + /** * see AudioManager.registerMediaButtonIntent(PendingIntent pi, ComponentName c) * precondition: mediaIntent != null, target != null */ @@ -3423,7 +3503,7 @@ public class AudioService extends IAudioService.Stub { } } - /** + /** * see AudioManager.unregisterMediaButtonIntent(PendingIntent mediaIntent) * precondition: mediaIntent != null, eventReceiver != null */ diff --git a/media/java/android/media/videoeditor/MediaArtistNativeHelper.java b/media/java/android/media/videoeditor/MediaArtistNativeHelper.java index 03ae62ac1e53..475607850a40 100644 --- a/media/java/android/media/videoeditor/MediaArtistNativeHelper.java +++ b/media/java/android/media/videoeditor/MediaArtistNativeHelper.java @@ -1845,7 +1845,7 @@ class MediaArtistNativeHelper { @SuppressWarnings("unused") private void onPreviewProgressUpdate(int progress, boolean isFinished, - boolean updateOverlay, String filename, int renderingMode) { + boolean updateOverlay, String filename, int renderingMode, int error) { if (mPreviewProgressListener != null) { if (mIsFirstProgress) { mPreviewProgressListener.onStart(mVideoEditor); @@ -1870,6 +1870,8 @@ class MediaArtistNativeHelper { if (isFinished) { mPreviewProgressListener.onStop(mVideoEditor); + } else if (error != 0) { + mPreviewProgressListener.onError(mVideoEditor, error); } else { mPreviewProgressListener.onProgress(mVideoEditor, progress, overlayData); } diff --git a/media/java/android/media/videoeditor/VideoEditor.java b/media/java/android/media/videoeditor/VideoEditor.java index 424e436f04e1..08d27d461f10 100755 --- a/media/java/android/media/videoeditor/VideoEditor.java +++ b/media/java/android/media/videoeditor/VideoEditor.java @@ -107,6 +107,17 @@ public interface VideoEditor { * @param videoEditor The VideoEditor instance */ public void onStop(VideoEditor videoEditor); + + /** + * This method notifies the listener when error has occurred during + * previewing a project. + * + * @param videoEditor The VideoEditor instance + * @param error The error that has occurred + * FIXME: We should pass well-defined error code to the application; + * but for now, we just pass whatever error code reported by the native layer. + */ + public void onError(VideoEditor videoEditor, int error); } /** diff --git a/media/java/android/mtp/MtpDatabase.java b/media/java/android/mtp/MtpDatabase.java index 4e271c7bf568..19db1c017718 100644..100755 --- a/media/java/android/mtp/MtpDatabase.java +++ b/media/java/android/mtp/MtpDatabase.java @@ -38,6 +38,7 @@ import android.view.WindowManager; import java.io.File; import java.util.HashMap; +import java.util.Locale; /** * {@hide} @@ -50,7 +51,15 @@ public class MtpDatabase { private final IContentProvider mMediaProvider; private final String mVolumeName; private final Uri mObjectsUri; - private final String mMediaStoragePath; // path to primary storage + // path to primary storage + private final String mMediaStoragePath; + // if not null, restrict all queries to these subdirectories + private final String[] mSubDirectories; + // where clause for restricting queries to files in mSubDirectories + private String mSubDirectoriesWhere; + // where arguments for restricting queries to files in mSubDirectories + private String[] mSubDirectoriesWhereArgs; + private final HashMap<String, MtpStorage> mStorageMap = new HashMap<String, MtpStorage>(); // cached property groups for single properties @@ -111,7 +120,8 @@ public class MtpDatabase { System.loadLibrary("media_jni"); } - public MtpDatabase(Context context, String volumeName, String storagePath) { + public MtpDatabase(Context context, String volumeName, String storagePath, + String[] subDirectories) { native_setup(); mContext = context; @@ -120,6 +130,45 @@ public class MtpDatabase { mMediaStoragePath = storagePath; mObjectsUri = Files.getMtpObjectsUri(volumeName); mMediaScanner = new MediaScanner(context); + + mSubDirectories = subDirectories; + if (subDirectories != null) { + // Compute "where" string for restricting queries to subdirectories + StringBuilder builder = new StringBuilder(); + builder.append("("); + int count = subDirectories.length; + for (int i = 0; i < count; i++) { + builder.append(Files.FileColumns.DATA + "=? OR " + + Files.FileColumns.DATA + " LIKE ?"); + if (i != count - 1) { + builder.append(" OR "); + } + } + builder.append(")"); + mSubDirectoriesWhere = builder.toString(); + + // Compute "where" arguments for restricting queries to subdirectories + mSubDirectoriesWhereArgs = new String[count * 2]; + for (int i = 0, j = 0; i < count; i++) { + String path = subDirectories[i]; + mSubDirectoriesWhereArgs[j++] = path; + mSubDirectoriesWhereArgs[j++] = path + "/%"; + } + } + + // Set locale to MediaScanner. + Locale locale = context.getResources().getConfiguration().locale; + if (locale != null) { + String language = locale.getLanguage(); + String country = locale.getCountry(); + if (language != null) { + if (country != null) { + mMediaScanner.setLocale(language + "_" + country); + } else { + mMediaScanner.setLocale(language); + } + } + } initDeviceProperties(context); } @@ -175,9 +224,44 @@ public class MtpDatabase { } } + // check to see if the path is contained in one of our storage subdirectories + // returns true if we have no special subdirectories + private boolean inStorageSubDirectory(String path) { + if (mSubDirectories == null) return true; + if (path == null) return false; + + boolean allowed = false; + int pathLength = path.length(); + for (int i = 0; i < mSubDirectories.length && !allowed; i++) { + String subdir = mSubDirectories[i]; + int subdirLength = subdir.length(); + if (subdirLength < pathLength && + path.charAt(subdirLength) == '/' && + path.startsWith(subdir)) { + allowed = true; + } + } + return allowed; + } + + // check to see if the path matches one of our storage subdirectories + // returns true if we have no special subdirectories + private boolean isStorageSubDirectory(String path) { + if (mSubDirectories == null) return false; + for (int i = 0; i < mSubDirectories.length; i++) { + if (path.equals(mSubDirectories[i])) { + return true; + } + } + return false; + } + private int beginSendObject(String path, int format, int parent, int storageId, long size, long modified) { - // first make sure the object does not exist + // if mSubDirectories is not null, do not allow copying files to any other locations + if (!inStorageSubDirectory(path)) return -1; + + // make sure the object does not exist if (path != null) { Cursor c = null; try { @@ -254,33 +338,40 @@ public class MtpDatabase { } private Cursor createObjectQuery(int storageID, int format, int parent) throws RemoteException { + String where; + String[] whereArgs; + if (storageID == 0xFFFFFFFF) { // query all stores if (format == 0) { // query all formats if (parent == 0) { // query all objects - return mMediaProvider.query(mObjectsUri, ID_PROJECTION, null, null, null); - } - if (parent == 0xFFFFFFFF) { - // all objects in root of store - parent = 0; + where = null; + whereArgs = null; + } else { + if (parent == 0xFFFFFFFF) { + // all objects in root of store + parent = 0; + } + where = PARENT_WHERE; + whereArgs = new String[] { Integer.toString(parent) }; } - return mMediaProvider.query(mObjectsUri, ID_PROJECTION, PARENT_WHERE, - new String[] { Integer.toString(parent) }, null); } else { // query specific format if (parent == 0) { // query all objects - return mMediaProvider.query(mObjectsUri, ID_PROJECTION, FORMAT_WHERE, - new String[] { Integer.toString(format) }, null); - } - if (parent == 0xFFFFFFFF) { - // all objects in root of store - parent = 0; + where = FORMAT_WHERE; + whereArgs = new String[] { Integer.toString(format) }; + } else { + if (parent == 0xFFFFFFFF) { + // all objects in root of store + parent = 0; + } + where = FORMAT_PARENT_WHERE; + whereArgs = new String[] { Integer.toString(format), + Integer.toString(parent) }; } - return mMediaProvider.query(mObjectsUri, ID_PROJECTION, FORMAT_PARENT_WHERE, - new String[] { Integer.toString(format), Integer.toString(parent) }, null); } } else { // query specific store @@ -288,35 +379,61 @@ public class MtpDatabase { // query all formats if (parent == 0) { // query all objects - return mMediaProvider.query(mObjectsUri, ID_PROJECTION, STORAGE_WHERE, - new String[] { Integer.toString(storageID) }, null); - } - if (parent == 0xFFFFFFFF) { - // all objects in root of store - parent = 0; + where = STORAGE_WHERE; + whereArgs = new String[] { Integer.toString(storageID) }; + } else { + if (parent == 0xFFFFFFFF) { + // all objects in root of store + parent = 0; + } + where = STORAGE_PARENT_WHERE; + whereArgs = new String[] { Integer.toString(storageID), + Integer.toString(parent) }; } - return mMediaProvider.query(mObjectsUri, ID_PROJECTION, STORAGE_PARENT_WHERE, - new String[] { Integer.toString(storageID), Integer.toString(parent) }, - null); } else { // query specific format if (parent == 0) { // query all objects - return mMediaProvider.query(mObjectsUri, ID_PROJECTION, STORAGE_FORMAT_WHERE, - new String[] { Integer.toString(storageID), Integer.toString(format) }, - null); + where = STORAGE_FORMAT_WHERE; + whereArgs = new String[] { Integer.toString(storageID), + Integer.toString(format) }; + } else { + if (parent == 0xFFFFFFFF) { + // all objects in root of store + parent = 0; + } + where = STORAGE_FORMAT_PARENT_WHERE; + whereArgs = new String[] { Integer.toString(storageID), + Integer.toString(format), + Integer.toString(parent) }; } - if (parent == 0xFFFFFFFF) { - // all objects in root of store - parent = 0; + } + } + + // if we are restricting queries to mSubDirectories, we need to add the restriction + // onto our "where" arguments + if (mSubDirectoriesWhere != null) { + if (where == null) { + where = mSubDirectoriesWhere; + whereArgs = mSubDirectoriesWhereArgs; + } else { + where = where + " AND " + mSubDirectoriesWhere; + + // create new array to hold whereArgs and mSubDirectoriesWhereArgs + String[] newWhereArgs = + new String[whereArgs.length + mSubDirectoriesWhereArgs.length]; + int i, j; + for (i = 0; i < whereArgs.length; i++) { + newWhereArgs[i] = whereArgs[i]; } - return mMediaProvider.query(mObjectsUri, ID_PROJECTION, STORAGE_FORMAT_PARENT_WHERE, - new String[] { Integer.toString(storageID), - Integer.toString(format), - Integer.toString(parent) }, - null); + for (j = 0; j < mSubDirectoriesWhereArgs.length; i++, j++) { + newWhereArgs[i] = mSubDirectoriesWhereArgs[j]; + } + whereArgs = newWhereArgs; } } + + return mMediaProvider.query(mObjectsUri, ID_PROJECTION, where, whereArgs, null); } private int[] getObjectList(int storageID, int format, int parent) { @@ -598,6 +715,11 @@ public class MtpDatabase { return MtpConstants.RESPONSE_INVALID_OBJECT_HANDLE; } + // do not allow renaming any of the special subdirectories + if (isStorageSubDirectory(path)) { + return MtpConstants.RESPONSE_OBJECT_WRITE_PROTECTED; + } + // now rename the file. make sure this succeeds before updating database File oldFile = new File(path); int lastSlash = path.lastIndexOf('/'); @@ -779,6 +901,11 @@ public class MtpDatabase { return MtpConstants.RESPONSE_GENERAL_ERROR; } + // do not allow deleting any of the special subdirectories + if (isStorageSubDirectory(path)) { + return MtpConstants.RESPONSE_OBJECT_WRITE_PROTECTED; + } + if (format == MtpConstants.FORMAT_ASSOCIATION) { // recursive case - delete all children first Uri uri = Files.getMtpObjectsUri(mVolumeName); diff --git a/media/jni/mediaeditor/VideoEditorMain.cpp b/media/jni/mediaeditor/VideoEditorMain.cpp index ed4e92edca20..3d6d85788ef4 100755 --- a/media/jni/mediaeditor/VideoEditorMain.cpp +++ b/media/jni/mediaeditor/VideoEditorMain.cpp @@ -477,7 +477,7 @@ static void jniPreviewProgressCallback (void* cookie, M4OSA_UInt32 msgType, pEnv->CallVoidMethod(pContext->engine, pContext->onPreviewProgressUpdateMethodId, currentMs,isFinished, pContext->mIsUpdateOverlay, - tmpFileName, pContext->mOverlayRenderingMode); + tmpFileName, pContext->mOverlayRenderingMode, error); if (pContext->mIsUpdateOverlay) { pContext->mIsUpdateOverlay = false; @@ -1630,7 +1630,7 @@ videoEditor_populateSettings( "not initialized"); pContext->onPreviewProgressUpdateMethodId = pEnv->GetMethodID(engineClass, - "onPreviewProgressUpdate", "(IZZLjava/lang/String;I)V"); + "onPreviewProgressUpdate", "(IZZLjava/lang/String;II)V"); // Check if the context is valid (required because the context is dereferenced). if (needToBeLoaded) { // Make sure that we are in a correct state. diff --git a/media/libmedia/IStreamSource.cpp b/media/libmedia/IStreamSource.cpp index b311f3522518..078be9446c88 100644 --- a/media/libmedia/IStreamSource.cpp +++ b/media/libmedia/IStreamSource.cpp @@ -30,7 +30,7 @@ namespace android { const char *const IStreamListener::kKeyResumeAtPTS = "resume-at-PTS"; // static -const char *const IStreamListener::kKeyFormatChange = "format-change"; +const char *const IStreamListener::kKeyDiscontinuityMask = "discontinuity-mask"; enum { // IStreamSource diff --git a/media/libmedia/MediaScannerClient.cpp b/media/libmedia/MediaScannerClient.cpp index 7a7aeb638b25..629b165dd491 100644 --- a/media/libmedia/MediaScannerClient.cpp +++ b/media/libmedia/MediaScannerClient.cpp @@ -82,7 +82,7 @@ status_t MediaScannerClient::addStringTag(const char* name, const char* value) // save the strings for later so they can be used for native encoding detection mNames->push_back(name); mValues->push_back(value); - return true; + return OK; } // else fall through } diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp index 2a5c0a6c53c6..93ab7043cf30 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp @@ -54,6 +54,7 @@ NuPlayer::NuPlayer() mVideoEOS(false), mScanSourcesPending(false), mScanSourcesGeneration(0), + mTimeDiscontinuityPending(false), mFlushingAudio(NONE), mFlushingVideo(NONE), mResetInProgress(false), @@ -462,11 +463,24 @@ void NuPlayer::onMessageReceived(const sp<AMessage> &msg) { { LOGV("kWhatReset"); + if (mRenderer != NULL) { + // There's an edge case where the renderer owns all output + // buffers and is paused, therefore the decoder will not read + // more input data and will never encounter the matching + // discontinuity. To avoid this, we resume the renderer. + + if (mFlushingAudio == AWAITING_DISCONTINUITY + || mFlushingVideo == AWAITING_DISCONTINUITY) { + mRenderer->resume(); + } + } + if (mFlushingAudio != NONE || mFlushingVideo != NONE) { // We're currently flushing, postpone the reset until that's // completed. - LOGV("postponing reset"); + LOGV("postponing reset mFlushingAudio=%d, mFlushingVideo=%d", + mFlushingAudio, mFlushingVideo); mResetPostponed = true; break; @@ -477,6 +491,8 @@ void NuPlayer::onMessageReceived(const sp<AMessage> &msg) { break; } + mTimeDiscontinuityPending = true; + if (mAudioDecoder != NULL) { flushDecoder(true /* audio */, true /* needShutdown */); } @@ -540,7 +556,10 @@ void NuPlayer::finishFlushIfPossible() { LOGV("both audio and video are flushed now."); - mRenderer->signalTimeDiscontinuity(); + if (mTimeDiscontinuityPending) { + mRenderer->signalTimeDiscontinuity(); + mTimeDiscontinuityPending = false; + } if (mAudioDecoder != NULL) { mAudioDecoder->signalResume(); @@ -663,10 +682,15 @@ status_t NuPlayer::feedDecoderInputData(bool audio, const sp<AMessage> &msg) { CHECK(accessUnit->meta()->findInt32("discontinuity", &type)); bool formatChange = - type == ATSParser::DISCONTINUITY_FORMATCHANGE; + (audio && + (type & ATSParser::DISCONTINUITY_AUDIO_FORMAT)) + || (!audio && + (type & ATSParser::DISCONTINUITY_VIDEO_FORMAT)); + + bool timeChange = (type & ATSParser::DISCONTINUITY_TIME) != 0; - LOGV("%s discontinuity (formatChange=%d)", - audio ? "audio" : "video", formatChange); + LOGI("%s discontinuity (formatChange=%d, time=%d)", + audio ? "audio" : "video", formatChange, timeChange); if (audio) { mSkipRenderingAudioUntilMediaTimeUs = -1; @@ -674,26 +698,45 @@ status_t NuPlayer::feedDecoderInputData(bool audio, const sp<AMessage> &msg) { mSkipRenderingVideoUntilMediaTimeUs = -1; } - sp<AMessage> extra; - if (accessUnit->meta()->findMessage("extra", &extra) - && extra != NULL) { - int64_t resumeAtMediaTimeUs; - if (extra->findInt64( - "resume-at-mediatimeUs", &resumeAtMediaTimeUs)) { - LOGI("suppressing rendering of %s until %lld us", - audio ? "audio" : "video", resumeAtMediaTimeUs); - - if (audio) { - mSkipRenderingAudioUntilMediaTimeUs = - resumeAtMediaTimeUs; - } else { - mSkipRenderingVideoUntilMediaTimeUs = - resumeAtMediaTimeUs; + if (timeChange) { + sp<AMessage> extra; + if (accessUnit->meta()->findMessage("extra", &extra) + && extra != NULL) { + int64_t resumeAtMediaTimeUs; + if (extra->findInt64( + "resume-at-mediatimeUs", &resumeAtMediaTimeUs)) { + LOGI("suppressing rendering of %s until %lld us", + audio ? "audio" : "video", resumeAtMediaTimeUs); + + if (audio) { + mSkipRenderingAudioUntilMediaTimeUs = + resumeAtMediaTimeUs; + } else { + mSkipRenderingVideoUntilMediaTimeUs = + resumeAtMediaTimeUs; + } } } } - flushDecoder(audio, formatChange); + mTimeDiscontinuityPending = + mTimeDiscontinuityPending || timeChange; + + if (formatChange || timeChange) { + flushDecoder(audio, formatChange); + } else { + // This stream is unaffected by the discontinuity + + if (audio) { + mFlushingAudio = FLUSHED; + } else { + mFlushingVideo = FLUSHED; + } + + finishFlushIfPossible(); + + return -EWOULDBLOCK; + } } reply->setInt32("err", err); @@ -794,6 +837,11 @@ void NuPlayer::notifyListener(int msg, int ext1, int ext2) { } void NuPlayer::flushDecoder(bool audio, bool needShutdown) { + if ((audio && mAudioDecoder == NULL) || (!audio && mVideoDecoder == NULL)) { + LOGI("flushDecoder %s without decoder present", + audio ? "audio" : "video"); + } + // Make sure we don't continue to scan sources until we finish flushing. ++mScanSourcesGeneration; mScanSourcesPending = false; diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h index f23deea60765..ffc710ee05c1 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h @@ -112,6 +112,10 @@ private: SHUT_DOWN, }; + // Once the current flush is complete this indicates whether the + // notion of time has changed. + bool mTimeDiscontinuityPending; + FlushStatus mFlushingAudio; FlushStatus mFlushingVideo; bool mResetInProgress; diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp index 640e9fac9c07..0cb7f45b6f62 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp @@ -628,11 +628,16 @@ void NuPlayer::Renderer::onPause() { mAudioSink->pause(); } + LOGV("now paused audio queue has %d entries, video has %d entries", + mAudioQueue.size(), mVideoQueue.size()); + mPaused = true; } void NuPlayer::Renderer::onResume() { - CHECK(mPaused); + if (!mPaused) { + return; + } if (mHasAudio) { mAudioSink->start(); diff --git a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp index e72adc4a24e8..a3f2bf68bec6 100644 --- a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp +++ b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp @@ -38,7 +38,8 @@ NuPlayer::RTSPSource::RTSPSource( mFlags(0), mState(DISCONNECTED), mFinalResult(OK), - mDisconnectReplyID(0) { + mDisconnectReplyID(0), + mSeekGeneration(0) { if (headers) { mExtraHeaders = *headers; @@ -146,14 +147,21 @@ status_t NuPlayer::RTSPSource::getDuration(int64_t *durationUs) { } status_t NuPlayer::RTSPSource::seekTo(int64_t seekTimeUs) { + sp<AMessage> msg = new AMessage(kWhatPerformSeek, mReflector->id()); + msg->setInt32("generation", ++mSeekGeneration); + msg->setInt64("timeUs", seekTimeUs); + msg->post(200000ll); + + return OK; +} + +void NuPlayer::RTSPSource::performSeek(int64_t seekTimeUs) { if (mState != CONNECTED) { - return UNKNOWN_ERROR; + return; } mState = SEEKING; mHandler->seek(seekTimeUs); - - return OK; } bool NuPlayer::RTSPSource::isSeekable() { @@ -168,6 +176,20 @@ void NuPlayer::RTSPSource::onMessageReceived(const sp<AMessage> &msg) { mDisconnectReplyID = replyID; finishDisconnectIfPossible(); return; + } else if (msg->what() == kWhatPerformSeek) { + int32_t generation; + CHECK(msg->findInt32("generation", &generation)); + + if (generation != mSeekGeneration) { + // obsolete. + return; + } + + int64_t seekTimeUs; + CHECK(msg->findInt64("timeUs", &seekTimeUs)); + + performSeek(seekTimeUs); + return; } CHECK_EQ(msg->what(), (int)kWhatNotify); @@ -208,21 +230,32 @@ void NuPlayer::RTSPSource::onMessageReceived(const sp<AMessage> &msg) { break; } - const TrackInfo &info = mTracks.editItemAt(trackIndex); - sp<AnotherPacketSource> source = info.mSource; + TrackInfo *info = &mTracks.editItemAt(trackIndex); + + sp<AnotherPacketSource> source = info->mSource; if (source != NULL) { -#if 1 uint32_t rtpTime; CHECK(accessUnit->meta()->findInt32("rtp-time", (int32_t *)&rtpTime)); + if (!info->mNPTMappingValid) { + // This is a live stream, we didn't receive any normal + // playtime mapping. Assume the first packets correspond + // to time 0. + + LOGV("This is a live stream, assuming time = 0"); + + info->mRTPTime = rtpTime; + info->mNormalPlaytimeUs = 0ll; + info->mNPTMappingValid = true; + } + int64_t nptUs = - ((double)rtpTime - (double)info.mRTPTime) - / info.mTimeScale + ((double)rtpTime - (double)info->mRTPTime) + / info->mTimeScale * 1000000ll - + info.mNormalPlaytimeUs; + + info->mNormalPlaytimeUs; accessUnit->meta()->setInt64("timeUs", nptUs); -#endif source->queueAccessUnit(accessUnit); } @@ -278,6 +311,7 @@ void NuPlayer::RTSPSource::onMessageReceived(const sp<AMessage> &msg) { TrackInfo *info = &mTracks.editItemAt(trackIndex); info->mRTPTime = rtpTime; info->mNormalPlaytimeUs = nptUs; + info->mNPTMappingValid = true; break; } @@ -305,6 +339,7 @@ void NuPlayer::RTSPSource::onConnected() { info.mTimeScale = timeScale; info.mRTPTime = 0; info.mNormalPlaytimeUs = 0ll; + info.mNPTMappingValid = false; if ((isAudio && mAudioTrack == NULL) || (isVideo && mVideoTrack == NULL)) { diff --git a/media/libmediaplayerservice/nuplayer/RTSPSource.h b/media/libmediaplayerservice/nuplayer/RTSPSource.h index 66eab7254df0..59d06ada8662 100644 --- a/media/libmediaplayerservice/nuplayer/RTSPSource.h +++ b/media/libmediaplayerservice/nuplayer/RTSPSource.h @@ -56,6 +56,7 @@ private: enum { kWhatNotify = 'noti', kWhatDisconnect = 'disc', + kWhatPerformSeek = 'seek', }; enum State { @@ -76,6 +77,7 @@ private: int32_t mTimeScale; uint32_t mRTPTime; int64_t mNormalPlaytimeUs; + bool mNPTMappingValid; }; AString mURL; @@ -95,12 +97,16 @@ private: sp<AnotherPacketSource> mAudioTrack; sp<AnotherPacketSource> mVideoTrack; + int32_t mSeekGeneration; + sp<AnotherPacketSource> getSource(bool audio); void onConnected(); void onDisconnected(const sp<AMessage> &msg); void finishDisconnectIfPossible(); + void performSeek(int64_t seekTimeUs); + DISALLOW_EVIL_CONSTRUCTORS(RTSPSource); }; diff --git a/media/libmediaplayerservice/nuplayer/StreamingSource.cpp b/media/libmediaplayerservice/nuplayer/StreamingSource.cpp index f79565425665..2e63b3b6afbe 100644 --- a/media/libmediaplayerservice/nuplayer/StreamingSource.cpp +++ b/media/libmediaplayerservice/nuplayer/StreamingSource.cpp @@ -63,17 +63,22 @@ status_t NuPlayer::StreamingSource::feedMoreTSData() { mFinalResult = ERROR_END_OF_STREAM; break; } else if (n == INFO_DISCONTINUITY) { - ATSParser::DiscontinuityType type = ATSParser::DISCONTINUITY_SEEK; + int32_t type = ATSParser::DISCONTINUITY_SEEK; - int32_t formatChange; + int32_t mask; if (extra != NULL && extra->findInt32( - IStreamListener::kKeyFormatChange, &formatChange) - && formatChange != 0) { - type = ATSParser::DISCONTINUITY_FORMATCHANGE; + IStreamListener::kKeyDiscontinuityMask, &mask)) { + if (mask == 0) { + LOGE("Client specified an illegal discontinuity type."); + return ERROR_UNSUPPORTED; + } + + type = mask; } - mTSParser->signalDiscontinuity(type, extra); + mTSParser->signalDiscontinuity( + (ATSParser::DiscontinuityType)type, extra); } else if (n < 0) { CHECK_EQ(n, -EWOULDBLOCK); break; diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp index d947760c19b6..dbc9b7ecb5df 100644 --- a/media/libstagefright/ACodec.cpp +++ b/media/libstagefright/ACodec.cpp @@ -342,6 +342,7 @@ void ACodec::initiateSetup(const sp<AMessage> &msg) { } void ACodec::signalFlush() { + LOGV("[%s] signalFlush", mComponentName.c_str()); (new AMessage(kWhatFlush, id()))->post(); } @@ -1092,6 +1093,20 @@ status_t ACodec::initNativeWindow() { return OK; } +size_t ACodec::countBuffersOwnedByComponent(OMX_U32 portIndex) const { + size_t n = 0; + + for (size_t i = 0; i < mBuffers[portIndex].size(); ++i) { + const BufferInfo &info = mBuffers[portIndex].itemAt(i); + + if (info.mStatus == BufferInfo::OWNED_BY_COMPONENT) { + ++n; + } + } + + return n; +} + bool ACodec::allYourBuffersAreBelongToUs( OMX_U32 portIndex) { for (size_t i = 0; i < mBuffers[portIndex].size(); ++i) { @@ -2041,6 +2056,14 @@ bool ACodec::ExecutingState::onMessageReceived(const sp<AMessage> &msg) { case kWhatFlush: { + LOGV("[%s] ExecutingState flushing now " + "(codec owns %d/%d input, %d/%d output).", + mCodec->mComponentName.c_str(), + mCodec->countBuffersOwnedByComponent(kPortIndexInput), + mCodec->mBuffers[kPortIndexInput].size(), + mCodec->countBuffersOwnedByComponent(kPortIndexOutput), + mCodec->mBuffers[kPortIndexOutput].size()); + mActive = false; CHECK_EQ(mCodec->mOMX->sendCommand( @@ -2180,6 +2203,12 @@ bool ACodec::OutputPortSettingsChangedState::onOMXEvent( err); mCodec->signalError(); + + // This is technically not correct, since we were unable + // to allocate output buffers and therefore the output port + // remains disabled. It is necessary however to allow us + // to shutdown the codec properly. + mCodec->changeState(mCodec->mExecutingState); } return true; @@ -2408,6 +2437,9 @@ bool ACodec::FlushingState::onMessageReceived(const sp<AMessage> &msg) { bool ACodec::FlushingState::onOMXEvent( OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2) { + LOGV("[%s] FlushingState onOMXEvent(%d,%ld)", + mCodec->mComponentName.c_str(), event, data1); + switch (event) { case OMX_EventCmdComplete: { diff --git a/media/libstagefright/AVIExtractor.cpp b/media/libstagefright/AVIExtractor.cpp index 0be2ca40153d..815f987bb504 100644 --- a/media/libstagefright/AVIExtractor.cpp +++ b/media/libstagefright/AVIExtractor.cpp @@ -1094,7 +1094,7 @@ status_t AVIExtractor::addH264CodecSpecificData(size_t trackIndex) { CHECK(meta->findData(kKeyAVCC, &type, &csd, &csdSize)); track->mMeta->setInt32(kKeyWidth, width); - track->mMeta->setInt32(kKeyHeight, width); + track->mMeta->setInt32(kKeyHeight, height); track->mMeta->setData(kKeyAVCC, type, csd, csdSize); return OK; diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk index 0aeb515d0181..690deac38e18 100644 --- a/media/libstagefright/Android.mk +++ b/media/libstagefright/Android.mk @@ -9,7 +9,6 @@ LOCAL_SRC_FILES:= \ AACWriter.cpp \ AMRExtractor.cpp \ AMRWriter.cpp \ - AVIExtractor.cpp \ AudioPlayer.cpp \ AudioSource.cpp \ AwesomePlayer.cpp \ diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp index f6d054d244eb..ba6ff10bde0c 100644 --- a/media/libstagefright/AwesomePlayer.cpp +++ b/media/libstagefright/AwesomePlayer.cpp @@ -335,11 +335,13 @@ status_t AwesomePlayer::setDataSource_l( return UNKNOWN_ERROR; } - dataSource->getDrmInfo(mDecryptHandle, &mDrmManagerClient); - if (mDecryptHandle != NULL) { - CHECK(mDrmManagerClient); - if (RightsStatus::RIGHTS_VALID != mDecryptHandle->status) { - notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, ERROR_DRM_NO_LICENSE); + if (extractor->getDrmFlag()) { + dataSource->getDrmInfo(mDecryptHandle, &mDrmManagerClient); + if (mDecryptHandle != NULL) { + CHECK(mDrmManagerClient); + if (RightsStatus::RIGHTS_VALID != mDecryptHandle->status) { + notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, ERROR_DRM_NO_LICENSE); + } } } @@ -1949,6 +1951,8 @@ status_t AwesomePlayer::finishSetDataSource_l() { mUri = newURI; } + AString sniffedMIME; + if (!strncasecmp("http://", mUri.string(), 7) || !strncasecmp("https://", mUri.string(), 8) || isWidevineStreaming) { @@ -1998,7 +2002,6 @@ status_t AwesomePlayer::finishSetDataSource_l() { mConnectingDataSource.clear(); - String8 contentType = dataSource->getMIMEType(); if (strncasecmp(contentType.string(), "audio/", 6)) { @@ -2020,16 +2023,51 @@ status_t AwesomePlayer::finishSetDataSource_l() { mLock.unlock(); + // Initially make sure we have at least 192 KB for the sniff + // to complete without blocking. + static const size_t kMinBytesForSniffing = 192 * 1024; + + off64_t metaDataSize = -1ll; for (;;) { status_t finalStatus; size_t cachedDataRemaining = mCachedSource->approxDataRemaining(&finalStatus); - if (finalStatus != OK || cachedDataRemaining >= kHighWaterMarkBytes + if (finalStatus != OK + || (metaDataSize >= 0 + && cachedDataRemaining >= metaDataSize) || (mFlags & PREPARE_CANCELLED)) { break; } + LOGV("now cached %d bytes of data", cachedDataRemaining); + + if (metaDataSize < 0 + && cachedDataRemaining >= kMinBytesForSniffing) { + String8 tmp; + float confidence; + sp<AMessage> meta; + if (!dataSource->sniff(&tmp, &confidence, &meta)) { + mLock.lock(); + return UNKNOWN_ERROR; + } + + // We successfully identified the file's extractor to + // be, remember this mime type so we don't have to + // sniff it again when we call MediaExtractor::Create() + // below. + sniffedMIME = tmp.string(); + + if (meta == NULL + || !meta->findInt64( + "meta-data-size", &metaDataSize)) { + metaDataSize = kHighWaterMarkBytes; + } + + CHECK_GE(metaDataSize, 0ll); + LOGV("metaDataSize = %lld bytes", metaDataSize); + } + usleep(200000); } @@ -2055,7 +2093,7 @@ status_t AwesomePlayer::finishSetDataSource_l() { String8 mimeType; float confidence; sp<AMessage> dummy; - bool success = SniffDRM(dataSource, &mimeType, &confidence, &dummy); + bool success = SniffWVM(dataSource, &mimeType, &confidence, &dummy); if (!success || strcasecmp( @@ -2063,23 +2101,29 @@ status_t AwesomePlayer::finishSetDataSource_l() { return ERROR_UNSUPPORTED; } + dataSource->DrmInitialization(); + mWVMExtractor = new WVMExtractor(dataSource); mWVMExtractor->setAdaptiveStreamingMode(true); + mWVMExtractor->setDrmFlag(true); extractor = mWVMExtractor; } else { - extractor = MediaExtractor::Create(dataSource); + extractor = MediaExtractor::Create( + dataSource, sniffedMIME.empty() ? NULL : sniffedMIME.c_str()); if (extractor == NULL) { return UNKNOWN_ERROR; } } - dataSource->getDrmInfo(mDecryptHandle, &mDrmManagerClient); + if (extractor->getDrmFlag()) { + dataSource->getDrmInfo(mDecryptHandle, &mDrmManagerClient); - if (mDecryptHandle != NULL) { - CHECK(mDrmManagerClient); - if (RightsStatus::RIGHTS_VALID != mDecryptHandle->status) { - notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, ERROR_DRM_NO_LICENSE); + if (mDecryptHandle != NULL) { + CHECK(mDrmManagerClient); + if (RightsStatus::RIGHTS_VALID != mDecryptHandle->status) { + notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, ERROR_DRM_NO_LICENSE); + } } } diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp index 256f3baaa9ad..57989c5e4a4a 100755 --- a/media/libstagefright/CameraSource.cpp +++ b/media/libstagefright/CameraSource.cpp @@ -33,6 +33,8 @@ namespace android { +static const int64_t CAMERA_SOURCE_TIMEOUT_NS = 3000000000LL; + struct CameraSourceListener : public CameraListener { CameraSourceListener(const sp<CameraSource> &source); @@ -156,6 +158,7 @@ CameraSource::CameraSource( mLastFrameTimestampUs(0), mStarted(false), mNumFramesEncoded(0), + mTimeBetweenFrameCaptureUs(0), mFirstFrameTimeUs(0), mNumFramesDropped(0), mNumGlitches(0), @@ -644,7 +647,8 @@ status_t CameraSource::stop() { releaseQueuedFrames(); while (!mFramesBeingEncoded.empty()) { if (NO_ERROR != - mFrameCompleteCondition.waitRelative(mLock, 3000000000LL)) { + mFrameCompleteCondition.waitRelative(mLock, + mTimeBetweenFrameCaptureUs * 1000LL + CAMERA_SOURCE_TIMEOUT_NS)) { LOGW("Timed out waiting for outstanding frames being encoded: %d", mFramesBeingEncoded.size()); } @@ -736,7 +740,8 @@ status_t CameraSource::read( Mutex::Autolock autoLock(mLock); while (mStarted && mFramesReceived.empty()) { if (NO_ERROR != - mFrameAvailableCondition.waitRelative(mLock, 1000000000LL)) { + mFrameAvailableCondition.waitRelative(mLock, + mTimeBetweenFrameCaptureUs * 1000LL + CAMERA_SOURCE_TIMEOUT_NS)) { if (mCameraRecordingProxy != 0 && !mCameraRecordingProxy->asBinder()->isBinderAlive()) { LOGW("camera recording proxy is gone"); diff --git a/media/libstagefright/CameraSourceTimeLapse.cpp b/media/libstagefright/CameraSourceTimeLapse.cpp index e4de20adae60..eb456f4a11fd 100644 --- a/media/libstagefright/CameraSourceTimeLapse.cpp +++ b/media/libstagefright/CameraSourceTimeLapse.cpp @@ -39,12 +39,12 @@ CameraSourceTimeLapse *CameraSourceTimeLapse::CreateFromCamera( Size videoSize, int32_t videoFrameRate, const sp<Surface>& surface, - int64_t timeBetweenTimeLapseFrameCaptureUs) { + int64_t timeBetweenFrameCaptureUs) { CameraSourceTimeLapse *source = new CameraSourceTimeLapse(camera, proxy, cameraId, videoSize, videoFrameRate, surface, - timeBetweenTimeLapseFrameCaptureUs); + timeBetweenFrameCaptureUs); if (source != NULL) { if (source->initCheck() != OK) { @@ -62,15 +62,15 @@ CameraSourceTimeLapse::CameraSourceTimeLapse( Size videoSize, int32_t videoFrameRate, const sp<Surface>& surface, - int64_t timeBetweenTimeLapseFrameCaptureUs) + int64_t timeBetweenFrameCaptureUs) : CameraSource(camera, proxy, cameraId, videoSize, videoFrameRate, surface, true), - mTimeBetweenTimeLapseFrameCaptureUs(timeBetweenTimeLapseFrameCaptureUs), mTimeBetweenTimeLapseVideoFramesUs(1E6/videoFrameRate), mLastTimeLapseFrameRealTimestampUs(0), mSkipCurrentFrame(false) { + mTimeBetweenFrameCaptureUs = timeBetweenFrameCaptureUs; LOGD("starting time lapse mode: %lld us", - mTimeBetweenTimeLapseFrameCaptureUs); + mTimeBetweenFrameCaptureUs); mVideoWidth = videoSize.width; mVideoHeight = videoSize.height; @@ -271,14 +271,14 @@ bool CameraSourceTimeLapse::skipFrameAndModifyTimeStamp(int64_t *timestampUs) { // The first 2 output frames from the encoder are: decoder specific info and // the compressed video frame data for the first input video frame. if (mNumFramesEncoded >= 1 && *timestampUs < - (mLastTimeLapseFrameRealTimestampUs + mTimeBetweenTimeLapseFrameCaptureUs)) { + (mLastTimeLapseFrameRealTimestampUs + mTimeBetweenFrameCaptureUs)) { // Skip all frames from last encoded frame until - // sufficient time (mTimeBetweenTimeLapseFrameCaptureUs) has passed. + // sufficient time (mTimeBetweenFrameCaptureUs) has passed. // Tell the camera to release its recording frame and return. LOGV("dataCallbackTimestamp timelapse: skipping intermediate frame"); return true; } else { - // Desired frame has arrived after mTimeBetweenTimeLapseFrameCaptureUs time: + // Desired frame has arrived after mTimeBetweenFrameCaptureUs time: // - Reset mLastTimeLapseFrameRealTimestampUs to current time. // - Artificially modify timestampUs to be one frame time (1/framerate) ahead // of the last encoded frame's time stamp. diff --git a/media/libstagefright/DRMExtractor.cpp b/media/libstagefright/DRMExtractor.cpp index 1f3d58181471..afc4a803518d 100644 --- a/media/libstagefright/DRMExtractor.cpp +++ b/media/libstagefright/DRMExtractor.cpp @@ -282,13 +282,13 @@ bool SniffDRM( if (decryptHandle != NULL) { if (decryptHandle->decryptApiType == DecryptApiType::CONTAINER_BASED) { *mimeType = String8("drm+container_based+") + decryptHandle->mimeType; + *confidence = 10.0f; } else if (decryptHandle->decryptApiType == DecryptApiType::ELEMENTARY_STREAM_BASED) { *mimeType = String8("drm+es_based+") + decryptHandle->mimeType; - } else if (decryptHandle->decryptApiType == DecryptApiType::WV_BASED) { - *mimeType = MEDIA_MIMETYPE_CONTAINER_WVM; - LOGW("SniffWVM: found match\n"); + *confidence = 10.0f; + } else { + return false; } - *confidence = 10.0f; return true; } diff --git a/media/libstagefright/DataSource.cpp b/media/libstagefright/DataSource.cpp index 70523c1cdcf8..6134344d8b65 100644 --- a/media/libstagefright/DataSource.cpp +++ b/media/libstagefright/DataSource.cpp @@ -15,7 +15,6 @@ */ #include "include/AMRExtractor.h" -#include "include/AVIExtractor.h" #include "include/MP3Extractor.h" #include "include/MPEG4Extractor.h" #include "include/WAVExtractor.h" @@ -27,6 +26,7 @@ #include "include/DRMExtractor.h" #include "include/FLACExtractor.h" #include "include/AACExtractor.h" +#include "include/WVMExtractor.h" #include "matroska/MatroskaExtractor.h" @@ -113,8 +113,8 @@ void DataSource::RegisterDefaultSniffers() { RegisterSniffer(SniffMPEG2TS); RegisterSniffer(SniffMP3); RegisterSniffer(SniffAAC); - RegisterSniffer(SniffAVI); RegisterSniffer(SniffMPEG2PS); + RegisterSniffer(SniffWVM); char value[PROPERTY_VALUE_MAX]; if (property_get("drm.service.enabled", value, NULL) diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp index 1ebf0a8c31ce..f6b06c79e0ea 100644 --- a/media/libstagefright/MPEG4Extractor.cpp +++ b/media/libstagefright/MPEG4Extractor.cpp @@ -30,6 +30,7 @@ #include <string.h> #include <media/stagefright/foundation/ADebug.h> +#include <media/stagefright/foundation/AMessage.h> #include <media/stagefright/DataSource.h> #include <media/stagefright/MediaBuffer.h> #include <media/stagefright/MediaBufferGroup.h> @@ -2301,51 +2302,121 @@ static bool isCompatibleBrand(uint32_t fourcc) { // Attempt to actually parse the 'ftyp' atom and determine if a suitable // compatible brand is present. +// Also try to identify where this file's metadata ends +// (end of the 'moov' atom) and report it to the caller as part of +// the metadata. static bool BetterSniffMPEG4( - const sp<DataSource> &source, String8 *mimeType, float *confidence) { - uint8_t header[12]; - if (source->readAt(0, header, 12) != 12 - || memcmp("ftyp", &header[4], 4)) { - return false; - } + const sp<DataSource> &source, String8 *mimeType, float *confidence, + sp<AMessage> *meta) { + // We scan up to 128 bytes to identify this file as an MP4. + static const off64_t kMaxScanOffset = 128ll; - size_t atomSize = U32_AT(&header[0]); - if (atomSize < 16 || (atomSize % 4) != 0) { - return false; - } + off64_t offset = 0ll; + bool foundGoodFileType = false; + off64_t moovAtomEndOffset = -1ll; + bool done = false; - bool success = false; - if (isCompatibleBrand(U32_AT(&header[8]))) { - success = true; - } else { - size_t numCompatibleBrands = (atomSize - 16) / 4; - for (size_t i = 0; i < numCompatibleBrands; ++i) { - uint8_t tmp[4]; - if (source->readAt(16 + i * 4, tmp, 4) != 4) { + while (!done && offset < kMaxScanOffset) { + uint32_t hdr[2]; + if (source->readAt(offset, hdr, 8) < 8) { + return false; + } + + uint64_t chunkSize = ntohl(hdr[0]); + uint32_t chunkType = ntohl(hdr[1]); + off64_t chunkDataOffset = offset + 8; + + if (chunkSize == 1) { + if (source->readAt(offset + 8, &chunkSize, 8) < 8) { return false; } - if (isCompatibleBrand(U32_AT(&tmp[0]))) { - success = true; + chunkSize = ntoh64(chunkSize); + chunkDataOffset += 8; + + if (chunkSize < 16) { + // The smallest valid chunk is 16 bytes long in this case. + return false; + } + } else if (chunkSize < 8) { + // The smallest valid chunk is 8 bytes long. + return false; + } + + off64_t chunkDataSize = offset + chunkSize - chunkDataOffset; + + switch (chunkType) { + case FOURCC('f', 't', 'y', 'p'): + { + if (chunkDataSize < 8) { + return false; + } + + uint32_t numCompatibleBrands = (chunkDataSize - 8) / 4; + for (size_t i = 0; i < numCompatibleBrands + 2; ++i) { + if (i == 1) { + // Skip this index, it refers to the minorVersion, + // not a brand. + continue; + } + + uint32_t brand; + if (source->readAt( + chunkDataOffset + 4 * i, &brand, 4) < 4) { + return false; + } + + brand = ntohl(brand); + + if (isCompatibleBrand(brand)) { + foundGoodFileType = true; + break; + } + } + + if (!foundGoodFileType) { + return false; + } + break; } + + case FOURCC('m', 'o', 'o', 'v'): + { + moovAtomEndOffset = offset + chunkSize; + + done = true; + break; + } + + default: + break; } + + offset += chunkSize; } - if (!success) { + if (!foundGoodFileType) { return false; } *mimeType = MEDIA_MIMETYPE_CONTAINER_MPEG4; *confidence = 0.4f; + if (moovAtomEndOffset >= 0) { + *meta = new AMessage; + (*meta)->setInt64("meta-data-size", moovAtomEndOffset); + + LOGV("found metadata size: %lld", moovAtomEndOffset); + } + return true; } bool SniffMPEG4( const sp<DataSource> &source, String8 *mimeType, float *confidence, - sp<AMessage> *) { - if (BetterSniffMPEG4(source, mimeType, confidence)) { + sp<AMessage> *meta) { + if (BetterSniffMPEG4(source, mimeType, confidence, meta)) { return true; } diff --git a/media/libstagefright/MediaExtractor.cpp b/media/libstagefright/MediaExtractor.cpp index 22212683d72c..9eee6aac8347 100644 --- a/media/libstagefright/MediaExtractor.cpp +++ b/media/libstagefright/MediaExtractor.cpp @@ -19,7 +19,6 @@ #include <utils/Log.h> #include "include/AMRExtractor.h" -#include "include/AVIExtractor.h" #include "include/MP3Extractor.h" #include "include/MPEG4Extractor.h" #include "include/WAVExtractor.h" @@ -110,10 +109,11 @@ sp<MediaExtractor> MediaExtractor::Create( ret = new MatroskaExtractor(source); } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG2TS)) { ret = new MPEG2TSExtractor(source); - } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_AVI)) { - ret = new AVIExtractor(source); } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_WVM)) { ret = new WVMExtractor(source); + if (ret != NULL) { + isDrm = true; + } } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC_ADTS)) { ret = new AACExtractor(source); } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG2PS)) { diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp index dfd3f4ade921..86b3fe4eea41 100755 --- a/media/libstagefright/OMXCodec.cpp +++ b/media/libstagefright/OMXCodec.cpp @@ -520,6 +520,85 @@ sp<MediaSource> OMXCodec::Create( return NULL; } +status_t OMXCodec::parseAVCCodecSpecificData( + const void *data, size_t size, + unsigned *profile, unsigned *level) { + const uint8_t *ptr = (const uint8_t *)data; + + // verify minimum size and configurationVersion == 1. + if (size < 7 || ptr[0] != 1) { + return ERROR_MALFORMED; + } + + *profile = ptr[1]; + *level = ptr[3]; + + // There is decodable content out there that fails the following + // assertion, let's be lenient for now... + // CHECK((ptr[4] >> 2) == 0x3f); // reserved + + size_t lengthSize = 1 + (ptr[4] & 3); + + // commented out check below as H264_QVGA_500_NO_AUDIO.3gp + // violates it... + // CHECK((ptr[5] >> 5) == 7); // reserved + + size_t numSeqParameterSets = ptr[5] & 31; + + ptr += 6; + size -= 6; + + for (size_t i = 0; i < numSeqParameterSets; ++i) { + if (size < 2) { + return ERROR_MALFORMED; + } + + size_t length = U16_AT(ptr); + + ptr += 2; + size -= 2; + + if (size < length) { + return ERROR_MALFORMED; + } + + addCodecSpecificData(ptr, length); + + ptr += length; + size -= length; + } + + if (size < 1) { + return ERROR_MALFORMED; + } + + size_t numPictureParameterSets = *ptr; + ++ptr; + --size; + + for (size_t i = 0; i < numPictureParameterSets; ++i) { + if (size < 2) { + return ERROR_MALFORMED; + } + + size_t length = U16_AT(ptr); + + ptr += 2; + size -= 2; + + if (size < length) { + return ERROR_MALFORMED; + } + + addCodecSpecificData(ptr, length); + + ptr += length; + size -= length; + } + + return OK; +} + status_t OMXCodec::configureCodec(const sp<MetaData> &meta) { LOGV("configureCodec protected=%d", (mFlags & kEnableGrallocUsageProtected) ? 1 : 0); @@ -542,66 +621,17 @@ status_t OMXCodec::configureCodec(const sp<MetaData> &meta) { } else if (meta->findData(kKeyAVCC, &type, &data, &size)) { // Parse the AVCDecoderConfigurationRecord - const uint8_t *ptr = (const uint8_t *)data; - - CHECK(size >= 7); - CHECK_EQ((unsigned)ptr[0], 1u); // configurationVersion == 1 - uint8_t profile = ptr[1]; - uint8_t level = ptr[3]; - - // There is decodable content out there that fails the following - // assertion, let's be lenient for now... - // CHECK((ptr[4] >> 2) == 0x3f); // reserved - - size_t lengthSize = 1 + (ptr[4] & 3); - - // commented out check below as H264_QVGA_500_NO_AUDIO.3gp - // violates it... - // CHECK((ptr[5] >> 5) == 7); // reserved - - size_t numSeqParameterSets = ptr[5] & 31; - - ptr += 6; - size -= 6; - - for (size_t i = 0; i < numSeqParameterSets; ++i) { - CHECK(size >= 2); - size_t length = U16_AT(ptr); - - ptr += 2; - size -= 2; - - CHECK(size >= length); - - addCodecSpecificData(ptr, length); - - ptr += length; - size -= length; - } - - CHECK(size >= 1); - size_t numPictureParameterSets = *ptr; - ++ptr; - --size; - - for (size_t i = 0; i < numPictureParameterSets; ++i) { - CHECK(size >= 2); - size_t length = U16_AT(ptr); - - ptr += 2; - size -= 2; - - CHECK(size >= length); - - addCodecSpecificData(ptr, length); - - ptr += length; - size -= length; + unsigned profile, level; + status_t err; + if ((err = parseAVCCodecSpecificData( + data, size, &profile, &level)) != OK) { + LOGE("Malformed AVC codec specific data."); + return err; } CODEC_LOGI( - "AVC profile = %d (%s), level = %d", - (int)profile, AVCProfileToString(profile), level); + "AVC profile = %u (%s), level = %u", + profile, AVCProfileToString(profile), level); if (!strcmp(mComponentName, "OMX.TI.Video.Decoder") && (profile != kAVCProfileBaseline || level > 30)) { diff --git a/media/libstagefright/SampleTable.cpp b/media/libstagefright/SampleTable.cpp index ebad3215802f..bf319472ffe2 100644 --- a/media/libstagefright/SampleTable.cpp +++ b/media/libstagefright/SampleTable.cpp @@ -627,18 +627,19 @@ status_t SampleTable::findSyncSampleNear( ++left; } - if (left > 0) { - --left; + + if (left == mNumSyncSamples) { + if (flags == kFlagAfter) { + LOGE("tried to find a sync frame after the last one: %d", left); + return ERROR_OUT_OF_RANGE; + } } - uint32_t x; - if (mDataSource->readAt( - mSyncSampleOffset + 8 + left * 4, &x, 4) != 4) { - return ERROR_IO; + if (left > 0) { + --left; } - x = ntohl(x); - --x; + uint32_t x = mSyncSamples[left]; if (left + 1 < mNumSyncSamples) { uint32_t y = mSyncSamples[left + 1]; @@ -679,13 +680,7 @@ status_t SampleTable::findSyncSampleNear( if (x > start_sample_index) { CHECK(left > 0); - if (mDataSource->readAt( - mSyncSampleOffset + 8 + (left - 1) * 4, &x, 4) != 4) { - return ERROR_IO; - } - - x = ntohl(x); - --x; + x = mSyncSamples[left - 1]; CHECK(x <= start_sample_index); } diff --git a/media/libstagefright/StagefrightMediaScanner.cpp b/media/libstagefright/StagefrightMediaScanner.cpp index bb6e4cd6b9e0..25050962d290 100644 --- a/media/libstagefright/StagefrightMediaScanner.cpp +++ b/media/libstagefright/StagefrightMediaScanner.cpp @@ -94,7 +94,7 @@ static MediaScanResult HandleMIDI( char buffer[20]; sprintf(buffer, "%ld", temp); status_t status = client->addStringTag("duration", buffer); - if (status) { + if (status != OK) { return MEDIA_SCAN_RESULT_ERROR; } return MEDIA_SCAN_RESULT_OK; @@ -178,7 +178,7 @@ MediaScanResult StagefrightMediaScanner::processFileInternal( const char *value; if ((value = mRetriever->extractMetadata(kKeyMap[i].key)) != NULL) { status = client.addStringTag(kKeyMap[i].tag, value); - if (status) { + if (status != OK) { return MEDIA_SCAN_RESULT_ERROR; } } diff --git a/media/libstagefright/SurfaceMediaSource.cpp b/media/libstagefright/SurfaceMediaSource.cpp index 2b27ee222d6a..86b33d1c4fd1 100644 --- a/media/libstagefright/SurfaceMediaSource.cpp +++ b/media/libstagefright/SurfaceMediaSource.cpp @@ -336,7 +336,7 @@ status_t SurfaceMediaSource::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h, (uint32_t(buffer->height) != h) || (uint32_t(buffer->format) != format) || ((uint32_t(buffer->usage) & usage) != usage)) { - usage |= GraphicBuffer::USAGE_HW_TEXTURE; + usage |= GraphicBuffer::USAGE_HW_VIDEO_ENCODER; status_t error; sp<GraphicBuffer> graphicBuffer( mGraphicBufferAlloc->createGraphicBuffer( diff --git a/media/libstagefright/WVMExtractor.cpp b/media/libstagefright/WVMExtractor.cpp index 26eda0c4cfb1..79dedcab1694 100644 --- a/media/libstagefright/WVMExtractor.cpp +++ b/media/libstagefright/WVMExtractor.cpp @@ -45,17 +45,12 @@ namespace android { static Mutex gWVMutex; WVMExtractor::WVMExtractor(const sp<DataSource> &source) - : mDataSource(source) { - { - Mutex::Autolock autoLock(gWVMutex); - if (gVendorLibHandle == NULL) { - gVendorLibHandle = dlopen("libwvm.so", RTLD_NOW); - } + : mDataSource(source) +{ + Mutex::Autolock autoLock(gWVMutex); - if (gVendorLibHandle == NULL) { - LOGE("Failed to open libwvm.so"); - return; - } + if (!getVendorLibHandle()) { + return; } typedef WVMLoadableExtractor *(*GetInstanceFunc)(sp<DataSource>); @@ -71,6 +66,19 @@ WVMExtractor::WVMExtractor(const sp<DataSource> &source) } } +bool WVMExtractor::getVendorLibHandle() +{ + if (gVendorLibHandle == NULL) { + gVendorLibHandle = dlopen("libwvm.so", RTLD_NOW); + } + + if (gVendorLibHandle == NULL) { + LOGE("Failed to open libwvm.so"); + } + + return gVendorLibHandle != NULL; +} + WVMExtractor::~WVMExtractor() { } @@ -113,5 +121,33 @@ void WVMExtractor::setAdaptiveStreamingMode(bool adaptive) { } } +bool SniffWVM( + const sp<DataSource> &source, String8 *mimeType, float *confidence, + sp<AMessage> *) { + + Mutex::Autolock autoLock(gWVMutex); + + if (!WVMExtractor::getVendorLibHandle()) { + return false; + } + + typedef WVMLoadableExtractor *(*SnifferFunc)(sp<DataSource>); + SnifferFunc snifferFunc = + (SnifferFunc) dlsym(gVendorLibHandle, + "_ZN7android15IsWidevineMediaENS_2spINS_10DataSourceEEE"); + + if (snifferFunc) { + if ((*snifferFunc)(source)) { + *mimeType = MEDIA_MIMETYPE_CONTAINER_WVM; + *confidence = 10.0f; + return true; + } + } else { + LOGE("IsWidevineMedia not found in libwvm.so"); + } + + return false; +} + } //namespace android diff --git a/media/libstagefright/foundation/ABitReader.cpp b/media/libstagefright/foundation/ABitReader.cpp index f07dd4f7fa90..5499c32bbaba 100644 --- a/media/libstagefright/foundation/ABitReader.cpp +++ b/media/libstagefright/foundation/ABitReader.cpp @@ -79,7 +79,13 @@ void ABitReader::skipBits(size_t n) { } void ABitReader::putBits(uint32_t x, size_t n) { - CHECK_LE(mNumBitsLeft + n, 32u); + CHECK_LE(n, 32u); + + while (mNumBitsLeft + n > 32) { + mNumBitsLeft -= 8; + --mData; + ++mSize; + } mReservoir = (mReservoir >> n) | (x << (32 - n)); mNumBitsLeft += n; diff --git a/media/libstagefright/include/WVMExtractor.h b/media/libstagefright/include/WVMExtractor.h index deecd2543a92..9f763f9debef 100644 --- a/media/libstagefright/include/WVMExtractor.h +++ b/media/libstagefright/include/WVMExtractor.h @@ -23,6 +23,8 @@ namespace android { +struct AMessage; +class String8; class DataSource; class WVMLoadableExtractor : public MediaExtractor { @@ -58,6 +60,8 @@ public: // is used. void setAdaptiveStreamingMode(bool adaptive); + static bool getVendorLibHandle(); + protected: virtual ~WVMExtractor(); @@ -69,6 +73,10 @@ private: WVMExtractor &operator=(const WVMExtractor &); }; +bool SniffWVM( + const sp<DataSource> &source, String8 *mimeType, float *confidence, + sp<AMessage> *); + } // namespace android #endif // DRM_EXTRACTOR_H_ diff --git a/media/libstagefright/mpeg2ts/ATSParser.cpp b/media/libstagefright/mpeg2ts/ATSParser.cpp index 72f12827f02d..6cec63a6af71 100644 --- a/media/libstagefright/mpeg2ts/ATSParser.cpp +++ b/media/libstagefright/mpeg2ts/ATSParser.cpp @@ -123,6 +123,9 @@ private: void extractAACFrames(const sp<ABuffer> &buffer); + bool isAudio() const; + bool isVideo() const; + DISALLOW_EVIL_CONSTRUCTORS(Stream); }; @@ -401,7 +404,7 @@ ATSParser::Stream::Stream( case STREAMTYPE_H264: mQueue = new ElementaryStreamQueue(ElementaryStreamQueue::H264); break; - case STREAMTYPE_MPEG2_AUDIO_ATDS: + case STREAMTYPE_MPEG2_AUDIO_ADTS: mQueue = new ElementaryStreamQueue(ElementaryStreamQueue::AAC); break; case STREAMTYPE_MPEG1_AUDIO: @@ -486,6 +489,31 @@ status_t ATSParser::Stream::parse( return OK; } +bool ATSParser::Stream::isVideo() const { + switch (mStreamType) { + case STREAMTYPE_H264: + case STREAMTYPE_MPEG1_VIDEO: + case STREAMTYPE_MPEG2_VIDEO: + case STREAMTYPE_MPEG4_VIDEO: + return true; + + default: + return false; + } +} + +bool ATSParser::Stream::isAudio() const { + switch (mStreamType) { + case STREAMTYPE_MPEG1_AUDIO: + case STREAMTYPE_MPEG2_AUDIO: + case STREAMTYPE_MPEG2_AUDIO_ADTS: + return true; + + default: + return false; + } +} + void ATSParser::Stream::signalDiscontinuity( DiscontinuityType type, const sp<AMessage> &extra) { if (mQueue == NULL) { @@ -495,34 +523,34 @@ void ATSParser::Stream::signalDiscontinuity( mPayloadStarted = false; mBuffer->setRange(0, 0); - switch (type) { - case DISCONTINUITY_SEEK: - case DISCONTINUITY_FORMATCHANGE: - { - bool isASeek = (type == DISCONTINUITY_SEEK); - - mQueue->clear(!isASeek); + bool clearFormat = false; + if (isAudio()) { + if (type & DISCONTINUITY_AUDIO_FORMAT) { + clearFormat = true; + } + } else { + if (type & DISCONTINUITY_VIDEO_FORMAT) { + clearFormat = true; + } + } - uint64_t resumeAtPTS; - if (extra != NULL - && extra->findInt64( - IStreamListener::kKeyResumeAtPTS, - (int64_t *)&resumeAtPTS)) { - int64_t resumeAtMediaTimeUs = - mProgram->convertPTSToTimestamp(resumeAtPTS); + mQueue->clear(clearFormat); - extra->setInt64("resume-at-mediatimeUs", resumeAtMediaTimeUs); - } + if (type & DISCONTINUITY_TIME) { + uint64_t resumeAtPTS; + if (extra != NULL + && extra->findInt64( + IStreamListener::kKeyResumeAtPTS, + (int64_t *)&resumeAtPTS)) { + int64_t resumeAtMediaTimeUs = + mProgram->convertPTSToTimestamp(resumeAtPTS); - if (mSource != NULL) { - mSource->queueDiscontinuity(type, extra); - } - break; + extra->setInt64("resume-at-mediatimeUs", resumeAtMediaTimeUs); } + } - default: - TRESPASS(); - break; + if (mSource != NULL) { + mSource->queueDiscontinuity(type, extra); } } @@ -764,10 +792,7 @@ sp<MediaSource> ATSParser::Stream::getSource(SourceType type) { switch (type) { case VIDEO: { - if (mStreamType == STREAMTYPE_H264 - || mStreamType == STREAMTYPE_MPEG1_VIDEO - || mStreamType == STREAMTYPE_MPEG2_VIDEO - || mStreamType == STREAMTYPE_MPEG4_VIDEO) { + if (isVideo()) { return mSource; } break; @@ -775,9 +800,7 @@ sp<MediaSource> ATSParser::Stream::getSource(SourceType type) { case AUDIO: { - if (mStreamType == STREAMTYPE_MPEG1_AUDIO - || mStreamType == STREAMTYPE_MPEG2_AUDIO - || mStreamType == STREAMTYPE_MPEG2_AUDIO_ATDS) { + if (isAudio()) { return mSource; } break; diff --git a/media/libstagefright/mpeg2ts/ATSParser.h b/media/libstagefright/mpeg2ts/ATSParser.h index 878e5342430c..c8038d1835be 100644 --- a/media/libstagefright/mpeg2ts/ATSParser.h +++ b/media/libstagefright/mpeg2ts/ATSParser.h @@ -33,9 +33,18 @@ struct MediaSource; struct ATSParser : public RefBase { enum DiscontinuityType { - DISCONTINUITY_NONE, - DISCONTINUITY_SEEK, - DISCONTINUITY_FORMATCHANGE + DISCONTINUITY_NONE = 0, + DISCONTINUITY_TIME = 1, + DISCONTINUITY_AUDIO_FORMAT = 2, + DISCONTINUITY_VIDEO_FORMAT = 4, + + DISCONTINUITY_SEEK = DISCONTINUITY_TIME, + + // For legacy reasons this also implies a time discontinuity. + DISCONTINUITY_FORMATCHANGE = + DISCONTINUITY_AUDIO_FORMAT + | DISCONTINUITY_VIDEO_FORMAT + | DISCONTINUITY_TIME, }; enum Flags { @@ -71,7 +80,7 @@ struct ATSParser : public RefBase { STREAMTYPE_MPEG2_VIDEO = 0x02, STREAMTYPE_MPEG1_AUDIO = 0x03, STREAMTYPE_MPEG2_AUDIO = 0x04, - STREAMTYPE_MPEG2_AUDIO_ATDS = 0x0f, + STREAMTYPE_MPEG2_AUDIO_ADTS = 0x0f, STREAMTYPE_MPEG4_VIDEO = 0x10, STREAMTYPE_H264 = 0x1b, }; diff --git a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp index ce07e32ddc26..f782ce554539 100644 --- a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp +++ b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp @@ -29,8 +29,17 @@ namespace android { AnotherPacketSource::AnotherPacketSource(const sp<MetaData> &meta) - : mFormat(meta), + : mIsAudio(false), + mFormat(meta), mEOSResult(OK) { + const char *mime; + CHECK(meta->findCString(kKeyMIMEType, &mime)); + + if (!strncasecmp("audio/", mime, 6)) { + mIsAudio = true; + } else { + CHECK(!strncasecmp("video/", mime, 6)); + } } void AnotherPacketSource::setFormat(const sp<MetaData> &meta) { @@ -67,8 +76,7 @@ status_t AnotherPacketSource::dequeueAccessUnit(sp<ABuffer> *buffer) { int32_t discontinuity; if ((*buffer)->meta()->findInt32("discontinuity", &discontinuity)) { - - if (discontinuity == ATSParser::DISCONTINUITY_FORMATCHANGE) { + if (wasFormatChange(discontinuity)) { mFormat.clear(); } @@ -96,7 +104,7 @@ status_t AnotherPacketSource::read( int32_t discontinuity; if (buffer->meta()->findInt32("discontinuity", &discontinuity)) { - if (discontinuity == ATSParser::DISCONTINUITY_FORMATCHANGE) { + if (wasFormatChange(discontinuity)) { mFormat.clear(); } @@ -117,6 +125,15 @@ status_t AnotherPacketSource::read( return mEOSResult; } +bool AnotherPacketSource::wasFormatChange( + int32_t discontinuityType) const { + if (mIsAudio) { + return (discontinuityType & ATSParser::DISCONTINUITY_AUDIO_FORMAT) != 0; + } + + return (discontinuityType & ATSParser::DISCONTINUITY_VIDEO_FORMAT) != 0; +} + void AnotherPacketSource::queueAccessUnit(const sp<ABuffer> &buffer) { int32_t damaged; if (buffer->meta()->findInt32("damaged", &damaged) && damaged) { diff --git a/media/libstagefright/mpeg2ts/AnotherPacketSource.h b/media/libstagefright/mpeg2ts/AnotherPacketSource.h index 439c78531fc0..c99f7f247f91 100644 --- a/media/libstagefright/mpeg2ts/AnotherPacketSource.h +++ b/media/libstagefright/mpeg2ts/AnotherPacketSource.h @@ -61,10 +61,13 @@ private: Mutex mLock; Condition mCondition; + bool mIsAudio; sp<MetaData> mFormat; List<sp<ABuffer> > mBuffers; status_t mEOSResult; + bool wasFormatChange(int32_t discontinuityType) const; + DISALLOW_EVIL_CONSTRUCTORS(AnotherPacketSource); }; diff --git a/media/libstagefright/mpeg2ts/MPEG2PSExtractor.cpp b/media/libstagefright/mpeg2ts/MPEG2PSExtractor.cpp index f55be6e208b1..a089dbfa6050 100644 --- a/media/libstagefright/mpeg2ts/MPEG2PSExtractor.cpp +++ b/media/libstagefright/mpeg2ts/MPEG2PSExtractor.cpp @@ -543,7 +543,7 @@ MPEG2PSExtractor::Track::Track( case ATSParser::STREAMTYPE_H264: mode = ElementaryStreamQueue::H264; break; - case ATSParser::STREAMTYPE_MPEG2_AUDIO_ATDS: + case ATSParser::STREAMTYPE_MPEG2_AUDIO_ADTS: mode = ElementaryStreamQueue::AAC; break; case ATSParser::STREAMTYPE_MPEG1_AUDIO: diff --git a/media/libstagefright/rtsp/MyHandler.h b/media/libstagefright/rtsp/MyHandler.h index 794c60b6a9a8..5a95f9cfc35c 100644 --- a/media/libstagefright/rtsp/MyHandler.h +++ b/media/libstagefright/rtsp/MyHandler.h @@ -1100,6 +1100,8 @@ struct MyHandler : public AHandler { float npt1, npt2; if (!ASessionDescription::parseNTPRange(val.c_str(), &npt1, &npt2)) { // This is a live stream and therefore not seekable. + + LOGI("This is a live stream"); return; } @@ -1386,12 +1388,14 @@ private: msg->setInt32("what", kWhatConnected); msg->post(); - for (size_t i = 0; i < mTracks.size(); ++i) { - TrackInfo *info = &mTracks.editItemAt(i); + if (mSeekable) { + for (size_t i = 0; i < mTracks.size(); ++i) { + TrackInfo *info = &mTracks.editItemAt(i); - postNormalPlayTimeMapping( - i, - info->mNormalPlayTimeRTP, info->mNormalPlayTimeUs); + postNormalPlayTimeMapping( + i, + info->mNormalPlayTimeRTP, info->mNormalPlayTimeUs); + } } mFirstAccessUnit = false; diff --git a/media/mtp/MtpDataPacket.cpp b/media/mtp/MtpDataPacket.cpp index 20225ba2cce5..cfea7e89d3ec 100644 --- a/media/mtp/MtpDataPacket.cpp +++ b/media/mtp/MtpDataPacket.cpp @@ -25,10 +25,12 @@ #include "MtpDataPacket.h" #include "MtpStringBuffer.h" +#define MTP_BUFFER_SIZE 16384 + namespace android { MtpDataPacket::MtpDataPacket() - : MtpPacket(16384), // MAX_USBFS_BUFFER_SIZE + : MtpPacket(MTP_BUFFER_SIZE), // MAX_USBFS_BUFFER_SIZE mOffset(MTP_CONTAINER_HEADER_SIZE) { } @@ -345,7 +347,7 @@ void MtpDataPacket::putString(const uint16_t* string) { #ifdef MTP_DEVICE int MtpDataPacket::read(int fd) { - int ret = ::read(fd, mBuffer, mBufferSize); + int ret = ::read(fd, mBuffer, MTP_BUFFER_SIZE); if (ret < MTP_CONTAINER_HEADER_SIZE) return -1; mPacketSize = ret; diff --git a/media/mtp/MtpServer.cpp b/media/mtp/MtpServer.cpp index dc6c0119e908..1dcfb74660d0 100644 --- a/media/mtp/MtpServer.cpp +++ b/media/mtp/MtpServer.cpp @@ -1053,11 +1053,14 @@ MtpResponseCode MtpServer::doDeleteObject() { int result = mDatabase->getObjectFilePath(handle, filePath, fileLength, format); if (result == MTP_RESPONSE_OK) { LOGV("deleting %s", (const char *)filePath); - deletePath((const char *)filePath); - return mDatabase->deleteFile(handle); - } else { - return result; + result = mDatabase->deleteFile(handle); + // Don't delete the actual files unless the database deletion is allowed + if (result == MTP_RESPONSE_OK) { + deletePath((const char *)filePath); + } } + + return result; } MtpResponseCode MtpServer::doGetObjectPropDesc() { diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkTestRunner.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkTestRunner.java index 3fb2da080954..92ac9eb09766 100755 --- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkTestRunner.java +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkTestRunner.java @@ -39,6 +39,7 @@ import com.android.mediaframeworktest.functional.videoeditor.VideoEditorExportTe import com.android.mediaframeworktest.functional.videoeditor.VideoEditorPreviewTest; import junit.framework.TestSuite; +import android.os.Bundle; import android.test.InstrumentationTestRunner; import android.test.InstrumentationTestSuite; @@ -54,6 +55,7 @@ import android.test.InstrumentationTestSuite; public class MediaFrameworkTestRunner extends InstrumentationTestRunner { + public static int mMinCameraFps = 0; @Override public TestSuite getAllTests() { @@ -87,4 +89,16 @@ public class MediaFrameworkTestRunner extends InstrumentationTestRunner { public ClassLoader getLoader() { return MediaFrameworkTestRunner.class.getClassLoader(); } + + @Override + public void onCreate(Bundle icicle) { + super.onCreate(icicle); + + String minCameraFps = (String) icicle.get("min_camera_fps"); + System.out.print("min_camera_" + minCameraFps); + + if (minCameraFps != null ) { + mMinCameraFps = Integer.parseInt(minCameraFps); + } + } } diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/mediarecorder/MediaRecorderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/mediarecorder/MediaRecorderTest.java index b5c8c8c486f0..0684946617c0 100644 --- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/mediarecorder/MediaRecorderTest.java +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/mediarecorder/MediaRecorderTest.java @@ -33,6 +33,7 @@ import android.util.Log; import android.view.SurfaceHolder; import android.view.SurfaceView; import com.android.mediaframeworktest.MediaProfileReader; +import com.android.mediaframeworktest.MediaFrameworkTestRunner; import android.test.suitebuilder.annotation.LargeTest; import android.test.suitebuilder.annotation.Suppress; @@ -115,9 +116,16 @@ public class MediaRecorderTest extends ActivityInstrumentationTestCase2<MediaFra int audioChannels = highQuality? audioCap.mMaxChannels: audioCap.mMinChannels ; int audioSamplingRate = highQuality? audioCap.mMaxSampleRate: audioCap.mMinSampleRate; + //Overide the fps if the min_camera_fps is set + if (MediaFrameworkTestRunner.mMinCameraFps != 0 && + MediaFrameworkTestRunner.mMinCameraFps > videoFps){ + videoFps = MediaFrameworkTestRunner.mMinCameraFps; + } + if (videoFps < MIN_VIDEO_FPS) { videoFps = MIN_VIDEO_FPS; } + mSurfaceHolder = MediaFrameworkTest.mSurfaceView.getHolder(); String filename = ("/sdcard/" + videoEncoder + "_" + audioEncoder + "_" + highQuality + ".3gp"); try { diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/videoeditor/VideoEditorPreviewTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/videoeditor/VideoEditorPreviewTest.java index e848f5f5b105..41819032f058 100644 --- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/videoeditor/VideoEditorPreviewTest.java +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/videoeditor/VideoEditorPreviewTest.java @@ -93,6 +93,7 @@ public class VideoEditorPreviewTest extends private boolean previewStart; private boolean previewStop; + private boolean previewError; /* Minimum waiting time for Semaphore to wait for release */ private final long minWaitingTime = 3000; @@ -141,7 +142,9 @@ public class VideoEditorPreviewTest extends protected void setPreviewStop() { previewStop = true; } - + protected void setPreviewError() { + previewError = true; + } protected void validatePreviewProgress(int startMs, int endMs, boolean loop, long duration) throws Exception { @@ -149,6 +152,7 @@ public class VideoEditorPreviewTest extends final Semaphore blockTillPreviewCompletes = new Semaphore(1); previewStart = false; previewStop = false; + previewError = false; mVideoEditor.generatePreview(new MediaProcessingProgressListener() { int i = 0; public void onProgress(Object item, int action, int progress) { @@ -187,6 +191,10 @@ public class VideoEditorPreviewTest extends setPreviewStop(); blockTillPreviewCompletes.release(); } + public void onError(VideoEditor videoEditor, int error) { + setPreviewError(); + blockTillPreviewCompletes.release(); + } }); } catch (Exception e) { blockTillPreviewCompletes.release(); @@ -196,6 +204,7 @@ public class VideoEditorPreviewTest extends mVideoEditor.stopPreview(); assertTrue("Preview Failed to start", previewStart); assertTrue("Preview Failed to stop", previewStop); + assertFalse("Preview Error occurred", previewError); blockTillPreviewCompletes.release(); } @@ -399,6 +408,7 @@ public class VideoEditorPreviewTest extends "TransitionSpiral_QVGA.jpg"; previewStart = false; previewStop = false; + previewError = false; final Semaphore blockTillPreviewCompletes = new Semaphore(1); @@ -490,6 +500,10 @@ public class VideoEditorPreviewTest extends setPreviewStop(); blockTillPreviewCompletes.release(); } + public void onError(VideoEditor videoEditor, int error) { + setPreviewError(); + blockTillPreviewCompletes.release(); + } }); } catch (Exception e) { blockTillPreviewCompletes.release(); @@ -499,6 +513,7 @@ public class VideoEditorPreviewTest extends blockTillPreviewCompletes.release(); assertTrue("Preview Failed to start", previewStart); assertTrue("Preview Failed to stop", previewStop); + assertFalse("Preview Error occurred", previewError); assertEquals("Removing Transition " + transition1And2CrossFade.getId(), transition1And2CrossFade, @@ -677,6 +692,7 @@ public class VideoEditorPreviewTest extends final Semaphore blockTillPreviewCompletes = new Semaphore(1); previewStart = false; previewStop = false; + previewError = false; final MediaVideoItem mediaVideoItem1 = mVideoEditorHelper.createMediaItem(mVideoEditor, "m1", @@ -693,7 +709,7 @@ public class VideoEditorPreviewTest extends blockTillPreviewCompletes.acquire(); - final String fileName = mVideoEditor.getPath() + "\test.3gp"; + final String fileName = mVideoEditor.getPath() + "/test.3gp"; final int height = MediaProperties.HEIGHT_480; final int bitrate = MediaProperties.BITRATE_512K; @@ -727,6 +743,10 @@ public class VideoEditorPreviewTest extends setPreviewStop(); blockTillPreviewCompletes.release(); } + public void onError(VideoEditor videoEditor, int error) { + setPreviewError(); + blockTillPreviewCompletes.release(); + } }); } catch (Exception e) { @@ -736,6 +756,8 @@ public class VideoEditorPreviewTest extends mVideoEditor.stopPreview(); assertTrue("Preview Failed to start", previewStart); assertTrue("Preview Failed to stop", previewStop); + assertFalse("Preview Error occurred", previewError); + blockTillPreviewCompletes.release(); } @@ -784,6 +806,10 @@ public class VideoEditorPreviewTest extends setPreviewStop(); blockTillPreviewCompletes.release(); } + public void onError(VideoEditor videoEditor, int error) { + setPreviewError(); + blockTillPreviewCompletes.release(); + } }); } catch (IllegalArgumentException e) { @@ -1023,7 +1049,10 @@ public class VideoEditorPreviewTest extends } public void onStop(VideoEditor videoEditor) { setPreviewStop(); - } + } + public void onError(VideoEditor videoEditor, int error) { + setPreviewError(); + } }); }catch (IllegalArgumentException e) { flagForException = true; @@ -1089,7 +1118,10 @@ public class VideoEditorPreviewTest extends } public void onStop(VideoEditor videoEditor) { setPreviewStop(); - } + } + public void onError(VideoEditor videoEditor, int error) { + setPreviewError(); + } }); }catch (IllegalArgumentException e) { flagForException = true; diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java index 0b887b9c6428..4f6e7d2831f5 100644 --- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java @@ -37,11 +37,13 @@ import android.util.Log; import android.view.SurfaceHolder; import java.util.List; +import java.io.BufferedReader; import java.io.FileDescriptor; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; +import java.io.InputStreamReader; import java.io.Writer; import java.io.File; import java.io.FileWriter; @@ -68,6 +70,8 @@ public class MediaPlayerPerformance extends ActivityInstrumentationTestCase2<Med private static final long MEDIA_STRESS_WAIT_TIME = 5000; //5 seconds private static final String MEDIA_MEMORY_OUTPUT = "/sdcard/mediaMemOutput.txt"; + private static final String MEDIA_PROCMEM_OUTPUT = + "/sdcard/mediaProcmemOutput.txt"; private static int mStartMemory = 0; private static int mEndMemory = 0; @@ -84,6 +88,9 @@ public class MediaPlayerPerformance extends ActivityInstrumentationTestCase2<Med private static int DECODER_LIMIT = 150; private static int CAMERA_LIMIT = 80; + private Writer mProcMemWriter; + private Writer mMemWriter; + private static List<VideoEncoderCap> videoEncoders = MediaProfileReader.getVideoEncoders(); Camera mCamera; @@ -97,12 +104,21 @@ public class MediaPlayerPerformance extends ActivityInstrumentationTestCase2<Med getActivity(); if (MediaFrameworkPerfTestRunner.mGetNativeHeapDump) MediaTestUtil.getNativeHeapDump(this.getName() + "_before"); + + mProcMemWriter = new BufferedWriter(new FileWriter + (new File(MEDIA_PROCMEM_OUTPUT), true)); + mProcMemWriter.write(this.getName() + "\n"); + mMemWriter = new BufferedWriter(new FileWriter + (new File(MEDIA_MEMORY_OUTPUT), true)); + } protected void tearDown() throws Exception { - super.tearDown(); if (MediaFrameworkPerfTestRunner.mGetNativeHeapDump) MediaTestUtil.getNativeHeapDump(this.getName() + "_after"); + mProcMemWriter.close(); + mMemWriter.close(); + super.tearDown(); } private void initializeMessageLooper() { @@ -247,24 +263,39 @@ public class MediaPlayerPerformance extends ActivityInstrumentationTestCase2<Med } //Write the ps output to the file - public void getMemoryWriteToLog(Writer output, int writeCount) { + public void getMemoryWriteToLog(int writeCount) { String memusage = null; try { if (writeCount == 0) { mStartMemory = getMediaserverVsize(); - output.write("Start memory : " + mStartMemory + "\n"); + mMemWriter.write("Start memory : " + mStartMemory + "\n"); } memusage = captureMediaserverInfo(); - output.write(memusage); + mMemWriter.write(memusage); if (writeCount == NUM_STRESS_LOOP - 1) { mEndMemory = getMediaserverVsize(); - output.write("End Memory :" + mEndMemory + "\n"); + mMemWriter.write("End Memory :" + mEndMemory + "\n"); } } catch (Exception e) { e.toString(); } } + public void writeProcmemInfo() throws Exception{ + String cmd = "procmem " + getMediaserverPid(); + Process p = Runtime.getRuntime().exec(cmd); + + InputStream inStream = p.getInputStream(); + InputStreamReader inReader = new InputStreamReader(inStream); + BufferedReader inBuffer = new BufferedReader(inReader); + String s; + while ((s = inBuffer.readLine()) != null) { + mProcMemWriter.write(s); + mProcMemWriter.write("\n"); + } + mProcMemWriter.write("\n\n"); + } + public String captureMediaserverInfo() { String cm = "ps mediaserver"; String memoryUsage = null; @@ -306,7 +337,7 @@ public class MediaPlayerPerformance extends ActivityInstrumentationTestCase2<Med return vsizevalue; } - public boolean validateMemoryResult(int startPid, int startMemory, Writer output, int limit) + public boolean validateMemoryResult(int startPid, int startMemory, int limit) throws Exception { // Wait for 10 seconds to make sure the memory settle. Thread.sleep(10000); @@ -315,11 +346,11 @@ public class MediaPlayerPerformance extends ActivityInstrumentationTestCase2<Med if (memDiff < 0) { memDiff = 0; } - output.write("The total diff = " + memDiff); - output.write("\n\n"); + mMemWriter.write("The total diff = " + memDiff); + mMemWriter.write("\n\n"); // mediaserver crash if (startPid != mEndPid) { - output.write("mediaserver died. Test failed\n"); + mMemWriter.write("mediaserver died. Test failed\n"); return false; } // memory leak greter than the tolerant @@ -331,18 +362,16 @@ public class MediaPlayerPerformance extends ActivityInstrumentationTestCase2<Med @LargeTest public void testH263VideoPlaybackMemoryUsage() throws Exception { boolean memoryResult = false; - mStartPid = getMediaserverPid(); - File h263MemoryOut = new File(MEDIA_MEMORY_OUTPUT); - Writer output = new BufferedWriter(new FileWriter(h263MemoryOut, true)); - output.write("H263 Video Playback Only\n"); + mStartPid = getMediaserverPid(); + mMemWriter.write("H263 Video Playback Only\n"); for (int i = 0; i < NUM_STRESS_LOOP; i++) { mediaStressPlayback(MediaNames.VIDEO_HIGHRES_H263); - getMemoryWriteToLog(output, i); + getMemoryWriteToLog(i); + writeProcmemInfo(); } - output.write("\n"); - memoryResult = validateMemoryResult(mStartPid, mStartMemory, output, DECODER_LIMIT); - output.close(); + mMemWriter.write("\n"); + memoryResult = validateMemoryResult(mStartPid, mStartMemory, DECODER_LIMIT); assertTrue("H263 playback memory test", memoryResult); } @@ -350,18 +379,16 @@ public class MediaPlayerPerformance extends ActivityInstrumentationTestCase2<Med @LargeTest public void testH264VideoPlaybackMemoryUsage() throws Exception { boolean memoryResult = false; - mStartPid = getMediaserverPid(); - File h264MemoryOut = new File(MEDIA_MEMORY_OUTPUT); - Writer output = new BufferedWriter(new FileWriter(h264MemoryOut, true)); - output.write("H264 Video Playback only\n"); + mStartPid = getMediaserverPid(); + mMemWriter.write("H264 Video Playback only\n"); for (int i = 0; i < NUM_STRESS_LOOP; i++) { mediaStressPlayback(MediaNames.VIDEO_H264_AMR); - getMemoryWriteToLog(output, i); + getMemoryWriteToLog(i); + writeProcmemInfo(); } - output.write("\n"); - memoryResult = validateMemoryResult(mStartPid, mStartMemory, output, DECODER_LIMIT); - output.close(); + mMemWriter.write("\n"); + memoryResult = validateMemoryResult(mStartPid, mStartMemory, DECODER_LIMIT); assertTrue("H264 playback memory test", memoryResult); } @@ -369,21 +396,19 @@ public class MediaPlayerPerformance extends ActivityInstrumentationTestCase2<Med @LargeTest public void testH263RecordVideoOnlyMemoryUsage() throws Exception { boolean memoryResult = false; - mStartPid = getMediaserverPid(); - File videoH263RecordOnlyMemoryOut = new File(MEDIA_MEMORY_OUTPUT); - Writer output = new BufferedWriter(new FileWriter(videoH263RecordOnlyMemoryOut, true)); - output.write("H263 video record only\n"); + mStartPid = getMediaserverPid(); + mMemWriter.write("H263 video record only\n"); int frameRate = MediaProfileReader.getMaxFrameRateForCodec(MediaRecorder.VideoEncoder.H263); assertTrue("H263 video recording frame rate", frameRate != -1); for (int i = 0; i < NUM_STRESS_LOOP; i++) { assertTrue(stressVideoRecord(frameRate, 352, 288, MediaRecorder.VideoEncoder.H263, MediaRecorder.OutputFormat.MPEG_4, MediaNames.RECORDED_VIDEO_3GP, true)); - getMemoryWriteToLog(output, i); + getMemoryWriteToLog(i); + writeProcmemInfo(); } - output.write("\n"); - memoryResult = validateMemoryResult(mStartPid, mStartMemory, output, ENCODER_LIMIT); - output.close(); + mMemWriter.write("\n"); + memoryResult = validateMemoryResult(mStartPid, mStartMemory, ENCODER_LIMIT); assertTrue("H263 record only memory test", memoryResult); } @@ -391,21 +416,19 @@ public class MediaPlayerPerformance extends ActivityInstrumentationTestCase2<Med @LargeTest public void testMpeg4RecordVideoOnlyMemoryUsage() throws Exception { boolean memoryResult = false; - mStartPid = getMediaserverPid(); - File videoMp4RecordOnlyMemoryOut = new File(MEDIA_MEMORY_OUTPUT); - Writer output = new BufferedWriter(new FileWriter(videoMp4RecordOnlyMemoryOut, true)); - output.write("MPEG4 video record only\n"); + mStartPid = getMediaserverPid(); + mMemWriter.write("MPEG4 video record only\n"); int frameRate = MediaProfileReader.getMaxFrameRateForCodec(MediaRecorder.VideoEncoder.MPEG_4_SP); assertTrue("MPEG4 video recording frame rate", frameRate != -1); for (int i = 0; i < NUM_STRESS_LOOP; i++) { assertTrue(stressVideoRecord(frameRate, 352, 288, MediaRecorder.VideoEncoder.MPEG_4_SP, MediaRecorder.OutputFormat.MPEG_4, MediaNames.RECORDED_VIDEO_3GP, true)); - getMemoryWriteToLog(output, i); + getMemoryWriteToLog(i); + writeProcmemInfo(); } - output.write("\n"); - memoryResult = validateMemoryResult(mStartPid, mStartMemory, output, ENCODER_LIMIT); - output.close(); + mMemWriter.write("\n"); + memoryResult = validateMemoryResult(mStartPid, mStartMemory, ENCODER_LIMIT); assertTrue("mpeg4 record only memory test", memoryResult); } @@ -414,21 +437,19 @@ public class MediaPlayerPerformance extends ActivityInstrumentationTestCase2<Med @LargeTest public void testRecordVideoAudioMemoryUsage() throws Exception { boolean memoryResult = false; - mStartPid = getMediaserverPid(); - File videoRecordAudioMemoryOut = new File(MEDIA_MEMORY_OUTPUT); - Writer output = new BufferedWriter(new FileWriter(videoRecordAudioMemoryOut, true)); + mStartPid = getMediaserverPid(); int frameRate = MediaProfileReader.getMaxFrameRateForCodec(MediaRecorder.VideoEncoder.H263); assertTrue("H263 video recording frame rate", frameRate != -1); - output.write("Audio and h263 video record\n"); + mMemWriter.write("Audio and h263 video record\n"); for (int i = 0; i < NUM_STRESS_LOOP; i++) { assertTrue(stressVideoRecord(frameRate, 352, 288, MediaRecorder.VideoEncoder.H263, MediaRecorder.OutputFormat.MPEG_4, MediaNames.RECORDED_VIDEO_3GP, false)); - getMemoryWriteToLog(output, i); + getMemoryWriteToLog(i); + writeProcmemInfo(); } - output.write("\n"); - memoryResult = validateMemoryResult(mStartPid, mStartMemory, output, ENCODER_LIMIT); - output.close(); + mMemWriter.write("\n"); + memoryResult = validateMemoryResult(mStartPid, mStartMemory, ENCODER_LIMIT); assertTrue("H263 audio video record memory test", memoryResult); } @@ -436,18 +457,16 @@ public class MediaPlayerPerformance extends ActivityInstrumentationTestCase2<Med @LargeTest public void testRecordAudioOnlyMemoryUsage() throws Exception { boolean memoryResult = false; - mStartPid = getMediaserverPid(); - File audioOnlyMemoryOut = new File(MEDIA_MEMORY_OUTPUT); - Writer output = new BufferedWriter(new FileWriter(audioOnlyMemoryOut, true)); - output.write("Audio record only\n"); + mStartPid = getMediaserverPid(); + mMemWriter.write("Audio record only\n"); for (int i = 0; i < NUM_STRESS_LOOP; i++) { stressAudioRecord(MediaNames.RECORDER_OUTPUT); - getMemoryWriteToLog(output, i); + getMemoryWriteToLog(i); + writeProcmemInfo(); } - output.write("\n"); - memoryResult = validateMemoryResult(mStartPid, mStartMemory, output, ENCODER_LIMIT); - output.close(); + mMemWriter.write("\n"); + memoryResult = validateMemoryResult(mStartPid, mStartMemory, ENCODER_LIMIT); assertTrue("audio record only memory test", memoryResult); } @@ -455,18 +474,16 @@ public class MediaPlayerPerformance extends ActivityInstrumentationTestCase2<Med @LargeTest public void testCameraPreviewMemoryUsage() throws Exception { boolean memoryResult = false; - mStartPid = getMediaserverPid(); - File cameraPreviewMemoryOut = new File(MEDIA_MEMORY_OUTPUT); - Writer output = new BufferedWriter(new FileWriter(cameraPreviewMemoryOut, true)); - output.write("Camera Preview Only\n"); + mStartPid = getMediaserverPid(); + mMemWriter.write("Camera Preview Only\n"); for (int i = 0; i < NUM_STRESS_LOOP; i++) { stressCameraPreview(); - getMemoryWriteToLog(output, i); + getMemoryWriteToLog(i); + writeProcmemInfo(); } - output.write("\n"); - memoryResult = validateMemoryResult(mStartPid, mStartMemory, output, CAMERA_LIMIT); - output.close(); + mMemWriter.write("\n"); + memoryResult = validateMemoryResult(mStartPid, mStartMemory, CAMERA_LIMIT); assertTrue("camera preview memory test", memoryResult); } } diff --git a/native/include/android/keycodes.h b/native/include/android/keycodes.h index 5d49775cb2c8..8414ff6eadc9 100644 --- a/native/include/android/keycodes.h +++ b/native/include/android/keycodes.h @@ -250,6 +250,10 @@ enum { AKEYCODE_LANGUAGE_SWITCH = 204, AKEYCODE_MANNER_MODE = 205, AKEYCODE_3D_MODE = 206, + AKEYCODE_CONTACTS = 207, + AKEYCODE_CALENDAR = 208, + AKEYCODE_MUSIC = 209, + AKEYCODE_CALCULATOR = 210, // NOTE: If you add a new keycode here you must also add it to several other files. // Refer to frameworks/base/core/java/android/view/KeyEvent.java for the full list. diff --git a/opengl/java/android/opengl/GLES11Ext.java b/opengl/java/android/opengl/GLES11Ext.java index 25d54674ca03..484439a9c143 100644 --- a/opengl/java/android/opengl/GLES11Ext.java +++ b/opengl/java/android/opengl/GLES11Ext.java @@ -125,6 +125,10 @@ public class GLES11Ext { public static final int GL_TEXTURE_MAX_ANISOTROPY_EXT = 0x84FE; public static final int GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT = 0x84FF; public static final int GL_BGRA = 0x80E1; + public static final int GL_TEXTURE_EXTERNAL_OES = 0x8D65; + public static final int GL_SAMPLER_EXTERNAL_OES = 0x8D66; + public static final int GL_TEXTURE_BINDING_EXTERNAL_OES = 0x8D67; + public static final int GL_REQUIRED_TEXTURE_IMAGE_UNITS_OES = 0x8D68; native private static void _nativeClassInit(); static { diff --git a/opengl/java/android/opengl/ManagedEGLContext.java b/opengl/java/android/opengl/ManagedEGLContext.java index d3a3662c8f4b..61fa565a049c 100644 --- a/opengl/java/android/opengl/ManagedEGLContext.java +++ b/opengl/java/android/opengl/ManagedEGLContext.java @@ -43,12 +43,13 @@ import com.google.android.gles_jni.EGLImpl; * of the currently created EGL contexts in the process are being managed * through this class, then they will all be asked to terminate through the * call to {@link #onTerminate}. + * + * @hide */ public abstract class ManagedEGLContext { static final String TAG = "ManagedEGLContext"; - static final ArrayList<ManagedEGLContext> sActive - = new ArrayList<ManagedEGLContext>(); + static final ArrayList<ManagedEGLContext> sActive = new ArrayList<ManagedEGLContext>(); final EGLContext mContext; @@ -127,7 +128,7 @@ public abstract class ManagedEGLContext { sActive.clear(); } - for (int i=0; i<active.size(); i++) { + for (int i = 0; i < active.size(); i++) { active.get(i).execTerminate(); } diff --git a/opengl/libs/Android.mk b/opengl/libs/Android.mk index 5855b635b053..9c1a10e21438 100644 --- a/opengl/libs/Android.mk +++ b/opengl/libs/Android.mk @@ -44,10 +44,17 @@ ifeq ($(ARCH_ARM_HAVE_TLS_REGISTER),true) LOCAL_CFLAGS += -DHAVE_ARM_TLS_REGISTER endif +ifneq ($(MAX_EGL_CACHE_ENTRY_SIZE),) + LOCAL_CFLAGS += -DMAX_EGL_CACHE_ENTRY_SIZE=$(MAX_EGL_CACHE_ENTRY_SIZE) +endif + +ifneq ($(MAX_EGL_CACHE_SIZE),) + LOCAL_CFLAGS += -DMAX_EGL_CACHE_SIZE=$(MAX_EGL_CACHE_SIZE) +endif + include $(BUILD_SHARED_LIBRARY) installed_libEGL := $(LOCAL_INSTALLED_MODULE) - # OpenGL drivers config file ifneq ($(BOARD_EGL_CFG),) diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp index 2237eb6c0873..2b0ed5dfd654 100644 --- a/opengl/libs/EGL/eglApi.cpp +++ b/opengl/libs/EGL/eglApi.cpp @@ -49,6 +49,8 @@ using namespace android; // ---------------------------------------------------------------------------- +#define EGL_VERSION_HW_ANDROID 0x3143 + struct extention_map_t { const char* name; __eglMustCastToProperFunctionPointerType address; @@ -370,6 +372,11 @@ EGLSurface eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config, } } + // the EGL spec requires that a new EGLSurface default to swap interval + // 1, so explicitly set that on the window here. + ANativeWindow* anw = reinterpret_cast<ANativeWindow*>(window); + anw->setSwapInterval(anw, 1); + EGLSurface surface = cnx->egl.eglCreateWindowSurface( iDpy, iConfig, window, attrib_list); if (surface != EGL_NO_SURFACE) { @@ -967,6 +974,12 @@ const char* eglQueryString(EGLDisplay dpy, EGLint name) return dp->getExtensionString(); case EGL_CLIENT_APIS: return dp->getClientApiString(); + case EGL_VERSION_HW_ANDROID: { + if (gEGLImpl[IMPL_HARDWARE].dso) { + return dp->disp[IMPL_HARDWARE].queryString.version; + } + return dp->disp[IMPL_SOFTWARE].queryString.version; + } } return setError(EGL_BAD_PARAMETER, (const char *)0); } diff --git a/opengl/libs/EGL/egl_cache.cpp b/opengl/libs/EGL/egl_cache.cpp index 13a492917d2c..c4a7466ec537 100644 --- a/opengl/libs/EGL/egl_cache.cpp +++ b/opengl/libs/EGL/egl_cache.cpp @@ -25,10 +25,18 @@ #include <sys/types.h> #include <unistd.h> +#ifndef MAX_EGL_CACHE_ENTRY_SIZE +#define MAX_EGL_CACHE_ENTRY_SIZE (16 * 1024); +#endif + +#ifndef MAX_EGL_CACHE_SIZE +#define MAX_EGL_CACHE_SIZE (64 * 1024); +#endif + // Cache size limits. static const size_t maxKeySize = 1024; -static const size_t maxValueSize = 4096; -static const size_t maxTotalSize = 64 * 1024; +static const size_t maxValueSize = MAX_EGL_CACHE_ENTRY_SIZE; +static const size_t maxTotalSize = MAX_EGL_CACHE_SIZE; // Cache file header static const char* cacheFileMagic = "EGL$"; @@ -85,7 +93,7 @@ void egl_cache_t::initialize(egl_display_t *display) { bool atStart = !strncmp(BC_EXT_STR " ", exts, bcExtLen+1); bool atEnd = (bcExtLen+1) < extsLen && !strcmp(" " BC_EXT_STR, exts + extsLen - (bcExtLen+1)); - bool inMiddle = strstr(" " BC_EXT_STR " ", exts); + bool inMiddle = strstr(exts, " " BC_EXT_STR " "); if (equal || atStart || atEnd || inMiddle) { PFNEGLSETBLOBCACHEFUNCSANDROIDPROC eglSetBlobCacheFuncsANDROID; eglSetBlobCacheFuncsANDROID = diff --git a/opengl/specs/README b/opengl/specs/README index 2fa258777f7f..16b278fd49be 100644 --- a/opengl/specs/README +++ b/opengl/specs/README @@ -9,4 +9,5 @@ for use by Android extensions. 0x3140 EGL_ANDROID_image_native_buffer 0x3141 (unused) 0x3142 EGL_ANDROID_recordable -0x3143 - 0x314F (unused) +0x3143 EGL_VERSION_HW_ANDROID (internal use) +0x3144 - 0x314F (unused) diff --git a/opengl/tools/glgen/stubs/gles11/GLES11ExtHeader.java-if b/opengl/tools/glgen/stubs/gles11/GLES11ExtHeader.java-if index c5e34cd1b9aa..0c5fa04f134f 100644 --- a/opengl/tools/glgen/stubs/gles11/GLES11ExtHeader.java-if +++ b/opengl/tools/glgen/stubs/gles11/GLES11ExtHeader.java-if @@ -124,6 +124,10 @@ public class GLES11Ext { public static final int GL_TEXTURE_MAX_ANISOTROPY_EXT = 0x84FE; public static final int GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT = 0x84FF; public static final int GL_BGRA = 0x80E1; + public static final int GL_TEXTURE_EXTERNAL_OES = 0x8D65; + public static final int GL_SAMPLER_EXTERNAL_OES = 0x8D66; + public static final int GL_TEXTURE_BINDING_EXTERNAL_OES = 0x8D67; + public static final int GL_REQUIRED_TEXTURE_IMAGE_UNITS_OES = 0x8D68; native private static void _nativeClassInit(); static { @@ -135,4 +139,4 @@ public class GLES11Ext { private static final int GL_FLOAT = GLES10.GL_FLOAT; private static final int GL_SHORT = GLES10.GL_SHORT; - private static Buffer _matrixIndexPointerOES;
\ No newline at end of file + private static Buffer _matrixIndexPointerOES; diff --git a/packages/BackupRestoreConfirmation/res/values-af/strings.xml b/packages/BackupRestoreConfirmation/res/values-af/strings.xml index 8ee5550eab8f..fadd12507d71 100644 --- a/packages/BackupRestoreConfirmation/res/values-af/strings.xml +++ b/packages/BackupRestoreConfirmation/res/values-af/strings.xml @@ -18,10 +18,10 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="backup_confirm_title" msgid="827563724209303345">"Volledige rugsteun"</string> <string name="restore_confirm_title" msgid="5469365809567486602">"Volledige herstel"</string> - <string name="backup_confirm_text" msgid="1878021282758896593">"\'n Volledige rugsteun van al die data na \'n tafelrekenaar is aangevra. Wil jy dit toelaat? "\n\n"As jy nie self die rugsteun versoek het nie, moenie toelaat dat die aksie voortgaan nie."</string> + <string name="backup_confirm_text" msgid="1878021282758896593">"\'n Volledige rugsteun van al die data na \'n rekenaar is aangevra. Wil jy dit toelaat? "\n\n"As jy nie self die rugsteun versoek het nie, moenie toelaat dat die aksie voortgaan nie."</string> <string name="allow_backup_button_label" msgid="4217228747769644068">"Rugsteun my data"</string> <string name="deny_backup_button_label" msgid="6009119115581097708">"Moenie rugsteun nie"</string> - <string name="restore_confirm_text" msgid="7499866728030461776">"\'n Volle teruglaai van alle data van \'n gekoppelde tafelrekenaar is versoek. Wil jy dit toelaat? "\n\n" As jy nie die teruglaai self versoek het nie, moenie die aksie toelaat nie. Dit sal enige data tans op die toestel vervang!"</string> + <string name="restore_confirm_text" msgid="7499866728030461776">"\'n Volle teruglaai van alle data van \'n gekoppelde rekenaar is versoek. Wil jy dit toelaat? "\n\n" As jy nie die teruglaai self versoek het nie, moenie die aksie toelaat nie. Dit sal enige data tans op die toestel vervang!"</string> <string name="allow_restore_button_label" msgid="3081286752277127827">"Laai my data terug"</string> <string name="deny_restore_button_label" msgid="1724367334453104378">"Moenie herstel nie"</string> <string name="current_password_text" msgid="8268189555578298067">"Voer asseblief jou huidige rugsteunwagwoord hieronder in:"</string> diff --git a/packages/SettingsProvider/res/values-vi/strings.xml b/packages/SettingsProvider/res/values-vi/strings.xml index 113d7adb9437..504479d68d5e 100644 --- a/packages/SettingsProvider/res/values-vi/strings.xml +++ b/packages/SettingsProvider/res/values-vi/strings.xml @@ -19,5 +19,5 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="app_label" msgid="4567566098528588863">"Bộ nhớ Cài đặt"</string> + <string name="app_label" msgid="4567566098528588863">"Lưu trữ cài đặt"</string> </resources> diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml index 7a98615fe836..1ebed1fd3c76 100644 --- a/packages/SettingsProvider/res/values/defaults.xml +++ b/packages/SettingsProvider/res/values/defaults.xml @@ -80,6 +80,9 @@ <!-- Default for Settings.Secure.ACCESSIBILITY_SCRIPT_INJECTION --> <bool name="def_accessibility_script_injection">false</bool> + <!-- Default for Settings.Secure.ACCESSIBILITY_SPEAK_PASSWORD --> + <bool name="def_accessibility_speak_password">false</bool> + <!-- Default for Settings.Secure.ACCESSIBILITY_WEB_CONTENT_KEY_BINDINGS --> <string name="def_accessibility_web_content_key_bindings" translatable="false"> <!-- DPAD/Trackball UP - traverse previous on current axis and send an event. --> diff --git a/packages/SettingsProvider/res/xml/bookmarks.xml b/packages/SettingsProvider/res/xml/bookmarks.xml index 83229f410d59..454f4562a239 100644 --- a/packages/SettingsProvider/res/xml/bookmarks.xml +++ b/packages/SettingsProvider/res/xml/bookmarks.xml @@ -19,6 +19,7 @@ Bookmarks for vendor apps should be added to a bookmarks resource overlay; not here. Typical shortcuts (not necessarily defined here): + 'a': Calculator 'b': Browser 'c': Contacts 'e': Email @@ -32,27 +33,27 @@ --> <bookmarks> <bookmark - package="com.android.browser" - class="com.android.browser.BrowserActivity" + category="android.intent.category.APP_CALCULATOR" + shortcut="a" /> + <bookmark + category="android.intent.category.APP_BROWSER" shortcut="b" /> <bookmark - package="com.android.contacts" - class="com.android.contacts.activities.ContactsFrontDoor" + category="android.intent.category.APP_CONTACTS" shortcut="c" /> <bookmark - package="com.google.android.email" - class="com.android.email.activity.Welcome" + category="android.intent.category.APP_EMAIL" shortcut="e" /> <bookmark - package="com.google.android.calendar" - class="com.android.calendar.LaunchActivity" + category="android.intent.category.APP_CALENDAR" shortcut="l" /> <bookmark - package="com.android.music" - class="com.android.music.MusicBrowserActivity" + category="android.intent.category.APP_MAPS" + shortcut="m" /> + <bookmark + category="android.intent.category.APP_MUSIC" shortcut="p" /> <bookmark - package="com.android.mms" - class="com.android.mms.ui.ConversationList" + category="android.intent.category.APP_MESSAGING" shortcut="s" /> </bookmarks> diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java index aa08e64353d8..1fbe08d87943 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java @@ -63,7 +63,7 @@ public class DatabaseHelper extends SQLiteOpenHelper { // database gets upgraded properly. At a minimum, please confirm that 'upgradeVersion' // is properly propagated through your change. Not doing so will result in a loss of user // settings. - private static final int DATABASE_VERSION = 70; + private static final int DATABASE_VERSION = 73; private Context mContext; @@ -946,6 +946,46 @@ public class DatabaseHelper extends SQLiteOpenHelper { upgradeVersion = 70; } + if (upgradeVersion == 70) { + // Update all built-in bookmarks. Some of the package names have changed. + loadBookmarks(db); + upgradeVersion = 71; + } + + if (upgradeVersion == 71) { + // New setting to specify whether to speak passwords in accessibility mode. + db.beginTransaction(); + SQLiteStatement stmt = null; + try { + stmt = db.compileStatement("INSERT INTO secure(name,value)" + + " VALUES(?,?);"); + loadBooleanSetting(stmt, Settings.Secure.ACCESSIBILITY_SPEAK_PASSWORD, + R.bool.def_accessibility_speak_password); + db.setTransactionSuccessful(); + } finally { + db.endTransaction(); + if (stmt != null) stmt.close(); + } + upgradeVersion = 72; + } + + if (upgradeVersion == 72) { + // update vibration settings + db.beginTransaction(); + SQLiteStatement stmt = null; + try { + stmt = db.compileStatement("INSERT OR REPLACE INTO system(name,value)" + + " VALUES(?,?);"); + loadBooleanSetting(stmt, Settings.System.VIBRATE_IN_SILENT, + R.bool.def_vibrate_in_silent); + db.setTransactionSuccessful(); + } finally { + db.endTransaction(); + if (stmt != null) stmt.close(); + } + upgradeVersion = 73; + } + // *** Remember to update DATABASE_VERSION above! if (upgradeVersion != currentVersion) { @@ -1086,16 +1126,11 @@ public class DatabaseHelper extends SQLiteOpenHelper { * Loads the default set of bookmarked shortcuts from an xml file. * * @param db The database to write the values into - * @param startingIndex The zero-based position at which bookmarks in this file should begin */ - private int loadBookmarks(SQLiteDatabase db, int startingIndex) { - Intent intent = new Intent(Intent.ACTION_MAIN, null); - intent.addCategory(Intent.CATEGORY_LAUNCHER); + private void loadBookmarks(SQLiteDatabase db) { ContentValues values = new ContentValues(); PackageManager packageManager = mContext.getPackageManager(); - int i = startingIndex; - try { XmlResourceParser parser = mContext.getResources().getXml(R.xml.bookmarks); XmlUtils.beginDocument(parser, "bookmarks"); @@ -1118,54 +1153,59 @@ public class DatabaseHelper extends SQLiteOpenHelper { String pkg = parser.getAttributeValue(null, "package"); String cls = parser.getAttributeValue(null, "class"); String shortcutStr = parser.getAttributeValue(null, "shortcut"); + String category = parser.getAttributeValue(null, "category"); int shortcutValue = shortcutStr.charAt(0); if (TextUtils.isEmpty(shortcutStr)) { Log.w(TAG, "Unable to get shortcut for: " + pkg + "/" + cls); + continue; } - ActivityInfo info = null; - ComponentName cn = new ComponentName(pkg, cls); - try { - info = packageManager.getActivityInfo(cn, 0); - } catch (PackageManager.NameNotFoundException e) { - String[] packages = packageManager.canonicalToCurrentPackageNames( - new String[] { pkg }); - cn = new ComponentName(packages[0], cls); + final Intent intent; + final String title; + if (pkg != null && cls != null) { + ActivityInfo info = null; + ComponentName cn = new ComponentName(pkg, cls); try { info = packageManager.getActivityInfo(cn, 0); - } catch (PackageManager.NameNotFoundException e1) { - Log.w(TAG, "Unable to add bookmark: " + pkg + "/" + cls, e); + } catch (PackageManager.NameNotFoundException e) { + String[] packages = packageManager.canonicalToCurrentPackageNames( + new String[] { pkg }); + cn = new ComponentName(packages[0], cls); + try { + info = packageManager.getActivityInfo(cn, 0); + } catch (PackageManager.NameNotFoundException e1) { + Log.w(TAG, "Unable to add bookmark: " + pkg + "/" + cls, e); + continue; + } } - } - - if (info != null) { + + intent = new Intent(Intent.ACTION_MAIN, null); + intent.addCategory(Intent.CATEGORY_LAUNCHER); intent.setComponent(cn); - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - values.put(Settings.Bookmarks.INTENT, intent.toUri(0)); - values.put(Settings.Bookmarks.TITLE, - info.loadLabel(packageManager).toString()); - values.put(Settings.Bookmarks.SHORTCUT, shortcutValue); - db.insert("bookmarks", null, values); - i++; + title = info.loadLabel(packageManager).toString(); + } else if (category != null) { + intent = Intent.makeMainSelectorActivity(Intent.ACTION_MAIN, category); + title = ""; + } else { + Log.w(TAG, "Unable to add bookmark for shortcut " + shortcutStr + + ": missing package/class or category attributes"); + continue; } + + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + values.put(Settings.Bookmarks.INTENT, intent.toUri(0)); + values.put(Settings.Bookmarks.TITLE, title); + values.put(Settings.Bookmarks.SHORTCUT, shortcutValue); + db.delete("bookmarks", "shortcut = ?", + new String[] { Integer.toString(shortcutValue) }); + db.insert("bookmarks", null, values); } } catch (XmlPullParserException e) { Log.w(TAG, "Got execption parsing bookmarks.", e); } catch (IOException e) { Log.w(TAG, "Got execption parsing bookmarks.", e); } - - return i; - } - - /** - * Loads the default set of bookmark packages. - * - * @param db The database to write the values into - */ - private void loadBookmarks(SQLiteDatabase db) { - loadBookmarks(db, 0); } /** @@ -1483,6 +1523,9 @@ public class DatabaseHelper extends SQLiteOpenHelper { loadBooleanSetting(stmt, Settings.Secure.TOUCH_EXPLORATION_ENABLED, R.bool.def_touch_exploration_enabled); + + loadBooleanSetting(stmt, Settings.Secure.ACCESSIBILITY_SPEAK_PASSWORD, + R.bool.def_accessibility_speak_password); } finally { if (stmt != null) stmt.close(); } diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml index dff41c977b5a..ec08e6c05c39 100644 --- a/packages/SystemUI/AndroidManifest.xml +++ b/packages/SystemUI/AndroidManifest.xml @@ -46,28 +46,9 @@ </intent-filter> </receiver> - <!-- should you need to launch the screensaver, this is a good way to do it --> - <activity android:name=".DreamsDockLauncher" - android:theme="@android:style/Theme.Dialog" - android:label="@string/dreams_dock_launcher"> - <intent-filter> - <action android:name="android.intent.action.MAIN" /> - <category android:name="android.intent.category.DEFAULT" /> - </intent-filter> - </activity> - - <!-- launch screensaver on (desk) dock event --> - <receiver android:name=".DreamsDockLauncher$DockEventReceiver" - android:exported="true" - > - <intent-filter> - <action android:name="android.intent.action.DOCK_EVENT" /> - </intent-filter> - </receiver> - - <activity android:name=".usb.UsbStorageActivity" - android:excludeFromRecents="true"> + android:label="@*android:string/usb_storage_activity_title" + android:excludeFromRecents="true"> </activity> <activity android:name="com.android.internal.app.ExternalMediaFormatActivity" android:theme="@*android:style/Theme.Dialog.Alert" diff --git a/packages/SystemUI/res/drawable-hdpi/ic_launcher_settings.png b/packages/SystemUI/res/drawable-hdpi/ic_launcher_settings.png Binary files differindex cbd72fb7cd8b..c02bd424f51d 100644 --- a/packages/SystemUI/res/drawable-hdpi/ic_launcher_settings.png +++ b/packages/SystemUI/res/drawable-hdpi/ic_launcher_settings.png diff --git a/packages/SystemUI/res/drawable-mdpi/ic_launcher_settings.png b/packages/SystemUI/res/drawable-mdpi/ic_launcher_settings.png Binary files differindex 765133110704..05cdd9aa94e8 100644 --- a/packages/SystemUI/res/drawable-mdpi/ic_launcher_settings.png +++ b/packages/SystemUI/res/drawable-mdpi/ic_launcher_settings.png diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_launcher_settings.png b/packages/SystemUI/res/drawable-xhdpi/ic_launcher_settings.png Binary files differindex b6317797d946..2b2907b60843 100644 --- a/packages/SystemUI/res/drawable-xhdpi/ic_launcher_settings.png +++ b/packages/SystemUI/res/drawable-xhdpi/ic_launcher_settings.png diff --git a/packages/SystemUI/res/layout-sw600dp/status_bar_ticker_panel.xml b/packages/SystemUI/res/layout-sw600dp/status_bar_ticker_panel.xml index 6cd8899b3415..d51f9c839f54 100644 --- a/packages/SystemUI/res/layout-sw600dp/status_bar_ticker_panel.xml +++ b/packages/SystemUI/res/layout-sw600dp/status_bar_ticker_panel.xml @@ -15,20 +15,29 @@ * limitations under the License. --> -<LinearLayout +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" - android:orientation="horizontal" - android:gravity="bottom" > + <View + android:layout_height="@*android:dimen/status_bar_height" + android:layout_width="match_parent" + android:background="@drawable/status_bar_ticker_background" + android:layout_alignParentLeft="true" + android:layout_alignParentBottom="true" + android:clickable="false" + /> + <ImageView android:id="@+id/large_icon" android:layout_width="@android:dimen/notification_large_icon_height" android:layout_height="@android:dimen/notification_large_icon_width" android:scaleType="center" android:visibility="gone" + android:layout_alignParentLeft="true" + android:layout_alignParentBottom="true" /> <FrameLayout @@ -36,6 +45,8 @@ android:layout_weight="1" android:layout_height="@*android:dimen/status_bar_height" android:layout_width="match_parent" - android:background="@drawable/status_bar_ticker_background" + android:layout_toRightOf="@id/large_icon" + android:layout_alignParentBottom="true" + android:layout_alignWithParentIfMissing="true" /> -</LinearLayout> +</RelativeLayout> diff --git a/packages/SystemUI/res/layout/global_screenshot.xml b/packages/SystemUI/res/layout/global_screenshot.xml index d416af929680..8b337eada622 100644 --- a/packages/SystemUI/res/layout/global_screenshot.xml +++ b/packages/SystemUI/res/layout/global_screenshot.xml @@ -19,23 +19,18 @@ <ImageView android:id="@+id/global_screenshot_background" android:layout_width="match_parent" android:layout_height="match_parent" - android:background="#FF000000" + android:src="@android:color/black" android:visibility="gone" /> - <FrameLayout - android:id="@+id/global_screenshot_container" + <ImageView android:id="@+id/global_screenshot" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:background="@drawable/screenshot_panel" - android:visibility="gone"> - <ImageView android:id="@+id/global_screenshot" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:adjustViewBounds="true" /> - </FrameLayout> + android:visibility="gone" + android:adjustViewBounds="true" /> <ImageView android:id="@+id/global_screenshot_flash" android:layout_width="match_parent" android:layout_height="match_parent" - android:background="#FFFFFFFF" + android:src="@android:color/white" android:visibility="gone" /> </FrameLayout> diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml index 08dedfa5cb48..e14049433e96 100644 --- a/packages/SystemUI/res/values-af/strings.xml +++ b/packages/SystemUI/res/values-af/strings.xml @@ -138,5 +138,4 @@ <string name="gps_notification_searching_text" msgid="8574247005642736060">"Soek vir GPS"</string> <string name="gps_notification_found_text" msgid="4619274244146446464">"Ligging deur GPS gestel"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"Verwyder alle kennisgewings."</string> - <string name="dreams_dock_launcher" msgid="3541196417659166245">"Aktiveer sluimerskerm"</string> </resources> diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml index 612b666d4fdb..7910f795928e 100644 --- a/packages/SystemUI/res/values-am/strings.xml +++ b/packages/SystemUI/res/values-am/strings.xml @@ -138,5 +138,4 @@ <string name="gps_notification_searching_text" msgid="8574247005642736060">"ለGPS በመፈለግ ላይ"</string> <string name="gps_notification_found_text" msgid="4619274244146446464">"በ GPS የተዘጋጀ ሥፍራ"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"ሁሉንም ማሳወቂያዎች አጽዳ"</string> - <string name="dreams_dock_launcher" msgid="3541196417659166245">" ገፁማያ ማቆያ አንቃ"</string> </resources> diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml index 4bc56afa1359..e302559a2af8 100644 --- a/packages/SystemUI/res/values-ar/strings.xml +++ b/packages/SystemUI/res/values-ar/strings.xml @@ -138,5 +138,4 @@ <string name="gps_notification_searching_text" msgid="8574247005642736060">"جارٍ البحث عن GPS"</string> <string name="gps_notification_found_text" msgid="4619274244146446464">"تم تعيين الموقع بواسطة GPS"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"محو جميع الإشعارات."</string> - <string name="dreams_dock_launcher" msgid="3541196417659166245">"تنشيط شاشة التوقف"</string> </resources> diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml index d083467e90ad..25a82a60e065 100644 --- a/packages/SystemUI/res/values-be/strings.xml +++ b/packages/SystemUI/res/values-be/strings.xml @@ -140,5 +140,4 @@ <string name="gps_notification_searching_text" msgid="8574247005642736060">"Пошук GPS"</string> <string name="gps_notification_found_text" msgid="4619274244146446464">"Месца задана праз GPS"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"Выдалiць усе апавяшчэннi."</string> - <string name="dreams_dock_launcher" msgid="3541196417659166245">"Актывацыя экраннай застаўкі"</string> </resources> diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml index 33aca928e91b..c2bce86508cf 100644 --- a/packages/SystemUI/res/values-bg/strings.xml +++ b/packages/SystemUI/res/values-bg/strings.xml @@ -138,5 +138,4 @@ <string name="gps_notification_searching_text" msgid="8574247005642736060">"Търси се GPS"</string> <string name="gps_notification_found_text" msgid="4619274244146446464">"Местоположението е зададено от GPS"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"Изчистване на всички известия."</string> - <string name="dreams_dock_launcher" msgid="3541196417659166245">"Активиране на скрийнсейвъра"</string> </resources> diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml index 775e610fe565..68ab2a795185 100644 --- a/packages/SystemUI/res/values-ca/strings.xml +++ b/packages/SystemUI/res/values-ca/strings.xml @@ -140,5 +140,4 @@ <string name="gps_notification_searching_text" msgid="8574247005642736060">"S\'està cercant un GPS"</string> <string name="gps_notification_found_text" msgid="4619274244146446464">"S\'ha establert la ubicació per GPS"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"Esborra totes les notificacions."</string> - <string name="dreams_dock_launcher" msgid="3541196417659166245">"Activa el protector de pantalla"</string> </resources> diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml index 4d9b2cdd9441..48ebbd03fa7e 100644 --- a/packages/SystemUI/res/values-cs/strings.xml +++ b/packages/SystemUI/res/values-cs/strings.xml @@ -140,5 +140,4 @@ <string name="gps_notification_searching_text" msgid="8574247005642736060">"Vyhledávání satelitů GPS"</string> <string name="gps_notification_found_text" msgid="4619274244146446464">"Poloha nastavena pomocí systému GPS"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"Vymazat všechna oznámení."</string> - <string name="dreams_dock_launcher" msgid="3541196417659166245">"Aktivovat spořič obrazovky"</string> </resources> diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml index 841f6e257da7..af6428b4c288 100644 --- a/packages/SystemUI/res/values-da/strings.xml +++ b/packages/SystemUI/res/values-da/strings.xml @@ -33,7 +33,7 @@ </plurals> <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Ingen meddelelser"</string> <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"I gang"</string> - <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Meddelelser"</string> + <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Underretninger"</string> <string name="battery_low_title" msgid="2783104807551211639">"Tilslut oplader"</string> <string name="battery_low_subtitle" msgid="1752040062087829196">"Batteriet er ved at være fladt."</string> <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> tilbage"</string> @@ -45,7 +45,7 @@ <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Automatisk skærmrotation"</string> <string name="status_bar_settings_mute_label" msgid="554682549917429396">"LYDLØS"</string> <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"AUTO"</string> - <string name="status_bar_settings_notifications" msgid="397146176280905137">"Meddelelser"</string> + <string name="status_bar_settings_notifications" msgid="397146176280905137">"Underretninger"</string> <string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth-tethering anvendt"</string> <string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Konfigurer inputmetoder"</string> <string name="status_bar_use_physical_keyboard" msgid="3695516942412442936">"Brug fysisk tastatur"</string> @@ -119,7 +119,7 @@ <string name="accessibility_airplane_mode" msgid="834748999790763092">"Flytilstand."</string> <string name="accessibility_battery_level" msgid="7451474187113371965">"Batteri <xliff:g id="NUMBER">%d</xliff:g> procent."</string> <string name="accessibility_settings_button" msgid="799583911231893380">"Systemindstillinger."</string> - <string name="accessibility_notifications_button" msgid="4498000369779421892">"Meddelelser."</string> + <string name="accessibility_notifications_button" msgid="4498000369779421892">"Underretninger."</string> <string name="accessibility_remove_notification" msgid="3603099514902182350">"Ryd meddelelse."</string> <string name="accessibility_gps_enabled" msgid="3511469499240123019">"GPS aktiveret."</string> <string name="accessibility_gps_acquiring" msgid="8959333351058967158">"GPS samler data."</string> @@ -138,5 +138,4 @@ <string name="gps_notification_searching_text" msgid="8574247005642736060">"Søger efter GPS"</string> <string name="gps_notification_found_text" msgid="4619274244146446464">"Placeringen er angivet ved hjælp af GPS"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"Ryd alle meddelelser."</string> - <string name="dreams_dock_launcher" msgid="3541196417659166245">"Aktiver pauseskærm"</string> </resources> diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml index dc1f1e3feea4..447229d56c28 100644 --- a/packages/SystemUI/res/values-de/strings.xml +++ b/packages/SystemUI/res/values-de/strings.xml @@ -140,5 +140,4 @@ <string name="gps_notification_searching_text" msgid="8574247005642736060">"GPS wird gesucht"</string> <string name="gps_notification_found_text" msgid="4619274244146446464">"Standort durch GPS festgelegt"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"Alle Benachrichtigungen löschen"</string> - <string name="dreams_dock_launcher" msgid="3541196417659166245">"Bildschirmschoner aktivieren"</string> </resources> diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml index cc9dce153136..2c25c4303693 100644 --- a/packages/SystemUI/res/values-el/strings.xml +++ b/packages/SystemUI/res/values-el/strings.xml @@ -140,5 +140,4 @@ <string name="gps_notification_searching_text" msgid="8574247005642736060">"Αναζήτηση για GPS"</string> <string name="gps_notification_found_text" msgid="4619274244146446464">"Ρύθμιση τοποθεσίας με GPS"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"Εκκαθάριση όλων των ειδοποιήσεων."</string> - <string name="dreams_dock_launcher" msgid="3541196417659166245">"Ενεργοποίηση προφύλαξης οθόνης"</string> </resources> diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml index 3c70b15ababd..d1835af4f123 100644 --- a/packages/SystemUI/res/values-en-rGB/strings.xml +++ b/packages/SystemUI/res/values-en-rGB/strings.xml @@ -138,5 +138,4 @@ <string name="gps_notification_searching_text" msgid="8574247005642736060">"Searching for GPS"</string> <string name="gps_notification_found_text" msgid="4619274244146446464">"Location set by GPS"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"Clear all notifications."</string> - <string name="dreams_dock_launcher" msgid="3541196417659166245">"Activate screen saver"</string> </resources> diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml index 85818ae6ee3b..66f43dff1ab6 100644 --- a/packages/SystemUI/res/values-es-rUS/strings.xml +++ b/packages/SystemUI/res/values-es-rUS/strings.xml @@ -140,5 +140,4 @@ <string name="gps_notification_searching_text" msgid="8574247005642736060">"Buscando GPS"</string> <string name="gps_notification_found_text" msgid="4619274244146446464">"La ubicación se estableció por GPS"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"Borrar todas las notificaciones"</string> - <string name="dreams_dock_launcher" msgid="3541196417659166245">"Activar el protector de pantalla"</string> </resources> diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml index f0dcc23a9b2e..f831aa4ada9a 100644 --- a/packages/SystemUI/res/values-es/strings.xml +++ b/packages/SystemUI/res/values-es/strings.xml @@ -138,5 +138,4 @@ <string name="gps_notification_searching_text" msgid="8574247005642736060">"Buscando GPS"</string> <string name="gps_notification_found_text" msgid="4619274244146446464">"Ubicación definida por GPS"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"Borrar todas las notificaciones"</string> - <string name="dreams_dock_launcher" msgid="3541196417659166245">"Activar salvapantallas"</string> </resources> diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml index ed62c101007d..772c78d70297 100644 --- a/packages/SystemUI/res/values-et/strings.xml +++ b/packages/SystemUI/res/values-et/strings.xml @@ -106,7 +106,7 @@ <string name="accessibility_wimax_one_bar" msgid="4170994299011863648">"WiMAX-i on üks riba."</string> <string name="accessibility_wimax_two_bars" msgid="9176236858336502288">"WiMAX-i on kaks riba."</string> <string name="accessibility_wimax_three_bars" msgid="6116551636752103927">"WiMAX-i on kolm riba."</string> - <string name="accessibility_wimax_signal_full" msgid="2768089986795579558">"WiMAX-i signaal on täis."</string> + <string name="accessibility_wimax_signal_full" msgid="2768089986795579558">"WiMAX-i signaal on tugev."</string> <string name="accessibility_data_connection_gprs" msgid="1606477224486747751">"GPRS"</string> <string name="accessibility_data_connection_3g" msgid="8628562305003568260">"3G"</string> <string name="accessibility_data_connection_3.5g" msgid="8664845609981692001">"3,5G"</string> @@ -138,5 +138,4 @@ <string name="gps_notification_searching_text" msgid="8574247005642736060">"GPS-i otsimine"</string> <string name="gps_notification_found_text" msgid="4619274244146446464">"GPS-i määratud asukoht"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"Kustuta kõik teatised."</string> - <string name="dreams_dock_launcher" msgid="3541196417659166245">"Aktiveeri ekraanisäästja"</string> </resources> diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml index 91a8f645a585..fa527cdcfb9f 100644 --- a/packages/SystemUI/res/values-fa/strings.xml +++ b/packages/SystemUI/res/values-fa/strings.xml @@ -138,5 +138,4 @@ <string name="gps_notification_searching_text" msgid="8574247005642736060">"جستجو برای GPS"</string> <string name="gps_notification_found_text" msgid="4619274244146446464">"مکان تنظیم شده توسط GPS"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"پاک کردن تمام اعلانها"</string> - <string name="dreams_dock_launcher" msgid="3541196417659166245">"فعال کردن محافظ صفحه نمایش"</string> </resources> diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml index cf9230c7b17f..2db027811722 100644 --- a/packages/SystemUI/res/values-fi/strings.xml +++ b/packages/SystemUI/res/values-fi/strings.xml @@ -138,5 +138,4 @@ <string name="gps_notification_searching_text" msgid="8574247005642736060">"Haetaan GPS-yhteyttä"</string> <string name="gps_notification_found_text" msgid="4619274244146446464">"Sijainti määritetty GPS:n avulla"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"Tyhjennä kaikki ilmoitukset."</string> - <string name="dreams_dock_launcher" msgid="3541196417659166245">"Ota näytönsäästäjä käyttöön"</string> </resources> diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml index df46d2609c8f..017c9e94a8c8 100644 --- a/packages/SystemUI/res/values-fr/strings.xml +++ b/packages/SystemUI/res/values-fr/strings.xml @@ -106,7 +106,7 @@ <string name="accessibility_wimax_one_bar" msgid="4170994299011863648">"Signal WiMAX : faible"</string> <string name="accessibility_wimax_two_bars" msgid="9176236858336502288">"Signal WiMAX : moyen"</string> <string name="accessibility_wimax_three_bars" msgid="6116551636752103927">"Signal WiMAX : bon"</string> - <string name="accessibility_wimax_signal_full" msgid="2768089986795579558">"Signal WiMAX excellent"</string> + <string name="accessibility_wimax_signal_full" msgid="2768089986795579558">"Signal WiMAX : excellent"</string> <string name="accessibility_data_connection_gprs" msgid="1606477224486747751">"GPRS"</string> <string name="accessibility_data_connection_3g" msgid="8628562305003568260">"3G"</string> <string name="accessibility_data_connection_3.5g" msgid="8664845609981692001">"3G+"</string> @@ -140,5 +140,4 @@ <string name="gps_notification_searching_text" msgid="8574247005642736060">"Recherche de GPS..."</string> <string name="gps_notification_found_text" msgid="4619274244146446464">"Position définie par GPS"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"Supprimer toutes les notifications"</string> - <string name="dreams_dock_launcher" msgid="3541196417659166245">"Activer l\'économiseur d\'écran"</string> </resources> diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml index 42b901c57b8c..f29d08ba8608 100644 --- a/packages/SystemUI/res/values-hi/strings.xml +++ b/packages/SystemUI/res/values-hi/strings.xml @@ -138,5 +138,4 @@ <string name="gps_notification_searching_text" msgid="8574247005642736060">"GPS को खोजा जा रहा है"</string> <string name="gps_notification_found_text" msgid="4619274244146446464">"GPS द्वारा सेट किया गया स्थान"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"सभी सूचनाएं साफ़ करें."</string> - <string name="dreams_dock_launcher" msgid="3541196417659166245">"स्क्रीन सेवर सक्रिय करें"</string> </resources> diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml index 4e6d99ca8241..d12a16bb18ab 100644 --- a/packages/SystemUI/res/values-hr/strings.xml +++ b/packages/SystemUI/res/values-hr/strings.xml @@ -138,5 +138,4 @@ <string name="gps_notification_searching_text" msgid="8574247005642736060">"Traženje GPS-a"</string> <string name="gps_notification_found_text" msgid="4619274244146446464">"Lokaciju utvrdio GPS"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"Brisanje svih obavijesti."</string> - <string name="dreams_dock_launcher" msgid="3541196417659166245">"Aktivirajte čuvar zaslona"</string> </resources> diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml index e710d50813ea..1d5fb73961dc 100644 --- a/packages/SystemUI/res/values-hu/strings.xml +++ b/packages/SystemUI/res/values-hu/strings.xml @@ -138,5 +138,4 @@ <string name="gps_notification_searching_text" msgid="8574247005642736060">"GPS keresése"</string> <string name="gps_notification_found_text" msgid="4619274244146446464">"A GPS beállította a helyet"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"Minden értesítés törlése"</string> - <string name="dreams_dock_launcher" msgid="3541196417659166245">"Képernyővédő aktiválása"</string> </resources> diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml index a8b024d0517b..ff2bbea8a735 100644 --- a/packages/SystemUI/res/values-in/strings.xml +++ b/packages/SystemUI/res/values-in/strings.xml @@ -138,5 +138,4 @@ <string name="gps_notification_searching_text" msgid="8574247005642736060">"Menelusuri GPS"</string> <string name="gps_notification_found_text" msgid="4619274244146446464">"Lokasi yang disetel oleh GPS"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"Menghapus semua pemberitahuan."</string> - <string name="dreams_dock_launcher" msgid="3541196417659166245">"Aktifkan tirai layar"</string> </resources> diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml index 0119d5c9247e..14b3745166c0 100644 --- a/packages/SystemUI/res/values-it/strings.xml +++ b/packages/SystemUI/res/values-it/strings.xml @@ -140,5 +140,4 @@ <string name="gps_notification_searching_text" msgid="8574247005642736060">"Ricerca del GPS"</string> <string name="gps_notification_found_text" msgid="4619274244146446464">"Posizione stabilita dal GPS"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"Cancella tutte le notifiche."</string> - <string name="dreams_dock_launcher" msgid="3541196417659166245">"Attiva screensaver"</string> </resources> diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml index b6376c8af411..c9f379162e9b 100644 --- a/packages/SystemUI/res/values-iw/strings.xml +++ b/packages/SystemUI/res/values-iw/strings.xml @@ -138,5 +138,4 @@ <string name="gps_notification_searching_text" msgid="8574247005642736060">"מחפש GPS"</string> <string name="gps_notification_found_text" msgid="4619274244146446464">"מיקום מוגדר על ידי GPS"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"נקה את כל ההתראות."</string> - <string name="dreams_dock_launcher" msgid="3541196417659166245">"הפעלת שומר מסך"</string> </resources> diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml index 54c8482268a5..3ea50f415ca7 100644 --- a/packages/SystemUI/res/values-ja/strings.xml +++ b/packages/SystemUI/res/values-ja/strings.xml @@ -102,7 +102,7 @@ <string name="accessibility_wifi_two_bars" msgid="3344340012058984348">"Wi-Fi電波: レベル2"</string> <string name="accessibility_wifi_three_bars" msgid="928322805193265041">"Wi-Fi電波: レベル3"</string> <string name="accessibility_wifi_signal_full" msgid="1275764416228473932">"Wi-Fi電波:フル"</string> - <string name="accessibility_no_wimax" msgid="4329180129727630368">"WiMAX電波状態:レベル0"</string> + <string name="accessibility_no_wimax" msgid="4329180129727630368">"WiMAX電波状態:圏外"</string> <string name="accessibility_wimax_one_bar" msgid="4170994299011863648">"WiMAX電波状態:レベル1"</string> <string name="accessibility_wimax_two_bars" msgid="9176236858336502288">"WiMAX電波状態:レベル2"</string> <string name="accessibility_wimax_three_bars" msgid="6116551636752103927">"WiMAX電波状態:レベル3"</string> @@ -140,5 +140,4 @@ <string name="gps_notification_searching_text" msgid="8574247005642736060">"GPSで検索中"</string> <string name="gps_notification_found_text" msgid="4619274244146446464">"GPSにより現在地が設定されました"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"通知をすべて消去。"</string> - <string name="dreams_dock_launcher" msgid="3541196417659166245">"スクリーンセーバーを有効にする"</string> </resources> diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml index 79569c592804..8eb7656ddf12 100644 --- a/packages/SystemUI/res/values-ko/strings.xml +++ b/packages/SystemUI/res/values-ko/strings.xml @@ -138,5 +138,4 @@ <string name="gps_notification_searching_text" msgid="8574247005642736060">"GPS 검색 중"</string> <string name="gps_notification_found_text" msgid="4619274244146446464">"GPS에서 위치 설정"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"모든 알림 지우기"</string> - <string name="dreams_dock_launcher" msgid="3541196417659166245">"스크린 세이버 활성화"</string> </resources> diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml index 490bd4a6ae4b..8ad91fb1186a 100644 --- a/packages/SystemUI/res/values-lt/strings.xml +++ b/packages/SystemUI/res/values-lt/strings.xml @@ -138,5 +138,4 @@ <string name="gps_notification_searching_text" msgid="8574247005642736060">"Ieškoma GPS"</string> <string name="gps_notification_found_text" msgid="4619274244146446464">"GPS nustatyta vieta"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"Išvalyti visus pranešimus."</string> - <string name="dreams_dock_launcher" msgid="3541196417659166245">"Aktyvinti ekrano užsklandą"</string> </resources> diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml index 62e99eea4e73..da0019fc9fa9 100644 --- a/packages/SystemUI/res/values-lv/strings.xml +++ b/packages/SystemUI/res/values-lv/strings.xml @@ -138,5 +138,4 @@ <string name="gps_notification_searching_text" msgid="8574247005642736060">"Notiek GPS meklēšana..."</string> <string name="gps_notification_found_text" msgid="4619274244146446464">"GPS iestatītā atrašanās vieta"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"Notīrīt visus paziņojumus"</string> - <string name="dreams_dock_launcher" msgid="3541196417659166245">"Aktivizēt ekrānsaudzētāju"</string> </resources> diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml index bc32081a83ac..32973392103c 100644 --- a/packages/SystemUI/res/values-ms/strings.xml +++ b/packages/SystemUI/res/values-ms/strings.xml @@ -102,7 +102,7 @@ <string name="accessibility_wifi_two_bars" msgid="3344340012058984348">"Dua bar Wi-Fi."</string> <string name="accessibility_wifi_three_bars" msgid="928322805193265041">"Tiga bar Wi-Fi."</string> <string name="accessibility_wifi_signal_full" msgid="1275764416228473932">"Isyarat WiFi penuh."</string> - <string name="accessibility_no_wimax" msgid="4329180129727630368">"No. WiMAX"</string> + <string name="accessibility_no_wimax" msgid="4329180129727630368">"Tiada WiMAX"</string> <string name="accessibility_wimax_one_bar" msgid="4170994299011863648">"WiMAX satu bar."</string> <string name="accessibility_wimax_two_bars" msgid="9176236858336502288">"WiMAX dua bar."</string> <string name="accessibility_wimax_three_bars" msgid="6116551636752103927">"WiMAX tiga bar."</string> @@ -138,5 +138,4 @@ <string name="gps_notification_searching_text" msgid="8574247005642736060">"Mencari GPS"</string> <string name="gps_notification_found_text" msgid="4619274244146446464">"Lokasi ditetapkan oleh GPS"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"Padamkan semua pemberitahuan."</string> - <string name="dreams_dock_launcher" msgid="3541196417659166245">"Aktifkan gambar skrin"</string> </resources> diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml index 7320d6eb6b3e..2a42cf911878 100644 --- a/packages/SystemUI/res/values-nb/strings.xml +++ b/packages/SystemUI/res/values-nb/strings.xml @@ -138,5 +138,4 @@ <string name="gps_notification_searching_text" msgid="8574247005642736060">"Søker etter GPS"</string> <string name="gps_notification_found_text" msgid="4619274244146446464">"Posisjon angitt av GPS"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"Fjern alle varslinger."</string> - <string name="dreams_dock_launcher" msgid="3541196417659166245">"Aktivér skjermbeskytter"</string> </resources> diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml index 8996b2a567cb..3cef79e1bd11 100644 --- a/packages/SystemUI/res/values-nl/strings.xml +++ b/packages/SystemUI/res/values-nl/strings.xml @@ -106,7 +106,7 @@ <string name="accessibility_wimax_one_bar" msgid="4170994299011863648">"WiMAX: één streepje."</string> <string name="accessibility_wimax_two_bars" msgid="9176236858336502288">"WiMAX: twee streepjes."</string> <string name="accessibility_wimax_three_bars" msgid="6116551636752103927">"WiMAX: drie streepjes."</string> - <string name="accessibility_wimax_signal_full" msgid="2768089986795579558">"WiMAX-signaal is op volledige sterkte."</string> + <string name="accessibility_wimax_signal_full" msgid="2768089986795579558">"WiMAX-signaal is op volle sterkte."</string> <string name="accessibility_data_connection_gprs" msgid="1606477224486747751">"GPRS"</string> <string name="accessibility_data_connection_3g" msgid="8628562305003568260">"3G"</string> <string name="accessibility_data_connection_3.5g" msgid="8664845609981692001">"3.5G"</string> @@ -138,5 +138,4 @@ <string name="gps_notification_searching_text" msgid="8574247005642736060">"Zoeken naar GPS"</string> <string name="gps_notification_found_text" msgid="4619274244146446464">"Locatie bepaald met GPS"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"Alle meldingen wissen."</string> - <string name="dreams_dock_launcher" msgid="3541196417659166245">"Schermbeveiliging inschakelen"</string> </resources> diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml index c65f99e8b212..b658de0c668a 100644 --- a/packages/SystemUI/res/values-pl/strings.xml +++ b/packages/SystemUI/res/values-pl/strings.xml @@ -138,5 +138,4 @@ <string name="gps_notification_searching_text" msgid="8574247005642736060">"Wyszukiwanie sygnału GPS"</string> <string name="gps_notification_found_text" msgid="4619274244146446464">"Lokalizacja ustawiona według GPS"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"Usuń wszystkie powiadomienia."</string> - <string name="dreams_dock_launcher" msgid="3541196417659166245">"Włącz wygaszacz ekranu."</string> </resources> diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml index e1340ec5bcd7..9b8d7d89933e 100644 --- a/packages/SystemUI/res/values-pt-rPT/strings.xml +++ b/packages/SystemUI/res/values-pt-rPT/strings.xml @@ -138,5 +138,4 @@ <string name="gps_notification_searching_text" msgid="8574247005642736060">"A procurar GPS"</string> <string name="gps_notification_found_text" msgid="4619274244146446464">"Localização definida por GPS"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"Limpar todas as notificações."</string> - <string name="dreams_dock_launcher" msgid="3541196417659166245">"Ativar proteção de ecrã"</string> </resources> diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml index 545d54eab8c8..8c87b2689b9d 100644 --- a/packages/SystemUI/res/values-pt/strings.xml +++ b/packages/SystemUI/res/values-pt/strings.xml @@ -140,5 +140,4 @@ <string name="gps_notification_searching_text" msgid="8574247005642736060">"Buscando GPS"</string> <string name="gps_notification_found_text" msgid="4619274244146446464">"Local definido por GPS"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"Limpar todas as notificações."</string> - <string name="dreams_dock_launcher" msgid="3541196417659166245">"Ativar proteção de tela"</string> </resources> diff --git a/packages/SystemUI/res/values-rm/strings.xml b/packages/SystemUI/res/values-rm/strings.xml index 2106b892da7c..105a30e752f2 100644 --- a/packages/SystemUI/res/values-rm/strings.xml +++ b/packages/SystemUI/res/values-rm/strings.xml @@ -244,6 +244,4 @@ <skip /> <!-- no translation found for accessibility_clear_all (5235938559247164925) --> <skip /> - <!-- no translation found for dreams_dock_launcher (3541196417659166245) --> - <skip /> </resources> diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml index e4c55d6ae2b1..7c06b61e5dbb 100644 --- a/packages/SystemUI/res/values-ro/strings.xml +++ b/packages/SystemUI/res/values-ro/strings.xml @@ -138,5 +138,4 @@ <string name="gps_notification_searching_text" msgid="8574247005642736060">"Se caută GPS"</string> <string name="gps_notification_found_text" msgid="4619274244146446464">"Locaţie setată prin GPS"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"Ştergeţi toate notificările."</string> - <string name="dreams_dock_launcher" msgid="3541196417659166245">"Activaţi screensaverul"</string> </resources> diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml index d6239900f385..44824a003e67 100644 --- a/packages/SystemUI/res/values-ru/strings.xml +++ b/packages/SystemUI/res/values-ru/strings.xml @@ -102,7 +102,7 @@ <string name="accessibility_wifi_two_bars" msgid="3344340012058984348">"Wi-Fi: два деления."</string> <string name="accessibility_wifi_three_bars" msgid="928322805193265041">"Wi-Fi: три деления."</string> <string name="accessibility_wifi_signal_full" msgid="1275764416228473932">"Надежный сигнал Wi-Fi."</string> - <string name="accessibility_no_wimax" msgid="4329180129727630368">"Сигнал WiMAX отсутствует."</string> + <string name="accessibility_no_wimax" msgid="4329180129727630368">"Нет сигнала WiMAX."</string> <string name="accessibility_wimax_one_bar" msgid="4170994299011863648">"Сигнал WiMAX: одно деление."</string> <string name="accessibility_wimax_two_bars" msgid="9176236858336502288">"Сигнал WiMAX: два деления."</string> <string name="accessibility_wimax_three_bars" msgid="6116551636752103927">"Сигнал WiMAX: три деления."</string> @@ -131,7 +131,7 @@ <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"Приложение \"<xliff:g id="APP">%s</xliff:g>\" удалено из списка."</string> <string name="data_usage_disabled_dialog_3g_title" msgid="5257833881698644687">"Передача данных по каналам 2G и 3G отключена"</string> <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"Передача данных по каналу 4G отключена"</string> - <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"Мобильный Интернет отключен"</string> + <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"Моб. Интернет отключен"</string> <string name="data_usage_disabled_dialog_title" msgid="2086815304858964954">"Передача данных отключена"</string> <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"Достигнут лимит трафика."\n\n"При восстановлении подключения оператор может взимать плату за передачу данных."</string> <string name="data_usage_disabled_dialog_enable" msgid="7729772039208664606">"Восстановить подключение"</string> @@ -140,5 +140,4 @@ <string name="gps_notification_searching_text" msgid="8574247005642736060">"Поиск GPS"</string> <string name="gps_notification_found_text" msgid="4619274244146446464">"Местоположение установлено с помощью GPS"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"Удалить все уведомления"</string> - <string name="dreams_dock_launcher" msgid="3541196417659166245">"Активация заставки экрана"</string> </resources> diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml index f0ec8ffbb219..f5213b56029b 100644 --- a/packages/SystemUI/res/values-sk/strings.xml +++ b/packages/SystemUI/res/values-sk/strings.xml @@ -140,5 +140,4 @@ <string name="gps_notification_searching_text" msgid="8574247005642736060">"Vyhľadávanie satelitov GPS"</string> <string name="gps_notification_found_text" msgid="4619274244146446464">"Poloha nastavená pomocou GPS"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"Vymazať všetky upozornenia."</string> - <string name="dreams_dock_launcher" msgid="3541196417659166245">"Aktivovať šetrič obrazovky"</string> </resources> diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml index 61b82c9291aa..5c3857e25c18 100644 --- a/packages/SystemUI/res/values-sl/strings.xml +++ b/packages/SystemUI/res/values-sl/strings.xml @@ -138,5 +138,4 @@ <string name="gps_notification_searching_text" msgid="8574247005642736060">"Iskanje GPS-a"</string> <string name="gps_notification_found_text" msgid="4619274244146446464">"Lokacija nastavljena z GPS-om"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"Izbriši vsa obvestila."</string> - <string name="dreams_dock_launcher" msgid="3541196417659166245">"Vklop ohranjevalnika zaslona"</string> </resources> diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml index f341fbaa82cb..ece79e93de56 100644 --- a/packages/SystemUI/res/values-sr/strings.xml +++ b/packages/SystemUI/res/values-sr/strings.xml @@ -138,5 +138,4 @@ <string name="gps_notification_searching_text" msgid="8574247005642736060">"Тражи се GPS"</string> <string name="gps_notification_found_text" msgid="4619274244146446464">"Локацију је подесио GPS"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"Обриши сва обавештења."</string> - <string name="dreams_dock_launcher" msgid="3541196417659166245">"Активирање чувара екрана"</string> </resources> diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml index f8fb054fc855..155d7220cdc4 100644 --- a/packages/SystemUI/res/values-sv/strings.xml +++ b/packages/SystemUI/res/values-sv/strings.xml @@ -138,5 +138,4 @@ <string name="gps_notification_searching_text" msgid="8574247005642736060">"Sökning efter GPS pågår"</string> <string name="gps_notification_found_text" msgid="4619274244146446464">"Platsen har identifierats av GPS"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"Ta bort alla meddelanden."</string> - <string name="dreams_dock_launcher" msgid="3541196417659166245">"Aktivera skärmsläckare"</string> </resources> diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml index 70e29ebe28a0..8d89dffba886 100644 --- a/packages/SystemUI/res/values-sw/strings.xml +++ b/packages/SystemUI/res/values-sw/strings.xml @@ -26,7 +26,7 @@ <string name="status_bar_recent_remove_item_title" msgid="6026395868129852968">"Ondoa kwenye orodha"</string> <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"Taarifa za programu-matumizi"</string> <string name="status_bar_no_recent_apps" msgid="6576392951053994640">"Hakuna programu za sasa"</string> - <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"Ondosha prog za hivi karibuni"</string> + <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"Ondosha programu za hivi karibuni"</string> <!-- String.format failed for translation --> <!-- no translation found for status_bar_accessibility_recent_apps:other (1040784359794890744) --> <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Hakuna arifa"</string> @@ -136,5 +136,4 @@ <string name="gps_notification_searching_text" msgid="8574247005642736060">"Inatafuta GPS"</string> <string name="gps_notification_found_text" msgid="4619274244146446464">"Mahali pamewekwa na GPS"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"Futa arifa zote."</string> - <string name="dreams_dock_launcher" msgid="3541196417659166245">"Amilisha hifadhi ya skrini"</string> </resources> diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml index 3f37060d2de7..b6f6671362b9 100644 --- a/packages/SystemUI/res/values-th/strings.xml +++ b/packages/SystemUI/res/values-th/strings.xml @@ -138,5 +138,4 @@ <string name="gps_notification_searching_text" msgid="8574247005642736060">"กำลังค้นหา GPS"</string> <string name="gps_notification_found_text" msgid="4619274244146446464">"ตำแหน่งที่กำหนดโดย GPS"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"ล้างการแจ้งเตือนทั้งหมด"</string> - <string name="dreams_dock_launcher" msgid="3541196417659166245">"เปิดโปรแกรมรักษาหน้าจอ"</string> </resources> diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml index 807d79750372..ff6243924118 100644 --- a/packages/SystemUI/res/values-tl/strings.xml +++ b/packages/SystemUI/res/values-tl/strings.xml @@ -138,5 +138,4 @@ <string name="gps_notification_searching_text" msgid="8574247005642736060">"Naghahanap ng GPS"</string> <string name="gps_notification_found_text" msgid="4619274244146446464">"Lokasyong itinatakda ng GPS"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"I-clear ang lahat ng notification."</string> - <string name="dreams_dock_launcher" msgid="3541196417659166245">"I-activate ang screen saver"</string> </resources> diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml index 83567ae52450..accf8785d381 100644 --- a/packages/SystemUI/res/values-tr/strings.xml +++ b/packages/SystemUI/res/values-tr/strings.xml @@ -138,5 +138,4 @@ <string name="gps_notification_searching_text" msgid="8574247005642736060">"GPS aranıyor"</string> <string name="gps_notification_found_text" msgid="4619274244146446464">"Konum GPS ile belirlendi"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"Tüm bildirimleri temizle"</string> - <string name="dreams_dock_launcher" msgid="3541196417659166245">"Ekran koruyucuyu etkinleştir"</string> </resources> diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml index bec231a11131..2d901ec5fc9f 100644 --- a/packages/SystemUI/res/values-uk/strings.xml +++ b/packages/SystemUI/res/values-uk/strings.xml @@ -138,5 +138,4 @@ <string name="gps_notification_searching_text" msgid="8574247005642736060">"Виконується пошук GPS-сигналу"</string> <string name="gps_notification_found_text" msgid="4619274244146446464">"Місцезнаходження встановлено за допомогою GPS"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"Очистити всі сповіщення."</string> - <string name="dreams_dock_launcher" msgid="3541196417659166245">"Активувати заставку"</string> </resources> diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml index 9cf90d2983a1..62b5eba86d71 100644 --- a/packages/SystemUI/res/values-vi/strings.xml +++ b/packages/SystemUI/res/values-vi/strings.xml @@ -20,7 +20,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="7164937344850004466">"Giao diện người dùng hệ thống"</string> - <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Xoá"</string> + <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Xóa"</string> <string name="status_bar_do_not_disturb_button" msgid="5812628897510997853">"Không làm phiền"</string> <string name="status_bar_please_disturb_button" msgid="3345398298841572813">"Hiển thị thông báo"</string> <string name="status_bar_recent_remove_item_title" msgid="6026395868129852968">"Xóa khỏi danh sách"</string> @@ -138,5 +138,4 @@ <string name="gps_notification_searching_text" msgid="8574247005642736060">"Đang tìm kiếm GPS"</string> <string name="gps_notification_found_text" msgid="4619274244146446464">"Vị trí đặt bởi GPS"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"Xóa tất cả thông báo."</string> - <string name="dreams_dock_launcher" msgid="3541196417659166245">"Kích hoạt trình bảo vệ màn hình"</string> </resources> diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml index 7e0e3c4dbd9b..58cae0d59354 100644 --- a/packages/SystemUI/res/values-zh-rCN/strings.xml +++ b/packages/SystemUI/res/values-zh-rCN/strings.xml @@ -140,5 +140,4 @@ <string name="gps_notification_searching_text" msgid="8574247005642736060">"正在搜索 GPS"</string> <string name="gps_notification_found_text" msgid="4619274244146446464">"已通过 GPS 确定位置"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"清除所有通知。"</string> - <string name="dreams_dock_launcher" msgid="3541196417659166245">"激活屏幕保护程序"</string> </resources> diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml index 614f14371cf8..e8a85b8eda30 100644 --- a/packages/SystemUI/res/values-zh-rTW/strings.xml +++ b/packages/SystemUI/res/values-zh-rTW/strings.xml @@ -140,5 +140,4 @@ <string name="gps_notification_searching_text" msgid="8574247005642736060">"正在搜尋 GPS"</string> <string name="gps_notification_found_text" msgid="4619274244146446464">"GPS 已定位"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"清除所有通知。"</string> - <string name="dreams_dock_launcher" msgid="3541196417659166245">"啟用螢幕保護程式"</string> </resources> diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml index 52a44a351a5c..614d599089af 100644 --- a/packages/SystemUI/res/values-zu/strings.xml +++ b/packages/SystemUI/res/values-zu/strings.xml @@ -68,7 +68,7 @@ <string name="screenshot_saved_title" msgid="6461865960961414961">"Umfanekiso weskrini uqoshiwe"</string> <string name="screenshot_saved_text" msgid="1152839647677558815">"Thinta ukubona imifanekiso yakho yeskrini"</string> <string name="screenshot_failed_title" msgid="705781116746922771">"Yehlulekile ukulondoloza umfanekiso weskrini."</string> - <string name="screenshot_failed_text" msgid="8134011269572415402">"Ayikwazanga ukulondoloza isithombe-skrini. Ukugcina kwangaphandle kungenzeka kuyasetshenziswa."</string> + <string name="screenshot_failed_text" msgid="8134011269572415402">"Ayikwazanga ukulondoloza isithombe-skrini. Isitoreji sangaphandle kungenzeka kuyasetshenziswa."</string> <string name="usb_preference_title" msgid="6551050377388882787">"Okukhethwa kokudluliswa kwefayela ye-USB"</string> <string name="use_mtp_button_title" msgid="4333504413563023626">"Lengisa njengesidlali semediya (MTP)"</string> <string name="use_ptp_button_title" msgid="7517127540301625751">"Lengisa ikhamera (PTP)"</string> @@ -138,5 +138,4 @@ <string name="gps_notification_searching_text" msgid="8574247005642736060">"Isesha i-GPS"</string> <string name="gps_notification_found_text" msgid="4619274244146446464">"Indawo ihlelwe i-GPS"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"Susa zonke izaziso."</string> - <string name="dreams_dock_launcher" msgid="3541196417659166245">"Yenza ukuthi iskrini seyiva sisebenze"</string> </resources> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index fc81f8ef6dd7..2c1473b22a41 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -362,7 +362,4 @@ <!-- Content description of the clear button in the notification panel for accessibility (not shown on the screen). [CHAR LIMIT=NONE] --> <string name="accessibility_clear_all">Clear all notifications.</string> - - <!-- Description of the desk dock action that invokes the Android Dreams screen saver feature --> - <string name="dreams_dock_launcher">Activate screen saver</string> </resources> diff --git a/packages/SystemUI/src/com/android/systemui/DreamsDockLauncher.java b/packages/SystemUI/src/com/android/systemui/DreamsDockLauncher.java deleted file mode 100644 index 00352969d743..000000000000 --- a/packages/SystemUI/src/com/android/systemui/DreamsDockLauncher.java +++ /dev/null @@ -1,67 +0,0 @@ -package com.android.systemui; - -import android.app.Activity; -import android.content.BroadcastReceiver; -import android.content.ComponentName; -import android.content.ContentResolver; -import android.content.Context; -import android.content.Intent; -import android.os.Bundle; -import android.provider.Settings; -import android.util.Slog; - -public class DreamsDockLauncher extends Activity { - private static final String TAG = "DreamsDockLauncher"; - - // Launch the screen saver if started as an activity. - @Override - protected void onCreate (Bundle icicle) { - super.onCreate(icicle); - launchDream(this); - finish(); - } - - private static void launchDream(Context context) { - try { - String component = Settings.Secure.getString( - context.getContentResolver(), Settings.Secure.DREAM_COMPONENT); - if (component == null) { - component = context.getResources().getString( - com.android.internal.R.string.config_defaultDreamComponent); - } - if (component != null) { - ComponentName cn = ComponentName.unflattenFromString(component); - Intent zzz = new Intent(Intent.ACTION_MAIN) - .setComponent(cn) - .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK - | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS - | Intent.FLAG_ACTIVITY_NO_USER_ACTION - ); - Slog.v(TAG, "Starting screen saver on dock event: " + component); - context.startActivity(zzz); - } else { - Slog.e(TAG, "Couldn't start screen saver: none selected"); - } - } catch (android.content.ActivityNotFoundException exc) { - // no screensaver? give up - Slog.e(TAG, "Couldn't start screen saver: none installed"); - } - } - - // Trap low-level dock events and launch the screensaver. - public static class DockEventReceiver extends BroadcastReceiver { - @Override - public void onReceive(Context context, Intent intent) { - if (Intent.ACTION_DOCK_EVENT.equals(intent.getAction())) { - Bundle extras = intent.getExtras(); - int state = extras - .getInt(Intent.EXTRA_DOCK_STATE, Intent.EXTRA_DOCK_STATE_UNDOCKED); - if (state == Intent.EXTRA_DOCK_STATE_DESK - || state == Intent.EXTRA_DOCK_STATE_LE_DESK - || state == Intent.EXTRA_DOCK_STATE_HE_DESK) { - launchDream(context); - } - } - } - } -} diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java index ad37603f4a07..2232995c5c64 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java @@ -34,15 +34,14 @@ import android.graphics.Canvas; import android.graphics.Matrix; import android.graphics.PixelFormat; import android.graphics.PointF; +import android.hardware.CameraSound; import android.net.Uri; import android.os.AsyncTask; import android.os.Environment; import android.os.Process; -import android.os.ServiceManager; import android.provider.MediaStore; import android.util.DisplayMetrics; import android.view.Display; -import android.view.IWindowManager; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.Surface; @@ -50,7 +49,6 @@ import android.view.View; import android.view.ViewGroup; import android.view.WindowManager; import android.view.animation.Interpolator; -import android.widget.FrameLayout; import android.widget.ImageView; import com.android.systemui.R; @@ -77,7 +75,6 @@ class SaveImageInBackgroundData { */ class SaveImageInBackgroundTask extends AsyncTask<SaveImageInBackgroundData, Void, SaveImageInBackgroundData> { - private static final String TAG = "SaveImageInBackgroundTask"; private static final String SCREENSHOTS_DIR_NAME = "Screenshots"; private static final String SCREENSHOT_FILE_NAME_TEMPLATE = "Screenshot_%s.png"; private static final String SCREENSHOT_FILE_PATH_TEMPLATE = "%s/%s/%s"; @@ -85,11 +82,8 @@ class SaveImageInBackgroundTask extends AsyncTask<SaveImageInBackgroundData, Voi private int mNotificationId; private NotificationManager mNotificationManager; private Notification.Builder mNotificationBuilder; - private Intent mLaunchIntent; - private String mImageDir; private String mImageFileName; private String mImageFilePath; - private String mImageDate; private long mImageTime; // WORKAROUND: We want the same notification across screenshots that we update so that we don't @@ -105,11 +99,11 @@ class SaveImageInBackgroundTask extends AsyncTask<SaveImageInBackgroundData, Voi // Prepare all the output metadata mImageTime = System.currentTimeMillis(); - mImageDate = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss").format(new Date(mImageTime)); - mImageDir = Environment.getExternalStoragePublicDirectory( + String imageDate = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss").format(new Date(mImageTime)); + String imageDir = Environment.getExternalStoragePublicDirectory( Environment.DIRECTORY_PICTURES).getAbsolutePath(); - mImageFileName = String.format(SCREENSHOT_FILE_NAME_TEMPLATE, mImageDate); - mImageFilePath = String.format(SCREENSHOT_FILE_PATH_TEMPLATE, mImageDir, + mImageFileName = String.format(SCREENSHOT_FILE_NAME_TEMPLATE, imageDate); + mImageFilePath = String.format(SCREENSHOT_FILE_PATH_TEMPLATE, imageDir, SCREENSHOTS_DIR_NAME, mImageFileName); // Create the large notification icon @@ -190,7 +184,7 @@ class SaveImageInBackgroundTask extends AsyncTask<SaveImageInBackgroundData, Voi } return params[0]; - }; + } @Override protected void onPostExecute(SaveImageInBackgroundData params) { @@ -202,14 +196,14 @@ class SaveImageInBackgroundTask extends AsyncTask<SaveImageInBackgroundData, Voi Resources r = params.context.getResources(); // Create the intent to show the screenshot in gallery - mLaunchIntent = new Intent(Intent.ACTION_VIEW); - mLaunchIntent.setDataAndType(params.imageUri, "image/png"); - mLaunchIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + Intent launchIntent = new Intent(Intent.ACTION_VIEW); + launchIntent.setDataAndType(params.imageUri, "image/png"); + launchIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); mNotificationBuilder .setContentTitle(r.getString(R.string.screenshot_saved_title)) .setContentText(r.getString(R.string.screenshot_saved_text)) - .setContentIntent(PendingIntent.getActivity(params.context, 0, mLaunchIntent, 0)) + .setContentIntent(PendingIntent.getActivity(params.context, 0, launchIntent, 0)) .setWhen(System.currentTimeMillis()) .setAutoCancel(true); @@ -218,7 +212,7 @@ class SaveImageInBackgroundTask extends AsyncTask<SaveImageInBackgroundData, Voi mNotificationManager.notify(mNotificationId, n); } params.finisher.run(); - }; + } } /** @@ -228,7 +222,6 @@ class SaveImageInBackgroundTask extends AsyncTask<SaveImageInBackgroundData, Voi * type of gallery? */ class GlobalScreenshot { - private static final String TAG = "GlobalScreenshot"; private static final int SCREENSHOT_NOTIFICATION_ID = 789; private static final int SCREENSHOT_FLASH_TO_PEAK_DURATION = 130; private static final int SCREENSHOT_DROP_IN_DURATION = 430; @@ -244,8 +237,6 @@ class GlobalScreenshot { private static final float SCREENSHOT_DROP_OUT_MIN_SCALE_OFFSET = 0f; private Context mContext; - private LayoutInflater mLayoutInflater; - private IWindowManager mIWindowManager; private WindowManager mWindowManager; private WindowManager.LayoutParams mWindowLayoutParams; private NotificationManager mNotificationManager; @@ -256,7 +247,6 @@ class GlobalScreenshot { private Bitmap mScreenBitmap; private View mScreenshotLayout; private ImageView mBackgroundView; - private FrameLayout mScreenshotContainerView; private ImageView mScreenshotView; private ImageView mScreenshotFlash; @@ -266,6 +256,8 @@ class GlobalScreenshot { private float mBgPadding; private float mBgPaddingScale; + private CameraSound mCameraSound; + /** * @param context everything needs a context :( @@ -273,14 +265,13 @@ class GlobalScreenshot { public GlobalScreenshot(Context context) { Resources r = context.getResources(); mContext = context; - mLayoutInflater = (LayoutInflater) + LayoutInflater layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); // Inflate the screenshot layout mDisplayMatrix = new Matrix(); - mScreenshotLayout = mLayoutInflater.inflate(R.layout.global_screenshot, null); + mScreenshotLayout = layoutInflater.inflate(R.layout.global_screenshot, null); mBackgroundView = (ImageView) mScreenshotLayout.findViewById(R.id.global_screenshot_background); - mScreenshotContainerView = (FrameLayout) mScreenshotLayout.findViewById(R.id.global_screenshot_container); mScreenshotView = (ImageView) mScreenshotLayout.findViewById(R.id.global_screenshot); mScreenshotFlash = (ImageView) mScreenshotLayout.findViewById(R.id.global_screenshot_flash); mScreenshotLayout.setFocusable(true); @@ -293,8 +284,6 @@ class GlobalScreenshot { }); // Setup the window that we are going to use - mIWindowManager = IWindowManager.Stub.asInterface( - ServiceManager.getService(Context.WINDOW_SERVICE)); mWindowLayoutParams = new WindowManager.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, 0, 0, WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY, @@ -318,6 +307,9 @@ class GlobalScreenshot { // Scale has to account for both sides of the bg mBgPadding = (float) r.getDimensionPixelSize(R.dimen.global_screenshot_bg_padding); mBgPaddingScale = mBgPadding / mDisplayMetrics.widthPixels; + + // Setup the Camera shutter sound + mCameraSound = new CameraSound(); } /** @@ -428,8 +420,11 @@ class GlobalScreenshot { mScreenshotLayout.post(new Runnable() { @Override public void run() { - mScreenshotContainerView.setLayerType(View.LAYER_TYPE_HARDWARE, null); - mScreenshotContainerView.buildLayer(); + // Play the shutter sound to notify that we've taken a screenshot + mCameraSound.playSound(CameraSound.SHUTTER_CLICK); + + mScreenshotView.setLayerType(View.LAYER_TYPE_HARDWARE, null); + mScreenshotView.buildLayer(); mScreenshotAnimation.start(); } }); @@ -463,20 +458,16 @@ class GlobalScreenshot { anim.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationStart(Animator animation) { - mBackgroundView.setFastAlpha(0f); + mBackgroundView.setAlpha(0f); mBackgroundView.setVisibility(View.VISIBLE); - mBackgroundView.fastInvalidate(); - mScreenshotContainerView.setFastAlpha(0f); - mScreenshotContainerView.setFastTranslationX(0f); - mScreenshotContainerView.setFastTranslationY(0f); - mScreenshotContainerView.setFastScaleX(SCREENSHOT_SCALE + mBgPaddingScale); - mScreenshotContainerView.setFastScaleY(SCREENSHOT_SCALE + mBgPaddingScale); - mScreenshotContainerView.setVisibility(View.VISIBLE); - mScreenshotContainerView.fastInvalidate(); - mScreenshotFlash.setFastAlpha(0f); + mScreenshotView.setAlpha(0f); + mScreenshotView.setTranslationX(0f); + mScreenshotView.setTranslationY(0f); + mScreenshotView.setScaleX(SCREENSHOT_SCALE + mBgPaddingScale); + mScreenshotView.setScaleY(SCREENSHOT_SCALE + mBgPaddingScale); + mScreenshotView.setVisibility(View.VISIBLE); + mScreenshotFlash.setAlpha(0f); mScreenshotFlash.setVisibility(View.VISIBLE); - mScreenshotFlash.fastInvalidate(); - mScreenshotLayout.invalidate(); } @Override public void onAnimationEnd(android.animation.Animator animation) { @@ -486,19 +477,15 @@ class GlobalScreenshot { anim.addUpdateListener(new AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { - float t = ((Float) animation.getAnimatedValue()).floatValue(); + float t = (Float) animation.getAnimatedValue(); float scaleT = (SCREENSHOT_SCALE + mBgPaddingScale) - - (float) scaleInterpolator.getInterpolation(t) + - scaleInterpolator.getInterpolation(t) * (SCREENSHOT_SCALE - SCREENSHOT_DROP_IN_MIN_SCALE); - mBackgroundView.setFastAlpha(scaleInterpolator.getInterpolation(t) * BACKGROUND_ALPHA); - mBackgroundView.fastInvalidate(); - mScreenshotContainerView.setFastAlpha(t); - mScreenshotContainerView.setFastScaleX(scaleT); - mScreenshotContainerView.setFastScaleY(scaleT); - mScreenshotContainerView.fastInvalidate(); - mScreenshotFlash.setFastAlpha(flashAlphaInterpolator.getInterpolation(t)); - mScreenshotFlash.fastInvalidate(); - mScreenshotLayout.invalidate(); + mBackgroundView.setAlpha(scaleInterpolator.getInterpolation(t) * BACKGROUND_ALPHA); + mScreenshotView.setAlpha(t); + mScreenshotView.setScaleX(scaleT); + mScreenshotView.setScaleY(scaleT); + mScreenshotFlash.setAlpha(flashAlphaInterpolator.getInterpolation(t)); } }); return anim; @@ -511,8 +498,8 @@ class GlobalScreenshot { @Override public void onAnimationEnd(Animator animation) { mBackgroundView.setVisibility(View.GONE); - mScreenshotContainerView.setVisibility(View.GONE); - mScreenshotContainerView.setLayerType(View.LAYER_TYPE_NONE, null); + mScreenshotView.setVisibility(View.GONE); + mScreenshotView.setLayerType(View.LAYER_TYPE_NONE, null); } }); @@ -522,17 +509,13 @@ class GlobalScreenshot { anim.addUpdateListener(new AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { - float t = ((Float) animation.getAnimatedValue()).floatValue(); + float t = (Float) animation.getAnimatedValue(); float scaleT = (SCREENSHOT_DROP_IN_MIN_SCALE + mBgPaddingScale) - - (float) t * (SCREENSHOT_DROP_IN_MIN_SCALE - - SCREENSHOT_FAST_DROP_OUT_MIN_SCALE); - mBackgroundView.setFastAlpha((1f - t) * BACKGROUND_ALPHA); - mBackgroundView.fastInvalidate(); - mScreenshotContainerView.setFastAlpha(1f - t); - mScreenshotContainerView.setFastScaleX(scaleT); - mScreenshotContainerView.setFastScaleY(scaleT); - mScreenshotContainerView.fastInvalidate(); - mScreenshotLayout.invalidate(); + - t * (SCREENSHOT_DROP_IN_MIN_SCALE - SCREENSHOT_FAST_DROP_OUT_MIN_SCALE); + mBackgroundView.setAlpha((1f - t) * BACKGROUND_ALPHA); + mScreenshotView.setAlpha(1f - t); + mScreenshotView.setScaleX(scaleT); + mScreenshotView.setScaleY(scaleT); } }); } else { @@ -563,19 +546,16 @@ class GlobalScreenshot { anim.addUpdateListener(new AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { - float t = ((Float) animation.getAnimatedValue()).floatValue(); + float t = (Float) animation.getAnimatedValue(); float scaleT = (SCREENSHOT_DROP_IN_MIN_SCALE + mBgPaddingScale) - - (float) scaleInterpolator.getInterpolation(t) + - scaleInterpolator.getInterpolation(t) * (SCREENSHOT_DROP_IN_MIN_SCALE - SCREENSHOT_DROP_OUT_MIN_SCALE); - mBackgroundView.setFastAlpha((1f - t) * BACKGROUND_ALPHA); - mBackgroundView.fastInvalidate(); - mScreenshotContainerView.setFastAlpha(1f - scaleInterpolator.getInterpolation(t)); - mScreenshotContainerView.setFastScaleX(scaleT); - mScreenshotContainerView.setFastScaleY(scaleT); - mScreenshotContainerView.setFastTranslationX(t * finalPos.x); - mScreenshotContainerView.setFastTranslationY(t * finalPos.y); - mScreenshotContainerView.fastInvalidate(); - mScreenshotLayout.invalidate(); + mBackgroundView.setAlpha((1f - t) * BACKGROUND_ALPHA); + mScreenshotView.setAlpha(1f - scaleInterpolator.getInterpolation(t)); + mScreenshotView.setScaleX(scaleT); + mScreenshotView.setScaleY(scaleT); + mScreenshotView.setTranslationX(t * finalPos.x); + mScreenshotView.setTranslationY(t * finalPos.y); } }); } 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 694da2088354..97a18555e432 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java @@ -20,6 +20,7 @@ import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.content.Context; import android.content.res.Resources; +import android.graphics.Rect; import android.os.ServiceManager; import android.util.AttributeSet; import android.util.Slog; @@ -32,6 +33,10 @@ import android.view.Surface; import android.view.WindowManager; import android.widget.LinearLayout; +import java.io.FileDescriptor; +import java.io.PrintWriter; +import java.lang.StringBuilder; + import com.android.internal.statusbar.IStatusBarService; import com.android.systemui.R; @@ -237,4 +242,79 @@ public class NavigationBarView extends LinearLayout { Slog.d(TAG, "reorient(): rot=" + mDisplay.getRotation()); } } + + private String getResourceName(int resId) { + if (resId != 0) { + final android.content.res.Resources res = mContext.getResources(); + try { + return res.getResourceName(resId); + } catch (android.content.res.Resources.NotFoundException ex) { + return "(unknown)"; + } + } else { + return "(null)"; + } + } + + private static String visibilityToString(int vis) { + switch (vis) { + case View.INVISIBLE: + return "INVISIBLE"; + case View.GONE: + return "GONE"; + default: + return "VISIBLE"; + } + } + + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + pw.println("NavigationBarView {"); + final Rect r = new Rect(); + + pw.println(String.format(" this: " + PhoneStatusBar.viewInfo(this) + + " " + visibilityToString(getVisibility()))); + + getWindowVisibleDisplayFrame(r); + final boolean offscreen = r.right > mDisplay.getRawWidth() + || r.bottom > mDisplay.getRawHeight(); + pw.println(" window: " + + r.toShortString() + + " " + visibilityToString(getWindowVisibility()) + + (offscreen ? " OFFSCREEN!" : "")); + + pw.println(String.format(" mCurrentView: id=%s (%dx%d) %s", + getResourceName(mCurrentView.getId()), + mCurrentView.getWidth(), mCurrentView.getHeight(), + visibilityToString(mCurrentView.getVisibility()))); + + pw.println(String.format(" disabled=0x%08x vertical=%s hidden=%s low=%s menu=%s", + mDisabledFlags, + mVertical ? "true" : "false", + mHidden ? "true" : "false", + mLowProfile ? "true" : "false", + mShowMenu ? "true" : "false")); + + final View back = getBackButton(); + final View home = getHomeButton(); + final View recent = getRecentsButton(); + final View menu = getMenuButton(); + + pw.println(" back: " + + PhoneStatusBar.viewInfo(back) + + " " + visibilityToString(back.getVisibility()) + ); + pw.println(" home: " + + PhoneStatusBar.viewInfo(home) + + " " + visibilityToString(home.getVisibility()) + ); + pw.println(" rcnt: " + + PhoneStatusBar.viewInfo(recent) + + " " + visibilityToString(recent.getVisibility()) + ); + pw.println(" menu: " + + PhoneStatusBar.viewInfo(menu) + + " " + visibilityToString(menu.getVisibility()) + ); + pw.println(" }"); + } } 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 f0093d33040a..3c9d12ce2221 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java @@ -136,7 +136,7 @@ public class PhoneStatusBar extends StatusBar { BatteryController mBatteryController; LocationController mLocationController; NetworkController mNetworkController; - + int mNaturalBarHeight = -1; int mIconSize = -1; int mIconHPadding = -1; @@ -168,7 +168,7 @@ public class PhoneStatusBar extends StatusBar { // drag bar CloseDragHandle mCloseView; - + // all notifications NotificationData mNotificationData = new NotificationData(); NotificationRowLayout mPile; @@ -298,7 +298,7 @@ public class PhoneStatusBar extends StatusBar { try { boolean showNav = mWindowManager.hasNavigationBar(); if (showNav) { - mNavigationBarView = + mNavigationBarView = (NavigationBarView) View.inflate(context, R.layout.navigation_bar, null); mNavigationBarView.setDisabledFlags(mDisabled); @@ -352,11 +352,11 @@ public class PhoneStatusBar extends StatusBar { mBatteryController = new BatteryController(mContext); mBatteryController.addIconView((ImageView)sb.findViewById(R.id.battery)); mNetworkController = new NetworkController(mContext); - final SignalClusterView signalCluster = + final SignalClusterView signalCluster = (SignalClusterView)sb.findViewById(R.id.signal_cluster); mNetworkController.addSignalCluster(signalCluster); signalCluster.setNetworkController(mNetworkController); -// final ImageView wimaxRSSI = +// final ImageView wimaxRSSI = // (ImageView)sb.findViewById(R.id.wimax_signal); // if (wimaxRSSI != null) { // mNetworkController.addWimaxIconView(wimaxRSSI); @@ -973,7 +973,7 @@ public class PhoneStatusBar extends StatusBar { } catch (NameNotFoundException ex) { Slog.e(TAG, "Failed looking up ApplicationInfo for " + sbn.pkg, ex); } - if (version > 0 && version < Build.VERSION_CODES.HONEYCOMB) { + if (version > 0 && version < Build.VERSION_CODES.GINGERBREAD) { content.setBackgroundResource(R.drawable.notification_row_legacy_bg); } else { content.setBackgroundResource(R.drawable.notification_row_bg); @@ -1085,8 +1085,8 @@ public class PhoneStatusBar extends StatusBar { } } - if ((diff & (StatusBarManager.DISABLE_HOME - | StatusBarManager.DISABLE_RECENT + if ((diff & (StatusBarManager.DISABLE_HOME + | StatusBarManager.DISABLE_RECENT | StatusBarManager.DISABLE_BACK)) != 0) { // the nav bar will take care of these if (mNavigationBarView != null) mNavigationBarView.setDisabledFlags(state); @@ -1204,7 +1204,7 @@ public class PhoneStatusBar extends StatusBar { public void animateCollapse(boolean excludeRecents) { animateCollapse(excludeRecents, 1.0f); } - + public void animateCollapse(boolean excludeRecents, float velocityMultiplier) { if (SPEW) { Slog.d(TAG, "animateCollapse(): mExpanded=" + mExpanded @@ -1516,8 +1516,8 @@ public class PhoneStatusBar extends StatusBar { } if (CHATTY) { - Slog.d(TAG, String.format("gesture: vraw=(%f,%f) vnorm=(%f,%f) vlinear=%f", - mVelocityTracker.getXVelocity(), + Slog.d(TAG, String.format("gesture: vraw=(%f,%f) vnorm=(%f,%f) vlinear=%f", + mVelocityTracker.getXVelocity(), mVelocityTracker.getYVelocity(), xVel, yVel, vel)); @@ -1735,9 +1735,9 @@ public class PhoneStatusBar extends StatusBar { return anim; } - public String viewInfo(View v) { - return "(" + v.getLeft() + "," + v.getTop() + ")(" + v.getRight() + "," + v.getBottom() - + " " + v.getWidth() + "x" + v.getHeight() + ")"; + public static String viewInfo(View v) { + return "[(" + v.getLeft() + "," + v.getTop() + ")(" + v.getRight() + "," + v.getBottom() + + ") " + v.getWidth() + "x" + v.getHeight() + "]"; } public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { @@ -1768,6 +1768,13 @@ public class PhoneStatusBar extends StatusBar { + " scroll " + mScrollView.getScrollX() + "," + mScrollView.getScrollY()); } + pw.print(" mNavigationBarView="); + if (mNavigationBarView == null) { + pw.println("null"); + } else { + mNavigationBarView.dump(fd, pw, args); + } + if (DUMPTRUCK) { synchronized (mNotificationData) { int N = mNotificationData.size(); @@ -1788,7 +1795,7 @@ public class PhoneStatusBar extends StatusBar { StatusBarIconView ic = (StatusBarIconView) mStatusIcons.getChildAt(i); pw.println(" [" + i + "] icon=" + ic); } - + if (false) { pw.println("see the logcat for a dump of the views we have created."); // must happen on ui thread @@ -1963,10 +1970,10 @@ public class PhoneStatusBar extends StatusBar { - (mTrackingParams.height-closePos) - contentsBottom; if (SPEW) { - Slog.d(PhoneStatusBar.TAG, + Slog.d(PhoneStatusBar.TAG, "pos=" + pos + " trackingHeight=" + mTrackingView.getHeight() + - " (trackingParams.height - closePos)=" + + " (trackingParams.height - closePos)=" + (mTrackingParams.height - closePos) + " contentsBottom=" + contentsBottom); } @@ -2041,7 +2048,7 @@ public class PhoneStatusBar extends StatusBar { mExpandedDialog.getWindow().setAttributes(mExpandedParams); } if (DEBUG) { - Slog.d(TAG, "updateExpandedSize: height=" + mExpandedParams.height + " " + + Slog.d(TAG, "updateExpandedSize: height=" + mExpandedParams.height + " " + (mExpandedVisible ? "VISIBLE":"INVISIBLE")); } } @@ -2181,6 +2188,11 @@ public class PhoneStatusBar extends StatusBar { private View.OnClickListener mSettingsButtonListener = new View.OnClickListener() { public void onClick(View v) { + try { + // Dismiss the lock screen when Settings starts. + ActivityManagerNative.getDefault().dismissKeyguardOnNextActivity(); + } catch (RemoteException e) { + } v.getContext().startActivity(new Intent(Settings.ACTION_SETTINGS) .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)); animateCollapse(); @@ -2230,7 +2242,7 @@ public class PhoneStatusBar extends StatusBar { loadDimens(); } - + protected void loadDimens() { final Resources res = mContext.getResources(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java index 903a300ad39f..603808ec830c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java @@ -36,7 +36,7 @@ public class BluetoothController extends BroadcastReceiver { private int mIconId = R.drawable.stat_sys_data_bluetooth; private int mContentDescriptionId = 0; - private boolean mEnabled; + private boolean mEnabled = false; public BluetoothController(Context context) { mContext = context; @@ -47,8 +47,10 @@ public class BluetoothController extends BroadcastReceiver { context.registerReceiver(this, filter); final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); - handleAdapterStateChange(adapter.getState()); - handleConnectionStateChange(adapter.getConnectionState()); + if (adapter != null) { + handleAdapterStateChange(adapter.getState()); + handleConnectionStateChange(adapter.getConnectionState()); + } refreshViews(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CompatModeButton.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CompatModeButton.java index 7fbf7344a25b..2d951c25f58b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CompatModeButton.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CompatModeButton.java @@ -49,6 +49,10 @@ public class CompatModeButton extends ImageView { public void refresh() { int mode = mAM.getFrontActivityScreenCompatMode(); + if (mode == ActivityManager.COMPAT_MODE_UNKNOWN) { + // If in an unknown state, don't change. + return; + } final boolean vis = (mode != ActivityManager.COMPAT_MODE_NEVER && mode != ActivityManager.COMPAT_MODE_ALWAYS); if (DEBUG) Slog.d(TAG, "compat mode is " + mode + "; icon will " + (vis ? "show" : "hide")); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java index 55a5b0ac3136..135a04c1a6cb 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java @@ -898,7 +898,7 @@ public class NetworkController extends BroadcastReceiver { combinedSignalIconId = mDataSignalIconId; // set by updateDataIcon() mContentDescriptionCombinedSignal = mContentDescriptionDataType; } - + if (mWifiConnected) { if (mWifiSsid == null) { label = context.getString(R.string.status_bar_settings_signal_meter_wifi_nossid); @@ -932,19 +932,23 @@ public class NetworkController extends BroadcastReceiver { mContentDescriptionCombinedSignal = mContext.getString( R.string.accessibility_bluetooth_tether); } - + if (mAirplaneMode && (mServiceState == null || (!hasService() && !mServiceState.isEmergencyOnly()))) { // Only display the flight-mode icon if not in "emergency calls only" mode. - label = context.getString(R.string.status_bar_settings_signal_meter_disconnected); - mContentDescriptionCombinedSignal = mContentDescriptionPhoneSignal - = mContext.getString(R.string.accessibility_airplane_mode); - + // look again; your radios are now airplanes + mContentDescriptionPhoneSignal = mContext.getString( + R.string.accessibility_airplane_mode); mPhoneSignalIconId = mDataSignalIconId = R.drawable.stat_sys_signal_flightmode; mDataTypeIconId = 0; - combinedSignalIconId = mDataSignalIconId; + // combined values from connected wifi take precedence over airplane mode + if (!mWifiConnected) { + label = context.getString(R.string.status_bar_settings_signal_meter_disconnected); + mContentDescriptionCombinedSignal = mContentDescriptionPhoneSignal; + combinedSignalIconId = mDataSignalIconId; + } } else if (!mDataConnected && !mWifiConnected && !mBluetoothTethered && !mWimaxConnected) { // pretty much totally disconnected diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java index 01406bc2bd3e..05ad79351d18 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java @@ -168,7 +168,6 @@ public class TabletStatusBar extends StatusBar implements NetworkController mNetworkController; ViewGroup mBarContents; - LayoutTransition mBarContentsLayoutTransition; // hide system chrome ("lights out") support View mShadow; @@ -461,19 +460,6 @@ public class TabletStatusBar extends StatusBar implements } mBarContents = (ViewGroup) sb.findViewById(R.id.bar_contents); - // layout transitions for the status bar's contents - mBarContentsLayoutTransition = new LayoutTransition(); - // add/removal will fade as normal - mBarContentsLayoutTransition.setAnimator(LayoutTransition.APPEARING, - ObjectAnimator.ofFloat(null, "alpha", 0f, 1f)); - mBarContentsLayoutTransition.setAnimator(LayoutTransition.DISAPPEARING, - ObjectAnimator.ofFloat(null, "alpha", 1f, 0f)); - // no animations for siblings on change: just jump into place please - mBarContentsLayoutTransition.setAnimator(LayoutTransition.CHANGE_APPEARING, null); - mBarContentsLayoutTransition.setAnimator(LayoutTransition.CHANGE_DISAPPEARING, null); - // quick like bunny - mBarContentsLayoutTransition.setDuration(250 * (DEBUG?10:1)); - mBarContents.setLayoutTransition(mBarContentsLayoutTransition); // the whole right-hand side of the bar mNotificationArea = sb.findViewById(R.id.notificationArea); @@ -522,7 +508,23 @@ public class TabletStatusBar extends StatusBar implements mMenuButton = mNavigationArea.findViewById(R.id.menu); mRecentButton = mNavigationArea.findViewById(R.id.recent_apps); mRecentButton.setOnClickListener(mOnClickListener); - mNavigationArea.setLayoutTransition(mBarContentsLayoutTransition); + + LayoutTransition lt = new LayoutTransition(); + lt.setDuration(250); + // don't wait for these transitions; we just want icons to fade in/out, not move around + lt.setDuration(LayoutTransition.CHANGE_APPEARING, 0); + lt.setDuration(LayoutTransition.CHANGE_DISAPPEARING, 0); + lt.addTransitionListener(new LayoutTransition.TransitionListener() { + public void endTransition(LayoutTransition transition, ViewGroup container, + View view, int transitionType) { + // ensure the menu button doesn't stick around on the status bar after it's been + // removed + mBarContents.invalidate(); + } + public void startTransition(LayoutTransition transition, ViewGroup container, + View view, int transitionType) {} + }); + mNavigationArea.setLayoutTransition(lt); // no multi-touch on the nav buttons mNavigationArea.setMotionEventSplittingEnabled(false); @@ -534,6 +536,7 @@ public class TabletStatusBar extends StatusBar implements mCompatModeButton = (CompatModeButton) sb.findViewById(R.id.compatModeButton); mCompatModeButton.setOnClickListener(mOnClickListener); + mCompatModeButton.setVisibility(View.GONE); // for redirecting errant bar taps to the IME mFakeSpaceBar = sb.findViewById(R.id.fake_space_bar); @@ -1835,7 +1838,7 @@ public class TabletStatusBar extends StatusBar implements } catch (NameNotFoundException ex) { Slog.e(TAG, "Failed looking up ApplicationInfo for " + sbn.pkg, ex); } - if (version > 0 && version < Build.VERSION_CODES.HONEYCOMB) { + if (version > 0 && version < Build.VERSION_CODES.GINGERBREAD) { content.setBackgroundResource(R.drawable.notification_row_legacy_bg); } else { content.setBackgroundResource(R.drawable.notification_row_bg); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletTicker.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletTicker.java index 6045e31d3ad7..e93a32bc1689 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletTicker.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletTicker.java @@ -73,6 +73,8 @@ public class TabletTicker private StatusBarNotification[] mQueue = new StatusBarNotification[QUEUE_LENGTH]; private int mQueuePos; + private final int mLargeIconHeight; + private TabletStatusBar mBar; private LayoutTransition mLayoutTransition; @@ -81,6 +83,9 @@ public class TabletTicker public TabletTicker(TabletStatusBar bar) { mBar = bar; mContext = bar.getContext(); + final Resources res = mContext.getResources(); + mLargeIconHeight = res.getDimensionPixelSize( + android.R.dimen.notification_large_icon_height); } public void add(IBinder key, StatusBarNotification notification) { @@ -209,8 +214,6 @@ public class TabletTicker final Resources res = mContext.getResources(); final FrameLayout view = new FrameLayout(mContext); final int width = res.getDimensionPixelSize(R.dimen.notification_ticker_width); - final int height = res.getDimensionPixelSize( - android.R.dimen.notification_large_icon_height); int windowFlags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS; @@ -219,7 +222,7 @@ public class TabletTicker } else { windowFlags |= WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE; } - WindowManager.LayoutParams lp = new WindowManager.LayoutParams(width, height, + WindowManager.LayoutParams lp = new WindowManager.LayoutParams(width, mLargeIconHeight, WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL, windowFlags, PixelFormat.TRANSLUCENT); lp.gravity = Gravity.BOTTOM | Gravity.RIGHT; @@ -297,6 +300,16 @@ public class TabletTicker if (n.largeIcon != null) { largeIcon.setImageBitmap(n.largeIcon); largeIcon.setVisibility(View.VISIBLE); + final ViewGroup.LayoutParams lp = largeIcon.getLayoutParams(); + final int statusBarHeight = mBar.getStatusBarHeight(); + if (n.largeIcon.getHeight() <= statusBarHeight) { + // for smallish largeIcons, it looks a little odd to have them floating halfway up + // the ticker, so we vertically center them in the status bar area instead + lp.height = statusBarHeight; + } else { + lp.height = mLargeIconHeight; + } + largeIcon.setLayoutParams(lp); } if (CLICKABLE_TICKER) { diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbStorageActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbStorageActivity.java index 43dfb96b7cea..e61ef8ada9ed 100644 --- a/packages/SystemUI/src/com/android/systemui/usb/UsbStorageActivity.java +++ b/packages/SystemUI/src/com/android/systemui/usb/UsbStorageActivity.java @@ -114,16 +114,11 @@ public class UsbStorageActivity extends Activity thr.start(); mAsyncStorageHandler = new Handler(thr.getLooper()); - requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS); - setProgressBarIndeterminateVisibility(true); - getWindow().addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD); if (Environment.isExternalStorageRemovable()) { getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED); } - setTitle(getString(com.android.internal.R.string.usb_storage_activity_title)); - setContentView(com.android.internal.R.layout.usb_storage_activity); mIcon = (ImageView) findViewById(com.android.internal.R.id.icon); diff --git a/policy/src/com/android/internal/policy/impl/GlobalActions.java b/policy/src/com/android/internal/policy/impl/GlobalActions.java index f040e87b7bae..38c85bb8db2b 100644 --- a/policy/src/com/android/internal/policy/impl/GlobalActions.java +++ b/policy/src/com/android/internal/policy/impl/GlobalActions.java @@ -56,13 +56,15 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac private static final String TAG = "GlobalActions"; + private static final boolean SHOW_SILENT_TOGGLE = true; + private final Context mContext; private final AudioManager mAudioManager; private ArrayList<Action> mItems; private AlertDialog mDialog; - private ToggleAction mSilentModeToggle; + private SilentModeAction mSilentModeAction; private ToggleAction mAirplaneModeOn; private MyAdapter mAdapter; @@ -113,39 +115,7 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac * @return A new dialog. */ private AlertDialog createDialog() { - mSilentModeToggle = new ToggleAction( - R.drawable.ic_audio_vol_mute, - R.drawable.ic_audio_vol, - R.string.global_action_toggle_silent_mode, - R.string.global_action_silent_mode_on_status, - R.string.global_action_silent_mode_off_status) { - - void willCreate() { - mEnabledIconResId = (Settings.System.getInt(mContext.getContentResolver(), - Settings.System.VIBRATE_IN_SILENT, 1) == 1) - ? R.drawable.ic_audio_ring_notif_vibrate - : R.drawable.ic_audio_vol_mute; - } - - void onToggle(boolean on) { - if (on) { - mAudioManager.setRingerMode((Settings.System.getInt(mContext.getContentResolver(), - Settings.System.VIBRATE_IN_SILENT, 1) == 1) - ? AudioManager.RINGER_MODE_VIBRATE - : AudioManager.RINGER_MODE_SILENT); - } else { - mAudioManager.setRingerMode(AudioManager.RINGER_MODE_NORMAL); - } - } - - public boolean showDuringKeyguard() { - return true; - } - - public boolean showBeforeProvisioning() { - return false; - } - }; + mSilentModeAction = new SilentModeAction(mAudioManager, mHandler); mAirplaneModeOn = new ToggleAction( R.drawable.ic_lock_airplane_mode, @@ -187,39 +157,45 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac } }; - mItems = Lists.newArrayList( - // silent mode - mSilentModeToggle, - // next: airplane mode - mAirplaneModeOn, - // last: power off - new SinglePressAction( - com.android.internal.R.drawable.ic_lock_power_off, - R.string.global_action_power_off) { - - public void onPress() { - // shutdown by making sure radio and power are handled accordingly. - ShutdownThread.shutdown(mContext, true); - } - - public boolean showDuringKeyguard() { - return true; - } - - public boolean showBeforeProvisioning() { - return true; - } - }); + mItems = new ArrayList<Action>(); + + // first: power off + mItems.add( + new SinglePressAction( + com.android.internal.R.drawable.ic_lock_power_off, + R.string.global_action_power_off) { + + public void onPress() { + // shutdown by making sure radio and power are handled accordingly. + ShutdownThread.shutdown(mContext, true); + } + + public boolean showDuringKeyguard() { + return true; + } + + public boolean showBeforeProvisioning() { + return true; + } + }); + + // next: airplane mode + mItems.add(mAirplaneModeOn); + + // last: silent mode + if (SHOW_SILENT_TOGGLE) { + mItems.add(mSilentModeAction); + } mAdapter = new MyAdapter(); final AlertDialog.Builder ab = new AlertDialog.Builder(mContext); ab.setAdapter(mAdapter, this) - .setInverseBackgroundForced(true) - .setTitle(R.string.global_actions); + .setInverseBackgroundForced(true); final AlertDialog dialog = ab.create(); + dialog.getListView().setItemsCanFocus(true); dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG); dialog.setOnDismissListener(this); @@ -230,8 +206,6 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac private void prepareDialog() { final boolean silentModeOn = mAudioManager.getRingerMode() != AudioManager.RINGER_MODE_NORMAL; - mSilentModeToggle.updateState( - silentModeOn ? ToggleAction.State.On : ToggleAction.State.Off); mAirplaneModeOn.updateState(mAirplaneState); mAdapter.notifyDataSetChanged(); if (mKeyguardShowing) { @@ -239,20 +213,28 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac } else { mDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG); } + if (SHOW_SILENT_TOGGLE) { + IntentFilter filter = new IntentFilter(AudioManager.RINGER_MODE_CHANGED_ACTION); + mContext.registerReceiver(mRingerModeReceiver, filter); + } } /** {@inheritDoc} */ public void onDismiss(DialogInterface dialog) { + if (SHOW_SILENT_TOGGLE) { + mContext.unregisterReceiver(mRingerModeReceiver); + } } /** {@inheritDoc} */ public void onClick(DialogInterface dialog, int which) { - dialog.dismiss(); + if (!(mAdapter.getItem(which) instanceof SilentModeAction)) { + dialog.dismiss(); + } mAdapter.getItem(which).onPress(); } - /** * The adapter used for the list within the global actions dialog, taking * into account whether the keyguard is showing via @@ -373,9 +355,7 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac public View create( Context context, View convertView, ViewGroup parent, LayoutInflater inflater) { - View v = (convertView != null) ? - convertView : - inflater.inflate(R.layout.global_actions_item, parent, false); + View v = inflater.inflate(R.layout.global_actions_item, parent, false); ImageView icon = (ImageView) v.findViewById(R.id.icon); TextView messageView = (TextView) v.findViewById(R.id.message); @@ -452,27 +432,31 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac LayoutInflater inflater) { willCreate(); - View v = (convertView != null) ? - convertView : - inflater.inflate(R + View v = inflater.inflate(R .layout.global_actions_item, parent, false); ImageView icon = (ImageView) v.findViewById(R.id.icon); TextView messageView = (TextView) v.findViewById(R.id.message); TextView statusView = (TextView) v.findViewById(R.id.status); + final boolean enabled = isEnabled(); - messageView.setText(mMessageResId); + if (messageView != null) { + messageView.setText(mMessageResId); + messageView.setEnabled(enabled); + } boolean on = ((mState == State.On) || (mState == State.TurningOn)); - icon.setImageDrawable(context.getResources().getDrawable( - (on ? mEnabledIconResId : mDisabledIconResid))); - statusView.setText(on ? mEnabledStatusMessageResId : mDisabledStatusMessageResId); - statusView.setVisibility(View.VISIBLE); + if (icon != null) { + icon.setImageDrawable(context.getResources().getDrawable( + (on ? mEnabledIconResId : mDisabledIconResid))); + icon.setEnabled(enabled); + } - final boolean enabled = isEnabled(); - messageView.setEnabled(enabled); - statusView.setEnabled(enabled); - icon.setEnabled(enabled); + if (statusView != null) { + statusView.setText(on ? mEnabledStatusMessageResId : mDisabledStatusMessageResId); + statusView.setVisibility(View.VISIBLE); + statusView.setEnabled(enabled); + } v.setEnabled(enabled); return v; @@ -510,6 +494,70 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac } } + private static class SilentModeAction implements Action, View.OnClickListener { + + private final int[] ITEM_IDS = { R.id.option1, R.id.option2, R.id.option3 }; + + private final AudioManager mAudioManager; + private final Handler mHandler; + + SilentModeAction(AudioManager audioManager, Handler handler) { + mAudioManager = audioManager; + mHandler = handler; + } + + private int ringerModeToIndex(int ringerMode) { + // They just happen to coincide + return ringerMode; + } + + private int indexToRingerMode(int index) { + // They just happen to coincide + return index; + } + + public View create(Context context, View convertView, ViewGroup parent, + LayoutInflater inflater) { + View v = inflater.inflate(R.layout.global_actions_silent_mode, parent, false); + + int selectedIndex = ringerModeToIndex(mAudioManager.getRingerMode()); + for (int i = 0; i < 3; i++) { + View itemView = v.findViewById(ITEM_IDS[i]); + itemView.setSelected(selectedIndex == i); + // Set up click handler + itemView.setTag(i); + itemView.setOnClickListener(this); + } + return v; + } + + public void onPress() { + } + + public boolean showDuringKeyguard() { + return true; + } + + public boolean showBeforeProvisioning() { + return false; + } + + public boolean isEnabled() { + return true; + } + + void willCreate() { + } + + public void onClick(View v) { + if (!(v.getTag() instanceof Integer)) return; + + int index = (Integer) v.getTag(); + mAudioManager.setRingerMode(indexToRingerMode(index)); + mHandler.sendEmptyMessageDelayed(MESSAGE_DISMISS, DIALOG_DISMISS_DELAY); + } + } + private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { public void onReceive(Context context, Intent intent) { String action = intent.getAction(); @@ -541,13 +589,27 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac } }; + private BroadcastReceiver mRingerModeReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (intent.getAction().equals(AudioManager.RINGER_MODE_CHANGED_ACTION)) { + mHandler.sendEmptyMessage(MESSAGE_REFRESH); + } + } + }; + private static final int MESSAGE_DISMISS = 0; + private static final int MESSAGE_REFRESH = 1; + private static final int DIALOG_DISMISS_DELAY = 300; // ms + private Handler mHandler = new Handler() { public void handleMessage(Message msg) { if (msg.what == MESSAGE_DISMISS) { if (mDialog != null) { mDialog.dismiss(); } + } else if (msg.what == MESSAGE_REFRESH) { + mAdapter.notifyDataSetChanged(); } } }; diff --git a/policy/src/com/android/internal/policy/impl/IconUtilities.java b/policy/src/com/android/internal/policy/impl/IconUtilities.java index 4564f904e83e..e997355583a0 100644 --- a/policy/src/com/android/internal/policy/impl/IconUtilities.java +++ b/policy/src/com/android/internal/policy/impl/IconUtilities.java @@ -38,6 +38,8 @@ import android.text.StaticLayout; import android.text.TextPaint; import android.util.DisplayMetrics; import android.util.Log; +import android.util.TypedValue; +import android.view.ContextThemeWrapper; import android.content.res.Resources; import android.content.Context; @@ -74,9 +76,13 @@ final class IconUtilities { mIconTextureWidth = mIconTextureHeight = mIconWidth + (int)(blurPx*2); mBlurPaint.setMaskFilter(new BlurMaskFilter(blurPx, BlurMaskFilter.Blur.NORMAL)); - mGlowColorPressedPaint.setColor(0xffffc300); + + TypedValue value = new TypedValue(); + mGlowColorPressedPaint.setColor(context.getTheme().resolveAttribute( + android.R.attr.colorPressedHighlight, value, true) ? value.data : 0xffffc300); mGlowColorPressedPaint.setMaskFilter(TableMaskFilter.CreateClipTable(0, 30)); - mGlowColorFocusedPaint.setColor(0xffff8e00); + mGlowColorFocusedPaint.setColor(context.getTheme().resolveAttribute( + android.R.attr.colorFocusedHighlight, value, true) ? value.data : 0xffff8e00); mGlowColorFocusedPaint.setMaskFilter(TableMaskFilter.CreateClipTable(0, 30)); ColorMatrix cm = new ColorMatrix(); diff --git a/policy/src/com/android/internal/policy/impl/KeyguardUpdateMonitor.java b/policy/src/com/android/internal/policy/impl/KeyguardUpdateMonitor.java index 84540a150b6c..b4b82aa6fc88 100644 --- a/policy/src/com/android/internal/policy/impl/KeyguardUpdateMonitor.java +++ b/policy/src/com/android/internal/policy/impl/KeyguardUpdateMonitor.java @@ -110,10 +110,14 @@ public class KeyguardUpdateMonitor { * the intent and provide a {@link SimCard.State} result. */ private static class SimArgs { - public final IccCard.State simState; - private SimArgs(Intent intent) { + SimArgs(IccCard.State state) { + simState = state; + } + + static SimArgs fromIntent(Intent intent) { + IccCard.State state; if (!TelephonyIntents.ACTION_SIM_STATE_CHANGED.equals(intent.getAction())) { throw new IllegalArgumentException("only handles intent ACTION_SIM_STATE_CHANGED"); } @@ -124,27 +128,28 @@ public class KeyguardUpdateMonitor { if (IccCard.INTENT_VALUE_ABSENT_ON_PERM_DISABLED.equals( absentReason)) { - this.simState = IccCard.State.PERM_DISABLED; + state = IccCard.State.PERM_DISABLED; } else { - this.simState = IccCard.State.ABSENT; + state = IccCard.State.ABSENT; } } else if (IccCard.INTENT_VALUE_ICC_READY.equals(stateExtra)) { - this.simState = IccCard.State.READY; + state = IccCard.State.READY; } else if (IccCard.INTENT_VALUE_ICC_LOCKED.equals(stateExtra)) { final String lockedReason = intent .getStringExtra(IccCard.INTENT_KEY_LOCKED_REASON); if (IccCard.INTENT_VALUE_LOCKED_ON_PIN.equals(lockedReason)) { - this.simState = IccCard.State.PIN_REQUIRED; + state = IccCard.State.PIN_REQUIRED; } else if (IccCard.INTENT_VALUE_LOCKED_ON_PUK.equals(lockedReason)) { - this.simState = IccCard.State.PUK_REQUIRED; + state = IccCard.State.PUK_REQUIRED; } else { - this.simState = IccCard.State.UNKNOWN; + state = IccCard.State.UNKNOWN; } } else if (IccCard.INTENT_VALUE_LOCKED_NETWORK.equals(stateExtra)) { - this.simState = IccCard.State.NETWORK_LOCKED; + state = IccCard.State.NETWORK_LOCKED; } else { - this.simState = IccCard.State.UNKNOWN; + state = IccCard.State.UNKNOWN; } + return new SimArgs(state); } public String toString() { @@ -279,8 +284,7 @@ public class KeyguardUpdateMonitor { mHandler.sendMessage(msg); } else if (TelephonyIntents.ACTION_SIM_STATE_CHANGED.equals(action)) { mHandler.sendMessage(mHandler.obtainMessage( - MSG_SIM_STATE_CHANGE, - new SimArgs(intent))); + MSG_SIM_STATE_CHANGE, SimArgs.fromIntent(intent))); } else if (AudioManager.RINGER_MODE_CHANGED_ACTION.equals(action)) { mHandler.sendMessage(mHandler.obtainMessage(MSG_RINGER_MODE_CHANGED, intent.getIntExtra(AudioManager.EXTRA_RINGER_MODE, -1), 0)); @@ -571,12 +575,16 @@ public class KeyguardUpdateMonitor { } /** - * Report that the user succesfully entered the sim pin or puk so we + * Report that the user successfully entered the SIM PIN or PUK/SIM PIN so we * have the information earlier than waiting for the intent * broadcast from the telephony code. + * + * NOTE: Because handleSimStateChange() invokes callbacks immediately without going + * through mHandler, this *must* be called from the UI thread. */ public void reportSimUnlocked() { mSimState = IccCard.State.READY; + handleSimStateChange(new SimArgs(mSimState)); } public boolean isKeyguardBypassEnabled() { diff --git a/policy/src/com/android/internal/policy/impl/KeyguardViewBase.java b/policy/src/com/android/internal/policy/impl/KeyguardViewBase.java index 26bd69775876..f204070598d5 100644 --- a/policy/src/com/android/internal/policy/impl/KeyguardViewBase.java +++ b/policy/src/com/android/internal/policy/impl/KeyguardViewBase.java @@ -46,6 +46,10 @@ public abstract class KeyguardViewBase extends FrameLayout { private KeyguardViewCallback mCallback; private AudioManager mAudioManager; private TelephonyManager mTelephonyManager = null; + // Whether the volume keys should be handled by keyguard. If true, then + // they will be handled here for specific media types such as music, otherwise + // the audio service will bring up the volume dialog. + private static final boolean KEYGUARD_MANAGES_VOLUME = true; // This is a faster way to draw the background on devices without hardware acceleration Drawable mBackgroundDrawable = new Drawable() { @@ -203,24 +207,28 @@ public abstract class KeyguardViewBase extends FrameLayout { case KeyEvent.KEYCODE_VOLUME_UP: case KeyEvent.KEYCODE_VOLUME_DOWN: case KeyEvent.KEYCODE_VOLUME_MUTE: { - synchronized (this) { - if (mAudioManager == null) { - mAudioManager = (AudioManager) getContext().getSystemService( - Context.AUDIO_SERVICE); + if (KEYGUARD_MANAGES_VOLUME) { + synchronized (this) { + if (mAudioManager == null) { + mAudioManager = (AudioManager) getContext().getSystemService( + Context.AUDIO_SERVICE); + } } + // Volume buttons should only function for music. + if (mAudioManager.isMusicActive()) { + // TODO: Actually handle MUTE. + mAudioManager.adjustStreamVolume( + AudioManager.STREAM_MUSIC, + keyCode == KeyEvent.KEYCODE_VOLUME_UP + ? AudioManager.ADJUST_RAISE + : AudioManager.ADJUST_LOWER, + 0); + } + // Don't execute default volume behavior + return true; + } else { + return false; } - // Volume buttons should only function for music. - if (mAudioManager.isMusicActive()) { - // TODO: Actually handle MUTE. - mAudioManager.adjustStreamVolume( - AudioManager.STREAM_MUSIC, - keyCode == KeyEvent.KEYCODE_VOLUME_UP - ? AudioManager.ADJUST_RAISE - : AudioManager.ADJUST_LOWER, - 0); - } - // Don't execute default volume behavior - return true; } } } else if (event.getAction() == KeyEvent.ACTION_UP) { diff --git a/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java b/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java index dd3b75d2c7a4..6eff4b6e1c2f 100644 --- a/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java +++ b/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java @@ -558,9 +558,12 @@ public class LockPatternKeyguardView extends KeyguardViewBase implements Handler mScreenOn = false; mForgotPattern = false; mHasOverlay = mUpdateMonitor.getPhoneState() != TelephonyManager.CALL_STATE_IDLE; - if (mMode == Mode.LockScreen) { + + // Emulate activity life-cycle for both lock and unlock screen. + if (mLockScreen != null) { ((KeyguardScreen) mLockScreen).onPause(); - } else { + } + if (mUnlockScreen != null) { ((KeyguardScreen) mUnlockScreen).onPause(); } @@ -651,9 +654,11 @@ public class LockPatternKeyguardView extends KeyguardViewBase implements Handler @Override public void show() { - if (mMode == Mode.LockScreen) { + // Emulate activity life-cycle for both lock and unlock screen. + if (mLockScreen != null) { ((KeyguardScreen) mLockScreen).onResume(); - } else { + } + if (mUnlockScreen != null) { ((KeyguardScreen) mUnlockScreen).onResume(); } diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java index af86ae954794..535f03932921 100644 --- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java +++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java @@ -1816,22 +1816,42 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { @Override public boolean dispatchKeyShortcutEvent(KeyEvent ev) { - // Perform the shortcut (mPreparedPanel can be null since - // global shortcuts (such as search) don't rely on a - // prepared panel or menu). - boolean handled = performPanelShortcut(mPreparedPanel, ev.getKeyCode(), ev, - Menu.FLAG_PERFORM_NO_CLOSE); - if (handled) { - if (mPreparedPanel != null) { - mPreparedPanel.isHandled = true; + // If the panel is already prepared, then perform the shortcut using it. + boolean handled; + if (mPreparedPanel != null) { + handled = performPanelShortcut(mPreparedPanel, ev.getKeyCode(), ev, + Menu.FLAG_PERFORM_NO_CLOSE); + if (handled) { + if (mPreparedPanel != null) { + mPreparedPanel.isHandled = true; + } + return true; } - return true; } // Shortcut not handled by the panel. Dispatch to the view hierarchy. final Callback cb = getCallback(); - return cb != null && !isDestroyed() && mFeatureId < 0 ? cb.dispatchKeyShortcutEvent(ev) - : super.dispatchKeyShortcutEvent(ev); + handled = cb != null && !isDestroyed() && mFeatureId < 0 + ? cb.dispatchKeyShortcutEvent(ev) : super.dispatchKeyShortcutEvent(ev); + if (handled) { + return true; + } + + // If the panel is not prepared, then we may be trying to handle a shortcut key + // combination such as Control+C. Temporarily prepare the panel then mark it + // unprepared again when finished to ensure that the panel will again be prepared + // the next time it is shown for real. + if (mPreparedPanel == null) { + PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, true); + preparePanel(st, ev); + handled = performPanelShortcut(st, ev.getKeyCode(), ev, + Menu.FLAG_PERFORM_NO_CLOSE); + st.isPrepared = false; + if (handled) { + return true; + } + } + return false; } @Override diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java index e00a54c0eab9..7510e04b9625 100755 --- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java @@ -39,7 +39,7 @@ import android.database.ContentObserver; import android.graphics.PixelFormat; import android.graphics.Rect; import android.graphics.RectF; -import android.os.Binder; +import android.os.BatteryManager; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; @@ -68,8 +68,10 @@ import android.util.DisplayMetrics; import android.util.EventLog; import android.util.Log; import android.util.Slog; +import android.util.SparseArray; import android.view.Gravity; import android.view.HapticFeedbackConstants; +import android.view.IApplicationToken; import android.view.IWindowManager; import android.view.InputChannel; import android.view.InputDevice; @@ -226,7 +228,30 @@ public class PhoneWindowManager implements WindowManagerPolicy { // Useful scan codes. private static final int SW_LID = 0x00; private static final int BTN_MOUSE = 0x110; - + + /* Table of Application Launch keys. Maps from key codes to intent categories. + * + * These are special keys that are used to launch particular kinds of applications, + * such as a web browser. HID defines nearly a hundred of them in the Consumer (0x0C) + * usage page. We don't support quite that many yet... + */ + static SparseArray<String> sApplicationLaunchKeyCategories; + static { + sApplicationLaunchKeyCategories = new SparseArray<String>(); + sApplicationLaunchKeyCategories.append( + KeyEvent.KEYCODE_EXPLORER, Intent.CATEGORY_APP_BROWSER); + sApplicationLaunchKeyCategories.append( + KeyEvent.KEYCODE_ENVELOPE, Intent.CATEGORY_APP_EMAIL); + sApplicationLaunchKeyCategories.append( + KeyEvent.KEYCODE_CONTACTS, Intent.CATEGORY_APP_CONTACTS); + sApplicationLaunchKeyCategories.append( + KeyEvent.KEYCODE_CALENDAR, Intent.CATEGORY_APP_CALENDAR); + sApplicationLaunchKeyCategories.append( + KeyEvent.KEYCODE_MUSIC, Intent.CATEGORY_APP_MUSIC); + sApplicationLaunchKeyCategories.append( + KeyEvent.KEYCODE_CALCULATOR, Intent.CATEGORY_APP_CALCULATOR); + } + /** * Lock protecting internal state. Must not call out into window * manager with lock held. (This lock will be acquired in places @@ -273,9 +298,15 @@ public class PhoneWindowManager implements WindowManagerPolicy { GlobalActions mGlobalActions; volatile boolean mPowerKeyHandled; // accessed from input reader and handler thread boolean mPendingPowerKeyUpCanceled; - RecentApplicationsDialog mRecentAppsDialog; Handler mHandler; + static final int RECENT_APPS_BEHAVIOR_SHOW_OR_DISMISS = 0; + static final int RECENT_APPS_BEHAVIOR_EXIT_TOUCH_MODE_AND_SHOW = 1; + static final int RECENT_APPS_BEHAVIOR_DISMISS_AND_SWITCH = 2; + + RecentApplicationsDialog mRecentAppsDialog; + int mRecentAppsDialogHeldModifiers; + private static final int LID_ABSENT = -1; private static final int LID_CLOSED = 0; private static final int LID_OPEN = 1; @@ -315,6 +346,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { // The last window we were told about in focusChanged. WindowState mFocusedWindow; + IApplicationToken mFocusedApp; private final InputHandler mPointerLocationInputHandler = new BaseInputHandler() { @Override @@ -394,10 +426,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { int mLockScreenTimeout; boolean mLockScreenTimerActive; - // visual screen saver support - int mScreenSaverTimeout = 0; - boolean mScreenSaverEnabled = true; - // Behavior of ENDCALL Button. (See Settings.System.END_BUTTON_BEHAVIOR.) int mEndcallBehavior; @@ -460,8 +488,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { Settings.Secure.DEFAULT_INPUT_METHOD), false, this); resolver.registerContentObserver(Settings.System.getUriFor( "fancy_rotation_anim"), false, this); - resolver.registerContentObserver(Settings.Secure.getUriFor( - Settings.Secure.DREAM_TIMEOUT), false, this); updateSettings(); } @@ -673,7 +699,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } if (mLongPressOnHomeBehavior == LONG_PRESS_HOME_RECENT_DIALOG) { - showOrHideRecentAppsDialog(0, true /*dismissIfShown*/); + showOrHideRecentAppsDialog(RECENT_APPS_BEHAVIOR_SHOW_OR_DISMISS); } else if (mLongPressOnHomeBehavior == LONG_PRESS_HOME_RECENT_SYSTEM_UI) { try { mStatusBarService.toggleRecentApps(); @@ -684,10 +710,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { } /** - * Create (if necessary) and launch the recent apps dialog, or hide it if it is - * already shown. + * Create (if necessary) and show or dismiss the recent apps dialog according + * according to the requested behavior. */ - void showOrHideRecentAppsDialog(final int heldModifiers, final boolean dismissIfShown) { + void showOrHideRecentAppsDialog(final int behavior) { mHandler.post(new Runnable() { @Override public void run() { @@ -695,12 +721,33 @@ public class PhoneWindowManager implements WindowManagerPolicy { mRecentAppsDialog = new RecentApplicationsDialog(mContext); } if (mRecentAppsDialog.isShowing()) { - if (dismissIfShown) { - mRecentAppsDialog.dismiss(); + switch (behavior) { + case RECENT_APPS_BEHAVIOR_SHOW_OR_DISMISS: + mRecentAppsDialog.dismiss(); + break; + case RECENT_APPS_BEHAVIOR_DISMISS_AND_SWITCH: + mRecentAppsDialog.dismissAndSwitch(); + break; + case RECENT_APPS_BEHAVIOR_EXIT_TOUCH_MODE_AND_SHOW: + default: + break; } } else { - mRecentAppsDialog.setHeldModifiers(heldModifiers); - mRecentAppsDialog.show(); + switch (behavior) { + case RECENT_APPS_BEHAVIOR_SHOW_OR_DISMISS: + mRecentAppsDialog.show(); + break; + case RECENT_APPS_BEHAVIOR_EXIT_TOUCH_MODE_AND_SHOW: + try { + mWindowManager.setInTouchMode(false); + } catch (RemoteException e) { + } + mRecentAppsDialog.show(); + break; + case RECENT_APPS_BEHAVIOR_DISMISS_AND_SWITCH: + default: + break; + } } } }); @@ -768,6 +815,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { mDockMode = intent.getIntExtra(Intent.EXTRA_DOCK_STATE, Intent.EXTRA_DOCK_STATE_UNDOCKED); } + mVibrator = new Vibrator(); mLongPressVibePattern = getLongIntArray(mContext.getResources(), com.android.internal.R.array.config_longPressVibePattern); @@ -916,10 +964,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { mHasSoftInput = hasSoftInput; updateRotation = true; } - - mScreenSaverTimeout = Settings.Secure.getInt(resolver, - Settings.Secure.DREAM_TIMEOUT, 0); - updateScreenSaverTimeoutLocked(); } if (updateRotation) { updateRotation(true); @@ -1581,7 +1625,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { return 0; } else if (keyCode == KeyEvent.KEYCODE_APP_SWITCH) { if (down && repeatCount == 0) { - showOrHideRecentAppsDialog(0, true /*dismissIfShown*/); + showOrHideRecentAppsDialog(RECENT_APPS_BEHAVIOR_SHOW_OR_DISMISS); } return -1; } @@ -1617,6 +1661,62 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } + // Invoke shortcuts using Meta. + if (down && repeatCount == 0 + && (metaState & KeyEvent.META_META_ON) != 0) { + final KeyCharacterMap kcm = event.getKeyCharacterMap(); + Intent shortcutIntent = mShortcutManager.getIntent(kcm, keyCode, + metaState & ~(KeyEvent.META_META_ON + | KeyEvent.META_META_LEFT_ON | KeyEvent.META_META_RIGHT_ON)); + if (shortcutIntent != null) { + shortcutIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + try { + mContext.startActivity(shortcutIntent); + } catch (ActivityNotFoundException ex) { + Slog.w(TAG, "Dropping shortcut key combination because " + + "the activity to which it is registered was not found: " + + "META+" + KeyEvent.keyCodeToString(keyCode), ex); + } + return -1; + } + } + + // Handle application launch keys. + if (down && repeatCount == 0) { + String category = sApplicationLaunchKeyCategories.get(keyCode); + if (category != null) { + Intent intent = Intent.makeMainSelectorActivity(Intent.ACTION_MAIN, category); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + try { + mContext.startActivity(intent); + } catch (ActivityNotFoundException ex) { + Slog.w(TAG, "Dropping application launch key because " + + "the activity to which it is registered was not found: " + + "keyCode=" + keyCode + ", category=" + category, ex); + } + return -1; + } + } + + // Display task switcher for ALT-TAB or Meta-TAB. + if (down && repeatCount == 0 && keyCode == KeyEvent.KEYCODE_TAB) { + if (mRecentAppsDialogHeldModifiers == 0) { + final int shiftlessModifiers = event.getModifiers() & ~KeyEvent.META_SHIFT_MASK; + if (KeyEvent.metaStateHasModifiers(shiftlessModifiers, KeyEvent.META_ALT_ON) + || KeyEvent.metaStateHasModifiers( + shiftlessModifiers, KeyEvent.META_META_ON)) { + mRecentAppsDialogHeldModifiers = shiftlessModifiers; + showOrHideRecentAppsDialog(RECENT_APPS_BEHAVIOR_EXIT_TOUCH_MODE_AND_SHOW); + return -1; + } + } + } else if (!down && mRecentAppsDialogHeldModifiers != 0 + && (metaState & mRecentAppsDialogHeldModifiers) == 0) { + mRecentAppsDialogHeldModifiers = 0; + showOrHideRecentAppsDialog(RECENT_APPS_BEHAVIOR_DISMISS_AND_SWITCH); + } + + // Let the application handle the key. return 0; } @@ -1638,39 +1738,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { final KeyCharacterMap kcm = event.getKeyCharacterMap(); final int keyCode = event.getKeyCode(); final int metaState = event.getMetaState(); - final boolean initialDown = event.getAction() == KeyEvent.ACTION_DOWN - && event.getRepeatCount() == 0; - - if (initialDown) { - // Invoke shortcuts using Meta as a fallback. - if ((metaState & KeyEvent.META_META_ON) != 0) { - Intent shortcutIntent = mShortcutManager.getIntent(kcm, keyCode, - metaState & ~(KeyEvent.META_META_ON - | KeyEvent.META_META_LEFT_ON | KeyEvent.META_META_RIGHT_ON)); - if (shortcutIntent != null) { - shortcutIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - try { - mContext.startActivity(shortcutIntent); - } catch (ActivityNotFoundException ex) { - Slog.w(TAG, "Dropping shortcut key combination because " - + "the activity to which it is registered was not found: " - + "META+" + KeyEvent.keyCodeToString(keyCode), ex); - } - return null; - } - } - - // Display task switcher for ALT-TAB or Meta-TAB. - if (keyCode == KeyEvent.KEYCODE_TAB) { - final int shiftlessModifiers = event.getModifiers() & ~KeyEvent.META_SHIFT_MASK; - if (KeyEvent.metaStateHasModifiers(shiftlessModifiers, KeyEvent.META_ALT_ON) - || KeyEvent.metaStateHasModifiers( - shiftlessModifiers, KeyEvent.META_META_ON)) { - showOrHideRecentAppsDialog(shiftlessModifiers, false /*dismissIfShown*/); - return null; - } - } - } // Check for fallback actions specified by the key character map. if (getFallbackAction(kcm, keyCode, metaState, mFallbackAction)) { @@ -2965,7 +3032,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { synchronized (mLock) { updateOrientationListenerLp(); updateLockScreenTimeout(); - updateScreenSaverTimeoutLocked(); } } @@ -3012,7 +3078,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { mScreenOnEarly = true; updateOrientationListenerLp(); updateLockScreenTimeout(); - updateScreenSaverTimeoutLocked(); } } @@ -3103,10 +3168,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } final int preferredRotation; - if (mHdmiPlugged) { - // Ignore sensor when plugged into HDMI. - preferredRotation = mHdmiRotation; - } else if (mLidOpen == LID_OPEN && mLidOpenRotation >= 0) { + if (mLidOpen == LID_OPEN && mLidOpenRotation >= 0) { // Ignore sensor when lid switch is open and rotation is forced. preferredRotation = mLidOpenRotation; } else if (mDockMode == Intent.EXTRA_DOCK_STATE_CAR @@ -3125,6 +3187,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { // enable 180 degree rotation while docked. preferredRotation = mDeskDockEnablesAccelerometer ? sensorRotation : mDeskDockRotation; + } else if (mHdmiPlugged) { + // Ignore sensor when plugged into HDMI. + // Note that the dock orientation overrides the HDMI orientation. + preferredRotation = mHdmiRotation; } else if ((mAccelerometerDefault != 0 /* implies not rotation locked */ && (orientation == ActivityInfo.SCREEN_ORIENTATION_USER || orientation == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED)) @@ -3367,6 +3433,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { WindowManager.LayoutParams.FLAG_DIM_BEHIND | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN); mBootMsgDialog.getWindow().setDimAmount(1); + WindowManager.LayoutParams lp = mBootMsgDialog.getWindow().getAttributes(); + lp.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_NOSENSOR; + mBootMsgDialog.getWindow().setAttributes(lp); mBootMsgDialog.setCancelable(false); mBootMsgDialog.show(); } @@ -3407,65 +3476,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { mHandler.postDelayed(mScreenLockTimeout, mLockScreenTimeout); } } - - synchronized (mLock) { - // Only posts messages; holds no additional locks. - updateScreenSaverTimeoutLocked(); - } - } - - Runnable mScreenSaverActivator = new Runnable() { - public void run() { - if (!(mScreenSaverEnabled && mScreenOnEarly)) { - Log.w(TAG, "mScreenSaverActivator ran, but the screensaver should not be showing. Who's driving this thing?"); - return; - } - - if (localLOGV) Log.v(TAG, "mScreenSaverActivator entering dreamland"); - try { - String component = Settings.Secure.getString( - mContext.getContentResolver(), Settings.Secure.DREAM_COMPONENT); - if (component == null) { - component = mContext.getResources().getString(R.string.config_defaultDreamComponent); - } - if (component != null) { - ComponentName cn = ComponentName.unflattenFromString(component); - Intent intent = new Intent(Intent.ACTION_MAIN) - .setComponent(cn) - .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK - | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS - | Intent.FLAG_ACTIVITY_NO_USER_ACTION - ); - mContext.startActivity(intent); - } else { - Log.e(TAG, "Couldn't start screen saver: none selected"); - } - } catch (android.content.ActivityNotFoundException exc) { - // no screensaver? give up - Log.e(TAG, "Couldn't start screen saver: none installed"); - } - } - }; - - // Must call while holding mLock - private void updateScreenSaverTimeoutLocked() { - if (mScreenSaverActivator == null) return; - - mHandler.removeCallbacks(mScreenSaverActivator); - if (mScreenSaverEnabled && mScreenOnEarly && mScreenSaverTimeout > 0) { - if (localLOGV) - Log.v(TAG, "scheduling screensaver for " + mScreenSaverTimeout + "ms from now"); - mHandler.postDelayed(mScreenSaverActivator, mScreenSaverTimeout); - } else { - if (localLOGV) { - if (mScreenSaverTimeout == 0) - Log.v(TAG, "screen saver disabled by user"); - else if (!mScreenOnEarly) - Log.v(TAG, "screen saver disabled while screen off"); - else - Log.v(TAG, "screen saver disabled by wakelock"); - } - } } Runnable mScreenLockTimeout = new Runnable() { @@ -3671,11 +3681,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { } public void screenOnStartedLw() { - // The window manager has just grabbed a wake lock. This is our cue to disable the screen - // saver. - synchronized (mLock) { - mScreenSaverEnabled = false; - } } public void screenOnStoppedLw() { @@ -3684,13 +3689,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { long curTime = SystemClock.uptimeMillis(); mPowerManager.userActivity(curTime, false, LocalPowerManager.OTHER_EVENT); } - - synchronized (mLock) { - // even if the keyguard is up, now that all the wakelocks have been released, we - // should re-enable the screen saver - mScreenSaverEnabled = true; - updateScreenSaverTimeoutLocked(); - } } } @@ -3711,11 +3709,13 @@ public class PhoneWindowManager implements WindowManagerPolicy { int diff = visibility ^ mLastSystemUiFlags; final boolean needsMenu = (mFocusedWindow.getAttrs().flags & WindowManager.LayoutParams.FLAG_NEEDS_MENU_KEY) != 0; - if (diff == 0 && mLastFocusNeedsMenu == needsMenu) { + if (diff == 0 && mLastFocusNeedsMenu == needsMenu + && mFocusedApp == mFocusedWindow.getAppToken()) { return 0; } mLastSystemUiFlags = visibility; mLastFocusNeedsMenu = needsMenu; + mFocusedApp = mFocusedWindow.getAppToken(); mHandler.post(new Runnable() { public void run() { if (mStatusBarService == null) { diff --git a/policy/src/com/android/internal/policy/impl/RecentApplicationsDialog.java b/policy/src/com/android/internal/policy/impl/RecentApplicationsDialog.java index aa00fbdd246f..b9903dd906ea 100644 --- a/policy/src/com/android/internal/policy/impl/RecentApplicationsDialog.java +++ b/policy/src/com/android/internal/policy/impl/RecentApplicationsDialog.java @@ -71,8 +71,6 @@ public class RecentApplicationsDialog extends Dialog implements OnClickListener } }; - private int mHeldModifiers; - public RecentApplicationsDialog(Context context) { super(context, com.android.internal.R.style.Theme_Dialog_RecentApplications); @@ -124,17 +122,6 @@ public class RecentApplicationsDialog extends Dialog implements OnClickListener } } - /** - * Sets the modifier keys that are being held to keep the dialog open, or 0 if none. - * Used to make the recent apps dialog automatically dismiss itself when the modifiers - * all go up. - * @param heldModifiers The held key modifiers, such as {@link KeyEvent#META_ALT_ON}. - * Should exclude shift. - */ - public void setHeldModifiers(int heldModifiers) { - mHeldModifiers = heldModifiers; - } - @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_TAB) { @@ -174,30 +161,27 @@ public class RecentApplicationsDialog extends Dialog implements OnClickListener return super.onKeyDown(keyCode, event); } - @Override - public boolean onKeyUp(int keyCode, KeyEvent event) { - if (mHeldModifiers != 0 && (event.getModifiers() & mHeldModifiers) == 0) { - final int numIcons = mIcons.length; - RecentTag tag = null; - for (int i = 0; i < numIcons; i++) { - if (mIcons[i].getVisibility() != View.VISIBLE) { + /** + * Dismiss the dialog and switch to the selected application. + */ + public void dismissAndSwitch() { + final int numIcons = mIcons.length; + RecentTag tag = null; + for (int i = 0; i < numIcons; i++) { + if (mIcons[i].getVisibility() != View.VISIBLE) { + break; + } + if (i == 0 || mIcons[i].hasFocus()) { + tag = (RecentTag) mIcons[i].getTag(); + if (mIcons[i].hasFocus()) { break; } - if (i == 0 || mIcons[i].hasFocus()) { - tag = (RecentTag) mIcons[i].getTag(); - if (mIcons[i].hasFocus()) { - break; - } - } - } - if (tag != null) { - switchTo(tag); } - dismiss(); - return true; } - - return super.onKeyUp(keyCode, event); + if (tag != null) { + switchTo(tag); + } + dismiss(); } /** diff --git a/policy/src/com/android/internal/policy/impl/SimPukUnlockScreen.java b/policy/src/com/android/internal/policy/impl/SimPukUnlockScreen.java index 47a715767c4e..ba06996064fe 100644 --- a/policy/src/com/android/internal/policy/impl/SimPukUnlockScreen.java +++ b/policy/src/com/android/internal/policy/impl/SimPukUnlockScreen.java @@ -242,20 +242,24 @@ public class SimPukUnlockScreen extends LinearLayout implements KeyguardScreen, new CheckSimPuk(mPukText.getText().toString(), mPinText.getText().toString()) { - void onSimLockChangedResponse(boolean success) { - if (mSimUnlockProgressDialog != null) { - mSimUnlockProgressDialog.hide(); - } - if (success) { - // before closing the keyguard, report back that - // the sim is unlocked so it knows right away - mUpdateMonitor.reportSimUnlocked(); - mCallback.goToUnlockScreen(); - } else { - mHeaderText.setText(R.string.badPuk); - mPukText.setText(""); - mPinText.setText(""); - } + void onSimLockChangedResponse(final boolean success) { + mPinText.post(new Runnable() { + public void run() { + if (mSimUnlockProgressDialog != null) { + mSimUnlockProgressDialog.hide(); + } + if (success) { + // before closing the keyguard, report back that + // the sim is unlocked so it knows right away + mUpdateMonitor.reportSimUnlocked(); + mCallback.goToUnlockScreen(); + } else { + mHeaderText.setText(R.string.badPuk); + mPukText.setText(""); + mPinText.setText(""); + } + } + }); } }.start(); } @@ -379,6 +383,9 @@ public class SimPukUnlockScreen extends LinearLayout implements KeyguardScreen, public void onClick(View v) { if (v == mCancelButton) { + // clear the PIN/PUK entry fields if the user cancels + mPinText.setText(""); + mPukText.setText(""); mCallback.goToLockScreen(); return; } diff --git a/policy/src/com/android/internal/policy/impl/SimUnlockScreen.java b/policy/src/com/android/internal/policy/impl/SimUnlockScreen.java index 99e1ce10cfb6..9604cdc6e7b0 100644 --- a/policy/src/com/android/internal/policy/impl/SimUnlockScreen.java +++ b/policy/src/com/android/internal/policy/impl/SimUnlockScreen.java @@ -214,21 +214,25 @@ public class SimUnlockScreen extends LinearLayout implements KeyguardScreen, Vie getSimUnlockProgressDialog().show(); new CheckSimPin(mPinText.getText().toString()) { - void onSimLockChangedResponse(boolean success) { - if (mSimUnlockProgressDialog != null) { - mSimUnlockProgressDialog.hide(); - } - if (success) { - // before closing the keyguard, report back that - // the sim is unlocked so it knows right away - mUpdateMonitor.reportSimUnlocked(); - mCallback.goToUnlockScreen(); - } else { - mHeaderText.setText(R.string.keyguard_password_wrong_pin_code); - mPinText.setText(""); - mEnteredDigits = 0; - } - mCallback.pokeWakelock(); + void onSimLockChangedResponse(final boolean success) { + mPinText.post(new Runnable() { + public void run() { + if (mSimUnlockProgressDialog != null) { + mSimUnlockProgressDialog.hide(); + } + if (success) { + // before closing the keyguard, report back that + // the sim is unlocked so it knows right away + mUpdateMonitor.reportSimUnlocked(); + mCallback.goToUnlockScreen(); + } else { + mHeaderText.setText(R.string.keyguard_password_wrong_pin_code); + mPinText.setText(""); + mEnteredDigits = 0; + } + mCallback.pokeWakelock(); + } + }); } }.start(); } @@ -355,6 +359,7 @@ public class SimUnlockScreen extends LinearLayout implements KeyguardScreen, Vie public void onClick(View v) { if (v == mCancelButton) { + mPinText.setText(""); // clear the PIN entry field if the user cancels mCallback.goToLockScreen(); return; } diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp index 780c0d2c9b23..e9ac3f93e8a0 100644 --- a/services/audioflinger/AudioFlinger.cpp +++ b/services/audioflinger/AudioFlinger.cpp @@ -89,6 +89,12 @@ static const int kRecordThreadSleepUs = 5000; static const nsecs_t kSetParametersTimeout = seconds(2); +// minimum sleep time for the mixer thread loop when tracks are active but in underrun +static const uint32_t kMinThreadSleepTimeUs = 5000; +// maximum divider applied to the active sleep time in the mixer thread loop +static const uint32_t kMaxThreadSleepTimeShift = 2; + + // ---------------------------------------------------------------------------- static bool recordingAllowed() { @@ -1810,6 +1816,18 @@ audio_stream_t* AudioFlinger::PlaybackThread::stream() return &mOutput->stream->common; } +uint32_t AudioFlinger::PlaybackThread::activeSleepTimeUs() +{ + // A2DP output latency is not due only to buffering capacity. It also reflects encoding, + // decoding and transfer time. So sleeping for half of the latency would likely cause + // underruns + if (audio_is_a2dp_device((audio_devices_t)mDevice)) { + return (uint32_t)((uint32_t)((mFrameCount * 1000) / mSampleRate) * 1000); + } else { + return (uint32_t)(mOutput->stream->get_latency(mOutput->stream) * 1000) / 2; + } +} + // ---------------------------------------------------------------------------- AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id, uint32_t device) @@ -1846,6 +1864,7 @@ bool AudioFlinger::MixerThread::threadLoop() uint32_t activeSleepTime = activeSleepTimeUs(); uint32_t idleSleepTime = idleSleepTimeUs(); uint32_t sleepTime = idleSleepTime; + uint32_t sleepTimeShift = 0; Vector< sp<EffectChain> > effectChains; #ifdef DEBUG_CPU_USAGE ThreadCpuUsage cpu; @@ -1937,6 +1956,7 @@ bool AudioFlinger::MixerThread::threadLoop() standbyTime = systemTime() + kStandbyTimeInNsecs; sleepTime = idleSleepTime; + sleepTimeShift = 0; continue; } } @@ -1953,6 +1973,10 @@ bool AudioFlinger::MixerThread::threadLoop() // mix buffers... mAudioMixer->process(); sleepTime = 0; + // increase sleep time progressively when application underrun condition clears + if (sleepTimeShift > 0) { + sleepTimeShift--; + } standbyTime = systemTime() + kStandbyTimeInNsecs; //TODO: delay standby when effects have a tail } else { @@ -1960,7 +1984,17 @@ bool AudioFlinger::MixerThread::threadLoop() // buffer size, then write 0s to the output if (sleepTime == 0) { if (mixerStatus == MIXER_TRACKS_ENABLED) { - sleepTime = activeSleepTime; + sleepTime = activeSleepTime >> sleepTimeShift; + if (sleepTime < kMinThreadSleepTimeUs) { + sleepTime = kMinThreadSleepTimeUs; + } + // reduce sleep time in case of consecutive application underruns to avoid + // starving the audio HAL. As activeSleepTimeUs() is larger than a buffer + // duration we would end up writing less data than needed by the audio HAL if + // the condition persists. + if (sleepTimeShift < kMaxThreadSleepTimeShift) { + sleepTimeShift++; + } } else { sleepTime = idleSleepTime; } @@ -2400,11 +2434,6 @@ status_t AudioFlinger::MixerThread::dumpInternals(int fd, const Vector<String16> return NO_ERROR; } -uint32_t AudioFlinger::MixerThread::activeSleepTimeUs() -{ - return (uint32_t)(mOutput->stream->get_latency(mOutput->stream) * 1000) / 2; -} - uint32_t AudioFlinger::MixerThread::idleSleepTimeUs() { return (uint32_t)(((mFrameCount * 1000) / mSampleRate) * 1000) / 2; @@ -2871,7 +2900,7 @@ uint32_t AudioFlinger::DirectOutputThread::activeSleepTimeUs() { uint32_t time; if (audio_is_linear_pcm(mFormat)) { - time = (uint32_t)(mOutput->stream->get_latency(mOutput->stream) * 1000) / 2; + time = PlaybackThread::activeSleepTimeUs(); } else { time = 10000; } diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h index 897bc78396f5..6cafa7ef7e7f 100644 --- a/services/audioflinger/AudioFlinger.h +++ b/services/audioflinger/AudioFlinger.h @@ -776,7 +776,7 @@ private: virtual int getTrackName_l() = 0; virtual void deleteTrackName_l(int name) = 0; - virtual uint32_t activeSleepTimeUs() = 0; + virtual uint32_t activeSleepTimeUs(); virtual uint32_t idleSleepTimeUs() = 0; virtual uint32_t suspendSleepTimeUs() = 0; @@ -833,7 +833,6 @@ private: Vector< sp<Track> > *tracksToRemove); virtual int getTrackName_l(); virtual void deleteTrackName_l(int name); - virtual uint32_t activeSleepTimeUs(); virtual uint32_t idleSleepTimeUs(); virtual uint32_t suspendSleepTimeUs(); diff --git a/services/input/InputDispatcher.cpp b/services/input/InputDispatcher.cpp index 04b4855d6238..40268b0ddab6 100644 --- a/services/input/InputDispatcher.cpp +++ b/services/input/InputDispatcher.cpp @@ -4320,12 +4320,23 @@ bool InputDispatcher::InputState::trackKey(const KeyEntry* entry, mKeyMementos.removeAt(index); return true; } + /* FIXME: We can't just drop the key up event because that prevents creating + * popup windows that are automatically shown when a key is held and then + * dismissed when the key is released. The problem is that the popup will + * not have received the original key down, so the key up will be considered + * to be inconsistent with its observed state. We could perhaps handle this + * by synthesizing a key down but that will cause other problems. + * + * So for now, allow inconsistent key up events to be dispatched. + * #if DEBUG_OUTBOUND_EVENT_DETAILS LOGD("Dropping inconsistent key up event: deviceId=%d, source=%08x, " "keyCode=%d, scanCode=%d", entry->deviceId, entry->source, entry->keyCode, entry->scanCode); #endif return false; + */ + return true; } case AKEY_EVENT_ACTION_DOWN: { diff --git a/services/java/com/android/server/AppWidgetService.java b/services/java/com/android/server/AppWidgetService.java index 2af51038dd21..4f811783b8ce 100644 --- a/services/java/com/android/server/AppWidgetService.java +++ b/services/java/com/android/server/AppWidgetService.java @@ -24,9 +24,9 @@ import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; import android.content.Intent; +import android.content.Intent.FilterComparison; import android.content.IntentFilter; import android.content.ServiceConnection; -import android.content.Intent.FilterComparison; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; @@ -39,6 +39,8 @@ import android.content.res.XmlResourceParser; import android.net.Uri; import android.os.Binder; import android.os.Bundle; +import android.os.Handler; +import android.os.HandlerThread; import android.os.IBinder; import android.os.RemoteException; import android.os.SystemClock; @@ -74,6 +76,7 @@ import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Locale; +import java.util.Set; class AppWidgetService extends IAppWidgetService.Stub { @@ -805,6 +808,45 @@ class AppWidgetService extends IAppWidgetService.Stub id.host.callbacks = null; } } + + // If the host is unavailable, then we call the associated + // RemoteViewsFactory.onDataSetChanged() directly + if (id.host.callbacks == null) { + Set<FilterComparison> keys = mRemoteViewsServicesAppWidgets.keySet(); + for (FilterComparison key : keys) { + if (mRemoteViewsServicesAppWidgets.get(key).contains(id.appWidgetId)) { + Intent intent = key.getIntent(); + + final ServiceConnection conn = new ServiceConnection() { + @Override + public void onServiceConnected(ComponentName name, IBinder service) { + IRemoteViewsFactory cb = + IRemoteViewsFactory.Stub.asInterface(service); + try { + cb.onDataSetChangedAsync(); + } catch (RemoteException e) { + e.printStackTrace(); + } catch (RuntimeException e) { + e.printStackTrace(); + } + mContext.unbindService(this); + } + @Override + public void onServiceDisconnected(android.content.ComponentName name) { + // Do nothing + } + }; + + // Bind to the service and call onDataSetChanged() + final long token = Binder.clearCallingIdentity(); + try { + mContext.bindService(intent, conn, Context.BIND_AUTO_CREATE); + } finally { + Binder.restoreCallingIdentity(token); + } + } + } + } } } diff --git a/services/java/com/android/server/DeviceStorageMonitorService.java b/services/java/com/android/server/DeviceStorageMonitorService.java index d34087f959d0..16eeb7babb35 100644 --- a/services/java/com/android/server/DeviceStorageMonitorService.java +++ b/services/java/com/android/server/DeviceStorageMonitorService.java @@ -163,7 +163,6 @@ public class DeviceStorageMonitorService extends Binder { } catch (IllegalArgumentException e) { // ignore; report -1 } - mCacheFileStats.restat(CACHE_PATH); EventLog.writeEvent(EventLogTags.FREE_STORAGE_LEFT, mFreeMem, mFreeSystem, mFreeCache); } diff --git a/services/java/com/android/server/EventLogTags.logtags b/services/java/com/android/server/EventLogTags.logtags index 54084361a28a..4dad2092edba 100644 --- a/services/java/com/android/server/EventLogTags.logtags +++ b/services/java/com/android/server/EventLogTags.logtags @@ -50,12 +50,12 @@ option java_package com.android.server # NotificationManagerService.java # --------------------------- # when a NotificationManager.notify is called -2750 notification_enqueue (pkg|3),(id|1|5),(notification|3) +2750 notification_enqueue (pkg|3),(id|1|5),(tag|3),(notification|3) # when someone tries to cancel a notification, the notification manager sometimes # calls this with flags too -2751 notification_cancel (pkg|3),(id|1|5),(required_flags|1) +2751 notification_cancel (pkg|3),(id|1|5),(tag|3),(required_flags|1),(forbidden_flags|1) # when someone tries to cancel all of the notifications for a particular package -2752 notification_cancel_all (pkg|3),(required_flags|1) +2752 notification_cancel_all (pkg|3),(required_flags|1),(forbidden_flags|1) # --------------------------- diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java index ddac35c5d533..f5c4ed46c411 100644 --- a/services/java/com/android/server/InputMethodManagerService.java +++ b/services/java/com/android/server/InputMethodManagerService.java @@ -382,6 +382,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub public void onReceive(Context context, Intent intent) { if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) { mScreenOn = true; + refreshImeWindowVisibilityLocked(); } else if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) { mScreenOn = false; setImeWindowVisibilityStatusHiddenLocked(); @@ -640,6 +641,21 @@ public class InputMethodManagerService extends IInputMethodManager.Stub updateImeWindowStatusLocked(); } + private void refreshImeWindowVisibilityLocked() { + final Configuration conf = mRes.getConfiguration(); + final boolean haveHardKeyboard = conf.keyboard + != Configuration.KEYBOARD_NOKEYS; + final boolean hardKeyShown = haveHardKeyboard + && conf.hardKeyboardHidden + != Configuration.HARDKEYBOARDHIDDEN_YES; + final boolean isScreenLocked = mKeyguardManager != null + && mKeyguardManager.isKeyguardLocked() + && mKeyguardManager.isKeyguardSecure(); + mImeWindowVis = (!isScreenLocked && (mInputShown || hardKeyShown)) ? + (InputMethodService.IME_ACTIVE | InputMethodService.IME_VISIBLE) : 0; + updateImeWindowStatusLocked(); + } + private void updateImeWindowStatusLocked() { setImeWindowStatus(mCurToken, mImeWindowVis, mBackDisposition); } @@ -1285,16 +1301,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } if (mCurMethod != null) { try { - final Configuration conf = mRes.getConfiguration(); - final boolean haveHardKeyboard = conf.keyboard - != Configuration.KEYBOARD_NOKEYS; - final boolean hardKeyShown = haveHardKeyboard - && conf.hardKeyboardHidden - != Configuration.HARDKEYBOARDHIDDEN_YES; - mImeWindowVis = (mInputShown || hardKeyShown) ? ( - InputMethodService.IME_ACTIVE | InputMethodService.IME_VISIBLE) - : 0; - updateImeWindowStatusLocked(); + refreshImeWindowVisibilityLocked(); // If subtype is null, try to find the most applicable one from // getCurrentInputMethodSubtype. if (subtype == null) { diff --git a/services/java/com/android/server/NetworkManagementService.java b/services/java/com/android/server/NetworkManagementService.java index da960aeae5e3..75e5366ba31e 100644 --- a/services/java/com/android/server/NetworkManagementService.java +++ b/services/java/com/android/server/NetworkManagementService.java @@ -856,13 +856,17 @@ public class NetworkManagementService extends INetworkManagementService.Stub NetworkInterface internalNetworkInterface = NetworkInterface.getByName(internalInterface); - Collection<InterfaceAddress>interfaceAddresses = - internalNetworkInterface.getInterfaceAddresses(); - cmd += " " + interfaceAddresses.size(); - for (InterfaceAddress ia : interfaceAddresses) { - InetAddress addr = NetworkUtils.getNetworkPart(ia.getAddress(), - ia.getNetworkPrefixLength()); - cmd = cmd + " " + addr.getHostAddress() + "/" + ia.getNetworkPrefixLength(); + if (internalNetworkInterface == null) { + cmd += " 0"; + } else { + Collection<InterfaceAddress>interfaceAddresses = + internalNetworkInterface.getInterfaceAddresses(); + cmd += " " + interfaceAddresses.size(); + for (InterfaceAddress ia : interfaceAddresses) { + InetAddress addr = NetworkUtils.getNetworkPart(ia.getAddress(), + ia.getNetworkPrefixLength()); + cmd = cmd + " " + addr.getHostAddress() + "/" + ia.getNetworkPrefixLength(); + } } mConnector.doCommand(cmd); diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/NotificationManagerService.java index 7d1d9765eb9d..5039294a2680 100755 --- a/services/java/com/android/server/NotificationManagerService.java +++ b/services/java/com/android/server/NotificationManagerService.java @@ -707,7 +707,8 @@ public class NotificationManagerService extends INotificationManager.Stub // behalf of the download manager without affecting other apps. if (!pkg.equals("com.android.providers.downloads") || Log.isLoggable("DownloadManager", Log.VERBOSE)) { - EventLog.writeEvent(EventLogTags.NOTIFICATION_ENQUEUE, pkg, id, notification.toString()); + EventLog.writeEvent(EventLogTags.NOTIFICATION_ENQUEUE, pkg, id, tag, + notification.toString()); } if (pkg == null || notification == null) { @@ -944,7 +945,8 @@ public class NotificationManagerService extends INotificationManager.Stub */ private void cancelNotification(String pkg, String tag, int id, int mustHaveFlags, int mustNotHaveFlags, boolean sendDelete) { - EventLog.writeEvent(EventLogTags.NOTIFICATION_CANCEL, pkg, id, mustHaveFlags); + EventLog.writeEvent(EventLogTags.NOTIFICATION_CANCEL, pkg, id, tag, + mustHaveFlags, mustNotHaveFlags); synchronized (mNotificationList) { int index = indexOfNotificationLocked(pkg, tag, id); @@ -972,7 +974,8 @@ public class NotificationManagerService extends INotificationManager.Stub */ boolean cancelAllNotificationsInt(String pkg, int mustHaveFlags, int mustNotHaveFlags, boolean doit) { - EventLog.writeEvent(EventLogTags.NOTIFICATION_CANCEL_ALL, pkg, mustHaveFlags); + EventLog.writeEvent(EventLogTags.NOTIFICATION_CANCEL_ALL, pkg, mustHaveFlags, + mustNotHaveFlags); synchronized (mNotificationList) { final int N = mNotificationList.size(); diff --git a/services/java/com/android/server/PowerManagerService.java b/services/java/com/android/server/PowerManagerService.java index 6b23b33ae7bb..2a0d2a086a94 100644 --- a/services/java/com/android/server/PowerManagerService.java +++ b/services/java/com/android/server/PowerManagerService.java @@ -1689,6 +1689,11 @@ public class PowerManagerService extends IPowerManager.Stub // before showing it to the user. We want the light off // until it is ready to be shown to the user, not it using // whatever the last value it had. + if (DEBUG_SCREEN_ON) { + Slog.i(TAG, "Forcing brightness 0: mPowerState=0x" + + Integer.toHexString(mPowerState) + + " mSkippedScreenOn=" + mSkippedScreenOn); + } mScreenBrightness.forceValueLocked(Power.BRIGHTNESS_OFF); } } @@ -2038,12 +2043,14 @@ public class PowerManagerService extends IPowerManager.Stub } finally { Binder.restoreCallingIdentity(identity); } - mScreenBrightness.setTargetLocked(brightness, steps, - INITIAL_SCREEN_BRIGHTNESS, nominalCurrentValue); - if (DEBUG_SCREEN_ON) { - RuntimeException e = new RuntimeException("here"); - e.fillInStackTrace(); - Slog.i(TAG, "Setting screen brightness: " + brightness, e); + if (!mSkippedScreenOn) { + mScreenBrightness.setTargetLocked(brightness, steps, + INITIAL_SCREEN_BRIGHTNESS, nominalCurrentValue); + if (DEBUG_SCREEN_ON) { + RuntimeException e = new RuntimeException("here"); + e.fillInStackTrace(); + Slog.i(TAG, "Setting screen brightness: " + brightness, e); + } } } @@ -2086,6 +2093,11 @@ public class PowerManagerService extends IPowerManager.Stub ? LightsService.BRIGHTNESS_MODE_SENSOR : LightsService.BRIGHTNESS_MODE_USER); if ((mask & SCREEN_BRIGHT_BIT) != 0) { + if (DEBUG_SCREEN_ON) { + RuntimeException e = new RuntimeException("here"); + e.fillInStackTrace(); + Slog.i(TAG, "Set LCD brightness: " + value, e); + } mLcdLight.setBrightness(value, brightnessMode); } if ((mask & BUTTON_BRIGHT_BIT) != 0) { @@ -2137,7 +2149,7 @@ public class PowerManagerService extends IPowerManager.Stub delta = (targetValue - (nominalCurrentValue >= 0 ? nominalCurrentValue : curValue)) / stepsToTarget; - if (mSpew) { + if (mSpew || DEBUG_SCREEN_ON) { String noticeMe = nominalCurrentValue == curValue ? "" : " ******************"; Slog.i(TAG, "setTargetLocked mask=" + mask + " curValue=" + curValue + " target=" + target + " targetValue=" + targetValue + " delta=" + delta @@ -2527,8 +2539,10 @@ public class PowerManagerService extends IPowerManager.Stub } if (mAutoBrightessEnabled && mScreenBrightnessOverride < 0) { - mScreenBrightness.setTargetLocked(lcdValue, AUTOBRIGHTNESS_ANIM_STEPS, - INITIAL_SCREEN_BRIGHTNESS, (int)mScreenBrightness.curValue); + if (!mSkippedScreenOn) { + mScreenBrightness.setTargetLocked(lcdValue, AUTOBRIGHTNESS_ANIM_STEPS, + INITIAL_SCREEN_BRIGHTNESS, (int)mScreenBrightness.curValue); + } } if (mButtonBrightnessOverride < 0) { mButtonLight.setBrightness(buttonValue); diff --git a/services/java/com/android/server/TextServicesManagerService.java b/services/java/com/android/server/TextServicesManagerService.java index d04b4404ae40..8384ebc23d7d 100644 --- a/services/java/com/android/server/TextServicesManagerService.java +++ b/services/java/com/android/server/TextServicesManagerService.java @@ -392,9 +392,16 @@ public class TextServicesManagerService extends ITextServicesManager.Stub { Slog.d(TAG, "FinishSpellCheckerService"); } synchronized(mSpellCheckerMap) { + final ArrayList<SpellCheckerBindGroup> removeList = + new ArrayList<SpellCheckerBindGroup>(); for (SpellCheckerBindGroup group : mSpellCheckerBindGroups.values()) { if (group == null) continue; - group.removeListener(listener); + // Use removeList to avoid modifying mSpellCheckerBindGroups in this loop. + removeList.add(group); + } + final int removeSize = removeList.size(); + for (int i = 0; i < removeSize; ++i) { + removeList.get(i).removeListener(listener); } } } @@ -669,6 +676,7 @@ public class TextServicesManagerService extends ITextServicesManager.Stub { } } + // cleanLocked may remove elements from mSpellCheckerBindGroups private void cleanLocked() { if (DBG) { Slog.d(TAG, "cleanLocked"); diff --git a/services/java/com/android/server/UiModeManagerService.java b/services/java/com/android/server/UiModeManagerService.java index e6392d746daa..c7fbc000a3a6 100644 --- a/services/java/com/android/server/UiModeManagerService.java +++ b/services/java/com/android/server/UiModeManagerService.java @@ -65,7 +65,7 @@ class UiModeManagerService extends IUiModeManager.Stub { // Enable launching of applications when entering the dock. private static final boolean ENABLE_LAUNCH_CAR_DOCK_APP = true; - private static final boolean ENABLE_LAUNCH_DESK_DOCK_APP = false; + private static final boolean ENABLE_LAUNCH_DESK_DOCK_APP = true; private static final int MSG_UPDATE_TWILIGHT = 0; private static final int MSG_ENABLE_LOCATION_UPDATES = 1; diff --git a/services/java/com/android/server/WallpaperManagerService.java b/services/java/com/android/server/WallpaperManagerService.java index 7fa404e85494..4925a4e46e51 100644 --- a/services/java/com/android/server/WallpaperManagerService.java +++ b/services/java/com/android/server/WallpaperManagerService.java @@ -476,6 +476,13 @@ class WallpaperManagerService extends IWallpaperManager.Stub { ParcelFileDescriptor updateWallpaperBitmapLocked(String name) { if (name == null) name = ""; try { + if (!WALLPAPER_DIR.exists()) { + WALLPAPER_DIR.mkdir(); + FileUtils.setPermissions( + WALLPAPER_DIR.getPath(), + FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH, + -1, -1); + } ParcelFileDescriptor fd = ParcelFileDescriptor.open(WALLPAPER_FILE, MODE_CREATE|MODE_READ_WRITE); mName = name; diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java index 3c65255ca5bf..aef3426b40c0 100644 --- a/services/java/com/android/server/WifiService.java +++ b/services/java/com/android/server/WifiService.java @@ -152,8 +152,12 @@ public class WifiService extends IWifiManager.Stub { /* Wifi disabled due to airplane mode on */ private static final int WIFI_DISABLED_AIRPLANE_ON = 3; - private AtomicInteger mWifiState = new AtomicInteger(WIFI_DISABLED); + /* Persisted state that tracks the wifi & airplane interaction from settings */ + private AtomicInteger mPersistWifiState = new AtomicInteger(WIFI_DISABLED); + /* Tracks current airplane mode state */ private AtomicBoolean mAirplaneModeOn = new AtomicBoolean(false); + /* Tracks whether wifi is enabled from WifiStateMachine's perspective */ + private boolean mWifiEnabled; private boolean mIsReceiverRegistered = false; @@ -373,8 +377,8 @@ public class WifiService extends IWifiManager.Stub { mAirplaneModeOn.set(isAirplaneModeOn()); /* On airplane mode disable, restore wifi state if necessary */ if (!mAirplaneModeOn.get() && (testAndClearWifiSavedState() || - mWifiState.get() == WIFI_ENABLED_AIRPLANE_OVERRIDE)) { - persistWifiEnabled(true); + mPersistWifiState.get() == WIFI_ENABLED_AIRPLANE_OVERRIDE)) { + persistWifiState(true); } updateWifiState(); } @@ -391,7 +395,12 @@ public class WifiService extends IWifiManager.Stub { @Override public void onReceive(Context context, Intent intent) { if (intent.getAction().equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) { - // reset & clear notification on any wifi state change + int wifiState = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, + WifiManager.WIFI_STATE_DISABLED); + + mWifiEnabled = (wifiState == WifiManager.WIFI_STATE_ENABLED); + + // reset & clear notification on any wifi state change resetNotification(); } else if (intent.getAction().equals( WifiManager.NETWORK_STATE_CHANGED_ACTION)) { @@ -435,7 +444,7 @@ public class WifiService extends IWifiManager.Stub { */ public void checkAndStartWifi() { mAirplaneModeOn.set(isAirplaneModeOn()); - mWifiState.set(getPersistedWifiState()); + mPersistWifiState.set(getPersistedWifiState()); /* Start if Wi-Fi should be enabled or the saved state indicates Wi-Fi was on */ boolean wifiEnabled = shouldWifiBeEnabled() || testAndClearWifiSavedState(); Slog.i(TAG, "WifiService starting up with Wi-Fi " + @@ -472,29 +481,30 @@ public class WifiService extends IWifiManager.Stub { private boolean shouldWifiBeEnabled() { if (mAirplaneModeOn.get()) { - return mWifiState.get() == WIFI_ENABLED_AIRPLANE_OVERRIDE; + return mPersistWifiState.get() == WIFI_ENABLED_AIRPLANE_OVERRIDE; } else { - return mWifiState.get() != WIFI_DISABLED; + return mPersistWifiState.get() != WIFI_DISABLED; } } - private void persistWifiEnabled(boolean enabled) { + private void persistWifiState(boolean enabled) { final ContentResolver cr = mContext.getContentResolver(); boolean airplane = mAirplaneModeOn.get() && isAirplaneToggleable(); if (enabled) { if (airplane) { - mWifiState.set(WIFI_ENABLED_AIRPLANE_OVERRIDE); + mPersistWifiState.set(WIFI_ENABLED_AIRPLANE_OVERRIDE); } else { - mWifiState.set(WIFI_ENABLED); + mPersistWifiState.set(WIFI_ENABLED); } } else { if (airplane) { - mWifiState.set(WIFI_DISABLED_AIRPLANE_ON); + mPersistWifiState.set(WIFI_DISABLED_AIRPLANE_ON); } else { - mWifiState.set(WIFI_DISABLED); + mPersistWifiState.set(WIFI_DISABLED); } } - Settings.Secure.putInt(cr, Settings.Secure.WIFI_ON, mWifiState.get()); + + Settings.Secure.putInt(cr, Settings.Secure.WIFI_ON, mPersistWifiState.get()); } @@ -545,7 +555,6 @@ public class WifiService extends IWifiManager.Stub { */ public synchronized boolean setWifiEnabled(boolean enable) { enforceChangePermission(); - if (DBG) { Slog.e(TAG, "Invoking mWifiStateMachine.setWifiEnabled\n"); } @@ -559,16 +568,20 @@ public class WifiService extends IWifiManager.Stub { * Caller might not have WRITE_SECURE_SETTINGS, * only CHANGE_WIFI_STATE is enforced */ - long ident = Binder.clearCallingIdentity(); - persistWifiEnabled(enable); - Binder.restoreCallingIdentity(ident); + + /* Avoids overriding of airplane state when wifi is already in the expected state */ + if (enable != mWifiEnabled) { + long ident = Binder.clearCallingIdentity(); + persistWifiState(enable); + Binder.restoreCallingIdentity(ident); + } if (enable) { if (!mIsReceiverRegistered) { registerForBroadcasts(); mIsReceiverRegistered = true; } - } else if (mIsReceiverRegistered){ + } else if (mIsReceiverRegistered) { mContext.unregisterReceiver(mReceiver); mIsReceiverRegistered = false; } @@ -840,7 +853,7 @@ public class WifiService extends IWifiManager.Stub { * of WifiLock & device idle status unless wifi enabled status is toggled */ - mWifiStateMachine.setDriverStart(true); + mWifiStateMachine.setDriverStart(true, mEmergencyCallbackMode); mWifiStateMachine.reconnectCommand(); } @@ -854,7 +867,7 @@ public class WifiService extends IWifiManager.Stub { * TODO: if a stop is issued, wifi is brought up only by startWifi * unless wifi enabled status is toggled */ - mWifiStateMachine.setDriverStart(false); + mWifiStateMachine.setDriverStart(false, mEmergencyCallbackMode); } @@ -1074,12 +1087,11 @@ public class WifiService extends IWifiManager.Stub { mWifiStateMachine.setWifiEnabled(true); mWifiStateMachine.setScanOnlyMode( strongestLockMode == WifiManager.WIFI_MODE_SCAN_ONLY); - mWifiStateMachine.setDriverStart(true); + mWifiStateMachine.setDriverStart(true, mEmergencyCallbackMode); mWifiStateMachine.setHighPerfModeEnabled(strongestLockMode == WifiManager.WIFI_MODE_FULL_HIGH_PERF); } else { - mWifiStateMachine.requestCmWakeLock(); - mWifiStateMachine.setDriverStart(false); + mWifiStateMachine.setDriverStart(false, mEmergencyCallbackMode); } } else { mWifiStateMachine.setWifiEnabled(false); diff --git a/services/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/java/com/android/server/accessibility/AccessibilityManagerService.java index fd528cce8490..b70ed9699a0f 100644 --- a/services/java/com/android/server/accessibility/AccessibilityManagerService.java +++ b/services/java/com/android/server/accessibility/AccessibilityManagerService.java @@ -115,8 +115,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub private final Set<ComponentName> mEnabledServices = new HashSet<ComponentName>(); - private final SparseArray<IAccessibilityInteractionConnection> mWindowIdToInteractionConnectionMap = - new SparseArray<IAccessibilityInteractionConnection>(); + private final SparseArray<AccessibilityConnectionWrapper> mWindowIdToInteractionConnectionWrapperMap = + new SparseArray<AccessibilityConnectionWrapper>(); private final SparseArray<IBinder> mWindowIdToWindowTokenMap = new SparseArray<IBinder>(); @@ -439,16 +439,11 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub final IWindow addedWindowToken = windowToken; final IAccessibilityInteractionConnection addedConnection = connection; final int windowId = sNextWindowId++; - addedConnection.asBinder().linkToDeath(new DeathRecipient() { - public void binderDied() { - synchronized (mLock) { - addedConnection.asBinder().unlinkToDeath(this, 0); - removeAccessibilityInteractionConnection(addedWindowToken); - } - } - }, 0); + AccessibilityConnectionWrapper wrapper = new AccessibilityConnectionWrapper(windowId, + connection); + wrapper.linkToDeath(); mWindowIdToWindowTokenMap.put(windowId, addedWindowToken.asBinder()); - mWindowIdToInteractionConnectionMap.put(windowId, connection); + mWindowIdToInteractionConnectionWrapperMap.put(windowId, wrapper); if (DEBUG) { Slog.i(LOG_TAG, "Adding interaction connection to windowId: " + windowId); } @@ -462,18 +457,17 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub for (int i = 0; i < count; i++) { if (mWindowIdToWindowTokenMap.valueAt(i) == windowToken.asBinder()) { final int windowId = mWindowIdToWindowTokenMap.keyAt(i); - mWindowIdToWindowTokenMap.remove(windowId); - mWindowIdToInteractionConnectionMap.remove(windowId); - if (DEBUG) { - Slog.i(LOG_TAG, "Removing interaction connection to windowId: " + windowId); - } + AccessibilityConnectionWrapper wrapper = + mWindowIdToInteractionConnectionWrapperMap.get(windowId); + wrapper.unlinkToDeath(); + removeAccessibilityInteractionConnectionLocked(windowId); return; } } } } - public IAccessibilityServiceConnection registerEventListener(IEventListener listener) { + public void registerEventListener(IEventListener listener) { mSecurityPolicy.enforceCallingPermission(Manifest.permission.RETRIEVE_WINDOW_CONTENT, FUNCTION_REGISTER_EVENT_LISTENER); ComponentName componentName = new ComponentName("foo.bar", @@ -501,7 +495,19 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub accessibilityServiceInfo.feedbackType = AccessibilityServiceInfo.FEEDBACK_GENERIC; Service service = new Service(componentName, accessibilityServiceInfo, true); service.onServiceConnected(componentName, listener.asBinder()); - return service; + } + + /** + * Removes an AccessibilityInteractionConnection. + * + * @param windowId The id of the window to which the connection is targeted. + */ + private void removeAccessibilityInteractionConnectionLocked(int windowId) { + mWindowIdToWindowTokenMap.remove(windowId); + mWindowIdToInteractionConnectionWrapperMap.remove(windowId); + if (DEBUG) { + Slog.i(LOG_TAG, "Removing interaction connection to windowId: " + windowId); + } } /** @@ -594,6 +600,13 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub */ private void notifyEventListenerLocked(Service service, int eventType) { IEventListener listener = service.mServiceInterface; + + // If the service died/was disabled while the message for dispatching + // the accessibility event was propagating the listener may be null. + if (listener == null) { + return; + } + AccessibilityEvent event = service.mPendingEvents.get(eventType); // Check for null here because there is a concurrent scenario in which this @@ -618,7 +631,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub service.mPendingEvents.remove(eventType); try { if (mSecurityPolicy.canRetrieveWindowContent(service)) { - event.setConnection(service); + event.setConnectionId(service.mId); } else { event.setSource(null); } @@ -666,6 +679,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub mComponentNameToServiceMap.remove(service.mComponentName); mHandler.removeMessages(service.mId); service.unlinkToOwnDeath(); + service.dispose(); updateInputFilterLocked(); return removed; } @@ -895,6 +909,33 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub sendStateToClientsLocked(); } + private class AccessibilityConnectionWrapper implements DeathRecipient { + private final int mWindowId; + private final IAccessibilityInteractionConnection mConnection; + + public AccessibilityConnectionWrapper(int windowId, + IAccessibilityInteractionConnection connection) { + mWindowId = windowId; + mConnection = connection; + } + + public void linkToDeath() throws RemoteException { + mConnection.asBinder().linkToDeath(this, 0); + } + + public void unlinkToDeath() { + mConnection.asBinder().unlinkToDeath(this, 0); + } + + @Override + public void binderDied() { + unlinkToDeath(); + synchronized (mLock) { + removeAccessibilityInteractionConnectionLocked(mWindowId); + } + } + } + /** * This class represents an accessibility service. It stores all per service * data required for the service management, provides API for starting/stopping the @@ -997,7 +1038,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub if (!mIsAutomation) { mContext.unbindService(this); } - mService = null; return true; } return false; @@ -1021,7 +1061,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub mService = service; mServiceInterface = IEventListener.Stub.asInterface(service); try { - mServiceInterface.setConnection(this); + mServiceInterface.setConnection(this, mId); synchronized (mLock) { tryAddServiceLocked(this); } @@ -1123,14 +1163,16 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub if (!permissionGranted) { return 0; } else { - connection = mWindowIdToInteractionConnectionMap.get(accessibilityWindowId); - if (connection == null) { + AccessibilityConnectionWrapper wrapper = + mWindowIdToInteractionConnectionWrapperMap.get(accessibilityWindowId); + if (wrapper == null) { if (DEBUG) { Slog.e(LOG_TAG, "No interaction connection to window: " + accessibilityWindowId); } return 0; } + connection = wrapper.mConnection; } } final int interrogatingPid = Binder.getCallingPid(); @@ -1159,14 +1201,16 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub if (!permissionGranted) { return false; } else { - connection = mWindowIdToInteractionConnectionMap.get(accessibilityWindowId); - if (connection == null) { + AccessibilityConnectionWrapper wrapper = + mWindowIdToInteractionConnectionWrapperMap.get(accessibilityWindowId); + if (wrapper == null) { if (DEBUG) { Slog.e(LOG_TAG, "No interaction connection to window: " + accessibilityWindowId); } return false; } + connection = wrapper.mConnection; } } final int interrogatingPid = Binder.getCallingPid(); @@ -1197,9 +1241,21 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub mService.unlinkToDeath(this, 0); } + public void dispose() { + try { + // Clear the proxy in the other process so this + // IAccessibilityServiceConnection can be garbage collected. + mServiceInterface.setConnection(null, mId); + } catch (RemoteException re) { + /* ignore */ + } + mService = null; + mServiceInterface = null; + } + public void binderDied() { synchronized (mLock) { - mService.unlinkToDeath(this, 0); + unlinkToOwnDeath(); tryRemoveServiceLocked(this); // We no longer have an automation service, so restore // the state based on values in the settings database. @@ -1214,7 +1270,9 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub if (DEBUG) { Slog.i(LOG_TAG, "Trying to get interaction connection to windowId: " + windowId); } - return mWindowIdToInteractionConnectionMap.get(windowId); + AccessibilityConnectionWrapper wrapper = + mWindowIdToInteractionConnectionWrapperMap.get(windowId); + return (wrapper != null) ? wrapper.mConnection : null; } private float getCompatibilityScale(int windowId) { diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index 80234771b466..df58e83186ac 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -129,7 +129,6 @@ import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; -import java.io.InputStream; import java.io.InputStreamReader; import java.io.PrintWriter; import java.io.StringWriter; @@ -415,7 +414,12 @@ public final class ActivityManagerService extends ActivityManagerNative * is in a different process from the one they are currently in. */ ProcessRecord mPreviousProcess; - + + /** + * The time at which the previous process was last visible. + */ + long mPreviousProcessVisibleTime; + /** * Packages that the user has asked to have run in screen size * compatibility mode instead of filling the screen. @@ -1222,6 +1226,23 @@ public final class ActivityManagerService extends ActivityManagerNative @Override public void run() { StringBuilder dropBuilder = new StringBuilder(1024); StringBuilder logBuilder = new StringBuilder(1024); + StringWriter oomSw = new StringWriter(); + PrintWriter oomPw = new PrintWriter(oomSw); + StringWriter catSw = new StringWriter(); + PrintWriter catPw = new PrintWriter(catSw); + String[] emptyArgs = new String[] { }; + StringBuilder tag = new StringBuilder(128); + StringBuilder stack = new StringBuilder(128); + tag.append("Low on memory -- "); + dumpApplicationMemoryUsage(null, oomPw, " ", emptyArgs, true, catPw, + tag, stack); + dropBuilder.append(stack); + dropBuilder.append('\n'); + dropBuilder.append('\n'); + String oomString = oomSw.toString(); + dropBuilder.append(oomString); + dropBuilder.append('\n'); + logBuilder.append(oomString); try { java.lang.Process proc = Runtime.getRuntime().exec(new String[] { "procrank", }); @@ -1244,27 +1265,15 @@ public final class ActivityManagerService extends ActivityManagerNative converter.close(); } catch (IOException e) { } - StringWriter sw = new StringWriter(); - PrintWriter pw = new PrintWriter(sw); - StringWriter catSw = new StringWriter(); - PrintWriter catPw = new PrintWriter(catSw); - String[] emptyArgs = new String[] { }; - StringBuilder tag = new StringBuilder(128); synchronized (ActivityManagerService.this) { + catPw.println(); dumpProcessesLocked(null, catPw, emptyArgs, 0, false, null); catPw.println(); dumpServicesLocked(null, catPw, emptyArgs, 0, false, false, null); catPw.println(); dumpActivitiesLocked(null, catPw, emptyArgs, 0, false, false, null); - catPw.println(); } - tag.append("Low on memory -- "); - dumpApplicationMemoryUsage(null, pw, " ", emptyArgs, true, catPw, tag); - String memUsage = sw.toString(); - dropBuilder.append('\n'); - dropBuilder.append(memUsage); dropBuilder.append(catSw.toString()); - logBuilder.append(memUsage); addErrorToDropBox("lowmem", null, "system_server", null, null, tag.toString(), dropBuilder.toString(), null, null); Slog.i(TAG, logBuilder.toString()); @@ -1420,7 +1429,7 @@ public final class ActivityManagerService extends ActivityManagerNative } mActivityManagerService.dumpApplicationMemoryUsage(fd, pw, " ", args, - false, null, null); + false, null, null, null); } } @@ -2716,6 +2725,10 @@ public final class ActivityManagerService extends ActivityManagerNative } if (!r.finishing) { Slog.w(TAG, "Force removing " + r + ": app died, no saved state"); + EventLog.writeEvent(EventLogTags.AM_FINISH_ACTIVITY, + System.identityHashCode(r), + r.task.taskId, r.shortComponentName, + "proc died without state saved"); } r.makeFinishing(); mMainStack.mHistory.remove(i); @@ -8353,6 +8366,12 @@ public final class ActivityManagerService extends ActivityManagerNative pw.println(); pw.println(" mHomeProcess: " + mHomeProcess); pw.println(" mPreviousProcess: " + mPreviousProcess); + if (dumpAll) { + StringBuilder sb = new StringBuilder(128); + sb.append(" mPreviousProcessVisibleTime: "); + TimeUtils.formatDuration(mPreviousProcessVisibleTime, sb); + pw.println(sb); + } if (mHeavyWeightProcess != null) { pw.println(" mHeavyWeightProcess: " + mHeavyWeightProcess); } @@ -9416,7 +9435,7 @@ public final class ActivityManagerService extends ActivityManagerNative } 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("bckup", null, 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.PERCEPTIBLE_APP_ADJ) { @@ -9645,7 +9664,8 @@ public final class ActivityManagerService extends ActivityManagerNative 1*1024*1024, 2*1024*1024, 5*1024*1024, 10*1024*1024, 20*1024*1024 }; - static final void appendMemBucket(StringBuilder out, long memKB, String label) { + static final void appendMemBucket(StringBuilder out, long memKB, String label, + boolean stackLike) { int start = label.lastIndexOf('.'); if (start >= 0) start++; else start = 0; @@ -9654,13 +9674,13 @@ public final class ActivityManagerService extends ActivityManagerNative if (DUMP_MEM_BUCKETS[i] >= memKB) { long bucket = DUMP_MEM_BUCKETS[i]/1024; out.append(bucket); - out.append("MB "); + out.append(stackLike ? "MB." : "MB "); out.append(label, start, end); return; } } out.append(memKB/1024); - out.append("MB "); + out.append(stackLike ? "MB." : "MB "); out.append(label, start, end); } @@ -9679,7 +9699,7 @@ public final class ActivityManagerService extends ActivityManagerNative final void dumpApplicationMemoryUsage(FileDescriptor fd, PrintWriter pw, String prefix, String[] args, boolean brief, - PrintWriter categoryPw, StringBuilder outTag) { + PrintWriter categoryPw, StringBuilder outTag, StringBuilder outStack) { boolean dumpAll = false; boolean oomOnly = false; @@ -9816,8 +9836,14 @@ public final class ActivityManagerService extends ActivityManagerNative } } - if (outTag != null) { - appendMemBucket(outTag, totalPss, "total"); + if (outTag != null || outStack != null) { + if (outTag != null) { + appendMemBucket(outTag, totalPss, "total", false); + } + if (outStack != null) { + appendMemBucket(outStack, totalPss, "total", true); + } + boolean firstLine = true; for (int i=0; i<oomMems.size(); i++) { MemItem miCat = oomMems.get(i); if (miCat.subitems == null || miCat.subitems.size() < 1) { @@ -9826,13 +9852,47 @@ public final class ActivityManagerService extends ActivityManagerNative if (miCat.id < ProcessList.SERVICE_ADJ || miCat.id == ProcessList.HOME_APP_ADJ || miCat.id == ProcessList.PREVIOUS_APP_ADJ) { - outTag.append(" / "); + if (outTag != null && miCat.id <= ProcessList.FOREGROUND_APP_ADJ) { + outTag.append(" / "); + } + if (outStack != null) { + if (miCat.id >= ProcessList.FOREGROUND_APP_ADJ) { + if (firstLine) { + outStack.append(":"); + firstLine = false; + } + outStack.append("\n\t at "); + } else { + outStack.append("$"); + } + } for (int j=0; j<miCat.subitems.size(); j++) { MemItem mi = miCat.subitems.get(j); if (j > 0) { - outTag.append(" "); + if (outTag != null) { + outTag.append(" "); + } + if (outStack != null) { + outStack.append("$"); + } + } + if (outTag != null && miCat.id <= ProcessList.FOREGROUND_APP_ADJ) { + appendMemBucket(outTag, mi.pss, mi.shortLabel, false); + } + if (outStack != null) { + appendMemBucket(outStack, mi.pss, mi.shortLabel, true); } - appendMemBucket(outTag, mi.pss, mi.shortLabel); + } + if (outStack != null && miCat.id >= ProcessList.FOREGROUND_APP_ADJ) { + outStack.append("("); + for (int k=0; k<DUMP_MEM_OOM_ADJ.length; k++) { + if (DUMP_MEM_OOM_ADJ[k] == miCat.id) { + outStack.append(DUMP_MEM_OOM_LABEL[k]); + outStack.append(":"); + outStack.append(DUMP_MEM_OOM_ADJ[k]); + } + } + outStack.append(")"); } } } @@ -13551,6 +13611,7 @@ public final class ActivityManagerService extends ActivityManagerNative adj = ProcessList.PERCEPTIBLE_APP_ADJ; app.adjType = "stopping"; } + app.hidden = false; app.foregroundActivities = true; } } @@ -14199,7 +14260,7 @@ public final class ActivityManagerService extends ActivityManagerNative if (app.curAdj != app.setAdj) { if (Process.setOomAdj(app.pid, app.curAdj)) { - if (true || DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v( + if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v( TAG, "Set " + app.pid + " " + app.processName + " adj " + app.curAdj + ": " + app.adjType); app.setAdj = app.curAdj; @@ -14358,10 +14419,16 @@ public final class ActivityManagerService extends ActivityManagerNative app.thread.scheduleTrimMemory(curLevel); } catch (RemoteException e) { } - if (curLevel >= ComponentCallbacks2.TRIM_MEMORY_COMPLETE) { - // For these apps we will also finish their activities - // to help them free memory. - mMainStack.destroyActivitiesLocked(app, false, "trim"); + if (false) { + // For now we won't do this; our memory trimming seems + // to be good enough at this point that destroying + // activities causes more harm than good. + if (curLevel >= ComponentCallbacks2.TRIM_MEMORY_COMPLETE + && app != mHomeProcess && app != mPreviousProcess) { + // For these apps we will also finish their activities + // to help them free memory. + mMainStack.destroyActivitiesLocked(app, false, "trim"); + } } } app.trimMemoryLevel = curLevel; diff --git a/services/java/com/android/server/am/ActivityRecord.java b/services/java/com/android/server/am/ActivityRecord.java index 951a946e06a0..c819114f3866 100644 --- a/services/java/com/android/server/am/ActivityRecord.java +++ b/services/java/com/android/server/am/ActivityRecord.java @@ -80,6 +80,7 @@ final class ActivityRecord { ThumbnailHolder thumbHolder; // where our thumbnails should go. long launchTime; // when we starting launching this activity long startTime; // last time this activity was started + long lastVisibleTime; // last time this activity became visible long cpuTimeAtResume; // the cpu time of host process at the time of resuming activity Configuration configuration; // configuration activity was last running in CompatibilityInfo compat;// last used compatibility mode @@ -188,6 +189,10 @@ final class ActivityRecord { TimeUtils.formatDuration(launchTime, pw); pw.print(" startTime="); TimeUtils.formatDuration(startTime, pw); pw.println(""); } + if (lastVisibleTime != 0) { + pw.print(prefix); pw.print("lastVisibleTime="); + TimeUtils.formatDuration(lastVisibleTime, pw); pw.println(""); + } if (waitingVisible || nowVisible) { pw.print(prefix); pw.print("waitingVisible="); pw.print(waitingVisible); pw.print(" nowVisible="); pw.println(nowVisible); @@ -632,6 +637,7 @@ final class ActivityRecord { ActivityManagerService.TAG, "windowsVisible(): " + this); if (!nowVisible) { nowVisible = true; + lastVisibleTime = SystemClock.uptimeMillis(); if (!idle) { // Instead of doing the full stop routine here, let's just // hide any activities we now can, and let them stop when diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java index c7ce3c3eed8d..6c1195387f4e 100644 --- a/services/java/com/android/server/am/ActivityStack.java +++ b/services/java/com/android/server/am/ActivityStack.java @@ -949,6 +949,22 @@ final class ActivityStack { if (r.configDestroy) { destroyActivityLocked(r, true, false, "stop-config"); resumeTopActivityLocked(null); + } else { + // Now that this process has stopped, we may want to consider + // it to be the previous app to try to keep around in case + // the user wants to return to it. + ProcessRecord fgApp = null; + if (mResumedActivity != null) { + fgApp = mResumedActivity.app; + } else if (mPausingActivity != null) { + fgApp = mPausingActivity.app; + } + if (r.app != null && fgApp != null && r.app != fgApp + && r.lastVisibleTime > mService.mPreviousProcessVisibleTime + && r.app != mService.mHomeProcess) { + mService.mPreviousProcess = r.app; + mService.mPreviousProcessVisibleTime = r.lastVisibleTime; + } } } } @@ -1363,14 +1379,6 @@ final class ActivityStack { + ", nowVisible=" + next.nowVisible); } } - - if (!prev.finishing && prev.app != null && prev.app != next.app - && prev.app != mService.mHomeProcess) { - // We are switching to a new activity that is in a different - // process than the previous one. Note the previous process, - // so we can try to keep it around. - mService.mPreviousProcess = prev.app; - } } // Launching this app's activity, make sure the app is no longer @@ -1924,8 +1932,9 @@ final class ActivityStack { // should be left as-is. replyChainEnd = -1; } - - } else if (target.resultTo != null) { + + } else if (target.resultTo != null && (below == null + || below.task == target.task)) { // If this activity is sending a reply to a previous // activity, we can't do anything with it now until // we reach the start of the reply chain. @@ -1955,6 +1964,8 @@ final class ActivityStack { replyChainEnd = targetI; } ActivityRecord p = null; + if (DEBUG_TASKS) Slog.v(TAG, "Finishing task at index " + + targetI + " to " + replyChainEnd); for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) { p = mHistory.get(srcPos); if (p.finishing) { @@ -1973,6 +1984,8 @@ final class ActivityStack { if (replyChainEnd < 0) { replyChainEnd = targetI; } + if (DEBUG_TASKS) Slog.v(TAG, "Reparenting task at index " + + targetI + " to " + replyChainEnd); for (int srcPos=replyChainEnd; srcPos>=targetI; srcPos--) { ActivityRecord p = mHistory.get(srcPos); if (p.finishing) { @@ -1994,6 +2007,7 @@ final class ActivityStack { p.setTask(task, null, false); mHistory.add(lastReparentPos, p); if (DEBUG_TASKS) Slog.v(TAG, "Pulling activity " + p + + " from " + srcPos + " to " + lastReparentPos + " in to resetting task " + task); mService.mWindowManager.moveAppToken(lastReparentPos, p.appToken); mService.mWindowManager.setAppGroupId(p.appToken, p.task.taskId); @@ -2023,6 +2037,11 @@ final class ActivityStack { } } } + + } else if (below != null && below.task != target.task) { + // We hit the botton of a task; the reply chain can't + // pass through it. + replyChainEnd = -1; } target = below; diff --git a/services/java/com/android/server/am/TaskRecord.java b/services/java/com/android/server/am/TaskRecord.java index a86076344e8a..de3129bda384 100644 --- a/services/java/com/android/server/am/TaskRecord.java +++ b/services/java/com/android/server/am/TaskRecord.java @@ -54,8 +54,17 @@ class TaskRecord extends ThumbnailHolder { void setIntent(Intent _intent, ActivityInfo info) { stringName = null; - + if (info.targetActivity == null) { + if (_intent != null) { + // If this Intent has a selector, we want to clear it for the + // recent task since it is not relevant if the user later wants + // to re-launch the app. + if (_intent.getSelector() != null) { + _intent = new Intent(_intent); + _intent.setSelector(null); + } + } intent = _intent; realActivity = _intent != null ? _intent.getComponent() : null; origActivity = null; @@ -65,6 +74,7 @@ class TaskRecord extends ThumbnailHolder { if (_intent != null) { Intent targetIntent = new Intent(_intent); targetIntent.setComponent(targetComponent); + targetIntent.setSelector(null); intent = targetIntent; realActivity = targetComponent; origActivity = _intent.getComponent(); diff --git a/services/java/com/android/server/connectivity/Vpn.java b/services/java/com/android/server/connectivity/Vpn.java index 55e067853372..72cf51253479 100644 --- a/services/java/com/android/server/connectivity/Vpn.java +++ b/services/java/com/android/server/connectivity/Vpn.java @@ -482,6 +482,7 @@ public class Vpn extends INetworkManagementEventObserver.Stub { if (state.exists()) { throw new IllegalStateException("Cannot delete the state"); } + new File("/data/misc/vpn/abort").delete(); // Check if we need to restart any of the daemons. boolean restart = false; diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java index 700554157ea1..6b61c47db696 100644 --- a/services/java/com/android/server/pm/PackageManagerService.java +++ b/services/java/com/android/server/pm/PackageManagerService.java @@ -2162,6 +2162,9 @@ public class PackageManagerService extends IPackageManager.Stub { int flags, List<ResolveInfo> query, int priority) { // writer synchronized (mPackages) { + if (intent.getSelector() != null) { + intent = intent.getSelector(); + } if (DEBUG_PREFERRED) intent.addFlags(Intent.FLAG_DEBUG_LOG_RESOLUTION); List<PreferredActivity> prefs = mSettings.mPreferredActivities.queryIntent(intent, resolvedType, @@ -2242,7 +2245,13 @@ public class PackageManagerService extends IPackageManager.Stub { public List<ResolveInfo> queryIntentActivities(Intent intent, String resolvedType, int flags) { - final ComponentName comp = intent.getComponent(); + ComponentName comp = intent.getComponent(); + if (comp == null) { + if (intent.getSelector() != null) { + intent = intent.getSelector(); + comp = intent.getComponent(); + } + } if (comp != null) { final List<ResolveInfo> list = new ArrayList<ResolveInfo>(1); final ActivityInfo ai = getActivityInfo(comp, flags); @@ -2440,6 +2449,12 @@ public class PackageManagerService extends IPackageManager.Stub { public List<ResolveInfo> queryIntentReceivers(Intent intent, String resolvedType, int flags) { ComponentName comp = intent.getComponent(); + if (comp == null) { + if (intent.getSelector() != null) { + intent = intent.getSelector(); + comp = intent.getComponent(); + } + } if (comp != null) { List<ResolveInfo> list = new ArrayList<ResolveInfo>(1); ActivityInfo ai = getReceiverInfo(comp, flags); @@ -2478,7 +2493,13 @@ public class PackageManagerService extends IPackageManager.Stub { } public List<ResolveInfo> queryIntentServices(Intent intent, String resolvedType, int flags) { - final ComponentName comp = intent.getComponent(); + ComponentName comp = intent.getComponent(); + if (comp == null) { + if (intent.getSelector() != null) { + intent = intent.getSelector(); + comp = intent.getComponent(); + } + } if (comp != null) { final List<ResolveInfo> list = new ArrayList<ResolveInfo>(1); final ServiceInfo si = getServiceInfo(comp, flags); diff --git a/services/java/com/android/server/wm/Session.java b/services/java/com/android/server/wm/Session.java index ee62a56ddc1f..77575f2f5251 100644 --- a/services/java/com/android/server/wm/Session.java +++ b/services/java/com/android/server/wm/Session.java @@ -151,18 +151,22 @@ final class Session extends IWindowSession.Stub public int relayout(IWindow window, int seq, WindowManager.LayoutParams attrs, int requestedWidth, int requestedHeight, int viewFlags, - boolean insetsPending, Rect outFrame, Rect outContentInsets, + int flags, Rect outFrame, Rect outContentInsets, Rect outVisibleInsets, Configuration outConfig, Surface outSurface) { if (false) Slog.d(WindowManagerService.TAG, ">>>>>> ENTERED relayout from " + Binder.getCallingPid()); int res = mService.relayoutWindow(this, window, seq, attrs, - requestedWidth, requestedHeight, viewFlags, insetsPending, + requestedWidth, requestedHeight, viewFlags, flags, outFrame, outContentInsets, outVisibleInsets, outConfig, outSurface); if (false) Slog.d(WindowManagerService.TAG, "<<<<<< EXITING relayout to " + Binder.getCallingPid()); return res; } + public void performDeferredDestroy(IWindow window) { + mService.performDeferredDestroyWindow(this, window); + } + public boolean outOfMemory(IWindow window) { return mService.outOfMemoryWindow(this, window); } diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java index ebb13d5c8f61..f5c2de912710 100644 --- a/services/java/com/android/server/wm/WindowManagerService.java +++ b/services/java/com/android/server/wm/WindowManagerService.java @@ -429,6 +429,18 @@ public class WindowManagerService extends IWindowManager.Stub boolean mSystemBooted = false; boolean mForceDisplayEnabled = false; boolean mShowingBootMessages = false; + + // This protects the following display size properties, so that + // getDisplaySize() doesn't need to acquire the global lock. This is + // needed because the window manager sometimes needs to use ActivityThread + // while it has its global state locked (for example to load animation + // resources), but the ActivityThread also needs get the current display + // size sometimes when it has its package lock held. + // + // These will only be modified with both mWindowMap and mDisplaySizeLock + // held (in that order) so the window manager doesn't need to acquire this + // lock when needing these values in its normal operation. + final Object mDisplaySizeLock = new Object(); int mInitialDisplayWidth = 0; int mInitialDisplayHeight = 0; int mBaseDisplayWidth = 0; @@ -437,6 +449,7 @@ public class WindowManagerService extends IWindowManager.Stub int mCurDisplayHeight = 0; int mAppDisplayWidth = 0; int mAppDisplayHeight = 0; + int mRotation = 0; int mForcedAppOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; boolean mAltOrientation = false; @@ -2499,12 +2512,13 @@ public class WindowManagerService extends IWindowManager.Stub public int relayoutWindow(Session session, IWindow client, int seq, WindowManager.LayoutParams attrs, int requestedWidth, - int requestedHeight, int viewVisibility, boolean insetsPending, + int requestedHeight, int viewVisibility, int flags, Rect outFrame, Rect outContentInsets, Rect outVisibleInsets, Configuration outConfig, Surface outSurface) { boolean displayed = false; boolean inTouchMode; boolean configChanged; + boolean surfaceChanged = false; // if they don't have this permission, mask out the status bar bits int systemUiVisibility = 0; @@ -2534,6 +2548,9 @@ public class WindowManagerService extends IWindowManager.Stub mPolicy.adjustWindowParamsLw(attrs); } + win.mSurfaceDestroyDeferred = + (flags&WindowManagerImpl.RELAYOUT_DEFER_SURFACE_DESTROY) != 0; + int attrChanges = 0; int flagChanges = 0; if (attrs != null) { @@ -2630,8 +2647,12 @@ public class WindowManagerService extends IWindowManager.Stub // To change the format, we need to re-build the surface. win.destroySurfaceLocked(); displayed = true; + surfaceChanged = true; } try { + if (win.mSurface == null) { + surfaceChanged = true; + } Surface surface = win.createSurfaceLocked(); if (surface != null) { outSurface.copyFrom(surface); @@ -2683,6 +2704,7 @@ public class WindowManagerService extends IWindowManager.Stub // If we are not currently running the exit animation, we // need to see about starting one. if (!win.mExiting || win.mSurfacePendingDestroy) { + surfaceChanged = true; // Try starting an animation; if there isn't one, we // can destroy the surface right away. int transit = WindowManagerPolicy.TRANSIT_EXIT; @@ -2715,10 +2737,10 @@ public class WindowManagerService extends IWindowManager.Stub if (win.mSurface == null || (win.getAttrs().flags & WindowManager.LayoutParams.FLAG_KEEP_SURFACE_WHILE_ANIMATING) == 0 || win.mSurfacePendingDestroy) { - // We are being called from a local process, which + // We could be called from a local process, which // means outSurface holds its current surface. Ensure the - // surface object is cleared, but we don't want it actually - // destroyed at this point. + // surface object is cleared, but we don't necessarily want + // it actually destroyed at this point. win.mSurfacePendingDestroy = false; outSurface.release(); if (DEBUG_VISIBILITY) Slog.i(TAG, "Releasing surface in: " + win); @@ -2760,7 +2782,7 @@ public class WindowManagerService extends IWindowManager.Stub } mLayoutNeeded = true; - win.mGivenInsetsPending = insetsPending; + win.mGivenInsetsPending = (flags&WindowManagerImpl.RELAYOUT_INSETS_PENDING) != 0; if (assignLayers) { assignLayersLocked(); } @@ -2797,8 +2819,25 @@ public class WindowManagerService extends IWindowManager.Stub Binder.restoreCallingIdentity(origId); - return (inTouchMode ? WindowManagerImpl.RELAYOUT_IN_TOUCH_MODE : 0) - | (displayed ? WindowManagerImpl.RELAYOUT_FIRST_TIME : 0); + return (inTouchMode ? WindowManagerImpl.RELAYOUT_RES_IN_TOUCH_MODE : 0) + | (displayed ? WindowManagerImpl.RELAYOUT_RES_FIRST_TIME : 0) + | (surfaceChanged ? WindowManagerImpl.RELAYOUT_RES_SURFACE_CHANGED : 0); + } + + public void performDeferredDestroyWindow(Session session, IWindow client) { + long origId = Binder.clearCallingIdentity(); + + try { + synchronized(mWindowMap) { + WindowState win = windowForClientLocked(session, client, false); + if (win == null) { + return; + } + win.destroyDeferredSurfaceLocked(); + } + } finally { + Binder.restoreCallingIdentity(origId); + } } public boolean outOfMemoryWindow(Session session, IWindow client) { @@ -3738,7 +3777,7 @@ public class WindowManagerService extends IWindowManager.Stub return; } - // If this is a translucent or wallpaper window, then don't + // If this is a translucent window, then don't // show a starting window -- the current effect (a full-screen // opaque starting window that fades away to the real contents // when it is ready) does not work for this. @@ -3755,7 +3794,16 @@ public class WindowManagerService extends IWindowManager.Stub } if (ent.array.getBoolean( com.android.internal.R.styleable.Window_windowShowWallpaper, false)) { - return; + if (mWallpaperTarget == null) { + // If this theme is requesting a wallpaper, and the wallpaper + // is not curently visible, then this effectively serves as + // an opaque window and our starting window transition animation + // can still work. We just need to make sure the starting window + // is also showing the wallpaper. + windowFlags |= WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER; + } else { + return; + } } } @@ -5971,25 +6019,27 @@ public class WindowManagerService extends IWindowManager.Stub final int realdw = rotated ? mBaseDisplayHeight : mBaseDisplayWidth; final int realdh = rotated ? mBaseDisplayWidth : mBaseDisplayHeight; - if (mAltOrientation) { - mCurDisplayWidth = realdw; - mCurDisplayHeight = realdh; - if (realdw > realdh) { - // Turn landscape into portrait. - int maxw = (int)(realdh/1.3f); - if (maxw < realdw) { - mCurDisplayWidth = maxw; + synchronized(mDisplaySizeLock) { + if (mAltOrientation) { + mCurDisplayWidth = realdw; + mCurDisplayHeight = realdh; + if (realdw > realdh) { + // Turn landscape into portrait. + int maxw = (int)(realdh/1.3f); + if (maxw < realdw) { + mCurDisplayWidth = maxw; + } + } else { + // Turn portrait into landscape. + int maxh = (int)(realdw/1.3f); + if (maxh < realdh) { + mCurDisplayHeight = maxh; + } } } else { - // Turn portrait into landscape. - int maxh = (int)(realdw/1.3f); - if (maxh < realdh) { - mCurDisplayHeight = maxh; - } + mCurDisplayWidth = realdw; + mCurDisplayHeight = realdh; } - } else { - mCurDisplayWidth = realdw; - mCurDisplayHeight = realdh; } final int dw = mCurDisplayWidth; @@ -6008,8 +6058,12 @@ public class WindowManagerService extends IWindowManager.Stub // Update application display metrics. final DisplayMetrics dm = mDisplayMetrics; - mAppDisplayWidth = mPolicy.getNonDecorDisplayWidth(dw, dh, mRotation); - mAppDisplayHeight = mPolicy.getNonDecorDisplayHeight(dw, dh, mRotation); + final int appWidth = mPolicy.getNonDecorDisplayWidth(dw, dh, mRotation); + final int appHeight = mPolicy.getNonDecorDisplayHeight(dw, dh, mRotation); + synchronized(mDisplaySizeLock) { + mAppDisplayWidth = appWidth; + mAppDisplayHeight = appHeight; + } if (false) { Slog.i(TAG, "Set app display size: " + mAppDisplayWidth + " x " + mAppDisplayHeight); @@ -6379,18 +6433,20 @@ public class WindowManagerService extends IWindowManager.Stub } WindowManager wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE); mDisplay = wm.getDefaultDisplay(); - mInitialDisplayWidth = mDisplay.getRawWidth(); - mInitialDisplayHeight = mDisplay.getRawHeight(); - int rot = mDisplay.getRotation(); - if (rot == Surface.ROTATION_90 || rot == Surface.ROTATION_270) { - // If the screen is currently rotated, we need to swap the - // initial width and height to get the true natural values. - int tmp = mInitialDisplayWidth; - mInitialDisplayWidth = mInitialDisplayHeight; - mInitialDisplayHeight = tmp; - } - mBaseDisplayWidth = mCurDisplayWidth = mAppDisplayWidth = mInitialDisplayWidth; - mBaseDisplayHeight = mCurDisplayHeight = mAppDisplayHeight = mInitialDisplayHeight; + synchronized(mDisplaySizeLock) { + mInitialDisplayWidth = mDisplay.getRawWidth(); + mInitialDisplayHeight = mDisplay.getRawHeight(); + int rot = mDisplay.getRotation(); + if (rot == Surface.ROTATION_90 || rot == Surface.ROTATION_270) { + // If the screen is currently rotated, we need to swap the + // initial width and height to get the true natural values. + int tmp = mInitialDisplayWidth; + mInitialDisplayWidth = mInitialDisplayHeight; + mInitialDisplayHeight = tmp; + } + mBaseDisplayWidth = mCurDisplayWidth = mAppDisplayWidth = mInitialDisplayWidth; + mBaseDisplayHeight = mCurDisplayHeight = mAppDisplayHeight = mInitialDisplayHeight; + } mInputManager.setDisplaySize(Display.DEFAULT_DISPLAY, mDisplay.getRawWidth(), mDisplay.getRawHeight(), mDisplay.getRawExternalWidth(), mDisplay.getRawExternalHeight()); @@ -6928,28 +6984,28 @@ public class WindowManagerService extends IWindowManager.Stub } public void getDisplaySize(Point size) { - synchronized(mWindowMap) { + synchronized(mDisplaySizeLock) { size.x = mAppDisplayWidth; size.y = mAppDisplayHeight; } } public void getRealDisplaySize(Point size) { - synchronized(mWindowMap) { + synchronized(mDisplaySizeLock) { size.x = mCurDisplayWidth; size.y = mCurDisplayHeight; } } public void getInitialDisplaySize(Point size) { - synchronized(mWindowMap) { + synchronized(mDisplaySizeLock) { size.x = mInitialDisplayWidth; size.y = mInitialDisplayHeight; } } public int getMaximumSizeDimension() { - synchronized(mWindowMap) { + synchronized(mDisplaySizeLock) { // Do this based on the raw screen size, until we are smarter. return mBaseDisplayWidth > mBaseDisplayHeight ? mBaseDisplayWidth : mBaseDisplayHeight; @@ -7042,8 +7098,10 @@ public class WindowManagerService extends IWindowManager.Stub private void setForcedDisplaySizeLocked(int width, int height) { Slog.i(TAG, "Using new display size: " + width + "x" + height); - mBaseDisplayWidth = width; - mBaseDisplayHeight = height; + synchronized(mDisplaySizeLock) { + mBaseDisplayWidth = width; + mBaseDisplayHeight = height; + } mPolicy.setInitialDisplaySize(mBaseDisplayWidth, mBaseDisplayHeight); mLayoutNeeded = true; @@ -7659,7 +7717,8 @@ public class WindowManagerService extends IWindowManager.Stub // a detached wallpaper animation. if (nowAnimating) { if (w.mAnimation != null) { - if (w.mAnimation.getDetachWallpaper()) { + if ((w.mAttrs.flags&FLAG_SHOW_WALLPAPER) != 0 + && w.mAnimation.getDetachWallpaper()) { windowDetachedWallpaper = w; } if (w.mAnimation.getBackgroundColor() != 0) { @@ -7679,7 +7738,8 @@ public class WindowManagerService extends IWindowManager.Stub // displayed behind it. if (w.mAppToken != null && w.mAppToken.animation != null && w.mAppToken.animating) { - if (w.mAppToken.animation.getDetachWallpaper()) { + if ((w.mAttrs.flags&FLAG_SHOW_WALLPAPER) != 0 + && w.mAppToken.animation.getDetachWallpaper()) { windowDetachedWallpaper = w; } if (w.mAppToken.animation.getBackgroundColor() != 0) { diff --git a/services/java/com/android/server/wm/WindowState.java b/services/java/com/android/server/wm/WindowState.java index 23ec2d9f578d..aa7bf2d1b7ce 100644 --- a/services/java/com/android/server/wm/WindowState.java +++ b/services/java/com/android/server/wm/WindowState.java @@ -85,6 +85,7 @@ final class WindowState implements WindowManagerPolicy.WindowState { boolean mPolicyVisibilityAfterAnim = true; boolean mAppFreezing; Surface mSurface; + Surface mPendingDestroySurface; boolean mReportDestroySurface; boolean mSurfacePendingDestroy; boolean mAttachedHidden; // is our parent window hidden? @@ -121,7 +122,13 @@ final class WindowState implements WindowManagerPolicy.WindowState { * we must tell them application to resize (and thus redraw itself). */ boolean mSurfaceResized; - + + /** + * Set if the client has asked that the destroy of its surface be delayed + * until it explicitly says it is okay. + */ + boolean mSurfaceDestroyDeferred; + /** * Insets that determine the actually visible area. These are in the application's * coordinate space (without compatibility scale applied). @@ -764,15 +771,32 @@ final class WindowState implements WindowManagerPolicy.WindowState { Slog.w(WindowManagerService.TAG, "Window " + this + " destroying surface " + mSurface + ", session " + mSession, e); } - if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) { - RuntimeException e = null; - if (!WindowManagerService.HIDE_STACK_CRAWLS) { - e = new RuntimeException(); - e.fillInStackTrace(); + if (mSurfaceDestroyDeferred) { + if (mSurface != null && mPendingDestroySurface != mSurface) { + if (mPendingDestroySurface != null) { + if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) { + RuntimeException e = null; + if (!WindowManagerService.HIDE_STACK_CRAWLS) { + e = new RuntimeException(); + e.fillInStackTrace(); + } + WindowManagerService.logSurface(this, "DESTROY PENDING", e); + } + mPendingDestroySurface.destroy(); + } + mPendingDestroySurface = mSurface; } - WindowManagerService.logSurface(this, "DESTROY", e); + } else { + if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) { + RuntimeException e = null; + if (!WindowManagerService.HIDE_STACK_CRAWLS) { + e = new RuntimeException(); + e.fillInStackTrace(); + } + WindowManagerService.logSurface(this, "DESTROY", e); + } + mSurface.destroy(); } - mSurface.destroy(); } catch (RuntimeException e) { Slog.w(WindowManagerService.TAG, "Exception thrown when destroying Window " + this + " surface " + mSurface + " session " + mSession @@ -784,6 +808,28 @@ final class WindowState implements WindowManagerPolicy.WindowState { } } + void destroyDeferredSurfaceLocked() { + try { + if (mPendingDestroySurface != null) { + if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) { + RuntimeException e = null; + if (!WindowManagerService.HIDE_STACK_CRAWLS) { + e = new RuntimeException(); + e.fillInStackTrace(); + } + mService.logSurface(this, "DESTROY PENDING", e); + } + mPendingDestroySurface.destroy(); + } + } catch (RuntimeException e) { + Slog.w(WindowManagerService.TAG, "Exception thrown when destroying Window " + + this + " surface " + mPendingDestroySurface + + " session " + mSession + ": " + e.toString()); + } + mSurfaceDestroyDeferred = false; + mPendingDestroySurface = null; + } + boolean finishDrawingLocked() { if (mDrawPending) { if (SHOW_TRANSACTIONS || WindowManagerService.DEBUG_ORIENTATION) Slog.v( @@ -977,6 +1023,9 @@ final class WindowState implements WindowManagerPolicy.WindowState { mAnimation.cancel(); mAnimation = null; } + if (mService.mWindowDetachedWallpaper == this) { + mService.mWindowDetachedWallpaper = null; + } mAnimLayer = mLayer; if (mIsImWindow) { mAnimLayer += mService.mInputMethodAnimLayerAdjustment; @@ -1415,6 +1464,7 @@ final class WindowState implements WindowManagerPolicy.WindowState { if (WindowManagerService.DEBUG_ADD_REMOVE) Slog.v(WindowManagerService.TAG, "Removing " + this + " from " + mAttachedWindow); mAttachedWindow.mChildWindows.remove(this); } + destroyDeferredSurfaceLocked(); destroySurfaceLocked(); mSession.windowRemovedLocked(); try { @@ -1612,6 +1662,10 @@ final class WindowState implements WindowManagerPolicy.WindowState { pw.print(") "); pw.print(mSurfaceW); pw.print(" x "); pw.println(mSurfaceH); } + if (mPendingDestroySurface != null) { + pw.print(prefix); pw.print("mPendingDestroySurface="); + pw.println(mPendingDestroySurface); + } if (dumpAll) { pw.print(prefix); pw.print("mToken="); pw.println(mToken); pw.print(prefix); pw.print("mRootToken="); pw.println(mRootToken); @@ -1640,6 +1694,10 @@ final class WindowState implements WindowManagerPolicy.WindowState { if (!mRelayoutCalled) { pw.print(prefix); pw.print("mRelayoutCalled="); pw.println(mRelayoutCalled); } + if (mSurfaceResized || mSurfaceDestroyDeferred) { + pw.print(prefix); pw.print("mSurfaceResized="); pw.print(mSurfaceResized); + pw.print(" mSurfaceDestroyDeferred="); pw.println(mSurfaceDestroyDeferred); + } if (mXOffset != 0 || mYOffset != 0) { pw.print(prefix); pw.print("Offsets x="); pw.print(mXOffset); pw.print(" y="); pw.println(mYOffset); diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk index 61a8358332eb..f63c0c12c22c 100644 --- a/services/surfaceflinger/Android.mk +++ b/services/surfaceflinger/Android.mk @@ -28,6 +28,7 @@ ifeq ($(TARGET_BOARD_PLATFORM), omap4) endif ifeq ($(TARGET_BOARD_PLATFORM), s5pc110) LOCAL_CFLAGS += -DHAS_CONTEXT_PRIORITY -DNEVER_DEFAULT_TO_ASYNC_MODE + LOCAL_CFLAGS += -DREFRESH_RATE=56 endif diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 1b00e9380a62..24bd2a63ed61 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -65,6 +65,8 @@ #define AID_GRAPHICS 1003 #endif +#define EGL_VERSION_HW_ANDROID 0x3143 + #define DISPLAY_COUNT 1 namespace android { @@ -708,6 +710,14 @@ void SurfaceFlinger::computeVisibleRegions( void SurfaceFlinger::commitTransaction() { + if (!mLayersPendingRemoval.isEmpty()) { + // Notify removed layers now that they can't be drawn from + for (size_t i = 0; i < mLayersPendingRemoval.size(); i++) { + mLayersPendingRemoval[i]->onRemoved(); + } + mLayersPendingRemoval.clear(); + } + mDrawingState = mCurrentState; mTransationPending = false; mTransactionCV.broadcast(); @@ -1160,7 +1170,7 @@ status_t SurfaceFlinger::purgatorizeLayer_l(const sp<LayerBase>& layerBase) mLayerPurgatory.add(layerBase); } - layerBase->onRemoved(); + mLayersPendingRemoval.push(layerBase); // it's possible that we don't find a layer, because it might // have been destroyed already -- this is not technically an error @@ -1527,7 +1537,7 @@ status_t SurfaceFlinger::dump(int fd, const Vector<String16>& args) * Dump the layers in the purgatory */ - const size_t purgatorySize = mLayerPurgatory.size(); + const size_t purgatorySize = mLayerPurgatory.size(); snprintf(buffer, SIZE, "Purgatory state (%d entries)\n", purgatorySize); result.append(buffer); for (size_t i=0 ; i<purgatorySize ; i++) { @@ -1548,6 +1558,12 @@ status_t SurfaceFlinger::dump(int fd, const Vector<String16>& args) extensions.getRenderer(), extensions.getVersion()); result.append(buffer); + + snprintf(buffer, SIZE, "EGL : %s\n", + eglQueryString(graphicPlane(0).getEGLDisplay(), + EGL_VERSION_HW_ANDROID)); + result.append(buffer); + snprintf(buffer, SIZE, "EXTS: %s\n", extensions.getExtension()); result.append(buffer); diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 17028dbb64fa..17b80a6ed2a0 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -345,6 +345,7 @@ private: Condition mTransactionCV; SortedVector< sp<LayerBase> > mLayerPurgatory; bool mTransationPending; + Vector< sp<LayerBase> > mLayersPendingRemoval; // protected by mStateLock (but we could use another lock) GraphicPlane mGraphicPlanes[1]; diff --git a/services/surfaceflinger/SurfaceTextureLayer.cpp b/services/surfaceflinger/SurfaceTextureLayer.cpp index 4390ca19fc24..5020e0007ae7 100644 --- a/services/surfaceflinger/SurfaceTextureLayer.cpp +++ b/services/surfaceflinger/SurfaceTextureLayer.cpp @@ -28,7 +28,7 @@ namespace android { SurfaceTextureLayer::SurfaceTextureLayer(GLuint tex, const sp<Layer>& layer) - : SurfaceTexture(tex), mLayer(layer) { + : SurfaceTexture(tex, true, GL_TEXTURE_EXTERNAL_OES, false), mLayer(layer) { } SurfaceTextureLayer::~SurfaceTextureLayer() { diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java index 56a0a2c05022..07afe3077ff2 100644 --- a/telephony/java/android/telephony/PhoneNumberUtils.java +++ b/telephony/java/android/telephony/PhoneNumberUtils.java @@ -2118,6 +2118,31 @@ public class PhoneNumberUtils } /** + * @return the "username" part of the specified SIP address, + * i.e. the part before the "@" character (or "%40"). + * + * @param number SIP address of the form "username@domainname" + * (or the URI-escaped equivalent "username%40domainname") + * @see isUriNumber + * + * @hide + */ + public static String getUsernameFromUriNumber(String number) { + // The delimiter between username and domain name can be + // either "@" or "%40" (the URI-escaped equivalent.) + int delimiterIndex = number.indexOf('@'); + if (delimiterIndex < 0) { + delimiterIndex = number.indexOf("%40"); + } + if (delimiterIndex < 0) { + Log.w(LOG_TAG, + "getUsernameFromUriNumber: no delimiter found in SIP addr '" + number + "'"); + delimiterIndex = number.length(); + } + return number.substring(0, delimiterIndex); + } + + /** * This function handles the plus code conversion within NANP CDMA network * If the number format is * 1)+1NANP,remove +, diff --git a/telephony/java/com/android/internal/telephony/ApnSetting.java b/telephony/java/com/android/internal/telephony/ApnSetting.java index 002ffad9294f..980bb49550e2 100755 --- a/telephony/java/com/android/internal/telephony/ApnSetting.java +++ b/telephony/java/com/android/internal/telephony/ApnSetting.java @@ -189,4 +189,11 @@ public class ApnSetting { } return false; } + + // TODO - if we have this function we should also have hashCode. + // Also should handle changes in type order and perhaps case-insensitivity + public boolean equals(Object o) { + if (o instanceof ApnSetting == false) return false; + return (this.toString().equals(o.toString())); + } } diff --git a/telephony/java/com/android/internal/telephony/BaseCommands.java b/telephony/java/com/android/internal/telephony/BaseCommands.java index f111dd6341fe..07b61836e4a6 100644 --- a/telephony/java/com/android/internal/telephony/BaseCommands.java +++ b/telephony/java/com/android/internal/telephony/BaseCommands.java @@ -683,6 +683,13 @@ public abstract class BaseCommands implements CommandsInterface { mRilConnectedRegistrants.remove(h); } + /** + * {@inheritDoc} + */ + @Override + public void setCurrentPreferredNetworkType() { + } + //***** Protected Methods /** * Store new RadioState and send notification based on the changes diff --git a/telephony/java/com/android/internal/telephony/CallerInfo.java b/telephony/java/com/android/internal/telephony/CallerInfo.java index 6324550cc1df..5d1f7588a584 100644 --- a/telephony/java/com/android/internal/telephony/CallerInfo.java +++ b/telephony/java/com/android/internal/telephony/CallerInfo.java @@ -288,7 +288,7 @@ public class CallerInfo { String number, CallerInfo previousResult) { if (!previousResult.contactExists && PhoneNumberUtils.isUriNumber(number)) { - String username = number.substring(0, number.indexOf('@')); + String username = PhoneNumberUtils.getUsernameFromUriNumber(number); if (PhoneNumberUtils.isGlobalPhoneNumber(username)) { previousResult = getCallerInfo(context, Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, diff --git a/telephony/java/com/android/internal/telephony/CommandsInterface.java b/telephony/java/com/android/internal/telephony/CommandsInterface.java index 33ead75e8008..d6e6ae05b854 100644 --- a/telephony/java/com/android/internal/telephony/CommandsInterface.java +++ b/telephony/java/com/android/internal/telephony/CommandsInterface.java @@ -1311,6 +1311,12 @@ public interface CommandsInterface { void queryAvailableBandMode (Message response); /** + * Set the current preferred network type. This will be the last + * networkType that was passed to setPreferredNetworkType. + */ + void setCurrentPreferredNetworkType(); + + /** * Requests to set the preferred network type for searching and registering * (CS/PS domain, RAT, and operation mode) * @param networkType one of NT_*_TYPE diff --git a/telephony/java/com/android/internal/telephony/DataCallState.java b/telephony/java/com/android/internal/telephony/DataCallState.java index 6d8956f452b7..efbf608d9020 100644 --- a/telephony/java/com/android/internal/telephony/DataCallState.java +++ b/telephony/java/com/android/internal/telephony/DataCallState.java @@ -126,6 +126,8 @@ public class DataCallState { // set link addresses if (addresses != null && addresses.length > 0) { for (String addr : addresses) { + addr = addr.trim(); + if (addr.isEmpty()) continue; LinkAddress la; int addrPrefixLen; @@ -159,6 +161,8 @@ public class DataCallState { // set dns servers if (dnses != null && dnses.length > 0) { for (String addr : dnses) { + addr = addr.trim(); + if (addr.isEmpty()) continue; InetAddress ia; try { ia = NetworkUtils.numericToInetAddress(addr); @@ -174,6 +178,8 @@ public class DataCallState { dnsServers[0] = SystemProperties.get(propertyPrefix + "dns1"); dnsServers[1] = SystemProperties.get(propertyPrefix + "dns2"); for (String dnsAddr : dnsServers) { + dnsAddr = dnsAddr.trim(); + if (dnsAddr.isEmpty()) continue; InetAddress ia; try { ia = NetworkUtils.numericToInetAddress(dnsAddr); @@ -198,6 +204,8 @@ public class DataCallState { } } for (String addr : gateways) { + addr = addr.trim(); + if (addr.isEmpty()) continue; InetAddress ia; try { ia = NetworkUtils.numericToInetAddress(addr); diff --git a/telephony/java/com/android/internal/telephony/DataConnection.java b/telephony/java/com/android/internal/telephony/DataConnection.java index 636646eef1d1..461989927d44 100644 --- a/telephony/java/com/android/internal/telephony/DataConnection.java +++ b/telephony/java/com/android/internal/telephony/DataConnection.java @@ -699,8 +699,10 @@ public abstract class DataConnection extends StateMachine { break; case EVENT_DISCONNECT: - if (DBG) log("DcDefaultState: msg.what=EVENT_DISCONNECT"); - notifyDisconnectCompleted((DisconnectParams) msg.obj); + if (DBG) { + log("DcDefaultState deferring msg.what=EVENT_DISCONNECT" + mRefCount); + } + deferMessage(msg); break; case EVENT_RIL_CONNECTED: @@ -807,6 +809,12 @@ public abstract class DataConnection extends StateMachine { retVal = HANDLED; break; + case EVENT_DISCONNECT: + if (DBG) log("DcInactiveState: msg.what=EVENT_DISCONNECT"); + notifyDisconnectCompleted((DisconnectParams)msg.obj); + retVal = HANDLED; + break; + default: if (VDBG) { log("DcInactiveState nothandled msg.what=0x" + @@ -831,13 +839,6 @@ public abstract class DataConnection extends StateMachine { ConnectionParams cp; switch (msg.what) { - case EVENT_DISCONNECT: - if (DBG) log("DcActivatingState deferring msg.what=EVENT_DISCONNECT" - + mRefCount); - deferMessage(msg); - retVal = HANDLED; - break; - case EVENT_CONNECT: if (DBG) log("DcActivatingState deferring msg.what=EVENT_CONNECT refCount = " + mRefCount); diff --git a/telephony/java/com/android/internal/telephony/RIL.java b/telephony/java/com/android/internal/telephony/RIL.java index 9f93fb8d7c78..f2e7f45923aa 100644 --- a/telephony/java/com/android/internal/telephony/RIL.java +++ b/telephony/java/com/android/internal/telephony/RIL.java @@ -1823,6 +1823,16 @@ public final class RIL extends BaseCommands implements CommandsInterface { /** * {@inheritDoc} */ + @Override + public void setCurrentPreferredNetworkType() { + if (RILJ_LOGD) riljLog("setCurrentPreferredNetworkType: " + mSetPreferredNetworkType); + setPreferredNetworkType(mSetPreferredNetworkType, null); + } + private int mSetPreferredNetworkType; + + /** + * {@inheritDoc} + */ public void setPreferredNetworkType(int networkType , Message response) { RILRequest rr = RILRequest.obtain( RILConstants.RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE, response); @@ -1830,6 +1840,7 @@ public final class RIL extends BaseCommands implements CommandsInterface { rr.mp.writeInt(1); rr.mp.writeInt(networkType); + mSetPreferredNetworkType = networkType; mPreferredNetworkType = networkType; if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java index 3d6cd6821c40..d939e9834181 100755 --- a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java +++ b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java @@ -257,6 +257,9 @@ public class CdmaServiceStateTracker extends ServiceStateTracker { break; case EVENT_RUIM_READY: + // TODO: Consider calling setCurrentPreferredNetworkType as we do in GsmSST. + // cm.setCurrentPreferredNetworkType(); + // The RUIM is now ready i.e if it was locked it has been // unlocked. At this stage, the radio is already powered on. isSubscriptionFromRuim = true; @@ -277,6 +280,9 @@ public class CdmaServiceStateTracker extends ServiceStateTracker { break; case EVENT_NV_READY: + // TODO: Consider calling setCurrentPreferredNetworkType as we do in GsmSST. + // cm.setCurrentPreferredNetworkType(); + isSubscriptionFromRuim = false; // For Non-RUIM phones, the subscription information is stored in // Non Volatile. Here when Non-Volatile is ready, we can poll the CDMA diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java index 7cd01a167d78..963db2c6809d 100644 --- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java +++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java @@ -914,10 +914,16 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.NUMERIC)), cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.NAME)), cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.APN)), - cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.PROXY)), + NetworkUtils.trimV4AddrZeros( + cursor.getString( + cursor.getColumnIndexOrThrow(Telephony.Carriers.PROXY))), cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.PORT)), - cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSC)), - cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSPROXY)), + NetworkUtils.trimV4AddrZeros( + cursor.getString( + cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSC))), + NetworkUtils.trimV4AddrZeros( + cursor.getString( + cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSPROXY))), cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSPORT)), cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.USER)), cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.PASSWORD)), @@ -1720,11 +1726,25 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { private DataConnection checkForConnectionForApnContext(ApnContext apnContext) { // Loop through all apnContexts looking for one with a conn that satisfies this apnType String apnType = apnContext.getApnType(); + ApnSetting dunSetting = null; + + if (Phone.APN_TYPE_DUN.equals(apnType)) { + dunSetting = fetchDunApn(); + } + for (ApnContext c : mApnContexts.values()) { DataConnection conn = c.getDataConnection(); if (conn != null) { ApnSetting apnSetting = c.getApnSetting(); - if (apnSetting != null && apnSetting.canHandleType(apnType)) { + if (dunSetting != null) { + if (dunSetting.equals(apnSetting)) { + if (DBG) { + log("checkForConnectionForApnContext: apnContext=" + apnContext + + " found conn=" + conn); + } + return conn; + } + } else if (apnSetting != null && apnSetting.canHandleType(apnType)) { if (DBG) { log("checkForConnectionForApnContext: apnContext=" + apnContext + " found conn=" + conn); @@ -1848,8 +1868,14 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { DataConnection dc = apnContext.getDataConnection(); if (DBG) { - log(String.format("onDataSetupComplete: success apn=%s", - apnContext.getWaitingApns().get(0).apn)); + // TODO We may use apnContext.getApnSetting() directly + // instead of getWaitingApns().get(0) + String apnStr = "<unknown>"; + if (apnContext.getWaitingApns() != null + && !apnContext.getWaitingApns().isEmpty()){ + apnStr = apnContext.getWaitingApns().get(0).apn; + } + log("onDataSetupComplete: success apn=" + apnStr); } ApnSetting apn = apnContext.getApnSetting(); if (apn.proxy != null && apn.proxy.length() != 0) { diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmMmiCode.java b/telephony/java/com/android/internal/telephony/gsm/GsmMmiCode.java index 37998949219f..16d3129acf0a 100644 --- a/telephony/java/com/android/internal/telephony/gsm/GsmMmiCode.java +++ b/telephony/java/com/android/internal/telephony/gsm/GsmMmiCode.java @@ -132,7 +132,7 @@ public final class GsmMmiCode extends Handler implements MmiCode { // See TS 22.030 6.5.2 "Structure of the MMI" static Pattern sPatternSuppService = Pattern.compile( - "((\\*|#|\\*#|\\*\\*|##)(\\d{2,3})(\\*([^*#]*)(\\*([^*#]*)(\\*([^*#]*)(\\*([^*#]*))?)?)?)?#)(.*)"); + "((\\*|#|\\*#|\\*\\*|##)(\\d{2,3})(\\*([^*#]*)(\\*([^*#]*)(\\*([^*#]*)(\\*([^*#]*))?)?)?)?#)([^#]*)"); /* 1 2 3 4 5 6 7 8 9 10 11 12 1 = Full string up to and including # @@ -141,7 +141,7 @@ public final class GsmMmiCode extends Handler implements MmiCode { 5 = SIA 7 = SIB 9 = SIC - 10 = dialing number + 10 = dialing number which must not include #, e.g. *SCn*SI#DN format */ static final int MATCH_GROUP_POUND_STRING = 1; @@ -1338,4 +1338,20 @@ public final class GsmMmiCode extends Handler implements MmiCode { * SpecialCharSequenceMgr class. */ + @Override + public String toString() { + StringBuilder sb = new StringBuilder("GsmMmiCode {"); + + sb.append("State=" + getState()); + if (action != null) sb.append(" action=" + action); + if (sc != null) sb.append(" sc=" + sc); + if (sia != null) sb.append(" sia=" + sia); + if (sib != null) sb.append(" sib=" + sib); + if (sic != null) sb.append(" sic=" + sic); + if (poundString != null) sb.append(" poundString=" + poundString); + if (dialingNumber != null) sb.append(" dialingNumber=" + dialingNumber); + if (pwd != null) sb.append(" pwd=" + pwd); + sb.append("}"); + return sb.toString(); + } } diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java index eea2780fb3df..84127cff8c63 100644 --- a/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java +++ b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java @@ -270,6 +270,9 @@ final class GsmServiceStateTracker extends ServiceStateTracker { break; case EVENT_SIM_READY: + // Set the network type, in case the radio does not restore it. + cm.setCurrentPreferredNetworkType(); + // The SIM is now ready i.e if it was locked // it has been unlocked. At this stage, the radio is already // powered on. diff --git a/tests/FrameworkPerf/Android.mk b/tests/FrameworkPerf/Android.mk index 03893d6254c5..2eb52f0ecf81 100644 --- a/tests/FrameworkPerf/Android.mk +++ b/tests/FrameworkPerf/Android.mk @@ -7,6 +7,8 @@ LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := FrameworkPerf +LOCAL_JAVA_LIBRARIES := android.test.runner + LOCAL_AAPT_FLAGS = -c 120dpi,240dpi,160dpi,161dpi,320dpi,nodpi include $(BUILD_PACKAGE) diff --git a/tests/FrameworkPerf/AndroidManifest.xml b/tests/FrameworkPerf/AndroidManifest.xml index e88f4fb6e02f..2591aaf8f1a6 100644 --- a/tests/FrameworkPerf/AndroidManifest.xml +++ b/tests/FrameworkPerf/AndroidManifest.xml @@ -4,6 +4,7 @@ <uses-sdk android:minSdkVersion="5" /> <application android:hardwareAccelerated="false"> + <uses-library android:name="android.test.runner" /> <activity android:name="FrameworkPerfActivity" android:label="Framework Perf"> <intent-filter> <action android:name="android.intent.action.MAIN" /> @@ -20,4 +21,9 @@ <receiver android:name="Receiver" android:exported="true"> </receiver> </application> + + <instrumentation android:name="android.test.InstrumentationTestRunner" + android:targetPackage="com.android.frameworkperf" + android:label="Framework Perf Runner" + /> </manifest> diff --git a/tests/FrameworkPerf/res/layout/main.xml b/tests/FrameworkPerf/res/layout/main.xml index 781264881ceb..e00ad924cd36 100644 --- a/tests/FrameworkPerf/res/layout/main.xml +++ b/tests/FrameworkPerf/res/layout/main.xml @@ -66,7 +66,24 @@ > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:textAppearance="?android:attr/textAppearanceMedium" + android:text="Limit by: " + /> + <Spinner android:id="@+id/limitspinner" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:drawSelectorOnTop="true" + /> + </LinearLayout> + + <LinearLayout android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="horizontal" + android:layout_marginTop="10dp" + > + <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" + android:textAppearance="?android:attr/textAppearanceMedium" android:text="Test time (ms): " + android:id="@+id/limitlabel" /> <EditText android:id="@+id/testtime" android:layout_width="match_parent" diff --git a/tests/FrameworkPerf/src/com/android/frameworkperf/FrameworkPerfActivity.java b/tests/FrameworkPerf/src/com/android/frameworkperf/FrameworkPerfActivity.java index 175f227f7e0f..30a968ffd33d 100644 --- a/tests/FrameworkPerf/src/com/android/frameworkperf/FrameworkPerfActivity.java +++ b/tests/FrameworkPerf/src/com/android/frameworkperf/FrameworkPerfActivity.java @@ -50,6 +50,8 @@ public class FrameworkPerfActivity extends Activity Spinner mFgSpinner; Spinner mBgSpinner; + Spinner mLimitSpinner; + TextView mLimitLabel; TextView mTestTime; Button mStartButton; Button mStopButton; @@ -58,10 +60,12 @@ public class FrameworkPerfActivity extends Activity PowerManager.WakeLock mPartialWakeLock; long mMaxRunTime = 5000; + boolean mLimitIsIterations; boolean mStarted; final String[] mAvailOpLabels; final String[] mAvailOpDescriptions; + final String[] mLimitLabels = { "Time", "Iterations" }; int mFgTestIndex = -1; int mBgTestIndex = -1; @@ -73,6 +77,8 @@ public class FrameworkPerfActivity extends Activity final ArrayList<RunResult> mResults = new ArrayList<RunResult>(); + Object mResultNotifier = new Object(); + class TestConnection implements ServiceConnection, IBinder.DeathRecipient { Messenger mService; boolean mLinked; @@ -167,8 +173,15 @@ public class FrameworkPerfActivity extends Activity adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); mBgSpinner.setAdapter(adapter); mBgSpinner.setOnItemSelectedListener(this); + mLimitSpinner = (Spinner) findViewById(R.id.limitspinner); + adapter = new ArrayAdapter<String>(this, + android.R.layout.simple_spinner_item, mLimitLabels); + adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); + mLimitSpinner.setAdapter(adapter); + mLimitSpinner.setOnItemSelectedListener(this); mTestTime = (TextView)findViewById(R.id.testtime); + mLimitLabel = (TextView)findViewById(R.id.limitlabel); mStartButton = (Button)findViewById(R.id.start); mStartButton.setOnClickListener(new View.OnClickListener() { @@ -194,16 +207,23 @@ public class FrameworkPerfActivity extends Activity @Override public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { - if (parent == mFgSpinner || parent == mBgSpinner) { + if (parent == mFgSpinner || parent == mBgSpinner || parent == mLimitSpinner) { TestService.Op op = TestService.mAvailOps[position]; if (parent == mFgSpinner) { mFgTestIndex = position; mFgTest = op; ((TextView)findViewById(R.id.fgtext)).setText(mAvailOpDescriptions[position]); - } else { + } else if (parent == mBgSpinner) { mBgTestIndex = position; mBgTest = op; ((TextView)findViewById(R.id.bgtext)).setText(mAvailOpDescriptions[position]); + } else if (parent == mLimitSpinner) { + mLimitIsIterations = (position != 0); + if (mLimitIsIterations) { + mLimitLabel.setText("Iterations: "); + } else { + mLimitLabel.setText("Test time (ms): "); + } } } } @@ -232,7 +252,11 @@ public class FrameworkPerfActivity extends Activity return; } TestArgs args = new TestArgs(); - args.maxTime = mMaxRunTime; + if (mLimitIsIterations) { + args.maxOps = mMaxRunTime; + } else { + args.maxTime = mMaxRunTime; + } if (mFgTestIndex == 0 && mBgTestIndex == 0) { args.combOp = mCurOpIndex; } else if (mFgTestIndex != 0 && mBgTestIndex != 0) { @@ -266,7 +290,9 @@ public class FrameworkPerfActivity extends Activity log(String.format("%s: fg=%d*%gms/op (%dms) / bg=%d*%gms/op (%dms)", result.name, result.fgOps, result.getFgMsPerOp(), result.fgTime, result.bgOps, result.getBgMsPerOp(), result.bgTime)); - mResults.add(result); + synchronized (mResults) { + mResults.add(result); + } if (!mStarted) { log("Stop"); stopRunning(); @@ -372,11 +398,14 @@ public class FrameworkPerfActivity extends Activity mTestTime.setEnabled(false); mFgSpinner.setEnabled(false); mBgSpinner.setEnabled(false); + mLimitSpinner.setEnabled(false); updateWakeLock(); startService(new Intent(this, SchedulerService.class)); mCurOpIndex = 0; mMaxRunTime = Integer.parseInt(mTestTime.getText().toString()); - mResults.clear(); + synchronized (mResults) { + mResults.clear(); + } startCurOp(); } } @@ -391,19 +420,25 @@ public class FrameworkPerfActivity extends Activity mTestTime.setEnabled(true); mFgSpinner.setEnabled(true); mBgSpinner.setEnabled(true); + mLimitSpinner.setEnabled(true); updateWakeLock(); stopService(new Intent(this, SchedulerService.class)); - for (int i=0; i<mResults.size(); i++) { - RunResult result = mResults.get(i); - float fgMsPerOp = result.getFgMsPerOp(); - float bgMsPerOp = result.getBgMsPerOp(); - String fgMsPerOpStr = fgMsPerOp != 0 ? Float.toString(fgMsPerOp) : ""; - String bgMsPerOpStr = bgMsPerOp != 0 ? Float.toString(bgMsPerOp) : ""; - Log.i("PerfRes", "\t" + result.name + "\t" + result.fgOps - + "\t" + result.getFgMsPerOp() + "\t" + result.fgTime - + "\t" + result.fgLongName + "\t" + result.bgOps - + "\t" + result.getBgMsPerOp() + "\t" + result.bgTime - + "\t" + result.bgLongName); + synchronized (mResults) { + for (int i=0; i<mResults.size(); i++) { + RunResult result = mResults.get(i); + float fgMsPerOp = result.getFgMsPerOp(); + float bgMsPerOp = result.getBgMsPerOp(); + String fgMsPerOpStr = fgMsPerOp != 0 ? Float.toString(fgMsPerOp) : ""; + String bgMsPerOpStr = bgMsPerOp != 0 ? Float.toString(bgMsPerOp) : ""; + Log.i("PerfRes", "\t" + result.name + "\t" + result.fgOps + + "\t" + result.getFgMsPerOp() + "\t" + result.fgTime + + "\t" + result.fgLongName + "\t" + result.bgOps + + "\t" + result.getBgMsPerOp() + "\t" + result.bgTime + + "\t" + result.bgLongName); + } + } + synchronized (mResultNotifier) { + mResultNotifier.notifyAll(); } } } diff --git a/tests/FrameworkPerf/src/com/android/frameworkperf/FrameworkPerfTest.java b/tests/FrameworkPerf/src/com/android/frameworkperf/FrameworkPerfTest.java new file mode 100644 index 000000000000..2a53b06e3c36 --- /dev/null +++ b/tests/FrameworkPerf/src/com/android/frameworkperf/FrameworkPerfTest.java @@ -0,0 +1,41 @@ +package com.android.frameworkperf; + +import android.app.Activity; +import android.os.Bundle; +import android.test.ActivityInstrumentationTestCase2; + +public class FrameworkPerfTest extends ActivityInstrumentationTestCase2<FrameworkPerfActivity> { + + private static final int TEST_TIMEOUT = 15 * 60 * 1000; //15 minutes + + public FrameworkPerfTest() { + super("com.android.frameworkperf", FrameworkPerfActivity.class); + } + + public void testFrameworkPerf() { + final FrameworkPerfActivity activity = getActivity(); + synchronized (activity.mResultNotifier) { + getInstrumentation().runOnMainSync(new Runnable() { + @Override + public void run() { + activity.startRunning(); + } + }); + try { + activity.mResultNotifier.wait(TEST_TIMEOUT); + } catch (InterruptedException e) { + fail("test interrupted."); + } + } + Bundle testResult = new Bundle(); + synchronized (activity.mResults) { + assertTrue("test results were empty.", activity.mResults.size() > 0); + for (RunResult result : activity.mResults) { + testResult.putString(result.name, String.format("%f,%d,%d,%f,%d,%d", + result.getFgMsPerOp(), result.fgOps, result.fgTime, + result.getBgMsPerOp(), result.bgOps, result.bgTime)); + } + } + getInstrumentation().sendStatus(Activity.RESULT_OK, testResult); + } +} diff --git a/tests/FrameworkPerf/src/com/android/frameworkperf/TestArgs.java b/tests/FrameworkPerf/src/com/android/frameworkperf/TestArgs.java index f2f7c5675bcf..2fe38aaca5d2 100644 --- a/tests/FrameworkPerf/src/com/android/frameworkperf/TestArgs.java +++ b/tests/FrameworkPerf/src/com/android/frameworkperf/TestArgs.java @@ -21,6 +21,7 @@ import android.os.Parcelable; public class TestArgs implements Parcelable { long maxTime; + long maxOps = -1; int combOp = -1; int fgOp = -1; int bgOp = -1; @@ -30,6 +31,7 @@ public class TestArgs implements Parcelable { public TestArgs(Parcel source) { maxTime = source.readLong(); + maxOps = source.readLong(); combOp = source.readInt(); fgOp = source.readInt(); bgOp = source.readInt(); @@ -43,6 +45,7 @@ public class TestArgs implements Parcelable { @Override public void writeToParcel(Parcel dest, int flags) { dest.writeLong(maxTime); + dest.writeLong(maxOps); dest.writeInt(combOp); dest.writeInt(fgOp); dest.writeInt(bgOp); diff --git a/tests/FrameworkPerf/src/com/android/frameworkperf/TestService.java b/tests/FrameworkPerf/src/com/android/frameworkperf/TestService.java index 8cf1ac2932e3..a8c43e993452 100644 --- a/tests/FrameworkPerf/src/com/android/frameworkperf/TestService.java +++ b/tests/FrameworkPerf/src/com/android/frameworkperf/TestService.java @@ -224,6 +224,7 @@ public class TestService extends Service { public class TestRunner { Handler mHandler; long mMaxRunTime; + long mMaxOps; Op mForegroundOp; Op mBackgroundOp; Runnable mDoneCallback; @@ -277,6 +278,7 @@ public class TestService extends Service { public void run(Handler handler, TestArgs args, Runnable doneCallback) { mHandler = handler; mMaxRunTime = args.maxTime; + mMaxOps = args.maxOps; if (args.combOp >= 0) { mForegroundOp = mOpPairs[args.combOp]; mBackgroundOp = mOpPairs[args.combOp+1]; @@ -352,9 +354,18 @@ public class TestService extends Service { if (!mBackgroundRunning && !mForegroundRunning) { return false; } - long now = SystemClock.uptimeMillis(); - if (now > (mStartTime+mMaxRunTime)) { - return false; + if (mMaxOps > 0) { + // iteration-limited case + if (mForegroundOps >= mMaxOps) { + return false; + } + mForegroundOps++; + } else { + // time-limited case + long now = SystemClock.uptimeMillis(); + if (now > (mStartTime+mMaxRunTime)) { + return false; + } } return true; } diff --git a/tests/StatusBar/res/layout/notification_builder_test.xml b/tests/StatusBar/res/layout/notification_builder_test.xml index e1199c75761e..6c384f70ff7e 100644 --- a/tests/StatusBar/res/layout/notification_builder_test.xml +++ b/tests/StatusBar/res/layout/notification_builder_test.xml @@ -605,6 +605,11 @@ style="@style/FieldContents" android:text="pineapple2" /> + <RadioButton + android:id="@+id/large_icon_small" + style="@style/FieldContents" + android:text="small" + /> </RadioGroup> diff --git a/tests/StatusBar/src/com/android/statusbartest/NotificationBuilderTest.java b/tests/StatusBar/src/com/android/statusbartest/NotificationBuilderTest.java index 5a2ebacefa44..fefd89050ae9 100644 --- a/tests/StatusBar/src/com/android/statusbartest/NotificationBuilderTest.java +++ b/tests/StatusBar/src/com/android/statusbartest/NotificationBuilderTest.java @@ -287,6 +287,9 @@ public class NotificationBuilderTest extends Activity case R.id.large_icon_pineapple2: b.setLargeIcon(loadBitmap(R.drawable.pineapple2)); break; + case R.id.large_icon_small: + b.setLargeIcon(loadBitmap(R.drawable.icon2)); + break; } // sound TODO diff --git a/tests/TileBenchmark/src/com/test/tilebenchmark/ProfiledWebView.java b/tests/TileBenchmark/src/com/test/tilebenchmark/ProfiledWebView.java index b1cef15ce639..10802b449d03 100644 --- a/tests/TileBenchmark/src/com/test/tilebenchmark/ProfiledWebView.java +++ b/tests/TileBenchmark/src/com/test/tilebenchmark/ProfiledWebView.java @@ -110,9 +110,9 @@ public class ProfiledWebView extends WebView { * been redrawn. */ @Override - protected void pageSwapCallback() { + protected void pageSwapCallback(boolean startAnim) { mContentInvalMillis = System.currentTimeMillis() - mContentInvalMillis; - super.pageSwapCallback(); + super.pageSwapCallback(startAnim); Log.d("ProfiledWebView", "REDRAW TOOK " + mContentInvalMillis + "millis"); mIsTesting = true; diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java index 1d97e1506866..a640a9139be8 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java @@ -79,12 +79,16 @@ public final class BridgeWindowSession implements IWindowSession { } public int relayout(IWindow arg0, int seq, LayoutParams arg1, int arg2, int arg3, int arg4, - boolean arg4_5, Rect arg5, Rect arg6, Rect arg7, Configuration arg7b, Surface arg8) + int arg4_5, Rect arg5, Rect arg6, Rect arg7, Configuration arg7b, Surface arg8) throws RemoteException { // pass for now. return 0; } + public void performDeferredDestroy(IWindow window) { + // pass for now. + } + public boolean outOfMemory(IWindow window) throws RemoteException { return false; } diff --git a/voip/java/com/android/server/sip/SipHelper.java b/voip/java/com/android/server/sip/SipHelper.java index dc628e027989..113f0070da8b 100644 --- a/voip/java/com/android/server/sip/SipHelper.java +++ b/voip/java/com/android/server/sip/SipHelper.java @@ -73,7 +73,7 @@ import javax.sip.message.Response; */ class SipHelper { private static final String TAG = SipHelper.class.getSimpleName(); - private static final boolean DEBUG = true; + private static final boolean DEBUG = false; private static final boolean DEBUG_PING = false; private SipStack mSipStack; diff --git a/voip/java/com/android/server/sip/SipService.java b/voip/java/com/android/server/sip/SipService.java index 119ed5412c94..38a683ed6a0d 100644 --- a/voip/java/com/android/server/sip/SipService.java +++ b/voip/java/com/android/server/sip/SipService.java @@ -68,8 +68,7 @@ import javax.sip.SipException; */ public final class SipService extends ISipService.Stub { static final String TAG = "SipService"; - static final boolean DEBUGV = false; - static final boolean DEBUG = true; + static final boolean DEBUG = false; private static final int EXPIRY_TIME = 3600; private static final int SHORT_EXPIRY_TIME = 10; private static final int MIN_EXPIRY_TIME = 60; @@ -581,7 +580,7 @@ public final class SipService extends ISipService.Stub { @Override public void onRinging(ISipSession s, SipProfile caller, String sessionDescription) { - if (DEBUGV) Log.d(TAG, "<<<<< onRinging()"); + if (DEBUG) Log.d(TAG, "<<<<< onRinging()"); SipSessionGroup.SipSessionImpl session = (SipSessionGroup.SipSessionImpl) s; synchronized (SipService.this) { @@ -778,7 +777,6 @@ public final class SipService extends ISipService.Stub { private void restartLater() { synchronized (SipService.this) { int interval = NAT_MEASUREMENT_RETRY_INTERVAL; - Log.d(TAG, "Retry measurement " + interval + "s later."); mTimer.cancel(this); mTimer.set(interval * 1000, this); } @@ -788,7 +786,7 @@ public final class SipService extends ISipService.Stub { private class AutoRegistrationProcess extends SipSessionAdapter implements Runnable, SipSessionGroup.KeepAliveProcessCallback { private static final int MIN_KEEPALIVE_SUCCESS_COUNT = 10; - private String TAG = "SipAudoReg"; + private String TAG = "SipAutoReg"; private SipSessionGroup.SipSessionImpl mSession; private SipSessionGroup.SipSessionImpl mKeepAliveSession; @@ -820,13 +818,12 @@ public final class SipService extends ISipService.Stub { // in registration to avoid adding duplicate entries to server mMyWakeLock.acquire(mSession); mSession.unregister(); - if (DEBUG) TAG = mSession.getLocalProfile().getUriString(); - if (DEBUG) Log.d(TAG, "start AutoRegistrationProcess"); + TAG = "SipAutoReg:" + mSession.getLocalProfile().getUriString(); } } private void startKeepAliveProcess(int interval) { - Log.d(TAG, "start keepalive w interval=" + interval); + if (DEBUG) Log.d(TAG, "start keepalive w interval=" + interval); if (mKeepAliveSession == null) { mKeepAliveSession = mSession.duplicate(); } else { @@ -864,9 +861,11 @@ public final class SipService extends ISipService.Stub { mKeepAliveSuccessCount = 0; } } else { - Log.i(TAG, "keep keepalive going with interval " - + interval + ", past success count=" - + mKeepAliveSuccessCount); + if (DEBUG) { + Log.i(TAG, "keep keepalive going with interval " + + interval + ", past success count=" + + mKeepAliveSuccessCount); + } mKeepAliveSuccessCount /= 2; } } else { @@ -894,7 +893,9 @@ public final class SipService extends ISipService.Stub { // SipSessionGroup.KeepAliveProcessCallback @Override public void onError(int errorCode, String description) { - Log.e(TAG, "keepalive error: " + description); + if (DEBUG) { + Log.e(TAG, "keepalive error: " + description); + } onResponse(true); // re-register immediately } @@ -917,7 +918,7 @@ public final class SipService extends ISipService.Stub { public void onKeepAliveIntervalChanged() { if (mKeepAliveSession != null) { int newInterval = getKeepAliveInterval(); - if (DEBUGV) { + if (DEBUG) { Log.v(TAG, "restart keepalive w interval=" + newInterval); } mKeepAliveSuccessCount = 0; @@ -987,7 +988,7 @@ public final class SipService extends ISipService.Stub { } private void restart(int duration) { - if (DEBUG) Log.d(TAG, "Refresh registration " + duration + "s later."); + Log.d(TAG, "Refresh registration " + duration + "s later."); mTimer.cancel(this); mTimer.set(duration * 1000, this); } diff --git a/voip/java/com/android/server/sip/SipSessionGroup.java b/voip/java/com/android/server/sip/SipSessionGroup.java index 06cdaf249ce5..877a0a44d23b 100644 --- a/voip/java/com/android/server/sip/SipSessionGroup.java +++ b/voip/java/com/android/server/sip/SipSessionGroup.java @@ -89,8 +89,8 @@ import javax.sip.message.Response; */ class SipSessionGroup implements SipListener { private static final String TAG = "SipSession"; - private static final boolean DEBUG = true; - private static final boolean DEBUG_PING = DEBUG && false; + private static final boolean DEBUG = false; + private static final boolean DEBUG_PING = false; private static final String ANONYMOUS = "anonymous"; // Limit the size of thread pool to 1 for the order issue when the phone is // waken up from sleep and there are many packets to be processed in the SIP @@ -205,7 +205,9 @@ class SipSessionGroup implements SipListener { } synchronized void resetExternalAddress() { - Log.d(TAG, " reset external addr on " + mSipStack); + if (DEBUG) { + Log.d(TAG, " reset external addr on " + mSipStack); + } mExternalIp = null; mExternalPort = 0; } @@ -362,7 +364,7 @@ class SipSessionGroup implements SipListener { + SipSession.State.toString(session.mState)); } } catch (Throwable e) { - Log.w(TAG, "event process error: " + event, e); + Log.w(TAG, "event process error: " + event, getRootCause(e)); session.onError(e); } } @@ -393,9 +395,20 @@ class SipSessionGroup implements SipListener { if ((rport > 0) && (externalIp != null)) { mExternalIp = externalIp; mExternalPort = rport; - Log.d(TAG, " got external addr " + externalIp + ":" + rport - + " on " + mSipStack); + if (DEBUG) { + Log.d(TAG, " got external addr " + externalIp + ":" + rport + + " on " + mSipStack); + } + } + } + + private Throwable getRootCause(Throwable exception) { + Throwable cause = exception.getCause(); + while (cause != null) { + exception = cause; + cause = exception.getCause(); } + return exception; } private SipSessionImpl createNewSession(RequestEvent event, @@ -890,7 +903,9 @@ class SipSessionGroup implements SipListener { if (expires != null && time < expires.getExpires()) { time = expires.getExpires(); } - Log.v(TAG, "Expiry time = " + time); + if (DEBUG) { + Log.v(TAG, "Expiry time = " + time); + } return time; } @@ -1409,15 +1424,6 @@ class SipSessionGroup implements SipListener { } } - private Throwable getRootCause(Throwable exception) { - Throwable cause = exception.getCause(); - while (cause != null) { - exception = cause; - cause = exception.getCause(); - } - return exception; - } - private int getErrorCode(Throwable exception) { String message = exception.getMessage(); if (exception instanceof UnknownHostException) { @@ -1555,8 +1561,10 @@ class SipSessionGroup implements SipListener { try { sendKeepAlive(); } catch (Throwable t) { - Log.w(TAG, "keepalive error: " - + mLocalProfile.getUriString(), getRootCause(t)); + if (DEBUG) { + Log.w(TAG, "keepalive error: " + + mLocalProfile.getUriString(), getRootCause(t)); + } // It's possible that the keepalive process is being stopped // during session.sendKeepAlive() so need to check mRunning // again here. diff --git a/voip/java/com/android/server/sip/SipWakeLock.java b/voip/java/com/android/server/sip/SipWakeLock.java index 52bc094afab4..0c4d14c77184 100644 --- a/voip/java/com/android/server/sip/SipWakeLock.java +++ b/voip/java/com/android/server/sip/SipWakeLock.java @@ -22,8 +22,8 @@ import android.util.Log; import java.util.HashSet; class SipWakeLock { - private static final boolean DEBUGV = SipService.DEBUGV; - private static final String TAG = SipService.TAG; + private static final boolean DEBUG = false; + private static final String TAG = "SipWakeLock"; private PowerManager mPowerManager; private PowerManager.WakeLock mWakeLock; private PowerManager.WakeLock mTimerWakeLock; @@ -34,9 +34,9 @@ class SipWakeLock { } synchronized void reset() { + if (DEBUG) Log.v(TAG, "reset count=" + mHolders.size()); mHolders.clear(); release(null); - if (DEBUGV) Log.v(TAG, "~~~ hard reset wakelock"); } synchronized void acquire(long timeout) { @@ -55,8 +55,7 @@ class SipWakeLock { PowerManager.PARTIAL_WAKE_LOCK, "SipWakeLock"); } if (!mWakeLock.isHeld()) mWakeLock.acquire(); - if (DEBUGV) Log.v(TAG, "acquire wakelock: holder count=" - + mHolders.size()); + if (DEBUG) Log.v(TAG, "acquire count=" + mHolders.size()); } synchronized void release(Object holder) { @@ -65,7 +64,6 @@ class SipWakeLock { && mWakeLock.isHeld()) { mWakeLock.release(); } - if (DEBUGV) Log.v(TAG, "release wakelock: holder count=" - + mHolders.size()); + if (DEBUG) Log.v(TAG, "release count=" + mHolders.size()); } } diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java index aadcaadaa663..82abe3ace9f2 100644 --- a/wifi/java/android/net/wifi/WifiStateMachine.java +++ b/wifi/java/android/net/wifi/WifiStateMachine.java @@ -123,6 +123,8 @@ public class WifiStateMachine extends StateMachine { private final LruCache<String, ScanResult> mScanResultCache; private String mInterfaceName; + /* Tethering interface could be seperate from wlan interface */ + private String mTetherInterfaceName; private int mLastSignalLevel = -1; private String mLastBssid; @@ -156,6 +158,14 @@ public class WifiStateMachine extends StateMachine { /* Tracks sequence number on stop failure message */ private int mSupplicantStopFailureToken = 0; + /** + * Tether state change notification time out + */ + private static final int TETHER_NOTIFICATION_TIME_OUT_MSECS = 5000; + + /* Tracks sequence number on a tether notification time out */ + private int mTetherToken = 0; + private LinkProperties mLinkProperties; // Wakelock held during wifi start/stop and driver load/unload @@ -240,10 +250,12 @@ public class WifiStateMachine extends StateMachine { static final int CMD_REQUEST_AP_CONFIG = BASE + 27; /* Response to access point configuration request */ static final int CMD_RESPONSE_AP_CONFIG = BASE + 28; - /* Set configuration on tether interface */ - static final int CMD_TETHER_INTERFACE = BASE + 29; + /* Invoked when getting a tether state change notification */ + static final int CMD_TETHER_STATE_CHANGE = BASE + 29; + /* A delayed message sent to indicate tether state change failed to arrive */ + static final int CMD_TETHER_NOTIFICATION_TIMED_OUT = BASE + 30; - static final int CMD_BLUETOOTH_ADAPTER_STATE_CHANGE = BASE + 30; + static final int CMD_BLUETOOTH_ADAPTER_STATE_CHANGE = BASE + 31; /* Supplicant commands */ /* Is supplicant alive ? */ @@ -294,8 +306,6 @@ public class WifiStateMachine extends StateMachine { static final int CMD_SET_HIGH_PERF_MODE = BASE + 77; /* Set the country code */ static final int CMD_SET_COUNTRY_CODE = BASE + 80; - /* Request connectivity manager wake lock before driver stop */ - static final int CMD_REQUEST_CM_WAKELOCK = BASE + 81; /* Enables RSSI poll */ static final int CMD_ENABLE_RSSI_POLL = BASE + 82; /* RSSI poll */ @@ -358,6 +368,10 @@ public class WifiStateMachine extends StateMachine { private static final int SUCCESS = 1; private static final int FAILURE = -1; + /* Phone in emergency call back mode */ + private static final int IN_ECM_STATE = 1; + private static final int NOT_IN_ECM_STATE = 0; + /** * The maximum number of times we will retry a connection to an access point * for which we have failed in acquiring an IP address from DHCP. A value of @@ -455,12 +469,25 @@ public class WifiStateMachine extends StateMachine { private State mSoftApStartingState = new SoftApStartingState(); /* Soft ap is running */ private State mSoftApStartedState = new SoftApStartedState(); + /* Soft ap is running and we are waiting for tether notification */ + private State mTetheringState = new TetheringState(); /* Soft ap is running and we are tethered through connectivity service */ private State mTetheredState = new TetheredState(); + /* Waiting for untether confirmation to stop soft Ap */ + private State mSoftApStoppingState = new SoftApStoppingState(); /* Wait till p2p is disabled */ private State mWaitForP2pDisableState = new WaitForP2pDisableState(); + private class TetherStateChange { + ArrayList<String> available; + ArrayList<String> active; + TetherStateChange(ArrayList<String> av, ArrayList<String> ac) { + available = av; + active = ac; + } + } + /** * One of {@link WifiManager#WIFI_STATE_DISABLED}, @@ -562,7 +589,9 @@ public class WifiStateMachine extends StateMachine { public void onReceive(Context context, Intent intent) { ArrayList<String> available = intent.getStringArrayListExtra( ConnectivityManager.EXTRA_AVAILABLE_TETHER); - sendMessage(CMD_TETHER_INTERFACE, available); + ArrayList<String> active = intent.getStringArrayListExtra( + ConnectivityManager.EXTRA_ACTIVE_TETHER); + sendMessage(CMD_TETHER_STATE_CHANGE, new TetherStateChange(available, active)); } },new IntentFilter(ConnectivityManager.ACTION_TETHER_STATE_CHANGED)); @@ -603,7 +632,9 @@ public class WifiStateMachine extends StateMachine { addState(mSupplicantStoppingState, mDefaultState); addState(mSoftApStartingState, mDefaultState); addState(mSoftApStartedState, mDefaultState); + addState(mTetheringState, mSoftApStartedState); addState(mTetheredState, mSoftApStartedState); + addState(mSoftApStoppingState, mDefaultState); addState(mWaitForP2pDisableState, mDefaultState); setInitialState(mInitialState); @@ -751,11 +782,11 @@ public class WifiStateMachine extends StateMachine { /** * TODO: doc */ - public void setDriverStart(boolean enable) { + public void setDriverStart(boolean enable, boolean ecm) { if (enable) { sendMessage(CMD_START_DRIVER); } else { - sendMessage(CMD_STOP_DRIVER); + sendMessage(obtainMessage(CMD_STOP_DRIVER, ecm ? IN_ECM_STATE : NOT_IN_ECM_STATE, 0)); } } @@ -1032,15 +1063,6 @@ public class WifiStateMachine extends StateMachine { return result; } - /** - * Request a wakelock with connectivity service to - * keep the device awake until we hand-off from wifi - * to an alternate network - */ - public void requestCmWakeLock() { - sendMessage(CMD_REQUEST_CM_WAKELOCK); - } - public void updateBatteryWorkSource(WorkSource newSource) { synchronized (mRunningWifiUids) { try { @@ -1139,6 +1161,7 @@ public class WifiStateMachine extends StateMachine { loge("Error tethering on " + intf); return false; } + mTetherInterfaceName = intf; return true; } } @@ -1165,11 +1188,27 @@ public class WifiStateMachine extends StateMachine { loge("Error resetting interface " + mInterfaceName + ", :" + e); } - if (mCm.untether(mInterfaceName) != ConnectivityManager.TETHER_ERROR_NO_ERROR) { + if (mCm.untether(mTetherInterfaceName) != ConnectivityManager.TETHER_ERROR_NO_ERROR) { loge("Untether initiate failed!"); } } + private boolean isWifiTethered(ArrayList<String> active) { + + checkAndSetConnectivityInstance(); + + String[] wifiRegexs = mCm.getTetherableWifiRegexs(); + for (String intf : active) { + for (String regex : wifiRegexs) { + if (intf.matches(regex)) { + return true; + } + } + } + // We found no interfaces that are tethered + return false; + } + /** * Set the country code from the system setting value, if any. */ @@ -1800,7 +1839,8 @@ public class WifiStateMachine extends StateMachine { case CMD_START_AP_SUCCESS: case CMD_START_AP_FAILURE: case CMD_STOP_AP: - case CMD_TETHER_INTERFACE: + case CMD_TETHER_STATE_CHANGE: + case CMD_TETHER_NOTIFICATION_TIMED_OUT: case CMD_START_SCAN: case CMD_DISCONNECT: case CMD_RECONNECT: @@ -1820,7 +1860,6 @@ public class WifiStateMachine extends StateMachine { case CMD_SET_HIGH_PERF_MODE: case CMD_SET_COUNTRY_CODE: case CMD_SET_FREQUENCY_BAND: - case CMD_REQUEST_CM_WAKELOCK: case CMD_CONNECT_NETWORK: case CMD_SAVE_NETWORK: case CMD_FORGET_NETWORK: @@ -2541,16 +2580,25 @@ public class WifiStateMachine extends StateMachine { WifiNative.setBluetoothCoexistenceScanModeCommand(mBluetoothConnectionActive); break; case CMD_STOP_DRIVER: - /* Already doing a delayed stop */ - if (mInDelayedStop) { + int mode = message.arg1; + + /* Already doing a delayed stop && not in ecm state */ + if (mInDelayedStop && mode != IN_ECM_STATE) { if (DBG) log("Already in delayed stop"); break; } mInDelayedStop = true; mDelayedStopCounter++; if (DBG) log("Delayed stop message " + mDelayedStopCounter); - sendMessageDelayed(obtainMessage(CMD_DELAYED_STOP_DRIVER, mDelayedStopCounter, - 0), DELAYED_DRIVER_STOP_MS); + + if (mode == IN_ECM_STATE) { + /* send a shut down immediately */ + sendMessage(obtainMessage(CMD_DELAYED_STOP_DRIVER, mDelayedStopCounter, 0)); + } else { + /* send regular delayed shut down */ + sendMessageDelayed(obtainMessage(CMD_DELAYED_STOP_DRIVER, + mDelayedStopCounter, 0), DELAYED_DRIVER_STOP_MS); + } break; case CMD_START_DRIVER: if (mInDelayedStop) { @@ -2977,10 +3025,6 @@ public class WifiStateMachine extends StateMachine { WifiNative.disconnectCommand(); transitionTo(mDisconnectingState); break; - case CMD_REQUEST_CM_WAKELOCK: - checkAndSetConnectivityInstance(); - mCm.requestNetworkTransitionWakelock(TAG); - break; case CMD_SET_SCAN_MODE: if (message.arg1 == SCAN_ONLY_MODE) { sendMessage(CMD_DISCONNECT); @@ -3053,6 +3097,11 @@ public class WifiStateMachine extends StateMachine { } @Override public void exit() { + + /* Request a CS wakelock during transition to mobile */ + checkAndSetConnectivityInstance(); + mCm.requestNetworkTransitionWakelock(TAG); + /* If a scan result is pending in connected state, the supplicant * is in SCAN_ONLY_MODE. Restore CONNECT_MODE on exit */ @@ -3284,7 +3333,7 @@ public class WifiStateMachine extends StateMachine { case CMD_SET_FREQUENCY_BAND: case CMD_START_PACKET_FILTERING: case CMD_STOP_PACKET_FILTERING: - case CMD_TETHER_INTERFACE: + case CMD_TETHER_STATE_CHANGE: case WifiP2pService.P2P_ENABLE_PENDING: deferMessage(message); break; @@ -3326,7 +3375,8 @@ public class WifiStateMachine extends StateMachine { case CMD_STOP_AP: if (DBG) log("Stopping Soft AP"); setWifiApState(WIFI_AP_STATE_DISABLING); - stopTethering(); + + /* We have not tethered at this point, so we just shutdown soft Ap */ try { mNwService.stopAccessPoint(mInterfaceName); } catch(Exception e) { @@ -3342,10 +3392,10 @@ public class WifiStateMachine extends StateMachine { loge("Cannot start supplicant with a running soft AP"); setWifiState(WIFI_STATE_UNKNOWN); break; - case CMD_TETHER_INTERFACE: - ArrayList<String> available = (ArrayList<String>) message.obj; - if (startTethering(available)) { - transitionTo(mTetheredState); + case CMD_TETHER_STATE_CHANGE: + TetherStateChange stateChange = (TetherStateChange) message.obj; + if (startTethering(stateChange.available)) { + transitionTo(mTetheringState); } break; case WifiP2pService.P2P_ENABLE_PENDING: @@ -3405,6 +3455,58 @@ public class WifiStateMachine extends StateMachine { } } + class TetheringState extends State { + @Override + public void enter() { + if (DBG) log(getName() + "\n"); + EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); + + /* Send ourselves a delayed message to shut down if tethering fails to notify */ + sendMessageDelayed(obtainMessage(CMD_TETHER_NOTIFICATION_TIMED_OUT, + ++mTetherToken, 0), TETHER_NOTIFICATION_TIME_OUT_MSECS); + } + @Override + public boolean processMessage(Message message) { + if (DBG) log(getName() + message.toString() + "\n"); + switch(message.what) { + case CMD_TETHER_STATE_CHANGE: + TetherStateChange stateChange = (TetherStateChange) message.obj; + if (isWifiTethered(stateChange.active)) { + transitionTo(mTetheredState); + } + return HANDLED; + case CMD_TETHER_NOTIFICATION_TIMED_OUT: + if (message.arg1 == mTetherToken) { + loge("Failed to get tether update, shutdown soft access point"); + setWifiApEnabled(null, false); + } + break; + case CMD_LOAD_DRIVER: + case CMD_UNLOAD_DRIVER: + case CMD_START_SUPPLICANT: + case CMD_STOP_SUPPLICANT: + case CMD_START_AP: + case CMD_STOP_AP: + case CMD_START_DRIVER: + case CMD_STOP_DRIVER: + case CMD_SET_SCAN_MODE: + case CMD_SET_SCAN_TYPE: + case CMD_SET_HIGH_PERF_MODE: + case CMD_SET_COUNTRY_CODE: + case CMD_SET_FREQUENCY_BAND: + case CMD_START_PACKET_FILTERING: + case CMD_STOP_PACKET_FILTERING: + case WifiP2pService.P2P_ENABLE_PENDING: + deferMessage(message); + break; + default: + return NOT_HANDLED; + } + EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what); + return HANDLED; + } + } + class TetheredState extends State { @Override public void enter() { @@ -3415,13 +3517,89 @@ public class WifiStateMachine extends StateMachine { public boolean processMessage(Message message) { if (DBG) log(getName() + message.toString() + "\n"); switch(message.what) { - case CMD_TETHER_INTERFACE: - // Ignore any duplicate interface available notifications - // when in tethered state + case CMD_TETHER_STATE_CHANGE: + TetherStateChange stateChange = (TetherStateChange) message.obj; + if (!isWifiTethered(stateChange.active)) { + loge("Tethering reports wifi as untethered!, shut down soft Ap"); + setWifiApEnabled(null, false); + } return HANDLED; + case CMD_STOP_AP: + if (DBG) log("Untethering before stopping AP"); + setWifiApState(WIFI_AP_STATE_DISABLING); + stopTethering(); + transitionTo(mSoftApStoppingState); + break; default: return NOT_HANDLED; } + EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what); + return HANDLED; + } + } + + class SoftApStoppingState extends State { + @Override + public void enter() { + if (DBG) log(getName() + "\n"); + EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); + + /* Send ourselves a delayed message to shut down if tethering fails to notify */ + sendMessageDelayed(obtainMessage(CMD_TETHER_NOTIFICATION_TIMED_OUT, + ++mTetherToken, 0), TETHER_NOTIFICATION_TIME_OUT_MSECS); + + } + @Override + public boolean processMessage(Message message) { + if (DBG) log(getName() + message.toString() + "\n"); + switch(message.what) { + case CMD_TETHER_STATE_CHANGE: + TetherStateChange stateChange = (TetherStateChange) message.obj; + + /* Wait till wifi is untethered */ + if (isWifiTethered(stateChange.active)) break; + + try { + mNwService.stopAccessPoint(mInterfaceName); + } catch(Exception e) { + loge("Exception in stopAccessPoint()"); + } + transitionTo(mDriverLoadedState); + break; + case CMD_TETHER_NOTIFICATION_TIMED_OUT: + if (message.arg1 == mTetherToken) { + loge("Failed to get tether update, force stop access point"); + try { + mNwService.stopAccessPoint(mInterfaceName); + } catch(Exception e) { + loge("Exception in stopAccessPoint()"); + } + transitionTo(mDriverLoadedState); + } + break; + case CMD_LOAD_DRIVER: + case CMD_UNLOAD_DRIVER: + case CMD_START_SUPPLICANT: + case CMD_STOP_SUPPLICANT: + case CMD_START_AP: + case CMD_STOP_AP: + case CMD_START_DRIVER: + case CMD_STOP_DRIVER: + case CMD_SET_SCAN_MODE: + case CMD_SET_SCAN_TYPE: + case CMD_SET_HIGH_PERF_MODE: + case CMD_SET_COUNTRY_CODE: + case CMD_SET_FREQUENCY_BAND: + case CMD_START_PACKET_FILTERING: + case CMD_STOP_PACKET_FILTERING: + case WifiP2pService.P2P_ENABLE_PENDING: + deferMessage(message); + break; + default: + return NOT_HANDLED; + } + EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what); + return HANDLED; } } diff --git a/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java b/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java index b4cbd01693f3..b27c60f44524 100644 --- a/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java +++ b/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java @@ -37,6 +37,7 @@ import android.provider.Settings; import android.provider.Settings.Secure; import android.util.Log; +import com.android.internal.R; import com.android.internal.util.Protocol; import com.android.internal.util.State; import com.android.internal.util.StateMachine; @@ -68,7 +69,8 @@ public class WifiWatchdogStateMachine extends StateMachine { private static final boolean DBG = false; private static final String TAG = "WifiWatchdogStateMachine"; - private static final String WATCHDOG_NOTIFICATION_ID = "Android.System.WifiWatchdog"; + private static final String DISABLED_NETWORK_NOTIFICATION_ID = "WifiWatchdog.networkdisabled"; + private static final String WALLED_GARDEN_NOTIFICATION_ID = "WifiWatchdog.walledgarden"; private static final int WIFI_SIGNAL_LEVELS = 4; /** @@ -148,6 +150,7 @@ public class WifiWatchdogStateMachine extends StateMachine { private ConnectedState mConnectedState = new ConnectedState(); private DnsCheckingState mDnsCheckingState = new DnsCheckingState(); private OnlineWatchState mOnlineWatchState = new OnlineWatchState(); + private OnlineState mOnlineState = new OnlineState(); private DnsCheckFailureState mDnsCheckFailureState = new DnsCheckFailureState(); private DelayWalledGardenState mDelayWalledGardenState = new DelayWalledGardenState(); private WalledGardenState mWalledGardenState = new WalledGardenState(); @@ -161,6 +164,7 @@ public class WifiWatchdogStateMachine extends StateMachine { private int mMinDnsResponses; private int mDnsPingTimeoutMs; private long mBlacklistFollowupIntervalMs; + private boolean mPoorNetworkDetectionEnabled; private boolean mWalledGardenTestEnabled; private String mWalledGardenUrl; @@ -185,7 +189,8 @@ public class WifiWatchdogStateMachine extends StateMachine { */ public boolean mDisableAPNextFailure = false; private static boolean sWifiOnly = false; - private boolean mNotificationShown; + private boolean mDisabledNotificationShown; + private boolean mWalledGardenNotificationShown; public boolean mHasConnectedWifiManager = false; /** @@ -223,6 +228,7 @@ public class WifiWatchdogStateMachine extends StateMachine { addState(mWalledGardenState, mConnectedState); addState(mBlacklistedApState, mConnectedState); addState(mOnlineWatchState, mConnectedState); + addState(mOnlineState, mConnectedState); setInitialState(mWatchdogDisabledState); updateSettings(); @@ -408,6 +414,10 @@ public class WifiWatchdogStateMachine extends StateMachine { mBlacklistFollowupIntervalMs = Secure.getLong(mContentResolver, Settings.Secure.WIFI_WATCHDOG_BLACKLIST_FOLLOWUP_INTERVAL_MS, DEFAULT_BLACKLIST_FOLLOWUP_INTERVAL_MS); + //TODO: enable this by default after changing watchdog behavior + //Also, update settings description + mPoorNetworkDetectionEnabled = getSettingsBoolean(mContentResolver, + Settings.Secure.WIFI_WATCHDOG_POOR_NETWORK_TEST_ENABLED, false); mWalledGardenTestEnabled = getSettingsBoolean(mContentResolver, Settings.Secure.WIFI_WATCHDOG_WALLED_GARDEN_TEST_ENABLED, true); mWalledGardenUrl = getSettingsStr(mContentResolver, @@ -477,51 +487,76 @@ public class WifiWatchdogStateMachine extends StateMachine { mLastWalledGardenCheckTime = null; mNumCheckFailures = 0; mBssids.clear(); - cancelNetworkNotification(); + setDisabledNetworkNotificationVisible(false); + setWalledGardenNotificationVisible(false); } - private void popUpBrowser() { - Uri uri = Uri.parse("http://www.google.com"); - Intent intent = new Intent(Intent.ACTION_VIEW, uri); - intent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT | - Intent.FLAG_ACTIVITY_NEW_TASK); - mContext.startActivity(intent); - } + private void setWalledGardenNotificationVisible(boolean visible) { + // If it should be hidden and it is already hidden, then noop + if (!visible && !mWalledGardenNotificationShown) { + return; + } - private void displayDisabledNetworkNotification(String ssid) { Resources r = Resources.getSystem(); - CharSequence title = - r.getText(com.android.internal.R.string.wifi_watchdog_network_disabled); - String msg = ssid + - r.getText(com.android.internal.R.string.wifi_watchdog_network_disabled_detailed); - - Notification wifiDisabledWarning = new Notification.Builder(mContext) - .setSmallIcon(com.android.internal.R.drawable.stat_sys_warning) - .setDefaults(Notification.DEFAULT_ALL) - .setTicker(title) - .setContentTitle(title) - .setContentText(msg) - .setContentIntent(PendingIntent.getActivity(mContext, 0, - new Intent(WifiManager.ACTION_PICK_WIFI_NETWORK) - .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK), 0)) - .setWhen(System.currentTimeMillis()) - .setAutoCancel(true) - .getNotification(); - NotificationManager notificationManager = (NotificationManager) mContext - .getSystemService(Context.NOTIFICATION_SERVICE); - - notificationManager.notify(WATCHDOG_NOTIFICATION_ID, 1, wifiDisabledWarning); - mNotificationShown = true; + .getSystemService(Context.NOTIFICATION_SERVICE); + + if (visible) { + Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(mWalledGardenUrl)); + intent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT | Intent.FLAG_ACTIVITY_NEW_TASK); + + CharSequence title = r.getString(R.string.wifi_available_sign_in, 0); + CharSequence details = r.getString(R.string.wifi_available_sign_in_detailed, + mConnectionInfo.getSSID()); + + Notification notification = new Notification(); + notification.when = 0; + notification.icon = com.android.internal.R.drawable.stat_notify_wifi_in_range; + notification.flags = Notification.FLAG_AUTO_CANCEL; + notification.contentIntent = PendingIntent.getActivity(mContext, 0, intent, 0); + notification.tickerText = title; + notification.setLatestEventInfo(mContext, title, details, notification.contentIntent); + + notificationManager.notify(WALLED_GARDEN_NOTIFICATION_ID, 1, notification); + } else { + notificationManager.cancel(WALLED_GARDEN_NOTIFICATION_ID, 1); + } + mWalledGardenNotificationShown = visible; } - public void cancelNetworkNotification() { - if (mNotificationShown) { - NotificationManager notificationManager = (NotificationManager) mContext - .getSystemService(Context.NOTIFICATION_SERVICE); - notificationManager.cancel(WATCHDOG_NOTIFICATION_ID, 1); - mNotificationShown = false; + private void setDisabledNetworkNotificationVisible(boolean visible) { + // If it should be hidden and it is already hidden, then noop + if (!visible && !mDisabledNotificationShown) { + return; } + + Resources r = Resources.getSystem(); + NotificationManager notificationManager = (NotificationManager) mContext + .getSystemService(Context.NOTIFICATION_SERVICE); + + if (visible) { + CharSequence title = r.getText(R.string.wifi_watchdog_network_disabled); + String msg = mConnectionInfo.getSSID() + + r.getText(R.string.wifi_watchdog_network_disabled_detailed); + + Notification wifiDisabledWarning = new Notification.Builder(mContext) + .setSmallIcon(R.drawable.stat_sys_warning) + .setDefaults(Notification.DEFAULT_ALL) + .setTicker(title) + .setContentTitle(title) + .setContentText(msg) + .setContentIntent(PendingIntent.getActivity(mContext, 0, + new Intent(WifiManager.ACTION_PICK_WIFI_NETWORK) + .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK), 0)) + .setWhen(System.currentTimeMillis()) + .setAutoCancel(true) + .getNotification(); + + notificationManager.notify(DISABLED_NETWORK_NOTIFICATION_ID, 1, wifiDisabledWarning); + } else { + notificationManager.cancel(DISABLED_NETWORK_NOTIFICATION_ID, 1); + } + mDisabledNotificationShown = visible; } class DefaultState extends State { @@ -576,9 +611,10 @@ public class WifiWatchdogStateMachine extends StateMachine { NetworkInfo networkInfo = (NetworkInfo) stateChangeIntent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO); + setDisabledNetworkNotificationVisible(false); + setWalledGardenNotificationVisible(false); switch (networkInfo.getState()) { case CONNECTED: - cancelNetworkNotification(); WifiInfo wifiInfo = (WifiInfo) stateChangeIntent.getParcelableExtra(WifiManager.EXTRA_WIFI_INFO); if (wifiInfo == null) { @@ -594,9 +630,13 @@ public class WifiWatchdogStateMachine extends StateMachine { initConnection(wifiInfo); mConnectionInfo = wifiInfo; - updateBssids(); - transitionTo(mDnsCheckingState); mNetEventCounter++; + if (mPoorNetworkDetectionEnabled) { + updateBssids(); + transitionTo(mDnsCheckingState); + } else { + transitionTo(mDelayWalledGardenState); + } break; default: mNetEventCounter++; @@ -648,12 +688,18 @@ public class WifiWatchdogStateMachine extends StateMachine { public boolean processMessage(Message msg) { switch (msg.what) { case EVENT_SCAN_RESULTS_AVAILABLE: - updateBssids(); + if (mPoorNetworkDetectionEnabled) { + updateBssids(); + } return HANDLED; case EVENT_WATCHDOG_SETTINGS_CHANGE: - // Stop current checks, but let state update - transitionTo(mOnlineWatchState); - return NOT_HANDLED; + updateSettings(); + if (mPoorNetworkDetectionEnabled) { + transitionTo(mOnlineWatchState); + } else { + transitionTo(mOnlineState); + } + return HANDLED; } return NOT_HANDLED; } @@ -800,7 +846,11 @@ public class WifiWatchdogStateMachine extends StateMachine { transitionTo(mWalledGardenState); } else { if (DBG) log("Walled garden test complete - online"); - transitionTo(mOnlineWatchState); + if (mPoorNetworkDetectionEnabled) { + transitionTo(mOnlineWatchState); + } else { + transitionTo(mOnlineState); + } } return HANDLED; default: @@ -932,6 +982,13 @@ public class WifiWatchdogStateMachine extends StateMachine { } } + + /* Child state of ConnectedState indicating that we are online + * and there is nothing to do + */ + class OnlineState extends State { + } + class DnsCheckFailureState extends State { @Override @@ -974,7 +1031,7 @@ public class WifiWatchdogStateMachine extends StateMachine { } mWifiManager.disableNetwork(networkId, WifiConfiguration.DISABLED_DNS_FAILURE); if (mShowDisabledNotification && mConnectionInfo.isExplicitConnect()) { - displayDisabledNetworkNotification(mConnectionInfo.getSSID()); + setDisabledNetworkNotificationVisible(true); } transitionTo(mNotConnectedState); } else { @@ -1007,8 +1064,12 @@ public class WifiWatchdogStateMachine extends StateMachine { } return HANDLED; } - popUpBrowser(); - transitionTo(mOnlineWatchState); + setWalledGardenNotificationVisible(true); + if (mPoorNetworkDetectionEnabled) { + transitionTo(mOnlineWatchState); + } else { + transitionTo(mOnlineState); + } return HANDLED; } } |