OSDN Git Service

am e03c0244: Merge "Clear data deletes too much" into jb-mr1-dev
authorKenny Root <kroot@google.com>
Mon, 22 Oct 2012 23:13:45 +0000 (16:13 -0700)
committerAndroid Git Automerger <android-git-automerger@android.com>
Mon, 22 Oct 2012 23:13:45 +0000 (16:13 -0700)
* commit 'e03c0244717093e0fbc9b05073d3ae3dbd8fcea5':
  Clear data deletes too much

31 files changed:
core/res/res/anim/keyguard_security_fade_out.xml
core/res/res/drawable-xhdpi/add_widget.png [new file with mode: 0644]
core/res/res/drawable-xhdpi/camera_widget.png [new file with mode: 0644]
core/res/res/drawable-xhdpi/security_frame.9.png [new file with mode: 0644]
core/res/res/drawable-xhdpi/security_handle.png [new file with mode: 0644]
core/res/res/layout-land/keyguard_host_view.xml
core/res/res/layout-port/keyguard_host_view.xml
core/res/res/layout-sw600dp-port/keyguard_host_view.xml [deleted file]
core/res/res/layout/keyguard_add_widget.xml [new file with mode: 0644]
core/res/res/layout/keyguard_camera_widget.xml [new file with mode: 0644]
core/res/res/layout/keyguard_status_view.xml
core/res/res/layout/keyguard_widget_pager.xml [new file with mode: 0644]
core/res/res/layout/keyguard_widget_region.xml [deleted file]
core/res/res/values/attrs.xml
core/res/res/values/dimens.xml
core/res/res/values/symbols.xml
policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java
policy/src/com/android/internal/policy/impl/keyguard/KeyguardMultiUserAvatar.java
policy/src/com/android/internal/policy/impl/keyguard/KeyguardSecurityContainer.java [new file with mode: 0644]
policy/src/com/android/internal/policy/impl/keyguard/KeyguardSimPukView.java
policy/src/com/android/internal/policy/impl/keyguard/KeyguardStatusViewManager.java
policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewBase.java
policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewManager.java
policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewMediator.java
policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewStateManager.java [new file with mode: 0644]
policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetFrame.java
policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetPager.java
policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetRegion.java [deleted file]
policy/src/com/android/internal/policy/impl/keyguard/PagedView.java
policy/src/com/android/internal/policy/impl/keyguard/SecureCamera.java [new file with mode: 0644]
policy/src/com/android/internal/policy/impl/keyguard/SlidingChallengeLayout.java [new file with mode: 0644]

index 08c8b2b..512fc1d 100644 (file)
@@ -13,7 +13,7 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<alpha xmlns:android="http://schemas.android.com/apk/res/android" 
+<alpha xmlns:android="http://schemas.android.com/apk/res/android"
     android:interpolator="@interpolator/accelerate_quad"
     android:fromAlpha="1.0"
     android:toAlpha="0.0"
diff --git a/core/res/res/drawable-xhdpi/add_widget.png b/core/res/res/drawable-xhdpi/add_widget.png
new file mode 100644 (file)
index 0000000..9cf9b60
Binary files /dev/null and b/core/res/res/drawable-xhdpi/add_widget.png differ
diff --git a/core/res/res/drawable-xhdpi/camera_widget.png b/core/res/res/drawable-xhdpi/camera_widget.png
new file mode 100644 (file)
index 0000000..0274388
Binary files /dev/null and b/core/res/res/drawable-xhdpi/camera_widget.png differ
diff --git a/core/res/res/drawable-xhdpi/security_frame.9.png b/core/res/res/drawable-xhdpi/security_frame.9.png
new file mode 100644 (file)
index 0000000..9eeadc4
Binary files /dev/null and b/core/res/res/drawable-xhdpi/security_frame.9.png differ
diff --git a/core/res/res/drawable-xhdpi/security_handle.png b/core/res/res/drawable-xhdpi/security_handle.png
new file mode 100644 (file)
index 0000000..bd4640f
Binary files /dev/null and b/core/res/res/drawable-xhdpi/security_handle.png differ
index 521853f..e605f95 100644 (file)
     and the security view. -->
 <com.android.internal.policy.impl.keyguard.KeyguardHostView
     xmlns:android="http://schemas.android.com/apk/res/android"
+
     android:id="@+id/keyguard_host_view"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:gravity="center_vertical"
+    android:gravity="center_horizontal"
     android:orientation="horizontal">
 
-    <include layout="@layout/keyguard_widget_region"
-        android:layout_width="0dp"
-        android:layout_height="match_parent"
-        android:layout_weight="@integer/kg_widget_region_weight" />
-
-    <com.android.internal.policy.impl.keyguard.KeyguardSecurityViewFlipper
-        android:id="@+id/view_flipper"
-        android:layout_width="0dp"
+    <com.android.internal.policy.impl.keyguard.SlidingChallengeLayout
+        android:id="@+id/sliding_layout"
+        android:layout_width="match_parent"
         android:layout_height="match_parent"
-        android:layout_weight="@integer/kg_security_flipper_weight"
-        android:clipChildren="false"
-        android:clipToPadding="false"
-        android:paddingLeft="@dimen/keyguard_security_view_margin"
-        android:paddingTop="@dimen/keyguard_security_view_margin"
-        android:paddingRight="@dimen/keyguard_security_view_margin"
-        android:paddingBottom="@dimen/keyguard_security_view_margin"
-        android:gravity="center">
+        android:dragHandle="@drawable/security_handle">
 
-    </com.android.internal.policy.impl.keyguard.KeyguardSecurityViewFlipper>
+        <FrameLayout
+            android:layout_width="match_parent"
+            android:layout_height="match_parent">
+            <include layout="@layout/keyguard_widget_pager"
+                     android:layout_width="match_parent"
+                     android:layout_height="match_parent"
+                     android:layout_gravity="center"/>
+        </FrameLayout>
 
+        <com.android.internal.policy.impl.keyguard.KeyguardSecurityContainer
+            android:id="@+id/keyguard_security_container"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_isChallenge="true"
+            android:gravity="bottom|center_horizontal"
+            android:background="@drawable/security_frame">
+            <com.android.internal.policy.impl.keyguard.KeyguardSecurityViewFlipper
+                android:id="@+id/view_flipper"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:clipChildren="false"
+                android:clipToPadding="false"
+                android:paddingLeft="@dimen/keyguard_security_view_margin"
+                android:paddingTop="@dimen/keyguard_security_view_margin"
+                android:paddingRight="@dimen/keyguard_security_view_margin"
+                android:paddingBottom="@dimen/keyguard_security_view_margin"
+                android:gravity="center">
+            </com.android.internal.policy.impl.keyguard.KeyguardSecurityViewFlipper>
+        </com.android.internal.policy.impl.keyguard.KeyguardSecurityContainer>
+    </com.android.internal.policy.impl.keyguard.SlidingChallengeLayout>
 </com.android.internal.policy.impl.keyguard.KeyguardHostView>
+
index 981fe6d..6e97102 100644 (file)
     and the security view. -->
 <com.android.internal.policy.impl.keyguard.KeyguardHostView
     xmlns:android="http://schemas.android.com/apk/res/android"
+
     android:id="@+id/keyguard_host_view"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:gravity="center_horizontal"
     android:orientation="vertical">
 
-    <include layout="@layout/keyguard_widget_region"
+    <com.android.internal.policy.impl.keyguard.SlidingChallengeLayout
+        android:id="@+id/sliding_layout"
         android:layout_width="match_parent"
-        android:layout_height="153dp" />
+        android:layout_height="match_parent"
+        android:dragHandle="@drawable/security_handle">
 
-    <com.android.internal.policy.impl.keyguard.KeyguardSecurityViewFlipper
-        android:id="@+id/view_flipper"
-        android:layout_width="match_parent"
-        android:layout_height="0dip"
-        android:clipChildren="false"
-        android:clipToPadding="false"
-        android:layout_weight="1"
-        android:paddingLeft="@dimen/keyguard_security_view_margin"
-        android:paddingTop="@dimen/keyguard_security_view_margin"
-        android:paddingRight="@dimen/keyguard_security_view_margin"
-        android:paddingBottom="@dimen/keyguard_security_view_margin"
-        android:gravity="center">
-    </com.android.internal.policy.impl.keyguard.KeyguardSecurityViewFlipper>
+        <FrameLayout
+            android:layout_width="match_parent"
+            android:layout_height="match_parent">
+            <include layout="@layout/keyguard_widget_pager"
+                     android:layout_width="match_parent"
+                     android:layout_height="match_parent"
+                     android:layout_gravity="center"/>
+        </FrameLayout>
+
+        <com.android.internal.policy.impl.keyguard.KeyguardSecurityContainer
+            android:id="@+id/keyguard_security_container"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_isChallenge="true"
+            android:gravity="bottom|center_horizontal"
+            android:background="@drawable/security_frame">
+            <com.android.internal.policy.impl.keyguard.KeyguardSecurityViewFlipper
+                android:id="@+id/view_flipper"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:clipChildren="false"
+                android:clipToPadding="false"
+                android:paddingLeft="@dimen/keyguard_security_view_margin"
+                android:paddingTop="@dimen/keyguard_security_view_margin"
+                android:paddingRight="@dimen/keyguard_security_view_margin"
+                android:paddingBottom="@dimen/keyguard_security_view_margin"
+                android:gravity="center">
+            </com.android.internal.policy.impl.keyguard.KeyguardSecurityViewFlipper>
+        </com.android.internal.policy.impl.keyguard.KeyguardSecurityContainer>
+    </com.android.internal.policy.impl.keyguard.SlidingChallengeLayout>
 </com.android.internal.policy.impl.keyguard.KeyguardHostView>
 
diff --git a/core/res/res/layout-sw600dp-port/keyguard_host_view.xml b/core/res/res/layout-sw600dp-port/keyguard_host_view.xml
deleted file mode 100644 (file)
index 23c1e9c..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-**
-** Copyright 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.
-*/
--->
-
-<!-- This is the host view that generally contains two sub views: the widget view
-    and the security view. -->
-<com.android.internal.policy.impl.keyguard.KeyguardHostView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/keyguard_host_view"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:gravity="center_horizontal"
-    android:orientation="vertical">
-
-    <include layout="@layout/keyguard_widget_region"
-        android:layout_width="match_parent"
-        android:layout_height="0dip"
-        android:layout_weight="@integer/kg_widget_region_weight" />
-
-    <com.android.internal.policy.impl.keyguard.KeyguardSecurityViewFlipper
-        android:id="@+id/view_flipper"
-        android:layout_width="match_parent"
-        android:layout_height="0dip"
-        android:layout_weight="@integer/kg_security_flipper_weight"
-        android:clipChildren="false"
-        android:clipToPadding="false"
-        android:paddingLeft="@dimen/keyguard_security_view_margin"
-        android:paddingTop="@dimen/keyguard_security_view_margin"
-        android:paddingRight="@dimen/keyguard_security_view_margin"
-        android:paddingBottom="@dimen/keyguard_security_view_margin"
-        android:layout_gravity="center">
-
-
-
-    </com.android.internal.policy.impl.keyguard.KeyguardSecurityViewFlipper>
-
-</com.android.internal.policy.impl.keyguard.KeyguardHostView>
-
diff --git a/core/res/res/layout/keyguard_add_widget.xml b/core/res/res/layout/keyguard_add_widget.xml
new file mode 100644 (file)
index 0000000..598e0a3
--- /dev/null
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 2009, 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.
+*/
+-->
+
+<!-- This is a view that shows general status information in Keyguard. -->
+<com.android.internal.policy.impl.keyguard.KeyguardWidgetFrame
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/keyguard_add_widget"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:gravity="center_horizontal">
+    <ImageView
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:src="@drawable/add_widget" />
+</com.android.internal.policy.impl.keyguard.KeyguardWidgetFrame>
\ No newline at end of file
diff --git a/core/res/res/layout/keyguard_camera_widget.xml b/core/res/res/layout/keyguard_camera_widget.xml
new file mode 100644 (file)
index 0000000..f1f5817
--- /dev/null
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 2009, 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.
+*/
+-->
+
+<!-- This is a view that shows general status information in Keyguard. -->
+<com.android.internal.policy.impl.keyguard.KeyguardWidgetFrame
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/keyguard_camera_widget"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:gravity="center_horizontal">
+
+    <ImageView
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:src="@drawable/camera_widget" />
+    
+</com.android.internal.policy.impl.keyguard.KeyguardWidgetFrame>
\ No newline at end of file
index 1de0f6c..9532a88 100644 (file)
@@ -35,7 +35,7 @@
 
         <LinearLayout android:layout_width="match_parent"
                       android:layout_height="wrap_content"
-                      android:layout_gravity="center_vertical"
+                      android:layout_gravity="center_horizontal|top"
                       android:orientation="vertical">
             <com.android.internal.policy.impl.keyguard.ClockView
                 android:id="@+id/clock_view"
diff --git a/core/res/res/layout/keyguard_widget_pager.xml b/core/res/res/layout/keyguard_widget_pager.xml
new file mode 100644 (file)
index 0000000..b884a18
--- /dev/null
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 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.
+*/
+-->
+
+<!-- This is the selector widget that allows the user to select an action. -->
+<com.android.internal.policy.impl.keyguard.KeyguardWidgetPager
+
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/app_widget_container"
+    android:paddingLeft="25dp"
+    android:paddingRight="25dp"
+    android:paddingTop="25dp"
+    android:paddingBottom="25dp"
+    android:clipChildren="false"
+    android:clipToPadding="false"
+    android:pageSpacing="10dp"
+    android:edgeSwipeRegionSize="8dp">
+</com.android.internal.policy.impl.keyguard.KeyguardWidgetPager>
\ No newline at end of file
diff --git a/core/res/res/layout/keyguard_widget_region.xml b/core/res/res/layout/keyguard_widget_region.xml
deleted file mode 100644 (file)
index ed10c2b..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-**
-** Copyright 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.
-*/
--->
-
-<!-- This is the selector widget that allows the user to select an action. -->
-<com.android.internal.policy.impl.keyguard.KeyguardWidgetRegion
-    xmlns:prvandroid="http://schemas.android.com/apk/prv/res/android"
-    xmlns:android="http://schemas.android.com/apk/res/android"
-        android:id="@+id/kg_widget_region"
-        android:visibility="gone"
-        android:gravity="center"
-        android:orientation="vertical">
-    <com.android.internal.policy.impl.keyguard.KeyguardWidgetPager
-        android:id="@+id/app_widget_container"
-        android:layout_width="match_parent"
-        android:layout_height="0dp"
-        android:layout_weight="1"
-        android:clipChildren="false"
-        android:clipToPadding="false">
-    </com.android.internal.policy.impl.keyguard.KeyguardWidgetPager>
-    <LinearLayout
-        android:layout_width="match_parent"
-        android:layout_height="10dp"
-        android:orientation="horizontal"
-        android:paddingLeft="@dimen/kg_widget_pager_horizontal_padding"
-        android:paddingRight="@dimen/kg_widget_pager_horizontal_padding"
-        android:layout_marginTop="@dimen/kg_runway_lights_top_margin"
-        android:visibility="gone">
-        <com.android.internal.policy.impl.keyguard.KeyguardGlowStripView
-            android:id="@+id/left_strip"
-            android:paddingTop="@dimen/kg_runway_lights_vertical_padding"
-            android:paddingBottom="@dimen/kg_runway_lights_vertical_padding"
-            android:layout_width="0dp"
-            android:layout_height="match_parent"
-            android:layout_weight="1"
-            prvandroid:numDots="5"
-            prvandroid:dotSize="@dimen/kg_runway_lights_height"
-            prvandroid:leftToRight="false"
-            prvandroid:glowDot="@*android:drawable/ic_lockscreen_glowdot" />
-        <Space
-            android:layout_width="0dp"
-            android:layout_height="match_parent"
-            android:layout_weight="1.6"/>
-        <com.android.internal.policy.impl.keyguard.KeyguardGlowStripView
-            android:id="@+id/right_strip"
-            android:paddingTop="@dimen/kg_runway_lights_vertical_padding"
-            android:paddingBottom="@dimen/kg_runway_lights_vertical_padding"
-            android:layout_width="0dp"
-            android:layout_height="match_parent"
-            android:layout_weight="1"
-            prvandroid:numDots="5"
-            prvandroid:dotSize="@dimen/kg_runway_lights_height"
-            prvandroid:leftToRight="true"
-            prvandroid:glowDot="@*android:drawable/ic_lockscreen_glowdot" />
-    </LinearLayout>
-</com.android.internal.policy.impl.keyguard.KeyguardWidgetRegion>
index 3550df9..d5589e8 100755 (executable)
     <!-- PagedView specific attributes. These attributes are used to customize
          a PagedView view in XML files. -->
     <declare-styleable name="PagedView">
-        <!-- A spacing override for the icons within a page -->
-        <attr name="pageLayoutWidthGap" format="dimension" />
-        <attr name="pageLayoutHeightGap" format="dimension" />
-        <!-- The padding of the pages that are dynamically created per page -->
-        <attr name="pageLayoutPaddingTop" format="dimension" />
-        <attr name="pageLayoutPaddingBottom" format="dimension" />
-        <attr name="pageLayoutPaddingLeft" format="dimension" />
-        <attr name="pageLayoutPaddingRight" format="dimension" />
         <!-- The space between adjacent pages of the PagedView. -->
         <attr name="pageSpacing" format="dimension" />
         <!-- The padding for the scroll indicator area -->
         <attr name="scrollIndicatorPaddingLeft" format="dimension" />
         <attr name="scrollIndicatorPaddingRight" format="dimension" />
