Merge "Additional annotations: @CallSuper, @Keep, etc."
diff --git a/api/current.txt b/api/current.txt
index c748577..e6d8546 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -4464,10 +4464,10 @@
     method public void setInTouchMode(boolean);
     method public void start();
     method public android.app.Activity startActivitySync(android.content.Intent);
-    method public void startAllocCounting();
+    method public deprecated void startAllocCounting();
     method public void startPerformanceSnapshot();
     method public void startProfiling();
-    method public void stopAllocCounting();
+    method public deprecated void stopAllocCounting();
     method public void stopProfiling();
     method public void waitForIdle(java.lang.Runnable);
     method public void waitForIdleSync();
@@ -22041,47 +22041,47 @@
     method public static final int getBinderProxyObjectCount();
     method public static int getBinderReceivedTransactions();
     method public static int getBinderSentTransactions();
-    method public static int getGlobalAllocCount();
-    method public static int getGlobalAllocSize();
-    method public static int getGlobalClassInitCount();
-    method public static int getGlobalClassInitTime();
+    method public static deprecated int getGlobalAllocCount();
+    method public static deprecated int getGlobalAllocSize();
+    method public static deprecated int getGlobalClassInitCount();
+    method public static deprecated int getGlobalClassInitTime();
     method public static deprecated int getGlobalExternalAllocCount();
     method public static deprecated int getGlobalExternalAllocSize();
     method public static deprecated int getGlobalExternalFreedCount();
     method public static deprecated int getGlobalExternalFreedSize();
-    method public static int getGlobalFreedCount();
-    method public static int getGlobalFreedSize();
-    method public static int getGlobalGcInvocationCount();
+    method public static deprecated int getGlobalFreedCount();
+    method public static deprecated int getGlobalFreedSize();
+    method public static deprecated int getGlobalGcInvocationCount();
     method public static int getLoadedClassCount();
     method public static void getMemoryInfo(android.os.Debug.MemoryInfo);
     method public static long getNativeHeapAllocatedSize();
     method public static long getNativeHeapFreeSize();
     method public static long getNativeHeapSize();
     method public static long getPss();
-    method public static int getThreadAllocCount();
-    method public static int getThreadAllocSize();
+    method public static deprecated int getThreadAllocCount();
+    method public static deprecated int getThreadAllocSize();
     method public static deprecated int getThreadExternalAllocCount();
     method public static deprecated int getThreadExternalAllocSize();
-    method public static int getThreadGcInvocationCount();
+    method public static deprecated int getThreadGcInvocationCount();
     method public static boolean isDebuggerConnected();
     method public static void printLoadedClasses(int);
-    method public static void resetAllCounts();
-    method public static void resetGlobalAllocCount();
-    method public static void resetGlobalAllocSize();
-    method public static void resetGlobalClassInitCount();
-    method public static void resetGlobalClassInitTime();
+    method public static deprecated void resetAllCounts();
+    method public static deprecated void resetGlobalAllocCount();
+    method public static deprecated void resetGlobalAllocSize();
+    method public static deprecated void resetGlobalClassInitCount();
+    method public static deprecated void resetGlobalClassInitTime();
     method public static deprecated void resetGlobalExternalAllocCount();
     method public static deprecated void resetGlobalExternalAllocSize();
     method public static deprecated void resetGlobalExternalFreedCount();
     method public static deprecated void resetGlobalExternalFreedSize();
-    method public static void resetGlobalFreedCount();
-    method public static void resetGlobalFreedSize();
-    method public static void resetGlobalGcInvocationCount();
-    method public static void resetThreadAllocCount();
-    method public static void resetThreadAllocSize();
+    method public static deprecated void resetGlobalFreedCount();
+    method public static deprecated void resetGlobalFreedSize();
+    method public static deprecated void resetGlobalGcInvocationCount();
+    method public static deprecated void resetThreadAllocCount();
+    method public static deprecated void resetThreadAllocSize();
     method public static deprecated void resetThreadExternalAllocCount();
     method public static deprecated void resetThreadExternalAllocSize();
-    method public static void resetThreadGcInvocationCount();
+    method public static deprecated void resetThreadGcInvocationCount();
     method public static deprecated int setAllocationLimit(int);
     method public static deprecated int setGlobalAllocationLimit(int);
     method public static deprecated void startAllocCounting();
@@ -22100,7 +22100,7 @@
     field public static final int SHOW_CLASSLOADER = 2; // 0x2
     field public static final int SHOW_FULL_DETAIL = 1; // 0x1
     field public static final int SHOW_INITIALIZED = 4; // 0x4
-    field public static final int TRACE_COUNT_ALLOCS = 1; // 0x1
+    field public static final deprecated int TRACE_COUNT_ALLOCS = 1; // 0x1
   }
 
   public static deprecated class Debug.InstructionCount {
@@ -29331,6 +29331,7 @@
   }
 
   public class TelephonyManager {
+    method public boolean canChangeDtmfToneLength();
     method public java.util.List<android.telephony.CellInfo> getAllCellInfo();
     method public int getCallState();
     method public android.telephony.CellLocation getCellLocation();
@@ -29366,6 +29367,7 @@
     method public boolean isNetworkRoaming();
     method public boolean isSmsCapable();
     method public boolean isVoiceCapable();
+    method public boolean isWorldPhone();
     method public void listen(android.telephony.PhoneStateListener, int);
     method public java.lang.String sendEnvelopeWithStatus(java.lang.String);
     method public boolean setLine1NumberForDisplay(java.lang.String, java.lang.String);
@@ -36925,6 +36927,12 @@
     method public abstract void onReceivedIcon(java.lang.String, android.graphics.Bitmap);
   }
 
+  public abstract class WebResourceError {
+    ctor public WebResourceError();
+    method public abstract java.lang.String getDescription();
+    method public abstract int getErrorCode();
+  }
+
   public abstract interface WebResourceRequest {
     method public abstract java.lang.String getMethod();
     method public abstract java.util.Map<java.lang.String, java.lang.String> getRequestHeaders();
@@ -36933,7 +36941,7 @@
     method public abstract boolean isForMainFrame();
   }
 
