77f63c8ac6
In setup wizard, InputMethodManager may not be able to be aware that this IME is installed, especially just after the IME is installed via GooglePlay app and hit the open button on the app to launch the setup wizard. Bug: 9299618 Change-Id: I00c8544178b41074253d49ae9481996ec56593d2
502 lines
19 KiB
Java
502 lines
19 KiB
Java
/*
|
|
* 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.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.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 static final boolean ENABLE_WELCOME_VIDEO = true;
|
|
|
|
private InputMethodManager mImm;
|
|
|
|
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;
|
|
private TextView mActionFinish;
|
|
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;
|
|
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 SettingsPoolingHandler mHandler;
|
|
|
|
private 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;
|
|
|
|
private final InputMethodManager mImmInHandler;
|
|
|
|
public SettingsPoolingHandler(final SetupWizardActivity outerInstance,
|
|
final InputMethodManager imm) {
|
|
super(outerInstance);
|
|
mImmInHandler = imm;
|
|
}
|
|
|
|
@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, mImmInHandler)) {
|
|
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_Translucent_NoTitleBar);
|
|
super.onCreate(savedInstanceState);
|
|
|
|
mImm = (InputMethodManager)getSystemService(INPUT_METHOD_SERVICE);
|
|
mHandler = new SettingsPoolingHandler(this, mImm);
|
|
|
|
setContentView(R.layout.setup_wizard);
|
|
mSetupWizard = findViewById(R.id.setup_wizard);
|
|
|
|
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);
|
|
final SettingsPoolingHandler handler = mHandler;
|
|
step1.setAction(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
invokeLanguageAndInputSettings();
|
|
handler.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() {
|
|
invokeInputMethodPicker();
|
|
}
|
|
});
|
|
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();
|
|
final VideoView welcomeVideoView = (VideoView)findViewById(R.id.setup_welcome_video);
|
|
welcomeVideoView.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.
|
|
welcomeVideoView.setBackgroundResource(0);
|
|
mp.setLooping(true);
|
|
}
|
|
});
|
|
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);
|
|
hideWelcomeVideoAndShowWelcomeImage();
|
|
return true;
|
|
}
|
|
});
|
|
mWelcomeVideoView = welcomeVideoView;
|
|
mWelcomeImageView = (ImageView)findViewById(R.id.setup_welcome_image);
|
|
|
|
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();
|
|
}
|
|
}
|
|
|
|
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);
|
|
mNeedsToAdjustStepNumberToSystemState = true;
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
void invokeLanguageAndInputSettings() {
|
|
final Intent intent = new Intent();
|
|
intent.setAction(Settings.ACTION_INPUT_METHOD_SETTINGS);
|
|
intent.addCategory(Intent.CATEGORY_DEFAULT);
|
|
startActivity(intent);
|
|
mNeedsToAdjustStepNumberToSystemState = true;
|
|
}
|
|
|
|
void invokeInputMethodPicker() {
|
|
// Invoke input method picker.
|
|
mImm.showInputMethodPicker();
|
|
mNeedsToAdjustStepNumberToSystemState = true;
|
|
}
|
|
|
|
void invokeSubtypeEnablerOfThisIme() {
|
|
final InputMethodInfo imi = SetupActivity.getInputMethodInfoOf(getPackageName(), mImm);
|
|
if (imi == null) {
|
|
return;
|
|
}
|
|
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, mImm)) {
|
|
return STEP_1;
|
|
}
|
|
if (!SetupActivity.isThisImeCurrent(this, mImm)) {
|
|
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();
|
|
// 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();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
protected void onResume() {
|
|
super.onResume();
|
|
if (mStepNumber == STEP_LAUNCHING_IME_SETTINGS) {
|
|
// Prevent white screen flashing while launching settings activity.
|
|
mSetupWizard.setVisibility(View.INVISIBLE);
|
|
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();
|
|
}
|
|
|
|
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() {
|
|
hideAndStopWelcomeVideo();
|
|
super.onPause();
|
|
}
|
|
|
|
@Override
|
|
public void onWindowFocusChanged(final boolean hasFocus) {
|
|
super.onWindowFocusChanged(hasFocus);
|
|
if (hasFocus && mNeedsToAdjustStepNumberToSystemState) {
|
|
mNeedsToAdjustStepNumberToSystemState = false;
|
|
mStepNumber = determineSetupStepNumber();
|
|
updateSetupStepView();
|
|
}
|
|
}
|
|
|
|
private void updateSetupStepView() {
|
|
mSetupWizard.setVisibility(View.VISIBLE);
|
|
final boolean welcomeScreen = (mStepNumber == STEP_WELCOME);
|
|
mWelcomeScreen.setVisibility(welcomeScreen ? View.VISIBLE : View.GONE);
|
|
mSetupScreen.setVisibility(welcomeScreen ? View.GONE : View.VISIBLE);
|
|
if (welcomeScreen) {
|
|
if (ENABLE_WELCOME_VIDEO) {
|
|
showAndStartWelcomeVideo();
|
|
} else {
|
|
hideWelcomeVideoAndShowWelcomeImage();
|
|
}
|
|
return;
|
|
}
|
|
hideAndStopWelcomeVideo();
|
|
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());
|
|
}
|
|
}
|
|
}
|