Merge "Add claifying comment"
diff --git a/java/res/layout-land/setup_steps_screen.xml b/java/res/layout-land/setup_steps_screen.xml
index 0b4a096..cf8c424 100644
--- a/java/res/layout-land/setup_steps_screen.xml
+++ b/java/res/layout-land/setup_steps_screen.xml
@@ -27,7 +27,9 @@
         android:layout_width="0dp"
         android:layout_height="match_parent"
         android:layout_weight="@integer/setup_title_weight_in_screen"
-        android:orientation="vertical">
+        android:orientation="vertical"
+        android:layout_marginEnd="@dimen/setup_title_end_margin"
+        android:layout_marginRight="@dimen/setup_title_end_margin">
         <include layout="@layout/setup_steps_title" />
     </LinearLayout>
     <LinearLayout
diff --git a/java/res/layout-land/setup_welcome_screen.xml b/java/res/layout-land/setup_welcome_screen.xml
index 8b162e2..38aea2c 100644
--- a/java/res/layout-land/setup_welcome_screen.xml
+++ b/java/res/layout-land/setup_welcome_screen.xml
@@ -27,7 +27,9 @@
         android:layout_width="0dp"
         android:layout_height="match_parent"
         android:layout_weight="@integer/setup_title_weight_in_screen"
-        android:orientation="vertical">
+        android:orientation="vertical"
+        android:layout_marginEnd="@dimen/setup_title_end_margin"
+        android:layout_marginRight="@dimen/setup_title_end_margin">
         <include layout="@layout/setup_welcome_title" />
     </LinearLayout>
     <LinearLayout
diff --git a/java/res/layout/setup_steps_cards.xml b/java/res/layout/setup_steps_cards.xml
index 2451731..9b03a3e 100644
--- a/java/res/layout/setup_steps_cards.xml
+++ b/java/res/layout/setup_steps_cards.xml
@@ -23,7 +23,7 @@
         android:id="@+id/setup_step_bullets"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:layout_marginTop="@dimen/setup_step_vertical_padding"
+        android:paddingTop="@dimen/setup_step_vertical_padding"
         android:orientation="horizontal">
         <TextView
             android:id="@+id/setup_step1_bullet"
diff --git a/java/res/layout/setup_welcome_title.xml b/java/res/layout/setup_welcome_title.xml
index 6e6d781..af7053a 100644
--- a/java/res/layout/setup_welcome_title.xml
+++ b/java/res/layout/setup_welcome_title.xml
@@ -27,6 +27,6 @@
     <TextView
         android:id="@+id/setup_welcome_description"
         android:text="@string/setup_welcome_additional_description"
-        android:layout_marginTop="12dp"
+        android:layout_marginTop="@dimen/setup_welcome_description_top_margin"
         style="@style/setupWelcomeDescritpionStyle" />
 </merge>
diff --git a/java/res/layout/setup_welcome_video.xml b/java/res/layout/setup_welcome_video.xml
index 8c04e63..7517732 100644
--- a/java/res/layout/setup_welcome_video.xml
+++ b/java/res/layout/setup_welcome_video.xml
@@ -23,26 +23,29 @@
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:orientation="horizontal"
-        android:paddingTop="@dimen/setup_welcome_video_vertical_margin"
-        android:paddingBottom="@dimen/setup_welcome_video_vertical_margin">
-        <View
-            android:layout_weight="@integer/setup_welcome_video_left_padding_weight_in_screen"
-            android:layout_width="0dp"
-            android:layout_height="0dp" />
-        <VideoView
-            android:id="@+id/setup_welcome_video"
-            android:background="@color/setup_background"
+        android:paddingTop="@dimen/setup_welcome_video_top_padding"
+        android:paddingBottom="@dimen/setup_welcome_video_bottom_padding">
+        <LinearLayout
             android:layout_weight="@integer/setup_welcome_video_weight_in_screen"
             android:layout_width="0dp"
-            android:layout_height="wrap_content" />
-        <ImageView
-            android:id="@+id/setup_welcome_image"
-            android:visibility="gone"
-            android:layout_weight="@integer/setup_welcome_video_weight_in_screen"
-            android:layout_width="0dp"
-            android:layout_height="wrap_content" />
+            android:layout_height="wrap_content"
+            android:orientation="horizontal"
+            android:padding="1dp"
+            android:background="@color/setup_welcome_video_margin_color" >
+            <VideoView
+                android:id="@+id/setup_welcome_video"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:background="@color/setup_background" />
+            <ImageView
+                android:id="@+id/setup_welcome_image"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:adjustViewBounds="true"
+                android:visibility="gone" />
+        </LinearLayout>
         <View
-            android:layout_weight="@integer/setup_welcome_video_right_padding_weight_in_screen"
+            android:layout_weight="@integer/setup_welcome_video_end_padding_weight_in_screen"
             android:layout_width="0dp"
             android:layout_height="0dp" />
     </LinearLayout>
diff --git a/java/res/raw/setup_welcome_image.png b/java/res/raw/setup_welcome_image.png
index 17e3111..2445915 100644
--- a/java/res/raw/setup_welcome_image.png
+++ b/java/res/raw/setup_welcome_image.png
Binary files differ
diff --git a/java/res/raw/setup_welcome_video.mp4 b/java/res/raw/setup_welcome_video.mp4
index 09357d8..8208525 100644
--- a/java/res/raw/setup_welcome_video.mp4
+++ b/java/res/raw/setup_welcome_video.mp4
Binary files differ
diff --git a/java/res/values-h1200dp-port/setup-dimens-large-tablet-port.xml b/java/res/values-h1200dp-port/setup-dimens-large-tablet-port.xml
index ad61c1a..bc7928d 100644
--- a/java/res/values-h1200dp-port/setup-dimens-large-tablet-port.xml
+++ b/java/res/values-h1200dp-port/setup-dimens-large-tablet-port.xml
@@ -17,7 +17,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android">
     <!-- Setup wizard dimensions for large-tablet/portrait. -->
     <dimen name="setup_title_text_size">72sp</dimen>
-    <dimen name="setup_welcome_description_text_size">36sp</dimen>
+    <dimen name="setup_welcome_description_text_size">38sp</dimen>
     <dimen name="setup_step_bullet_text_size">24sp</dimen>
     <dimen name="setup_step_triangle_indicator_height">24dp</dimen>
     <dimen name="setup_step_indicator_height">24dp</dimen>
@@ -33,8 +33,10 @@
     <dimen name="setup_step_horizontal_line_height">2dp</dimen>
     <integer name="setup_title_weight_in_screen">40</integer>
     <integer name="setup_body_weight_in_screen">60</integer>
-    <dimen name="setup_welcome_video_vertical_margin">24dp</dimen>
-    <integer name="setup_welcome_video_weight_in_screen">50</integer>
-    <integer name="setup_welcome_video_left_padding_weight_in_screen">25</integer>
-    <integer name="setup_welcome_video_right_padding_weight_in_screen">25</integer>
+    <dimen name="setup_title_end_margin">24dp</dimen>
+    <dimen name="setup_welcome_description_top_margin">12dp</dimen>
+    <dimen name="setup_welcome_video_top_padding">24dp</dimen>
+    <dimen name="setup_welcome_video_bottom_padding">24dp</dimen>
+    <integer name="setup_welcome_video_weight_in_screen">70</integer>
+    <integer name="setup_welcome_video_end_padding_weight_in_screen">30</integer>
 </resources>
diff --git a/java/res/values-h330dp-land/setup-dimens-large-phone-land.xml b/java/res/values-h330dp-land/setup-dimens-large-phone-land.xml
index 69a8a7a..aebf6d2 100644
--- a/java/res/values-h330dp-land/setup-dimens-large-phone-land.xml
+++ b/java/res/values-h330dp-land/setup-dimens-large-phone-land.xml
@@ -16,13 +16,13 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android">
     <!-- Setup wizard dimensions for large-phone/landscape. -->
-    <dimen name="setup_title_text_size">42sp</dimen>
-    <dimen name="setup_welcome_description_text_size">24sp</dimen>
+    <dimen name="setup_title_text_size">40sp</dimen>
+    <dimen name="setup_welcome_description_text_size">22sp</dimen>
     <dimen name="setup_step_bullet_text_size">22sp</dimen>
     <dimen name="setup_step_triangle_indicator_height">24dp</dimen>
     <dimen name="setup_step_indicator_height">24dp</dimen>
-    <dimen name="setup_step_title_text_size">22sp</dimen>
-    <dimen name="setup_step_instruction_text_size">14sp</dimen>
+    <dimen name="setup_step_title_text_size">20sp</dimen>
+    <dimen name="setup_step_instruction_text_size">16sp</dimen>
     <dimen name="setup_step_action_text_size">18sp</dimen>
     <dimen name="setup_vertical_padding">16dp</dimen>
     <dimen name="setup_horizontal_padding">16dp</dimen>
@@ -33,8 +33,10 @@
     <dimen name="setup_step_horizontal_line_height">2dp</dimen>
     <integer name="setup_title_weight_in_screen">40</integer>
     <integer name="setup_body_weight_in_screen">60</integer>
-    <dimen name="setup_welcome_video_vertical_margin">24dp</dimen>
-    <integer name="setup_welcome_video_weight_in_screen">80</integer>
-    <integer name="setup_welcome_video_left_padding_weight_in_screen">10</integer>
-    <integer name="setup_welcome_video_right_padding_weight_in_screen">10</integer>
+    <dimen name="setup_title_end_margin">24dp</dimen>
+    <dimen name="setup_welcome_description_top_margin">10dp</dimen>
+    <dimen name="setup_welcome_video_top_padding">0dp</dimen>
+    <dimen name="setup_welcome_video_bottom_padding">12dp</dimen>
+    <integer name="setup_welcome_video_weight_in_screen">70</integer>
+    <integer name="setup_welcome_video_end_padding_weight_in_screen">30</integer>
 </resources>
diff --git a/java/res/values-h520dp-land/setup-dimens-small-tablet-land.xml b/java/res/values-h520dp-land/setup-dimens-small-tablet-land.xml
index 6a14d59..aedf79f 100644
--- a/java/res/values-h520dp-land/setup-dimens-small-tablet-land.xml
+++ b/java/res/values-h520dp-land/setup-dimens-small-tablet-land.xml
@@ -16,8 +16,8 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android">
     <!-- Setup wizard dimensions for small-tablet/landscape. -->
-    <dimen name="setup_title_text_size">56sp</dimen>
-    <dimen name="setup_welcome_description_text_size">28sp</dimen>
+    <dimen name="setup_title_text_size">60sp</dimen>
+    <dimen name="setup_welcome_description_text_size">32sp</dimen>
     <dimen name="setup_step_bullet_text_size">24sp</dimen>
     <dimen name="setup_step_triangle_indicator_height">24dp</dimen>
     <dimen name="setup_step_indicator_height">24dp</dimen>
@@ -31,10 +31,12 @@
     <dimen name="setup_step_horizontal_padding_half">12dp</dimen>
     <dimen name="setup_step_vertical_padding">16dp</dimen>
     <dimen name="setup_step_horizontal_line_height">2dp</dimen>
