Merge "allow re-targetting of surfaces" into kraken
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 35e7ee6..296d70a4 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -78,6 +78,15 @@
             = "android.app.action.ADD_DEVICE_ADMIN";
     
     /**
+     * Activity action: send when any policy admin changes a policy.
+     * This is generally used to find out when a new policy is in effect.
+     * 
+     * @hide
+     */
+    public static final String ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED
+            = "android.app.action.DEVICE_POLICY_MANAGER_STATE_CHANGED";
+
+    /**
      * The ComponentName of the administrator component.
      *
      * @see #ACTION_ADD_DEVICE_ADMIN
diff --git a/services/java/com/android/server/DevicePolicyManagerService.java b/services/java/com/android/server/DevicePolicyManagerService.java
index 7fb7db0..19d146d 100644
--- a/services/java/com/android/server/DevicePolicyManagerService.java
+++ b/services/java/com/android/server/DevicePolicyManagerService.java
@@ -367,6 +367,7 @@
             out.endDocument();
             stream.close();
             journal.commit();
+            sendChangedNotification();
         } catch (IOException e) {
             try {
                 if (stream != null) {
@@ -379,6 +380,12 @@
         }
     }
 
+    private void sendChangedNotification() {
+        Intent intent = new Intent(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
+        intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+        mContext.sendBroadcast(intent);
+    }
+
     private void loadSettingsLocked() {
         JournaledFile journal = makeJournaledFile();
         FileInputStream stream = null;
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index dcee6e7f..ac5e3f1 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -55,7 +55,10 @@
 import android.app.ActivityManagerNative;
 import android.app.IActivityManager;
 import android.app.admin.DevicePolicyManager;
+import android.content.BroadcastReceiver;
 import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
 import android.content.pm.ActivityInfo;
 import android.content.pm.PackageManager;
 import android.content.res.CompatibilityInfo;
@@ -235,11 +238,20 @@
      */
     private boolean mKeyguardDisabled = false;
 
+    private static final int ALLOW_DISABLE_YES = 1;
+    private static final int ALLOW_DISABLE_NO = 0;
+    private static final int ALLOW_DISABLE_UNKNOWN = -1; // check with DevicePolicyManager
+    private int mAllowDisableKeyguard = ALLOW_DISABLE_UNKNOWN; // sync'd by mKeyguardTokenWatcher
+
     final TokenWatcher mKeyguardTokenWatcher = new TokenWatcher(
             new Handler(), "WindowManagerService.mKeyguardTokenWatcher") {
         public void acquired() {
-            mPolicy.enableKeyguard(false);
-            mKeyguardDisabled = true;
+            if (shouldAllowDisableKeyguard()) {
+                mPolicy.enableKeyguard(false);
+                mKeyguardDisabled = true;
+            } else {
+                Log.v(TAG, "Not disabling keyguard since device policy is enforced");
+            }
         }
         public void released() {
             mPolicy.enableKeyguard(true);
@@ -250,6 +262,18 @@
         }
     };
 
+    final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            mPolicy.enableKeyguard(true);
+            synchronized(mKeyguardTokenWatcher) {
+                // lazily evaluate this next time we're asked to disable keyguard
+                mAllowDisableKeyguard = ALLOW_DISABLE_UNKNOWN;
+                mKeyguardDisabled = false;
+            }
+        }
+    };
+
     final Context mContext;
 
     final boolean mHaveInputMethods;
@@ -610,6 +634,11 @@
         mTransitionAnimationScale = Settings.System.getFloat(context.getContentResolver(),
                 Settings.System.TRANSITION_ANIMATION_SCALE, mTransitionAnimationScale);
 
