Allow pattern to start from outside pattern view

This effectively makes the pattern view slippery, which enables the
user to start their pattern outside the view and cross the view.

Fixes bug 7118762

Change-Id: I085c5ec8f7ccd2fc37a10606a8925078dc44be13
diff --git a/core/res/res/layout-land/keyguard_host_view.xml b/core/res/res/layout-land/keyguard_host_view.xml
index 0028a54..8e7c232 100644
--- a/core/res/res/layout-land/keyguard_host_view.xml
+++ b/core/res/res/layout-land/keyguard_host_view.xml
@@ -38,7 +38,7 @@
     </com.android.internal.policy.impl.keyguard.KeyguardWidgetPager>
 
 
-    <ViewFlipper
+    <com.android.internal.policy.impl.keyguard.KeyguardSecurityViewFlipper
         android:id="@+id/view_flipper"
         android:layout_width="0dip"
         android:layout_height="match_parent"
@@ -48,6 +48,6 @@
         <!-- SelectorView is always used, so add it here. The rest are loaded dynamically -->
         <include layout="@layout/keyguard_selector_view"/>
 
-    </ViewFlipper>
+    </com.android.internal.policy.impl.keyguard.KeyguardSecurityViewFlipper>
 
 </com.android.internal.policy.impl.keyguard.KeyguardHostView>
diff --git a/core/res/res/layout-port/keyguard_host_view.xml b/core/res/res/layout-port/keyguard_host_view.xml
index 5e467d1..55c4c0d 100644
--- a/core/res/res/layout-port/keyguard_host_view.xml
+++ b/core/res/res/layout-port/keyguard_host_view.xml
@@ -28,7 +28,7 @@
     android:gravity="center_horizontal"
     android:clipChildren="false">
 
-    <ViewFlipper
+    <com.android.internal.policy.impl.keyguard.KeyguardSecurityViewFlipper
         android:id="@+id/view_flipper"
         android:layout_height="match_parent"
         android:gravity="center">
@@ -36,7 +36,7 @@
         <!-- SelectorView is always used, so add it here. The rest are loaded dynamically -->
         <include layout="@layout/keyguard_selector_view"/>
 
-    </ViewFlipper>
+    </com.android.internal.policy.impl.keyguard.KeyguardSecurityViewFlipper>
 
 </com.android.internal.policy.impl.keyguard.KeyguardHostView>
 
diff --git a/core/res/res/layout-sw600dp-land/keyguard_host_view.xml b/core/res/res/layout-sw600dp-land/keyguard_host_view.xml
index 5b6bb2f..652bdde 100644
--- a/core/res/res/layout-sw600dp-land/keyguard_host_view.xml
+++ b/core/res/res/layout-sw600dp-land/keyguard_host_view.xml
@@ -44,7 +44,7 @@
         android:layout_weight="1"
         android:gravity="center">
 
-        <ViewFlipper
+        <com.android.internal.policy.impl.keyguard.KeyguardSecurityViewFlipper
             android:id="@+id/view_flipper"
             android:layout_width="@dimen/kg_security_view_width"
             android:layout_height="match_parent"
@@ -55,7 +55,7 @@
             <!-- SelectorView is always used, so add it here. The rest are loaded dynamically -->
             <include layout="@layout/keyguard_selector_view"/>
 
-        </ViewFlipper>
+        </com.android.internal.policy.impl.keyguard.KeyguardSecurityViewFlipper>
 
     </FrameLayout>
 
diff --git a/core/res/res/layout-sw600dp-port/keyguard_host_view.xml b/core/res/res/layout-sw600dp-port/keyguard_host_view.xml
index 397b881..0c1dd0c 100644
--- a/core/res/res/layout-sw600dp-port/keyguard_host_view.xml
+++ b/core/res/res/layout-sw600dp-port/keyguard_host_view.xml
@@ -40,7 +40,7 @@
 
     </com.android.internal.policy.impl.keyguard.KeyguardWidgetPager>
 
-    <ViewFlipper
+    <com.android.internal.policy.impl.keyguard.KeyguardSecurityViewFlipper
         android:id="@+id/view_flipper"
         android:layout_width="@dimen/kg_security_view_width"
         android:layout_height="0dip"
@@ -50,7 +50,7 @@
         <!-- SelectorView is always used, so add it here. The rest are loaded dynamically -->
         <include layout="@layout/keyguard_selector_view"/>
 
-    </ViewFlipper>
+    </com.android.internal.policy.impl.keyguard.KeyguardSecurityViewFlipper>
 
 </com.android.internal.policy.impl.keyguard.KeyguardHostView>
 