-    <integer name="setup_title_weight_in_screen">40</integer>
-    <integer name="setup_body_weight_in_screen">60</integer>
-    <dimen name="setup_welcome_video_vertical_margin">24dp</dimen>
-    <integer name="setup_welcome_video_weight_in_screen">60</integer>
-    <integer name="setup_welcome_video_left_padding_weight_in_screen">20</integer>
-    <integer name="setup_welcome_video_right_padding_weight_in_screen">20</integer>
+    <integer name="setup_title_weight_in_screen">50</integer>
+    <integer name="setup_body_weight_in_screen">50</integer>
+    <dimen name="setup_title_end_margin">24dp</dimen>
+    <dimen name="setup_welcome_description_top_margin">12dp</dimen>
+    <dimen name="setup_welcome_video_top_padding">0dp</dimen>
+    <dimen name="setup_welcome_video_bottom_padding">24dp</dimen>
+    <integer name="setup_welcome_video_weight_in_screen">80</integer>
+    <integer name="setup_welcome_video_end_padding_weight_in_screen">20</integer>
 </resources>
diff --git a/java/res/values-h540dp-port/setup-dimens-large-phone-port.xml b/java/res/values-h540dp-port/setup-dimens-large-phone-port.xml
index b8dd33d..6d66f46 100644
--- a/java/res/values-h540dp-port/setup-dimens-large-phone-port.xml
+++ b/java/res/values-h540dp-port/setup-dimens-large-phone-port.xml
@@ -16,15 +16,15 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android">
     <!-- Setup wizard dimensions for large-phone/portrait. -->
-    <dimen name="setup_title_text_size">46sp</dimen>
+    <dimen name="setup_title_text_size">48sp</dimen>
     <dimen name="setup_welcome_description_text_size">26sp</dimen>
     <dimen name="setup_step_bullet_text_size">22sp</dimen>
     <dimen name="setup_step_triangle_indicator_height">24dp</dimen>
     <dimen name="setup_step_indicator_height">24dp</dimen>
-    <dimen name="setup_step_title_text_size">22sp</dimen>
-    <dimen name="setup_step_instruction_text_size">14sp</dimen>
+    <dimen name="setup_step_title_text_size">20sp</dimen>
+    <dimen name="setup_step_instruction_text_size">16sp</dimen>
     <dimen name="setup_step_action_text_size">18sp</dimen>
-    <dimen name="setup_vertical_padding">16dp</dimen>
+    <dimen name="setup_vertical_padding">8dp</dimen>
     <dimen name="setup_horizontal_padding">16dp</dimen>
     <dimen name="setup_step_action_height">48dp</dimen>
     <dimen name="setup_step_horizontal_padding">24dp</dimen>
@@ -33,8 +33,10 @@
     <dimen name="setup_step_horizontal_line_height">2dp</dimen>
     <integer name="setup_title_weight_in_screen">40</integer>
     <integer name="setup_body_weight_in_screen">60</integer>
-    <dimen name="setup_welcome_video_vertical_margin">24dp</dimen>
-    <integer name="setup_welcome_video_weight_in_screen">80</integer>
-    <integer name="setup_welcome_video_left_padding_weight_in_screen">10</integer>
-    <integer name="setup_welcome_video_right_padding_weight_in_screen">10</integer>
+    <dimen name="setup_title_end_margin">24dp</dimen>
+    <dimen name="setup_welcome_description_top_margin">6dp</dimen>
+    <dimen name="setup_welcome_video_top_padding">12dp</dimen>
+    <dimen name="setup_welcome_video_bottom_padding">12dp</dimen>
+    <integer name="setup_welcome_video_weight_in_screen">70</integer>
+    <integer name="setup_welcome_video_end_padding_weight_in_screen">30</integer>
 </resources>
diff --git a/java/res/values-h720dp-land/setup-dimens-large-tablet-land.xml b/java/res/values-h720dp-land/setup-dimens-large-tablet-land.xml
index 0004a3c..e22b741 100644
--- a/java/res/values-h720dp-land/setup-dimens-large-tablet-land.xml
+++ b/java/res/values-h720dp-land/setup-dimens-large-tablet-land.xml
@@ -16,8 +16,8 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android">
     <!-- Setup wizard dimensions for large-tablet/landscape. -->
-    <dimen name="setup_title_text_size">58sp</dimen>
-    <dimen name="setup_welcome_description_text_size">28sp</dimen>
+    <dimen name="setup_title_text_size">72sp</dimen>
+    <dimen name="setup_welcome_description_text_size">38sp</dimen>
     <dimen name="setup_step_bullet_text_size">24sp</dimen>
     <dimen name="setup_step_triangle_indicator_height">24dp</dimen>
     <dimen name="setup_step_indicator_height">24dp</dimen>
@@ -25,16 +25,18 @@
     <dimen name="setup_step_instruction_text_size">18sp</dimen>
     <dimen name="setup_step_action_text_size">20sp</dimen>
     <dimen name="setup_vertical_padding">96dp</dimen>
-    <dimen name="setup_horizontal_padding">192dp</dimen>
+    <dimen name="setup_horizontal_padding">160dp</dimen>
     <dimen name="setup_step_action_height">48dp</dimen>
     <dimen name="setup_step_horizontal_padding">24dp</dimen>
     <dimen name="setup_step_horizontal_padding_half">12dp</dimen>
     <dimen name="setup_step_vertical_padding">16dp</dimen>
     <dimen name="setup_step_horizontal_line_height">2dp</dimen>
-    <integer name="setup_title_weight_in_screen">40</integer>
-    <integer name="setup_body_weight_in_screen">60</integer>
-    <dimen name="setup_welcome_video_vertical_margin">24dp</dimen>
-    <integer name="setup_welcome_video_weight_in_screen">50</integer>
-    <integer name="setup_welcome_video_left_padding_weight_in_screen">25</integer>
-    <integer name="setup_welcome_video_right_padding_weight_in_screen">25</integer>
+    <integer name="setup_title_weight_in_screen">50</integer>
+    <integer name="setup_body_weight_in_screen">50</integer>
+    <dimen name="setup_title_end_margin">24dp</dimen>
+    <dimen name="setup_welcome_description_top_margin">12dp</dimen>
+    <dimen name="setup_welcome_video_top_padding">0dp</dimen>
+    <dimen name="setup_welcome_video_bottom_padding">24dp</dimen>
+    <integer name="setup_welcome_video_weight_in_screen">80</integer>
+    <integer name="setup_welcome_video_end_padding_weight_in_screen">20</integer>
 </resources>
diff --git a/java/res/values-h800dp-port/setup-dimens-small-tablet-port.xml b/java/res/values-h800dp-port/setup-dimens-small-tablet-port.xml
index 87c991c..86cf3a0 100644
--- a/java/res/values-h800dp-port/setup-dimens-small-tablet-port.xml
+++ b/java/res/values-h800dp-port/setup-dimens-small-tablet-port.xml
@@ -33,8 +33,10 @@
     <dimen name="setup_step_horizontal_line_height">2dp</dimen>
     <integer name="setup_title_weight_in_screen">40</integer>
     <integer name="setup_body_weight_in_screen">60</integer>
-    <dimen name="setup_welcome_video_vertical_margin">24dp</dimen>
-    <integer name="setup_welcome_video_weight_in_screen">60</integer>
-    <integer name="setup_welcome_video_left_padding_weight_in_screen">20</integer>
-    <integer name="setup_welcome_video_right_padding_weight_in_screen">20</integer>
+    <dimen name="setup_title_end_margin">24dp</dimen>
+    <dimen name="setup_welcome_description_top_margin">12dp</dimen>
+    <dimen name="setup_welcome_video_top_padding">24dp</dimen>
+    <dimen name="setup_welcome_video_bottom_padding">24dp</dimen>
+    <integer name="setup_welcome_video_weight_in_screen">70</integer>
+    <integer name="setup_welcome_video_end_padding_weight_in_screen">30</integer>
 </resources>
diff --git a/java/res/values-land/setup-dimens-small-phone-land.xml b/java/res/values-land/setup-dimens-small-phone-land.xml
index 63f4661..088e656 100644
--- a/java/res/values-land/setup-dimens-small-phone-land.xml
+++ b/java/res/values-land/setup-dimens-small-phone-land.xml
@@ -16,7 +16,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android">
     <!-- Setup wizard dimensions for small-phone/landscape. -->
-    <dimen name="setup_title_text_size">36sp</dimen>
+    <dimen name="setup_title_text_size">32sp</dimen>
     <dimen name="setup_welcome_description_text_size">18sp</dimen>
     <dimen name="setup_step_bullet_text_size">18sp</dimen>
     <dimen name="setup_step_triangle_indicator_height">18dp</dimen>
@@ -24,7 +24,7 @@
     <dimen name="setup_step_title_text_size">18sp</dimen>
     <dimen name="setup_step_instruction_text_size">14sp</dimen>
     <dimen name="setup_step_action_text_size">16sp</dimen>
-    <dimen name="setup_vertical_padding">12dp</dimen>
+    <dimen name="setup_vertical_padding">16dp</dimen>
     <dimen name="setup_horizontal_padding">12dp</dimen>
     <dimen name="setup_step_action_height">42dp</dimen>
     <dimen name="setup_step_horizontal_padding">20dp</dimen>
@@ -33,8 +33,10 @@
     <dimen name="setup_step_horizontal_line_height">2dp</dimen>
     <integer name="setup_title_weight_in_screen">40</integer>
     <integer name="setup_body_weight_in_screen">60</integer>
-    <dimen name="setup_welcome_video_vertical_margin">24dp</dimen>
-    <integer name="setup_welcome_video_weight_in_screen">80</integer>
-    <integer name="setup_welcome_video_left_padding_weight_in_screen">10</integer>
-    <integer name="setup_welcome_video_right_padding_weight_in_screen">10</integer>
+    <dimen name="setup_title_end_margin">12dp</dimen>
+    <dimen name="setup_welcome_description_top_margin">12dp</dimen>
+    <dimen name="setup_welcome_video_top_padding">0dp</dimen>
+    <dimen name="setup_welcome_video_bottom_padding">12dp</dimen>
+    <integer name="setup_welcome_video_weight_in_screen">70</integer>
+    <integer name="setup_welcome_video_end_padding_weight_in_screen">30</integer>
 </resources>
diff --git a/java/res/values-port/setup-dimens-small-phone-port.xml b/java/res/values-port/setup-dimens-small-phone-port.xml
index 34f4d92..8ac72ea 100644
--- a/java/res/values-port/setup-dimens-small-phone-port.xml
+++ b/java/res/values-port/setup-dimens-small-phone-port.xml
@@ -24,7 +24,7 @@
     <dimen name="setup_step_title_text_size">18sp</dimen>
     <dimen name="setup_step_instruction_text_size">14sp</dimen>
     <dimen name="setup_step_action_text_size">16sp</dimen>
-    <dimen name="setup_vertical_padding">12dp</dimen>
+    <dimen name="setup_vertical_padding">2dp</dimen>
     <dimen name="setup_horizontal_padding">12dp</dimen>
     <dimen name="setup_step_action_height">42dp</dimen>
     <dimen name="setup_step_horizontal_padding">20dp</dimen>
@@ -33,8 +33,10 @@
     <dimen name="setup_step_horizontal_line_height">2dp</dimen>
     <integer name="setup_title_weight_in_screen">40</integer>
     <integer name="setup_body_weight_in_screen">60</integer>