+        <attr name="edgeSwipeRegionSize" format="dimension" />
     </declare-styleable>
 
     <declare-styleable name="KeyguardGlowStripView">
         <attr name="leftToRight" format="boolean" />
     </declare-styleable>
 
+    <declare-styleable name="SlidingChallengeLayout">
+        <attr name="dragHandle" format="reference" />
+    </declare-styleable>
+
+    <declare-styleable name="SlidingChallengeLayout_Layout">
+        <attr name="layout_isChallenge" format="boolean" />
+    </declare-styleable>
+
     <!-- Attributes that can be used with <code>&lt;FragmentBreadCrumbs&gt;</code>
     tags. -->
     <declare-styleable name="FragmentBreadCrumbs">
index 948a3d3..4be76ef 100644 (file)
     <dimen name="notification_subtext_size">12dp</dimen>
 
     <!-- Keyguard dimensions -->
+    <!-- TEMP -->
+    <dimen name="kg_security_panel_height">600dp</dimen>
+
     <!-- Width of security view in keyguard. -->
     <dimen name="kg_glow_pad_size">500dp</dimen>
 
index 8ef91df..7953a77 100644 (file)
   <java-symbol type="layout" name="notification_template_inbox" />
   <java-symbol type="layout" name="keyguard_multi_user_avatar" />
   <java-symbol type="layout" name="keyguard_multi_user_selector_widget" />
-  <java-symbol type="layout" name="keyguard_widget_region" />
   <java-symbol type="layout" name="sms_short_code_confirmation_dialog" />
+  <java-symbol type="layout" name="keyguard_add_widget" />
+  <java-symbol type="layout" name="keyguard_camera_widget" />
 
   <java-symbol type="anim" name="slide_in_child_bottom" />
   <java-symbol type="anim" name="slide_in_right" />
   <java-symbol type="bool" name="config_reverseDefaultRotation" />
   <java-symbol type="bool" name="config_showNavigationBar" />
   <java-symbol type="bool" name="kg_share_status_area" />
-  <java-symbol type="bool" name="kg_sim_puk_account_full_screen" />  
+  <java-symbol type="bool" name="kg_sim_puk_account_full_screen" />
   <java-symbol type="bool" name="target_honeycomb_needs_options_menu" />
   <java-symbol type="color" name="kg_multi_user_text_active" />
   <java-symbol type="color" name="kg_multi_user_text_inactive" />
   <java-symbol type="drawable" name="magnified_region_frame" />
   <java-symbol type="drawable" name="menu_background" />
   <java-symbol type="drawable" name="stat_sys_secure" />
+  <java-symbol type="drawable" name="security_frame" />
   <java-symbol type="id" name="action_mode_bar_stub" />
   <java-symbol type="id" name="alarm_status" />
   <java-symbol type="id" name="backspace" />
   <java-symbol type="id" name="keyguard_users_grid" />
   <java-symbol type="id" name="clock_text" />
   <java-symbol type="id" name="clock_view" />
-  <java-symbol type="id" name="kg_widget_region" />
-  <java-symbol type="id" name="left_strip" />
-  <java-symbol type="id" name="right_strip" />
   <java-symbol type="id" name="keyguard_multi_user_selector" />
   <java-symbol type="id" name="status_security_message" />
+  <java-symbol type="id" name="sliding_layout" />
+  <java-symbol type="id" name="keyguard_add_widget" />
+  <java-symbol type="id" name="sliding_layout" />
 
   <java-symbol type="integer" name="config_carDockRotation" />
   <java-symbol type="integer" name="config_defaultUiModeType" />