-  public class WebResourceResponse {
+  public class WebResourceResponse extends android.webkit.WebResourceResponseBase {
     ctor public WebResourceResponse(java.lang.String, java.lang.String, java.io.InputStream);
     ctor public WebResourceResponse(java.lang.String, java.lang.String, int, java.lang.String, java.util.Map<java.lang.String, java.lang.String>, java.io.InputStream);
     method public java.io.InputStream getData();
@@ -36949,6 +36957,16 @@
     method public void setStatusCodeAndReasonPhrase(int, java.lang.String);
   }
 
+  public abstract class WebResourceResponseBase {
+    ctor public WebResourceResponseBase();
+    method public abstract java.io.InputStream getData();
+    method public abstract java.lang.String getEncoding();
+    method public abstract java.lang.String getMimeType();
+    method public abstract java.lang.String getReasonPhrase();
+    method public abstract java.util.Map<java.lang.String, java.lang.String> getResponseHeaders();
+    method public abstract int getStatusCode();
+  }
+
   public abstract class WebSettings {
     ctor public WebSettings();
     method public abstract deprecated boolean enableSmoothTransition();
@@ -37263,8 +37281,10 @@
     method public void onPageFinished(android.webkit.WebView, java.lang.String);
     method public void onPageStarted(android.webkit.WebView, java.lang.String, android.graphics.Bitmap);
     method public void onReceivedClientCertRequest(android.webkit.WebView, android.webkit.ClientCertRequest);
-    method public void onReceivedError(android.webkit.WebView, int, java.lang.String, java.lang.String);
+    method public deprecated void onReceivedError(android.webkit.WebView, int, java.lang.String, java.lang.String);
+    method public void onReceivedError(android.webkit.WebView, android.webkit.WebResourceRequest, android.webkit.WebResourceError);
     method public void onReceivedHttpAuthRequest(android.webkit.WebView, android.webkit.HttpAuthHandler, java.lang.String, java.lang.String);
+    method public void onReceivedHttpError(android.webkit.WebView, android.webkit.WebResourceRequest, android.webkit.WebResourceResponseBase);
     method public void onReceivedLoginRequest(android.webkit.WebView, java.lang.String, java.lang.String, java.lang.String);
     method public void onReceivedSslError(android.webkit.WebView, android.webkit.SslErrorHandler, android.net.http.SslError);
     method public void onScaleChanged(android.webkit.WebView, float, float);
@@ -37277,6 +37297,7 @@
     method public boolean shouldOverrideUrlLoading(android.webkit.WebView, java.lang.String);
     field public static final int ERROR_AUTHENTICATION = -4; // 0xfffffffc
     field public static final int ERROR_BAD_URL = -12; // 0xfffffff4
+    field public static final int ERROR_BLOCKED = -16; // 0xfffffff0
     field public static final int ERROR_CONNECT = -6; // 0xfffffffa
     field public static final int ERROR_FAILED_SSL_HANDSHAKE = -11; // 0xfffffff5
     field public static final int ERROR_FILE = -13; // 0xfffffff3
diff --git a/api/system-current.txt b/api/system-current.txt
index 2e980de..ca84133 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -4554,10 +4554,10 @@
     method public void setInTouchMode(boolean);
     method public void start();
     method public android.app.Activity startActivitySync(android.content.Intent);
-    method public void startAllocCounting();
+    method public deprecated void startAllocCounting();
     method public void startPerformanceSnapshot();
     method public void startProfiling();
-    method public void stopAllocCounting();
+    method public deprecated void stopAllocCounting();
     method public void stopProfiling();
     method public void waitForIdle(java.lang.Runnable);
     method public void waitForIdleSync();
@@ -23631,47 +23631,47 @@
     method public static final int getBinderProxyObjectCount();
     method public static int getBinderReceivedTransactions();
     method public static int getBinderSentTransactions();
-    method public static int getGlobalAllocCount();
-    method public static int getGlobalAllocSize();
-    method public static int getGlobalClassInitCount();
-    method public static int getGlobalClassInitTime();
+    method public static deprecated int getGlobalAllocCount();
+    method public static deprecated int getGlobalAllocSize();
+    method public static deprecated int getGlobalClassInitCount();
+    method public static deprecated int getGlobalClassInitTime();
     method public static deprecated int getGlobalExternalAllocCount();
     method public static deprecated int getGlobalExternalAllocSize();
     method public static deprecated int getGlobalExternalFreedCount();
     method public static deprecated int getGlobalExternalFreedSize();
-    method public static int getGlobalFreedCount();
-    method public static int getGlobalFreedSize();
-    method public static int getGlobalGcInvocationCount();
+    method public static deprecated int getGlobalFreedCount();
+    method public static deprecated int getGlobalFreedSize();
+    method public static deprecated int getGlobalGcInvocationCount();
     method public static int getLoadedClassCount();
     method public static void getMemoryInfo(android.os.Debug.MemoryInfo);
     method public static long getNativeHeapAllocatedSize();
     method public static long getNativeHeapFreeSize();
     method public static long getNativeHeapSize();
     method public static long getPss();
-    method public static int getThreadAllocCount();
-    method public static int getThreadAllocSize();
+    method public static deprecated int getThreadAllocCount();
+    method public static deprecated int getThreadAllocSize();
     method public static deprecated int getThreadExternalAllocCount();
     method public static deprecated int getThreadExternalAllocSize();
-    method public static int getThreadGcInvocationCount();
+    method public static deprecated int getThreadGcInvocationCount();
     method public static boolean isDebuggerConnected();
     method public static void printLoadedClasses(int);
-    method public static void resetAllCounts();
-    method public static void resetGlobalAllocCount();
-    method public static void resetGlobalAllocSize();
-    method public static void resetGlobalClassInitCount();
-    method public static void resetGlobalClassInitTime();
+    method public static deprecated void resetAllCounts();
+    method public static deprecated void resetGlobalAllocCount();
+    method public static deprecated void resetGlobalAllocSize();
+    method public static deprecated void resetGlobalClassInitCount();
+    method public static deprecated void resetGlobalClassInitTime();
     method public static deprecated void resetGlobalExternalAllocCount();
     method public static deprecated void resetGlobalExternalAllocSize();
     method public static deprecated void resetGlobalExternalFreedCount();
     method public static deprecated void resetGlobalExternalFreedSize();
-    method public static void resetGlobalFreedCount();
-    method public static void resetGlobalFreedSize();
-    method public static void resetGlobalGcInvocationCount();
-    method public static void resetThreadAllocCount();
-    method public static void resetThreadAllocSize();
+    method public static deprecated void resetGlobalFreedCount();
+    method public static deprecated void resetGlobalFreedSize();
+    method public static deprecated void resetGlobalGcInvocationCount();
+    method public static deprecated void resetThreadAllocCount();
+    method public static deprecated void resetThreadAllocSize();
     method public static deprecated void resetThreadExternalAllocCount();
     method public static deprecated void resetThreadExternalAllocSize();
-    method public static void resetThreadGcInvocationCount();
+    method public static deprecated void resetThreadGcInvocationCount();
     method public static deprecated int setAllocationLimit(int);
     method public static deprecated int setGlobalAllocationLimit(int);
     method public static deprecated void startAllocCounting();
@@ -23690,7 +23690,7 @@
     field public static final int SHOW_CLASSLOADER = 2; // 0x2
     field public static final int SHOW_FULL_DETAIL = 1; // 0x1
     field public static final int SHOW_INITIALIZED = 4; // 0x4
-    field public static final int TRACE_COUNT_ALLOCS = 1; // 0x1
+    field public static final deprecated int TRACE_COUNT_ALLOCS = 1; // 0x1
   }
 
   public static deprecated class Debug.InstructionCount {
@@ -31458,6 +31458,7 @@
   public class TelephonyManager {
     method public void answerRingingCall();
     method public void call(java.lang.String, java.lang.String);
+    method public boolean canChangeDtmfToneLength();
     method public int checkCarrierPrivilegesForPackage(java.lang.String);
     method public void dial(java.lang.String);
     method public boolean disableDataConnectivity();
@@ -31517,6 +31518,7 @@
     method public boolean isSmsCapable();
     method public boolean isVideoCallingEnabled();
     method public boolean isVoiceCapable();
+    method public boolean isWorldPhone();
     method public void listen(android.telephony.PhoneStateListener, int);
     method public boolean needsOtaServiceProvisioning();
     method public java.lang.String sendEnvelopeWithStatus(java.lang.String);
@@ -39149,6 +39151,12 @@
     method public abstract void onReceivedIcon(java.lang.String, android.graphics.Bitmap);
   }
 
+  public abstract class WebResourceError {
+    ctor public WebResourceError();
+    method public abstract java.lang.String getDescription();
+    method public abstract int getErrorCode();
+  }
+
   public abstract interface WebResourceRequest {
     method public abstract java.lang.String getMethod();
     method public abstract java.util.Map<java.lang.String, java.lang.String> getRequestHeaders();
@@ -39157,7 +39165,7 @@
     method public abstract boolean isForMainFrame();
   }
 
-  public class WebResourceResponse {
+  public class WebResourceResponse extends android.webkit.WebResourceResponseBase {
     ctor public WebResourceResponse(java.lang.String, java.lang.String, java.io.InputStream);
     ctor public WebResourceResponse(java.lang.String, java.lang.String, int, java.lang.String, java.util.Map<java.lang.String, java.lang.String>, java.io.InputStream);
     method public java.io.InputStream getData();
@@ -39173,6 +39181,16 @@
     method public void setStatusCodeAndReasonPhrase(int, java.lang.String);
   }
 
+  public abstract class WebResourceResponseBase {
+    ctor public WebResourceResponseBase();
+    method public abstract java.io.InputStream getData();
+    method public abstract java.lang.String getEncoding();
+    method public abstract java.lang.String getMimeType();
+    method public abstract java.lang.String getReasonPhrase();
+    method public abstract java.util.Map<java.lang.String, java.lang.String> getResponseHeaders();
+    method public abstract int getStatusCode();
+  }
+
   public abstract class WebSettings {
     ctor public WebSettings();
     method public abstract deprecated boolean enableSmoothTransition();
@@ -39532,8 +39550,10 @@
     method public void onPageFinished(android.webkit.WebView, java.lang.String);
     method public void onPageStarted(android.webkit.WebView, java.lang.String, android.graphics.Bitmap);
     method public void onReceivedClientCertRequest(android.webkit.WebView, android.webkit.ClientCertRequest);
-    method public void onReceivedError(android.webkit.WebView, int, java.lang.String, java.lang.String);
+    method public deprecated void onReceivedError(android.webkit.WebView, int, java.lang.String, java.lang.String);
+    method public void onReceivedError(android.webkit.WebView, android.webkit.WebResourceRequest, android.webkit.WebResourceError);
     method public void onReceivedHttpAuthRequest(android.webkit.WebView, android.webkit.HttpAuthHandler, java.lang.String, java.lang.String);
+    method public void onReceivedHttpError(android.webkit.WebView, android.webkit.WebResourceRequest, android.webkit.WebResourceResponseBase);
     method public void onReceivedLoginRequest(android.webkit.WebView, java.lang.String, java.lang.String, java.lang.String);
     method public void onReceivedSslError(android.webkit.WebView, android.webkit.SslErrorHandler, android.net.http.SslError);
     method public void onScaleChanged(android.webkit.WebView, float, float);
@@ -39546,6 +39566,7 @@
     method public boolean shouldOverrideUrlLoading(android.webkit.WebView, java.lang.String);
     field public static final int ERROR_AUTHENTICATION = -4; // 0xfffffffc
     field public static final int ERROR_BAD_URL = -12; // 0xfffffff4
+    field public static final int ERROR_BLOCKED = -16; // 0xfffffff0
     field public static final int ERROR_CONNECT = -6; // 0xfffffffa
     field public static final int ERROR_FAILED_SSL_HANDSHAKE = -11; // 0xfffffff5
     field public static final int ERROR_FILE = -13; // 0xfffffff3
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index ad2b61f..5572d30 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -1322,7 +1322,10 @@
     
     /*
      * Starts allocation counting. This triggers a gc and resets the counts.
+     *
+     * @deprecated Accurate counting is a burden on the runtime and may be removed.
      */
+    @Deprecated
     public void startAllocCounting() {
         // Before we start trigger a GC and reset the debug counts. Run the 
         // finalizers and another GC before starting and stopping the alloc
@@ -1340,7 +1343,10 @@
     
     /*
      * Stops allocation counting.
+     *
+     * @deprecated Accurate counting is a burden on the runtime and may be removed.
      */
+    @Deprecated
     public void stopAllocCounting() {
         Runtime.getRuntime().gc();
         Runtime.getRuntime().runFinalization();
diff --git a/core/java/android/app/backup/BackupAgent.java b/core/java/android/app/backup/BackupAgent.java
index 1b1e600..7f89100 100644
--- a/core/java/android/app/backup/BackupAgent.java
+++ b/core/java/android/app/backup/BackupAgent.java
@@ -258,6 +258,7 @@
      *
      * <ul>
      * <li>The contents of the {@link #getCacheDir()} directory</li>
+     * <li>The contents of the {@link #getCodeCacheDir()} directory</li>
      * <li>The contents of the {@link #getNoBackupFilesDir()} directory</li>
      * <li>The contents of the app's shared library directory</li>
      * </ul>
@@ -285,6 +286,7 @@
         String databaseDir = getDatabasePath("foo").getParentFile().getCanonicalPath();
         String sharedPrefsDir = getSharedPrefsFile("foo").getParentFile().getCanonicalPath();
         String cacheDir = getCacheDir().getCanonicalPath();
+        String codeCacheDir = getCodeCacheDir().getCanonicalPath();
         String libDir = (appInfo.nativeLibraryDir != null)
                 ? new File(appInfo.nativeLibraryDir).getCanonicalPath()
                 : null;
@@ -298,6 +300,7 @@
             filterSet.add(libDir);
         }
         filterSet.add(cacheDir);
+        filterSet.add(codeCacheDir);
         filterSet.add(databaseDir);
         filterSet.add(sharedPrefsDir);
         filterSet.add(filesDir);
@@ -354,6 +357,7 @@
         String dbDir;
         String spDir;
         String cacheDir;
+        String codeCacheDir;
         String libDir;
         String efDir = null;
         String filePath;
@@ -367,6 +371,7 @@
             dbDir = getDatabasePath("foo").getParentFile().getCanonicalPath();
             spDir = getSharedPrefsFile("foo").getParentFile().getCanonicalPath();
             cacheDir = getCacheDir().getCanonicalPath();
+            codeCacheDir = getCodeCacheDir().getCanonicalPath();
             libDir = (appInfo.nativeLibraryDir == null)
                     ? null
                     : new File(appInfo.nativeLibraryDir).getCanonicalPath();
@@ -380,7 +385,8 @@
             }
 
             // Now figure out which well-defined tree the file is placed in, working from
-            // most to least specific.  We also specifically exclude the lib and cache dirs.
+            // most to least specific.  We also specifically exclude the lib, cache,
+            // and code_cache dirs.
             filePath = file.getCanonicalPath();
         } catch (IOException e) {
             Log.w(TAG, "Unable to obtain canonical paths");
@@ -388,9 +394,10 @@
         }
 
         if (filePath.startsWith(cacheDir)
+                || filePath.startsWith(codeCacheDir)
                 || filePath.startsWith(libDir)
                 || filePath.startsWith(nbFilesDir)) {
-            Log.w(TAG, "lib, cache, and no_backup files are not backed up");
+            Log.w(TAG, "lib, cache, code_cache, and no_backup files are not backed up");
             return;
         }
 
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index d03365b..512e212 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -63,7 +63,10 @@
      *
      * TRACE_COUNT_ALLOCS adds the results from startAllocCounting to the
      * trace key file.
+     *
+     * @deprecated Accurate counting is a burden on the runtime and may be removed.
      */
+    @Deprecated
     public static final int TRACE_COUNT_ALLOCS  = VMDebug.TRACE_COUNT_ALLOCS;
 
     /**
@@ -760,7 +763,7 @@
     /**
      * Stop counting the number and aggregate size of memory allocations.
      *
-     * @see #startAllocCounting()
+     * @deprecated Accurate counting is a burden on the runtime and may be removed.
      */
     @Deprecated
     public static void stopAllocCounting() {
@@ -770,7 +773,10 @@
     /**
      * Returns the global count of objects allocated by the runtime between a
      * {@link #startAllocCounting() start} and {@link #stopAllocCounting() stop}.
+     *
+     * @deprecated Accurate counting is a burden on the runtime and may be removed.
      */
+    @Deprecated
     public static int getGlobalAllocCount() {
         return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_ALLOCATED_OBJECTS);
     }
@@ -778,7 +784,10 @@
     /**
      * Clears the global count of objects allocated.
      * @see #getGlobalAllocCount()
+     *
+     * @deprecated Accurate counting is a burden on the runtime and may be removed.
      */
+    @Deprecated
     public static void resetGlobalAllocCount() {
         VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_ALLOCATED_OBJECTS);
     }
@@ -786,7 +795,10 @@
     /**
      * Returns the global size, in bytes, of objects allocated by the runtime between a
      * {@link #startAllocCounting() start} and {@link #stopAllocCounting() stop}.
+     *
+     * @deprecated Accurate counting is a burden on the runtime and may be removed.
      */
+    @Deprecated
     public static int getGlobalAllocSize() {
         return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_ALLOCATED_BYTES);
     }
@@ -794,7 +806,10 @@
     /**
      * Clears the global size of objects allocated.
      * @see #getGlobalAllocSize()
+     *
+     * @deprecated Accurate counting is a burden on the runtime and may be removed.
      */
+    @Deprecated
     public static void resetGlobalAllocSize() {
         VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_ALLOCATED_BYTES);
     }
@@ -802,7 +817,10 @@
     /**
      * Returns the global count of objects freed by the runtime between a
      * {@link #startAllocCounting() start} and {@link #stopAllocCounting() stop}.
+     *
+     * @deprecated Accurate counting is a burden on the runtime and may be removed.
      */
+    @Deprecated
     public static int getGlobalFreedCount() {
         return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_FREED_OBJECTS);
     }
@@ -810,7 +828,10 @@
     /**
      * Clears the global count of objects freed.
      * @see #getGlobalFreedCount()
+     *
+     * @deprecated Accurate counting is a burden on the runtime and may be removed.
      */
+    @Deprecated
     public static void resetGlobalFreedCount() {
         VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_FREED_OBJECTS);
     }
@@ -818,7 +839,10 @@
     /**
      * Returns the global size, in bytes, of objects freed by the runtime between a
      * {@link #startAllocCounting() start} and {@link #stopAllocCounting() stop}.
+     *
+     * @deprecated Accurate counting is a burden on the runtime and may be removed.
      */
+    @Deprecated
     public static int getGlobalFreedSize() {
         return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_FREED_BYTES);
     }