-    <dimen name="setup_welcome_video_vertical_margin">16dp</dimen>
-    <integer name="setup_welcome_video_weight_in_screen">80</integer>
-    <integer name="setup_welcome_video_left_padding_weight_in_screen">10</integer>
-    <integer name="setup_welcome_video_right_padding_weight_in_screen">10</integer>
+    <dimen name="setup_title_end_margin">16dp</dimen>
+    <dimen name="setup_welcome_description_top_margin">4dp</dimen>
+    <dimen name="setup_welcome_video_top_padding">12dp</dimen>
+    <dimen name="setup_welcome_video_bottom_padding">12dp</dimen>
+    <integer name="setup_welcome_video_weight_in_screen">70</integer>
+    <integer name="setup_welcome_video_end_padding_weight_in_screen">30</integer>
 </resources>
diff --git a/java/res/values/colors.xml b/java/res/values/colors.xml
index 8a8049f..daa167c 100644
--- a/java/res/values/colors.xml
+++ b/java/res/values/colors.xml
@@ -58,4 +58,5 @@
     <color name="setup_text_dark">#FF707070</color>
     <color name="setup_text_action">@android:color/holo_blue_light</color>
     <color name="setup_step_background">@android:color/background_light</color>
+    <color name="setup_welcome_video_margin_color">#FFCCCCCC</color>
 </resources>
diff --git a/java/res/values/dimens.xml b/java/res/values/dimens.xml
index b6413b3..98ae76c 100644
--- a/java/res/values/dimens.xml
+++ b/java/res/values/dimens.xml
@@ -102,7 +102,7 @@
 
     <!-- Gesture trail parameters -->
     <!-- Minimum distance between gesture trail sampling points. -->
-    <dimen name="gesture_trail_min_sampling_distance">6.4dp</dimen>
+    <dimen name="gesture_trail_min_sampling_distance">9.6dp</dimen>
     <!-- Maximum angular threshold between gesture trails interpolation segments in degree. -->
     <integer name="gesture_trail_max_interpolation_angular_threshold">15</integer>
     <!-- Maximum distance threshold between gesture trails interpolation segments. -->
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardActionListener.java b/java/src/com/android/inputmethod/keyboard/KeyboardActionListener.java
index 60d09d6..9eeee5b 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardActionListener.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardActionListener.java
@@ -27,8 +27,9 @@
      *
      * @param primaryCode the unicode of the key being pressed. If the touch is not on a valid key,
      *            the value will be zero.
+     * @param isSinglePointer true if pressing has occurred while no other key is being pressed.
      */
-    public void onPressKey(int primaryCode);
+    public void onPressKey(int primaryCode, boolean isSinglePointer);
 
     /**
      * Called when the user releases a key. This is sent after the {@link #onCodeInput} is called.
@@ -88,6 +89,11 @@
     public void onCancelInput();
 
     /**
+     * Called when user finished sliding key input.
+     */
+    public void onFinishSlidingInput();
+
+    /**
      * Send a non-"code input" custom request to the listener.
      * @return true if the request has been consumed, false otherwise.
      */
@@ -97,7 +103,7 @@
         public static final Adapter EMPTY_LISTENER = new Adapter();
 
         @Override
-        public void onPressKey(int primaryCode) {}
+        public void onPressKey(int primaryCode, boolean isSinglePointer) {}
         @Override
         public void onReleaseKey(int primaryCode, boolean withSliding) {}
         @Override
@@ -115,6 +121,8 @@
         @Override
         public void onCancelInput() {}
         @Override
+        public void onFinishSlidingInput() {}
+        @Override
         public boolean onCustomRequest(int requestCode) {
             return false;
         }
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
index 39afe90..ad08d64 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
@@ -216,19 +216,19 @@
         mState.onResetKeyboardStateToAlphabet();
     }
 