+        // Track changes to DevicePolicyManager state so we can enable/disable keyguard.
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
+        mContext.registerReceiver(mBroadcastReceiver, filter);
+
         int max_events_per_sec = 35;
         try {
             max_events_per_sec = Integer.parseInt(SystemProperties
@@ -4173,17 +4202,20 @@
     // Misc IWindowSession methods
     // -------------------------------------------------------------
 
-    private boolean allowDisableKeyguard()
+    private boolean shouldAllowDisableKeyguard()
     {
-        // We fail safe if this gets called before the service has started.
-        boolean allow = false;
-        DevicePolicyManager dpm = (DevicePolicyManager) mContext.getSystemService(
-                Context.DEVICE_POLICY_SERVICE);
-        if (dpm != null) {
-            allow = dpm.getPasswordQuality(null)
-                    == DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
+        // We fail safe and prevent disabling keyguard in the unlikely event this gets 
+        // called before DevicePolicyManagerService has started.
+        if (mAllowDisableKeyguard == ALLOW_DISABLE_UNKNOWN) {
+            DevicePolicyManager dpm = (DevicePolicyManager) mContext.getSystemService(
+                    Context.DEVICE_POLICY_SERVICE);
+            if (dpm != null) {
+                mAllowDisableKeyguard = dpm.getPasswordQuality(null)
+                        == DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED ?
+                                ALLOW_DISABLE_YES : ALLOW_DISABLE_NO;
+            }
         }
-        return allow;
+        return mAllowDisableKeyguard == ALLOW_DISABLE_YES;
     }
 
     public void disableKeyguard(IBinder token, String tag) {
@@ -4192,12 +4224,8 @@
             throw new SecurityException("Requires DISABLE_KEYGUARD permission");
         }
 
-        if (allowDisableKeyguard()) {
-            synchronized (mKeyguardTokenWatcher) {
-                mKeyguardTokenWatcher.acquire(token, tag);
-            }
-        } else {
-            Log.w(TAG, tag + ": disableKeyguard() ignored while DevicePolicyAmin is enabled.");
+        synchronized (mKeyguardTokenWatcher) {
+            mKeyguardTokenWatcher.acquire(token, tag);
         }
     }
 
@@ -4207,29 +4235,25 @@
             throw new SecurityException("Requires DISABLE_KEYGUARD permission");
         }
 
-        if (allowDisableKeyguard()) {
-            synchronized (mKeyguardTokenWatcher) {
-                mKeyguardTokenWatcher.release(token);
+        synchronized (mKeyguardTokenWatcher) {
+            mKeyguardTokenWatcher.release(token);
 
-                if (!mKeyguardTokenWatcher.isAcquired()) {
-                    // If we are the last one to reenable the keyguard wait until
-                    // we have actaully finished reenabling until returning.
-                    // It is possible that reenableKeyguard() can be called before
-                    // the previous disableKeyguard() is handled, in which case
-                    // neither mKeyguardTokenWatcher.acquired() or released() would
-                    // be called.  In that case mKeyguardDisabled will be false here
-                    // and we have nothing to wait for.
-                    while (mKeyguardDisabled) {
-                        try {
-                            mKeyguardTokenWatcher.wait();
-                        } catch (InterruptedException e) {
-                            Thread.currentThread().interrupt();
-                        }
+            if (!mKeyguardTokenWatcher.isAcquired()) {
+                // If we are the last one to reenable the keyguard wait until
+                // we have actually finished reenabling until returning.
+                // It is possible that reenableKeyguard() can be called before
+                // the previous disableKeyguard() is handled, in which case
+                // neither mKeyguardTokenWatcher.acquired() or released() would
+                // be called. In that case mKeyguardDisabled will be false here
+                // and we have nothing to wait for.
+                while (mKeyguardDisabled) {
+                    try {
+                        mKeyguardTokenWatcher.wait();
+                    } catch (InterruptedException e) {
+                        Thread.currentThread().interrupt();
                     }
                 }
             }
-        } else {
-            Log.w(TAG, "reenableKeyguard() ignored while DevicePolicyAmin is enabled.");
         }
     }