Introduce another activity to launch setup wizard

Bug: 8336068
Change-Id: I35b94dd87c5b01d3e927da8f918a5398dd565d33
diff --git a/java/AndroidManifest.xml b/java/AndroidManifest.xml
index e39ca18..fb973f3 100644
--- a/java/AndroidManifest.xml
+++ b/java/AndroidManifest.xml
@@ -57,14 +57,22 @@
         <activity android:name=".setup.SetupActivity"
                 android:label="@string/english_ime_name"
                 android:icon="@mipmap/ic_launcher_keyboard"
-                android:launchMode="singleTop"
-                android:clearTaskOnLaunch="true">
+                android:launchMode="singleTask"
+                android:noHistory="true">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.intent.category.LAUNCHER" />
             </intent-filter>
         </activity>
 
+        <activity android:name=".setup.SetupWizardActivity"
+                android:label="@string/english_ime_name"
+                android:clearTaskOnLaunch="true">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+            </intent-filter>
+        </activity>
+
         <receiver android:name=".setup.LauncherIconVisibilityManager">
             <intent-filter>
                 <action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
diff --git a/java/src/com/android/inputmethod/latin/setup/SetupActivity.java b/java/src/com/android/inputmethod/latin/setup/SetupActivity.java
index 97cf7fc..8a2de88 100644
--- a/java/src/com/android/inputmethod/latin/setup/SetupActivity.java
+++ b/java/src/com/android/inputmethod/latin/setup/SetupActivity.java
@@ -17,255 +17,27 @@
 package com.android.inputmethod.latin.setup;
 
 import android.app.Activity;
-import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
-import android.content.res.Resources;
-import android.media.MediaPlayer;
-import android.net.Uri;
 import android.os.Bundle;
-import android.os.Message;
 import android.provider.Settings;
-import android.util.Log;
-import android.view.View;
 import android.view.inputmethod.InputMethodInfo;
 import android.view.inputmethod.InputMethodManager;
-import android.widget.ImageView;
-import android.widget.TextView;
-import android.widget.VideoView;
 
