blob: 15d0bac3736329b20094a8e22dbf6415ab0669a9 [file] [log] [blame]
/*
* 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.Context;
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 mStepNumber;
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();
if (setupActivity == null) {
return;
}
switch (msg.what) {
case MSG_POLLING_IME_SETTINGS:
if (SetupActivity.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);
}
}
@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 = determineSetupStepNumber();
} else {
mStepNumber = savedInstanceState.getInt(STATE_STEP);
}
if (mStepNumber == 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);
final int appName = getApplicationInfo().labelRes;
titleView.setText(getString(R.string.setup_title, getString(appName)));
mStepIndicatorView = (SetupStepIndicatorView)findViewById(R.id.setup_step_indicator);
final SetupStep step1 = new SetupStep(findViewById(R.id.setup_step1),
appName, 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),
appName, 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),
appName, 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_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);
}
/**
* Check if the IME specified by the context is enabled.
* Note that {@link RichInputMethodManager} must have been initialized before calling this
* method.
*
* @param context package context of the IME to be checked.
* @return true if this IME is enabled.
*/
public static boolean isThisImeEnabled(final Context context) {
final String packageName = context.getPackageName();
final InputMethodManager imm = RichInputMethodManager.getInstance().getInputMethodManager();
for (final InputMethodInfo imi : imm.getEnabledInputMethodList()) {
if (packageName.equals(imi.getPackageName())) {
return true;
}
}
return false;
}
/**
* Check if the IME specified by the context is the current IME.
* Note that {@link RichInputMethodManager} must have been initialized before calling this
* method.
*
* @param context package context of the IME to be checked.
* @return true if this IME is the current IME.
*/
public static boolean isThisImeCurrent(final Context context) {
final InputMethodInfo myImi =
RichInputMethodManager.getInstance().getInputMethodInfoOfThisIme();
final String currentImeId = Settings.Secure.getString(
context.getContentResolver(), Settings.Secure.DEFAULT_INPUT_METHOD);
return myImi.getId().equals(currentImeId);
}
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);
}
@Override
protected void onStart() {
super.onStart();
mStepNumber = determineSetupStepNumber();
}
@Override
protected void onRestart() {
super.onRestart();
mStepNumber = determineSetupStepNumber();
}
@Override
protected void onResume() {
super.onResume();
updateSetupStepView();
}
@Override
public void onWindowFocusChanged(final boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if (!hasFocus) {
return;
}
mStepNumber = determineSetupStepNumber();
updateSetupStepView();
}
private void updateSetupStepView() {
final int layoutDirection = ViewCompatUtils.getLayoutDirection(mStepIndicatorView);
mStepIndicatorView.setIndicatorPosition(
getIndicatorPosition(mStepNumber, mSetupSteps.getTotalStep(), layoutDirection));
mSetupSteps.enableStep(mStepNumber);
}
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 appName, final int title,
final int instruction, final int actionIcon, final int actionLabel) {
mRootView = rootView;
final Resources res = rootView.getResources();
final String applicationName = res.getString(appName);
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();
}
}
}