Merge "Ensure that activities behind keyguard are paused." into klp-dev
diff --git a/api/current.txt b/api/current.txt
index 49ce637..fd9f0be 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -3167,31 +3167,27 @@
   }
 
   public class AppOpsManager {
-    method public int checkOp(int, int, java.lang.String);
-    method public int checkOpNoThrow(int, int, java.lang.String);
+    method public int checkOp(java.lang.String, int, java.lang.String);
+    method public int checkOpNoThrow(java.lang.String, int, java.lang.String);
     method public void checkPackage(int, java.lang.String);
-    method public void finishOp(int, int, java.lang.String);
-    method public void finishOp(int);
-    method public int noteOp(int, int, java.lang.String);
-    method public int noteOpNoThrow(int, int, java.lang.String);
-    method public static java.lang.String opToName(int);
-    method public int startOp(int, int, java.lang.String);
-    method public int startOpNoThrow(int, int, java.lang.String);
-    method public void startWatchingMode(int, java.lang.String, android.app.AppOpsManager.Callback);
-    method public void stopWatchingMode(android.app.AppOpsManager.Callback);
+    method public void finishOp(java.lang.String, int, java.lang.String);
+    method public int noteOp(java.lang.String, int, java.lang.String);
+    method public int noteOpNoThrow(java.lang.String, int, java.lang.String);
+    method public int startOp(java.lang.String, int, java.lang.String);
+    method public int startOpNoThrow(java.lang.String, int, java.lang.String);
+    method public void startWatchingMode(int, java.lang.String, android.app.AppOpsManager.OnOpChangedListener);
+    method public void stopWatchingMode(android.app.AppOpsManager.OnOpChangedListener);
     field public static final int MODE_ALLOWED = 0; // 0x0
     field public static final int MODE_ERRORED = 2; // 0x2
     field public static final int MODE_IGNORED = 1; // 0x1
-    field public static final int OP_COARSE_LOCATION = 0; // 0x0
-    field public static final int OP_FINE_LOCATION = 1; // 0x1
-    field public static final int OP_GPS = 2; // 0x2
-    field public static final int OP_MONITOR_HIGH_POWER_LOCATION = 42; // 0x2a
-    field public static final int OP_MONITOR_LOCATION = 41; // 0x29
-    field public static final int OP_NONE = -1; // 0xffffffff
+    field public static final java.lang.String OPSTR_COARSE_LOCATION = "android:coarse_location";
+    field public static final java.lang.String OPSTR_FINE_LOCATION = "android:fine_location";
+    field public static final java.lang.String OPSTR_MONITOR_HIGH_POWER_LOCATION = "android:monitor_location_high_power";
+    field public static final java.lang.String OPSTR_MONITOR_LOCATION = "android:monitor_location";
   }
 