-    public void onPressKey(final int code) {
+    public void onPressKey(final int code, final boolean isSinglePointer) {
         if (isVibrateAndSoundFeedbackRequired()) {
             mFeedbackManager.hapticAndAudioFeedback(code, mKeyboardView);
         }
-        mState.onPressKey(code, isSinglePointer(), mLatinIME.getCurrentAutoCapsState());
+        mState.onPressKey(code, isSinglePointer, mLatinIME.getCurrentAutoCapsState());
     }
 
     public void onReleaseKey(final int code, final boolean withSliding) {
         mState.onReleaseKey(code, withSliding);
     }
 
-    public void onCancelInput() {
-        mState.onCancelInput(isSinglePointer());
+    public void onFinishSlidingInput() {
+        mState.onFinishSlidingInput();
     }
 
     // Implements {@link KeyboardState.SwitchActions}.
@@ -346,15 +346,11 @@
         return mKeyboardView != null && !mKeyboardView.isInSlidingKeyInput();
     }
 
-    private boolean isSinglePointer() {
-        return mKeyboardView != null && mKeyboardView.getPointerCount() == 1;
-    }
-
     /**
      * Updates state machine to figure out when to automatically switch back to the previous mode.
      */
     public void onCodeInput(final int code) {
-        mState.onCodeInput(code, isSinglePointer(), mLatinIME.getCurrentAutoCapsState());
+        mState.onCodeInput(code, mLatinIME.getCurrentAutoCapsState());
     }
 
     public MainKeyboardView getMainKeyboardView() {
diff --git a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java
index 3201d2e..6c6fc61 100644
--- a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java
@@ -1100,10 +1100,6 @@
         return false;
     }
 
-    public int getPointerCount() {
-        return mOldPointerCount;
-    }
-
     @Override
     public boolean dispatchTouchEvent(MotionEvent event) {
         if (AccessibilityUtils.getInstance().isTouchExplorationEnabled()) {
diff --git a/java/src/com/android/inputmethod/keyboard/PointerTracker.java b/java/src/com/android/inputmethod/keyboard/PointerTracker.java
index a832728..1742393 100644
--- a/java/src/com/android/inputmethod/keyboard/PointerTracker.java
+++ b/java/src/com/android/inputmethod/keyboard/PointerTracker.java
@@ -459,7 +459,7 @@
             return false;
         }
         if (key.isEnabled()) {
-            mListener.onPressKey(key.mCode);
+            mListener.onPressKey(key.mCode, getActivePointerTrackerCount() == 1);
             final boolean keyboardLayoutHasBeenChanged = mKeyboardLayoutHasBeenChanged;
             mKeyboardLayoutHasBeenChanged = false;
             mTimerProxy.startTypingStateTimer(key);
@@ -527,6 +527,13 @@
         }
     }
 
+    private void callListenerOnFinishSlidingInput() {
+        if (DEBUG_LISTENER) {
+            Log.d(TAG, String.format("[%d] onFinishSlidingInput", mPointerId));
+        }
+        mListener.onFinishSlidingInput();
+    }
+
     private void callListenerOnCancelInput() {
         if (DEBUG_LISTENER) {
             Log.d(TAG, String.format("[%d] onCancelInput", mPointerId));
@@ -1036,7 +1043,7 @@
 
     private void processSildeOutFromOldKey(final Key oldKey) {
         setReleasedKeyGraphics(oldKey);
-        callListenerOnRelease(oldKey, oldKey.mCode, true);
+        callListenerOnRelease(oldKey, oldKey.mCode, true /* withSliding */);
         startSlidingKeyInput(oldKey);
         mTimerProxy.cancelKeyTimers();
     }
@@ -1169,6 +1176,7 @@
     private void onUpEventInternal(final int x, final int y, final long eventTime) {
         mTimerProxy.cancelKeyTimers();
         final boolean isInSlidingKeyInput = mIsInSlidingKeyInput;
+        final boolean isInSlidingKeyInputFromModifier = mIsInSlidingKeyInputFromModifier;
         resetSlidingKeyInput();
         mIsDetectingGesture = false;
         final Key currentKey = mCurrentKey;
@@ -1189,7 +1197,7 @@
 
         if (sInGesture) {
             if (currentKey != null) {
-                callListenerOnRelease(currentKey, currentKey.mCode, true);
+                callListenerOnRelease(currentKey, currentKey.mCode, true /* withSliding */);
             }
             mayEndBatchInput(eventTime);
             return;
@@ -1203,6 +1211,9 @@
             return;
         }
         detectAndSendKey(currentKey, mKeyX, mKeyY, eventTime);
+        if (isInSlidingKeyInputFromModifier) {
+            callListenerOnFinishSlidingInput();
+        }
     }
 
     public void onShowMoreKeysPanel(final int translatedX, final int translatedY,
@@ -1328,7 +1339,7 @@
 
         final int code = key.mCode;
         callListenerOnCodeInput(key, code, x, y, eventTime);
-        callListenerOnRelease(key, code, false);
+        callListenerOnRelease(key, code, false /* withSliding */);
     }
 
     private void printTouchEvent(final String title, final int x, final int y,
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java
index 962bde9..6af1bd7 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java
@@ -28,9 +28,9 @@
  * This class contains all keyboard state transition logic.
  *
  * The input events are {@link #onLoadKeyboard()}, {@link #onSaveKeyboardState()},
- * {@link #onPressKey(int, boolean, int)}, {@link #onReleaseKey(int, boolean)},
- * {@link #onCodeInput(int, boolean, int)}, {@link #onCancelInput(boolean)},
- * {@link #onUpdateShiftState(int, int)}, {@link #onLongPressTimeout(int)}.
+ * {@link #onPressKey(int,boolean,int)}, {@link #onReleaseKey(int,boolean)},
+ * {@link #onCodeInput(int,int)}, {@link #onFinishSlidingInput()}, {@link #onCancelInput()},
+ * {@link #onUpdateShiftState(int,int)}, {@link #onLongPressTimeout(int)}.
  *
  * The actions are {@link SwitchActions}'s methods.
  */
@@ -74,6 +74,7 @@
     private static final int SWITCH_STATE_SYMBOL = 2;
     private static final int SWITCH_STATE_MOMENTARY_ALPHA_AND_SYMBOL = 3;
     private static final int SWITCH_STATE_MOMENTARY_SYMBOL_AND_MORE = 4;
+    private static final int SWITCH_STATE_MOMENTARY_ALPHA_SHIFT = 5;
     private int mSwitchState = SWITCH_STATE_ALPHA;
 
     private boolean mIsAlphabetMode;
@@ -525,6 +526,9 @@
             } else if (mAlphabetShiftState.isShiftLockShifted() && withSliding) {
                 // In shift locked state, shift has been pressed and slid out to other key.
                 setShiftLocked(true);
+            } else if (mAlphabetShiftState.isManualShifted() && withSliding) {
+                // Shift has been pressed and slid out to other key.
+                mSwitchState = SWITCH_STATE_MOMENTARY_ALPHA_SHIFT;
             } else if (isShiftLocked && !mAlphabetShiftState.isShiftLockShifted()
                     && (mShiftKeyState.isPressing() || mShiftKeyState.isPressingOnShifted())
                     && !withSliding) {
@@ -554,17 +558,21 @@
         mShiftKeyState.onRelease();
     }
 
-    public void onCancelInput(final boolean isSinglePointer) {
+    public void onFinishSlidingInput() {
         if (DEBUG_EVENT) {
-            Log.d(TAG, "onCancelInput: single=" + isSinglePointer + " " + this);
+            Log.d(TAG, "onFinishSlidingInput: " + this);
         }
         // Switch back to the previous keyboard mode if the user cancels sliding input.
-        if (isSinglePointer) {
-            if (mSwitchState == SWITCH_STATE_MOMENTARY_ALPHA_AND_SYMBOL) {
-                toggleAlphabetAndSymbols();
-            } else if (mSwitchState == SWITCH_STATE_MOMENTARY_SYMBOL_AND_MORE) {
-                toggleShiftInSymbols();
-            }
+        switch (mSwitchState) {
+        case SWITCH_STATE_MOMENTARY_ALPHA_AND_SYMBOL:
+            toggleAlphabetAndSymbols();
+            break;
+        case SWITCH_STATE_MOMENTARY_SYMBOL_AND_MORE:
+            toggleShiftInSymbols();
+            break;
+        case SWITCH_STATE_MOMENTARY_ALPHA_SHIFT:
+            setAlphabetKeyboard();
+            break;
         }
     }
 
@@ -577,10 +585,9 @@
         return c == Constants.CODE_SPACE || c == Constants.CODE_ENTER;
     }
 
-    public void onCodeInput(final int code, final boolean isSinglePointer, final int autoCaps) {
+    public void onCodeInput(final int code, final int autoCaps) {
         if (DEBUG_EVENT) {
             Log.d(TAG, "onCodeInput: code=" + Constants.printableCode(code)
-                    + " single=" + isSinglePointer
                     + " autoCaps=" + autoCaps + " " + this);
         }
 
@@ -593,23 +600,12 @@
                 } else {
                     mSwitchState = SWITCH_STATE_SYMBOL_BEGIN;
                 }
-            } else if (isSinglePointer) {
-                // Switch back to the previous keyboard mode if the user pressed the mode change key
-                // and slid to other key, then released the finger.
-                // If the user cancels the sliding input, switching back to the previous keyboard
-                // mode is handled by {@link #onCancelInput}.
-                toggleAlphabetAndSymbols();
             }
             break;
         case SWITCH_STATE_MOMENTARY_SYMBOL_AND_MORE:
             if (code == Constants.CODE_SHIFT) {
                 // Detected only the shift key has been pressed on symbol layout, and then released.
                 mSwitchState = SWITCH_STATE_SYMBOL_BEGIN;
-            } else if (isSinglePointer) {
-                // Switch back to the previous keyboard mode if the user pressed the shift key on
-                // symbol mode and slid to other key, then released the finger.
-                toggleShiftInSymbols();
-                mSwitchState = SWITCH_STATE_SYMBOL;
             }
             break;
         case SWITCH_STATE_SYMBOL_BEGIN:
@@ -650,6 +646,7 @@
         case SWITCH_STATE_SYMBOL: return "SYMBOL";
         case SWITCH_STATE_MOMENTARY_ALPHA_AND_SYMBOL: return "MOMENTARY-ALPHA-SYMBOL";
         case SWITCH_STATE_MOMENTARY_SYMBOL_AND_MORE: return "MOMENTARY-SYMBOL-MORE";
+        case SWITCH_STATE_MOMENTARY_ALPHA_SHIFT: return "MOMENTARY-ALPHA_SHIFT";
         default: return null;
         }
     }
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index 5dd42bf..347a4c6 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -90,7 +90,7 @@
 /**
  * Input method implementation for Qwerty'ish keyboard.
  */
-public final class LatinIME extends InputMethodService implements KeyboardActionListener,
+public class LatinIME extends InputMethodService implements KeyboardActionListener,
         SuggestionStripView.Listener, TargetApplicationGetter.OnTargetApplicationKnownListener,
         Suggest.SuggestInitializationListener {
     private static final String TAG = LatinIME.class.getSimpleName();
@@ -188,6 +188,8 @@
     // Keeps track of most recently inserted text (multi-character key) for reverting
     private String mEnteredText;
 
+    // TODO: This boolean is persistent state and causes large side effects at unexpected times.
+    // Find a way to remove it for readability.
     private boolean mIsAutoCorrectionIndicatorOn;
 
     private AlertDialog mOptionsDialog;
@@ -902,7 +904,12 @@
         // we know for sure the cursor moved while we were composing and we should reset
         // the state.
         final boolean noComposingSpan = composingSpanStart == -1 && composingSpanEnd == -1;
-        if (!mExpectingUpdateSelection
+        // If the keyboard is not visible, we don't need to do all the housekeeping work, as it
+        // will be reset when the keyboard shows up anyway.
+        // TODO: revisit this when LatinIME supports hardware keyboards.
+        // NOTE: the test harness subclasses LatinIME and overrides isInputViewShown().
+        // TODO: find a better way to simulate actual execution.
+        if (isInputViewShown() && !mExpectingUpdateSelection
                 && !mConnection.isBelatedExpectedUpdate(oldSelStart, newSelStart)) {
             // TAKE CARE: there is a race condition when we enter this test even when the user
             // did not explicitly move the cursor. This happens when typing fast, where two keys
@@ -1752,9 +1759,16 @@
 
     // Called from PointerTracker through the KeyboardActionListener interface
     @Override
+    public void onFinishSlidingInput() {
+        // User finished sliding input.
+        mKeyboardSwitcher.onFinishSlidingInput();
+    }
+
+    // Called from PointerTracker through the KeyboardActionListener interface
+    @Override
     public void onCancelInput() {
         // User released a finger outside any key
-        mKeyboardSwitcher.onCancelInput();
+        // Nothing to do so far.
     }
 
     @Override
@@ -2102,25 +2116,16 @@
     }
 
     private boolean isSuggestionsStripVisible() {
-        final MainKeyboardView mainKeyboardView = mKeyboardSwitcher.getMainKeyboardView();
-        if (null == mainKeyboardView || !mainKeyboardView.isShown()) {
+        if (mSuggestionStripView == null)
             return false;
-        }
-        if (mSuggestionStripView == null) {
-            return false;
-        }
-        if (mSuggestionStripView.isShowingAddToDictionaryHint()) {
+        if (mSuggestionStripView.isShowingAddToDictionaryHint())
             return true;
-        }
-        if (null == mSettings.getCurrent()) {
+        if (null == mSettings.getCurrent())
             return false;
-        }
-        if (!mSettings.getCurrent().isSuggestionStripVisibleInOrientation(mDisplayOrientation)) {
+        if (!mSettings.getCurrent().isSuggestionStripVisibleInOrientation(mDisplayOrientation))
             return false;
-        }
-        if (mSettings.getCurrent().isApplicationSpecifiedCompletionsOn()) {
+        if (mSettings.getCurrent().isApplicationSpecifiedCompletionsOn())
             return true;
-        }
         return mSettings.getCurrent().isSuggestionsRequested(mDisplayOrientation);
     }
 
@@ -2509,7 +2514,10 @@
 
         // Note that it's very important here that suggestedWords.mWillAutoCorrect is false.
         // We never want to auto-correct on a resumed suggestion. Please refer to the three
-        // places above where suggestedWords is affected.
+        // places above where suggestedWords is affected. We also need to reset
+        // mIsAutoCorrectionIndicatorOn to avoid showSuggestionStrip touching the text to adapt it.
+        // TODO: remove mIsAutoCorrectionIndicator on (see comment on definition)
+        mIsAutoCorrectionIndicatorOn = false;
         showSuggestionStrip(suggestedWords, typedWord);
     }
 
@@ -2621,8 +2629,8 @@
     // Callback called by PointerTracker through the KeyboardActionListener. This is called when a
     // key is depressed; release matching call is onReleaseKey below.
     @Override
-    public void onPressKey(final int primaryCode) {
-        mKeyboardSwitcher.onPressKey(primaryCode);
+    public void onPressKey(final int primaryCode, final boolean isSinglePointer) {
+        mKeyboardSwitcher.onPressKey(primaryCode, isSinglePointer);
     }
 
     // Callback by PointerTracker through the KeyboardActionListener. This is called when a key
diff --git a/java/src/com/android/inputmethod/latin/setup/SetupWizardActivity.java b/java/src/com/android/inputmethod/latin/setup/SetupWizardActivity.java
index 3406ecf..78a6478 100644
--- a/java/src/com/android/inputmethod/latin/setup/SetupWizardActivity.java
+++ b/java/src/com/android/inputmethod/latin/setup/SetupWizardActivity.java
@@ -46,11 +46,14 @@
 public final class SetupWizardActivity extends Activity implements View.OnClickListener {
     static final String TAG = SetupWizardActivity.class.getSimpleName();
 
+    private static final boolean ENABLE_WELCOME_VIDEO = true;
+
     private View mSetupWizard;
     private View mWelcomeScreen;
     private View mSetupScreen;
     private Uri mWelcomeVideoUri;
     private VideoView mWelcomeVideoView;
+    private ImageView mWelcomeImageView;
     private View mActionStart;
     private View mActionNext;
     private TextView mStep1Bullet;
@@ -58,6 +61,7 @@
     private SetupStepGroup mSetupStepGroup;
     private static final String STATE_STEP = "step";
     private int mStepNumber;
+    private boolean mNeedsToAdjustStepNumberToSystemState;
     private static final int STEP_WELCOME = 0;
     private static final int STEP_1 = 1;
     private static final int STEP_2 = 2;
@@ -156,9 +160,7 @@
         step2.setAction(new Runnable() {
             @Override
             public void run() {
-                // Invoke input method picker.
-                RichInputMethodManager.getInstance().getInputMethodManager()
-                        .showInputMethodPicker();
+                invokeInputMethodPicker();
             }
         });
         mSetupStepGroup.addStep(step2);
@@ -191,18 +193,16 @@
                 mp.setLooping(true);
             }
         });
-        final ImageView welcomeImageView = (ImageView)findViewById(R.id.setup_welcome_image);
         welcomeVideoView.setOnErrorListener(new MediaPlayer.OnErrorListener() {
             @Override
             public boolean onError(final MediaPlayer mp, final int what, final int extra) {
                 Log.e(TAG, "Playing welcome video causes error: what=" + what + " extra=" + extra);
-                welcomeVideoView.setVisibility(View.GONE);
-                welcomeImageView.setImageResource(R.raw.setup_welcome_image);
-                welcomeImageView.setVisibility(View.VISIBLE);
+                hideWelcomeVideoAndShowWelcomeImage();
                 return true;
             }
         });
         mWelcomeVideoView = welcomeVideoView;
+        mWelcomeImageView = (ImageView)findViewById(R.id.setup_welcome_image);
 
         mActionStart = findViewById(R.id.setup_start_label);
         mActionStart.setOnClickListener(this);
@@ -244,6 +244,7 @@
                 | Intent.FLAG_ACTIVITY_SINGLE_TOP
                 | Intent.FLAG_ACTIVITY_CLEAR_TOP);
         startActivity(intent);
+        mNeedsToAdjustStepNumberToSystemState = true;
     }
 
     private void invokeSettingsOfThisIme() {
@@ -259,6 +260,14 @@
         intent.setAction(Settings.ACTION_INPUT_METHOD_SETTINGS);
         intent.addCategory(Intent.CATEGORY_DEFAULT);
         startActivity(intent);
+        mNeedsToAdjustStepNumberToSystemState = true;
+    }
+
+    void invokeInputMethodPicker() {
+        // Invoke input method picker.
+        RichInputMethodManager.getInstance().getInputMethodManager()
+                .showInputMethodPicker();
+        mNeedsToAdjustStepNumberToSystemState = true;
     }
 
     void invokeSubtypeEnablerOfThisIme() {
@@ -312,6 +321,9 @@
     @Override
     protected void onRestart() {
         super.onRestart();
+        // Probably the setup wizard has been invoked from "Recent" menu. The setup step number
+        // needs to be adjusted to system state, because the state (IME is enabled and/or current)
+        // may have been changed.
         if (isInSetupSteps(mStepNumber)) {
             mStepNumber = determineSetupStepNumber();
         }
@@ -344,21 +356,34 @@
         super.onBackPressed();
     }
 
-    private static void hideAndStopVideo(final VideoView videoView) {
-        videoView.stopPlayback();
-        videoView.setVisibility(View.INVISIBLE);
+    void hideWelcomeVideoAndShowWelcomeImage() {
+        mWelcomeVideoView.setVisibility(View.GONE);
+        mWelcomeImageView.setImageResource(R.raw.setup_welcome_image);
+        mWelcomeImageView.setVisibility(View.VISIBLE);
+    }
+
+    private void showAndStartWelcomeVideo() {
+        mWelcomeVideoView.setVisibility(View.VISIBLE);
+        mWelcomeVideoView.setVideoURI(mWelcomeVideoUri);
+        mWelcomeVideoView.start();
+    }
+
+    private void hideAndStopWelcomeVideo() {
+        mWelcomeVideoView.stopPlayback();
+        mWelcomeVideoView.setVisibility(View.GONE);
     }
 
     @Override
     protected void onPause() {
-        hideAndStopVideo(mWelcomeVideoView);
+        hideAndStopWelcomeVideo();
         super.onPause();
     }
 
     @Override
     public void onWindowFocusChanged(final boolean hasFocus) {
         super.onWindowFocusChanged(hasFocus);
-        if (hasFocus && isInSetupSteps(mStepNumber)) {
+        if (hasFocus && mNeedsToAdjustStepNumberToSystemState) {
+            mNeedsToAdjustStepNumberToSystemState = false;
             mStepNumber = determineSetupStepNumber();
             updateSetupStepView();
         }
@@ -370,12 +395,14 @@
         mWelcomeScreen.setVisibility(welcomeScreen ? View.VISIBLE : View.GONE);
         mSetupScreen.setVisibility(welcomeScreen ? View.GONE : View.VISIBLE);
         if (welcomeScreen) {
-            mWelcomeVideoView.setVisibility(View.VISIBLE);
-            mWelcomeVideoView.setVideoURI(mWelcomeVideoUri);
-            mWelcomeVideoView.start();
+            if (ENABLE_WELCOME_VIDEO) {
+                showAndStartWelcomeVideo();
+            } else {
+                hideWelcomeVideoAndShowWelcomeImage();
+            }
             return;
         }
-        hideAndStopVideo(mWelcomeVideoView);
+        hideAndStopWelcomeVideo();
         final boolean isStepActionAlreadyDone = mStepNumber < determineSetupStepNumber();
         mSetupStepGroup.enableStep(mStepNumber, isStepActionAlreadyDone);
         mActionNext.setVisibility(isStepActionAlreadyDone ? View.VISIBLE : View.GONE);
diff --git a/java/src/com/android/inputmethod/research/ResearchLogger.java b/java/src/com/android/inputmethod/research/ResearchLogger.java
index b3c0faf..8b8ea21 100644
--- a/java/src/com/android/inputmethod/research/ResearchLogger.java
+++ b/java/src/com/android/inputmethod/research/ResearchLogger.java
@@ -156,11 +156,6 @@
     // LogUnits are queued in the LogBuffers and published to the ResearchLogs when words are
     // complete.
     /* package for test */ MainLogBuffer mMainLogBuffer; // always non-null after init() is called
-    // TODO: Remove the feedback log.  The feedback log continuously captured user data in case the
-    // user wanted to submit it.  We now use the mUserRecordingLogBuffer to allow the user to
-    // explicitly reproduce a problem.
-    private ResearchLog mFeedbackLog;
-    private LogBuffer mFeedbackLogBuffer;
     /* package */ ResearchLog mUserRecordingLog;
     /* package */ LogBuffer mUserRecordingLogBuffer;
     private File mUserRecordingFile = null;
@@ -200,15 +195,6 @@
     private long mSavedDownEventTime;
     private Bundle mFeedbackDialogBundle = null;
     private boolean mInFeedbackDialog = false;
-    // The feedback dialog causes stop() to be called for the keyboard connected to the original
-    // window.  This is because the feedback dialog must present its own EditText box that displays
-    // a keyboard.  stop() normally causes mFeedbackLogBuffer, which contains the user's data, to be
-    // cleared, and causes mFeedbackLog, which is ready to collect information in case the user
-    // wants to upload, to be closed.  This is good because we don't need to log information about
-    // what the user is typing in the feedback dialog, but bad because this data must be uploaded.
-    // Here we save the LogBuffer and Log so the feedback dialog can later access their data.
-    private LogBuffer mSavedFeedbackLogBuffer;
-    private ResearchLog mSavedFeedbackLog;
     private Handler mUserRecordingTimeoutHandler;
     private static final long USER_RECORDING_TIMEOUT_MS = 30L * DateUtils.SECOND_IN_MILLIS;
 
@@ -280,10 +266,6 @@
                 publishLogUnits(logUnits, mMainResearchLog, canIncludePrivateData);
             }
         };
-
-        mFeedbackLog = new ResearchLog(mResearchLogDirectory.getLogFilePath(
-                System.currentTimeMillis(), System.nanoTime()), mLatinIME);
-        mFeedbackLogBuffer = new FixedLogBuffer(FEEDBACK_WORD_BUFFER_SIZE);
     }
 
     private void cleanLogDirectoryIfNeeded(final ResearchLogDirectory researchLogDirectory,
@@ -436,7 +418,6 @@
             Log.w(TAG, "IOException when publishing LogBuffer", e);
         }
         mMainResearchLog.blockingClose(RESEARCHLOG_CLOSE_TIMEOUT_IN_MS);
-        mFeedbackLog.blockingClose(RESEARCHLOG_CLOSE_TIMEOUT_IN_MS);
 
         resetLogBuffers();
     }
@@ -447,8 +428,6 @@
         }
         mMainLogBuffer.clear();
         mMainResearchLog.blockingAbort(RESEARCHLOG_ABORT_TIMEOUT_IN_MS);
-        mFeedbackLogBuffer.clear();
-        mFeedbackLog.blockingAbort(RESEARCHLOG_ABORT_TIMEOUT_IN_MS);
 
         resetLogBuffers();
     }
@@ -482,12 +461,6 @@
             saveRecording();
         }
         mInFeedbackDialog = true;
-        mSavedFeedbackLogBuffer = mFeedbackLogBuffer;
-        mSavedFeedbackLog = mFeedbackLog;
-        // Set the non-saved versions to null so that the stop() caused by switching to the
-        // Feedback dialog will not close them.
-        mFeedbackLogBuffer = null;
-        mFeedbackLog = null;
 
         final Intent intent = new Intent();
         intent.setClass(mLatinIME, FeedbackActivity.class);
@@ -645,12 +618,6 @@
             new LogStatement("UserFeedback", false, false, "contents", "accountName", "recording");
     public void sendFeedback(final String feedbackContents, final boolean includeHistory,
             final boolean isIncludingAccountName, final boolean isIncludingRecording) {
-        if (mSavedFeedbackLogBuffer == null) {
-            return;
-        }
-        if (!includeHistory) {
-            mSavedFeedbackLogBuffer.clear();
-        }
         String recording = "";
         if (isIncludingRecording) {
             // Try to read recording from recently written json file
@@ -682,9 +649,13 @@
         final String accountName = isIncludingAccountName ? getAccountName() : "";
         feedbackLogUnit.addLogStatement(LOGSTATEMENT_FEEDBACK, SystemClock.uptimeMillis(),
                 feedbackContents, accountName, recording);
-        mFeedbackLogBuffer.shiftIn(feedbackLogUnit);
-        publishLogBuffer(mFeedbackLogBuffer, mSavedFeedbackLog, true /* isIncludingPrivateData */);
-        mSavedFeedbackLog.blockingClose(RESEARCHLOG_CLOSE_TIMEOUT_IN_MS);
+
+        final ResearchLog feedbackLog = new ResearchLog(mResearchLogDirectory.getLogFilePath(
+                System.currentTimeMillis(), System.nanoTime()), mLatinIME);
+        final LogBuffer feedbackLogBuffer = new LogBuffer();
+        feedbackLogBuffer.shiftIn(feedbackLogUnit);
+        publishLogBuffer(feedbackLogBuffer, feedbackLog, true /* isIncludingPrivateData */);
+        feedbackLog.blockingClose(RESEARCHLOG_CLOSE_TIMEOUT_IN_MS);
         uploadNow();
 
         if (isIncludingRecording && DEBUG_REPLAY_AFTER_FEEDBACK) {
@@ -836,9 +807,6 @@
         }
         if (!mCurrentLogUnit.isEmpty()) {
             mMainLogBuffer.shiftIn(mCurrentLogUnit);
-            if (mFeedbackLogBuffer != null) {
-                mFeedbackLogBuffer.shiftIn(mCurrentLogUnit);
-            }
             if (mUserRecordingLogBuffer != null) {
                 mUserRecordingLogBuffer.shiftIn(mCurrentLogUnit);
             }
@@ -884,9 +852,6 @@
         } else {
             mCurrentLogUnit = oldLogUnit;
         }
-        if (mFeedbackLogBuffer != null) {
-            mFeedbackLogBuffer.unshiftIn();
-        }
         enqueueEvent(LOGSTATEMENT_UNCOMMIT_CURRENT_LOGUNIT);
         if (DEBUG) {
             Log.d(TAG, "uncommitCurrentLogUnit (dump=" + dumpCurrentLogUnit + ") back to "
diff --git a/java/src/com/android/inputmethod/research/Uploader.java b/java/src/com/android/inputmethod/research/Uploader.java
index ba05ec1..c7ea3e6 100644
--- a/java/src/com/android/inputmethod/research/Uploader.java
+++ b/java/src/com/android/inputmethod/research/Uploader.java
@@ -49,7 +49,7 @@
     private static final boolean DEBUG = false
             && ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS_DEBUG;
     // Set IS_INHIBITING_AUTO_UPLOAD to true for local testing
-    private static final boolean IS_INHIBITING_AUTO_UPLOAD = false
+    private static final boolean IS_INHIBITING_UPLOAD = false
             && ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS_DEBUG;
     private static final int BUF_SIZE = 1024 * 8;
 
@@ -76,7 +76,7 @@
     }
 
     public boolean isPossibleToUpload() {
-        return hasUploadingPermission() && mUrl != null && !IS_INHIBITING_AUTO_UPLOAD;
+        return hasUploadingPermission() && mUrl != null && !IS_INHIBITING_UPLOAD;
     }
 
     private boolean hasUploadingPermission() {
diff --git a/tests/src/com/android/inputmethod/keyboard/internal/KeyboardStateSingleTouchTests.java b/tests/src/com/android/inputmethod/keyboard/internal/KeyboardStateSingleTouchTests.java
index a3f9dbd..d5b9d1d 100644
--- a/tests/src/com/android/inputmethod/keyboard/internal/KeyboardStateSingleTouchTests.java
+++ b/tests/src/com/android/inputmethod/keyboard/internal/KeyboardStateSingleTouchTests.java
@@ -352,30 +352,34 @@
         // Alphabet -> shift key + letter -> alphabet.
         // Press and slide from shift key, enter alphabet shifted.
         pressAndSlideFromKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED);
-        // Enter/release letter key, switch back to alphabet.
-        pressAndReleaseKey('Z', ALPHABET_MANUAL_SHIFTED, ALPHABET_UNSHIFTED);
+        // Enter/release letter keys, switch back to alphabet.
+        pressAndSlideFromKey('A', ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED);
+        stopSlidingOnKey('Z', ALPHABET_MANUAL_SHIFTED, ALPHABET_UNSHIFTED);
 
         // Alphabet -> "?123" key + letter -> alphabet.
         // Press and slide from "123?" key, enter symbols.
         pressAndSlideFromKey(CODE_SYMBOL, SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED);
-        // Enter/release into symbol letter key, switch back to alphabet.
-        pressAndReleaseKey('!', SYMBOLS_UNSHIFTED, ALPHABET_UNSHIFTED);
+        // Enter/release into symbol letter keys, switch back to alphabet.
+        pressAndSlideFromKey('@', SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED);
+        stopSlidingOnKey('!', SYMBOLS_UNSHIFTED, ALPHABET_UNSHIFTED);
 
         // Alphabet shifted -> shift key + letter -> alphabet.
         // Press/release shift key, enter alphabet shifted.
         pressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED);
         // Press and slide from shift key, remain alphabet shifted.
         pressAndSlideFromKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED);
-        // Enter/release letter key, switch back to alphabet (not alphabet shifted).
-        pressAndReleaseKey('Z', ALPHABET_MANUAL_SHIFTED, ALPHABET_UNSHIFTED);
+        // Enter/release letter keys, switch back to alphabet (not alphabet shifted).
+        pressAndSlideFromKey('A', ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED);
+        stopSlidingOnKey('Z', ALPHABET_MANUAL_SHIFTED, ALPHABET_UNSHIFTED);
 
         // Alphabet shifted -> "?123" key + letter -> alphabet.
         // Press/release shift key, enter alphabet shifted.
         pressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED);
         // Press and slide from "123?" key, enter symbols.
         pressAndSlideFromKey(CODE_SYMBOL, SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED);
-        // Enter/release into symbol letter key, switch back to alphabet (not alphabet shifted).
-        pressAndReleaseKey('!', SYMBOLS_UNSHIFTED, ALPHABET_UNSHIFTED);
+        // Enter/release into symbol letter keys, switch back to alphabet (not alphabet shifted).
+        pressAndSlideFromKey('@', SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED);
+        stopSlidingOnKey('!', SYMBOLS_UNSHIFTED, ALPHABET_UNSHIFTED);
 
         // Alphabet shift locked -> shift key + letter -> alphabet shift locked.
         // Long press shift key, enter alphabet shift locked.
@@ -383,14 +387,76 @@
                 ALPHABET_SHIFT_LOCKED);
         // Press and slide from "123?" key, enter symbols.
         pressAndSlideFromKey(CODE_SYMBOL, SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED);
-        // Enter/release into symbol letter key, switch back to alphabet shift locked.
-        pressAndReleaseKey('!', SYMBOLS_UNSHIFTED, ALPHABET_SHIFT_LOCKED);
+        // Enter/release into symbol letter keys, switch back to alphabet shift locked.
+        pressAndSlideFromKey('!', SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED);
+        stopSlidingOnKey('!', SYMBOLS_UNSHIFTED, ALPHABET_SHIFT_LOCKED);
 
         // Alphabet shift locked -> "?123" key + letter -> alphabet shift locked.
         // Press and slide from shift key, enter alphabet shifted.
         pressAndSlideFromKey(CODE_SHIFT, ALPHABET_SHIFT_LOCK_SHIFTED, ALPHABET_SHIFT_LOCKED);
+        // Enter/release letter keys, switch back to shift locked.
+        pressAndSlideFromKey('A', ALPHABET_SHIFT_LOCKED, ALPHABET_SHIFT_LOCKED);
+        stopSlidingOnKey('Z', ALPHABET_SHIFT_LOCKED, ALPHABET_SHIFT_LOCKED);
+    }
+
+    // Cancel sliding input in alphabet.
+    public void testSlidingAlphabetCancel() {
+        // Alphabet -> shift key + letter -> cancel -> alphabet.
+        // Press and slide from shift key, enter alphabet shifted.
+        pressAndSlideFromKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED);
+        // Press and slide from shift key, enter alphabet shifted.
+        pressAndSlideFromKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED);
+        // Enter/release letter key, remains in alphabet shifted.
+        pressAndSlideFromKey('Z', ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED);
+        // Cancel sliding, switch back to alphabet.
+        stopSlidingAndCancel(ALPHABET_UNSHIFTED);
+
+        // Alphabet -> "?123" key + letter -> cancel -> alphabet.
+        // Press and slide from "123?" key, enter symbols.
+        pressAndSlideFromKey(CODE_SYMBOL, SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED);
+        // Enter/release into symbol letter key, remains in symbols.
+        pressAndSlideFromKey('!', SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED);
+        // Cancel sliding, switch back to alphabet.
+        stopSlidingAndCancel(ALPHABET_UNSHIFTED);
+
+        // Alphabet shifted -> shift key + letter -> cancel -> alphabet.
+        // Press/release shift key, enter alphabet shifted.
+        pressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED);
+        // Press and slide from shift key, remain alphabet shifted.
+        pressAndSlideFromKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED);
+        // Enter/release letter key, remains in alphabet shifted.
+        pressAndSlideFromKey('Z', ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED);
+        // Cancel sliding, switch back to alphabet (not alphabet shifted).
+        stopSlidingAndCancel(ALPHABET_UNSHIFTED);
+
+        // Alphabet shifted -> "?123" key + letter -> cancel -> alphabet.
+        // Press/release shift key, enter alphabet shifted.
+        pressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED);
+        // Press and slide from "123?" key, enter symbols.
+        pressAndSlideFromKey(CODE_SYMBOL, SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED);
+        // Enter/release into symbol letter key, remains in symbols.
+        pressAndSlideFromKey('!', SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED);
+        // Cancel sliding, switch back to alphabet (not alphabet shifted).
+        stopSlidingAndCancel(ALPHABET_UNSHIFTED);
+
+        // Alphabet shift locked -> shift key + letter -> cancel -> alphabet shift locked.
+        // Long press shift key, enter alphabet shift locked.
+        longPressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED,
+                ALPHABET_SHIFT_LOCKED);
+        // Press and slide from "123?" key, enter symbols.
+        pressAndSlideFromKey(CODE_SYMBOL, SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED);
+        // Enter/release into symbol letter key, remains in symbols.
+        pressAndSlideFromKey('!', SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED);
+        // Cancel sliding, switch back to alphabet shift locked.
+        stopSlidingAndCancel( ALPHABET_SHIFT_LOCKED);
+
+        // Alphabet shift locked -> "?123" key + letter -> cancel -> alphabet shift locked.
+        // Press and slide from shift key, enter alphabet shifted.
+        pressAndSlideFromKey(CODE_SHIFT, ALPHABET_SHIFT_LOCK_SHIFTED, ALPHABET_SHIFT_LOCKED);
+        // Enter/release letter key, remains in alphabet shift locked.
+        pressAndSlideFromKey('Z', ALPHABET_SHIFT_LOCKED, ALPHABET_SHIFT_LOCKED);
         // Enter/release letter key, switch back to shift locked.