@@ -826,7 +850,10 @@
     /**
      * Clears the global size of objects freed.
      * @see #getGlobalFreedSize()
+     *
+     * @deprecated Accurate counting is a burden on the runtime and may be removed.
      */
+    @Deprecated
     public static void resetGlobalFreedSize() {
         VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_FREED_BYTES);
     }
@@ -834,7 +861,10 @@
     /**
      * Returns the number of non-concurrent GC invocations between a
      * {@link #startAllocCounting() start} and {@link #stopAllocCounting() stop}.
+     *
+     * @deprecated Accurate counting is a burden on the runtime and may be removed.
      */
+    @Deprecated
     public static int getGlobalGcInvocationCount() {
         return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_GC_INVOCATIONS);
     }
@@ -842,7 +872,10 @@
     /**
      * Clears the count of non-concurrent GC invocations.
      * @see #getGlobalGcInvocationCount()
+     *
+     * @deprecated Accurate counting is a burden on the runtime and may be removed.
      */
+    @Deprecated
     public static void resetGlobalGcInvocationCount() {
         VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_GC_INVOCATIONS);
     }
@@ -851,7 +884,10 @@
      * Returns the number of classes successfully initialized (ie those that executed without
      * throwing an exception) between a {@link #startAllocCounting() start} and
      * {@link #stopAllocCounting() stop}.
+     *
+     * @deprecated Accurate counting is a burden on the runtime and may be removed.
      */
+    @Deprecated
     public static int getGlobalClassInitCount() {
         return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_CLASS_INIT_COUNT);
     }
@@ -859,7 +895,10 @@
     /**
      * Clears the count of classes initialized.
      * @see #getGlobalClassInitCount()
+     *
+     * @deprecated Accurate counting is a burden on the runtime and may be removed.
      */
+    @Deprecated
     public static void resetGlobalClassInitCount() {
         VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_CLASS_INIT_COUNT);
     }
@@ -867,7 +906,10 @@
     /**
      * Returns the time spent successfully initializing classes between a
      * {@link #startAllocCounting() start} and {@link #stopAllocCounting() stop}.
+     *
+     * @deprecated Accurate counting is a burden on the runtime and may be removed.
      */
+    @Deprecated
     public static int getGlobalClassInitTime() {
         /* cumulative elapsed time for class initialization, in usec */
         return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_CLASS_INIT_TIME);
@@ -876,7 +918,10 @@
     /**
      * Clears the count of time spent initializing classes.
      * @see #getGlobalClassInitTime()
+     *
+     * @deprecated Accurate counting is a burden on the runtime and may be removed.
      */
+    @Deprecated
     public static void resetGlobalClassInitTime() {
         VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_CLASS_INIT_TIME);
     }