-  public static abstract interface AppOpsManager.Callback {
-    method public abstract void opChanged(int, java.lang.String);
+  public static abstract interface AppOpsManager.OnOpChangedListener {
+    method public abstract void onOpChanged(java.lang.String, java.lang.String);
   }
 
   public class Application extends android.content.ContextWrapper implements android.content.ComponentCallbacks2 {
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index bf2a1e4..055044b 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -23,6 +23,7 @@
 import com.android.internal.app.IAppOpsCallback;
 
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
 
 import android.content.Context;
@@ -32,50 +33,76 @@
 import android.os.RemoteException;
 
 /**
- * API for interacting with "application operation" tracking.  Allows you to:
+ * API for interacting with "application operation" tracking.
  *
- * <ul>
- * <li> Note when operations are happening, and find out if they are allowed for the current
- * caller.</li>
- * <li> Disallow specific apps from doing specific operations.</li>
- * <li> Collect all of the current information about operations that have been executed or are not
- * being allowed.</li>
- * <li> Monitor for changes in whether an operation is allowed.</li>
- * </ul>
- *
- * <p>Each operation is identified by a single integer; these integers are a fixed set of
- * operations, enumerated by the OP_* constants.
- *
- * <p></p>When checking operations, the result is a "mode" integer indicating the current setting
- * for the operation under that caller: MODE_ALLOWED, MODE_IGNORED (don't execute the operation but
- * fake its behavior enough so that the caller doesn't crash), MODE_ERRORED (through a
- * SecurityException back to the caller; the normal operation calls will do this for you).
+ * <p>This API is not generally intended for third party application developers; most
+ * features are only available to system applicatins.  Obtain an instance of it through
+ * {@link Context#getSystemService(String) Context.getSystemService} with
+ * {@link Context#APP_OPS_SERVICE Context.APP_OPS_SERVICE}.</p>
  */
 public class AppOpsManager {
+    /**
+     * <p>App ops allows callers to:</p>
+     *
+     * <ul>
+     * <li> Note when operations are happening, and find out if they are allowed for the current
+     * caller.</li>
+     * <li> Disallow specific apps from doing specific operations.</li>
+     * <li> Collect all of the current information about operations that have been executed or
+     * are not being allowed.</li>
+     * <li> Monitor for changes in whether an operation is allowed.</li>
+     * </ul>
+     *
+     * <p>Each operation is identified by a single integer; these integers are a fixed set of
+     * operations, enumerated by the OP_* constants.
+     *
+     * <p></p>When checking operations, the result is a "mode" integer indicating the current
+     * setting for the operation under that caller: MODE_ALLOWED, MODE_IGNORED (don't execute
+     * the operation but fake its behavior enough so that the caller doesn't crash),
+     * MODE_ERRORED (throw a SecurityException back to the caller; the normal operation calls
+     * will do this for you).
+     */
+
     final Context mContext;
     final IAppOpsService mService;
-    final ArrayMap<Callback, IAppOpsCallback> mModeWatchers
-            = new ArrayMap<Callback, IAppOpsCallback>();
+    final ArrayMap<OnOpChangedListener, IAppOpsCallback> mModeWatchers
+            = new ArrayMap<OnOpChangedListener, IAppOpsCallback>();
 
     static IBinder sToken;
 
+    /**
+     * Result from {@link #checkOp}, {@link #noteOp}, {@link #startOp}: the given caller is
+     * allowed to perform the given operation.
+     */
     public static final int MODE_ALLOWED = 0;
+
+    /**
+     * Result from {@link #checkOp}, {@link #noteOp}, {@link #startOp}: the given caller is
+     * not allowed to perform the given operation, and this attempt should
+     * <em>silently fail</em> (it should not cause the app to crash).
+     */
     public static final int MODE_IGNORED = 1;
+
+    /**
+     * Result from {@link #checkOpNoThrow}, {@link #noteOpNoThrow}, {@link #startOpNoThrow}: the
+     * given caller is not allowed to perform the given operation, and this attempt should
+     * cause it to have a fatal error, typically a {@link SecurityException}.
+     */
     public static final int MODE_ERRORED = 2;
 
     // when adding one of these:
     //  - increment _NUM_OP
-    //  - add rows to sOpToSwitch, sOpNames, sOpPerms, sOpDefaultMode
+    //  - add rows to sOpToSwitch, sOpToString, sOpNames, sOpPerms, sOpDefaultMode
     //  - add descriptive strings to Settings/res/values/arrays.xml
     //  - add the op to the appropriate template in AppOpsState.OpsTemplate (settings app)
 
-    /** No operation specified. */
+    /** @hide No operation specified. */
     public static final int OP_NONE = -1;
-    /** Access to coarse location information. */
+    /** @hide Access to coarse location information. */
     public static final int OP_COARSE_LOCATION = 0;
-    /** Access to fine location information. */
+    /** @hide Access to fine location information. */
     public static final int OP_FINE_LOCATION = 1;
-    /** Causing GPS to run. */
+    /** @hide Causing GPS to run. */
     public static final int OP_GPS = 2;
     /** @hide */
     public static final int OP_VIBRATE = 3;
@@ -153,13 +180,26 @@
     public static final int OP_AUDIO_BLUETOOTH_VOLUME = 39;
     /** @hide */
     public static final int OP_WAKE_LOCK = 40;
-    /** Continually monitoring location data. */
+    /** @hide Continually monitoring location data. */
     public static final int OP_MONITOR_LOCATION = 41;
-    /** Continually monitoring location data with a relatively high power request. */
+    /** @hide Continually monitoring location data with a relatively high power request. */
     public static final int OP_MONITOR_HIGH_POWER_LOCATION = 42;
     /** @hide */
     public static final int _NUM_OP = 43;
 
+    /** Access to coarse location information. */
+    public static final String OPSTR_COARSE_LOCATION =
+            "android:coarse_location";
+    /** Access to fine location information. */
+    public static final String OPSTR_FINE_LOCATION =
+            "android:fine_location";
+    /** Continually monitoring location data. */
+    public static final String OPSTR_MONITOR_LOCATION
+            = "android:monitor_location";
+    /** Continually monitoring location data with a relatively high power request. */
+    public static final String OPSTR_MONITOR_HIGH_POWER_LOCATION
+            = "android:monitor_location_high_power";
+
     /**
      * This maps each operation to the operation that serves as the
      * switch to determine whether it is allowed.  Generally this is
@@ -215,6 +255,56 @@
     };
 
     /**
+     * This maps each operation to the public string constant for it.
+     * If it doesn't have a public string constant, it maps to null.
+     */
+    private static String[] sOpToString = new String[] {
+            OPSTR_COARSE_LOCATION,
+            OPSTR_FINE_LOCATION,
+            null,
+            null,
+            null,
+            null,
+            null,
+            null,
+            null,
+            null,
+            null,
+            null,
+            null,
+            null,
+            null,
+            null,
+            null,
+            null,
+            null,
+            null,
+            null,
+            null,
+            null,
+            null,
+            null,
+            null,
+            null,
+            null,
+            null,
+            null,
+            null,
+            null,
+            null,
+            null,
+            null,
+            null,
+            null,
+            null,
+            null,
+            null,
+            null,
+            OPSTR_MONITOR_LOCATION,
+            OPSTR_MONITOR_HIGH_POWER_LOCATION,
+    };
+
+    /**
      * This provides a simple name for each operation to be used
      * in debug output.
      */
@@ -363,6 +453,36 @@
             AppOpsManager.MODE_ALLOWED,
     };
 
+    private static HashMap<String, Integer> sOpStrToOp = new HashMap<String, Integer>();
+
+    static {
+        if (sOpToSwitch.length != _NUM_OP) {
+            throw new IllegalStateException("sOpStringLength " + sOpToSwitch.length
+                    + " should be " + _NUM_OP);
+        }
+        if (sOpToString.length != _NUM_OP) {
+            throw new IllegalStateException("sOpStringLength " + sOpToString.length
+                    + " should be " + _NUM_OP);
+        }
+        if (sOpNames.length != _NUM_OP) {
+            throw new IllegalStateException("sOpStringLength " + sOpNames.length
+                    + " should be " + _NUM_OP);
+        }
+        if (sOpPerms.length != _NUM_OP) {
+            throw new IllegalStateException("sOpStringLength " + sOpPerms.length
+                    + " should be " + _NUM_OP);
+        }
+        if (sOpDefaultMode.length != _NUM_OP) {
+            throw new IllegalStateException("sOpStringLength " + sOpDefaultMode.length
+                    + " should be " + _NUM_OP);
+        }
+        for (int i=0; i<_NUM_OP; i++) {
+            if (sOpToString[i] != null) {
+                sOpStrToOp.put(sOpToString[i], i);
+            }
+        }
+    }
+
     /**
      * Retrieve the op switch that controls the given operation.
      * @hide
@@ -373,6 +493,7 @@
 
     /**
      * Retrieve a non-localized name for the operation, for debugging output.
+     * @hide
      */
     public static String opToName(int op) {
         if (op == OP_NONE) return "NONE";
@@ -537,8 +658,18 @@
     /**
      * Callback for notification of changes to operation state.
      */
-    public interface Callback {
-        public void opChanged(int op, String packageName);
+    public interface OnOpChangedListener {
+        public void onOpChanged(String op, String packageName);
+    }
+
+    /**
+     * Callback for notification of changes to operation state.
+     * This allows you to see the raw op codes instead of strings.
+     * @hide
+     */
+    public static class OnOpChangedInternalListener implements OnOpChangedListener {
+        public void onOpChanged(String op, String packageName) { }
+        public void onOpChanged(int op, String packageName) { }
     }
 
     AppOpsManager(Context context, IAppOpsService service) {
@@ -598,13 +729,18 @@
      * @param packageName The name of the application to monitor.
      * @param callback Where to report changes.
      */
-    public void startWatchingMode(int op, String packageName, final Callback callback) {
+    public void startWatchingMode(int op, String packageName, final OnOpChangedListener callback) {
         synchronized (mModeWatchers) {
             IAppOpsCallback cb = mModeWatchers.get(callback);
             if (cb == null) {
                 cb = new IAppOpsCallback.Stub() {
                     public void opChanged(int op, String packageName) {
-                        callback.opChanged(op, packageName);
+                        if (callback instanceof OnOpChangedInternalListener) {
+                            ((OnOpChangedInternalListener)callback).onOpChanged(op, packageName);
+                        }
+                        if (sOpToString[op] != null) {
+                            callback.onOpChanged(sOpToString[op], packageName);
+                        }
                     }
                 };
                 mModeWatchers.put(callback, cb);
@@ -620,7 +756,7 @@
      * Stop monitoring that was previously started with {@link #startWatchingMode}.  All
      * monitoring associated with this callback will be removed.
      */
-    public void stopWatchingMode(Callback callback) {
+    public void stopWatchingMode(OnOpChangedListener callback) {
         synchronized (mModeWatchers) {
             IAppOpsCallback cb = mModeWatchers.get(callback);
             if (cb != null) {
@@ -636,6 +772,106 @@
         return packageName + " from uid " + uid + " not allowed to perform " + sOpNames[op];
     }
 
+    private int strOpToOp(String op) {
+        Integer val = sOpStrToOp.get(op);
+        if (val == null) {
+            throw new IllegalArgumentException("Unknown operation string: " + op);
+        }
+        return val;
+    }
+
+    /**
+     * Do a quick check for whether an application might be able to perform an operation.
+     * This is <em>not</em> a security check; you must use {@link #noteOp(String, int, String)}
+     * or {@link #startOp(String, int, String)} for your actual security checks, which also
+     * ensure that the given uid and package name are consistent.  This function can just be
+     * used for a quick check to see if an operation has been disabled for the application,
+     * as an early reject of some work.  This does not modify the time stamp or other data
+     * about the operation.
+     * @param op The operation to check.  One of the OPSTR_* constants.
+     * @param uid The user id of the application attempting to perform the operation.
+     * @param packageName The name of the application attempting to perform the operation.
+     * @return Returns {@link #MODE_ALLOWED} if the operation is allowed, or
+     * {@link #MODE_IGNORED} if it is not allowed and should be silently ignored (without
+     * causing the app to crash).
+     * @throws SecurityException If the app has been configured to crash on this op.
+     */
+    public int checkOp(String op, int uid, String packageName) {
+        return checkOp(strOpToOp(op), uid, packageName);
+    }
+
+    /**
+     * Like {@link #checkOp but instead of throwing a {@link SecurityException} it
+     * returns {@link #MODE_ERRORED}.
+     */
+    public int checkOpNoThrow(String op, int uid, String packageName) {
+        return checkOpNoThrow(strOpToOp(op), uid, packageName);
+    }
+
+    /**
+     * Make note of an application performing an operation.  Note that you must pass
+     * in both the uid and name of the application to be checked; this function will verify
+     * that these two match, and if not, return {@link #MODE_IGNORED}.  If this call
+     * succeeds, the last execution time of the operation for this app will be updated to
+     * the current time.
+     * @param op The operation to note.  One of the OPSTR_* constants.
+     * @param uid The user id of the application attempting to perform the operation.
+     * @param packageName The name of the application attempting to perform the operation.
+     * @return Returns {@link #MODE_ALLOWED} if the operation is allowed, or
+     * {@link #MODE_IGNORED} if it is not allowed and should be silently ignored (without
+     * causing the app to crash).
+     * @throws SecurityException If the app has been configured to crash on this op.
+     */
+    public int noteOp(String op, int uid, String packageName) {
+        return noteOp(strOpToOp(op), uid, packageName);
+    }
+
+    /**
+     * Like {@link #noteOp} but instead of throwing a {@link SecurityException} it
+     * returns {@link #MODE_ERRORED}.
+     */
+    public int noteOpNoThrow(String op, int uid, String packageName) {
+        return noteOpNoThrow(strOpToOp(op), uid, packageName);
+    }
+
+    /**
+     * Report that an application has started executing a long-running operation.  Note that you
+     * must pass in both the uid and name of the application to be checked; this function will
+     * verify that these two match, and if not, return {@link #MODE_IGNORED}.  If this call
+     * succeeds, the last execution time of the operation for this app will be updated to
+     * the current time and the operation will be marked as "running".  In this case you must
+     * later call {@link #finishOp(String, int, String)} to report when the application is no
+     * longer performing the operation.
+     * @param op The operation to start.  One of the OPSTR_* constants.
+     * @param uid The user id of the application attempting to perform the operation.
+     * @param packageName The name of the application attempting to perform the operation.
+     * @return Returns {@link #MODE_ALLOWED} if the operation is allowed, or
+     * {@link #MODE_IGNORED} if it is not allowed and should be silently ignored (without
+     * causing the app to crash).
+     * @throws SecurityException If the app has been configured to crash on this op.
+     */
+    public int startOp(String op, int uid, String packageName) {
+        return startOp(strOpToOp(op), uid, packageName);
+    }
+
+    /**
+     * Like {@link #startOp} but instead of throwing a {@link SecurityException} it
+     * returns {@link #MODE_ERRORED}.
+     */
+    public int startOpNoThrow(String op, int uid, String packageName) {
+        return startOpNoThrow(strOpToOp(op), uid, packageName);
+    }
+
+    /**
+     * Report that an application is no longer performing an operation that had previously
+     * been started with {@link #startOp(String, int, String)}.  There is no validation of input
+     * or result; the parameters supplied here must be the exact same ones previously passed
+     * in when starting the operation.
+     */
+    public void finishOp(String op, int uid, String packageName) {
+        finishOp(strOpToOp(op), uid, packageName);
+    }
+
     /**
      * Do a quick check for whether an application might be able to perform an operation.
      * This is <em>not</em> a security check; you must use {@link #noteOp(int, int, String)}
@@ -651,6 +887,7 @@
      * {@link #MODE_IGNORED} if it is not allowed and should be silently ignored (without
      * causing the app to crash).
      * @throws SecurityException If the app has been configured to crash on this op.
+     * @hide
      */
     public int checkOp(int op, int uid, String packageName) {
         try {
@@ -667,6 +904,7 @@
     /**
      * Like {@link #checkOp} but instead of throwing a {@link SecurityException} it
      * returns {@link #MODE_ERRORED}.
+     * @hide
      */
     public int checkOpNoThrow(int op, int uid, String packageName) {
         try {
@@ -706,6 +944,7 @@
      * {@link #MODE_IGNORED} if it is not allowed and should be silently ignored (without
      * causing the app to crash).
      * @throws SecurityException If the app has been configured to crash on this op.
+     * @hide
      */
     public int noteOp(int op, int uid, String packageName) {
         try {
@@ -722,6 +961,7 @@
     /**
      * Like {@link #noteOp} but instead of throwing a {@link SecurityException} it
      * returns {@link #MODE_ERRORED}.
+     * @hide
      */
     public int noteOpNoThrow(int op, int uid, String packageName) {
         try {
@@ -766,6 +1006,7 @@
      * {@link #MODE_IGNORED} if it is not allowed and should be silently ignored (without
      * causing the app to crash).
      * @throws SecurityException If the app has been configured to crash on this op.
+     * @hide
      */
     public int startOp(int op, int uid, String packageName) {
         try {
@@ -782,6 +1023,7 @@
     /**
      * Like {@link #startOp} but instead of throwing a {@link SecurityException} it
      * returns {@link #MODE_ERRORED}.
+     * @hide
      */
     public int startOpNoThrow(int op, int uid, String packageName) {
         try {
@@ -801,6 +1043,7 @@
      * been started with {@link #startOp(int, int, String)}.  There is no validation of input
      * or result; the parameters supplied here must be the exact same ones previously passed
      * in when starting the operation.
+     * @hide
      */
     public void finishOp(int op, int uid, String packageName) {
         try {
@@ -809,6 +1052,7 @@
         }
     }
 
+    /** @hide */
     public void finishOp(int op) {
         finishOp(op, Process.myUid(), mContext.getOpPackageName());
     }
diff --git a/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java b/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java
index bcef79c..5d48350 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java
@@ -444,6 +444,10 @@
             // the requested pages, then nothing else to do.
             if (!infoChanged && !layoutChanged
                     && PageRangeUtils.contains(mDocument.pages, mRequestedPages)) {
+                // Nothing interesting changed and we have all requested pages.
+                // Then update the print jobs's pages as we will not do a write
+                // and we usually update the pages in the write complete callback.
+                updatePrintJobPages(mDocument.pages, mRequestedPages);
                 if (mEditor.isDone()) {
                     requestCreatePdfFileOrFinish();
                 }
@@ -499,36 +503,44 @@
                         + " and got: " + Arrays.toString(mDocument.pages));
             }
 
+            updatePrintJobPages(mDocument.pages, mRequestedPages);
+
+            if (mEditor.isDone()) {
+                requestCreatePdfFileOrFinish();
+            }
+        }
+
+        private void updatePrintJobPages(PageRange[] writtenPages, PageRange[] requestedPages) {
             // Adjust the print job pages based on what was requested and written.
             // The cases are ordered in the most expected to the least expected.
-            if (Arrays.equals(mDocument.pages, mRequestedPages)) {
+            if (Arrays.equals(writtenPages, requestedPages)) {
                 // We got a document with exactly the pages we wanted. Hence,
                 // the printer has to print all pages in the data.
                 PrintSpoolerService.peekInstance().setPrintJobPagesNoPersistence(mPrintJobId,
                         ALL_PAGES_ARRAY);
-            } else if (Arrays.equals(mDocument.pages, ALL_PAGES_ARRAY)) {
+            } else if (Arrays.equals(writtenPages, ALL_PAGES_ARRAY)) {
                 // We requested specific pages but got all of them. Hence,
                 // the printer has to print only the requested pages.
                 PrintSpoolerService.peekInstance().setPrintJobPagesNoPersistence(mPrintJobId,
-                        mRequestedPages);
-            } else if (PageRangeUtils.contains(mDocument.pages, mRequestedPages)) {
+                        requestedPages);
+            } else if (PageRangeUtils.contains(writtenPages, requestedPages)) {
                 // We requested specific pages and got more but not all pages.
                 // Hence, we have to offset appropriately the printed pages to
-                // exclude the pages we did not request. Note that pages is
-                // guaranteed to be not null and not empty.
-                final int offset = mDocument.pages[0].getStart() - pages[0].getStart();
-                PageRange[] offsetPages = Arrays.copyOf(mDocument.pages, mDocument.pages.length);
-                PageRangeUtils.offsetStart(offsetPages, offset);
+                // be based off the start of the written ones instead of zero.
+                // The written pages are always non-null and not empty.
+                final int offset = -writtenPages[0].getStart();
+                PageRange[] offsetPages = Arrays.copyOf(requestedPages, requestedPages.length);
+                PageRangeUtils.offset(offsetPages, offset);
                 PrintSpoolerService.peekInstance().setPrintJobPagesNoPersistence(mPrintJobId,
                         offsetPages);
-            } else if (Arrays.equals(mRequestedPages, ALL_PAGES_ARRAY)
-                    && mDocument.pages.length == 1 && mDocument.pages[0].getStart() == 0
-                    && mDocument.pages[0].getEnd() == mDocument.info.getPageCount() - 1) {
+            } else if (Arrays.equals(requestedPages, ALL_PAGES_ARRAY)
+                    && writtenPages.length == 1 && writtenPages[0].getStart() == 0
+                    && writtenPages[0].getEnd() == mDocument.info.getPageCount() - 1) {
                 // We requested all pages via the special constant and got all
                 // of them as an explicit enumeration. Hence, the printer has
                 // to print only the requested pages.
                 PrintSpoolerService.peekInstance().setPrintJobPagesNoPersistence(mPrintJobId,
-                        mDocument.pages);
+                        writtenPages);
             } else {
                 // We did not get the pages we requested, then the application
                 // misbehaves, so we fail quickly.
@@ -537,10 +549,6 @@
                 Log.e(LOG_TAG, "Received invalid pages from the app");
                 PrintJobConfigActivity.this.finish();
             }
-
-            if (mEditor.isDone()) {
-                requestCreatePdfFileOrFinish();
-            }
         }
 
         private void requestCreatePdfFileOrFinish() {
@@ -2191,38 +2199,39 @@
             throw new UnsupportedOperationException();
         }
 
-        public static boolean contains(PageRange[] ourPageRanges, PageRange[] otherPageRanges) {
-            if (ourPageRanges == null || otherPageRanges == null) {
+        public static boolean contains(PageRange[] ourRanges, PageRange[] otherRanges) {
+            if (ourRanges == null || otherRanges == null) {
                 return false;
             }
 
-            if (ourPageRanges.length == 1
-                    && PageRange.ALL_PAGES.equals(ourPageRanges[0])) {
+            if (ourRanges.length == 1
+                    && PageRange.ALL_PAGES.equals(ourRanges[0])) {
                 return true;
             }
 
-            otherPageRanges = normalize(otherPageRanges);
+            ourRanges = normalize(ourRanges);
+            otherRanges = normalize(otherRanges);
 
-            int otherPageIdx = 0;
-            final int myPageCount = ourPageRanges.length;
-            final int otherPageCount = otherPageRanges.length;
-            for (int i= 0; i < myPageCount; i++) {
-                PageRange myPage = ourPageRanges[i];
-                for (; otherPageIdx < otherPageCount; otherPageIdx++) {
-                    PageRange otherPage = otherPageRanges[otherPageIdx];
-                    if (otherPage.getStart() > myPage.getStart()) {
+            // Note that the code below relies on the ranges being normalized
+            // which is they contain monotonically increasing non-intersecting
+            // subranges whose start is less that or equal to the end.
+            int otherRangeIdx = 0;
+            final int ourRangeCount = ourRanges.length;
+            final int otherRangeCount = otherRanges.length;
+            for (int ourRangeIdx = 0; ourRangeIdx < ourRangeCount; ourRangeIdx++) {
+                PageRange ourRange = ourRanges[ourRangeIdx];
+                for (; otherRangeIdx < otherRangeCount; otherRangeIdx++) {
+                    PageRange otherRange = otherRanges[otherRangeIdx];
+                    if (otherRange.getStart() > ourRange.getEnd()) {
                         break;
                     }
-                    if ((otherPage.getStart() < myPage.getStart()
-                                    && otherPage.getEnd() > myPage.getStart())
-                            || (otherPage.getEnd() > myPage.getEnd()
-                                    && otherPage.getStart() < myPage.getEnd())
-                            || (otherPage.getEnd() < myPage.getStart())) {
+                    if (otherRange.getStart() < ourRange.getStart()
+                            || otherRange.getEnd() > ourRange.getEnd()) {
                         return false;
                     }
                 }
             }
-            if (otherPageIdx < otherPageCount) {
+            if (otherRangeIdx < otherRangeCount) {
                 return false;
             }
             return true;
@@ -2256,7 +2265,7 @@
                     oldRangeCount);
         }
 
-        public static void offsetStart(PageRange[] pageRanges, int offset) {
+        public static void offset(PageRange[] pageRanges, int offset) {
             if (offset == 0) {
                 return;
             }
diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java
index b6ccce7..3e8770e 100644
--- a/services/java/com/android/server/LocationManagerService.java
+++ b/services/java/com/android/server/LocationManagerService.java
@@ -223,8 +223,9 @@
             mGeofenceManager = new GeofenceManager(mContext, mBlacklist);
 
             // Monitor for app ops mode changes.
-            AppOpsManager.Callback callback = new AppOpsManager.Callback() {
-                public void opChanged(int op, String packageName) {
+            AppOpsManager.OnOpChangedListener callback
+                    = new AppOpsManager.OnOpChangedInternalListener() {
+                public void onOpChanged(int op, String packageName) {
                     synchronized (mLock) {
                         for (Receiver receiver : mReceivers.values()) {
                             receiver.updateMonitoring(true);
diff --git a/services/java/com/android/server/am/ActiveServices.java b/services/java/com/android/server/am/ActiveServices.java
index 4379c70..fa1769f 100644
--- a/services/java/com/android/server/am/ActiveServices.java
+++ b/services/java/com/android/server/am/ActiveServices.java
@@ -1009,23 +1009,15 @@
                 stracker.setExecuting(true, mAm.mProcessStats.getMemFactorLocked(), now);
             }
             if (r.app != null) {
-                if (r.app.executingServices.size() == 0) {
-                    Message msg = mAm.mHandler.obtainMessage(
-                            ActivityManagerService.SERVICE_TIMEOUT_MSG);
-                    msg.obj = r.app;
-                    mAm.mHandler.sendMessageAtTime(msg,
-                            fg ? (now+SERVICE_TIMEOUT) : (now+ SERVICE_BACKGROUND_TIMEOUT));
-                }
                 r.app.executingServices.add(r);
                 r.app.execServicesFg |= fg;
+                if (r.app.executingServices.size() == 1) {
+                    scheduleServiceTimeoutLocked(r.app);
+                }
             }
         } else if (r.app != null && fg && !r.app.execServicesFg) {
-            mAm.mHandler.removeMessages(ActivityManagerService.SERVICE_TIMEOUT_MSG);
-            Message msg = mAm.mHandler.obtainMessage(
-                    ActivityManagerService.SERVICE_TIMEOUT_MSG);
-            msg.obj = r.app;
-            mAm.mHandler.sendMessageAtTime(msg,now+SERVICE_TIMEOUT);
             r.app.execServicesFg = true;
+            scheduleServiceTimeoutLocked(r.app);
         }
         r.executeFg |= fg;
         r.executeNesting++;
@@ -2144,7 +2136,7 @@
                         ActivityManagerService.SERVICE_TIMEOUT_MSG);
                 msg.obj = proc;
                 mAm.mHandler.sendMessageAtTime(msg, proc.execServicesFg
-                        ? (nextTime+SERVICE_TIMEOUT) : (nextTime+ SERVICE_BACKGROUND_TIMEOUT));
+                        ? (nextTime+SERVICE_TIMEOUT) : (nextTime + SERVICE_BACKGROUND_TIMEOUT));
             }
         }
 
@@ -2153,6 +2145,18 @@
         }
     }
 
+    void scheduleServiceTimeoutLocked(ProcessRecord proc) {
+        if (proc.executingServices.size() == 0 || proc.thread == null) {
+            return;
+        }
+        long now = SystemClock.uptimeMillis();
+        Message msg = mAm.mHandler.obtainMessage(
+                ActivityManagerService.SERVICE_TIMEOUT_MSG);
+        msg.obj = proc;
+        mAm.mHandler.sendMessageAtTime(msg,
+                proc.execServicesFg ? (now+SERVICE_TIMEOUT) : (now+ SERVICE_BACKGROUND_TIMEOUT));
+    }
+
     /**
      * Prints a list of ServiceRecords (dumpsys activity services)
      */
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 47297c0..cbe97d2 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -2230,7 +2230,8 @@
         mHandler.sendMessage(msg);
     }
 
-    private final int updateLruProcessInternalLocked(ProcessRecord app, long now, int index) {
+    private final int updateLruProcessInternalLocked(ProcessRecord app, long now, int index,
+            String what, Object obj, ProcessRecord srcApp) {
         app.lastActivityTime = now;
 
         if (app.activities.size() > 0) {
@@ -2241,7 +2242,7 @@
         int lrui = mLruProcesses.lastIndexOf(app);
         if (lrui < 0) {
             throw new IllegalStateException("Adding dependent process " + app
-                    + " not on LRU list!");
+                    + " not on LRU list: " + what + obj + " from " + srcApp);
         }
 
         if (lrui >= mLruProcessActivityStart) {
@@ -2309,13 +2310,15 @@
             if (cr.binding != null && cr.binding.service != null
                     && cr.binding.service.app != null
                     && cr.binding.service.app.lruSeq != mLruSeq) {
-                nextIndex = updateLruProcessInternalLocked(cr.binding.service.app, now, nextIndex);
+                nextIndex = updateLruProcessInternalLocked(cr.binding.service.app, now, nextIndex,
+                        "service connection", cr, app);
             }
         }
         for (int j=app.conProviders.size()-1; j>=0; j--) {
             ContentProviderRecord cpr = app.conProviders.get(j).provider;
             if (cpr.proc != null && cpr.proc.lruSeq != mLruSeq) {
-                nextIndex = updateLruProcessInternalLocked(cpr.proc, now, nextIndex);
+                nextIndex = updateLruProcessInternalLocked(cpr.proc, now, nextIndex,
+                        "provider reference", cpr, app);
             }
         }
 
@@ -3863,7 +3866,13 @@
                 // 0 == show dialog, 1 = keep waiting, -1 = kill process immediately
                 int res = mController.appNotResponding(app.processName, app.pid, info.toString());
                 if (res != 0) {
-                    if (res < 0 && app.pid != MY_PID) Process.killProcess(app.pid);
+                    if (res < 0 && app.pid != MY_PID) {
+                        Process.killProcess(app.pid);
+                    } else {
+                        synchronized (this) {
+                            mServices.scheduleServiceTimeoutLocked(app);
+                        }
+                    }
                     return;
                 }
             } catch (RemoteException e) {
diff --git a/services/java/com/android/server/am/AppNotRespondingDialog.java b/services/java/com/android/server/am/AppNotRespondingDialog.java
index b5e0715..d0a0441 100644
--- a/services/java/com/android/server/am/AppNotRespondingDialog.java
+++ b/services/java/com/android/server/am/AppNotRespondingDialog.java
@@ -128,6 +128,7 @@
                         if (app.anrDialog == AppNotRespondingDialog.this) {
                             app.anrDialog = null;
                         }
+                        mService.mServices.scheduleServiceTimeoutLocked(app);
                     }
                     break;
             }
diff --git a/services/java/com/android/server/am/ServiceRecord.java b/services/java/com/android/server/am/ServiceRecord.java
index 448117e..ac14da9 100644
--- a/services/java/com/android/server/am/ServiceRecord.java
+++ b/services/java/com/android/server/am/ServiceRecord.java
@@ -253,6 +253,7 @@
                     pw.print(" executeFg="); pw.print(executeFg);
                     pw.print(" executingStart=");
                     TimeUtils.formatDuration(executingStart, now, pw);
+                    pw.println();
         }
         if (crashCount != 0 || restartCount != 0
                 || restartDelay != 0 || nextRestartTime != 0) {
diff --git a/services/java/com/android/server/content/SyncManager.java b/services/java/com/android/server/content/SyncManager.java
index 9a41166..635ba5c 100644
--- a/services/java/com/android/server/content/SyncManager.java
+++ b/services/java/com/android/server/content/SyncManager.java
@@ -315,7 +315,9 @@
                     if (Log.isLoggable(TAG, Log.VERBOSE)) {
                         Log.v(TAG, "Reconnection detected: clearing all backoffs");
                     }
-                    mSyncStorageEngine.clearAllBackoffs(mSyncQueue);
+                    synchronized(mSyncQueue) {
+                        mSyncStorageEngine.clearAllBackoffsLocked(mSyncQueue);
+                    }
                 }
                 sendCheckAlarmsMessage();
             }
diff --git a/services/java/com/android/server/content/SyncStorageEngine.java b/services/java/com/android/server/content/SyncStorageEngine.java
index 1b9ed98..d51c2d7 100644
--- a/services/java/com/android/server/content/SyncStorageEngine.java
+++ b/services/java/com/android/server/content/SyncStorageEngine.java
@@ -710,28 +710,31 @@
         }
     }
 
-    public void clearAllBackoffs(SyncQueue syncQueue) {
+    /**
+     * Callers of this function need to hold a lock for syncQueue object passed in. Bear in mind
+     * this function grabs the lock for {@link #mAuthorities}
+     * @param syncQueue queue containing pending sync operations.
+     */
+    public void clearAllBackoffsLocked(SyncQueue syncQueue) {
         boolean changed = false;
         synchronized (mAuthorities) {
-            synchronized (syncQueue) {
-                for (AccountInfo accountInfo : mAccounts.values()) {
-                    for (AuthorityInfo authorityInfo : accountInfo.authorities.values()) {
-                        if (authorityInfo.backoffTime != NOT_IN_BACKOFF_MODE
-                                || authorityInfo.backoffDelay != NOT_IN_BACKOFF_MODE) {
-                            if (DEBUG) {
-                                Log.v(TAG, "clearAllBackoffs:"
-                                        + " authority:" + authorityInfo.authority
-                                        + " account:" + accountInfo.accountAndUser.account.name
-                                        + " user:" + accountInfo.accountAndUser.userId
-                                        + " backoffTime was: " + authorityInfo.backoffTime
-                                        + " backoffDelay was: " + authorityInfo.backoffDelay);
-                            }
-                            authorityInfo.backoffTime = NOT_IN_BACKOFF_MODE;
-                            authorityInfo.backoffDelay = NOT_IN_BACKOFF_MODE;
-                            syncQueue.onBackoffChanged(accountInfo.accountAndUser.account,
-                                    accountInfo.accountAndUser.userId, authorityInfo.authority, 0);
-                            changed = true;
+            for (AccountInfo accountInfo : mAccounts.values()) {
+                for (AuthorityInfo authorityInfo : accountInfo.authorities.values()) {
+                    if (authorityInfo.backoffTime != NOT_IN_BACKOFF_MODE
+                            || authorityInfo.backoffDelay != NOT_IN_BACKOFF_MODE) {
+                        if (DEBUG) {
+                            Log.v(TAG, "clearAllBackoffs:"
+                                    + " authority:" + authorityInfo.authority
+                                    + " account:" + accountInfo.accountAndUser.account.name
+                                    + " user:" + accountInfo.accountAndUser.userId
+                                    + " backoffTime was: " + authorityInfo.backoffTime
+                                    + " backoffDelay was: " + authorityInfo.backoffDelay);
                         }
+                        authorityInfo.backoffTime = NOT_IN_BACKOFF_MODE;
+                        authorityInfo.backoffDelay = NOT_IN_BACKOFF_MODE;
+                        syncQueue.onBackoffChanged(accountInfo.accountAndUser.account,
+                                accountInfo.accountAndUser.userId, authorityInfo.authority, 0);
+                        changed = true;
                     }
                 }
             }
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index d063db5..e4f5c7c 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -754,9 +754,9 @@
         mBatteryStats = BatteryStatsService.getService();
         mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
         mAppOps.startWatchingMode(AppOpsManager.OP_SYSTEM_ALERT_WINDOW, null,
-                new AppOpsManager.Callback() {
+                new AppOpsManager.OnOpChangedInternalListener() {
                     @Override
-                    public void opChanged(int op, String packageName) {
+                    public void onOpChanged(int op, String packageName) {
                         updateAppOpsState();
                     }
                 }
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 4c84f17..87afa88 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -361,7 +361,8 @@
             if (allowedKeyManagement.get(KeyMgmt.WPA_EAP) == false) {
                 return false;
             }
-            if (allowedKeyManagement.get(KeyMgmt.IEEE8021X) == false) {
+            if ((allowedKeyManagement.get(KeyMgmt.IEEE8021X) == false)
+                    && (allowedKeyManagement.get(KeyMgmt.WPA_PSK) == false)) {
                 return false;
             }
         }