-        pressAndReleaseKey('Z', ALPHABET_SHIFT_LOCKED, ALPHABET_SHIFT_LOCKED);
+        stopSlidingAndCancel(ALPHABET_SHIFT_LOCKED);
     }
 
     // Sliding input in symbols.
@@ -398,16 +464,18 @@
         // Symbols -> "=\<" key + letter -> symbols.
         // Press/release "?123" key, enter into symbols.
         pressAndReleaseKey(CODE_SYMBOL, SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED);
-        // Press and slide from shift key, enter symols shifted.
+        // Press and slide from shift key, enter symbols shifted.
         pressAndSlideFromKey(CODE_SHIFT, SYMBOLS_SHIFTED, SYMBOLS_SHIFTED);
-        // Enter/release symbol shifted letter key, switch back to symbols.
-        pressAndReleaseKey('~', SYMBOLS_SHIFTED, SYMBOLS_UNSHIFTED);
+        // Enter/release symbol shifted letter keys, switch back to symbols.
+        pressAndSlideFromKey('|', SYMBOLS_SHIFTED, SYMBOLS_SHIFTED);
+        stopSlidingOnKey('~', SYMBOLS_SHIFTED, SYMBOLS_UNSHIFTED);
 
         // Symbols -> "ABC" key + letter -> Symbols.
         // Press and slide from "ABC" key, enter alphabet.
         pressAndSlideFromKey(CODE_SYMBOL, ALPHABET_UNSHIFTED, ALPHABET_UNSHIFTED);