@@ -948,7 +993,10 @@
     /**
      * Returns the thread-local count of objects allocated by the runtime between a
      * {@link #startAllocCounting() start} and {@link #stopAllocCounting() stop}.
+     *
+     * @deprecated Accurate counting is a burden on the runtime and may be removed.
      */
+    @Deprecated
     public static int getThreadAllocCount() {
         return VMDebug.getAllocCount(VMDebug.KIND_THREAD_ALLOCATED_OBJECTS);
     }
@@ -956,7 +1004,10 @@
     /**
      * Clears the thread-local count of objects allocated.
      * @see #getThreadAllocCount()
+     *
+     * @deprecated Accurate counting is a burden on the runtime and may be removed.
      */
+    @Deprecated
     public static void resetThreadAllocCount() {
         VMDebug.resetAllocCount(VMDebug.KIND_THREAD_ALLOCATED_OBJECTS);
     }
@@ -965,7 +1016,10 @@
      * Returns the thread-local size of objects allocated by the runtime between a
      * {@link #startAllocCounting() start} and {@link #stopAllocCounting() stop}.
      * @return The allocated size in bytes.
+     *
+     * @deprecated Accurate counting is a burden on the runtime and may be removed.
      */
+    @Deprecated
     public static int getThreadAllocSize() {
         return VMDebug.getAllocCount(VMDebug.KIND_THREAD_ALLOCATED_BYTES);
     }
@@ -973,7 +1027,10 @@
     /**
      * Clears the thread-local count of objects allocated.
      * @see #getThreadAllocSize()
+     *
+     * @deprecated Accurate counting is a burden on the runtime and may be removed.
      */
+    @Deprecated
     public static void resetThreadAllocSize() {
         VMDebug.resetAllocCount(VMDebug.KIND_THREAD_ALLOCATED_BYTES);
     }
@@ -1013,7 +1070,10 @@
     /**
      * Returns the number of thread-local non-concurrent GC invocations between a
      * {@link #startAllocCounting() start} and {@link #stopAllocCounting() stop}.
+     *
+     * @deprecated Accurate counting is a burden on the runtime and may be removed.
      */
+    @Deprecated
     public static int getThreadGcInvocationCount() {
         return VMDebug.getAllocCount(VMDebug.KIND_THREAD_GC_INVOCATIONS);
     }
@@ -1021,7 +1081,10 @@
     /**
      * Clears the thread-local count of non-concurrent GC invocations.
      * @see #getThreadGcInvocationCount()
+     *
+     * @deprecated Accurate counting is a burden on the runtime and may be removed.
      */
+    @Deprecated
     public static void resetThreadGcInvocationCount() {
         VMDebug.resetAllocCount(VMDebug.KIND_THREAD_GC_INVOCATIONS);
     }
@@ -1029,7 +1092,10 @@
     /**
      * Clears all the global and thread-local memory allocation counters.
      * @see #startAllocCounting()
+     *
+     * @deprecated Accurate counting is a burden on the runtime and may be removed.
      */
+    @Deprecated
     public static void resetAllCounts() {
         VMDebug.resetAllocCount(VMDebug.KIND_ALL_COUNTS);
     }
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index f25b640..4b3765a 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -5849,7 +5849,7 @@
      *
      * @see AccessibilityDelegate
      */
-    public void setAccessibilityDelegate(AccessibilityDelegate delegate) {
+    public void setAccessibilityDelegate(@Nullable AccessibilityDelegate delegate) {
         mAccessibilityDelegate = delegate;
     }
 
diff --git a/core/java/android/webkit/WebResourceError.java b/core/java/android/webkit/WebResourceError.java
new file mode 100644
index 0000000..080d174
--- /dev/null
+++ b/core/java/android/webkit/WebResourceError.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.webkit;
+
+/**
+ * Encapsulates information about errors occured during loading of web resources. See
+ * {@link WebViewClient#onReceivedError(WebView, WebResourceRequest, WebResourceError) WebViewClient.onReceivedError(WebView, WebResourceRequest, WebResourceError)}
+ */
+public abstract class WebResourceError {
+    /**
+     * Gets the error code of the error. The code corresponds to one
+     * of the ERROR_* constants in {@link WebViewClient}.
+     *
+     * @return The error code of the error
+     */
+    public abstract int getErrorCode();
+
+    /**
+     * Gets the string describing the error. Descriptions are localized,
+     * and thus can be used for communicating the problem to the user.
+     *
+     * @return The description of the error
+     */
+    public abstract String getDescription();
+}
diff --git a/core/java/android/webkit/WebResourceResponse.java b/core/java/android/webkit/WebResourceResponse.java
index f487a4e..a42aaa7 100644
--- a/core/java/android/webkit/WebResourceResponse.java
+++ b/core/java/android/webkit/WebResourceResponse.java
@@ -25,7 +25,7 @@
  * class from {@link WebViewClient#shouldInterceptRequest} to provide a custom
  * response when the WebView requests a particular resource.
  */
-public class WebResourceResponse {
+public class WebResourceResponse extends WebResourceResponseBase {
     private String mMimeType;
     private String mEncoding;
     private int mStatusCode;
@@ -75,38 +75,36 @@
     }
 
     /**
-     * Sets the resource response's MIME type, for example text/html.
+     * Sets the resource response's MIME type, for example &quot;text/html&quot;.
      *
-     * @param mimeType the resource response's MIME type
+     * @param mimeType The resource response's MIME type
      */
     public void setMimeType(String mimeType) {
         mMimeType = mimeType;
     }
 
     /**
-     * Gets the resource response's MIME type.
-     *
-     * @return the resource response's MIME type
+     * {@inheritDoc}
      */
+    @Override
     public String getMimeType() {
         return mMimeType;
     }
 
     /**
-     * Sets the resource response's encoding, for example UTF-8. This is used
+     * Sets the resource response's encoding, for example &quot;UTF-8&quot;. This is used
      * to decode the data from the input stream.
      *
-     * @param encoding the resource response's encoding
+     * @param encoding The resource response's encoding
      */
     public void setEncoding(String encoding) {
         mEncoding = encoding;
     }
 
     /**
-     * Gets the resource response's encoding.
-     *
-     * @return the resource response's encoding
+     * {@inheritDoc}
      */
+    @Override
     public String getEncoding() {
         return mEncoding;
     }
@@ -142,19 +140,17 @@
     }
 
     /**
-     * Gets the resource response's status code.
-     *
-     * @return the resource response's status code.
+     * {@inheritDoc}
      */
+    @Override
     public int getStatusCode() {
         return mStatusCode;
     }
 
     /**
-     * Gets the description of the resource response's status code.
-     *
-     * @return the description of the resource response's status code.
+     * {@inheritDoc}
      */
+    @Override
     public String getReasonPhrase() {
         return mReasonPhrase;
     }
@@ -162,17 +158,16 @@
     /**
      * Sets the headers for the resource response.
      *
-     * @param headers mapping of header name -> header value.
+     * @param headers Mapping of header name -> header value.
      */
     public void setResponseHeaders(Map<String, String> headers) {
         mResponseHeaders = headers;
     }
 
     /**
-     * Gets the headers for the resource response.
-     *
-     * @return the headers for the resource response.
+     * {@inheritDoc}
      */
+    @Override
     public Map<String, String> getResponseHeaders() {
         return mResponseHeaders;
     }
@@ -190,15 +185,13 @@
             throw new IllegalArgumentException("StringBufferInputStream is deprecated and must " +
                 "not be passed to a WebResourceResponse");
         }
-
         mInputStream = data;
     }
 
     /**
-     * Gets the input stream that provides the resource response's data.
-     *
-     * @return the input stream that provides the resource response's data
+     * {@inheritDoc}
      */
+    @Override
     public InputStream getData() {
         return mInputStream;
     }
diff --git a/core/java/android/webkit/WebResourceResponseBase.java b/core/java/android/webkit/WebResourceResponseBase.java
new file mode 100644
index 0000000..cffde82
--- /dev/null
+++ b/core/java/android/webkit/WebResourceResponseBase.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.webkit;
+
+import java.io.InputStream;
+import java.util.Map;
+
+/**
+ * Encapsulates a resource response received from the server.
+ * This is an abstract class used by WebView callbacks.
+ */
+public abstract class WebResourceResponseBase {
+    /**
+     * Gets the resource response's MIME type.
+     *
+     * @return The resource response's MIME type
+     */
+    public abstract String getMimeType();
+
+    /**
+     * Gets the resource response's encoding.
+     *
+     * @return The resource response's encoding
+     */
+    public abstract String getEncoding();
+
+    /**
+     * Gets the resource response's status code.
+     *
+     * @return The resource response's status code.
+     */
+    public abstract int getStatusCode();
+
+    /**
+     * Gets the description of the resource response's status code.
+     *
+     * @return The description of the resource response's status code.
+     */
+    public abstract String getReasonPhrase();
+
+    /**
+     * Gets the headers for the resource response.
+     *
+     * @return The headers for the resource response.
+     */
+    public abstract Map<String, String> getResponseHeaders();
+
+    /**
+     * Gets the input stream that provides the resource response's data.
+     *
+     * @return The input stream that provides the resource response's data
+     */
+    public abstract InputStream getData();
+}
diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java
index 1d2c311..3df1293 100644
--- a/core/java/android/webkit/WebSettings.java
+++ b/core/java/android/webkit/WebSettings.java
@@ -1285,7 +1285,7 @@
      * strongly discouraged.
      *
      * @param mode The mixed content mode to use. One of {@link #MIXED_CONTENT_NEVER_ALLOW},
-     *     {@link #MIXED_CONTENT_NEVER_ALLOW} or {@link #MIXED_CONTENT_COMPATIBILITY_MODE}.
+     *     {@link #MIXED_CONTENT_ALWAYS_ALLOW} or {@link #MIXED_CONTENT_COMPATIBILITY_MODE}.
      */
     public abstract void setMixedContentMode(int mode);
 
@@ -1293,7 +1293,7 @@
      * Gets the current behavior of the WebView with regard to loading insecure content from a
      * secure origin.
      * @return The current setting, one of {@link #MIXED_CONTENT_NEVER_ALLOW},
-     *     {@link #MIXED_CONTENT_NEVER_ALLOW} or {@link #MIXED_CONTENT_COMPATIBILITY_MODE}.
+     *     {@link #MIXED_CONTENT_ALWAYS_ALLOW} or {@link #MIXED_CONTENT_COMPATIBILITY_MODE}.
      */
     public abstract int getMixedContentMode();
 
diff --git a/core/java/android/webkit/WebViewClient.java b/core/java/android/webkit/WebViewClient.java
index 01f9b37..34b8cf6 100644
--- a/core/java/android/webkit/WebViewClient.java
+++ b/core/java/android/webkit/WebViewClient.java
@@ -174,6 +174,8 @@
     public static final int ERROR_FILE_NOT_FOUND = -14;
     /** Too many requests during this load */
     public static final int ERROR_TOO_MANY_REQUESTS = -15;
+    /** Request blocked by the browser */
+    public static final int ERROR_BLOCKED = -16;
 
     /**
      * Report an error to the host application. These errors are unrecoverable
@@ -183,12 +185,45 @@
      * @param errorCode The error code corresponding to an ERROR_* value.
      * @param description A String describing the error.
      * @param failingUrl The url that failed to load.
+     * @deprecated Use {@link #onReceivedError(WebView, WebResourceRequest, WebResourceError)
+     *             onReceivedError(WebView, WebResourceRequest, WebResourceError)} instead.
      */
+    @Deprecated
     public void onReceivedError(WebView view, int errorCode,
             String description, String failingUrl) {
     }
 
     /**
+     * Report web resource loading error to the host application. These errors usually indicate
+     * inability to connect to the server. Note that unlike the deprecated version of the callback,
+     * the new version will be called for any resource (iframe, image, etc), not just for the main
+     * page. Thus, it is recommended to perform minimum required work in this callback.
+     * @param view The WebView that is initiating the callback.
+     * @param request The originating request.
+     * @param error Information about the error occured.
+     */
+    public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
+        if (request.isForMainFrame()) {
+            onReceivedError(view,
+                    error.getErrorCode(), error.getDescription(), request.getUrl().toString());
+        }
+    }
+
+    /**
+     * Notify the host application that an HTTP error has been received from the server while
+     * loading a resource.  HTTP errors have status codes &gt;= 400.  This callback will be called
+     * for any resource (iframe, image, etc), not just for the main page. Thus, it is recommended to
+     * perform minimum required work in this callback. Note that the content of the server
+     * response may not be provided within the <b>errorResponse</b> parameter.
+     * @param view The WebView that is initiating the callback.
+     * @param request The originating request.
+     * @param errorResponse Information about the error occured.
+     */
+    public void onReceivedHttpError(
+            WebView view, WebResourceRequest request, WebResourceResponseBase errorResponse) {
+    }
+
+    /**
      * As the host application if the browser should resend data as the
      * requested page was a result of a POST. The default is to not resend the
      * data.
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 5d519ed..8197b3d 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -128,7 +128,7 @@
     // Each Editor manages its own undo stack.
     private final UndoManager mUndoManager = new UndoManager();
     private UndoOwner mUndoOwner = mUndoManager.getOwner(UNDO_OWNER_TAG, this);
-    final InputFilter mUndoInputFilter = new UndoInputFilter(this);
+    final UndoInputFilter mUndoInputFilter = new UndoInputFilter(this);
     boolean mAllowUndo = true;
 
     // Cursor Controllers.
@@ -246,6 +246,15 @@
         mUndoOwner = mUndoManager.getOwner(UNDO_OWNER_TAG, this);
     }
 
+    /**
+     * Forgets all undo and redo operations for this Editor.
+     */
+    void forgetUndoRedo() {
+        UndoOwner[] owners = { mUndoOwner };
+        mUndoManager.forgetUndos(owners, -1 /* all */);
+        mUndoManager.forgetRedos(owners, -1 /* all */);
+    }
+
     boolean canUndo() {
         UndoOwner[] owners = { mUndoOwner };
         return mAllowUndo && mUndoManager.countUndos(owners) > 0;
@@ -1214,6 +1223,7 @@
                     ims.mChangedEnd = EXTRACT_UNKNOWN;
                     ims.mContentChanged = false;
                 }
+                mUndoInputFilter.beginBatchEdit();
                 mTextView.onBeginBatchEdit();
             }
         }
@@ -1240,6 +1250,7 @@
 
     void finishBatchEdit(final InputMethodState ims) {
         mTextView.onEndBatchEdit();
+        mUndoInputFilter.endBatchEdit();
 
         if (ims.mContentChanged || ims.mSelectionModeChanged) {
             mTextView.updateAfterEdit();
@@ -4546,10 +4557,30 @@
     public static class UndoInputFilter implements InputFilter {
         private final Editor mEditor;
 
+        // Whether the current filter pass is directly caused by an end-user text edit.
+        private boolean mIsUserEdit;
+
+        // Whether this is the first pass through the filter for a given end-user text edit.
+        private boolean mFirstFilterPass;
+
         public UndoInputFilter(Editor editor) {
             mEditor = editor;
         }
 
+        /**
+         * Signals that a user-triggered edit is starting.
+         */
+        public void beginBatchEdit() {
+            if (DEBUG_UNDO) Log.d(TAG, "beginBatchEdit");
+            mIsUserEdit = true;
+            mFirstFilterPass = true;
+        }
+
+        public void endBatchEdit() {
+            if (DEBUG_UNDO) Log.d(TAG, "endBatchEdit");
+            mIsUserEdit = false;
+        }
+
         @Override
         public CharSequence filter(CharSequence source, int start, int end,
                 Spanned dest, int dstart, int dend) {
@@ -4558,36 +4589,24 @@
                         "dest=" + dest + " (" + dstart + "-" + dend + ")");
             }
 
-            if (!mEditor.mAllowUndo) {
-                if (DEBUG_UNDO) Log.d(TAG, "filter: undo is disabled");
+            // Check to see if this edit should be tracked for undo.
+            if (!canUndoEdit(source, start, end, dest, dstart, dend)) {
                 return null;
             }
 
-            final UndoManager um = mEditor.mUndoManager;
-            if (um.isInUndo()) {
-                if (DEBUG_UNDO) Log.d(TAG, "filter: skipping, currently performing undo/redo");
-                return null;
-            }
-
-            // Text filters run before input operations are applied. However, some input operations
-            // are invalid and will throw exceptions when applied. This is common in tests. Don't
-            // attempt to undo invalid operations.
-            if (!isValidRange(source, start, end) || !isValidRange(dest, dstart, dend)) {
-                if (DEBUG_UNDO) Log.d(TAG, "filter: invalid op");
-                return null;
-            }
-
-            // Earlier filters can rewrite input to be a no-op, for example due to a length limit
-            // on an input field. Skip no-op changes.
-            if (start == end && dstart == dend) {
-                if (DEBUG_UNDO) Log.d(TAG, "filter: skipping no-op");
-                return null;
-            }
+            // An application may install a TextWatcher to provide additional modifications after
+            // the initial input filters run (e.g. a credit card formatter that adds spaces to a
+            // string). This results in multiple filter() calls for what the user considers to be
+            // a single operation. Always undo the whole set of changes in one step.
+            final boolean forceMerge = !mFirstFilterPass;
+            mFirstFilterPass = false;
 
             // Build a new operation with all the information from this edit.
-            EditOperation edit = new EditOperation(mEditor, source, start, end, dest, dstart, dend);
+            EditOperation edit = new EditOperation(mEditor, forceMerge,
+                    source, start, end, dest, dstart, dend);
 
             // Fetch the last edit operation and attempt to merge in the new edit.
+            final UndoManager um = mEditor.mUndoManager;
             um.beginUpdate("Edit text");
             EditOperation lastEdit = um.getLastOperation(
                   EditOperation.class, mEditor.mUndoOwner, UndoManager.MERGE_MODE_UNIQUE);
@@ -4595,6 +4614,12 @@
                 // Add this as the first edit.
                 if (DEBUG_UNDO) Log.d(TAG, "filter: adding first op " + edit);
                 um.addOperation(edit, UndoManager.MERGE_MODE_NONE);
+            } else if (!mIsUserEdit) {
+                // An application directly modified the Editable outside of a text edit. Treat this
+                // as a new change and don't attempt to merge.
+                if (DEBUG_UNDO) Log.d(TAG, "non-user edit, new op " + edit);
+                um.commitState(mEditor.mUndoOwner);
+                um.addOperation(edit, UndoManager.MERGE_MODE_NONE);
             } else if (lastEdit.mergeWith(edit)) {
                 // Merge succeeded, nothing else to do.
                 if (DEBUG_UNDO) Log.d(TAG, "filter: merge succeeded, created " + lastEdit);
@@ -4607,6 +4632,36 @@
             um.endUpdate();
             return null;  // Text not changed.
         }
+
+        private boolean canUndoEdit(CharSequence source, int start, int end,
+                Spanned dest, int dstart, int dend) {
+            if (!mEditor.mAllowUndo) {
+                if (DEBUG_UNDO) Log.d(TAG, "filter: undo is disabled");
+                return false;
+            }
+
+            if (mEditor.mUndoManager.isInUndo()) {
+                if (DEBUG_UNDO) Log.d(TAG, "filter: skipping, currently performing undo/redo");
+                return false;
+            }
+
+            // Text filters run before input operations are applied. However, some input operations
+            // are invalid and will throw exceptions when applied. This is common in tests. Don't
+            // attempt to undo invalid operations.
+            if (!isValidRange(source, start, end) || !isValidRange(dest, dstart, dend)) {
+                if (DEBUG_UNDO) Log.d(TAG, "filter: invalid op");
+                return false;
+            }
+
+            // Earlier filters can rewrite input to be a no-op, for example due to a length limit
+            // on an input field. Skip no-op changes.
+            if (start == end && dstart == dend) {
+                if (DEBUG_UNDO) Log.d(TAG, "filter: skipping no-op");
+                return false;
+            }
+
+            return true;
+        }
     }
 
     /**
@@ -4618,6 +4673,7 @@
         private static final int TYPE_REPLACE = 2;
 
         private int mType;
+        private boolean mForceMerge;
         private String mOldText;
         private int mOldTextStart;
         private String mNewText;
@@ -4629,10 +4685,12 @@
         /**
          * Constructs an edit operation from a text input operation that replaces the range
          * (dstart, dend) of dest with (start, end) of source. See {@link InputFilter#filter}.
+         * If forceMerge is true then always forcibly merge this operation with any previous one.
          */
-        public EditOperation(Editor editor, CharSequence source, int start, int end,
-                Spanned dest, int dstart, int dend) {
+        public EditOperation(Editor editor, boolean forceMerge,
+                CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
             super(editor.mUndoOwner);
+            mForceMerge = forceMerge;
 
             mOldText = dest.subSequence(dstart, dend).toString();
             mNewText = source.subSequence(start, end).toString();
@@ -4660,6 +4718,7 @@
         public EditOperation(Parcel src, ClassLoader loader) {
             super(src, loader);
             mType = src.readInt();
+            mForceMerge = src.readInt() != 0;
             mOldText = src.readString();
             mOldTextStart = src.readInt();
             mNewText = src.readString();
@@ -4671,6 +4730,7 @@
         @Override
         public void writeToParcel(Parcel dest, int flags) {
             dest.writeInt(mType);
+            dest.writeInt(mForceMerge ? 1 : 0);
             dest.writeString(mOldText);
             dest.writeInt(mOldTextStart);
             dest.writeString(mNewText);
@@ -4679,6 +4739,14 @@
             dest.writeInt(mNewCursorPos);
         }
 
+        private int getNewTextEnd() {
+            return mNewTextStart + mNewText.length();
+        }
+
+        private int getOldTextEnd() {
+            return mOldTextStart + mOldText.length();
+        }
+
         @Override
         public void commit() {
         }
@@ -4687,14 +4755,20 @@
         public void undo() {
             if (DEBUG_UNDO) Log.d(TAG, "undo");
             // Remove the new text and insert the old.
-            modifyText(mNewTextStart, getNewTextEnd(), mOldText, mOldTextStart, mOldCursorPos);
+            Editor editor = getOwnerData();
+            Editable text = (Editable) editor.mTextView.getText();
+            modifyText(text, mNewTextStart, getNewTextEnd(), mOldText, mOldTextStart,
+                    mOldCursorPos);
         }
 
         @Override
         public void redo() {
             if (DEBUG_UNDO) Log.d(TAG, "redo");
             // Remove the old text and insert the new.
-            modifyText(mOldTextStart, getOldTextEnd(), mNewText, mNewTextStart, mNewCursorPos);
+            Editor editor = getOwnerData();
+            Editable text = (Editable) editor.mTextView.getText();
+            modifyText(text, mOldTextStart, getOldTextEnd(), mNewText, mNewTextStart,
+                    mNewCursorPos);
         }
 
         /**
@@ -4704,6 +4778,14 @@
          * object unchanged.
          */
         private boolean mergeWith(EditOperation edit) {
+            if (DEBUG_UNDO) {
+                Log.d(TAG, "mergeWith old " + this);
+                Log.d(TAG, "mergeWith new " + edit);
+            }
+            if (edit.mForceMerge) {
+                forceMergeWith(edit);
+                return true;
+            }
             switch (mType) {
                 case TYPE_INSERT:
                     return mergeInsertWith(edit);
@@ -4717,7 +4799,6 @@
         }
 
         private boolean mergeInsertWith(EditOperation edit) {
-            if (DEBUG_UNDO) Log.d(TAG, "mergeInsertWith " + edit);
             // Only merge continuous insertions.
             if (edit.mType != TYPE_INSERT) {
                 return false;
@@ -4733,7 +4814,6 @@
 
         // TODO: Support forward delete.
         private boolean mergeDeleteWith(EditOperation edit) {
-            if (DEBUG_UNDO) Log.d(TAG, "mergeDeleteWith " + edit);
             // Only merge continuous deletes.
             if (edit.mType != TYPE_DELETE) {
                 return false;
@@ -4749,11 +4829,8 @@
         }
 
         private boolean mergeReplaceWith(EditOperation edit) {
-            if (DEBUG_UNDO) Log.d(TAG, "mergeReplaceWith " + edit);
-            // Replacements can merge only with adjacent inserts and adjacent replacements.
-            if (edit.mType == TYPE_DELETE ||
-                    getNewTextEnd() != edit.mOldTextStart ||
-                    edit.mOldTextStart != edit.mNewTextStart) {
+            // Replacements can merge only with adjacent inserts.
+            if (edit.mType != TYPE_INSERT || getNewTextEnd() != edit.mNewTextStart) {
                 return false;
             }
             mOldText += edit.mOldText;
@@ -4762,18 +4839,42 @@
             return true;
         }
 
-        private int getNewTextEnd() {
-            return mNewTextStart + mNewText.length();
-        }
-
-        private int getOldTextEnd() {
-            return mOldTextStart + mOldText.length();
-        }
-
-        private void modifyText(int deleteFrom, int deleteTo, CharSequence newText,
-                int newTextInsertAt, int newCursorPos) {
+        /**
+         * Forcibly creates a single merged edit operation by simulating the entire text
+         * contents being replaced.
+         */
+        private void forceMergeWith(EditOperation edit) {
+            if (DEBUG_UNDO) Log.d(TAG, "forceMerge");
             Editor editor = getOwnerData();
-            Editable text = (Editable) editor.mTextView.getText();
+
+            // Copy the text of the current field.
+            // NOTE: Using StringBuilder instead of SpannableStringBuilder would be somewhat faster,
+            // but would require two parallel implementations of modifyText() because Editable and
+            // StringBuilder do not share an interface for replace/delete/insert.
+            Editable editable = (Editable) editor.mTextView.getText();
+            Editable originalText = new SpannableStringBuilder(editable.toString());
+
+            // Roll back the last operation.
+            modifyText(originalText, mNewTextStart, getNewTextEnd(), mOldText, mOldTextStart,
+                    mOldCursorPos);
+
+            // Clone the text again and apply the new operation.
+            Editable finalText = new SpannableStringBuilder(editable.toString());
+            modifyText(finalText, edit.mOldTextStart, edit.getOldTextEnd(), edit.mNewText,
+                    edit.mNewTextStart, edit.mNewCursorPos);
+
+            // Convert this operation into a non-mergeable replacement of the entire string.
+            mType = TYPE_REPLACE;
+            mNewText = finalText.toString();
+            mNewTextStart = 0;
+            mOldText = originalText.toString();
+            mOldTextStart = 0;
+            mNewCursorPos = edit.mNewCursorPos;
+            // mOldCursorPos is unchanged.
+        }
+
+        private static void modifyText(Editable text, int deleteFrom, int deleteTo,
+                CharSequence newText, int newTextInsertAt, int newCursorPos) {
             // Apply the edit if it is still valid.
             if (isValidRange(text, deleteFrom, deleteTo) &&
                     newTextInsertAt <= text.length() - (deleteTo - deleteFrom)) {
@@ -4791,10 +4892,22 @@
             }
         }
 
+        private String getTypeString() {
+            switch (mType) {
+                case TYPE_INSERT:
+                    return "insert";
+                case TYPE_DELETE:
+                    return "delete";
+                case TYPE_REPLACE:
+                    return "replace";
+                default:
+                    return "";
+            }
+        }
+
         @Override
         public String toString() {
-            return "EditOperation: [" +
-                    "mType=" + mType + ", " +
+            return "[mType=" + getTypeString() + ", " +
                     "mOldText=" + mOldText + ", " +
                     "mOldTextStart=" + mOldTextStart + ", " +
                     "mNewText=" + mNewText + ", " +
diff --git a/core/java/android/widget/LinearLayout.java b/core/java/android/widget/LinearLayout.java
index f599035..da15302 100644
--- a/core/java/android/widget/LinearLayout.java
+++ b/core/java/android/widget/LinearLayout.java
@@ -19,6 +19,7 @@
 import com.android.internal.R;
 
 import android.annotation.IntDef;
+import android.annotation.Nullable;
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.graphics.Canvas;
@@ -186,11 +187,11 @@
         this(context, null);
     }
 
-    public LinearLayout(Context context, AttributeSet attrs) {
+    public LinearLayout(Context context, @Nullable AttributeSet attrs) {
         this(context, attrs, 0);
     }
     
-    public LinearLayout(Context context, AttributeSet attrs, int defStyleAttr) {
+    public LinearLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
         this(context, attrs, defStyleAttr, 0);
     }
 
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 9bef1fe..dfe68fd 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -637,16 +637,17 @@
         this(context, null);
     }
 
-    public TextView(Context context, AttributeSet attrs) {
+    public TextView(Context context, @Nullable AttributeSet attrs) {
         this(context, attrs, com.android.internal.R.attr.textViewStyle);
     }
 
-    public TextView(Context context, AttributeSet attrs, int defStyleAttr) {
+    public TextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
         this(context, attrs, defStyleAttr, 0);
     }
 
     @SuppressWarnings("deprecation")
-    public TextView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+    public TextView(
+            Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
 
         mText = "";
@@ -4119,6 +4120,7 @@
         if (type == BufferType.EDITABLE || getKeyListener() != null ||
                 needEditableForNotification) {
             createEditorIfNeeded();
+            mEditor.forgetUndoRedo();
             Editable t = mEditableFactory.newEditable(text);
             text = t;
             setFilters(t, mFilters);
diff --git a/core/java/com/android/internal/backup/LocalTransport.java b/core/java/com/android/internal/backup/LocalTransport.java
index c3cc60a..fb0ffb0 100644
--- a/core/java/com/android/internal/backup/LocalTransport.java
+++ b/core/java/com/android/internal/backup/LocalTransport.java
@@ -369,6 +369,9 @@
                 return TRANSPORT_ERROR;
             }
         }
+        if (DEBUG) {
+            Log.v(TAG, "   stored " + numBytes + " of data");
+        }
         return TRANSPORT_OK;
     }
 
@@ -431,6 +434,10 @@
 
     @Override
     public RestoreDescription nextRestorePackage() {
+        if (DEBUG) {
+            Log.v(TAG, "nextRestorePackage() : mRestorePackage=" + mRestorePackage
+                    + " length=" + mRestorePackages.length);
+        }
         if (mRestorePackages == null) throw new IllegalStateException("startRestore not called");
 
         boolean found = false;
@@ -441,7 +448,10 @@
             // skip packages where we have a data dir but no actual contents
             String[] contents = (new File(mRestoreSetIncrementalDir, name)).list();
             if (contents != null && contents.length > 0) {
-                if (DEBUG) Log.v(TAG, "  nextRestorePackage(TYPE_KEY_VALUE) = " + name);
+                if (DEBUG) {
+                    Log.v(TAG, "  nextRestorePackage(TYPE_KEY_VALUE) @ "
+                        + mRestorePackage + " = " + name);
+                }
                 mRestoreType = RestoreDescription.TYPE_KEY_VALUE;
                 found = true;
             }
@@ -450,7 +460,10 @@
                 // No key/value data; check for [non-empty] full data
                 File maybeFullData = new File(mRestoreSetFullDir, name);
                 if (maybeFullData.length() > 0) {
-                    if (DEBUG) Log.v(TAG, "  nextRestorePackage(TYPE_FULL_STREAM) = " + name);
+                    if (DEBUG) {
+                        Log.v(TAG, "  nextRestorePackage(TYPE_FULL_STREAM) @ "
+                                + mRestorePackage + " = " + name);
+                    }
                     mRestoreType = RestoreDescription.TYPE_FULL_STREAM;
                     mCurFullRestoreStream = null;   // ensure starting from the ground state
                     found = true;
@@ -460,6 +473,11 @@
             if (found) {
                 return new RestoreDescription(name, mRestoreType);
             }
+
+            if (DEBUG) {
+                Log.v(TAG, "  ... package @ " + mRestorePackage + " = " + name
+                        + " has no data; skipping");
+            }
         }
 
         if (DEBUG) Log.v(TAG, "  no more packages to restore");
diff --git a/docs/html/guide/topics/connectivity/usb/host.jd b/docs/html/guide/topics/connectivity/usb/host.jd
index 355dd2d..f957b60 100644
--- a/docs/html/guide/topics/connectivity/usb/host.jd
+++ b/docs/html/guide/topics/connectivity/usb/host.jd
@@ -31,7 +31,7 @@
         <li><a href="{@docRoot}resources/samples/USB/AdbTest/index.html">AdbTest</a></li>
 
         <li><a href=
-        "{@docRoot}resources/samples/USB/MissileLauncher/index.html">MissleLauncher</a></li>
+        "{@docRoot}resources/samples/USB/MissileLauncher/index.html">MissileLauncher</a></li>
       </ol>
     </div>
   </div>
@@ -283,7 +283,7 @@
 
   <h3 id="permission-d">Obtaining permission to communicate with a device</h3>
 
-  <p>Before communicating with the USB device, your applicaton must have permission from your
+  <p>Before communicating with the USB device, your application must have permission from your
   users.</p>
 
   <p class="note"><strong>Note:</strong> If your application <a href="#using-intents">uses an
@@ -388,7 +388,7 @@
   should have more logic to correctly find the correct interface and endpoints to communicate on
   and also should do any transferring of data in a different thread than the main UI thread:</p>
   <pre>
-private Byte[] bytes
+private Byte[] bytes;
 private static int TIMEOUT = 0;
 private boolean forceClaim = true;
 
@@ -409,7 +409,7 @@
   <p>For more information, see the <a href=
   "{@docRoot}resources/samples/USB/AdbTest/index.html">AdbTest sample</a>, which shows how to do
   asynchronous bulk transfers, and the <a href=
-  "{@docRoot}resources/samples/USB/MissileLauncher/index.html">MissleLauncher sample</a>, which
+  "{@docRoot}resources/samples/USB/MissileLauncher/index.html">MissileLauncher sample</a>, which
   shows how to listen on an interrupt endpoint asynchronously.</p>
 
   <h3 id="terminating-d">Terminating communication with a device</h3>
diff --git a/docs/html/tools/adk/adk.jd b/docs/html/tools/adk/adk.jd
index 7e75c11..3f45c3c 100644
--- a/docs/html/tools/adk/adk.jd
+++ b/docs/html/tools/adk/adk.jd
@@ -331,7 +331,7 @@
     <li>Install the application to your device.</li>
 
     <li>Connect the ADK board (USB-A) to your Android-powered device (micro-USB). Ensure that the
-    power cable to the accessory is plugged in or that the micro-USB port on the accesory is
+    power cable to the accessory is plugged in or that the micro-USB port on the accessory is
     connected to your computer for power (this also allows you to <a href="#monitoring">monitor the
     ADK board</a>). When connected, accept the prompt that asks for whether or not to open the
     DemoKit application to connect to the accessory. If the prompt does not show up, connect and
diff --git a/graphics/java/android/graphics/PorterDuff.java b/graphics/java/android/graphics/PorterDuff.java
index f5fbe70..dcccf35 100644
--- a/graphics/java/android/graphics/PorterDuff.java
+++ b/graphics/java/android/graphics/PorterDuff.java
@@ -51,7 +51,7 @@
              Sc*(1 - Da) + Dc*(1 - Sa) + max(Sc, Dc)] */
         LIGHTEN     (17),
         /** [Sa * Da, Sc * Dc] */
-        MULTIPLY    (24),
+        MULTIPLY    (13),
         /** [Sa + Da - Sa * Da, Sc + Dc - Sc * Dc] */
         SCREEN      (14),
         /** Saturate(S + D) */
diff --git a/libs/hwui/ProgramCache.cpp b/libs/hwui/ProgramCache.cpp
index 8c6a91cc..e9b22e2 100644
--- a/libs/hwui/ProgramCache.cpp
+++ b/libs/hwui/ProgramCache.cpp
@@ -380,9 +380,9 @@
         // Xor
         "return vec4(src.rgb * (1.0 - dst.a) + (1.0 - src.a) * dst.rgb, "
                 "src.a + dst.a - 2.0 * src.a * dst.a);\n",
-        // Add
+        // Plus
         "return min(src + dst, 1.0);\n",
-        // Multiply
+        // Modulate
         "return src * dst;\n",
         // Screen
         "return src + dst - src * dst;\n",
@@ -830,7 +830,7 @@
     while ((index = shader.find("\n", index)) > -1) {
         String8 line(str, index - lastIndex);
         if (line.length() == 0) line.append("\n");
-        PROGRAM_LOGD("%s", line.string());
+        ALOGD("%s", line.string());
         index++;
         str += (index - lastIndex);
         lastIndex = index;
diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp
index 1cf589d..16758d0 100644
--- a/media/jni/android_media_MediaCodec.cpp
+++ b/media/jni/android_media_MediaCodec.cpp
@@ -215,7 +215,7 @@
 status_t JMediaCodec::setCallback(jobject cb) {
     if (cb != NULL) {
         if (mCallbackNotification == NULL) {
-            mCallbackNotification = new AMessage(kWhatCallbackNotify, id());
+            mCallbackNotification = new AMessage(kWhatCallbackNotify, this);
         }
     } else {
         mCallbackNotification.clear();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 3a812cc..37d9a73 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -59,6 +59,7 @@
 import android.service.notification.StatusBarNotification;
 import android.text.TextUtils;
 import android.util.Log;
+import android.util.Slog;
 import android.util.SparseArray;
 import android.util.SparseBooleanArray;
 import android.view.Display;
@@ -2150,6 +2151,14 @@
     }
 
     public boolean isKeyguardSecure() {
+        if (mStatusBarKeyguardViewManager == null) {
+            // startKeyguard() hasn't been called yet, so we don't know.
+            // Make sure anything that needs to know isKeyguardSecure() checks and re-checks this
+            // value onVisibilityChanged().
+            Slog.w(TAG, "isKeyguardSecure() called before startKeyguard(), returning false",
+                    new Throwable());
+            return false;
+        }
         return mStatusBarKeyguardViewManager.isSecure();
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
index acf7af9..0c21b20 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -220,6 +220,7 @@
 
     public void setPhoneStatusBar(PhoneStatusBar phoneStatusBar) {
         mPhoneStatusBar = phoneStatusBar;
+        updateCameraVisibility(); // in case onFinishInflate() was called too early
     }
 
     private Intent getCameraIntent() {
@@ -231,6 +232,10 @@
     }
 
     private void updateCameraVisibility() {
+        if (mCameraImageView == null) {
+            // Things are not set up yet; reply hazy, ask again later
+            return;
+        }
         ResolveInfo resolved = mContext.getPackageManager().resolveActivityAsUser(getCameraIntent(),
                 PackageManager.MATCH_DEFAULT_ONLY,
                 mLockPatternUtils.getCurrentUser());
@@ -253,7 +258,7 @@
     private boolean isCameraDisabledByDpm() {
         final DevicePolicyManager dpm =
                 (DevicePolicyManager) getContext().getSystemService(Context.DEVICE_POLICY_SERVICE);
-        if (dpm != null) {
+        if (dpm != null && mPhoneStatusBar != null) {
             try {
                 final int userId = ActivityManagerNative.getDefault().getCurrentUser().id;
                 final int disabledFlags = dpm.getKeyguardDisabledFeatures(null, userId);
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index 94d400a..26510328 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -601,7 +601,7 @@
         return token;
     }
 
-    // High level policy: apps are ineligible for backup if certain conditions apply
+    // High level policy: apps are generally ineligible for backup if certain conditions apply
     public static boolean appIsEligibleForBackup(ApplicationInfo app) {
         // 1. their manifest states android:allowBackup="false"
         if ((app.flags&ApplicationInfo.FLAG_ALLOW_BACKUP) == 0) {
@@ -628,7 +628,7 @@
             return (pkg.applicationInfo.flags & ApplicationInfo.FLAG_FULL_BACKUP_ONLY) != 0;
         }
 
-        // No agent means we do full backups for it
+        // No agent or fullBackupOnly="true" means we do indeed perform full-data backups for it
         return true;
     }
 
@@ -1266,7 +1266,23 @@
                     for (int i = 0; i < N; i++) {
                         String pkgName = in.readUTF();
                         long lastBackup = in.readLong();
-                        schedule.add(new FullBackupEntry(pkgName, lastBackup));
+                        try {
+                            PackageInfo pkg = mPackageManager.getPackageInfo(pkgName, 0);
+                            if (appGetsFullBackup(pkg)
+                                    && appIsEligibleForBackup(pkg.applicationInfo)) {
+                                schedule.add(new FullBackupEntry(pkgName, lastBackup));
+                            } else {
+                                if (DEBUG) {
+                                    Slog.i(TAG, "Package " + pkgName
+                                            + " no longer eligible for full backup");
+                                }
+                            }
+                        } catch (NameNotFoundException e) {
+                            if (DEBUG) {
+                                Slog.i(TAG, "Package " + pkgName
+                                        + " not installed; dropping from full backup");
+                            }
+                        }
                     }
                     Collections.sort(schedule);
                 } catch (Exception e) {
@@ -1289,7 +1305,7 @@
                 schedule = new ArrayList<FullBackupEntry>(N);
                 for (int i = 0; i < N; i++) {
                     PackageInfo info = apps.get(i);
-                    if (appGetsFullBackup(info)) {
+                    if (appGetsFullBackup(info) && appIsEligibleForBackup(info.applicationInfo)) {
                         schedule.add(new FullBackupEntry(info.packageName, 0));
                     }
                 }
@@ -1761,11 +1777,11 @@
                     addPackageParticipantsLocked(pkgList);
                 }
                 // If they're full-backup candidates, add them there instead
+                final long now = System.currentTimeMillis();
                 for (String packageName : pkgList) {
                     try {
                         PackageInfo app = mPackageManager.getPackageInfo(packageName, 0);
-                        long now = System.currentTimeMillis();
-                        if (appGetsFullBackup(app)) {
+                        if (appGetsFullBackup(app) && appIsEligibleForBackup(app.applicationInfo)) {
                             enqueueFullBackup(packageName, now);
                             scheduleNextFullBackupJob();
                         }
@@ -2462,7 +2478,7 @@
             BackupRequest request = mQueue.get(0);
             mQueue.remove(0);
 
-            Slog.d(TAG, "starting agent for backup of " + request);
+            Slog.d(TAG, "starting key/value backup of " + request);
             addBackupTrace("launch agent for " + request.packageName);
 
             // Verify that the requested app exists; it might be something that
@@ -2473,13 +2489,24 @@
             try {
                 mCurrentPackage = mPackageManager.getPackageInfo(request.packageName,
                         PackageManager.GET_SIGNATURES);
-                if (mCurrentPackage.applicationInfo.backupAgentName == null) {
+                if (!appIsEligibleForBackup(mCurrentPackage.applicationInfo)) {
                     // The manifest has changed but we had a stale backup request pending.
                     // This won't happen again because the app won't be requesting further
                     // backups.
                     Slog.i(TAG, "Package " + request.packageName
                             + " no longer supports backup; skipping");
-                    addBackupTrace("skipping - no agent, completion is noop");
+                    addBackupTrace("skipping - not eligible, completion is noop");
+                    executeNextState(BackupState.RUNNING_QUEUE);
+                    return;
+                }
+
+                if (appGetsFullBackup(mCurrentPackage)) {
+                    // It's possible that this app *formerly* was enqueued for key/value backup,
+                    // but has since been updated and now only supports the full-data path.
+                    // Don't proceed with a key/value backup for it in this case.
+                    Slog.i(TAG, "Package " + request.packageName
+                            + " requests full-data rather than key/value; skipping");
+                    addBackupTrace("skipping - fullBackupOnly, completion is noop");
                     executeNextState(BackupState.RUNNING_QUEUE);
                     return;
                 }
@@ -9161,6 +9188,8 @@
             // check whether there is data for it in the current dataset, falling back
             // to the ancestral dataset if not.
             long token = getAvailableRestoreToken(packageName);
+            if (DEBUG) Slog.v(TAG, "restorePackage pkg=" + packageName
+                    + " token=" + Long.toHexString(token));
 
             // If we didn't come up with a place to look -- no ancestral dataset and
             // the app has never been backed up from this device -- there's nothing
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 0a4b787..f3b2d2e 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -3716,6 +3716,34 @@
     }
 
     /**
+     * Whether the device supports configuring the DTMF tone length.
+     *
+     * @return {@code true} if the DTMF tone length can be changed, and {@code false} otherwise.
+     */
+    public boolean canChangeDtmfToneLength() {
+        try {
+            return getITelephony().canChangeDtmfToneLength();
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error calling ITelephony#canChangeDtmfToneLength", e);
+        }
+        return false;
+    }
+
+    /**
+     * Whether the device is a world phone.
+     *
+     * @return {@code true} if the device is a world phone, and {@code false} otherwise.
+     */
+    public boolean isWorldPhone() {
+        try {
+            return getITelephony().isWorldPhone();
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error calling ITelephony#isWorldPhone", e);
+        }
+        return false;
+    }
+
+    /**
      * This function retrieves value for setting "name+subId", and if that is not found
      * retrieves value for setting "name", and if that is not found uses def as default
      *
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 62c8746..3769dee 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -863,11 +863,25 @@
     /**
      * Whether video calling has been enabled by the user.
      *
-     * @return {@code True} if the user has enabled video calling, {@code false} otherwise.
+     * @return {@code true} if the user has enabled video calling, {@code false} otherwise.
      */
     boolean isVideoCallingEnabled();
 
     /**
+     * Whether the DTMF tone length can be changed.
+     *
+     * @return {@code true} if the DTMF tone length can be changed.
+     */
+    boolean canChangeDtmfToneLength();
+
+    /**
+     * Whether the device is a world phone.
+     *
+     * @return {@code true} if the devices is a world phone.
+     */
+    boolean isWorldPhone();
+
+    /**
      * Get IMS Registration Status
      */
     boolean isImsRegistered();