Merge "Add keyguard background scrim and protection around keyguard APIs"
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 2ab981b3..83d6061 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2209,6 +2209,13 @@
         android:label="@string/permlab_access_keyguard_secure_storage"
         android:description="@string/permdesc_access_keyguard_secure_storage" />
 
+    <!-- Allows an application to control keyguard.  Only allowed for system processes.
+        @hide -->
+    <permission android:name="android.permission.CONTROL_KEYGUARD"
+        android:protectionLevel="signature"
+        android:label="@string/permlab_control_keyguard"
+        android:description="@string/permdesc_control_keyguard" />
+
     <!-- Must be required by an {@link
          android.service.notification.NotificationListenerService},
          to ensure that only the system can bind to it. -->
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index b832bbe..09be719 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -3474,6 +3474,11 @@
     <!-- Description of an application permission that lets an application access keyguard secure storage. -->
     <string name="permdesc_access_keyguard_secure_storage">Allows an application to access keguard secure storage.</string>
 
+    <!-- Title of an application permission that lets it control keyguard. -->
+    <string name="permlab_control_keyguard">Control displaying and hiding keyguard</string>
+    <!-- Description of an application permission that lets it control keyguard. -->
+    <string name="permdesc_control_keyguard">Allows an application to control keguard.</string>
+
     <!-- Shown in the tutorial for tap twice for zoom control. -->
     <string name="tutorial_double_tap_to_zoom_message_short">Touch twice for zoom control</string>
 
diff --git a/packages/Keyguard/Android.mk b/packages/Keyguard/Android.mk
index 2f8edad..bc86a44 100644
--- a/packages/Keyguard/Android.mk
+++ b/packages/Keyguard/Android.mk
@@ -16,7 +16,7 @@
 LOCAL_PATH:= $(call my-dir)
 include $(CLEAR_VARS)
 
-LOCAL_SRC_FILES := $(call all-subdir-java-files) $(call all-subdir-Iaidl-files)
+LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-subdir-Iaidl-files)
 
 LOCAL_JAVA_LIBRARIES := services
 
@@ -28,4 +28,4 @@
 
 include $(BUILD_PACKAGE)
 
-include $(call all-makefiles-under,$(LOCAL_PATH))
+#include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/packages/Keyguard/AndroidManifest.xml b/packages/Keyguard/AndroidManifest.xml
index 38e764a..7a40a9e7 100644
--- a/packages/Keyguard/AndroidManifest.xml
+++ b/packages/Keyguard/AndroidManifest.xml
@@ -38,7 +38,7 @@
     <uses-permission android:name="android.permission.BIND_DEVICE_ADMIN" />
     <uses-permission android:name="android.permission.CHANGE_COMPONENT_ENABLED_STATE" />
 
-    <application android:label="@string/app_name" android:icon="@drawable/app_icon"
+    <application android:label="@string/app_name"
         android:process="com.android.systemui.keyguard"
         android:persistent="true" >
 
diff --git a/packages/Keyguard/res/drawable-nodpi/app_icon.png b/packages/Keyguard/res/drawable-nodpi/app_icon.png
deleted file mode 100644
index ea31bd8..0000000
--- a/packages/Keyguard/res/drawable-nodpi/app_icon.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardService.java b/packages/Keyguard/src/com/android/keyguard/KeyguardService.java
index 9fa4790..f89ad65 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardService.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardService.java
@@ -21,7 +21,11 @@
 
 import android.app.Service;
 import android.content.Intent;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+
+import android.os.Binder;
 import android.os.Bundle;
+import android.os.Debug;
 import android.os.IBinder;
 import android.util.Log;
 
@@ -32,6 +36,7 @@
 
 public class KeyguardService extends Service {
     static final String TAG = "KeyguardService";
+    static final String PERMISSION = android.Manifest.permission.CONTROL_KEYGUARD;
     private KeyguardViewMediator mKeyguardViewMediator;
 
     @Override
@@ -53,6 +58,14 @@
         // TODO
     }
 