-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.ArrayList;
-
-// TODO: Use Fragment to implement welcome screen and setup steps.
-public final class SetupActivity extends Activity implements View.OnClickListener {
-    private static final String TAG = SetupActivity.class.getSimpleName();
-
-    private View mWelcomeScreen;
-    private View mSetupScreen;
-    private Uri mWelcomeVideoUri;
-    private VideoView mWelcomeVideoView;
-    private View mActionStart;
-    private View mActionNext;
-    private TextView mStep1Bullet;
-    private TextView mActionFinish;
-    private SetupStepGroup mSetupStepGroup;
-    private static final String STATE_STEP = "step";
-    private int mStepNumber;
-    private static final int STEP_WELCOME = 0;
-    private static final int STEP_1 = 1;
-    private static final int STEP_2 = 2;
-    private static final int STEP_3 = 3;
-    private static final int STEP_LAUNCHING_IME_SETTINGS = 4;
-    private static final int STEP_BACK_FROM_IME_SETTINGS = 5;
-
-    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();
-            if (setupActivity == null) {
-                return;
-            }
-            switch (msg.what) {
-            case MSG_POLLING_IME_SETTINGS:
-                if (isThisImeEnabled(setupActivity)) {
-                    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);
-        }
-    }
-
+public final class SetupActivity extends Activity {
     @Override
     protected void onCreate(final Bundle savedInstanceState) {
-        setTheme(android.R.style.Theme_DeviceDefault_Light_NoActionBar);
         super.onCreate(savedInstanceState);
-
-        setContentView(R.layout.setup_wizard);
-
-        RichInputMethodManager.init(this);
-
-        if (savedInstanceState == null) {
-            mStepNumber = determineSetupStepNumberFromLauncher();
-        } else {
-            mStepNumber = savedInstanceState.getInt(STATE_STEP);
-        }
-
-        final String applicationName = getResources().getString(getApplicationInfo().labelRes);
-        mWelcomeScreen = findViewById(R.id.setup_welcome_screen);
-        final TextView welcomeTitle = (TextView)findViewById(R.id.setup_welcome_title);
-        welcomeTitle.setText(getString(R.string.setup_welcome_title, applicationName));
-
-        mSetupScreen = findViewById(R.id.setup_steps_screen);
-        final TextView stepsTitle = (TextView)findViewById(R.id.setup_title);
-        stepsTitle.setText(getString(R.string.setup_steps_title, applicationName));
-
-        final SetupStepIndicatorView indicatorView =
-                (SetupStepIndicatorView)findViewById(R.id.setup_step_indicator);
-        mSetupStepGroup = new SetupStepGroup(indicatorView);
-
-        mStep1Bullet = (TextView)findViewById(R.id.setup_step1_bullet);
-        mStep1Bullet.setOnClickListener(this);
-        final SetupStep step1 = new SetupStep(STEP_1, applicationName,
-                mStep1Bullet, findViewById(R.id.setup_step1),
-                R.string.setup_step1_title, R.string.setup_step1_instruction,
-                R.string.setup_step1_finished_instruction, R.drawable.ic_setup_step1,
-                R.string.setup_step1_action);
-        step1.setAction(new Runnable() {
-            @Override
-            public void run() {
-                invokeLanguageAndInputSettings();
-                mHandler.startPollingImeSettings();
-            }
-        });
-        mSetupStepGroup.addStep(step1);
-
-        final SetupStep step2 = new SetupStep(STEP_2, applicationName,
-                (TextView)findViewById(R.id.setup_step2_bullet), findViewById(R.id.setup_step2),
-                R.string.setup_step2_title, R.string.setup_step2_instruction,
-                0 /* finishedInstruction */, R.drawable.ic_setup_step2,
-                R.string.setup_step2_action);
-        step2.setAction(new Runnable() {
-            @Override
-            public void run() {
-                // Invoke input method picker.
-                RichInputMethodManager.getInstance().getInputMethodManager()
-                        .showInputMethodPicker();
-            }
-        });
-        mSetupStepGroup.addStep(step2);
-
-        final SetupStep step3 = new SetupStep(STEP_3, applicationName,
-                (TextView)findViewById(R.id.setup_step3_bullet), findViewById(R.id.setup_step3),
-                R.string.setup_step3_title, R.string.setup_step3_instruction,
-                0 /* finishedInstruction */, R.drawable.ic_setup_step3,
-                R.string.setup_step3_action);
-        step3.setAction(new Runnable() {
-            @Override
-            public void run() {
-                invokeSubtypeEnablerOfThisIme();
-            }
-        });
-        mSetupStepGroup.addStep(step3);
-
-        mWelcomeVideoUri = new Uri.Builder()
-                .scheme(ContentResolver.SCHEME_ANDROID_RESOURCE)
-                .authority(getPackageName())
-                .path(Integer.toString(R.raw.setup_welcome_video))
-                .build();
-        mWelcomeVideoView = (VideoView)findViewById(R.id.setup_welcome_video);
-        mWelcomeVideoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
-            @Override
-            public void onPrepared(final MediaPlayer mp) {
-                // Now VideoView has been laid-out and ready to play, remove background of it to
-                // reveal the video.
-                mWelcomeVideoView.setBackgroundResource(0);
-                mp.setLooping(true);
-            }
-        });
-        final ImageView welcomeImageView = (ImageView)findViewById(R.id.setup_welcome_image);
-        mWelcomeVideoView.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);
-                mWelcomeVideoView.setVisibility(View.GONE);
-                welcomeImageView.setImageResource(R.raw.setup_welcome_image);
-                welcomeImageView.setVisibility(View.VISIBLE);
-                return true;
-            }
-        });
-
-        mActionStart = findViewById(R.id.setup_start_label);
-        mActionStart.setOnClickListener(this);
-        mActionNext = findViewById(R.id.setup_next);
-        mActionNext.setOnClickListener(this);
-        mActionFinish = (TextView)findViewById(R.id.setup_finish);
-        TextViewCompatUtils.setCompoundDrawablesRelativeWithIntrinsicBounds(mActionFinish,
-                getResources().getDrawable(R.drawable.ic_setup_finish), null, null, null);
-        mActionFinish.setOnClickListener(this);
-    }
-
-    @Override
-    public void onClick(final View v) {
-        if (v == mActionFinish) {
+        final Intent intent = new Intent();
+        intent.setClass(this, SetupWizardActivity.class);
+        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP
+                | Intent.FLAG_ACTIVITY_NEW_TASK);
+        startActivity(intent);
+        if (!isFinishing()) {
             finish();
-            return;
         }
-        final int currentStep = determineSetupStepNumber();
-        final int nextStep;
-        if (v == mActionStart) {
-            nextStep = STEP_1;
-        } else if (v == mActionNext) {
-            nextStep = mStepNumber + 1;
-        } else if (v == mStep1Bullet && currentStep == STEP_2) {
-            nextStep = STEP_1;
-        } else {
-            nextStep = mStepNumber;
-        }
-        if (mStepNumber != nextStep) {
-            mStepNumber = nextStep;
-            updateSetupStepView();
-        }
-    }
-
-    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_RESET_TASK_IF_NEEDED
-                | Intent.FLAG_ACTIVITY_CLEAR_TOP);
-        startActivity(intent);
-    }
-
-    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);
     }
 
     /**
@@ -302,194 +74,4 @@
                 context.getContentResolver(), Settings.Secure.DEFAULT_INPUT_METHOD);
         return myImi.getId().equals(currentImeId);
     }
-
-    private int determineSetupStepNumberFromLauncher() {
-        final int stepNumber = determineSetupStepNumber();
-        if (stepNumber == STEP_1) {
-            return STEP_WELCOME;
-        }
-        if (stepNumber == STEP_3) {
-            return STEP_LAUNCHING_IME_SETTINGS;
-        }
-        return stepNumber;
-    }
-
-    private int determineSetupStepNumber() {
-        mHandler.cancelPollingImeSettings();
-        if (!isThisImeEnabled(this)) {
-            return STEP_1;
-        }
-        if (!isThisImeCurrent(this)) {
-            return STEP_2;
-        }
-        return STEP_3;
-    }
-
-    @Override
-    protected void onSaveInstanceState(final Bundle outState) {
-        super.onSaveInstanceState(outState);
-        outState.putInt(STATE_STEP, mStepNumber);
-    }
-
-    @Override
-    protected void onRestoreInstanceState(final Bundle savedInstanceState) {
-        super.onRestoreInstanceState(savedInstanceState);
-        mStepNumber = savedInstanceState.getInt(STATE_STEP);
-    }
-
-    private static boolean isInSetupSteps(final int stepNumber) {
-        return stepNumber >= STEP_1 && stepNumber <= STEP_3;
-    }
-
-    @Override
-    protected void onRestart() {
-        super.onRestart();
-        if (isInSetupSteps(mStepNumber)) {
-            mStepNumber = determineSetupStepNumber();
-        }
-    }
-
-    @Override
-    protected void onResume() {
-        super.onResume();
-        if (mStepNumber == STEP_LAUNCHING_IME_SETTINGS) {
-            invokeSettingsOfThisIme();
-            mStepNumber = STEP_BACK_FROM_IME_SETTINGS;
-            return;
-        }
-        if (mStepNumber == STEP_BACK_FROM_IME_SETTINGS) {
-            finish();
-            return;
-        }
-        updateSetupStepView();
-    }
-
-    @Override
-    public void onBackPressed() {
-        if (mStepNumber == STEP_1) {
-            mStepNumber = STEP_WELCOME;
-            updateSetupStepView();
-            return;
-        }
-        super.onBackPressed();
-    }
-
-    private static void hideAndStopVideo(final VideoView videoView) {
-        videoView.stopPlayback();
-        videoView.setVisibility(View.INVISIBLE);
-    }
-
-    @Override
-    protected void onPause() {
-        hideAndStopVideo(mWelcomeVideoView);
-        super.onPause();
-    }
-
-    @Override
-    public void onWindowFocusChanged(final boolean hasFocus) {
-        super.onWindowFocusChanged(hasFocus);
-        if (hasFocus && isInSetupSteps(mStepNumber)) {
-            mStepNumber = determineSetupStepNumber();
-            updateSetupStepView();
-        }
-    }
-
-    private void updateSetupStepView() {
-        final boolean welcomeScreen = (mStepNumber == STEP_WELCOME);
-        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();
-            return;
-        }
-        hideAndStopVideo(mWelcomeVideoView);
-        final boolean isStepActionAlreadyDone = mStepNumber < determineSetupStepNumber();
-        mSetupStepGroup.enableStep(mStepNumber, isStepActionAlreadyDone);
-        mActionNext.setVisibility(isStepActionAlreadyDone ? View.VISIBLE : View.GONE);
-        mActionFinish.setVisibility((mStepNumber == STEP_3) ? View.VISIBLE : View.GONE);
-    }
-
-    static final class SetupStep implements View.OnClickListener {
-        public final int mStepNo;
-        private final View mStepView;
-        private final TextView mBulletView;
-        private final int mActivatedColor;
-        private final int mDeactivatedColor;
-        private final String mInstruction;
-        private final String mFinishedInstruction;
-        private final TextView mActionLabel;
-        private Runnable mAction;
-
-        public SetupStep(final int stepNo, final String applicationName, final TextView bulletView,
-                final View stepView, final int title, final int instruction,
-                final int finishedInstruction, final int actionIcon, final int actionLabel) {
-            mStepNo = stepNo;
-            mStepView = stepView;
-            mBulletView = bulletView;
-            final Resources res = stepView.getResources();
-            mActivatedColor = res.getColor(R.color.setup_text_action);
-            mDeactivatedColor = res.getColor(R.color.setup_text_dark);
-
-            final TextView titleView = (TextView)mStepView.findViewById(R.id.setup_step_title);
-            titleView.setText(res.getString(title, applicationName));
-            mInstruction = (instruction == 0) ? null
-                    : res.getString(instruction, applicationName);
-            mFinishedInstruction = (finishedInstruction == 0) ? null
-                    : res.getString(finishedInstruction, applicationName);
-
-            mActionLabel = (TextView)mStepView.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 {
-                TextViewCompatUtils.setCompoundDrawablesRelativeWithIntrinsicBounds(
-                        mActionLabel, res.getDrawable(actionIcon), null, null, null);
-            }
-        }
-
-        public void setEnabled(final boolean enabled, final boolean isStepActionAlreadyDone) {
-            mStepView.setVisibility(enabled ? View.VISIBLE : View.GONE);
-            mBulletView.setTextColor(enabled ? mActivatedColor : mDeactivatedColor);
-            final TextView instructionView = (TextView)mStepView.findViewById(
-                    R.id.setup_step_instruction);
-            instructionView.setText(isStepActionAlreadyDone ? mFinishedInstruction : mInstruction);
-            mActionLabel.setVisibility(isStepActionAlreadyDone ? View.GONE : View.VISIBLE);
-        }
-
-        public void setAction(final Runnable action) {
-            mActionLabel.setOnClickListener(this);
-            mAction = action;
-        }
-
-        @Override
-        public void onClick(final View v) {
-            if (v == mActionLabel && mAction != null) {
-                mAction.run();
-                return;
-            }
-        }
-    }
-
-    static final class SetupStepGroup {
-        private final SetupStepIndicatorView mIndicatorView;
-        private final ArrayList<SetupStep> mGroup = CollectionUtils.newArrayList();
-
-        public SetupStepGroup(final SetupStepIndicatorView indicatorView) {
-            mIndicatorView = indicatorView;
-        }
-
-        public void addStep(final SetupStep step) {
-            mGroup.add(step);
-        }
-
-        public void enableStep(final int enableStepNo, final boolean isStepActionAlreadyDone) {
-            for (final SetupStep step : mGroup) {
-                step.setEnabled(step.mStepNo == enableStepNo, isStepActionAlreadyDone);
-            }
-            mIndicatorView.setIndicatorPosition(enableStepNo - STEP_1, mGroup.size());
-        }
-    }
 }
diff --git a/java/src/com/android/inputmethod/latin/setup/SetupWizardActivity.java b/java/src/com/android/inputmethod/latin/setup/SetupWizardActivity.java
new file mode 100644
index 0000000..8f6a2e5
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/setup/SetupWizardActivity.java
@@ -0,0 +1,460 @@
+/*
+ * 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.app.Activity;
+import android.content.ContentResolver;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.media.MediaPlayer;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Message;
+import android.provider.Settings;
+import android.util.Log;
+import android.view.View;
+import android.view.inputmethod.InputMethodInfo;
+import android.widget.ImageView;
+import android.widget.TextView;
+import android.widget.VideoView;
+
+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.ArrayList;
+
+// TODO: Use Fragment to implement welcome screen and setup steps.
+public final class SetupWizardActivity extends Activity implements View.OnClickListener {
+    static final String TAG = SetupWizardActivity.class.getSimpleName();
+
+    private View mWelcomeScreen;
+    private View mSetupScreen;
+    private Uri mWelcomeVideoUri;
+    private VideoView mWelcomeVideoView;
+    private View mActionStart;
+    private View mActionNext;
+    private TextView mStep1Bullet;
+    private TextView mActionFinish;
+    private SetupStepGroup mSetupStepGroup;
+    private static final String STATE_STEP = "step";
+    private int mStepNumber;
+    private static final int STEP_WELCOME = 0;
+    private static final int STEP_1 = 1;
+    private static final int STEP_2 = 2;
+    private static final int STEP_3 = 3;
+    private static final int STEP_LAUNCHING_IME_SETTINGS = 4;
+    private static final int STEP_BACK_FROM_IME_SETTINGS = 5;
+
+    private final SettingsPoolingHandler mHandler = new SettingsPoolingHandler(this);
+
+    static final class SettingsPoolingHandler
+            extends StaticInnerHandlerWrapper<SetupWizardActivity> {
+        private static final int MSG_POLLING_IME_SETTINGS = 0;
+        private static final long IME_SETTINGS_POLLING_INTERVAL = 200;
+
+        public SettingsPoolingHandler(final SetupWizardActivity outerInstance) {
+            super(outerInstance);
+        }
+
+        @Override
+        public void handleMessage(final Message msg) {
+            final SetupWizardActivity setupWizardActivity = getOuterInstance();
+            if (setupWizardActivity == null) {
+                return;
+            }
+            switch (msg.what) {
+            case MSG_POLLING_IME_SETTINGS:
+                if (SetupActivity.isThisImeEnabled(setupWizardActivity)) {
+                    setupWizardActivity.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(final Bundle savedInstanceState) {
+        setTheme(android.R.style.Theme_DeviceDefault_Light_NoActionBar);
+        super.onCreate(savedInstanceState);
+
+        setContentView(R.layout.setup_wizard);
+
+        RichInputMethodManager.init(this);
+
+        if (savedInstanceState == null) {
+            mStepNumber = determineSetupStepNumberFromLauncher();
+        } else {
+            mStepNumber = savedInstanceState.getInt(STATE_STEP);
+        }
+
+        final String applicationName = getResources().getString(getApplicationInfo().labelRes);
+        mWelcomeScreen = findViewById(R.id.setup_welcome_screen);
+        final TextView welcomeTitle = (TextView)findViewById(R.id.setup_welcome_title);
+        welcomeTitle.setText(getString(R.string.setup_welcome_title, applicationName));
+
+        mSetupScreen = findViewById(R.id.setup_steps_screen);
+        final TextView stepsTitle = (TextView)findViewById(R.id.setup_title);
+        stepsTitle.setText(getString(R.string.setup_steps_title, applicationName));
+
+        final SetupStepIndicatorView indicatorView =
+                (SetupStepIndicatorView)findViewById(R.id.setup_step_indicator);
+        mSetupStepGroup = new SetupStepGroup(indicatorView);
+
+        mStep1Bullet = (TextView)findViewById(R.id.setup_step1_bullet);
+        mStep1Bullet.setOnClickListener(this);
+        final SetupStep step1 = new SetupStep(STEP_1, applicationName,
+                mStep1Bullet, findViewById(R.id.setup_step1),
+                R.string.setup_step1_title, R.string.setup_step1_instruction,
+                R.string.setup_step1_finished_instruction, R.drawable.ic_setup_step1,
+                R.string.setup_step1_action);
+        step1.setAction(new Runnable() {
+            @Override
+            public void run() {
+                invokeLanguageAndInputSettings();
+                mHandler.startPollingImeSettings();
+            }
+        });
+        mSetupStepGroup.addStep(step1);
+
+        final SetupStep step2 = new SetupStep(STEP_2, applicationName,
+                (TextView)findViewById(R.id.setup_step2_bullet), findViewById(R.id.setup_step2),
+                R.string.setup_step2_title, R.string.setup_step2_instruction,
+                0 /* finishedInstruction */, R.drawable.ic_setup_step2,
+                R.string.setup_step2_action);
+        step2.setAction(new Runnable() {
+            @Override
+            public void run() {
+                // Invoke input method picker.
+                RichInputMethodManager.getInstance().getInputMethodManager()
+                        .showInputMethodPicker();
+            }
+        });
+        mSetupStepGroup.addStep(step2);
+
+        final SetupStep step3 = new SetupStep(STEP_3, applicationName,
+                (TextView)findViewById(R.id.setup_step3_bullet), findViewById(R.id.setup_step3),
+                R.string.setup_step3_title, R.string.setup_step3_instruction,
+                0 /* finishedInstruction */, R.drawable.ic_setup_step3,
+                R.string.setup_step3_action);
+        step3.setAction(new Runnable() {
+            @Override
+            public void run() {
+                invokeSubtypeEnablerOfThisIme();
+            }
+        });
+        mSetupStepGroup.addStep(step3);
+
+        mWelcomeVideoUri = new Uri.Builder()
+                .scheme(ContentResolver.SCHEME_ANDROID_RESOURCE)
+                .authority(getPackageName())
+                .path(Integer.toString(R.raw.setup_welcome_video))
+                .build();
+        mWelcomeVideoView = (VideoView)findViewById(R.id.setup_welcome_video);
+        mWelcomeVideoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
+            @Override
+            public void onPrepared(final MediaPlayer mp) {
+                // Now VideoView has been laid-out and ready to play, remove background of it to
+                // reveal the video.
+                mWelcomeVideoView.setBackgroundResource(0);
+                mp.setLooping(true);
+            }
+        });
+        final ImageView welcomeImageView = (ImageView)findViewById(R.id.setup_welcome_image);
+        mWelcomeVideoView.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);
+                mWelcomeVideoView.setVisibility(View.GONE);
+                welcomeImageView.setImageResource(R.raw.setup_welcome_image);
+                welcomeImageView.setVisibility(View.VISIBLE);
+                return true;
+            }
+        });
+
+        mActionStart = findViewById(R.id.setup_start_label);
+        mActionStart.setOnClickListener(this);
+        mActionNext = findViewById(R.id.setup_next);
+        mActionNext.setOnClickListener(this);
+        mActionFinish = (TextView)findViewById(R.id.setup_finish);
+        TextViewCompatUtils.setCompoundDrawablesRelativeWithIntrinsicBounds(mActionFinish,
+                getResources().getDrawable(R.drawable.ic_setup_finish), null, null, null);
+        mActionFinish.setOnClickListener(this);
+    }
+
+    @Override
+    public void onClick(final View v) {
+        if (v == mActionFinish) {
+            finish();
+            return;
+        }
+        final int currentStep = determineSetupStepNumber();
+        final int nextStep;
+        if (v == mActionStart) {
+            nextStep = STEP_1;
+        } else if (v == mActionNext) {
+            nextStep = mStepNumber + 1;
+        } else if (v == mStep1Bullet && currentStep == STEP_2) {
+            nextStep = STEP_1;
+        } else {
+            nextStep = mStepNumber;
+        }
+        if (mStepNumber != nextStep) {
+            mStepNumber = nextStep;
+            updateSetupStepView();
+        }
+    }
+
+    private void invokeSetupWizardOfThisIme() {
+        final Intent intent = new Intent();
+        intent.setClass(this, SetupWizardActivity.class);
+        intent.setFlags(Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
+                | Intent.FLAG_ACTIVITY_SINGLE_TOP
+                | 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_RESET_TASK_IF_NEEDED
+                | Intent.FLAG_ACTIVITY_CLEAR_TOP);
+        startActivity(intent);
+    }
+
+    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 int determineSetupStepNumberFromLauncher() {
+        final int stepNumber = determineSetupStepNumber();
+        if (stepNumber == STEP_1) {
+            return STEP_WELCOME;
+        }
+        if (stepNumber == STEP_3) {
+            return STEP_LAUNCHING_IME_SETTINGS;
+        }
+        return stepNumber;
+    }
+
+    private int determineSetupStepNumber() {
+        mHandler.cancelPollingImeSettings();
+        if (!SetupActivity.isThisImeEnabled(this)) {
+            return STEP_1;
+        }
+        if (!SetupActivity.isThisImeCurrent(this)) {
+            return STEP_2;
+        }
+        return STEP_3;
+    }
+
+    @Override
+    protected void onSaveInstanceState(final Bundle outState) {
+        super.onSaveInstanceState(outState);
+        outState.putInt(STATE_STEP, mStepNumber);
+    }
+
+    @Override
+    protected void onRestoreInstanceState(final Bundle savedInstanceState) {
+        super.onRestoreInstanceState(savedInstanceState);
+        mStepNumber = savedInstanceState.getInt(STATE_STEP);
+    }
+
+    private static boolean isInSetupSteps(final int stepNumber) {
+        return stepNumber >= STEP_1 && stepNumber <= STEP_3;
+    }
+
+    @Override
+    protected void onRestart() {
+        super.onRestart();
+        if (isInSetupSteps(mStepNumber)) {
+            mStepNumber = determineSetupStepNumber();
+        }
+    }
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+        if (mStepNumber == STEP_LAUNCHING_IME_SETTINGS) {
+            invokeSettingsOfThisIme();
+            mStepNumber = STEP_BACK_FROM_IME_SETTINGS;
+            return;
+        }
+        if (mStepNumber == STEP_BACK_FROM_IME_SETTINGS) {
+            finish();
+            return;
+        }
+        updateSetupStepView();
+    }
+
+    @Override
+    public void onBackPressed() {
+        if (mStepNumber == STEP_1) {
+            mStepNumber = STEP_WELCOME;
+            updateSetupStepView();
+            return;
+        }
+        super.onBackPressed();
+    }
+
+    private static void hideAndStopVideo(final VideoView videoView) {
+        videoView.stopPlayback();
+        videoView.setVisibility(View.INVISIBLE);
+    }
+
+    @Override
+    protected void onPause() {
+        hideAndStopVideo(mWelcomeVideoView);
+        super.onPause();
+    }
+
+    @Override
+    public void onWindowFocusChanged(final boolean hasFocus) {
+        super.onWindowFocusChanged(hasFocus);
+        if (hasFocus && isInSetupSteps(mStepNumber)) {
+            mStepNumber = determineSetupStepNumber();
+            updateSetupStepView();
+        }
+    }
+
+    private void updateSetupStepView() {
+        final boolean welcomeScreen = (mStepNumber == STEP_WELCOME);
+        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();
+            return;
+        }
+        hideAndStopVideo(mWelcomeVideoView);
+        final boolean isStepActionAlreadyDone = mStepNumber < determineSetupStepNumber();
+        mSetupStepGroup.enableStep(mStepNumber, isStepActionAlreadyDone);
+        mActionNext.setVisibility(isStepActionAlreadyDone ? View.VISIBLE : View.GONE);
+        mActionFinish.setVisibility((mStepNumber == STEP_3) ? View.VISIBLE : View.GONE);
+    }
+
+    static final class SetupStep implements View.OnClickListener {
+        public final int mStepNo;
+        private final View mStepView;
+        private final TextView mBulletView;
+        private final int mActivatedColor;
+        private final int mDeactivatedColor;
+        private final String mInstruction;
+        private final String mFinishedInstruction;
+        private final TextView mActionLabel;
+        private Runnable mAction;
+
+        public SetupStep(final int stepNo, final String applicationName, final TextView bulletView,
+                final View stepView, final int title, final int instruction,
+                final int finishedInstruction, final int actionIcon, final int actionLabel) {
+            mStepNo = stepNo;
+            mStepView = stepView;
+            mBulletView = bulletView;
+            final Resources res = stepView.getResources();
+            mActivatedColor = res.getColor(R.color.setup_text_action);
+            mDeactivatedColor = res.getColor(R.color.setup_text_dark);
+
+            final TextView titleView = (TextView)mStepView.findViewById(R.id.setup_step_title);
+            titleView.setText(res.getString(title, applicationName));
+            mInstruction = (instruction == 0) ? null
+                    : res.getString(instruction, applicationName);
+            mFinishedInstruction = (finishedInstruction == 0) ? null
+                    : res.getString(finishedInstruction, applicationName);
+
+            mActionLabel = (TextView)mStepView.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 {
+                TextViewCompatUtils.setCompoundDrawablesRelativeWithIntrinsicBounds(
+                        mActionLabel, res.getDrawable(actionIcon), null, null, null);
+            }
+        }
+
+        public void setEnabled(final boolean enabled, final boolean isStepActionAlreadyDone) {
+            mStepView.setVisibility(enabled ? View.VISIBLE : View.GONE);
+            mBulletView.setTextColor(enabled ? mActivatedColor : mDeactivatedColor);
+            final TextView instructionView = (TextView)mStepView.findViewById(
+                    R.id.setup_step_instruction);
+            instructionView.setText(isStepActionAlreadyDone ? mFinishedInstruction : mInstruction);
+            mActionLabel.setVisibility(isStepActionAlreadyDone ? View.GONE : View.VISIBLE);
+        }
+
+        public void setAction(final Runnable action) {
+            mActionLabel.setOnClickListener(this);
+            mAction = action;
+        }
+
+        @Override
+        public void onClick(final View v) {
+            if (v == mActionLabel && mAction != null) {
+                mAction.run();
+                return;
+            }
+        }
+    }
+
+    static final class SetupStepGroup {
+        private final SetupStepIndicatorView mIndicatorView;
+        private final ArrayList<SetupStep> mGroup = CollectionUtils.newArrayList();
+
+        public SetupStepGroup(final SetupStepIndicatorView indicatorView) {
+            mIndicatorView = indicatorView;
+        }
+
+        public void addStep(final SetupStep step) {
+            mGroup.add(step);
+        }
+
+        public void enableStep(final int enableStepNo, final boolean isStepActionAlreadyDone) {
+            for (final SetupStep step : mGroup) {
+                step.setEnabled(step.mStepNo == enableStepNo, isStepActionAlreadyDone);
+            }
+            mIndicatorView.setIndicatorPosition(enableStepNo - STEP_1, mGroup.size());
+        }
+    }
+}