From 46878544ec894fd3db368e183404a01c3e3ecc92 Mon Sep 17 00:00:00 2001
From: "Tadashi G. Takaoka" <takaoka@google.com>
Date: Thu, 14 Feb 2013 16:46:39 +0900
Subject: [PATCH] Add preliminary setup wizard

Bug: 8159728
Change-Id: I30d9cd637fb1d2e64588550e0aa4387bc1f7e6e5
---
 .../drawable-hdpi/ic_settings_language.png    | Bin 0 -> 986 bytes
 .../drawable-mdpi/ic_settings_language.png    | Bin 0 -> 756 bytes
 .../drawable-xhdpi/ic_settings_language.png   | Bin 0 -> 1267 bytes
 java/res/layout/setup_step.xml                |  58 ++++
 java/res/layout/setup_wizard.xml              |  78 +++++
 java/res/values-sw600dp-land/setup-dimens.xml |  20 ++
 java/res/values-sw768dp-land/setup-dimens.xml |  20 ++
 java/res/values/colors.xml                    |   5 +
 java/res/values/setup-dimens.xml              |  20 ++
 java/res/values/setup-styles.xml              |  45 +++
 java/res/values/strings.xml                   |  25 ++
 .../compat/TextViewCompatUtils.java           |  44 +++
 .../inputmethod/compat/ViewCompatUtils.java   |  68 ++++
 .../latin/setup/SetupActivity.java            | 311 +++++++++++++++++-
 .../latin/setup/SetupStepIndicatorView.java   |  56 ++++
 15 files changed, 745 insertions(+), 5 deletions(-)
 create mode 100644 java/res/drawable-hdpi/ic_settings_language.png
 create mode 100644 java/res/drawable-mdpi/ic_settings_language.png
 create mode 100644 java/res/drawable-xhdpi/ic_settings_language.png
 create mode 100644 java/res/layout/setup_step.xml
 create mode 100644 java/res/layout/setup_wizard.xml
 create mode 100644 java/res/values-sw600dp-land/setup-dimens.xml
 create mode 100644 java/res/values-sw768dp-land/setup-dimens.xml
 create mode 100644 java/res/values/setup-dimens.xml
 create mode 100644 java/res/values/setup-styles.xml
 create mode 100644 java/src/com/android/inputmethod/compat/TextViewCompatUtils.java
 create mode 100644 java/src/com/android/inputmethod/compat/ViewCompatUtils.java
 create mode 100644 java/src/com/android/inputmethod/latin/setup/SetupStepIndicatorView.java