-        // Enter/release letter key, switch back to symbols.
-        pressAndReleaseKey('a', ALPHABET_UNSHIFTED, SYMBOLS_UNSHIFTED);
+        // Enter/release letter keys, switch back to symbols.
+        pressAndSlideFromKey('z', ALPHABET_UNSHIFTED, ALPHABET_UNSHIFTED);
+        stopSlidingOnKey('a', ALPHABET_UNSHIFTED, SYMBOLS_UNSHIFTED);
         // Press/release "ABC" key, switch to alphabet.
         pressAndReleaseKey(CODE_SYMBOL, ALPHABET_UNSHIFTED, ALPHABET_UNSHIFTED);
 
@@ -421,8 +489,9 @@
         pressAndReleaseKey(CODE_SYMBOL, SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED);
         // Press and slide from "ABC" key.
         pressAndSlideFromKey(CODE_SYMBOL, ALPHABET_UNSHIFTED, ALPHABET_UNSHIFTED);
-        // Enter/release letter key, switch back to symbols.
-        pressAndReleaseKey('a', ALPHABET_UNSHIFTED, SYMBOLS_UNSHIFTED);
+        // Enter/release letter keys, switch back to symbols.
+        pressAndSlideFromKey('z', ALPHABET_UNSHIFTED, ALPHABET_UNSHIFTED);
+        stopSlidingOnKey('a', ALPHABET_UNSHIFTED, SYMBOLS_UNSHIFTED);
         // Press/release "ABC" key, switch to alphabet (not alphabet shifted).
         pressAndReleaseKey(CODE_SYMBOL, ALPHABET_UNSHIFTED, ALPHABET_UNSHIFTED);
 