diff --git a/core/res/res/layout/keyguard_pattern_view.xml b/core/res/res/layout/keyguard_pattern_view.xml
index 954a92c..356bce3 100644
--- a/core/res/res/layout/keyguard_pattern_view.xml
+++ b/core/res/res/layout/keyguard_pattern_view.xml
@@ -23,42 +23,36 @@
 <com.android.internal.policy.impl.keyguard.KeyguardPatternView
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/keyguard_pattern_view"
+    android:orientation="vertical"
     android:layout_width="match_parent"
-    android:layout_height="match_parent">
+    android:layout_height="match_parent"
+    android:gravity="center_horizontal">
 
-    <GridLayout
-        android:orientation="vertical"
+    <include layout="@layout/keyguard_navigation"/>
+
+    <Space android:layout_gravity="fill" />
+
+    <Button android:id="@+id/forgot_password_button"
+        android:layout_gravity="right"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:textSize="@*android:dimen/keyguard_lockscreen_status_line_font_size"
+        android:drawableLeft="@*android:drawable/lockscreen_forgot_password_button"
+        android:drawablePadding="0dip"
+        android:visibility="gone"/>
+
+    <!-- We need MATCH_PARENT here only to force the size of the parent to be passed to
+    the pattern view for it to compute its size. This is an unusual case, caused by
+    LockPatternView's requirement to maintain a square aspect ratio based on the width
+    of the screen. -->
+    <com.android.internal.widget.LockPatternView
+        android:id="@+id/lockPatternView"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
-        android:gravity="center_horizontal">
-
-        <include layout="@layout/keyguard_navigation"/>
-
-        <Space android:layout_gravity="fill" />
-
-        <Button android:id="@+id/forgot_password_button"
-            android:layout_gravity="right"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:textSize="@*android:dimen/keyguard_lockscreen_status_line_font_size"
-            android:drawableLeft="@*android:drawable/lockscreen_forgot_password_button"
-            android:drawablePadding="0dip"
-            android:visibility="gone"/>
-
-        <!-- We need MATCH_PARENT here only to force the size of the parent to be passed to
-        the pattern view for it to compute its size. This is an unusual case, caused by
-        LockPatternView's requirement to maintain a square aspect ratio based on the width
-        of the screen. -->
-        <com.android.internal.widget.LockPatternView
-            android:id="@+id/lockPatternView"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:layout_marginEnd="8dip"
-            android:layout_marginBottom="4dip"
-            android:layout_marginStart="8dip"
-            android:layout_gravity="center_horizontal"
-         />
-
-    </GridLayout>
+        android:layout_marginEnd="8dip"
+        android:layout_marginBottom="4dip"
+        android:layout_marginStart="8dip"
+        android:layout_gravity="center_horizontal"
+     />
 
 </com.android.internal.policy.impl.keyguard.KeyguardPatternView>
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java
index e170ec1..863f4f8 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java
@@ -32,17 +32,17 @@
 import android.content.pm.UserInfo;
 import android.content.res.Resources;
 import android.graphics.Canvas;
+import android.graphics.Rect;
 import android.os.UserManager;
-import android.telephony.TelephonyManager;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.util.Slog;
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
+import android.view.MotionEvent;
 import android.view.View;
 import android.view.WindowManager;
 import android.view.animation.AnimationUtils;
-import android.widget.Button;
 import android.widget.RemoteViews.OnClickHandler;
 import android.widget.ViewFlipper;
 
@@ -51,7 +51,6 @@
 import com.android.internal.widget.LockPatternUtils;
 
 import java.io.File;
-import java.util.ArrayList;
 import java.util.List;
 
 public class KeyguardHostView extends KeyguardViewBase {
@@ -77,6 +76,8 @@
 
     private KeyguardSecurityModel mSecurityModel;
 
+    private Rect mTempRect = new Rect();
+
     public KeyguardHostView(Context context) {
         this(context, null);
     }
@@ -94,6 +95,17 @@
     }
 
     @Override