diff --git a/java/res/drawable-hdpi/ic_settings_language.png b/java/res/drawable-hdpi/ic_settings_language.png
new file mode 100644
index 0000000000000000000000000000000000000000..f635b2e7a0b84b83bd1b1e06b4c61fd601706b8c
GIT binary patch
literal 986
zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA0wn)(8}a}trX+877l!}s{b%+Ad7K3vk;OpT
z1B~5HX4`=T%L*LRfizez!?|}o;XrMVJY5_^A`ZWu?z>*ZRithHtNv=|rt+Q@++X-T
z8WId9@{8}9(8_6DE+r%sv!PJ8zL8bsALHExP0|UCh7L(dd)T(S2t{V^QB=Fm;W6Xo
zy7r@A&b&>u+f`k3S0UXj*0l6o^mE(gujVv8|8&NChK$uL-)S2}+h0vqQ+LZdYuUOt
zV9iV4tTf}ANpqC<WL=bUHhQ=5T!X=_r+cP4-g(MvddqcD)#2Erh#i8#ALm#Zl>Ono
zQtZrKI&+CefRF`Ci=U!|VEu|s0f#-(bbMZlJ=AR|iOQE+py<*2-<(Nj(j<okZx&4|
zjnLL)osd|~wYx&V;ymNMN2ibF%-?-ffh~XK)8NXu74hAjj(^t8TIs#=o>bI}ca2M2
z&M|9BeyFUze_OZvK>r^m5s?GFb*ci}&Dri7@T^byvNPgf9(Ti%oFYk$7ZZb-rdRk}
zQ@fJO;PpUDdJTj6Pl1y^db8iwWH3))64zePZxNSS>-wELHEq_kSGmQ_6%Mrz@&wB(
z%CqhUWlA;XOHN?Ut~tmW$5bR&xKh@$+qUCX^7jyToel{ewMTZpw;tNEgk5mQIa#K@
z{7VnRADCUAU7Nwg5!w)(GF2{n&BbI<&qi)pW?R?5kpCZC1&go0-TiXe(&<NCVm^O2
z^z;r4VY>g>eD#4qzR8ytyB}hIqq^yk{hc*ox}JdyaVvc0Ft9O*JejlV#{HX}ODwN{
zP2cxST`bvX(XSJe_r06>?Da0*hHvv<O-eG2o*(&Zfv3uP(dteXFBN4WNmHicOIvrU
zu`^vWGm=@pRfD(sl4W#mIKP`8x5%7l3iiy`Z=9EWpeX;DuRLR)1y7REX0`m#XYxKr
zgkSA`)FmA!_%Zma`s8O49w+yF(`Nkk(TwwW!{Y<hdk)RsbCB;|`X8qV0sr8SZ<?NM
z50T#$n0jgcztyj5-$$-WUq1VOq{`Q6dH1U?FHiW@Dm+27?~~DIIfcHjZt)X)_D3wY
z&pCO>sUf${>F@LY1J6I%Pf-8jsu8>-jNv9Q>8qBwMwFx^mZVxG7o`Fz1|tJQLtO(y
zT_eK~LlY|_Ln}iQT>}d%0|UnIJc%e8a`RI%(<*UmC|I@SE>MFc$cEtjw370~qErUQ
il>DSr1<%~X^wgl##FWaylc_d9MGT&<elF{r5}E-14VmZw

literal 0
HcmV?d00001

diff --git a/java/res/drawable-mdpi/ic_settings_language.png b/java/res/drawable-mdpi/ic_settings_language.png
new file mode 100644
index 0000000000000000000000000000000000000000..f8aca679ba063ecea7374d3951516abf20aa5b29
GIT binary patch
literal 756
zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE0wix1Z>k4UOiAAEE)4(M`_JqL@;D1TB8!2v
z2N=7Z%(epwmK8Xr18D^?ZvQoBE&~JOA5Ry@5Rc<Wr`l(W1d1H3&o_$PBH&^oHtCj=
zlN7f%_g|(uMn`SIH!j}xO)M<j+JcIU9IuE7Z58ZXs$`h7WrM(CjVy;pvufX`Z=8I0
z=3nF0N>BKB4(~2MH>dj9p5F<pm2>QFY&TL_Gp+Sh7Tc1C64SEGR<B|ZIN@gC5z2R0
z%t$Es%!cU^&WSz!a~`rrde}-f?^v*HP4~227uMyu-&?51tH$Ul`ec;~(`1t$t{K}W
zO`p`slA<aqB$?2!xAISC)~Z{(Q(TlH!yo@!^>CItlmCoI3g<agUL96=rnh>d%1uSV
z{#7d@I$v$tDe+3uC1K+7Cn+|MeirbRZrjOcBB5@?UC*wNT=P_~phx+DZrz0M9+BJ=
z8Y=HGF1KXdlU66uevpB22V2f_uHqi%@Rj$MPu(wYb?LTCd9!NnOrIO`RR0O{1tCfE
z%!>~Uc607|ZYX`GXko!K4mMp=E8TbHu~+rq2`}$;{l;H2VI#Z6IkQ<NH;;NIG_7%K
z?_%@(`^33k>|Xb}-v{`!w%k0OAkffSdby#};Lxem)kl(!?|&+@de1|h`H>H8?z2ao
zQZTDonkQi$9=uoM-iJ*Uw<QbDg>L>Qc1z%UwOdrs^*QBtP2b=AGP}IWJ*sqt+yf!u
zsSC9%ts|60zRz7#(6#hkfUNB`-8YkWsXP6=`oDC;pWhd^ef=nHIDfanX89OKV1iIB
zag8WRNi0dVN-jzTQVd20hK9NZhPp<EA%-SaMut{~Cb|X|Rt5%)-+2;IH00)|WTsW(
z)=;o&%Uz%bNstY}`DrEPiAAXljw$&`sS2LCiRr09sfj6-g(p*OfQlGAUHx3vIVCg!
E0M>pkKmY&$

literal 0
HcmV?d00001

diff --git a/java/res/drawable-xhdpi/ic_settings_language.png b/java/res/drawable-xhdpi/ic_settings_language.png
new file mode 100644
index 0000000000000000000000000000000000000000..2c42db3aa571578d2ea3f4ac909d2bc4e15d4aa4
GIT binary patch
literal 1267
zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I0wfs{c7_5;rX+877l!}s{b%+Ad7K3vk;OpT
z1B~5HX4`=T%L*LRfwTh{zxw<mfq{Yfx2KC^NXEUlGkr5+T}6)9r>p57$;##pGFf?d
zho+v0xl+XDOTG&=>n7+ek``a&Ev~fd?V+U)771MN4c_Xz=$eqDl!?%;2~mRfK?@Tc
zmx`88b;-G3ZCo#29(T#?{Uz(~wzGZziQkibcgOOxy?ptzGnE@!b#oFYC*GCkHn_6g
zGsJ4Dw!GTm@2PeA+V9_7x~ji-wXb==uVn>32Iu^k+-y0{i~1QlpZTz2!pSG5OY0K7
z;?!23a5%y3>y@=??S;oz!-6lRD3&VkVozk?6Dq8T>7RaF&~nC-Fck)ap4D%EOD9^i
zowhp7`Q>}E#?)s;Oa92e@LFI$ZN1u7ac-BSUEd$9YrLi0%6#j~j)d!58w~zE@s)dA
zcrQ)#>Q*OPZjOk=Nv;g%3g<2Eypp@g;mC~CiH<V!*pB~@@fIwM=BQwLpR}cuMd?^b
zY-A~$>jNJ91xtz@YEHUl>Bg0Ea9B)Rbbr#6ddsNuoIhEV=6TQYD~x}Ub0Gas^ZD(L
zc8rYiAFF4*VQg#Yc&t86;Xd0>78`@PMrsvPpEDljsEKfod&j`|{HK(nlC#ZmMUQ*-
zCzt*Sv6}9{vMlrAhYt6O3GI@q2^L{9m#MscA<p=4$Du#7&gnn6dDx;=IHB+A9fvc@
z0*2>4825P`**sTu+6`6~rM~w+)xIa6xy>zOuzOkk1Jy^fgboQ>oC~h>db%g(O~d?6
z|27_dUDy3vrv52w5?>?7oCMZ(2LEP9HpwN9%=2?Tn9EPxDixxx(34%`v+<o|qnPh3
zlgx`=8}kq7gbN?_S|P_Qc)q-5_8<MY$DLCcU1W-7j(1p`E1YKNbk%016(h4>5wAbX
zyN3qlao2wf7;7rbK4TnaYr66slY4?<Cg<av#je$FZ=IHSAb3n^;jTM-N)s3^9xzZd
zlwp2p)DzBdc)6{T^ZHdC6>;eeYPrWMjUpE*yUIMsytO6cgIiIs>)chrqQX5NICodh
zTqqqB;GC1(_I>9W<2R?b9`e=r#G~uMWj^<F^7LzKe>W{@{rYC<I#w=UWx?A8d3`6H
zj!I_k-F`#$_mieRWiu|FMGIG`t=ZnqbXGU~Xx*GX+5H8Io<%yJv$Le_KSi%y;-6}`
zLD2D%^{(*mFKs;o+fCO5)+%^bd0TIF|J>!u6JobFRe)oXUiNl@TdTL}y~<PkvSLZ<
zT}9zr>Yi4yZVT=>go*_-ml-e}(AY5dH=_jOyQJ__vx{Tr>KH6uP^KzA=PIM^>Qv85
zi@s$$iK}?VXY7x=BG1J&>tu1G_^b(6Rs}4JR==s2xn0F~%G8&;gbik1m^hDnimc4b
z6KkGimd>;0Gd$Nf&ueR+s9&MdQ-N5P+^UVYN~=#=_1aB+&E0tI>V(<<+K-BD+tBKJ
zyk2u##f?WFzT^VS1Jx4Oh?11Vl2ohYqEsNoU}RuusB2)XYiJf?Xl7+#W@T!iYhZ3=
zV4%6GMHfXwZhlH;S|x4`5#Mbl0yRj2YzWRzD=AMbN@Z|N$xljE@XSq2PYp^<OsOn9
SnQ8-6#Ng@b=d#Wzp$Py)>lH)*

literal 0
HcmV?d00001

diff --git a/java/res/layout/setup_step.xml b/java/res/layout/setup_step.xml
new file mode 100644
index 0000000000..26d7fe7995
--- /dev/null
+++ b/java/res/layout/setup_step.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:orientation="vertical">
+    <TextView
+        android:id="@+id/setup_step_title"
+        style="@style/setupStepTitleStyle"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:paddingTop="16dp"
+        android:paddingBottom="16dp"
+        android:paddingLeft="24dp"
+        android:paddingRight="24dp" />
+    <TextView
+        android:id="@+id/setup_step_instruction"
+        style="@style/setupStepInstructionStyle"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:paddingBottom="16dp"
+        android:paddingLeft="24dp"
+        android:paddingRight="24dp" />
+    <View
+        android:layout_width="match_parent"
+        android:layout_height="2dp" />
+    <TextView
+        android:id="@+id/setup_step_action_label"
+        style="@style/setupStepActionLabelStyle"
+        android:gravity="center_vertical"
+        android:drawablePadding="12dp"
+        android:layout_width="match_parent"
+        android:layout_height="48dp"
+        android:clickable="true"
+        android:focusable="true"
+        android:paddingLeft="12dp"
+        android:paddingStart="12dp"
+        android:paddingRight="24dp"
+        android:paddingEnd="24dp" />
+</LinearLayout>
diff --git a/java/res/layout/setup_wizard.xml b/java/res/layout/setup_wizard.xml
new file mode 100644
index 0000000000..acbbe30b34
--- /dev/null
+++ b/java/res/layout/setup_wizard.xml
@@ -0,0 +1,78 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:fillViewport="true">
+    <RelativeLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:background="@color/setup_background"
+        android:paddingLeft="@dimen/setup_horizontal_padding"
+        android:paddingRight="@dimen/setup_horizontal_padding"
+        android:paddingTop="16dp"
+        android:paddingBottom="16dp">
+        <TextView
+            android:id="@+id/setup_title"
+            style="@style/setupTitleStyle"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_alignParentLeft="true"
+            android:layout_alignParentStart="true"
+            android:layout_alignParentTop="true" />
+        <LinearLayout
+            android:id="@+id/setup_step_bullets"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_below="@id/setup_title"
+            android:paddingTop="16dp"
+            android:orientation="horizontal">
+            <TextView
+                style="@style/setupStepBulletStyle"
+                android:text="@string/setup_step1_bullet" />
+            <TextView
+                style="@style/setupStepBulletStyle"
+                android:text="@string/setup_step2_bullet" />
+            <TextView
+                style="@style/setupStepBulletStyle"
+                android:text="@string/setup_step3_bullet" />
+        </LinearLayout>
+        <com.android.inputmethod.latin.setup.SetupStepIndicatorView
+            android:id="@+id/setup_step_indicator"
+            android:layout_width="match_parent"
+            android:layout_height="24dp"
+            android:layout_below="@id/setup_step_bullets" />
+        <FrameLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_below="@id/setup_step_indicator">
+            <include
+                android:id="@+id/setup_step1"
+                layout="@layout/setup_step" />
+            <include
+                android:id="@+id/setup_step2"
+                layout="@layout/setup_step" />
+            <include
+                android:id="@+id/setup_step3"
+                layout="@layout/setup_step" />
+        </FrameLayout>
+    </RelativeLayout>
+</ScrollView>
diff --git a/java/res/values-sw600dp-land/setup-dimens.xml b/java/res/values-sw600dp-land/setup-dimens.xml
new file mode 100644
index 0000000000..9aea214238
--- /dev/null
+++ b/java/res/values-sw600dp-land/setup-dimens.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android">
+    <dimen name="setup_title_text_size">64sp</dimen>
+    <dimen name="setup_horizontal_padding">96dp</dimen>
+</resources>
diff --git a/java/res/values-sw768dp-land/setup-dimens.xml b/java/res/values-sw768dp-land/setup-dimens.xml
new file mode 100644
index 0000000000..0d2af17e3d
--- /dev/null
+++ b/java/res/values-sw768dp-land/setup-dimens.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android">
+    <dimen name="setup_title_text_size">64sp</dimen>
+    <dimen name="setup_horizontal_padding">192dp</dimen>
+</resources>
diff --git a/java/res/values/colors.xml b/java/res/values/colors.xml
index c0ea321cef..8a8049f1f9 100644
--- a/java/res/values/colors.xml
+++ b/java/res/values/colors.xml
@@ -53,4 +53,9 @@
     <color name="spacebar_text_color_ics">#FFC0C0C0</color>
     <color name="spacebar_text_shadow_color_ics">#80000000</color>
     <color name="typed_word_color_ics">@color/highlight_color_ics</color>
+    <!-- Color resources for setup wizard and tutorial -->
+    <color name="setup_background">#FFEBEBEB</color>
+    <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>
 </resources>
diff --git a/java/res/values/setup-dimens.xml b/java/res/values/setup-dimens.xml
new file mode 100644
index 0000000000..007906dc09
--- /dev/null
+++ b/java/res/values/setup-dimens.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android">
+    <dimen name="setup_title_text_size">46sp</dimen>
+    <dimen name="setup_horizontal_padding">16dp</dimen>
+</resources>
diff --git a/java/res/values/setup-styles.xml b/java/res/values/setup-styles.xml
new file mode 100644
index 0000000000..cfc689a78e
--- /dev/null
+++ b/java/res/values/setup-styles.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android">
+    <style name="setupTitleStyle">
+        <item name="android:textColor">@color/setup_text_dark</item>
+        <item name="android:textSize">@dimen/setup_title_text_size</item>
+    </style>
+    <style name="setupStepBulletStyle">
+        <item name="android:textColor">@color/setup_text_dark</item>
+        <item name="android:textSize">22sp</item>
+        <item name="android:layout_width">0dp</item>
+        <item name="android:layout_weight">1.0</item>
+        <item name="android:layout_height">wrap_content</item>
+        <item name="android:gravity">center_horizontal</item>
+    </style>
+    <style name="setupStepTitleStyle">
+        <item name="android:background">@color/setup_step_background</item>
+        <item name="android:textColor">@color/setup_text_dark</item>
+        <item name="android:textSize">22sp</item>
+    </style>
+    <style name="setupStepInstructionStyle">
+        <item name="android:background">@color/setup_step_background</item>
+        <item name="android:textColor">@color/setup_text_dark</item>
+        <item name="android:textSize">14sp</item>
+    </style>
+    <style name="setupStepActionLabelStyle">
+        <item name="android:background">@color/setup_step_background</item>
+        <item name="android:textColor">@color/setup_text_action</item>
+        <item name="android:textSize">18sp</item>
+    </style>
+</resources>
diff --git a/java/res/values/strings.xml b/java/res/values/strings.xml
index ee79b450e0..f7d34c8e36 100644
--- a/java/res/values/strings.xml
+++ b/java/res/values/strings.xml
@@ -408,4 +408,29 @@
 
     <!-- Title of the button to revert to the default value of the device in the settings dialog [CHAR LIMIT=15] -->
     <string name="button_default">Default</string>
+
+    <!-- Title of the setup wizard. [CHAR LIMT=40] -->
+    <string name="setup_title">"Installing <xliff:g id="application_name">%s</xliff:g>"</string>
+    <!-- Ordinal number of the 1st step in the setup wizard. [CHAR LIMIT=5] -->
+    <string name="setup_step1_bullet">1</string>
+    <!-- Title of the 1st step in the setup wizard. [CHAR LIMIT=64] -->
+    <string name="setup_step1_title">"Enable <xliff:g id="application_name">%s</xliff:g> in settings."</string>
+    <!-- Detailed instruction of the 1st step in the setup wizard. [CHAR LIMIT=80] -->
+    <string name="setup_step1_instruction">"For security, please check \"<xliff:g id="application_name">%s</xliff:g>\""</string>
+    <!-- Ordinal number of the 2nd step in the setup wizard. [CHAR LIMIT=5] -->
+    <string name="setup_step2_bullet">2</string>
+    <!-- Title of the 2nd step in the setup wizard. [CHAR LIMIT=64] -->
+    <string name="setup_step2_title">"Switch to <xliff:g id="application_name">%s</xliff:g>."</string>
+    <!-- Detailed instruction of the 2nd step in the setup wizard. [CHAR LIMIT=80] -->
+    <string name="setup_step2_instruction">"Now that you've enabled <xliff:g id="application_name">%s</xliff:g>, you can switch to it."</string>
+    <!-- Ordinal number of the 3rd step in the setup wizard. [CHAR LIMIT=5] -->
+    <string name="setup_step3_bullet">3</string>
+    <!-- Title of the 3rd step in the setup wizard. [CHAR LIMIT=64] -->
+    <string name="setup_step3_title">"Congratulations, you're all set!"</string>
+    <!-- Detailed instruction of the 3rd step in the setup wizard. [CHAR LIMIT=80] -->
+    <string name="setup_step3_instruction">Configure additional languages</string>
+    <!-- Title of the Language & input settings. This should be aligned with msgid="5292716747264442359" -->
+    <string name="language_settings">Language &amp; input</string>
+    <!-- Title of the Input method picker. This should be aligned with msgid="4653387336791222978" -->
+    <string name="select_input_method">Choose input method</string>
 </resources>
diff --git a/java/src/com/android/inputmethod/compat/TextViewCompatUtils.java b/java/src/com/android/inputmethod/compat/TextViewCompatUtils.java
new file mode 100644
index 0000000000..d4f1ea8301
--- /dev/null
+++ b/java/src/com/android/inputmethod/compat/TextViewCompatUtils.java
@@ -0,0 +1,44 @@
+/*
+ * 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.compat;
+
+import android.graphics.drawable.Drawable;
+import android.widget.TextView;
+
+import java.lang.reflect.Method;
+
+public final class TextViewCompatUtils {
+    // Note that TextView.setCompoundDrawablesRelative(Drawable,Drawable,Drawable,Drawable) has
+    // been introduced in API level 17 (Build.VERSION_CODE.JELLY_BEAN_MR1).
+    private static final Method METHOD_setCompoundDrawablesRelative = CompatUtils.getMethod(
+            TextView.class, "setCompoundDrawablesRelative",
+            Drawable.class, Drawable.class, Drawable.class, Drawable.class);
+
+    private TextViewCompatUtils() {
+        // This utility class is not publicly instantiable.
+    }
+
+    public static void setCompoundDrawablesRelative(final TextView textView, final Drawable start,
+            final Drawable top, final Drawable end, final Drawable bottom) {
+        if (METHOD_setCompoundDrawablesRelative == null) {
+            textView.setCompoundDrawables(start, top, end, bottom);
+            return;
+        }
+        CompatUtils.invoke(textView, null, METHOD_setCompoundDrawablesRelative,
+                start, top, end, bottom);
+    }
+}
diff --git a/java/src/com/android/inputmethod/compat/ViewCompatUtils.java b/java/src/com/android/inputmethod/compat/ViewCompatUtils.java
new file mode 100644
index 0000000000..a8fab8855e
--- /dev/null
+++ b/java/src/com/android/inputmethod/compat/ViewCompatUtils.java
@@ -0,0 +1,68 @@
+/*
+ * 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.compat;
+
+import android.view.View;
+
+import java.lang.reflect.Method;
+
+public final class ViewCompatUtils {
+    // Note that View.LAYOUT_DIRECTION_LTR and View.LAYOUT_DIRECTION_RTL have been introduced in
+    // API level 17 (Build.VERSION_CODE.JELLY_BEAN_MR1).
+    public static final int LAYOUT_DIRECTION_LTR = (Integer)CompatUtils.getFieldValue(null, 0x0,
+            CompatUtils.getField(View.class, "LAYOUT_DIRECTION_LTR"));
+    public static final int LAYOUT_DIRECTION_RTL = (Integer)CompatUtils.getFieldValue(null, 0x1,
+            CompatUtils.getField(View.class, "LAYOUT_DIRECTION_RTL"));
+
+    // Note that View.getPaddingEnd(), View.setPaddingRelative(int,int,int,int), and
+    // View.getLayoutDirection() have been introduced in API level 17
+    // (Build.VERSION_CODE.JELLY_BEAN_MR1).
+    private static final Method METHOD_getPaddingEnd = CompatUtils.getMethod(
+            View.class, "getPaddingEnd");
+    private static final Method METHOD_setPaddingRelative = CompatUtils.getMethod(
+            View.class, "setPaddingRelative",
+            Integer.TYPE, Integer.TYPE, Integer.TYPE, Integer.TYPE);
+    private static final Method METHOD_getLayoutDirection = CompatUtils.getMethod(
+            View.class, "getLayoutDirection");
+
+    private ViewCompatUtils() {
+        // This utility class is not publicly instantiable.
+    }
+
+    public static int getPaddingEnd(final View view) {
+        if (METHOD_getPaddingEnd == null) {
+            return view.getPaddingRight();
+        }
+        return (Integer)CompatUtils.invoke(view, 0, METHOD_getPaddingEnd);
+    }
+
+    public static void setPaddingRelative(final View view, final int start, final int top,
+            final int end, final int bottom) {
+        if (METHOD_setPaddingRelative == null) {
+            view.setPadding(start, top, end, bottom);
+            return;
+        }
+        CompatUtils.invoke(view, null, METHOD_setPaddingRelative, start, top, end, bottom);
+    }
+
+    public static int getLayoutDirection(final View view) {
+        if (METHOD_getLayoutDirection == null) {
+            return LAYOUT_DIRECTION_LTR;
+        }
+        return (Integer)CompatUtils.invoke(view, 0, METHOD_getLayoutDirection);
+    }
+}
diff --git a/java/src/com/android/inputmethod/latin/setup/SetupActivity.java b/java/src/com/android/inputmethod/latin/setup/SetupActivity.java
index fab8945840..c30ecfb16f 100644
--- a/java/src/com/android/inputmethod/latin/setup/SetupActivity.java
+++ b/java/src/com/android/inputmethod/latin/setup/SetupActivity.java
@@ -18,22 +18,323 @@ package com.android.inputmethod.latin.setup;
 
 import android.app.Activity;
 import android.content.Intent;
+import android.content.res.Resources;
+import android.graphics.PorterDuff;
+import android.graphics.drawable.Drawable;
 import android.os.Bundle;
+import android.os.Message;
+import android.provider.Settings;
+import android.view.View;
+import android.view.inputmethod.InputMethodInfo;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.TextView;
 
+import com.android.inputmethod.compat.TextViewCompatUtils;
+import com.android.inputmethod.compat.ViewCompatUtils;
+import com.android.inputmethod.latin.CollectionUtils;
+import com.android.inputmethod.latin.R;
+import com.android.inputmethod.latin.RichInputMethodManager;
 import com.android.inputmethod.latin.SettingsActivity;
+import com.android.inputmethod.latin.StaticInnerHandlerWrapper;
+
+import java.util.HashMap;
 
 public final class SetupActivity extends Activity {
+    private SetupStepIndicatorView mStepIndicatorView;
+    private final SetupStepGroup mSetupSteps = new SetupStepGroup();
+    private static final String STATE_STEP = "step";
+    private int mStepNo;
+    private static final int STEP_1 = 1;
+    private static final int STEP_2 = 2;
+    private static final int STEP_3 = 3;
+
+    private final SettingsPoolingHandler mHandler = new SettingsPoolingHandler(this);
+
+    static final class SettingsPoolingHandler extends StaticInnerHandlerWrapper<SetupActivity> {
+        private static final int MSG_POLLING_IME_SETTINGS = 0;
+        private static final long IME_SETTINGS_POLLING_INTERVAL = 200;
+
+        public SettingsPoolingHandler(final SetupActivity outerInstance) {
+            super(outerInstance);
+        }
+
+        @Override
+        public void handleMessage(final Message msg) {
+            final SetupActivity setupActivity = getOuterInstance();
+            switch (msg.what) {
+            case MSG_POLLING_IME_SETTINGS:
+                if (setupActivity.isMyImeEnabled()) {
+                    setupActivity.invokeSetupWizardOfThisIme();
+                    return;
+                }
+                startPollingImeSettings();
+                break;
+            }
+        }
+
+        public void startPollingImeSettings() {
+            sendMessageDelayed(obtainMessage(MSG_POLLING_IME_SETTINGS),
+                    IME_SETTINGS_POLLING_INTERVAL);
+        }
+
+        public void cancelPollingImeSettings() {
+            removeMessages(MSG_POLLING_IME_SETTINGS);
+        }
+    }
+
     @Override
-    protected void onCreate(Bundle savedInstanceState) {
+    protected void onCreate(final Bundle savedInstanceState) {
+        setTheme(android.R.style.Theme_DeviceDefault_Light_NoActionBar);
         super.onCreate(savedInstanceState);
 
-        // TODO: Implement setup wizard.
+        setContentView(R.layout.setup_wizard);
+
+        RichInputMethodManager.init(this);
+
+        if (savedInstanceState == null) {
+            mStepNo = determineSetupStepNo();
+        } else {
+            mStepNo = savedInstanceState.getInt(STATE_STEP);
+        }
+
+        if (mStepNo == STEP_3) {
+            // This IME already has been enabled and set as current IME.
+            // TODO: Implement tutorial.
+            invokeSettingsOfThisIme();
+            finish();
+            return;
+        }
+
+        // TODO: Use sans-serif-thin font family depending on the system locale white list and
+        // the SDK version.
+        final TextView titleView = (TextView)findViewById(R.id.setup_title);
+        titleView.setText(getString(R.string.setup_title, getString(R.string.english_ime_name)));
+
+        mStepIndicatorView = (SetupStepIndicatorView)findViewById(R.id.setup_step_indicator);
+
+        final SetupStep step1 = new SetupStep(findViewById(R.id.setup_step1),
+                R.string.setup_step1_title, R.string.setup_step1_instruction,
+                R.drawable.ic_settings_language, R.string.language_settings);
+        step1.setAction(new Runnable() {
+            @Override
+            public void run() {
+                invokeLanguageAndInputSettings();
+                mHandler.startPollingImeSettings();
+            }
+        });
+        mSetupSteps.addStep(STEP_1, step1);
+
+        final SetupStep step2 = new SetupStep(findViewById(R.id.setup_step2),
+                R.string.setup_step2_title, R.string.setup_step2_instruction,
+                0 /* actionIcon */, R.string.select_input_method);
+        step2.setAction(new Runnable() {
+            @Override
+            public void run() {
+                // Invoke input method picker.
+                RichInputMethodManager.getInstance().getInputMethodManager()
+                        .showInputMethodPicker();
+            }
+        });
+        mSetupSteps.addStep(STEP_2, step2);
+
+        final SetupStep step3 = new SetupStep(findViewById(R.id.setup_step3),
+                R.string.setup_step3_title, 0 /* instruction */,
+                R.drawable.sym_keyboard_language_switch, R.string.setup_step3_instruction);
+        step3.setAction(new Runnable() {
+            @Override
+            public void run() {
+                invokeSubtypeEnablerOfThisIme();
+            }
+        });
+        mSetupSteps.addStep(STEP_3, step3);
+    }
+
+    private void invokeSetupWizardOfThisIme() {
+        final Intent intent = new Intent();
+        intent.setClass(this, SetupActivity.class);
+        intent.setFlags(Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
+                | Intent.FLAG_ACTIVITY_CLEAR_TOP);
+        startActivity(intent);
+    }
+
+    private void invokeSettingsOfThisIme() {
         final Intent intent = new Intent();
         intent.setClass(this, SettingsActivity.class);
-        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
-                | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
+        intent.setFlags(Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
                 | Intent.FLAG_ACTIVITY_CLEAR_TOP);
         startActivity(intent);
-        finish();
+    }
+
+    private void invokeLanguageAndInputSettings() {
+        final Intent intent = new Intent();
+        intent.setAction(Settings.ACTION_INPUT_METHOD_SETTINGS);
+        intent.addCategory(Intent.CATEGORY_DEFAULT);
+        startActivity(intent);
+    }
+
+    private void invokeSubtypeEnablerOfThisIme() {
+        final InputMethodInfo imi =
+                RichInputMethodManager.getInstance().getInputMethodInfoOfThisIme();
+        final Intent intent = new Intent();
+        intent.setAction(Settings.ACTION_INPUT_METHOD_SUBTYPE_SETTINGS);
+        intent.addCategory(Intent.CATEGORY_DEFAULT);
+        intent.putExtra(Settings.EXTRA_INPUT_METHOD_ID, imi.getId());
+        startActivity(intent);
+    }
+
+    private boolean isMyImeEnabled() {
+        final String packageName = getPackageName();
+        final InputMethodManager imm = RichInputMethodManager.getInstance().getInputMethodManager();
+        for (final InputMethodInfo imi : imm.getEnabledInputMethodList()) {
+            if (packageName.equals(imi.getPackageName())) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private boolean isMyImeCurrent() {
+        final InputMethodInfo myImi =
+                RichInputMethodManager.getInstance().getInputMethodInfoOfThisIme();
+        final String currentImeId = Settings.Secure.getString(
+                getContentResolver(), Settings.Secure.DEFAULT_INPUT_METHOD);
+        return myImi.getId().equals(currentImeId);
+    }
+
+    private int determineSetupStepNo() {
+        mHandler.cancelPollingImeSettings();
+        if (!isMyImeEnabled()) {
+            return STEP_1;
+        }
+        if (!isMyImeCurrent()) {
+            return STEP_2;
+        }
+        return STEP_3;
+    }
+
+    @Override
+    protected void onSaveInstanceState(final Bundle outState) {
+        super.onSaveInstanceState(outState);
+        outState.putInt(STATE_STEP, mStepNo);
+    }
+
+    @Override
+    protected void onRestoreInstanceState(final Bundle savedInstanceState) {
+        super.onRestoreInstanceState(savedInstanceState);
+        mStepNo = savedInstanceState.getInt(STATE_STEP);
+    }
+
+    @Override
+    protected void onStart() {
+        super.onStart();
+        mStepNo = determineSetupStepNo();
+    }
+
+    @Override
+    protected void onRestart() {
+        super.onRestart();
+        mStepNo = determineSetupStepNo();
+    }
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+        updateSetupStepView();
+    }
+
+    @Override
+    public void onWindowFocusChanged(final boolean hasFocus) {
+        super.onWindowFocusChanged(hasFocus);
+        if (!hasFocus) {
+            return;
+        }
+        mStepNo = determineSetupStepNo();
+        updateSetupStepView();
+    }
+
+    private void updateSetupStepView() {
+        final int layoutDirection = ViewCompatUtils.getLayoutDirection(mStepIndicatorView);
+        mStepIndicatorView.setIndicatorPosition(
+                getIndicatorPosition(mStepNo, mSetupSteps.getTotalStep(), layoutDirection));
+        mSetupSteps.enableStep(mStepNo);
+    }
+
+    private static float getIndicatorPosition(final int step, final int totalStep,
+            final int layoutDirection) {
+        final float pos = ((step - STEP_1) * 2 + 1) / (float)(totalStep * 2);
+        return (layoutDirection == ViewCompatUtils.LAYOUT_DIRECTION_RTL) ? 1.0f - pos : pos;
+    }
+
+    static final class SetupStep implements View.OnClickListener {
+        private final View mRootView;
+        private final TextView mActionLabel;
+        private Runnable mAction;
+
+        public SetupStep(final View rootView, final int title, final int instruction,
+                final int actionIcon, final int actionLabel) {
+            mRootView = rootView;
+            final Resources res = rootView.getResources();
+            final String applicationName = res.getString(R.string.english_ime_name);
+
+            final TextView titleView = (TextView)rootView.findViewById(R.id.setup_step_title);
+            titleView.setText(res.getString(title, applicationName));
+
+            final TextView instructionView = (TextView)rootView.findViewById(
+                    R.id.setup_step_instruction);
+            if (instruction == 0) {
+                instructionView.setVisibility(View.GONE);
+            } else {
+                instructionView.setText(res.getString(instruction, applicationName));
+            }
+
+            mActionLabel = (TextView)rootView.findViewById(R.id.setup_step_action_label);
+            mActionLabel.setText(res.getString(actionLabel));
+            if (actionIcon == 0) {
+                final int paddingEnd = ViewCompatUtils.getPaddingEnd(mActionLabel);
+                ViewCompatUtils.setPaddingRelative(mActionLabel, paddingEnd, 0, paddingEnd, 0);
+            } else {
+                final int overrideColor = res.getColor(R.color.setup_text_action);
+                final Drawable icon = res.getDrawable(actionIcon);
+                icon.setColorFilter(overrideColor, PorterDuff.Mode.MULTIPLY);
+                icon.setBounds(0, 0, icon.getIntrinsicWidth(), icon.getIntrinsicHeight());
+                TextViewCompatUtils.setCompoundDrawablesRelative(
+                        mActionLabel, icon, null, null, null);
+            }
+        }
+
+        public void setEnabled(final boolean enabled) {
+            mRootView.setVisibility(enabled ? View.VISIBLE : View.GONE);
+        }
+
+        public void setAction(final Runnable action) {
+            mActionLabel.setOnClickListener(this);
+            mAction = action;
+        }
+
+        @Override
+        public void onClick(final View v) {
+            if (mAction != null) {
+                mAction.run();
+            }
+        }
+    }
+
+    static final class SetupStepGroup {
+        private final HashMap<Integer, SetupStep> mGroup = CollectionUtils.newHashMap();
+
+        public void addStep(final int stepNo, final SetupStep step) {
+            mGroup.put(stepNo, step);
+        }
+
+        public void enableStep(final int enableStepNo) {
+            for (final Integer stepNo : mGroup.keySet()) {
+                final SetupStep step = mGroup.get(stepNo);
+                step.setEnabled(stepNo == enableStepNo);
+            }
+        }
+
+        public int getTotalStep() {
+            return mGroup.size();
+        }
     }
 }
diff --git a/java/src/com/android/inputmethod/latin/setup/SetupStepIndicatorView.java b/java/src/com/android/inputmethod/latin/setup/SetupStepIndicatorView.java
new file mode 100644
index 0000000000..077a217936
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/setup/SetupStepIndicatorView.java
@@ -0,0 +1,56 @@
+/*
+ * 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.setup;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.util.AttributeSet;
+import android.view.View;
+
+import com.android.inputmethod.latin.R;
+
+public final class SetupStepIndicatorView extends View {
+    private final Path mIndicatorPath = new Path();
+    private final Paint mIndicatorPaint = new Paint();
+    private float mXRatio;
+
+    public SetupStepIndicatorView(final Context context, final AttributeSet attrs) {
+        super(context, attrs);
+        mIndicatorPaint.setColor(getResources().getColor(R.color.setup_step_background));
+        mIndicatorPaint.setStyle(Paint.Style.FILL);
+    }
+
+    public void setIndicatorPosition(final float xRatio) {
+        mXRatio = xRatio;
+        invalidate();
+    }
+
+    @Override
+    protected void onDraw(final Canvas canvas) {
+        super.onDraw(canvas);
+        final int xPos = (int)(getWidth() * mXRatio);
+        final int height = getHeight();
+        mIndicatorPath.rewind();
+        mIndicatorPath.moveTo(xPos, 0);
+        mIndicatorPath.lineTo(xPos + height, height);
+        mIndicatorPath.lineTo(xPos - height, height);
+        mIndicatorPath.close();
+        canvas.drawPath(mIndicatorPath, mIndicatorPaint);
+    }
+}
-- 
GitLab