@@ -437,8 +506,9 @@
         pressAndReleaseKey(CODE_SYMBOL, SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED);
         // Press and slide from "ABC" key, enter alphabet shift locked.
         pressAndSlideFromKey(CODE_SYMBOL, ALPHABET_SHIFT_LOCKED, ALPHABET_SHIFT_LOCKED);
-        // Enter/release letter key, switch back to symbols.
-        pressAndReleaseKey('A', ALPHABET_SHIFT_LOCKED, SYMBOLS_UNSHIFTED);
+        // Enter/release letter keys, switch back to symbols.
+        pressAndSlideFromKey('Z', ALPHABET_SHIFT_LOCKED, ALPHABET_SHIFT_LOCKED);
+        stopSlidingOnKey('A', ALPHABET_SHIFT_LOCKED, SYMBOLS_UNSHIFTED);
         // Press/release "ABC" key, switch to alphabet shift locked.
         pressAndReleaseKey(CODE_SYMBOL, ALPHABET_SHIFT_LOCKED, ALPHABET_SHIFT_LOCKED);
 
@@ -453,8 +523,85 @@
         pressAndReleaseKey(CODE_SYMBOL, SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED);
         // Press and slide from "=\<" key, enter symbols shifted.
         pressAndSlideFromKey(CODE_SHIFT, SYMBOLS_SHIFTED, SYMBOLS_SHIFTED);
-        // Enter/release symbols shift letter key, switch back to symbols.
-        pressAndReleaseKey('~', SYMBOLS_SHIFTED, SYMBOLS_UNSHIFTED);
+        // Enter/release symbols shift letter keys, switch back to symbols.
+        pressAndSlideFromKey('|', SYMBOLS_SHIFTED, SYMBOLS_SHIFTED);
+        stopSlidingOnKey('~', SYMBOLS_SHIFTED, SYMBOLS_UNSHIFTED);
+        // Press/release "ABC" key, switch to alphabet shift locked.
+        pressAndReleaseKey(CODE_SYMBOL, ALPHABET_SHIFT_LOCKED, ALPHABET_SHIFT_LOCKED);
+    }
+
+    // Cancel sliding input in symbols.
+    public void testSlidingSymbolsCancel() {
+        // Symbols -> "=\<" key + letter -> cancel -> symbols.
+        // Press/release "?123" key, enter into symbols.
+        pressAndReleaseKey(CODE_SYMBOL, SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED);
+        // Press and slide from shift key, enter symbols shifted.
+        pressAndSlideFromKey(CODE_SHIFT, SYMBOLS_SHIFTED, SYMBOLS_SHIFTED);
+        // Enter/release symbol shifted letter key, remains in symbols shifted.
+        pressAndSlideFromKey('|', SYMBOLS_SHIFTED, SYMBOLS_SHIFTED);
+        // Cancel sliding, switch back to symbols.
+        stopSlidingAndCancel(SYMBOLS_UNSHIFTED);
+
+        // Symbols -> "ABC" key + letter -> Symbols.
+        // Press and slide from "ABC" key, enter alphabet.
+        pressAndSlideFromKey(CODE_SYMBOL, ALPHABET_UNSHIFTED, ALPHABET_UNSHIFTED);
+        // Enter/release letter keys, remains in alphabet.
+        pressAndSlideFromKey('z', ALPHABET_UNSHIFTED, ALPHABET_UNSHIFTED);
+        // Cancel sliding, switch back to symbols.
+        stopSlidingAndCancel(SYMBOLS_UNSHIFTED);
+        // Press/release "ABC" key, switch to alphabet.
+        pressAndReleaseKey(CODE_SYMBOL, ALPHABET_UNSHIFTED, ALPHABET_UNSHIFTED);
+
+        // Alphabet shifted -> symbols -> "ABC" key + letter -> symbols ->
+        // alphabet.
+        // Load keyboard
+        loadKeyboard(ALPHABET_UNSHIFTED);
+        // Press/release shift key, enter alphabet shifted.
+        pressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED);
+        // Press/release "?123" key, enter into symbols.
+        pressAndReleaseKey(CODE_SYMBOL, SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED);
+        // Press and slide from "ABC" key.
+        pressAndSlideFromKey(CODE_SYMBOL, ALPHABET_UNSHIFTED, ALPHABET_UNSHIFTED);
+        // Enter/release letter key, remains in alphabet.
+        pressAndSlideFromKey('z', ALPHABET_UNSHIFTED, ALPHABET_UNSHIFTED);
+        // Cancel sliding, switch back to symbols.
+        stopSlidingAndCancel(SYMBOLS_UNSHIFTED);
+        // Press/release "ABC" key, switch to alphabet (not alphabet shifted).
+        pressAndReleaseKey(CODE_SYMBOL, ALPHABET_UNSHIFTED, ALPHABET_UNSHIFTED);
+
+        // Alphabet shift locked -> symbols -> "ABC" key + letter -> symbols ->
+        // alphabet shift locked.
+        // Load keyboard
+        loadKeyboard(ALPHABET_UNSHIFTED);
+        // Long press shift key, enter alphabet shift locked.
+        longPressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED,
+                ALPHABET_SHIFT_LOCKED);
+        // Press/release "?123" key, enter into symbols.
+        pressAndReleaseKey(CODE_SYMBOL, SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED);
+        // Press and slide from "ABC" key, enter alphabet shift locked.
+        pressAndSlideFromKey(CODE_SYMBOL, ALPHABET_SHIFT_LOCKED, ALPHABET_SHIFT_LOCKED);
+        // Enter/release letter key, remains in alphabet shifted.
+        pressAndSlideFromKey('Z', ALPHABET_SHIFT_LOCKED, ALPHABET_SHIFT_LOCKED);
+        // Cancel sliding, switch back to symbols.
+        stopSlidingAndCancel(SYMBOLS_UNSHIFTED);
+        // Press/release "ABC" key, switch to alphabet shift locked.
+        pressAndReleaseKey(CODE_SYMBOL, ALPHABET_SHIFT_LOCKED, ALPHABET_SHIFT_LOCKED);
+
+        // Alphabet shift locked -> symbols -> "=\<" key + letter -> symbols ->
+        // alphabet shift locked.
+        // Load keyboard
+        loadKeyboard(ALPHABET_UNSHIFTED);
+        // Long press shift key, enter alphabet shift locked.
+        longPressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED,
+                ALPHABET_SHIFT_LOCKED);
+        // Press/release "?123" key, enter into symbols.
+        pressAndReleaseKey(CODE_SYMBOL, SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED);
+        // Press and slide from "=\<" key, enter symbols shifted.
+        pressAndSlideFromKey(CODE_SHIFT, SYMBOLS_SHIFTED, SYMBOLS_SHIFTED);
+        // Enter/release symbols shift letter key, remains in symbols shifted.
+        pressAndSlideFromKey('|', SYMBOLS_SHIFTED, SYMBOLS_SHIFTED);
+        // Cancel sliding, switch back to symbols.
+        stopSlidingAndCancel(SYMBOLS_UNSHIFTED);
         // Press/release "ABC" key, switch to alphabet shift locked.
         pressAndReleaseKey(CODE_SYMBOL, ALPHABET_SHIFT_LOCKED, ALPHABET_SHIFT_LOCKED);
     }
@@ -468,14 +615,16 @@
         pressAndReleaseKey(CODE_SHIFT, SYMBOLS_SHIFTED, SYMBOLS_SHIFTED);
         // Press and slide from shift key, enter symbols.
         pressAndSlideFromKey(CODE_SHIFT, SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED);
-        // Enter/release symbol letter key, switch back to symbols shifted.
-        pressAndReleaseKey('1', SYMBOLS_UNSHIFTED, SYMBOLS_SHIFTED);
+        // Enter/release symbol letter keys, switch back to symbols shifted.
+        pressAndSlideFromKey('2', SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED);
+        stopSlidingOnKey('1', SYMBOLS_UNSHIFTED, SYMBOLS_SHIFTED);
 
         // Symbols shifted -> "ABC" key + letter -> symbols shifted.
         // Press and slide from "ABC" key, enter alphabet.
         pressAndSlideFromKey(CODE_SYMBOL, ALPHABET_UNSHIFTED, ALPHABET_UNSHIFTED);
-        // Enter/release letter key, switch back to symbols shifted.
-        pressAndReleaseKey('a', ALPHABET_UNSHIFTED, SYMBOLS_SHIFTED);
+        // Enter/release letter keys, switch back to symbols shifted.
+        pressAndSlideFromKey('z', ALPHABET_UNSHIFTED, ALPHABET_UNSHIFTED);
+        stopSlidingOnKey('a', ALPHABET_UNSHIFTED, SYMBOLS_SHIFTED);
         // Press/release "ABC" key, switch to alphabet.
         pressAndReleaseKey(CODE_SYMBOL, ALPHABET_UNSHIFTED, ALPHABET_UNSHIFTED);
 
@@ -491,8 +640,9 @@
         pressAndReleaseKey(CODE_SHIFT, SYMBOLS_SHIFTED, SYMBOLS_SHIFTED);
         // Press and slide from "ABC" key.
         pressAndSlideFromKey(CODE_SYMBOL, ALPHABET_UNSHIFTED, ALPHABET_UNSHIFTED);
-        // Enter/release letter key, switch back to symbols shifted.
-        pressAndReleaseKey('a', ALPHABET_UNSHIFTED, SYMBOLS_SHIFTED);
+        // Enter/release letter keys, switch back to symbols shifted.
+        pressAndSlideFromKey('z', ALPHABET_UNSHIFTED, ALPHABET_UNSHIFTED);
+        stopSlidingOnKey('a', ALPHABET_UNSHIFTED, SYMBOLS_SHIFTED);
         // Press/release "ABC" key, switch to alphabet (not alphabet shifted).
         pressAndReleaseKey(CODE_SYMBOL, ALPHABET_UNSHIFTED, ALPHABET_UNSHIFTED);
 
@@ -509,8 +659,9 @@
         pressAndReleaseKey(CODE_SHIFT, SYMBOLS_SHIFTED, SYMBOLS_SHIFTED);
         // Press and slide from "ABC" key.
         pressAndSlideFromKey(CODE_SYMBOL, ALPHABET_SHIFT_LOCKED, ALPHABET_SHIFT_LOCKED);
-        // Enter/release letter key, switch back to symbols shifted.
-        pressAndReleaseKey('A', ALPHABET_SHIFT_LOCKED, SYMBOLS_SHIFTED);
+        // Enter/release letter keys, switch back to symbols shifted.
+        pressAndSlideFromKey('Z', ALPHABET_SHIFT_LOCKED, ALPHABET_SHIFT_LOCKED);
+        stopSlidingOnKey('A', ALPHABET_SHIFT_LOCKED, SYMBOLS_SHIFTED);
         // Press/release "ABC" key, switch to alphabet shift locked.
         pressAndReleaseKey(CODE_SYMBOL, ALPHABET_SHIFT_LOCKED, ALPHABET_SHIFT_LOCKED);
 
@@ -527,8 +678,93 @@
         pressAndReleaseKey(CODE_SHIFT, SYMBOLS_SHIFTED, SYMBOLS_SHIFTED);
         // Press and slide from "?123" key.
         pressAndSlideFromKey(CODE_SHIFT, SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED);