+    void checkPermission() {
+        if (getBaseContext().checkCallingOrSelfPermission(PERMISSION) != PERMISSION_GRANTED) {
+            Log.w(TAG, "Caller needs permission '" + PERMISSION + "' to call " + Debug.getCaller());
+            throw new SecurityException("Access denied to process: " + Binder.getCallingPid()
+                    + ", must have permission " + PERMISSION);
+        }
+    }
+
     private final IKeyguardService.Stub mBinder = new IKeyguardService.Stub() {
         public boolean isShowing() {
             return mKeyguardViewMediator.isShowing();
@@ -70,48 +83,61 @@
             mKeyguardViewMediator.verifyUnlock(callback);
         }
         public void keyguardDone(boolean authenticated, boolean wakeup) {
+            checkPermission();
             mKeyguardViewMediator.keyguardDone(authenticated, wakeup);
         }
         public void setHidden(boolean isHidden) {
+            checkPermission();
             mKeyguardViewMediator.setHidden(isHidden);
         }
         public void dismiss() {
             mKeyguardViewMediator.dismiss();
         }
         public void onWakeKeyWhenKeyguardShowing(int keyCode) {
+            checkPermission();
             mKeyguardViewMediator.onWakeKeyWhenKeyguardShowing(keyCode);
         }
         public void onWakeMotionWhenKeyguardShowing() {
+            checkPermission();
             mKeyguardViewMediator.onWakeMotionWhenKeyguardShowing();
         }
         public void onDreamingStarted() {
+            checkPermission();
             mKeyguardViewMediator.onDreamingStarted();
         }
         public void onDreamingStopped() {
+            checkPermission();
             mKeyguardViewMediator.onDreamingStopped();
         }
         public void onScreenTurnedOff(int reason) {
+            checkPermission();
             mKeyguardViewMediator.onScreenTurnedOff(reason);
         }
         public void onScreenTurnedOn(IKeyguardShowCallback callback) {
+            checkPermission();
             mKeyguardViewMediator.onScreenTurnedOn(callback);
         }
         public void setKeyguardEnabled(boolean enabled) {
+            checkPermission();
             mKeyguardViewMediator.setKeyguardEnabled(enabled);
         }
         public boolean isDismissable() {
             return mKeyguardViewMediator.isDismissable();
         }
         public void onSystemReady() {
+            checkPermission();
             mKeyguardViewMediator.onSystemReady();
         }
         public void doKeyguardTimeout(Bundle options) {
+            checkPermission();
             mKeyguardViewMediator.doKeyguardTimeout(options);
         }
         public void setCurrentUser(int userId) {
+            checkPermission();
             mKeyguardViewMediator.setCurrentUser(userId);
         }
         public void showAssistant() {
+            checkPermission();
             mKeyguardViewMediator.showAssistant();
         }
     };
diff --git a/packages/Keyguard/test/Android.mk b/packages/Keyguard/test/Android.mk
new file mode 100644
index 0000000..d011df4
--- /dev/null
+++ b/packages/Keyguard/test/Android.mk
@@ -0,0 +1,28 @@
+# Copyright (C) 2013 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := KeyguardTest
+
+# Remove this to verify permission checks are working correctly
+LOCAL_CERTIFICATE := platform
+
+# LOCAL_PROGUARD_FLAG_FILES := proguard.flags
+
+include $(BUILD_PACKAGE)
diff --git a/packages/Keyguard/test/AndroidManifest.xml b/packages/Keyguard/test/AndroidManifest.xml
new file mode 100644
index 0000000..b801e4b
--- /dev/null
+++ b/packages/Keyguard/test/AndroidManifest.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.keyguard.test">
+    <uses-sdk android:minSdkVersion="10" android:targetSdkVersion="17"/>
+    <uses-permission android:name="android.permission.CONTROL_KEYGUARD" />
+    <application android:label="@string/app_name" android:icon="@drawable/app_icon">
+        <activity android:name=".KeyguardTestActivity"
+                android:label="@string/app_name"
+                android:theme="@android:style/Theme.Holo">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+</manifest>
diff --git a/packages/Keyguard/test/res/drawable-hdpi/app_icon.png b/packages/Keyguard/test/res/drawable-hdpi/app_icon.png
new file mode 100644
index 0000000..732133c
--- /dev/null
+++ b/packages/Keyguard/test/res/drawable-hdpi/app_icon.png
Binary files differ
diff --git a/packages/Keyguard/test/res/drawable-mdpi/app_icon.png b/packages/Keyguard/test/res/drawable-mdpi/app_icon.png
new file mode 100644
index 0000000..30eb974
--- /dev/null
+++ b/packages/Keyguard/test/res/drawable-mdpi/app_icon.png
Binary files differ
diff --git a/packages/Keyguard/test/res/drawable-xhdpi/app_icon.png b/packages/Keyguard/test/res/drawable-xhdpi/app_icon.png
new file mode 100644
index 0000000..c44a330
--- /dev/null
+++ b/packages/Keyguard/test/res/drawable-xhdpi/app_icon.png
Binary files differ
diff --git a/packages/Keyguard/res/layout/keyguard_test_activity.xml b/packages/Keyguard/test/res/layout/keyguard_test_activity.xml
similarity index 96%
rename from packages/Keyguard/res/layout/keyguard_test_activity.xml
rename to packages/Keyguard/test/res/layout/keyguard_test_activity.xml
index a3b75b0..dab1088 100644
--- a/packages/Keyguard/res/layout/keyguard_test_activity.xml
+++ b/packages/Keyguard/test/res/layout/keyguard_test_activity.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
 **