+    public boolean dispatchTouchEvent(MotionEvent ev) {
+        boolean result = super.dispatchTouchEvent(ev);
+        mTempRect.set(0, 0, 0, 0);
+        offsetRectIntoDescendantCoords(mSecurityViewContainer, mTempRect);
+        ev.offsetLocation(mTempRect.left, mTempRect.top);
+        result = mSecurityViewContainer.dispatchTouchEvent(ev) || result;
+        ev.offsetLocation(-mTempRect.left, -mTempRect.top);
+        return result;
+    }
+
+    @Override
     protected void dispatchDraw(Canvas canvas) {
         super.dispatchDraw(canvas);
         mViewMediatorCallback.keyguardDoneDrawing();
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardPatternView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardPatternView.java
index 3a32b5b..6de40e4 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardPatternView.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardPatternView.java
@@ -22,6 +22,7 @@
 import android.accounts.AuthenticatorException;
 import android.accounts.OperationCanceledException;
 import android.content.Context;
+import android.graphics.Rect;
 import android.os.Bundle;
 import android.os.CountDownTimer;
 import android.os.SystemClock;
@@ -31,7 +32,7 @@
 import android.view.MotionEvent;
 import android.view.View;
 import android.widget.Button;
-import android.widget.LinearLayout;
+import android.widget.GridLayout;
 
 import com.android.internal.widget.LockPatternUtils;
 import com.android.internal.widget.LockPatternView;
@@ -40,7 +41,7 @@
 import java.io.IOException;
 import java.util.List;
 
-public class KeyguardPatternView extends LinearLayout implements KeyguardSecurityView {
+public class KeyguardPatternView extends GridLayout implements KeyguardSecurityView {
 
     private static final String TAG = "SecurityPatternView";
     private static final boolean DEBUG = false;
@@ -83,6 +84,7 @@
             mLockPatternView.clearPattern();
         }
     };
+    private Rect mTempRect = new Rect();
 
     enum FooterMode {
         Normal,
@@ -156,13 +158,18 @@
 
     @Override
     public boolean dispatchTouchEvent(MotionEvent ev) {
-        final boolean result = super.dispatchTouchEvent(ev);
+        boolean result = super.dispatchTouchEvent(ev);
         // as long as the user is entering a pattern (i.e sending a touch event that was handled
         // by this screen), keep poking the wake lock so that the screen will stay on.
         final long elapsed = SystemClock.elapsedRealtime() - mLastPokeTime;
         if (result && (elapsed > (UNLOCK_PATTERN_WAKE_INTERVAL_MS - 100))) {
             mLastPokeTime = SystemClock.elapsedRealtime();
         }
+        mTempRect.set(0, 0, 0, 0);
+        offsetRectIntoDescendantCoords(mLockPatternView, mTempRect);
+        ev.offsetLocation(mTempRect.left, mTempRect.top);
+        result = mLockPatternView.dispatchTouchEvent(ev) || result;
+        ev.offsetLocation(-mTempRect.left, -mTempRect.top);
         return result;
     }
 
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSecurityViewFlipper.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSecurityViewFlipper.java
new file mode 100644
index 0000000..911cfe0
--- /dev/null
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSecurityViewFlipper.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2012 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 com.android.internal.policy.impl.keyguard;
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.View;
+import android.widget.ViewFlipper;
+
+/**
+ * Subclass of the current view flipper that allows us to overload dispatchTouchEvent() so
+ * we can emulate {@link WindowManager.LayoutParams#FLAG_SLIPPERY} within a view hierarchy.
+ *
+ */
+public class KeyguardSecurityViewFlipper extends ViewFlipper {
+    private Rect mTempRect = new Rect();
+
+    public KeyguardSecurityViewFlipper(Context context) {
+        this(context, null);
+    }
+
+    public KeyguardSecurityViewFlipper(Context context, AttributeSet attr) {
+        super(context, attr);
+    }
+
+    @Override
+    public boolean dispatchTouchEvent(MotionEvent ev) {
+        boolean result = super.dispatchTouchEvent(ev);
+        mTempRect.set(0, 0, 0, 0);
+        for (int i = 0; i < getChildCount(); i++) {
+            View child = getChildAt(i);
+            if (child.getVisibility() == View.VISIBLE) {
+                offsetRectIntoDescendantCoords(child, mTempRect);
+                ev.offsetLocation(mTempRect.left, mTempRect.top);
+                result = child.dispatchTouchEvent(ev) || result;
+                ev.offsetLocation(-mTempRect.left, -mTempRect.top);
+            }
+        }
+        return result;
+    }
+
+}
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardUpdateMonitor.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardUpdateMonitor.java
index 66c7c10..c48e2d7 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardUpdateMonitor.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardUpdateMonitor.java
@@ -73,9 +73,9 @@
     private static final int MSG_PHONE_STATE_CHANGED = 306;
     private static final int MSG_CLOCK_VISIBILITY_CHANGED = 307;
     private static final int MSG_DEVICE_PROVISIONED = 308;
-    protected static final int MSG_DPM_STATE_CHANGED = 309;
-    protected static final int MSG_USER_SWITCHED = 310;
-    protected static final int MSG_USER_REMOVED = 311;
+    private static final int MSG_DPM_STATE_CHANGED = 309;
+    private static final int MSG_USER_SWITCHED = 310;
+    private static final int MSG_USER_REMOVED = 311;
 
     private static KeyguardUpdateMonitor sInstance;