-        // Enter/release symbol letter key, switch back to symbols shifted.
-        pressAndReleaseKey('1', SYMBOLS_UNSHIFTED, SYMBOLS_SHIFTED);
+        // Enter/release symbol letter keys, switch back to symbols shifted.
+        pressAndSlideFromKey('2', SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED);
+        stopSlidingOnKey('1', SYMBOLS_UNSHIFTED, SYMBOLS_SHIFTED);
+        // Press/release "ABC" key, switch to alphabet shift locked.
+        pressAndReleaseKey(CODE_SYMBOL, ALPHABET_SHIFT_LOCKED, ALPHABET_SHIFT_LOCKED);
+    }
+
+    // Cancel sliding input in symbols shifted.
+    public void testSlidingSymbolsShiftedCancel() {
+        // Symbols shifted -> "?123" + letter -> symbols shifted.
+        // Press/release "?123" key, enter into symbols.
+        pressAndReleaseKey(CODE_SYMBOL, SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED);
+        // Press/release "=\<" key, enter into symbols shifted.
+        pressAndReleaseKey(CODE_SHIFT, SYMBOLS_SHIFTED, SYMBOLS_SHIFTED);
+        // Press and slide from shift key, enter symbols.
+        pressAndSlideFromKey(CODE_SHIFT, SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED);
+        // Enter/release symbol letter key, remains in symbols.
+        pressAndSlideFromKey('2', SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED);
+        // Cancel sliding, switch back to symbols shifted.
+        stopSlidingAndCancel(SYMBOLS_SHIFTED);
+
+        // Symbols shifted -> "ABC" key + letter -> symbols shifted.
+        // Press and slide from "ABC" key, enter alphabet.
+        pressAndSlideFromKey(CODE_SYMBOL, ALPHABET_UNSHIFTED, ALPHABET_UNSHIFTED);
+        // Enter/release letter key, remains in alphabet.
+        pressAndSlideFromKey('z', ALPHABET_UNSHIFTED, ALPHABET_UNSHIFTED);
+        // Cancel sliding, switch back to symbols shifted.
+        stopSlidingAndCancel(SYMBOLS_SHIFTED);
+        // Press/release "ABC" key, switch to alphabet.
+        pressAndReleaseKey(CODE_SYMBOL, ALPHABET_UNSHIFTED, ALPHABET_UNSHIFTED);
+
+        // Alphabet shifted -> symbols shifted -> "ABC" + letter -> symbols shifted ->
+        // alphabet.
+        // Load keyboard
+        loadKeyboard(ALPHABET_UNSHIFTED);
+        // Press/release shift key, enter alphabet shifted.
+        pressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED);
+        // Press/release "?123" key, enter into symbols.
+        pressAndReleaseKey(CODE_SYMBOL, SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED);
+        // Press/release "=\<" key, enter into symbols shifted.
+        pressAndReleaseKey(CODE_SHIFT, SYMBOLS_SHIFTED, SYMBOLS_SHIFTED);
+        // Press and slide from "ABC" key.
+        pressAndSlideFromKey(CODE_SYMBOL, ALPHABET_UNSHIFTED, ALPHABET_UNSHIFTED);
+        // Enter/release letter key, remains in alphabet.
+        pressAndSlideFromKey('z', ALPHABET_UNSHIFTED, ALPHABET_UNSHIFTED);
+        // Cancel sliding, switch back to symbols shifted.
+        stopSlidingAndCancel(SYMBOLS_SHIFTED);
+        // Press/release "ABC" key, switch to alphabet (not alphabet shifted).
+        pressAndReleaseKey(CODE_SYMBOL, ALPHABET_UNSHIFTED, ALPHABET_UNSHIFTED);
+
+        // Alphabet shift locked -> symbols shifted -> "ABC" + letter -> symbols shifted ->
+        // alphabet shift locked.
+        // Load keyboard
+        loadKeyboard(ALPHABET_UNSHIFTED);
+        // Long press shift key, enter alphabet shift locked.
+        longPressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED,
+                ALPHABET_SHIFT_LOCKED);
+        // Press/release "?123" key, enter into symbols.
+        pressAndReleaseKey(CODE_SYMBOL, SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED);
+        // Press/release "=\<" key, enter into symbols shifted.
+        pressAndReleaseKey(CODE_SHIFT, SYMBOLS_SHIFTED, SYMBOLS_SHIFTED);
+        // Press and slide from "ABC" key.
+        pressAndSlideFromKey(CODE_SYMBOL, ALPHABET_SHIFT_LOCKED, ALPHABET_SHIFT_LOCKED);
+        // Enter/release letter key, remains in alphabet shift locked.
+        pressAndSlideFromKey('Z', ALPHABET_SHIFT_LOCKED, ALPHABET_SHIFT_LOCKED);
+        // Cancel sliding, switch back to symbols shifted.
+        stopSlidingAndCancel(SYMBOLS_SHIFTED);
+        // Press/release "ABC" key, switch to alphabet shift locked.
+        pressAndReleaseKey(CODE_SYMBOL, ALPHABET_SHIFT_LOCKED, ALPHABET_SHIFT_LOCKED);
+
+        // Alphabet shift locked -> symbols shifted -> "?123" + letter -> symbols shifted ->
+        // alphabet shift locked.
+        // Load keyboard
+        loadKeyboard(ALPHABET_UNSHIFTED);
+        // Long press shift key, enter alphabet shift locked.
+        longPressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED,
+                ALPHABET_SHIFT_LOCKED);
+        // Press/release "?123" key, enter into symbols.
+        pressAndReleaseKey(CODE_SYMBOL, SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED);
+        // Press/release "=\<" key, enter into symbols shifted.
+        pressAndReleaseKey(CODE_SHIFT, SYMBOLS_SHIFTED, SYMBOLS_SHIFTED);
+        // Press and slide from "?123" key.
+        pressAndSlideFromKey(CODE_SHIFT, SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED);
+        // Enter/release symbol letter key, remains in symbols.
+        pressAndSlideFromKey('2', SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED);
+        // Cancel sliding, switch back to symbols shifted.
+        stopSlidingAndCancel(SYMBOLS_SHIFTED);
         // Press/release "ABC" key, switch to alphabet shift locked.
         pressAndReleaseKey(CODE_SYMBOL, ALPHABET_SHIFT_LOCKED, ALPHABET_SHIFT_LOCKED);
     }
diff --git a/tests/src/com/android/inputmethod/keyboard/internal/KeyboardStateTestsBase.java b/tests/src/com/android/inputmethod/keyboard/internal/KeyboardStateTestsBase.java
index 5e94aeb..e06ca06 100644
--- a/tests/src/com/android/inputmethod/keyboard/internal/KeyboardStateTestsBase.java
+++ b/tests/src/com/android/inputmethod/keyboard/internal/KeyboardStateTestsBase.java
@@ -71,7 +71,7 @@
     }
 
     public void releaseKey(final int code, final int afterRelease) {
-        mSwitcher.onCodeInput(code, SINGLE);
+        mSwitcher.onCodeInput(code);
         mSwitcher.onReleaseKey(code, NOT_SLIDING);
         assertLayout("afterRelease", afterRelease, mSwitcher.getLayoutId());
     }
@@ -87,7 +87,7 @@
     }
 
     public void chordingReleaseKey(final int code, final int afterRelease) {
-        mSwitcher.onCodeInput(code, MULTI);
+        mSwitcher.onCodeInput(code);
         mSwitcher.onReleaseKey(code, NOT_SLIDING);
         assertLayout("afterRelease", afterRelease, mSwitcher.getLayoutId());
     }
@@ -104,6 +104,19 @@
         assertLayout("afterSlide", afterSlide, mSwitcher.getLayoutId());
     }
 
+    public void stopSlidingOnKey(final int code, final int afterPress, final int afterSlide) {
+        pressKey(code, afterPress);
+        mSwitcher.onCodeInput(code);
+        mSwitcher.onReleaseKey(code, NOT_SLIDING);
+        mSwitcher.onFinishSlidingInput();
+        assertLayout("afterSlide", afterSlide, mSwitcher.getLayoutId());
+    }
+
+    public void stopSlidingAndCancel(final int afterCancelSliding) {
+        mSwitcher.onFinishSlidingInput();
+        assertLayout("afterCancelSliding", afterCancelSliding, mSwitcher.getLayoutId());
+    }
+
     public void longPressKey(final int code, final int afterPress, final int afterLongPress) {
         pressKey(code, afterPress);
         mSwitcher.onLongPressTimeout(code);
diff --git a/tests/src/com/android/inputmethod/keyboard/internal/MockKeyboardSwitcher.java b/tests/src/com/android/inputmethod/keyboard/internal/MockKeyboardSwitcher.java
index 74506d2..2544b6c 100644
--- a/tests/src/com/android/inputmethod/keyboard/internal/MockKeyboardSwitcher.java
+++ b/tests/src/com/android/inputmethod/keyboard/internal/MockKeyboardSwitcher.java
@@ -185,7 +185,7 @@
         }
     }
 
-    public void onCodeInput(final int code, final boolean isSinglePointer) {
+    public void onCodeInput(final int code) {
         if (mAutoCapsMode == MockConstants.CAP_MODE_WORDS) {
             if (Constants.isLetterCode(code)) {
                 mAutoCapsState = (code == MockConstants.CODE_AUTO_CAPS_TRIGGER)
@@ -194,10 +194,10 @@
         } else {
             mAutoCapsState = mAutoCapsMode;
         }
-        mState.onCodeInput(code, isSinglePointer, mAutoCapsState);
+        mState.onCodeInput(code, mAutoCapsState);
     }
 
-    public void onCancelInput(final boolean isSinglePointer) {
-        mState.onCancelInput(isSinglePointer);
+    public void onFinishSlidingInput() {
+        mState.onFinishSlidingInput();
     }
-}
\ No newline at end of file
+}
diff --git a/tests/src/com/android/inputmethod/latin/InputTestsBase.java b/tests/src/com/android/inputmethod/latin/InputTestsBase.java
index 807c9f3..aec4aac 100644
--- a/tests/src/com/android/inputmethod/latin/InputTestsBase.java
+++ b/tests/src/com/android/inputmethod/latin/InputTestsBase.java
@@ -39,7 +39,7 @@
 
 import java.util.Locale;
 
-public class InputTestsBase extends ServiceTestCase<LatinIME> {
+public class InputTestsBase extends ServiceTestCase<LatinIMEForTests> {
 
     private static final String PREF_DEBUG_MODE = "debug_mode";
 
@@ -121,7 +121,7 @@
     }
 
     public InputTestsBase() {
-        super(LatinIME.class);
+        super(LatinIMEForTests.class);
     }
 
     // TODO: Isn't there a way to make this generic somehow? We can take a <T> and return a <T>
diff --git a/tests/src/com/android/inputmethod/latin/LatinIMEForTests.java b/tests/src/com/android/inputmethod/latin/LatinIMEForTests.java
new file mode 100644
index 0000000..e47c557
--- /dev/null
+++ b/tests/src/com/android/inputmethod/latin/LatinIMEForTests.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.latin;
+
+public class LatinIMEForTests extends LatinIME {
+    @Override
+    public boolean isInputViewShown() {
+        return true;
+    }
+}