-** Copyright 2012, The Android Open Source Project
+** Copyright 2013, The Android Open Source Project
 **
 ** Licensed under the Apache License, Version 2.0 (the "License")
 ** you may not use this file except in compliance with the License.
diff --git a/packages/Keyguard/res/menu/optionmenu.xml b/packages/Keyguard/test/res/menu/optionmenu.xml
similarity index 100%
rename from packages/Keyguard/res/menu/optionmenu.xml
rename to packages/Keyguard/test/res/menu/optionmenu.xml
diff --git a/packages/Keyguard/res/values/activitystrings.xml b/packages/Keyguard/test/res/values/strings.xml
similarity index 96%
rename from packages/Keyguard/res/values/activitystrings.xml
rename to packages/Keyguard/test/res/values/strings.xml
index 5af9dea..129204b 100644
--- a/packages/Keyguard/res/values/activitystrings.xml
+++ b/packages/Keyguard/test/res/values/strings.xml
@@ -2,7 +2,7 @@
 <!--
 /* //device/apps/common/assets/res/any/strings.xml
 **
-** Copyright 2006, The Android Open Source Project
+** Copyright 2013, The Android Open Source Project
 **
 ** Licensed under the Apache License, Version 2.0 (the "License");
 ** you may not use this file except in compliance with the License.
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardTestActivity.java b/packages/Keyguard/test/src/com/android/keyguard/test/KeyguardTestActivity.java
similarity index 88%
rename from packages/Keyguard/src/com/android/keyguard/KeyguardTestActivity.java
rename to packages/Keyguard/test/src/com/android/keyguard/test/KeyguardTestActivity.java
index 0ff00e3..e89c10e 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardTestActivity.java
+++ b/packages/Keyguard/test/src/com/android/keyguard/test/KeyguardTestActivity.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.keyguard;
+package com.android.keyguard.test;
 
 import com.android.internal.policy.IKeyguardShowCallback;
 import com.android.internal.policy.IKeyguardExitCallback;
@@ -28,6 +28,7 @@
 import android.content.Intent;
 import android.content.ServiceConnection;
 import android.os.Bundle;
+import android.os.Handler;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.SystemClock;
@@ -56,6 +57,7 @@
     private static final int MODE_SIM_PIN = 4;
     private static final int MODE_SIM_PUK = 5;
     private static final String SECURITY_MODE = "security_mode";
+    Handler mHandler = new Handler();
 
     IKeyguardService mService = null;
 
@@ -76,13 +78,17 @@
     class KeyguardExitCallback extends IKeyguardExitCallback.Stub {
 
         @Override
-        public void onKeyguardExitResult(boolean success) throws RemoteException {
-            new AlertDialog.Builder(KeyguardTestActivity.this)
-                .setMessage("Result: " + success)
-                .setPositiveButton("OK", null)
-                .show();
+        public void onKeyguardExitResult(final boolean success) throws RemoteException {
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    new AlertDialog.Builder(KeyguardTestActivity.this)
+                    .setMessage("Result: " + success)
+                    .setPositiveButton("OK", null)
+                    .show();
+                }
+            });
         }
-
     };
 
     private class RemoteServiceConnection implements ServiceConnection {
@@ -158,12 +164,13 @@
         setMode(savedInstanceState.getInt(SECURITY_MODE));
     }
 
-    @Override
-    public boolean onCreateOptionsMenu(Menu menu) {
-        MenuInflater inflater = getMenuInflater();
-        inflater.inflate(R.menu.optionmenu, menu);
-        return true;
-    }
+// TODO: Find a secure way to inject mock into keyguard...
+//    @Override
+//    public boolean onCreateOptionsMenu(Menu menu) {
+//        MenuInflater inflater = getMenuInflater();
+//        inflater.inflate(R.menu.optionmenu, menu);
+//        return true;
+//    }
 
     private void setMode(int mode) {
         mTestSimPin = false;
@@ -255,12 +262,22 @@
                 mService.doKeyguardTimeout(null);
                 break;
             case R.id.verify_unlock:
-                mService.verifyUnlock(mKeyguardExitCallback);
+                mService.doKeyguardTimeout(null);
+                // Wait for keyguard to lock and then try this...
+                mHandler.postDelayed(new Runnable() {
+                    @Override
+                    public void run() {
+                        try {
+                            mService.verifyUnlock(mKeyguardExitCallback);
+                        } catch (RemoteException e) {
+                            Log.e(TAG, "Failed verifyUnlock()", e);
+                        }
+                    }
+                }, 5000);
                 break;
             }
         } catch (RemoteException e) {
-            Log.e(TAG, "Remote service died");
-            e.printStackTrace();
+            Log.e(TAG, "onClick(): Failed due to remote exeption", e);
         }
     }
 
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 63584ac..41efaa5 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -1722,7 +1722,6 @@
                     return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON;
                 }
                 mKeyguard = win;
-                hideKeyguardScrim();
                 break;
             case TYPE_KEYGUARD_SCRIM:
                 if (mKeyguardScrim != null) {
@@ -1742,7 +1741,7 @@
         } else if (mKeyguard == win) {
             Log.v(TAG, "Removing keyguard window (Did it crash?)");
             mKeyguard = null;
-            showKeyguardScrimLw();
+            mKeyguardDelegate.showScrim();
         } else if (mKeyguardScrim == win) {
             Log.v(TAG, "Removing keyguard scrim");
             mKeyguardScrim = null;
@@ -1751,14 +1750,6 @@
         }
     }
 
-    private void showKeyguardScrimLw() {
-        Log.v(TAG, "*** SHOWING KEYGUARD SCRIM ***");
-    }
-    
-    private void hideKeyguardScrim() {
-        Log.v(TAG, "*** HIDING KEYGUARD SCRIM ***");
-    }
-
     static final boolean PRINT_ANIM = false;
     
     /** {@inheritDoc} */
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceDelegate.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceDelegate.java
index bf18b99..2bb94be 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceDelegate.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceDelegate.java
@@ -4,12 +4,17 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.ServiceConnection;
+import android.content.pm.ActivityInfo;
+import android.graphics.PixelFormat;
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.util.Log;
 import android.util.Slog;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
 import android.view.WindowManagerPolicy.OnKeyguardExitResult;
 
 import com.android.internal.policy.IKeyguardExitCallback;