index b86e5b8..1991bb8 100644 (file)
@@ -71,7 +71,6 @@ public class KeyguardHostView extends KeyguardViewBase {
     private static final int TRANSPORT_VISIBLE = 2;
 
     private AppWidgetHost mAppWidgetHost;
-    private KeyguardWidgetRegion mAppWidgetRegion;
     private KeyguardWidgetPager mAppWidgetContainer;
     private ViewFlipper mSecurityViewContainer;
     private KeyguardSelectorView mKeyguardSelectorView;
@@ -87,6 +86,7 @@ public class KeyguardHostView extends KeyguardViewBase {
     private LockPatternUtils mLockPatternUtils;
 
     private KeyguardSecurityModel mSecurityModel;
+    private KeyguardViewStateManager mViewStateManager;
 
     private Rect mTempRect = new Rect();
     private int mTransportState = TRANSPORT_GONE;
@@ -151,17 +151,33 @@ public class KeyguardHostView extends KeyguardViewBase {
 
     @Override
     protected void onFinishInflate() {
-        mAppWidgetRegion = (KeyguardWidgetRegion) findViewById(R.id.kg_widget_region);
-        mAppWidgetRegion.setVisibility(VISIBLE);
-        mAppWidgetRegion.setCallbacks(mWidgetCallbacks);
-
+        // Grab instances of and make any necessary changes to the main layouts. Create
+        // view state manager and wire up necessary listeners / callbacks.
         mAppWidgetContainer = (KeyguardWidgetPager) findViewById(R.id.app_widget_container);
+        mAppWidgetContainer.setVisibility(VISIBLE);
+        mAppWidgetContainer.setCallbacks(mWidgetCallbacks);
+        mAppWidgetContainer.setMinScale(0.5f);
+
+        addDefaultWidgets();
+        maybePopulateWidgets();
+
+        mViewStateManager = new KeyguardViewStateManager();
+        SlidingChallengeLayout challengeLayout =
+                (SlidingChallengeLayout) findViewById(R.id.sliding_layout);
+        challengeLayout.setOnChallengeScrolledListener(mViewStateManager);
+        mAppWidgetContainer.setViewStateManager(mViewStateManager);
+
+        mViewStateManager.setPagedView(mAppWidgetContainer);
+        mViewStateManager.setSlidingChallenge(challengeLayout);
+
         mSecurityViewContainer = (ViewFlipper) findViewById(R.id.view_flipper);
         mKeyguardSelectorView = (KeyguardSelectorView) findViewById(R.id.keyguard_selector_view);
 
-        addDefaultWidgets();
+
         updateSecurityViews();
-        setSystemUiVisibility(getSystemUiVisibility() | View.STATUS_BAR_DISABLE_BACK);
+        if (!(mContext instanceof Activity)) {
+            setSystemUiVisibility(getSystemUiVisibility() | View.STATUS_BAR_DISABLE_BACK);
+        }
 
         if (KeyguardUpdateMonitor.getInstance(mContext).getIsFirstBoot()) {
             showPrimarySecurityScreen(false);
@@ -195,8 +211,6 @@ public class KeyguardHostView extends KeyguardViewBase {
     protected void onAttachedToWindow() {
         super.onAttachedToWindow();
         mAppWidgetHost.startListening();
-        // TODO: Re-enable when we have layouts that can support a better variety of widgets.
-        // maybePopulateWidgets();
         disableStatusViewInteraction();
         post(mSwitchPageRunnable);
     }
@@ -221,12 +235,12 @@ public class KeyguardHostView extends KeyguardViewBase {
         return mAppWidgetHost;
     }
 
-    void addWidget(AppWidgetHostView view) {
-        mAppWidgetContainer.addWidget(view);
+    void addWidget(AppWidgetHostView view, int pageIndex) {
+        mAppWidgetContainer.addWidget(view, pageIndex);
     }
 
-    private KeyguardWidgetRegion.Callbacks mWidgetCallbacks
-            = new KeyguardWidgetRegion.Callbacks() {
+    private KeyguardWidgetPager.Callbacks mWidgetCallbacks
+            = new KeyguardWidgetPager.Callbacks() {
         @Override
         public void userActivity() {
             if (mViewMediatorCallback != null) {
@@ -246,8 +260,8 @@ public class KeyguardHostView extends KeyguardViewBase {
     public long getUserActivityTimeout() {
         // Currently only considering user activity timeouts needed by widgets.
         // Could also take into account longer timeouts for certain security views.
-        if (mAppWidgetRegion != null) {
-            return mAppWidgetRegion.getUserActivityTimeout();
+        if (mAppWidgetContainer != null) {
+            return mAppWidgetContainer.getUserActivityTimeout();
         }
         return -1;
     }
@@ -607,7 +621,8 @@ public class KeyguardHostView extends KeyguardViewBase {
                 break;
             }
         }
-        boolean simPukFullScreen = getResources().getBoolean(R.bool.kg_sim_puk_account_full_screen);
+        boolean simPukFullScreen = getResources().getBoolean(
+                com.android.internal.R.bool.kg_sim_puk_account_full_screen);
         int layoutId = getLayoutIdFor(securityMode);
         if (view == null && layoutId != 0) {
             final LayoutInflater inflater = LayoutInflater.from(mContext);
@@ -631,7 +646,7 @@ public class KeyguardHostView extends KeyguardViewBase {
         if (securityMode == SecurityMode.SimPin || securityMode == SecurityMode.SimPuk ||
             securityMode == SecurityMode.Account) {
             if (simPukFullScreen) {
-                mAppWidgetRegion.setVisibility(View.GONE);
+                mAppWidgetContainer.setVisibility(View.GONE);
             }
         }
 
@@ -799,12 +814,12 @@ public class KeyguardHostView extends KeyguardViewBase {
         }
     }
 
-    private void addWidget(int appId) {
+    private void addWidget(int appId, int pageIndex) {
         AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(mContext);
         AppWidgetProviderInfo appWidgetInfo = appWidgetManager.getAppWidgetInfo(appId);
         if (appWidgetInfo != null) {
             AppWidgetHostView view = getAppWidgetHost().createView(mContext, appId, appWidgetInfo);
-            addWidget(view);
+            addWidget(view, pageIndex);
         } else {
             Log.w(TAG, "AppWidgetInfo was null; not adding widget id " + appId);
         }
@@ -812,9 +827,15 @@ public class KeyguardHostView extends KeyguardViewBase {
 
     private void addDefaultWidgets() {
         LayoutInflater inflater = LayoutInflater.from(mContext);
-        inflater.inflate(R.layout.keyguard_status_view, mAppWidgetContainer, true);
         inflater.inflate(R.layout.keyguard_transport_control_view, this, true);
 
+        View addWidget = inflater.inflate(R.layout.keyguard_add_widget, null, true);
+        mAppWidgetContainer.addWidget(addWidget);
+        View statusWidget = inflater.inflate(R.layout.keyguard_status_view, null, true);
+        mAppWidgetContainer.addWidget(statusWidget);
+        View cameraWidget = inflater.inflate(R.layout.keyguard_camera_widget, null, true);
+        mAppWidgetContainer.addWidget(cameraWidget);
+
         inflateAndAddUserSelectorWidgetIfNecessary();
         initializeTransportControl();
     }
@@ -874,27 +895,21 @@ public class KeyguardHostView extends KeyguardViewBase {
             }
         }
 
-        // Replace status widget if selected by user in Settings
-        int statusWidgetId = mLockPatternUtils.getStatusWidget();
-        if (statusWidgetId != -1) {
-            addWidget(statusWidgetId);
-            View newStatusWidget = mAppWidgetContainer.getChildAt(
-                    mAppWidgetContainer.getChildCount() - 1);
-
-            int oldStatusWidgetPosition = getWidgetPosition(R.id.keyguard_status_view);
-            mAppWidgetContainer.removeViewAt(oldStatusWidgetPosition);
-
-            // Re-add new status widget at position of old one
-            mAppWidgetContainer.removeView(newStatusWidget);
-            newStatusWidget.setId(R.id.keyguard_status_view);
-            mAppWidgetContainer.addView(newStatusWidget, oldStatusWidgetPosition);
+        View addWidget = mAppWidgetContainer.findViewById(R.id.keyguard_add_widget);
+        int addPageIndex = mAppWidgetContainer.indexOfChild(addWidget);
+        // This shouldn't happen, but just to be safe!
+        if (addPageIndex < 0) {
+            addPageIndex = 0;
         }
 
         // Add user-selected widget
         final int[] widgets = mLockPatternUtils.getUserDefinedWidgets();
-        for (int i = 0; i < widgets.length; i++) {
+        for (int i = widgets.length -1; i >= 0; i--) {
             if (widgets[i] != -1) {
-                addWidget(widgets[i]);
+                // We add the widgets from left to right, starting after the first page after
+                // the add page. We count down, since the order will be persisted from right
+                // to left, starting after camera.
+                addWidget(widgets[i], addPageIndex + 1);
             }
         }
     }
index 3c972bc..79b35d4 100644 (file)
@@ -73,8 +73,8 @@ class KeyguardMultiUserAvatar extends FrameLayout {
         super(context, attrs, defStyle);
 
         Resources res = mContext.getResources();
-        mActiveTextColor = res.getColor(R.color.kg_multi_user_text_active);
-        mInactiveTextColor = res.getColor(R.color.kg_multi_user_text_inactive);
+        mActiveTextColor = res.getColor(com.android.internal.R.color.kg_multi_user_text_active);
+        mInactiveTextColor = res.getColor(com.android.internal.R.color.kg_multi_user_text_inactive);
     }
 
     public void init(UserInfo user, KeyguardMultiUserSelectorView userSelector) {
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSecurityContainer.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSecurityContainer.java
new file mode 100644 (file)
index 0000000..f6a90c5
--- /dev/null
@@ -0,0 +1,20 @@
+package com.android.internal.policy.impl.keyguard;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.widget.FrameLayout;
+
+public class KeyguardSecurityContainer extends FrameLayout {
+
+    public KeyguardSecurityContainer(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public KeyguardSecurityContainer(Context context) {
+        this(null, null, 0);
+    }
+
+    public KeyguardSecurityContainer(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+    }
+}
index 562d893..320cdc8 100644 (file)
@@ -91,7 +91,8 @@ public class KeyguardSimPukView extends LinearLayout implements View.OnClickList
             } else if (state == CONFIRM_PIN) {
                 if (confirmPin()) {
                     state = DONE;
-                    msg = R.string.lockscreen_sim_unlock_progress_dialog_message;
+                    msg =
+                        com.android.internal.R.string.lockscreen_sim_unlock_progress_dialog_message;
                     updateSim();
                 } else {
                     msg = R.string.kg_invalid_confirm_pin_hint;
index 5b85064..b6985bd 100644 (file)
@@ -78,7 +78,7 @@ class KeyguardStatusViewManager implements SecurityMessageDisplay {
     // Whether to use the last line as a combined line to either display owner info / charging.
     // If false, each item will be given a dedicated space.
     private boolean mShareStatusRegion = false;
-    
+
     // last known battery level
     private int mBatteryLevel = 100;
 
@@ -121,9 +121,9 @@ class KeyguardStatusViewManager implements SecurityMessageDisplay {
         if (DEBUG) Log.v(TAG, "KeyguardStatusViewManager()");
         mContainer = view;
         Resources res = getContext().getResources();
-        mDateFormatString = 
+        mDateFormatString =
                 res.getText(com.android.internal.R.string.abbrev_wday_month_day_no_year);
-        mShareStatusRegion = res.getBoolean(R.bool.kg_share_status_area);
+        mShareStatusRegion = res.getBoolean(com.android.internal.R.bool.kg_share_status_area);
         mLockPatternUtils = new LockPatternUtils(view.getContext());
         mUpdateMonitor = KeyguardUpdateMonitor.getInstance(view.getContext());
 
index 3191f4a..9e3424d 100644 (file)
@@ -16,6 +16,7 @@
 
 package com.android.internal.policy.impl.keyguard;
 
+import android.app.Activity;
 import android.content.Context;
 import android.graphics.Canvas;
 import android.graphics.ColorFilter;
@@ -27,11 +28,11 @@ import android.media.IAudioService;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.telephony.TelephonyManager;
-import android.view.KeyEvent;
-import android.widget.LinearLayout;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.util.Slog;
+import android.view.KeyEvent;
+import android.widget.FrameLayout;
 
 /**
  * Base class for keyguard view.  {@link #reset} is where you should
@@ -42,7 +43,7 @@ import android.util.Slog;
  * Handles intercepting of media keys that still work when the keyguard is
  * showing.
  */
-public abstract class KeyguardViewBase extends LinearLayout {
+public abstract class KeyguardViewBase extends FrameLayout {
 
     private static final int BACKGROUND_COLOR = 0x70000000;
     private AudioManager mAudioManager;
@@ -249,7 +250,10 @@ public abstract class KeyguardViewBase extends LinearLayout {
     @Override
     public void dispatchSystemUiVisibilityChanged(int visibility) {
         super.dispatchSystemUiVisibilityChanged(visibility);
-        setSystemUiVisibility(STATUS_BAR_DISABLE_BACK);
+
+        if (!(mContext instanceof Activity)) {
+            setSystemUiVisibility(STATUS_BAR_DISABLE_BACK);
+        }
     }
 
     public void setViewMediatorCallback(
index b66c883..452fbca 100644 (file)
@@ -233,7 +233,6 @@ public class KeyguardViewManager {
 
         if (mScreenOn) {
             mKeyguardView.show();
-            mKeyguardView.requestFocus();
         }
     }
 
index ceb0325..2be16eb 100644 (file)
@@ -629,7 +629,9 @@ public class KeyguardViewMediator {
             mScreenOn = true;
             cancelDoKeyguardLaterLocked();
             if (DEBUG) Log.d(TAG, "onScreenTurnedOn, seq = " + mDelayedShowingSequence);
-            notifyScreenOnLocked(showListener);
+            if (showListener != null) {
+                notifyScreenOnLocked(showListener);
+            }
         }
         maybeSendUserPresentBroadcast();
     }
@@ -1321,7 +1323,9 @@ public class KeyguardViewMediator {
                         + " isSecure=" + isSecure() + " --> flags=0x" + Integer.toHexString(flags));
             }
 
-            mStatusBarManager.disable(flags);
+            if (!(mContext instanceof Activity)) {
+                mStatusBarManager.disable(flags);
+            }
         }
     }
 
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewStateManager.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewStateManager.java
new file mode 100644 (file)
index 0000000..4a78e0e
--- /dev/null
@@ -0,0 +1,112 @@
+package com.android.internal.policy.impl.keyguard;
+
+import android.view.View;
+
+public class KeyguardViewStateManager implements SlidingChallengeLayout.OnChallengeScrolledListener {
+
+    private KeyguardWidgetPager mPagedView;
+    private int mCurrentPageIndex;
+    private SlidingChallengeLayout mSlidingChallengeLayout;
+    private int[] mTmpPoint = new int[2];
+
+    int mChallengeTop = 0;
+
+    public KeyguardViewStateManager() {
+    }
+
+    public void setPagedView(KeyguardWidgetPager pagedView) {
+        mPagedView = pagedView;
+    }
+
+    public void setSlidingChallenge(SlidingChallengeLayout layout) {
+        mSlidingChallengeLayout = layout;
+    }
+
+    public void onPageBeginMoving() {
+        if (mSlidingChallengeLayout.isChallengeShowing()) {
+            mSlidingChallengeLayout.showChallenge(false);
+        }
+    }
+
+    public void onPageEndMoving() {
+    }
+
+    public void onPageSwitch(View newPage, int newPageIndex) {
+        // Reset the previous page size and ensure the current page is sized appropriately
+        if (mPagedView != null) {
+            KeyguardWidgetFrame oldPage = mPagedView.getWidgetPageAt(mCurrentPageIndex);
+            // Reset the old widget page to full size
+            if (oldPage != null) {
+                oldPage.resetSize();
+            }
+
+            KeyguardWidgetFrame newCurPage = mPagedView.getWidgetPageAt(newPageIndex);
+            if (mSlidingChallengeLayout.isChallengeShowing()) {
+                sizeWidgetFrameToChallengeTop(newCurPage);
+            }
+        }
+        mCurrentPageIndex = newPageIndex;
+    }
+
+    private void sizeWidgetFrameToChallengeTop(KeyguardWidgetFrame frame) {
+        if (frame == null) return;
+        mTmpPoint[0] = 0;
+        mTmpPoint[1] = mChallengeTop;
+        mapPoint(mSlidingChallengeLayout, frame, mTmpPoint);
+        frame.setChallengeTop(mTmpPoint[1]);
+    }
+
+    /**
+     * Simple method to map a point from one view's coordinates to another's. Note: this method
+     * doesn't account for transforms, so if the views will be transformed, this should not be used.
+     *
+     * @param fromView The view to which the point is relative
+     * @param toView The view into which the point should be mapped
+     * @param pt The point
+     */
+    public void mapPoint(View fromView, View toView, int pt[]) {
+        int[] loc = new int[2];
+        fromView.getLocationInWindow(loc);
+        int x = loc[0];
+        int y = loc[1];
+
+        toView.getLocationInWindow(loc);
+        int vX = loc[0];
+        int vY = loc[1];
+
+        pt[0] += x - vX;
+        pt[1] += y - vY;
+    }
+
+    @Override
+    public void onScrollStateChanged(int scrollState) {
+        if (scrollState == SlidingChallengeLayout.SCROLL_STATE_IDLE) {
+            if (mPagedView == null) return;
+
+            boolean challengeShowing = mSlidingChallengeLayout.isChallengeShowing();
+            int curPage = mPagedView.getCurrentPage();
+            KeyguardWidgetFrame frame = mPagedView.getWidgetPageAt(curPage);
+
+            if (frame != null) {
+                if (!challengeShowing) {
+                    frame.resetSize();
+                } else {
+                    sizeWidgetFrameToChallengeTop(frame);
+                }
+            }
+
+            if (challengeShowing) {
+                mPagedView.setOnlyAllowEdgeSwipes(true);
+            } else {
+                mPagedView.setOnlyAllowEdgeSwipes(false);
+            }
+
+        }
+    }
+
+    @Override
+    public void onScrollPositionChanged(float scrollPosition, int challengeTop) {
+        mChallengeTop = challengeTop;
+    }
+
+}
index 311eec6..34e372e 100644 (file)
@@ -19,17 +19,18 @@ package com.android.internal.policy.impl.keyguard;
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.Canvas;
-import android.graphics.Color;
 import android.graphics.LinearGradient;
 import android.graphics.Paint;
 import android.graphics.PorterDuff;
 import android.graphics.PorterDuffXfermode;
 import android.graphics.Rect;
 import android.graphics.Shader;
+import android.graphics.drawable.Drawable;
 import android.os.PowerManager;
 import android.os.SystemClock;
 import android.util.AttributeSet;
 import android.view.MotionEvent;
+import android.view.View;
 import android.widget.FrameLayout;
 
 import com.android.internal.R;
@@ -51,6 +52,11 @@ public class KeyguardWidgetFrame extends FrameLayout {
     private PowerManager mPowerManager;
     private boolean mDisableInteraction;
 
+    private float mBackgroundAlpha;
+    private float mBackgroundAlphaMultiplier;
+    private Drawable mBackgroundDrawable;
+    private Rect mBackgroundRect = new Rect();
+
     public KeyguardWidgetFrame(Context context) {
         this(context, null, 0);
     }
@@ -65,10 +71,18 @@ public class KeyguardWidgetFrame extends FrameLayout {
         mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
 
         Resources res = context.getResources();
+        /*
         int hPadding = res.getDimensionPixelSize(R.dimen.kg_widget_pager_horizontal_padding);
         int topPadding = res.getDimensionPixelSize(R.dimen.kg_widget_pager_top_padding);
         int bottomPadding = res.getDimensionPixelSize(R.dimen.kg_widget_pager_bottom_padding);
         setPadding(hPadding, topPadding, hPadding, bottomPadding);
+        */
+        // TODO: this padding should really correspond to the padding embedded in the background
+        // drawable (ie. outlines). 
+        int padding = (int) (res.getDisplayMetrics().density * 8);
+        setPadding(padding, padding, padding, padding);
+
+        mBackgroundDrawable = res.getDrawable(R.drawable.security_frame);
         mGradientColor = res.getColor(com.android.internal.R.color.kg_widget_pager_gradient);
         mGradientPaint.setXfermode(sAddBlendMode);
     }
@@ -88,17 +102,114 @@ public class KeyguardWidgetFrame extends FrameLayout {
 
     @Override
     protected void dispatchDraw(Canvas canvas) {
+        drawBg(canvas);
         super.dispatchDraw(canvas);
         drawGradientOverlay(canvas);
 
     }
 
+    /**
+     * Because this view has fading outlines, it is essential that we enable hardware
+     * layers on the content (child) so that updating the alpha of the outlines doesn't
+     * result in the content layer being recreated.
+     */
+    public void enableHardwareLayersForContent() {
+        View widget = getContent();
+        if (widget != null) {
+            widget.setLayerType(LAYER_TYPE_HARDWARE, null);
+        }
+    }
+
+    /**
+     * Because this view has fading outlines, it is essential that we enable hardware
+     * layers on the content (child) so that updating the alpha of the outlines doesn't
+     * result in the content layer being recreated.
+     */
+    public void disableHardwareLayersForContent() {
+        View widget = getContent();
+        if (widget != null) {
+            widget.setLayerType(LAYER_TYPE_NONE, null);
+        }
+    }
+
+    public View getContent() {
+        return getChildAt(0);
+    }
+
     private void drawGradientOverlay(Canvas c) {
         mGradientPaint.setShader(mForegroundGradient);
         mGradientPaint.setAlpha(mForegroundAlpha);
         c.drawRect(mForegroundRect, mGradientPaint);
     }
 
+    protected void drawBg(Canvas canvas) {
+        if (mBackgroundAlpha > 0.0f) {
+            Drawable bg = mBackgroundDrawable;
+
+            bg.setAlpha((int) (mBackgroundAlpha * mBackgroundAlphaMultiplier * 255));
+            bg.setBounds(mBackgroundRect);
+            bg.draw(canvas);
+        }
+    }
+
+    public float getBackgroundAlpha() {
+        return mBackgroundAlpha;
+    }
+
+    public void setBackgroundAlphaMultiplier(float multiplier) {
+        if (mBackgroundAlphaMultiplier != multiplier) {
+            mBackgroundAlphaMultiplier = multiplier;
+            invalidate();
+        }
+    }
+
+    public float getBackgroundAlphaMultiplier() {
+        return mBackgroundAlphaMultiplier;
+    }
+
+    public void setBackgroundAlpha(float alpha) {
+        if (mBackgroundAlpha != alpha) {
+            mBackgroundAlpha = alpha;
+            invalidate();
+        }
+    }
+
+    /**
+     * Depending on whether the security is up, the widget size needs to change
+     * 
+     * @param height The height of the widget, -1 for full height
+     */
+    public void setWidgetHeight(int height) {
+        boolean needLayout = false;
+        View widget = getContent();
+        if (widget != null) {
+            LayoutParams lp = (LayoutParams) widget.getLayoutParams();
+            if (lp.height != height) {
+                needLayout = true;
+                lp.height = height;
+            }
+        }
+        if (needLayout) {
+            requestLayout();
+        }
+    }
+
+    /**
+     * Set the top location of the challenge.
+     *
+     * @param top The top of the challenge, in _local_ coordinates, or -1 to indicate the challenge
+     *              is down.
+     */
+    public void setChallengeTop(int top) {
+        // The widget starts below the padding, and extends to the top of the challengs.
+        int widgetHeight = top - getPaddingTop();
+        setWidgetHeight(widgetHeight);
+    }
+
+    public void resetSize() {
+        setWidgetHeight(LayoutParams.MATCH_PARENT);
+    }
+
     @Override
     protected void onSizeChanged(int w, int h, int oldw, int oldh) {
         super.onSizeChanged(w, h, oldw, oldh);
@@ -110,6 +221,7 @@ public class KeyguardWidgetFrame extends FrameLayout {
                 mGradientColor, 0, Shader.TileMode.CLAMP);
         mRightToLeftGradient = new LinearGradient(x1, 0f, x0, 0f,
                 mGradientColor, 0, Shader.TileMode.CLAMP);
+        mBackgroundRect.set(0, 0, w, h);
     }
 
     void setOverScrollAmount(float r, boolean left) {
index 1e65665..23cf217 100644 (file)
@@ -15,6 +15,7 @@
  */
 package com.android.internal.policy.impl.keyguard;
 
+import android.animation.ObjectAnimator;
 import android.animation.TimeInterpolator;
 import android.appwidget.AppWidgetHostView;
 import android.content.Context;
@@ -22,14 +23,17 @@ import android.util.AttributeSet;
 import android.view.Gravity;
 import android.view.MotionEvent;
 import android.view.View;
+import android.view.View.OnLongClickListener;
+import android.view.ViewGroup;
 import android.view.animation.AccelerateInterpolator;
 import android.view.animation.DecelerateInterpolator;
-
 import android.widget.FrameLayout;
 
 import com.android.internal.R;
 
-public class KeyguardWidgetPager extends PagedView {
+public class KeyguardWidgetPager extends PagedView implements PagedView.PageSwitchListener,
+        OnLongClickListener {
+
     ZInterpolator mZInterpolator = new ZInterpolator(0.5f);
     private static float CAMERA_DISTANCE = 10000;
     private static float TRANSITION_SCALE_FACTOR = 0.74f;
@@ -38,6 +42,21 @@ public class KeyguardWidgetPager extends PagedView {
     private static final boolean PERFORM_OVERSCROLL_ROTATION = true;
     private AccelerateInterpolator mAlphaInterpolator = new AccelerateInterpolator(0.9f);
     private DecelerateInterpolator mLeftScreenAlphaInterpolator = new DecelerateInterpolator(4);
+    private KeyguardViewStateManager mViewStateManager;
+
+    // Related to the fading in / out background outlines
+    private static final int CHILDREN_OUTLINE_FADE_OUT_DELAY = 0;
+    private static final int CHILDREN_OUTLINE_FADE_OUT_DURATION = 375;
+    private static final int CHILDREN_OUTLINE_FADE_IN_DURATION = 100;
+    private ObjectAnimator mChildrenOutlineFadeInAnimation;
+    private ObjectAnimator mChildrenOutlineFadeOutAnimation;
+    private float mChildrenOutlineAlpha = 0;
+
+    private static final long CUSTOM_WIDGET_USER_ACTIVITY_TIMEOUT = 30000;
+    private static final boolean CAFETERIA_TRAY = false;
+
+    private int mPage = 0;
+    private Callbacks mCallbacks;
 
     public KeyguardWidgetPager(Context context, AttributeSet attrs) {
         this(context, attrs, 0);
@@ -52,38 +71,162 @@ public class KeyguardWidgetPager extends PagedView {
         if (getImportantForAccessibility() == View.IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
             setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
         }
+
+        setPageSwitchListener(this);
+    }
+
+    public void setViewStateManager(KeyguardViewStateManager viewStateManager) {
+        mViewStateManager = viewStateManager;
+    }
+
+    @Override
+    public void onPageSwitch(View newPage, int newPageIndex) {
+        boolean showingStatusWidget = false;
+        if (newPage instanceof ViewGroup) {
+            ViewGroup vg = (ViewGroup) newPage;
+            if (vg.getChildAt(0) instanceof KeyguardStatusView) {
+                showingStatusWidget = true;
+            }
+        }
+
+        // Disable the status bar clock if we're showing the default status widget
+        if (showingStatusWidget) {
+            setSystemUiVisibility(getSystemUiVisibility() | View.STATUS_BAR_DISABLE_CLOCK);
+        } else {
+            setSystemUiVisibility(getSystemUiVisibility() & ~View.STATUS_BAR_DISABLE_CLOCK);
+        }
+
+        // Extend the display timeout if the user switches pages
+        if (mPage != newPageIndex) {
+            mPage = newPageIndex;
+            if (mCallbacks != null) {
+                mCallbacks.onUserActivityTimeoutChanged();
+                mCallbacks.userActivity();
+            }
+        }
+        if (mViewStateManager != null) {
+            mViewStateManager.onPageSwitch(newPage, newPageIndex);
+        }
+    }
+
+    public void showPagingFeedback() {
+        // Nothing yet.
+    }
+
+    public long getUserActivityTimeout() {
+        View page = getPageAt(mPage);
+        if (page instanceof ViewGroup) {
+            ViewGroup vg = (ViewGroup) page;
+            View view = vg.getChildAt(0);
+            if (!(view instanceof KeyguardStatusView)
+                    && !(view instanceof KeyguardMultiUserSelectorView)) {
+                return CUSTOM_WIDGET_USER_ACTIVITY_TIMEOUT;
+            }
+        }
+        return -1;
+    }
+
+    public void setCallbacks(Callbacks callbacks) {
+        mCallbacks = callbacks;
+    }
+
+    public interface Callbacks {
+        public void userActivity();
+        public void onUserActivityTimeoutChanged();
+    }
+
+    public void addWidget(View widget) {
+        addWidget(widget, -1);
     }
 
     /*
-     * We wrap widgets in a special frame which handles drawing the overscroll foreground.
+     * We wrap widgets in a special frame which handles drawing the over scroll foreground.
      */
-    public void addWidget(AppWidgetHostView widget) {
-        KeyguardWidgetFrame frame = new KeyguardWidgetFrame(getContext());
-        FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT,
-                LayoutParams.MATCH_PARENT);
-        lp.gravity = Gravity.CENTER;
-        // The framework adds a default padding to AppWidgetHostView. We don't need this padding
-        // for the Keyguard, so we override it to be 0.
-        widget.setPadding(0,  0, 0, 0);
-        widget.setContentDescription(widget.getAppWidgetInfo().label);
-        frame.addView(widget, lp);
-        addView(frame);
+    public void addWidget(View widget, int pageIndex) {
+        KeyguardWidgetFrame frame;
+        // All views contained herein should be wrapped in a KeyguardWidgetFrame
+        if (!(widget instanceof KeyguardWidgetFrame)) {
+            frame = new KeyguardWidgetFrame(getContext());
+            FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT,
+                    LayoutParams.MATCH_PARENT);
+            lp.gravity = Gravity.TOP;
+            // The framework adds a default padding to AppWidgetHostView. We don't need this padding
+            // for the Keyguard, so we override it to be 0.
+            widget.setPadding(0,  0, 0, 0);
+            if (widget instanceof AppWidgetHostView) {
+                AppWidgetHostView awhv = (AppWidgetHostView) widget;
+                widget.setContentDescription(awhv.getAppWidgetInfo().label);
+            }
+            frame.addView(widget, lp);
+        } else {
+            frame = (KeyguardWidgetFrame) widget;
+        }
+
+        ViewGroup.LayoutParams pageLp = new ViewGroup.LayoutParams(
+                ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
+        frame.setOnLongClickListener(this);
+
+        if (pageIndex == -1) {
+            addView(frame, pageLp);
+        } else {
+            addView(frame, pageIndex, pageLp);
+        }
     }
 
-    protected void onUnhandledTap(MotionEvent ev) {
-        if (getParent() instanceof KeyguardWidgetRegion) {
-            ((KeyguardWidgetRegion) getParent()).showPagingFeedback();
+    // We enforce that all children are KeyguardWidgetFrames
+    @Override
+    public void addView(View child, int index) {
+        enforceKeyguardWidgetFrame(child);
+        super.addView(child, index);
+    }
+
+    @Override
+    public void addView(View child, int width, int height) {
+        enforceKeyguardWidgetFrame(child);
+        super.addView(child, width, height);
+    }
+
+    @Override
+    public void addView(View child, LayoutParams params) {
+        enforceKeyguardWidgetFrame(child);
+        super.addView(child, params);
+    }
+
+    @Override
+    public void addView(View child, int index, LayoutParams params) {
+        enforceKeyguardWidgetFrame(child);
+        super.addView(child, index, params);
+    }
+
+    private void enforceKeyguardWidgetFrame(View child) {
+        if (!(child instanceof KeyguardWidgetFrame)) {
+            throw new IllegalArgumentException(
+                    "KeyguardWidgetPager children must be KeyguardWidgetFrames");
         }
     }
 
+    public KeyguardWidgetFrame getWidgetPageAt(int index) {
+        // This is always a valid cast as we've guarded the ability to
+        return (KeyguardWidgetFrame) getChildAt(index);
+    }
+
+    protected void onUnhandledTap(MotionEvent ev) {
+        showPagingFeedback();
+    }
+
     @Override
     protected void onPageBeginMoving() {
         // Enable hardware layers while pages are moving
         // TODO: We should only do this for the two views that are actually moving
         int children = getChildCount();
         for (int i = 0; i < children; i++) {
-            getChildAt(i).setLayerType(LAYER_TYPE_HARDWARE, null);
+            getWidgetPageAt(i).enableHardwareLayersForContent();
+        }
+
+        if (mViewStateManager != null) {
+            mViewStateManager.onPageBeginMoving();
         }
+        showOutlines();
     }
 
     @Override
@@ -91,8 +234,13 @@ public class KeyguardWidgetPager extends PagedView {
         // Disable hardware layers while pages are moving
         int children = getChildCount();
         for (int i = 0; i < children; i++) {
-            getChildAt(i).setLayerType(LAYER_TYPE_NONE, null);
+            getWidgetPageAt(i).disableHardwareLayersForContent();
         }
+
+        if (mViewStateManager != null) {
+            mViewStateManager.onPageEndMoving();
+        }
+        hideOutlines();
     }
 
     /*
@@ -118,7 +266,7 @@ public class KeyguardWidgetPager extends PagedView {
     public String getCurrentPageDescription() {
         final int nextPageIndex = getNextPage();
         if (nextPageIndex >= 0 && nextPageIndex < getChildCount()) {
-            KeyguardWidgetFrame frame = (KeyguardWidgetFrame) getChildAt(nextPageIndex);
+            KeyguardWidgetFrame frame = getWidgetPageAt(nextPageIndex);
             CharSequence title = frame.getChildAt(0).getContentDescription();
             if (title == null) {
                 title = "";
@@ -135,30 +283,59 @@ public class KeyguardWidgetPager extends PagedView {
         acceleratedOverScroll(amount);
     }
 
+    float backgroundAlphaInterpolator(float r) {
+        return r;
+    }
+
+    private void updatePageAlphaValues(int screenCenter) {
+        boolean isInOverscroll = mOverScrollX < 0 || mOverScrollX > mMaxScrollX;
+        if (!isInOverscroll) {
+            for (int i = 0; i < getChildCount(); i++) {
+                KeyguardWidgetFrame child = getWidgetPageAt(i);
+                if (child != null) {
+                    float scrollProgress = getScrollProgress(screenCenter, child, i);
+                    float alpha = 1 - Math.abs(scrollProgress);
+                    // TODO: Set content alpha
+                    if (!isReordering()) {
+                        child.setBackgroundAlphaMultiplier(
+                                backgroundAlphaInterpolator(Math.abs(scrollProgress)));
+                    } else {
+                        child.setBackgroundAlphaMultiplier(1f);
+                    }
+                }
+            }
+        }
+    }
+
     // In apps customize, we have a scrolling effect which emulates pulling cards off of a stack.
     @Override
     protected void screenScrolled(int screenCenter) {
         super.screenScrolled(screenCenter);
-
+        updatePageAlphaValues(screenCenter);
         for (int i = 0; i < getChildCount(); i++) {
-            View v = getPageAt(i);
+            KeyguardWidgetFrame v = getWidgetPageAt(i);
+            if (v == mDragView) continue;
             if (v != null) {
                 float scrollProgress = getScrollProgress(screenCenter, v, i);
-
-                float interpolatedProgress =
+                float interpolatedProgress = 
                         mZInterpolator.getInterpolation(Math.abs(Math.min(scrollProgress, 0)));
-                float scale = (1 - interpolatedProgress) +
-                        interpolatedProgress * TRANSITION_SCALE_FACTOR;
-                float translationX = Math.min(0, scrollProgress) * v.getMeasuredWidth();
-
-                float alpha;
-
-                if (scrollProgress < 0) {
-                    alpha = scrollProgress < 0 ? mAlphaInterpolator.getInterpolation(
-                        1 - Math.abs(scrollProgress)) : 1.0f;
-                } else {
-                    // On large screens we need to fade the page as it nears its leftmost position
-                    alpha = mLeftScreenAlphaInterpolator.getInterpolation(1 - scrollProgress);
+
+                float scale = 1.0f;
+                float translationX = 0;
+                float alpha = 1.0f;
+
+                if (CAFETERIA_TRAY) {
+                    scale = (1 - interpolatedProgress) +
+                            interpolatedProgress * TRANSITION_SCALE_FACTOR;
+                    translationX = Math.min(0, scrollProgress) * v.getMeasuredWidth();
+
+                    if (scrollProgress < 0) {
+                        alpha = scrollProgress < 0 ? mAlphaInterpolator.getInterpolation(
+                            1 - Math.abs(scrollProgress)) : 1.0f;
+                    } else {
+                        // On large screens we need to fade the page as it nears its leftmost position
+                        alpha = mLeftScreenAlphaInterpolator.getInterpolation(1 - scrollProgress);
+                    }
                 }
 
                 v.setCameraDistance(mDensity * CAMERA_DISTANCE);
@@ -170,10 +347,7 @@ public class KeyguardWidgetPager extends PagedView {
                         // Overscroll to the left
                         v.setPivotX(TRANSITION_PIVOT * pageWidth);
                         v.setRotationY(-TRANSITION_MAX_ROTATION * scrollProgress);
-                        if (v instanceof KeyguardWidgetFrame) {
-                            ((KeyguardWidgetFrame) v).setOverScrollAmount(Math.abs(scrollProgress),
-                                    true);
-                        }
+                        v.setOverScrollAmount(Math.abs(scrollProgress), true);
                         scale = 1.0f;
                         alpha = 1.0f;
                         // On the first page, we don't want the page to have any lateral motion
@@ -184,25 +358,22 @@ public class KeyguardWidgetPager extends PagedView {
                         v.setRotationY(-TRANSITION_MAX_ROTATION * scrollProgress);
                         scale = 1.0f;
                         alpha = 1.0f;
-                        if (v instanceof KeyguardWidgetFrame) {
-                            ((KeyguardWidgetFrame) v).setOverScrollAmount(Math.abs(scrollProgress),
-                                    false);
-                        }
+                        v.setOverScrollAmount(Math.abs(scrollProgress), false);
                         // On the last page, we don't want the page to have any lateral motion.
                         translationX = 0;
                     } else {
                         v.setPivotY(pageHeight / 2.0f);
                         v.setPivotX(pageWidth / 2.0f);
                         v.setRotationY(0f);
-                        if (v instanceof KeyguardWidgetFrame) {
-                            ((KeyguardWidgetFrame) v).setOverScrollAmount(0, false);
-                        }
+                        v.setOverScrollAmount(0, false);
                     }
                 }
 
-                v.setTranslationX(translationX);
-                v.setScaleX(scale);
-                v.setScaleY(scale);
+                if (CAFETERIA_TRAY) {
+                    v.setTranslationX(translationX);
+                    v.setScaleX(scale);
+                    v.setScaleY(scale);
+                }
                 v.setAlpha(alpha);
 
                 // If the view has 0 alpha, we set it to be invisible so as to prevent
@@ -215,4 +386,58 @@ public class KeyguardWidgetPager extends PagedView {
             }
         }
     }
+
+    @Override
+    protected void onStartReordering() {
+        super.onStartReordering();
+        setChildrenOutlineMultiplier(1.0f);
+        showOutlines();
+    }
+
+    @Override
+    protected void onEndReordering() {
+        super.onEndReordering();
+        hideOutlines();
+    }
+
+    void showOutlines() {
+        if (mChildrenOutlineFadeOutAnimation != null) mChildrenOutlineFadeOutAnimation.cancel();
+        if (mChildrenOutlineFadeInAnimation != null) mChildrenOutlineFadeInAnimation.cancel();
+        mChildrenOutlineFadeInAnimation = ObjectAnimator.ofFloat(this, "childrenOutlineAlpha", 1.0f);
+        mChildrenOutlineFadeInAnimation.setDuration(CHILDREN_OUTLINE_FADE_IN_DURATION);
+        mChildrenOutlineFadeInAnimation.start();
+    }
+
+    void hideOutlines() {
+        if (mChildrenOutlineFadeInAnimation != null) mChildrenOutlineFadeInAnimation.cancel();
+        if (mChildrenOutlineFadeOutAnimation != null) mChildrenOutlineFadeOutAnimation.cancel();
+        mChildrenOutlineFadeOutAnimation = ObjectAnimator.ofFloat(this, "childrenOutlineAlpha", 0.0f);
+        mChildrenOutlineFadeOutAnimation.setDuration(CHILDREN_OUTLINE_FADE_OUT_DURATION);
+        mChildrenOutlineFadeOutAnimation.setStartDelay(CHILDREN_OUTLINE_FADE_OUT_DELAY);
+        mChildrenOutlineFadeOutAnimation.start();
+    }
+
+    public void setChildrenOutlineAlpha(float alpha) {
+        mChildrenOutlineAlpha = alpha;
+        for (int i = 0; i < getChildCount(); i++) {
+            getWidgetPageAt(i).setBackgroundAlpha(alpha);
+        }
+    }
+
+    public void setChildrenOutlineMultiplier(float alpha) {
+        mChildrenOutlineAlpha = alpha;
+        for (int i = 0; i < getChildCount(); i++) {
+            getWidgetPageAt(i).setBackgroundAlphaMultiplier(alpha);
+        }
+    }
+
+    public float getChildrenOutlineAlpha() {
+        return mChildrenOutlineAlpha;
+    }
+
+    @Override
+    public boolean onLongClick(View v) {
+        startReordering();
+        return true;
+    }
 }
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetRegion.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetRegion.java
deleted file mode 100644 (file)
index 4ff6f27..0000000
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * 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.util.AttributeSet;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.LinearLayout;
-
-import com.android.internal.R;
-public class KeyguardWidgetRegion extends LinearLayout implements PagedView.PageSwitchListener {
-    KeyguardGlowStripView mLeftStrip;
-    KeyguardGlowStripView mRightStrip;
-    KeyguardWidgetPager mPager;
-    private int mPage = 0;
-    private Callbacks mCallbacks;
-
-    // We are disabling touch interaction of the widget region for factory ROM. 
-    private static final boolean DISABLE_TOUCH_INTERACTION = true;
-
-    private static final long CUSTOM_WIDGET_USER_ACTIVITY_TIMEOUT = 30000;
-
-    public KeyguardWidgetRegion(Context context) {
-        this(context, null, 0);
-    }
-
-    public KeyguardWidgetRegion(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public KeyguardWidgetRegion(Context context, AttributeSet attrs, int defStyle) {
-        super(context, attrs, defStyle);
-    }
-
-    @Override
-    protected void onFinishInflate() {
-        super.onFinishInflate();
-        mLeftStrip = (KeyguardGlowStripView) findViewById(R.id.left_strip);
-        mRightStrip = (KeyguardGlowStripView) findViewById(R.id.right_strip);
-        mPager = (KeyguardWidgetPager) findViewById(R.id.app_widget_container);
-        mPager.setPageSwitchListener(this);
-
-        setSoundEffectsEnabled(false);
-        if (!DISABLE_TOUCH_INTERACTION) {
-            setOnClickListener(new OnClickListener() {
-                @Override
-                public void onClick(View v) {
-                    showPagingFeedback();
-                }
-            });
-        }
-    }
-
-    public void showPagingFeedback() {
-        if ((mPage < mPager.getPageCount() - 1)) {
-            mLeftStrip.makeEmGo();
-        }
-        if ((mPage > 0)) {
-            mRightStrip.makeEmGo();
-        }
-    }
-
-    @Override
-    public void onPageSwitch(View newPage, int newPageIndex) {
-        boolean showingStatusWidget = false;
-        if (newPage instanceof ViewGroup) {
-            ViewGroup vg = (ViewGroup) newPage;
-            if (vg.getChildAt(0) instanceof KeyguardStatusView) {
-                showingStatusWidget = true;
-            }
-        }
-
-        // Disable the status bar clock if we're showing the default status widget
-        if (showingStatusWidget) {
-            setSystemUiVisibility(getSystemUiVisibility() | View.STATUS_BAR_DISABLE_CLOCK);
-        } else {
-            setSystemUiVisibility(getSystemUiVisibility() & ~View.STATUS_BAR_DISABLE_CLOCK);
-        }
-
-        // Extend the display timeout if the user switches pages
-        if (mPage != newPageIndex) {
-            mPage = newPageIndex;
-            if (mCallbacks != null) {
-                mCallbacks.onUserActivityTimeoutChanged();
-                mCallbacks.userActivity();
-            }
-        }
-    }
-
-    public long getUserActivityTimeout() {
-        View page = mPager.getPageAt(mPage);
-        if (page instanceof ViewGroup) {
-            ViewGroup vg = (ViewGroup) page;
-            View view = vg.getChildAt(0);
-            if (!(view instanceof KeyguardStatusView)
-                    && !(view instanceof KeyguardMultiUserSelectorView)) {
-                return CUSTOM_WIDGET_USER_ACTIVITY_TIMEOUT;
-            }
-        }
-        return -1;
-    }
-
-    public void setCallbacks(Callbacks callbacks) {
-        mCallbacks = callbacks;
-    }
-
-    public interface Callbacks {
-        public void userActivity();
-        public void onUserActivityTimeoutChanged();
-    }
-}
index 86c05b1..df03c9e 100644 (file)
@@ -18,12 +18,17 @@ package com.android.internal.policy.impl.keyguard;
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
 import android.animation.ObjectAnimator;
 import android.animation.PropertyValuesHolder;
+import android.animation.TimeInterpolator;
 import android.animation.ValueAnimator;
+import android.animation.ValueAnimator.AnimatorUpdateListener;
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.graphics.Canvas;
+import android.graphics.Matrix;
+import android.graphics.PointF;
 import android.graphics.Rect;
 import android.os.Bundle;
 import android.os.Parcel;
@@ -38,9 +43,13 @@ import android.view.View;
 import android.view.ViewConfiguration;
 import android.view.ViewGroup;
 import android.view.ViewParent;
+import android.view.View.MeasureSpec;
+import android.view.ViewGroup.LayoutParams;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
 import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.animation.AnimationUtils;
+import android.view.animation.DecelerateInterpolator;
 import android.view.animation.Interpolator;
 import android.widget.Scroller;
 
@@ -60,7 +69,7 @@ public class PagedView extends ViewGroup implements ViewGroup.OnHierarchyChangeL
     // the min drag distance for a fling to register, to prevent random page shifts
     private static final int MIN_LENGTH_FOR_FLING = 25;
 
-    protected static final int PAGE_SNAP_ANIMATION_DURATION = 550;
+    protected static final int PAGE_SNAP_ANIMATION_DURATION = 750;
     protected static final int SLOW_PAGE_SNAP_ANIMATION_DURATION = 950;
     protected static final float NANOTIME_DIV = 1000000000.0f;
 
@@ -78,7 +87,9 @@ public class PagedView extends ViewGroup implements ViewGroup.OnHierarchyChangeL
     private static final int MIN_FLING_VELOCITY = 250;
 
     // We are disabling touch interaction of the widget region for factory ROM. 
-    private static final boolean DISABLE_TOUCH_INTERACTION = true;
+    private static final boolean DISABLE_TOUCH_INTERACTION = false;
+    private static final boolean DISABLE_TOUCH_SIDE_PAGES = true;
+    private static final boolean DISABLE_FLING_TO_DELETE = false;
 
     static final int AUTOMATIC_PAGE_SPACING = -1;
 
@@ -100,7 +111,11 @@ public class PagedView extends ViewGroup implements ViewGroup.OnHierarchyChangeL
     protected Scroller mScroller;
     private VelocityTracker mVelocityTracker;
 
+    private float mParentDownMotionX;
+    private float mParentDownMotionY;
     private float mDownMotionX;
+    private float mDownMotionY;
+    private float mDownScrollX;
     protected float mLastMotionX;
     protected float mLastMotionXRemainder;
     protected float mLastMotionY;
@@ -114,6 +129,8 @@ public class PagedView extends ViewGroup implements ViewGroup.OnHierarchyChangeL
     protected final static int TOUCH_STATE_SCROLLING = 1;
     protected final static int TOUCH_STATE_PREV_PAGE = 2;
     protected final static int TOUCH_STATE_NEXT_PAGE = 3;
+    protected final static int TOUCH_STATE_REORDERING = 4;
+
     protected final static float ALPHA_QUANTIZE_LEVEL = 0.0001f;
 
     protected int mTouchState = TOUCH_STATE_REST;
@@ -128,15 +145,8 @@ public class PagedView extends ViewGroup implements ViewGroup.OnHierarchyChangeL
     private int mMaximumVelocity;
     private int mMinimumWidth;
     protected int mPageSpacing;
-    protected int mPageLayoutPaddingTop;
-    protected int mPageLayoutPaddingBottom;
-    protected int mPageLayoutPaddingLeft;
-    protected int mPageLayoutPaddingRight;
-    protected int mPageLayoutWidthGap;
-    protected int mPageLayoutHeightGap;
     protected int mCellCountX = 0;
     protected int mCellCountY = 0;
-    protected boolean mCenterPagesVertically;
     protected boolean mAllowOverScroll = true;
     protected int mUnboundedScrollX;
     protected int[] mTempVisiblePagesRange = new int[2];
@@ -162,7 +172,7 @@ public class PagedView extends ViewGroup implements ViewGroup.OnHierarchyChangeL
     protected boolean mContentIsRefreshable = true;
 
     // If true, modify alpha of neighboring pages as user scrolls left/right
-    protected boolean mFadeInAdjacentScreens = true;
+    protected boolean mFadeInAdjacentScreens = false;
 
     // It true, use a different slop parameter (pagingTouchSlop = 2 * touchSlop) for deciding
     // to switch to a new page
@@ -188,6 +198,37 @@ public class PagedView extends ViewGroup implements ViewGroup.OnHierarchyChangeL
     protected static final int sScrollIndicatorFadeOutDuration = 650;
     protected static final int sScrollIndicatorFlashDuration = 650;
 
+    // Reordering
+    // We use the min scale to determine how much to expand the actually PagedView measured 
+    // dimensions such that when we are zoomed out, the view is not clipped 
+    private int REORDERING_DROP_REPOSITION_DURATION = 200;
+    private int REORDERING_REORDER_REPOSITION_DURATION = 350;
+    private int REORDERING_ZOOM_IN_OUT_DURATION = 250;
+    private int REORDERING_SIDE_PAGE_HOVER_TIMEOUT = 500;
+    private float REORDERING_SIDE_PAGE_BUFFER_PERCENTAGE = 0.1f;
+    private float mMinScale = 1f;
+    protected View mDragView;
+    private AnimatorSet mZoomInOutAnim;
+    private Runnable mSidePageHoverRunnable;
+    private int mSidePageHoverIndex = -1;
+
+    // Edge swiping
+    private boolean mOnlyAllowEdgeSwipes = false;
+    private boolean mDownEventOnEdge = false;
+    private int mEdgeSwipeRegionSize = 0;
+
+    // Convenience/caching
+    private Matrix mTmpInvMatrix = new Matrix();
+    private float[] mTmpPoint = new float[2];
+
+    // Fling to delete
+    private int FLING_TO_DELETE_FADE_OUT_DURATION = 350;
+    private float FLING_TO_DELETE_FRICTION = 0.035f;
+    // The degrees specifies how much deviation from the up vector to still consider a fling "up"
+    private float FLING_TO_DELETE_MAX_FLING_DEGREES = 35f;
+    protected int mFlingToDeleteThresholdVelocity = -1400; // TEMPORARY
+    private boolean mIsFlingingToDelete = false;
+
     public interface PageSwitchListener {
         void onPageSwitch(View newPage, int newPageIndex);
     }
@@ -205,22 +246,12 @@ public class PagedView extends ViewGroup implements ViewGroup.OnHierarchyChangeL
         TypedArray a = context.obtainStyledAttributes(attrs,
                 R.styleable.PagedView, defStyle, 0);
         setPageSpacing(a.getDimensionPixelSize(R.styleable.PagedView_pageSpacing, 0));
-        mPageLayoutPaddingTop = a.getDimensionPixelSize(
-                R.styleable.PagedView_pageLayoutPaddingTop, 0);
-        mPageLayoutPaddingBottom = a.getDimensionPixelSize(
-                R.styleable.PagedView_pageLayoutPaddingBottom, 0);
-        mPageLayoutPaddingLeft = a.getDimensionPixelSize(
-                R.styleable.PagedView_pageLayoutPaddingLeft, 0);
-        mPageLayoutPaddingRight = a.getDimensionPixelSize(
-                R.styleable.PagedView_pageLayoutPaddingRight, 0);
-        mPageLayoutWidthGap = a.getDimensionPixelSize(
-                R.styleable.PagedView_pageLayoutWidthGap, 0);
-        mPageLayoutHeightGap = a.getDimensionPixelSize(
-                R.styleable.PagedView_pageLayoutHeightGap, 0);
         mScrollIndicatorPaddingLeft =
             a.getDimensionPixelSize(R.styleable.PagedView_scrollIndicatorPaddingLeft, 0);
         mScrollIndicatorPaddingRight =
             a.getDimensionPixelSize(R.styleable.PagedView_scrollIndicatorPaddingRight, 0);
+        mEdgeSwipeRegionSize =
+                a.getDimensionPixelSize(R.styleable.PagedView_edgeSwipeRegionSize, 0);
         a.recycle();
 
         setHapticFeedbackEnabled(false);
@@ -235,7 +266,6 @@ public class PagedView extends ViewGroup implements ViewGroup.OnHierarchyChangeL
         mDirtyPageContent.ensureCapacity(32);
         mScroller = new Scroller(getContext(), new ScrollInterpolator());
         mCurrentPage = 0;
-        mCenterPagesVertically = true;
 
         final ViewConfiguration configuration = ViewConfiguration.get(getContext());
         mTouchSlop = configuration.getScaledTouchSlop();
@@ -249,6 +279,66 @@ public class PagedView extends ViewGroup implements ViewGroup.OnHierarchyChangeL
         setOnHierarchyChangeListener(this);
     }
 
+    // Convenience methods to map points from self to parent and vice versa
+    float[] mapPointFromSelfToParent(float x, float y) {
+        mTmpPoint[0] = x;
+        mTmpPoint[1] = y;
+        getMatrix().mapPoints(mTmpPoint);
+        mTmpPoint[0] += getLeft();
+        mTmpPoint[1] += getTop();
+        return mTmpPoint;
+    }
+    float[] mapPointFromParentToSelf(float x, float y) {
+        mTmpPoint[0] = x - getLeft();
+        mTmpPoint[1] = y - getTop();
+        getMatrix().invert(mTmpInvMatrix);
+        mTmpInvMatrix.mapPoints(mTmpPoint);
+        return mTmpPoint;
+    }
+
+    void updateDragViewTranslationDuringDrag() {
+        float x = mLastMotionX - mDownMotionX + getScrollX() - mDownScrollX;
+        float y = mLastMotionY - mDownMotionY;
+        mDragView.setTranslationX(x);
+        mDragView.setTranslationY(y);
+
+        if (DEBUG) Log.d(TAG, "PagedView.updateDragViewTranslationDuringDrag(): " + x + ", " + y);
+    }
+
+    public void setMinScale(float f) {
+        mMinScale = f;
+        requestLayout();
+    }
+
+    @Override
+    public void setScaleX(float scaleX) {
+        super.setScaleX(scaleX);
+        if (mTouchState == TOUCH_STATE_REORDERING) {
+            float[] p = mapPointFromParentToSelf(mParentDownMotionX, mParentDownMotionY);
+            mLastMotionX = p[0];
+            mLastMotionY = p[1];
+            updateDragViewTranslationDuringDrag();
+        }
+    }
+
+    // Convenience methods to get the actual width/height of the PagedView (since it is measured 
+    // to be larger to account for the minimum possible scale)
+    int getMinScaledMeasuredWidth() {
+        return (int) (getMeasuredWidth() * mMinScale);
+    }
+    int getMinScaledMeasuredHeight() {
+        return (int) (getMeasuredHeight() * mMinScale);
+    }
+
+    // Convenience methods to get the offset ASSUMING that we are centering the pages in the 
+    // PagedView both horizontally and vertically
+    int getOffsetX() {
+        return (getMeasuredWidth() - getMinScaledMeasuredWidth()) / 2;
+    }
+    int getOffsetY() {
+        return (getMeasuredHeight() - getMinScaledMeasuredHeight()) / 2;
+    }
+
     public void setPageSwitchListener(PageSwitchListener pageSwitchListener) {
         mPageSwitchListener = pageSwitchListener;
         if (mPageSwitchListener != null) {
@@ -328,6 +418,10 @@ public class PagedView extends ViewGroup implements ViewGroup.OnHierarchyChangeL
         invalidate();
     }
 
+    public void setOnlyAllowEdgeSwipes(boolean enable) {
+        mOnlyAllowEdgeSwipes = enable;
+    }
+
     protected void notifyPageSwitchListener() {
         if (mPageSwitchListener != null) {
             mPageSwitchListener.onPageSwitch(getPageAt(mCurrentPage), mCurrentPage);
@@ -400,6 +494,14 @@ public class PagedView extends ViewGroup implements ViewGroup.OnHierarchyChangeL
 
         mTouchX = x;
         mSmoothingTime = System.nanoTime() / NANOTIME_DIV;
+
+        // Update the last motion events when scrolling
+        if (mTouchState == TOUCH_STATE_REORDERING) {
+            float[] p = mapPointFromParentToSelf(mParentDownMotionX, mParentDownMotionY);
+            mLastMotionX = p[0];
+            mLastMotionY = p[1];
+            updateDragViewTranslationDuringDrag();
+        }
     }
 
     // we moved this functionality to a helper function so SmoothPagedView can reuse it
@@ -454,6 +556,10 @@ public class PagedView extends ViewGroup implements ViewGroup.OnHierarchyChangeL
             return;
         }
 
+        // We measure the dimensions of the PagedView to be larger than the pages so that when we
+        // zoom out (and scale down), the view is still contained in the parent
+        int scaledWidthSize = (int) (MeasureSpec.getSize(widthMeasureSpec) / mMinScale);
+        int scaledHeightSize = (int) (MeasureSpec.getSize(heightMeasureSpec) / mMinScale);
         final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
         final int widthSize = MeasureSpec.getSize(widthMeasureSpec);
         final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
@@ -481,13 +587,26 @@ public class PagedView extends ViewGroup implements ViewGroup.OnHierarchyChangeL
         // The children are given the same width and height as the workspace
         // unless they were set to WRAP_CONTENT
         if (DEBUG) Log.d(TAG, "PagedView.onMeasure(): " + widthSize + ", " + heightSize);
+        if (DEBUG) Log.d(TAG, "PagedView.horizontalPadding: " + horizontalPadding);
         final int childCount = getChildCount();
         for (int i = 0; i < childCount; i++) {
             // disallowing padding in paged view (just pass 0)
             final View child = getPageAt(i);
+            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
 
-            int childWidthMode = MeasureSpec.EXACTLY;
-            int childHeightMode = MeasureSpec.EXACTLY;
+            int childWidthMode;
+            if (lp.width == LayoutParams.WRAP_CONTENT) {
+                childWidthMode = MeasureSpec.AT_MOST;
+            } else {
+                childWidthMode = MeasureSpec.EXACTLY;
+            }
+
+            int childHeightMode;
+            if (lp.height == LayoutParams.WRAP_CONTENT) {
+                childHeightMode = MeasureSpec.AT_MOST;
+            } else {
+                childHeightMode = MeasureSpec.EXACTLY;
+            }
 
             final int childWidthMeasureSpec =
                 MeasureSpec.makeMeasureSpec(widthSize - horizontalPadding, childWidthMode);
@@ -496,8 +615,7 @@ public class PagedView extends ViewGroup implements ViewGroup.OnHierarchyChangeL
 
             child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
         }
-
-        setMeasuredDimension(widthSize, heightSize);
+        setMeasuredDimension(scaledWidthSize, scaledHeightSize);
 
         // We can't call getChildOffset/getRelativeChildOffset until we set the measured dimensions.
         // We also wait until we set the measured dimensions before flushing the cache as well, to
@@ -510,7 +628,7 @@ public class PagedView extends ViewGroup implements ViewGroup.OnHierarchyChangeL
         mChildCountOnLastMeasure = getChildCount();
 
         if (childCount > 0) {
-            if (DEBUG) Log.d(TAG, "getRelativeChildOffset(): " + getMeasuredWidth() + ", "
+            if (DEBUG) Log.d(TAG, "getRelativeChildOffset(): " + getMinScaledMeasuredWidth() + ", "
                     + getChildWidth(0));
 
             // Calculate the variable page spacing if necessary
@@ -547,19 +665,18 @@ public class PagedView extends ViewGroup implements ViewGroup.OnHierarchyChangeL
         }
 
         if (DEBUG) Log.d(TAG, "PagedView.onLayout()");
-        final int verticalPadding = getPaddingTop() + getPaddingBottom();
         final int childCount = getChildCount();
-        int childLeft = getRelativeChildOffset(0);
 
+        int scaleOffsetX = getOffsetX();
+        int scaleOffsetY = getOffsetY();
+
+        int childLeft = scaleOffsetX + getRelativeChildOffset(0);
         for (int i = 0; i < childCount; i++) {
             final View child = getPageAt(i);
+            int childTop = scaleOffsetY + getPaddingTop();
             if (child.getVisibility() != View.GONE) {
                 final int childWidth = getScaledMeasuredWidth(child);
                 final int childHeight = child.getMeasuredHeight();
-                int childTop = getPaddingTop();
-                if (mCenterPagesVertically) {
-                    childTop += ((getMeasuredHeight() - verticalPadding) - childHeight) / 2;
-                }
 
                 if (DEBUG) Log.d(TAG, "\tlayout-child" + i + ": " + childLeft + ", " + childTop);
                 child.layout(childLeft, childTop,
@@ -606,7 +723,7 @@ public class PagedView extends ViewGroup implements ViewGroup.OnHierarchyChangeL
 
     @Override
     public void onChildViewRemoved(View parent, View child) {
-        // TODO Auto-generated method stub
+        mForceScreenScrolled = true;
     }
 
     protected void invalidateCachedOffsets() {
@@ -659,7 +776,7 @@ public class PagedView extends ViewGroup implements ViewGroup.OnHierarchyChangeL
         } else {
             final int padding = getPaddingLeft() + getPaddingRight();
             final int offset = getPaddingLeft() +
-                    (getMeasuredWidth() - padding - getChildWidth(index)) / 2;
+                    (getMinScaledMeasuredWidth() - padding - getChildWidth(index)) / 2;
             if (mChildRelativeOffsets != null) {
                 mChildRelativeOffsets[index] = offset;
             }
@@ -676,33 +793,42 @@ public class PagedView extends ViewGroup implements ViewGroup.OnHierarchyChangeL
         return (int) (maxWidth * mLayoutScale + 0.5f);
     }
 
+    // TODO: Fix this
     protected void getVisiblePages(int[] range) {
+        range[0] = 0;
+        range[1] = getPageCount() - 1;
+        /*
         final int pageCount = getChildCount();
 
         if (pageCount > 0) {
-            final int screenWidth = getMeasuredWidth();
+            final int screenWidth = getMinScaledMeasuredWidth();
             int leftScreen = 0;
             int rightScreen = 0;
+            int offsetX = getOffsetX() + getScrollX();
             View currPage = getPageAt(leftScreen);
             while (leftScreen < pageCount - 1 &&
                     currPage.getX() + currPage.getWidth() -
-                    currPage.getPaddingRight() < getScrollX()) {
+                    currPage.getPaddingRight() < offsetX) {
                 leftScreen++;
                 currPage = getPageAt(leftScreen);
             }
             rightScreen = leftScreen;
             currPage = getPageAt(rightScreen + 1);
             while (rightScreen < pageCount - 1 &&
-                    currPage.getX() - currPage.getPaddingLeft() < getScrollX() + screenWidth) {
+                    currPage.getX() - currPage.getPaddingLeft() < offsetX + screenWidth) {
                 rightScreen++;
                 currPage = getPageAt(rightScreen + 1);
             }
-            range[0] = leftScreen;
-            range[1] = rightScreen;
+
+            // TEMP: this is a hacky way to ensure that animations to new pages are not clipped
+            // because we don't draw them while scrolling?
+            range[0] = Math.max(0, leftScreen - 1);
+            range[1] = Math.min(rightScreen + 1, getChildCount() - 1);
         } else {
             range[0] = -1;
             range[1] = -1;
         }
+        */
     }
 
     protected boolean shouldDrawChild(View child) {
@@ -711,7 +837,7 @@ public class PagedView extends ViewGroup implements ViewGroup.OnHierarchyChangeL
 
     @Override
     protected void dispatchDraw(Canvas canvas) {
-        int halfScreenSize = getMeasuredWidth() / 2;
+        int halfScreenSize = getMinScaledMeasuredWidth() / 2;
         // mOverScrollX is equal to getScrollX() when we're within the normal scroll range.
         // Otherwise it is equal to the scaled overscroll position.
         int screenCenter = mOverScrollX + halfScreenSize;
@@ -737,13 +863,20 @@ public class PagedView extends ViewGroup implements ViewGroup.OnHierarchyChangeL
                 canvas.clipRect(getScrollX(), getScrollY(), getScrollX() + getRight() - getLeft(),
                         getScrollY() + getBottom() - getTop());
 
-                for (int i = getChildCount() - 1; i >= 0; i--) {
+                // Draw all the children, leaving the drag view for last
+                for (int i = pageCount - 1; i >= 0; i--) {
                     final View v = getPageAt(i);
+                    if (v == mDragView) continue;
                     if (mForceDrawAllChildrenNextFrame ||
                                (leftScreen <= i && i <= rightScreen && shouldDrawChild(v))) {
                         drawChild(canvas, v, drawingTime);
                     }
                 }
+                // Draw the drag view on top (if there is one)
+                if (mDragView != null) {
+                    drawChild(canvas, mDragView, drawingTime);
+                }
+
                 mForceDrawAllChildrenNextFrame = false;
                 canvas.restore();
             }
@@ -853,14 +986,14 @@ public class PagedView extends ViewGroup implements ViewGroup.OnHierarchyChangeL
      * Return true if a tap at (x, y) should trigger a flip to the previous page.
      */
     protected boolean hitsPreviousPage(float x, float y) {
-        return (x < getRelativeChildOffset(mCurrentPage) - mPageSpacing);
+        return (x < getOffsetX() + getRelativeChildOffset(mCurrentPage) - mPageSpacing);
     }
 
     /**
      * Return true if a tap at (x, y) should trigger a flip to the next page.
      */
     protected boolean hitsNextPage(float x, float y) {
-        return  (x > (getMeasuredWidth() - getRelativeChildOffset(mCurrentPage) + mPageSpacing));
+        return  (x > (getOffsetX() + getMinScaledMeasuredWidth() - getRelativeChildOffset(mCurrentPage) + mPageSpacing));
     }
 
     @Override
@@ -912,12 +1045,23 @@ public class PagedView extends ViewGroup implements ViewGroup.OnHierarchyChangeL
                 final float y = ev.getY();
                 // Remember location of down touch
                 mDownMotionX = x;
+                mDownMotionY = y;
+                mDownScrollX = getScrollX();
                 mLastMotionX = x;
                 mLastMotionY = y;
+                float[] p = mapPointFromSelfToParent(x, y);
+                mParentDownMotionX = p[0];
+                mParentDownMotionY = p[1];
                 mLastMotionXRemainder = 0;
                 mTotalMotionX = 0;
                 mActivePointerId = ev.getPointerId(0);
-                mAllowLongPress = true;
+
+                // Determine if the down event is within the threshold to be an edge swipe
+                int leftEdgeBoundary = getOffsetX() + mEdgeSwipeRegionSize;
+                int rightEdgeBoundary = getMeasuredWidth() - getOffsetX() - mEdgeSwipeRegionSize;
+                if ((mDownMotionX <= leftEdgeBoundary || mDownMotionX >= rightEdgeBoundary)) {
+                    mDownEventOnEdge = true;
+                }
 
                 /*
                  * If being flinged and user touches the screen, initiate drag;
@@ -935,12 +1079,14 @@ public class PagedView extends ViewGroup implements ViewGroup.OnHierarchyChangeL
 
                 // check if this can be the beginning of a tap on the side of the pages
                 // to scroll the current page
-                if (mTouchState != TOUCH_STATE_PREV_PAGE && mTouchState != TOUCH_STATE_NEXT_PAGE) {
-                    if (getChildCount() > 0) {
-                        if (hitsPreviousPage(x, y)) {
-                            mTouchState = TOUCH_STATE_PREV_PAGE;
-                        } else if (hitsNextPage(x, y)) {
-                            mTouchState = TOUCH_STATE_NEXT_PAGE;
+                if (!DISABLE_TOUCH_SIDE_PAGES) {
+                    if (mTouchState != TOUCH_STATE_PREV_PAGE && mTouchState != TOUCH_STATE_NEXT_PAGE) {
+                        if (getChildCount() > 0) {
+                            if (hitsPreviousPage(x, y)) {
+                                mTouchState = TOUCH_STATE_PREV_PAGE;
+                            } else if (hitsNextPage(x, y)) {
+                                mTouchState = TOUCH_STATE_NEXT_PAGE;
+                            }
                         }
                     }
                 }
@@ -949,10 +1095,7 @@ public class PagedView extends ViewGroup implements ViewGroup.OnHierarchyChangeL
 
             case MotionEvent.ACTION_UP:
             case MotionEvent.ACTION_CANCEL:
-                mTouchState = TOUCH_STATE_REST;
-                mAllowLongPress = false;
-                mActivePointerId = INVALID_POINTER;
-                releaseVelocityTracker();
+                resetTouchState();
                 break;
 
             case MotionEvent.ACTION_POINTER_UP:
@@ -982,9 +1125,17 @@ public class PagedView extends ViewGroup implements ViewGroup.OnHierarchyChangeL
          * of the down event.
          */
         final int pointerIndex = ev.findPointerIndex(mActivePointerId);
+
         if (pointerIndex == -1) {
             return;
         }
+
+        // If we're only allowing edge swipes, we break out early if the down event wasn't
+        // at the edge.
+        if (mOnlyAllowEdgeSwipes && !mDownEventOnEdge) {
+            return;
+        }
+
         final float x = ev.getX(pointerIndex);
         final float y = ev.getY(pointerIndex);
         final int xDiff = (int) Math.abs(x - mLastMotionX);
@@ -1002,30 +1153,15 @@ public class PagedView extends ViewGroup implements ViewGroup.OnHierarchyChangeL
                 mTotalMotionX += Math.abs(mLastMotionX - x);
                 mLastMotionX = x;
                 mLastMotionXRemainder = 0;
-                mTouchX = getScrollX();
+                mTouchX = getOffsetX() + getScrollX();
                 mSmoothingTime = System.nanoTime() / NANOTIME_DIV;
                 pageBeginMoving();
             }
-            // Either way, cancel any pending longpress
-            cancelCurrentPageLongPress();
-        }
-    }
-
-    protected void cancelCurrentPageLongPress() {
-        if (mAllowLongPress) {
-            mAllowLongPress = false;
-            // Try canceling the long press. It could also have been scheduled
-            // by a distant descendant, so use the mAllowLongPress flag to block
-            // everything
-            final View currentPage = getPageAt(mCurrentPage);
-            if (currentPage != null) {
-                currentPage.cancelLongPress();
-            }
         }
     }
 
     protected float getScrollProgress(int screenCenter, View v, int page) {
-        final int halfScreenSize = getMeasuredWidth() / 2;
+        final int halfScreenSize = getMinScaledMeasuredWidth() / 2;
 
         int totalDistance = getScaledMeasuredWidth(v) + mPageSpacing;
         int delta = screenCenter - (getChildOffset(page) -
@@ -1045,7 +1181,7 @@ public class PagedView extends ViewGroup implements ViewGroup.OnHierarchyChangeL
     }
 
     protected void acceleratedOverScroll(float amount) {
-        int screenSize = getMeasuredWidth();
+        int screenSize = getMinScaledMeasuredWidth();
 
         // We want to reach the max over scroll effect when the user has
         // over scrolled half the size of the screen
@@ -1070,7 +1206,7 @@ public class PagedView extends ViewGroup implements ViewGroup.OnHierarchyChangeL
     }
 
     protected void dampedOverScroll(float amount) {
-        int screenSize = getMeasuredWidth();
+        int screenSize = getMinScaledMeasuredWidth();
 
         float f = (amount / screenSize);
 
@@ -1104,7 +1240,7 @@ public class PagedView extends ViewGroup implements ViewGroup.OnHierarchyChangeL
         f = f / (Math.abs(f)) * (overScrollInfluenceCurve(Math.abs(f)));
         return OVERSCROLL_DAMP_FACTOR * f;
     }
-
+    
     @Override
     public boolean onTouchEvent(MotionEvent ev) {
         if (DISABLE_TOUCH_INTERACTION) {
@@ -1130,9 +1266,22 @@ public class PagedView extends ViewGroup implements ViewGroup.OnHierarchyChangeL
 
             // Remember where the motion event started
             mDownMotionX = mLastMotionX = ev.getX();
+            mDownMotionY = mLastMotionY = ev.getY();
+            mDownScrollX = getScrollX();
+            float[] p = mapPointFromSelfToParent(mLastMotionX, mLastMotionY);
+            mParentDownMotionX = p[0];
+            mParentDownMotionY = p[1];
             mLastMotionXRemainder = 0;
             mTotalMotionX = 0;
             mActivePointerId = ev.getPointerId(0);
+
+            // Determine if the down event is within the threshold to be an edge swipe
+            int leftEdgeBoundary = getOffsetX() + mEdgeSwipeRegionSize;
+            int rightEdgeBoundary = getMeasuredWidth() - getOffsetX() - mEdgeSwipeRegionSize;
+            if ((mDownMotionX <= leftEdgeBoundary || mDownMotionX >= rightEdgeBoundary)) {
+                mDownEventOnEdge = true;
+            }
+
             if (mTouchState == TOUCH_STATE_SCROLLING) {
                 pageBeginMoving();
             }
@@ -1164,7 +1313,93 @@ public class PagedView extends ViewGroup implements ViewGroup.OnHierarchyChangeL
                 } else {
                     awakenScrollBars();
                 }
-            } else {
+            } else if (mTouchState == TOUCH_STATE_REORDERING) {
+                // Update the last motion position
+                mLastMotionX = ev.getX();
+                mLastMotionY = ev.getY();
+
+                // Update the parent down so that our zoom animations take this new movement into 
+                // account
+                float[] pt = mapPointFromSelfToParent(mLastMotionX, mLastMotionY);
+                mParentDownMotionX = pt[0];
+                mParentDownMotionY = pt[1];
+                updateDragViewTranslationDuringDrag();
+
+                // Find the closest page to the touch point
+                final int dragViewIndex = indexOfChild(mDragView);
+                int bufferSize = (int) (REORDERING_SIDE_PAGE_BUFFER_PERCENTAGE * 
+                    getMinScaledMeasuredWidth());
+                int leftBufferEdge = (int) mapPointFromSelfToParent(0, 0)[0] + bufferSize;
+                int rightBufferEdge = (int) mapPointFromSelfToParent(getMeasuredWidth(), 0)[0] 
+                        - bufferSize;
+                float parentX = mParentDownMotionX;
+                int pageIndexToSnapTo = -1;                
+                if (parentX < leftBufferEdge && dragViewIndex > 0) {
+                    pageIndexToSnapTo = dragViewIndex - 1;
+                } else if (parentX > rightBufferEdge && dragViewIndex < getChildCount() - 1) {
+                    pageIndexToSnapTo = dragViewIndex + 1;
+                }       
+
+                final int pageUnderPointIndex = pageIndexToSnapTo;
+                if (pageUnderPointIndex > -1) {
+                    if (pageUnderPointIndex != mSidePageHoverIndex && mScroller.isFinished()) {
+                        mSidePageHoverIndex = pageUnderPointIndex;
+                        mSidePageHoverRunnable = new Runnable() {
+                            @Override
+                            public void run() {
+                                // Update the down scroll position to account for the fact that the
+                                // current page is moved
+                                mDownScrollX = getChildOffset(pageUnderPointIndex) 
+                                        - getRelativeChildOffset(pageUnderPointIndex);
+                                
+                                // Setup the scroll to the correct page before we swap the views
+                                snapToPage(pageUnderPointIndex);
+                                
+                                // For each of the pages between the paged view and the drag view, 
+                                // animate them from the previous position to the new position in 
+                                // the layout (as a result of the drag view moving in the layout)
+                                int shiftDelta = (dragViewIndex < pageUnderPointIndex) ? -1 : 1;
+                                int lowerIndex = (dragViewIndex < pageUnderPointIndex) ? 
+                                        dragViewIndex + 1 : pageUnderPointIndex;
+                                int upperIndex = (dragViewIndex > pageUnderPointIndex) ?
+                                        dragViewIndex - 1 : pageUnderPointIndex;
+                                for (int i = lowerIndex; i <= upperIndex; ++i) {
+                                    View v = getChildAt(i);
+                                    // dragViewIndex < pageUnderPointIndex, so after we remove the 
+                                    // drag view all subsequent views to pageUnderPointIndex will 
+                                    // shift down.
+                                    int oldX = getOffsetX() + getChildOffset(i);
+                                    int newX = getOffsetX() + getChildOffset(i + shiftDelta);
+                                        
+
+                                    // Animate the view translation from its old position to its new
+                                    // position
+                                    AnimatorSet anim = (AnimatorSet) v.getTag();
+                                    if (anim != null) {
+                                        anim.cancel();
+                                    }
+
+                                    v.setTranslationX(oldX - newX);
+                                    anim = new AnimatorSet();
+                                    anim.setDuration(REORDERING_REORDER_REPOSITION_DURATION);
+                                    anim.playTogether(
+                                            ObjectAnimator.ofFloat(v, "translationX", 0f));
+                                    anim.start();
+                                    v.setTag(anim);
+                                }
+
+                                removeView(mDragView);
+                                addView(mDragView, pageUnderPointIndex);
+                                mSidePageHoverIndex = -1;
+                            }  
+                        };
+                        postDelayed(mSidePageHoverRunnable, REORDERING_SIDE_PAGE_HOVER_TIMEOUT);
+                    }
+                } else {
+                    removeCallbacks(mSidePageHoverRunnable);
+                    mSidePageHoverIndex = -1;
+                }
+            } else {                
                 determineScrollingStart(ev);
             }
             break;
@@ -1232,21 +1467,29 @@ public class PagedView extends ViewGroup implements ViewGroup.OnHierarchyChangeL
                 } else {
                     snapToDestination();
                 }
+            } else if (mTouchState == TOUCH_STATE_REORDERING) {
+                if (!DISABLE_FLING_TO_DELETE) {
+                    // Check the velocity and see if we are flinging-to-delete
+                    PointF flingToDeleteVector = isFlingingToDelete();
+                    if (flingToDeleteVector != null) {
+                        onFlingToDelete(flingToDeleteVector);
+                    }
+                }
             } else {
                 onUnhandledTap(ev);
             }
-            mTouchState = TOUCH_STATE_REST;
-            mActivePointerId = INVALID_POINTER;
-            releaseVelocityTracker();
+
+            // Remove the callback to wait for the side page hover timeout
+            removeCallbacks(mSidePageHoverRunnable);
+            // End any intermediate reordering states
+            resetTouchState();
             break;
 
         case MotionEvent.ACTION_CANCEL:
             if (mTouchState == TOUCH_STATE_SCROLLING) {
                 snapToDestination();
             }
-            mTouchState = TOUCH_STATE_REST;
-            mActivePointerId = INVALID_POINTER;
-            releaseVelocityTracker();
+            resetTouchState();
             break;
 
         case MotionEvent.ACTION_POINTER_UP:
@@ -1257,6 +1500,16 @@ public class PagedView extends ViewGroup implements ViewGroup.OnHierarchyChangeL
         return true;
     }
 
+    private void resetTouchState() {
+        releaseVelocityTracker();
+        endReordering();
+        mTouchState = TOUCH_STATE_REST;
+        mActivePointerId = INVALID_POINTER;
+        mDownEventOnEdge = false;
+    }
+
+    protected void onUnhandledTap(MotionEvent ev) {}
+
     @Override
     public boolean onGenericMotionEvent(MotionEvent event) {
         if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) {
@@ -1319,8 +1572,6 @@ public class PagedView extends ViewGroup implements ViewGroup.OnHierarchyChangeL
         }
     }
 
-    protected void onUnhandledTap(MotionEvent ev) {}
-
     @Override
     public void requestChildFocus(View child, View focused) {
         super.requestChildFocus(child, focused);
@@ -1351,17 +1602,29 @@ public class PagedView extends ViewGroup implements ViewGroup.OnHierarchyChangeL
         final int minWidth = mMinimumWidth;
         return (minWidth > measuredWidth) ? minWidth : measuredWidth;
     }
+    
+    int getPageNearestToPoint(float x) {
+        int index = 0;
+        for (int i = 0; i < getChildCount(); ++i) {
+            if (x < getChildAt(i).getRight() - getScrollX()) {
+                return index;
+            } else {
+                index++;
+            }
+        }
+        return Math.min(index, getChildCount() - 1); 
+    }
 
     int getPageNearestToCenterOfScreen() {
         int minDistanceFromScreenCenter = Integer.MAX_VALUE;
         int minDistanceFromScreenCenterIndex = -1;
-        int screenCenter = getScrollX() + (getMeasuredWidth() / 2);
+        int screenCenter = getOffsetX() + getScrollX() + (getMinScaledMeasuredWidth() / 2);
         final int childCount = getChildCount();
         for (int i = 0; i < childCount; ++i) {
             View layout = (View) getPageAt(i);
             int childWidth = getScaledMeasuredWidth(layout);
             int halfChildWidth = (childWidth / 2);
-            int childCenter = getChildOffset(i) + halfChildWidth;
+            int childCenter = getOffsetX() + getChildOffset(i) + halfChildWidth;
             int distanceFromScreenCenter = Math.abs(childCenter - screenCenter);
             if (distanceFromScreenCenter < minDistanceFromScreenCenter) {
                 minDistanceFromScreenCenter = distanceFromScreenCenter;
@@ -1397,11 +1660,11 @@ public class PagedView extends ViewGroup implements ViewGroup.OnHierarchyChangeL
 
     protected void snapToPageWithVelocity(int whichPage, int velocity) {
         whichPage = Math.max(0, Math.min(whichPage, getChildCount() - 1));
-        int halfScreenSize = getMeasuredWidth() / 2;
+        int halfScreenSize = getMinScaledMeasuredWidth() / 2;
 
         if (DEBUG) Log.d(TAG, "snapToPage.getChildOffset(): " + getChildOffset(whichPage));
         if (DEBUG) Log.d(TAG, "snapToPageWithVelocity.getRelativeChildOffset(): "
-                + getMeasuredWidth() + ", " + getChildWidth(whichPage));
+                + getMinScaledMeasuredWidth() + ", " + getChildWidth(whichPage));
         final int newX = getChildOffset(whichPage) - getRelativeChildOffset(whichPage);
         int delta = newX - mUnboundedScrollX;
         int duration = 0;
@@ -1440,7 +1703,7 @@ public class PagedView extends ViewGroup implements ViewGroup.OnHierarchyChangeL
         whichPage = Math.max(0, Math.min(whichPage, getPageCount() - 1));
 
         if (DEBUG) Log.d(TAG, "snapToPage.getChildOffset(): " + getChildOffset(whichPage));
-        if (DEBUG) Log.d(TAG, "snapToPage.getRelativeChildOffset(): " + getMeasuredWidth() + ", "
+        if (DEBUG) Log.d(TAG, "snapToPage.getRelativeChildOffset(): " + getMinScaledMeasuredWidth() + ", "
                 + getChildWidth(whichPage));
         int newX = getChildOffset(whichPage) - getRelativeChildOffset(whichPage);
         final int sX = mUnboundedScrollX;
@@ -1500,21 +1763,6 @@ public class PagedView extends ViewGroup implements ViewGroup.OnHierarchyChangeL
         return result;
     }
 
-    /**
-     * @return True is long presses are still allowed for the current touch
-     */
-    public boolean allowLongPress() {
-        return mAllowLongPress;
-    }
-
-    /**
-     * Set true to allow long-press events to be triggered, usually checked by
-     * {@link Launcher} to accept or block dpad-initiated long-presses.
-     */
-    public void setAllowLongPress(boolean allowLongPress) {
-        mAllowLongPress = allowLongPress;
-    }
-
     public static class SavedState extends BaseSavedState {
         int currentPage = -1;
 
@@ -1653,7 +1901,7 @@ public class PagedView extends ViewGroup implements ViewGroup.OnHierarchyChangeL
         if (!isScrollingIndicatorEnabled()) return;
         if (mScrollIndicator == null) return;
         int numPages = getChildCount();
-        int pageWidth = getMeasuredWidth();
+        int pageWidth = getMinScaledMeasuredWidth();
         int lastChildIndex = Math.max(0, getChildCount() - 1);
         int maxScrollX = getChildOffset(lastChildIndex) - getRelativeChildOffset(lastChildIndex);
         int trackWidth = pageWidth - mScrollIndicatorPaddingLeft - mScrollIndicatorPaddingRight;
@@ -1675,6 +1923,234 @@ public class PagedView extends ViewGroup implements ViewGroup.OnHierarchyChangeL
         mScrollIndicator.setTranslationX(indicatorPos);
     }
 
+    // Animate the drag view back to the original position
+    void animateChildrenToOriginalPosition() {
+        if (mDragView != null) {
+            AnimatorSet anim = new AnimatorSet();
+            anim.setDuration(REORDERING_DROP_REPOSITION_DURATION);
+            anim.playTogether(
+                    ObjectAnimator.ofFloat(mDragView, "translationX", 0f),
+                    ObjectAnimator.ofFloat(mDragView, "translationY", 0f));
+            anim.start();
+        }
+    }
+
+    // "Zooms out" the PagedView to reveal more side pages
+    boolean zoomOut() {
+        if (!(getScaleX() < 1f || getScaleY() < 1f)) {
+            if (mZoomInOutAnim != null && mZoomInOutAnim.isRunning()) {
+                mZoomInOutAnim.cancel();
+            }
+
+            mZoomInOutAnim = new AnimatorSet();
+            mZoomInOutAnim.setDuration(REORDERING_ZOOM_IN_OUT_DURATION);
+            mZoomInOutAnim.playTogether(
+                    ObjectAnimator.ofFloat(this, "scaleX", mMinScale),
+                    ObjectAnimator.ofFloat(this, "scaleY", mMinScale));
+            mZoomInOutAnim.start();
+            return true;
+        }
+        return false;
+    }
+
+    protected void onStartReordering() {
+    }
+
+    protected void onEndReordering() {
+    }
+    
+    public void startReordering() {
+        if (zoomOut()) {
+            onStartReordering();
+
+            // Set the touch state to reordering (allows snapping to pages, dragging a child, etc.)
+            mTouchState = TOUCH_STATE_REORDERING;
+            // Find the drag view under the pointer
+            mDragView = getChildAt(getPageNearestToCenterOfScreen());
+
+            // We must invalidate to trigger a redraw to update the layers such that the drag view
+            // is always drawn on top
+            invalidate();
+        }
+    }
+
+    void endReordering() {
+        Runnable onCompleteRunnable = new Runnable() {
+            @Override
+            public void run() {
+                onEndReordering();
+            }
+        };
+        if (zoomIn(onCompleteRunnable)) {
+            // Snap to the current page
+            snapToDestination();
+        }
+        // If we haven't flung-to-delete the current child, then we just animate the drag view
+        // back into position
+        if (!mIsFlingingToDelete) {
+            animateChildrenToOriginalPosition();
+        }
+    }
+
+    public boolean isReordering() {
+        return mTouchState == TOUCH_STATE_REORDERING;
+    }
+
+    // "Zooms in" the PagedView to highlight the current page
+    boolean zoomIn(final Runnable onCompleteRunnable) {
+        if (getScaleX() < 1f || getScaleY() < 1f) {
+            if (mZoomInOutAnim != null && mZoomInOutAnim.isRunning()) {
+                mZoomInOutAnim.cancel();
+            }
+
+            mZoomInOutAnim = new AnimatorSet();
+            mZoomInOutAnim.setDuration(REORDERING_ZOOM_IN_OUT_DURATION);
+            mZoomInOutAnim.playTogether(
+                    ObjectAnimator.ofFloat(this, "scaleX", 1f),
+                    ObjectAnimator.ofFloat(this, "scaleY", 1f));
+            mZoomInOutAnim.addListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationCancel(Animator animation) {
+                    mDragView = null;
+                }
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    mDragView = null;
+                    if (onCompleteRunnable != null) {
+                        onCompleteRunnable.run();
+                    }
+                }
+            });
+            mZoomInOutAnim.start();
+            return true;
+        }
+        return false;
+    }
+
+    /*
+     * Flinging to delete - IN PROGRESS 
+     */
+    private PointF isFlingingToDelete() {
+        ViewConfiguration config = ViewConfiguration.get(getContext());
+        mVelocityTracker.computeCurrentVelocity(1000, config.getScaledMaximumFlingVelocity());
+
+        if (mVelocityTracker.getYVelocity() < mFlingToDeleteThresholdVelocity) {
+            // Do a quick dot product test to ensure that we are flinging upwards
+            PointF vel = new PointF(mVelocityTracker.getXVelocity(),
+                    mVelocityTracker.getYVelocity());
+            PointF upVec = new PointF(0f, -1f);
+            float theta = (float) Math.acos(((vel.x * upVec.x) + (vel.y * upVec.y)) /
+                    (vel.length() * upVec.length()));
+            if (theta <= Math.toRadians(FLING_TO_DELETE_MAX_FLING_DEGREES)) {
+                return vel;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Creates an animation from the current drag view along its current velocity vector.
+     * For this animation, the alpha runs for a fixed duration and we update the position
+     * progressively.
+     */
+    private static class FlingAlongVectorAnimatorUpdateListener implements AnimatorUpdateListener {
+        private View mDragView;
+        private PointF mVelocity;
+        private Rect mFrom;
+        private long mPrevTime;
+        private float mFriction;
+
+        private final TimeInterpolator mAlphaInterpolator = new DecelerateInterpolator(0.75f);
+
+        public FlingAlongVectorAnimatorUpdateListener(View dragView, PointF vel, Rect from,
+                long startTime, float friction) {
+            mDragView = dragView;
+            mVelocity = vel;
+            mFrom = from;
+            mPrevTime = startTime;
+            mFriction = 1f - (mDragView.getResources().getDisplayMetrics().density * friction);
+        }
+
+        @Override
+        public void onAnimationUpdate(ValueAnimator animation) {
+            float t = ((Float) animation.getAnimatedValue()).floatValue();
+            long curTime = AnimationUtils.currentAnimationTimeMillis();
+
+            mFrom.left += (mVelocity.x * (curTime - mPrevTime) / 1000f);
+            mFrom.top += (mVelocity.y * (curTime - mPrevTime) / 1000f);
+
+            mDragView.setTranslationX(mFrom.left);
+            mDragView.setTranslationY(mFrom.top);
+            mDragView.setAlpha(1f - mAlphaInterpolator.getInterpolation(t));
+
+            mVelocity.x *= mFriction;
+            mVelocity.y *= mFriction;
+            mPrevTime = curTime;
+        }
+    };
+
+    public void onFlingToDelete(PointF vel) {
+        final ViewConfiguration config = ViewConfiguration.get(getContext());
+        final long startTime = AnimationUtils.currentAnimationTimeMillis();
+
+        // NOTE: Because it takes time for the first frame of animation to actually be
+        // called and we expect the animation to be a continuation of the fling, we have
+        // to account for the time that has elapsed since the fling finished.  And since
+        // we don't have a startDelay, we will always get call to update when we call
+        // start() (which we want to ignore).
+        final TimeInterpolator tInterpolator = new TimeInterpolator() {
+            private int mCount = -1;
+            private long mStartTime;
+            private float mOffset;
+            /* Anonymous inner class ctor */ {
+                mStartTime = startTime;
+            }
+
+            @Override
+            public float getInterpolation(float t) {
+                if (mCount < 0) {
+                    mCount++;
+                } else if (mCount == 0) {
+                    mOffset = Math.min(0.5f, (float) (AnimationUtils.currentAnimationTimeMillis() -
+                            mStartTime) / FLING_TO_DELETE_FADE_OUT_DURATION);
+                    mCount++;
+                }
+                return Math.min(1f, mOffset + t);
+            }
+        };
+
+        final Rect from = new Rect();
+        final View dragView = mDragView;   
+        from.left = (int) dragView.getTranslationX();
+        from.top = (int) dragView.getTranslationY();
+        AnimatorUpdateListener updateCb = new FlingAlongVectorAnimatorUpdateListener(dragView, vel, from, startTime,
+                FLING_TO_DELETE_FRICTION);
+
+        final Runnable onAnimationEndRunnable = new Runnable() {
+            @Override
+            public void run() {
+                // TEMP - in progress
+                mIsFlingingToDelete = false;
+                removeView(dragView);
+                requestLayout();
+            }
+        };
+
+        // Create and start the animation
+        ValueAnimator mDropAnim = new ValueAnimator();
+        mDropAnim.setInterpolator(tInterpolator);
+        mDropAnim.setDuration(FLING_TO_DELETE_FADE_OUT_DURATION);
+        mDropAnim.setFloatValues(0f, 1f);
+        mDropAnim.addUpdateListener(updateCb);
+        mDropAnim.addListener(new AnimatorListenerAdapter() {
+            public void onAnimationEnd(Animator animation) {
+                onAnimationEndRunnable.run();
+            }
+        });
+        mDropAnim.start();
+        mIsFlingingToDelete = true;
+    }
+
     /* Accessibility */
     @Override
     public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/SecureCamera.java b/policy/src/com/android/internal/policy/impl/keyguard/SecureCamera.java
new file mode 100644 (file)
index 0000000..505917e
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * 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.app.Activity;
+import android.os.Bundle;
+import android.widget.FrameLayout;
+
+public class SecureCamera extends Activity  {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(new FrameLayout(this));
+    }
+
+}
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/SlidingChallengeLayout.java b/policy/src/com/android/internal/policy/impl/keyguard/SlidingChallengeLayout.java
new file mode 100644 (file)
index 0000000..d11da02
--- /dev/null
@@ -0,0 +1,690 @@
+/*
+ * 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.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.MotionEvent;
+import android.view.VelocityTracker;
+import android.view.View;
+import android.view.ViewConfiguration;
+import android.view.ViewGroup;
+import android.view.animation.Interpolator;
+import android.widget.Scroller;
+
+import com.android.internal.R;
+
+/**
+ * This layout handles interaction with the sliding security challenge views
+ * that overlay/resize other keyguard contents.
+ */
+public class SlidingChallengeLayout extends ViewGroup {
+    private static final String TAG = "SlidingChallengeLayout";
+
+    // Drawn to show the drag handle in closed state; crossfades to the challenge view
+    // when challenge is fully visible
+    private Drawable mHandleDrawable;
+
+    // Initialized during measurement from child layoutparams
+    private View mChallengeView;
+
+    // Range: 0 (fully hidden) to 1 (fully visible)
+    private float mChallengeOffset = 1.f;
+    private boolean mChallengeShowing = true;
+
+    private final Scroller mScroller;
+    private int mScrollState;
+    private OnChallengeScrolledListener mListener;
+
+    public static final int SCROLL_STATE_IDLE = 0;
+    public static final int SCROLL_STATE_DRAGGING = 1;
+    public static final int SCROLL_STATE_SETTLING = 2;
+
+    private static final int MAX_SETTLE_DURATION = 600; // ms
+
+    // ID of the pointer in charge of a current drag
+    private int mActivePointerId = INVALID_POINTER;
+    private static final int INVALID_POINTER = -1;
+
+    // True if the user is currently dragging the slider
+    private boolean mDragging;
+    // True if the user may not drag until a new gesture begins
+    private boolean mBlockDrag;
+
+    private VelocityTracker mVelocityTracker;
+    private int mMinVelocity;
+    private int mMaxVelocity;
+    private float mLastTouchY;
+    private int mDragHandleSize;
+
+    private static final int DRAG_HANDLE_DEFAULT_SIZE = 32; // dp
+
+    // True if at least one layout pass has happened since the view was attached.
+    private boolean mHasLayout;
+
+    private static final Interpolator sMotionInterpolator = new Interpolator() {
+        public float getInterpolation(float t) {
+            t -= 1.0f;
+            return t * t * t * t * t + 1.0f;
+        }
+    };
+
+    private static final Interpolator sHandleFadeInterpolator = new Interpolator() {
+        public float getInterpolation(float t) {
+            return t * t;
+        }
+    };
+
+    private final Runnable mEndScrollRunnable = new Runnable () {
+        public void run() {
+            completeChallengeScroll();
+        }
+    };
+
+    /**
+     * Listener interface that reports changes in scroll state of the challenge area.
+     */
+    public interface OnChallengeScrolledListener {
+        /**
+         * The scroll state itself changed.
+         *
+         * <p>scrollState will be one of the following:</p>
+         *
+         * <ul>
+         * <li><code>SCROLL_STATE_IDLE</code> - The challenge area is stationary.</li>
+         * <li><code>SCROLL_STATE_DRAGGING</code> - The user is actively dragging
+         * the challenge area.</li>
+         * <li><code>SCROLL_STATE_SETTLING</code> - The challenge area is animating
+         * into place.</li>
+         * </ul>
+         *
+         * <p>Do not perform expensive operations (e.g. layout)
+         * while the scroll state is not <code>SCROLL_STATE_IDLE</code>.</p>
+         *
+         * @param scrollState The new scroll state of the challenge area.
+         */
+        public void onScrollStateChanged(int scrollState);
+
+        /**
+         * The precise position of the challenge area has changed.
+         *
+         * <p>NOTE: It is NOT safe to modify layout or call any View methods that may
+         * result in a requestLayout anywhere in your view hierarchy as a result of this call.
+         * It may be called during drawing.</p>
+         *
+         * @param scrollPosition New relative position of the challenge area.
+         *                       1.f = fully visible/ready to be interacted with.
+         *                       0.f = fully invisible/inaccessible to the user.
+         * @param challengeTop Position of the top edge of the challenge view in px in the
+         *                     SlidingChallengeLayout's coordinate system.
+         */
+        public void onScrollPositionChanged(float scrollPosition, int challengeTop);
+    }
+
+    public SlidingChallengeLayout(Context context) {
+        this(context, null);
+    }
+
+    public SlidingChallengeLayout(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public SlidingChallengeLayout(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+
+        final TypedArray a = context.obtainStyledAttributes(attrs,
+                R.styleable.SlidingChallengeLayout, defStyle, 0);
+        setDragHandleDrawable(a.getDrawable(R.styleable.SlidingChallengeLayout_dragHandle));
+
+        a.recycle();
+
+        mScroller = new Scroller(context, sMotionInterpolator);
+
+        final ViewConfiguration vc = ViewConfiguration.get(context);
+        mMinVelocity = vc.getScaledMinimumFlingVelocity();
+        mMaxVelocity = vc.getScaledMaximumFlingVelocity();
+
+        setWillNotDraw(false);
+    }
+
+    public void setDragHandleDrawable(Drawable d) {
+        if (d != null) {
+            mDragHandleSize = d.getIntrinsicHeight();
+        }
+        if (mDragHandleSize == 0 || d == null) {
+            final float density = getResources().getDisplayMetrics().density;
+            mDragHandleSize = (int) (DRAG_HANDLE_DEFAULT_SIZE * density + 0.5f);
+        }
+        mHandleDrawable = d;
+    }
+
+    private void sendInitialListenerUpdates() {
+        if (mListener != null) {
+            int challengeTop = mChallengeView != null ? mChallengeView.getTop() : 0;
+            mListener.onScrollPositionChanged(mChallengeOffset, challengeTop);
+            mListener.onScrollStateChanged(mScrollState);
+        }
+    }
+
+    public void setOnChallengeScrolledListener(OnChallengeScrolledListener listener) {
+        mListener = listener;
+        if (mHasLayout) {
+            sendInitialListenerUpdates();
+        }
+    }
+
+    @Override
+    public void onAttachedToWindow() {
+        super.onAttachedToWindow();
+
+        mHasLayout = false;
+    }
+
+    @Override
+    public void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+
+        removeCallbacks(mEndScrollRunnable);
+        mHasLayout = false;
+    }
+
+    // We want the duration of the page snap animation to be influenced by the distance that
+    // the screen has to travel, however, we don't want this duration to be effected in a
+    // purely linear fashion. Instead, we use this method to moderate the effect that the distance
+    // of travel has on the overall snap duration.
+    float distanceInfluenceForSnapDuration(float f) {
+        f -= 0.5f; // center the values about 0.
+        f *= 0.3f * Math.PI / 2.0f;
+        return (float) Math.sin(f);
+    }
+
+    void setScrollState(int state) {
+        if (mScrollState != state) {
+            mScrollState = state;
+
+            if (mListener != null) {
+                mListener.onScrollStateChanged(state);
+            }
+        }
+    }
+
+    void completeChallengeScroll() {
+        setChallengeShowing(mChallengeOffset != 0);
+        setScrollState(SCROLL_STATE_IDLE);
+    }
+
+    /**
+     * Animate the bottom edge of the challenge view to the given position.
+     *
+     * @param y desired final position for the bottom edge of the challenge view in px
+     * @param velocity velocity in
+     */
+    void animateChallengeTo(int y, int velocity) {
+        if (mChallengeView == null) {
+            // Nothing to do.
+            return;
+        }
+        int sy = mChallengeView.getBottom();
+        int dy = y - sy;
+        if (dy == 0) {
+            completeChallengeScroll();
+            return;
+        }
+
+        setScrollState(SCROLL_STATE_SETTLING);
+
+        final int childHeight = mChallengeView.getHeight();
+        final int halfHeight = childHeight / 2;
+        final float distanceRatio = Math.min(1f, 1.0f * Math.abs(dy) / childHeight);
+        final float distance = halfHeight + halfHeight *
+                distanceInfluenceForSnapDuration(distanceRatio);
+
+        int duration = 0;
+        velocity = Math.abs(velocity);
+        if (velocity > 0) {
+            duration = 4 * Math.round(1000 * Math.abs(distance / velocity));
+        } else {
+            final float childDelta = (float) Math.abs(dy) / childHeight;
+            duration = (int) ((childDelta + 1) * 100);
+        }
+        duration = Math.min(duration, MAX_SETTLE_DURATION);
+
+        mScroller.startScroll(0, sy, 0, dy, duration);
+        postInvalidateOnAnimation();
+    }
+
+    private void setChallengeShowing(boolean showChallenge) {
+        if (mChallengeShowing != showChallenge) {
+            mChallengeShowing = showChallenge;
+            if (mChallengeView != null) {
+                mChallengeView.setVisibility(showChallenge ? VISIBLE : INVISIBLE);
+            }
+        }
+    }
+
+    /**
+     * @return true if the challenge is at all visible.
+     */
+    public boolean isChallengeShowing() {
+        return mChallengeShowing;
+    }
+
+    @Override
+    public void requestDisallowInterceptTouchEvent(boolean allowIntercept) {
+        // We'll intercept whoever we feel like! ...as long as it isn't a challenge view.
+        // If there are one or more pointers in the challenge view before we take over
+        // touch events, onInterceptTouchEvent will set mBlockDrag.
+    }
+
+    @Override
+    public boolean onInterceptTouchEvent(MotionEvent ev) {
+        if (mVelocityTracker == null) {
+            mVelocityTracker = VelocityTracker.obtain();
+        }
+        mVelocityTracker.addMovement(ev);
+
+        final int action = ev.getActionMasked();
+        switch (action) {
+            case MotionEvent.ACTION_CANCEL:
+            case MotionEvent.ACTION_UP:
+                resetTouch();
+                break;
+
+            case MotionEvent.ACTION_MOVE:
+                final int count = ev.getPointerCount();
+                for (int i = 0; i < count; i++) {
+                    final float x = ev.getX(i);
+                    final float y = ev.getY(i);
+
+                    if ((isInDragHandle(x, y) ||
+                            (isInChallengeView(x, y) && mScrollState == SCROLL_STATE_SETTLING)) &&
+                            mActivePointerId == INVALID_POINTER) {
+                        mActivePointerId = ev.getPointerId(i);
+                        mLastTouchY = y;
+                        mDragging = true;
+                    } else if (isInChallengeView(x, y)) {
+                        mBlockDrag = true;
+                    }
+                }
+                break;
+        }
+
+        if (mBlockDrag) {
+            mActivePointerId = INVALID_POINTER;
+            mDragging = false;
+        }
+
+        return mDragging;
+    }
+
+    private void resetTouch() {
+        mVelocityTracker.recycle();
+        mVelocityTracker = null;
+        mActivePointerId = INVALID_POINTER;
+        mDragging = mBlockDrag = false;
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent ev) {
+        if (mVelocityTracker == null) {
+            mVelocityTracker = VelocityTracker.obtain();
+        }
+        mVelocityTracker.addMovement(ev);
+
+        final int action = ev.getActionMasked();
+        switch (action) {
+            case MotionEvent.ACTION_CANCEL:
+                if (mDragging) {
+                    showChallenge(0);
+                }
+                resetTouch();
+                break;
+
+            case MotionEvent.ACTION_POINTER_UP:
+                if (mActivePointerId != ev.getPointerId(ev.getActionIndex())) {
+                    break;
+                }
+            case MotionEvent.ACTION_UP:
+                if (mDragging) {
+                    mVelocityTracker.computeCurrentVelocity(1000, mMaxVelocity);
+                    showChallenge((int) mVelocityTracker.getYVelocity(mActivePointerId));
+                }
+                resetTouch();
+                break;
+
+            case MotionEvent.ACTION_MOVE:
+                if (!mDragging && !mBlockDrag) {
+                    final int count = ev.getPointerCount();
+                    for (int i = 0; i < count; i++) {
+                        final float x = ev.getX(i);
+                        final float y = ev.getY(i);
+
+                        if ((isInDragHandle(x, y) ||
+                                (isInChallengeView(x, y) && mScrollState == SCROLL_STATE_SETTLING))
+                                && mActivePointerId == INVALID_POINTER) {
+                            mActivePointerId = ev.getPointerId(i);
+                            mDragging = true;
+                            break;
+                        }
+                    }
+                }
+                // Not an else; this can be set above.
+                if (mDragging) {
+                    // No-op if already in this state, but set it here in case we arrived
+                    // at this point from either intercept or the above.
+                    setScrollState(SCROLL_STATE_DRAGGING);
+
+                    final int index = ev.findPointerIndex(mActivePointerId);
+                    if (index < 0) {
+                        // Oops, bogus state. We lost some touch events somewhere.
+                        // Just drop it with no velocity and let things settle.
+                        resetTouch();
+                        showChallenge(0);
+                        return true;
+                    }
+                    final float y = ev.getY(index);
+                    final float delta = y - mLastTouchY;
+                    final int idelta = (int) delta;
+                    // Don't lose the rounded component
+                    mLastTouchY = y + delta - idelta;
+
+                    moveChallengeBy(idelta);
+                }
+                break;
+        }
+        return true;
+    }
+
+    private boolean isInChallengeView(float x, float y) {
+        if (mChallengeView == null) return false;
+
+        return x >= mChallengeView.getLeft() && y >= mChallengeView.getTop() &&
+                x < mChallengeView.getRight() && y < mChallengeView.getBottom();
+    }
+
+    private boolean isInDragHandle(float x, float y) {
+        if (mChallengeView == null) return false;
+
+        return x >= 0 && y >= mChallengeView.getTop() && x < getWidth() &&
+                y < mChallengeView.getTop() + mDragHandleSize;
+    }
+
+    @Override
+    protected void onMeasure(int widthSpec, int heightSpec) {
+        if (MeasureSpec.getMode(widthSpec) != MeasureSpec.EXACTLY ||
+                MeasureSpec.getMode(heightSpec) != MeasureSpec.EXACTLY) {
+            throw new IllegalArgumentException(
+                    "SlidingChallengeLayout must be measured with an exact size");
+        }
+
+        final int width = MeasureSpec.getSize(widthSpec);
+        final int height = MeasureSpec.getSize(heightSpec);
+        setMeasuredDimension(width, height);
+
+        // Find one and only one challenge view.
+        final View oldChallengeView = mChallengeView;
+        mChallengeView = null;
+        final int count = getChildCount();
+        for (int i = 0; i < count; i++) {
+            final View child = getChildAt(i);
+            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+
+            if (lp.isChallenge) {
+                if (mChallengeView != null) {
+                    throw new IllegalStateException(
+                            "There may only be one child with layout_isChallenge=\"true\"");
+                }
+                mChallengeView = child;
+                if (mChallengeView != oldChallengeView) {
+                    mChallengeView.setVisibility(mChallengeShowing ? VISIBLE : INVISIBLE);
+                }
+            }
+
+            if (child.getVisibility() == GONE) continue;
+
+            measureChildWithMargins(child, widthSpec, 0, heightSpec, 0);
+        }
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int l, int t, int r, int b) {
+        final int paddingLeft = getPaddingLeft();
+        final int paddingTop = getPaddingTop();
+        final int paddingRight = getPaddingRight();
+        final int paddingBottom = getPaddingBottom();
+        final int width = r - l;
+        final int height = b - t;
+
+        final int count = getChildCount();
+        for (int i = 0; i < count; i++) {
+            final View child = getChildAt(i);
+
+            if (child.getVisibility() == GONE) continue;
+
+            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+
+            if (lp.isChallenge) {
+                // Challenge views pin to the bottom, offset by a portion of their height,
+                // and center horizontally.
+                final int center = (paddingLeft + width - paddingRight) / 2;
+                final int childWidth = child.getMeasuredWidth();
+                final int childHeight = child.getMeasuredHeight();
+                final int left = center - childWidth / 2;
+                final int layoutBottom = height - paddingBottom - lp.bottomMargin;
+                // We use the top of the challenge view to position the handle, so
+                // we never want less than the handle size showing at the bottom.
+                final int bottom = layoutBottom + (int) ((childHeight - mDragHandleSize)
+                        * (1 - mChallengeOffset));
+                float offset = 1.f - (bottom - layoutBottom) / childHeight;
+                child.setAlpha(offset);
+                child.layout(left, bottom - childHeight, left + childWidth, bottom);
+            } else {
+                // Non-challenge views lay out from the upper left, layered.
+                child.layout(paddingLeft + lp.leftMargin,
+                        paddingTop + lp.topMargin,
+                        paddingLeft + child.getMeasuredWidth(),
+                        paddingTop + child.getMeasuredHeight());
+            }
+        }
+
+        if (!mHasLayout) {
+            // We want to trigger the initial listener updates outside of layout pass,
+            // in case the listeners trigger requestLayout().
+            post(new Runnable() {
+                @Override
+                public void run() {
+                    sendInitialListenerUpdates();
+                }
+            });
+        }
+        mHasLayout = true;
+    }
+
+    public void computeScroll() {
+        super.computeScroll();
+
+        if (!mScroller.isFinished()) {
+            if (mChallengeView == null) {
+                // Can't scroll if the view is missing.
+                Log.e(TAG, "Challenge view missing in computeScroll");
+                mScroller.abortAnimation();
+                return;
+            }
+
+            mScroller.computeScrollOffset();
+            moveChallengeTo(mScroller.getCurrY());
+
+            if (mScroller.isFinished()) {
+                post(mEndScrollRunnable);
+            }
+        }
+    }
+
+    @Override
+    public void draw(Canvas c) {
+        super.draw(c);
+        if (mChallengeOffset < 1.f && mChallengeView != null && mHandleDrawable != null) {
+            final int top = mChallengeView.getTop();
+            mHandleDrawable.setBounds(0, top, getWidth(), top + mDragHandleSize);
+            final float alpha = sHandleFadeInterpolator.getInterpolation(1 - mChallengeOffset);
+            mHandleDrawable.setAlpha((int) (alpha * 0xFF));
+            mHandleDrawable.draw(c);
+        }
+    }
+
+    /**
+     * Move the bottom edge of mChallengeView to a new position and notify the listener
+     * if it represents a change in position. Changes made through this method will
+     * be stable across layout passes. If this method is called before first layout of
+     * this SlidingChallengeLayout it will have no effect.
+     *
+     * @param bottom New bottom edge in px in this SlidingChallengeLayout's coordinate system.
+     * @return true if the challenge view was moved
+     */
+    private boolean moveChallengeTo(int bottom) {
+        if (mChallengeView == null || !mHasLayout) {
+            return false;
+        }
+
+        final int bottomMargin = ((LayoutParams) mChallengeView.getLayoutParams()).bottomMargin;
+        final int layoutBottom = getHeight() - getPaddingBottom() - bottomMargin;
+        final int challengeHeight = mChallengeView.getHeight();
+
+        bottom = Math.max(layoutBottom,
+                Math.min(bottom, layoutBottom + challengeHeight - mDragHandleSize));
+
+        float offset = 1.f - (float) (bottom - layoutBottom) / (challengeHeight - mDragHandleSize);
+        mChallengeOffset = offset;
+        if (offset > 0 && !mChallengeShowing) {
+            setChallengeShowing(true);
+        }
+
+        mChallengeView.layout(mChallengeView.getLeft(),
+                bottom - mChallengeView.getHeight(), mChallengeView.getRight(), bottom);
+
+        mChallengeView.setAlpha(offset);
+        if (mListener != null) {
+            mListener.onScrollPositionChanged(offset, mChallengeView.getTop());
+        }
+        postInvalidateOnAnimation();
+        return true;
+    }
+
+    private int getChallengeBottom() {
+        if (mChallengeView == null) return 0;
+
+        return mChallengeView.getBottom();
+    }
+
+    private void moveChallengeBy(int delta) {
+        moveChallengeTo(getChallengeBottom() + delta);
+    }
+
+    /**
+     * Show or hide the challenge view, animating it if necessary.
+     * @param show true to show, false to hide
+     */
+    public void showChallenge(boolean show) {
+        showChallenge(show, 0);
+    }
+
+    private void showChallenge(int velocity) {
+        boolean show = false;
+        if (Math.abs(velocity) > mMinVelocity) {
+            show = velocity < 0;
+        } else {
+            show = mChallengeOffset >= 0.5f;
+        }
+        showChallenge(show, velocity);
+    }
+
+    private void showChallenge(boolean show, int velocity) {
+        if (mChallengeView == null) {
+            setChallengeShowing(false);
+            return;
+        }
+
+        if (mHasLayout) {
+            final int bottomMargin = ((LayoutParams) mChallengeView.getLayoutParams()).bottomMargin;
+            final int layoutBottom = getHeight() - getPaddingBottom() - bottomMargin;
+            animateChallengeTo(show ? layoutBottom :
+                layoutBottom + mChallengeView.getHeight() - mDragHandleSize, velocity);
+        }
+    }
+
+    @Override
+    public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {
+        return new LayoutParams(getContext(), attrs);
+    }
+
+    @Override
+    protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
+        return p instanceof LayoutParams ? new LayoutParams((LayoutParams) p) :
+                p instanceof MarginLayoutParams ? new LayoutParams((MarginLayoutParams) p) :
+                new LayoutParams(p);
+    }
+
+    @Override
+    protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
+        return new LayoutParams();
+    }
+
+    @Override
+    protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
+        return p instanceof LayoutParams;
+    }
+
+    public static class LayoutParams extends MarginLayoutParams {
+        public boolean isChallenge = false;
+
+        public LayoutParams() {
+            this(MATCH_PARENT, WRAP_CONTENT);
+        }
+
+        public LayoutParams(int width, int height) {
+            super(width, height);
+        }
+
+        public LayoutParams(android.view.ViewGroup.LayoutParams source) {
+            super(source);
+        }
+
+        public LayoutParams(MarginLayoutParams source) {
+            super(source);
+        }
+
+        public LayoutParams(LayoutParams source) {
+            super(source);
+
+            isChallenge = source.isChallenge;
+        }
+
+        public LayoutParams(Context c, AttributeSet attrs) {
+            super(c, attrs);
+
+            final TypedArray a = c.obtainStyledAttributes(attrs,
+                    R.styleable.SlidingChallengeLayout_Layout);
+            isChallenge = a.getBoolean(R.styleable.SlidingChallengeLayout_Layout_layout_isChallenge,
+                    false);
+            a.recycle();
+        }
+    }
+}