@@ -29,6 +34,7 @@
     private static final String TAG = "KeyguardServiceDelegate";
     private static final boolean DEBUG = true;
     protected KeyguardServiceWrapper mKeyguardService;
+    private View mScrim; // shown if keyguard crashes
     private KeyguardState mKeyguardState = new KeyguardState();
 
     /* package */ static final class KeyguardState {
@@ -64,6 +70,7 @@
             if (mShowListener != null) {
                 mShowListener.onShown(windowToken);
             }
+            hideScrim();
         }
     };
 
@@ -87,6 +94,7 @@
     public KeyguardServiceDelegate(Context context, LockPatternUtils lockPatternUtils) {
         Intent intent = new Intent();
         intent.setClassName(KEYGUARD_PACKAGE, KEYGUARD_CLASS);
+        mScrim = createScrim(context);
         if (!context.bindServiceAsUser(intent, mKeyguardConnection,
                 Context.BIND_AUTO_CREATE, UserHandle.OWNER)) {
             if (DEBUG) Log.v(TAG, "*** Keyguard: can't bind to " + KEYGUARD_CLASS);
@@ -102,7 +110,10 @@
             mKeyguardService = new KeyguardServiceWrapper(
                     IKeyguardService.Stub.asInterface(service));
             if (mKeyguardState.systemIsReady) {
+                // If the system is ready, it means keyguard crashed and restarted.
                 mKeyguardService.onSystemReady();
+                // This is used to hide the scrim once keyguard displays.
+                mKeyguardService.onScreenTurnedOn(new KeyguardShowDelegate(null));
             }
         }
 
@@ -257,4 +268,51 @@
         mKeyguardState.currentUser = newUserId;
     }
 
+    private static final View createScrim(Context context) {
+        View view = new View(context);
+
+        int flags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
+                | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR
+                | WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN
+                | WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER
+                ;
+
+        final int stretch = ViewGroup.LayoutParams.MATCH_PARENT;
+        final int type = WindowManager.LayoutParams.TYPE_KEYGUARD_SCRIM;
+        WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
+                stretch, stretch, type, flags, PixelFormat.TRANSLUCENT);
+        lp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
+        lp.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
+        lp.setTitle("KeyguardScrim");
+        WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
+        wm.addView(view, lp);
+        view.setVisibility(View.GONE);
+        // Disable pretty much everything in statusbar until keyguard comes back and we know
+        // the state of the world.
+        view.setSystemUiVisibility(View.STATUS_BAR_DISABLE_HOME
+                | View.STATUS_BAR_DISABLE_BACK
+                | View.STATUS_BAR_DISABLE_RECENT
+                | View.STATUS_BAR_DISABLE_EXPAND
+                | View.STATUS_BAR_DISABLE_SEARCH);
+        return view;
+    }
+
+    public void showScrim() {
+        mScrim.post(new Runnable() {
+            @Override
+            public void run() {
+                mScrim.setVisibility(View.VISIBLE);
+            }
+        });
+    }
+
+    public void hideScrim() {
+        mScrim.post(new Runnable() {
+            @Override
+            public void run() {
+                mScrim.setVisibility(View.GONE);
+            }
+        });
+    }
+
 }