| /* | |
| * Copyright (C) 2012 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.settings.inputmethod; | |
| import android.app.Activity; | |
| import android.app.AlertDialog; | |
| import android.app.Dialog; | |
| import android.app.DialogFragment; | |
| import android.app.LoaderManager.LoaderCallbacks; | |
| import android.content.AsyncTaskLoader; | |
| import android.content.Context; | |
| import android.content.DialogInterface; | |
| import android.content.Intent; | |
| import android.content.Loader; | |
| import android.hardware.input.InputDeviceIdentifier; | |
| import android.hardware.input.InputManager; | |
| import android.hardware.input.InputManager.InputDeviceListener; | |
| import android.hardware.input.KeyboardLayout; | |
| import android.os.Bundle; | |
| import android.view.InputDevice; | |
| import android.view.LayoutInflater; | |
| import android.view.View; | |
| import android.view.ViewGroup; | |
| import android.widget.ArrayAdapter; | |
| import android.widget.CheckedTextView; | |
| import android.widget.RadioButton; | |
| import android.widget.TextView; | |
| import com.android.settings.R; | |
| import java.util.ArrayList; | |
| import java.util.Collections; | |
| public class KeyboardLayoutDialogFragment extends DialogFragment | |
| implements InputDeviceListener, LoaderCallbacks<KeyboardLayoutDialogFragment.Keyboards> { | |
| private static final String KEY_INPUT_DEVICE_IDENTIFIER = "inputDeviceIdentifier"; | |
| private InputDeviceIdentifier mInputDeviceIdentifier; | |
| private int mInputDeviceId = -1; | |
| private InputManager mIm; | |
| private KeyboardLayoutAdapter mAdapter; | |
| private boolean mHasShownLayoutSelectionScreen; | |
| public KeyboardLayoutDialogFragment() { | |
| } | |
| public KeyboardLayoutDialogFragment(InputDeviceIdentifier inputDeviceIdentifier) { | |
| mInputDeviceIdentifier = inputDeviceIdentifier; | |
| } | |
| @Override | |
| public void onAttach(Activity activity) { | |
| super.onAttach(activity); | |
| Context context = activity.getBaseContext(); | |
| mIm = (InputManager)context.getSystemService(Context.INPUT_SERVICE); | |
| mAdapter = new KeyboardLayoutAdapter(context); | |
| } | |
| @Override | |
| public void onCreate(Bundle savedInstanceState) { | |
| super.onCreate(savedInstanceState); | |
| if (savedInstanceState != null) { | |
| mInputDeviceIdentifier = savedInstanceState.getParcelable(KEY_INPUT_DEVICE_IDENTIFIER); | |
| } | |
| getLoaderManager().initLoader(0, null, this); | |
| } | |
| @Override | |
| public void onSaveInstanceState(Bundle outState) { | |
| super.onSaveInstanceState(outState); | |
| outState.putParcelable(KEY_INPUT_DEVICE_IDENTIFIER, mInputDeviceIdentifier); | |
| } | |
| @Override | |
| public Dialog onCreateDialog(Bundle savedInstanceState) { | |
| Context context = getActivity(); | |
| LayoutInflater inflater = LayoutInflater.from(context); | |
| AlertDialog.Builder builder = new AlertDialog.Builder(context) | |
| .setTitle(R.string.keyboard_layout_dialog_title) | |
| .setPositiveButton(R.string.keyboard_layout_dialog_setup_button, | |
| new DialogInterface.OnClickListener() { | |
| @Override | |
| public void onClick(DialogInterface dialog, int which) { | |
| onSetupLayoutsButtonClicked(); | |
| } | |
| }) | |
| .setSingleChoiceItems(mAdapter, -1, | |
| new DialogInterface.OnClickListener() { | |
| @Override | |
| public void onClick(DialogInterface dialog, int which) { | |
| onKeyboardLayoutClicked(which); | |
| } | |
| }) | |
| .setView(inflater.inflate(R.layout.keyboard_layout_dialog_switch_hint, null)); | |
| updateSwitchHintVisibility(); | |
| return builder.create(); | |
| } | |
| @Override | |
| public void onResume() { | |
| super.onResume(); | |
| mIm.registerInputDeviceListener(this, null); | |
| InputDevice inputDevice = | |
| mIm.getInputDeviceByDescriptor(mInputDeviceIdentifier.getDescriptor()); | |
| if (inputDevice == null) { | |
| dismiss(); | |
| return; | |
| } | |
| mInputDeviceId = inputDevice.getId(); | |
| } | |
| @Override | |
| public void onPause() { | |
| mIm.unregisterInputDeviceListener(this); | |
| mInputDeviceId = -1; | |
| super.onPause(); | |
| } | |
| @Override | |
| public void onCancel(DialogInterface dialog) { | |
| super.onCancel(dialog); | |
| dismiss(); | |
| } | |
| private void onSetupLayoutsButtonClicked() { | |
| ((OnSetupKeyboardLayoutsListener)getTargetFragment()).onSetupKeyboardLayouts( | |
| mInputDeviceIdentifier); | |
| } | |
| @Override | |
| public void onActivityResult(int requestCode, int resultCode, Intent data) { | |
| super.onActivityResult(requestCode, resultCode, data); | |
| show(getActivity().getFragmentManager(), "layout"); | |
| } | |
| private void onKeyboardLayoutClicked(int which) { | |
| if (which >= 0 && which < mAdapter.getCount()) { | |
| KeyboardLayout keyboardLayout = mAdapter.getItem(which); | |
| if (keyboardLayout != null) { | |
| mIm.setCurrentKeyboardLayoutForInputDevice(mInputDeviceIdentifier, | |
| keyboardLayout.getDescriptor()); | |
| } | |
| dismiss(); | |
| } | |
| } | |
| @Override | |
| public Loader<Keyboards> onCreateLoader(int id, Bundle args) { | |
| return new KeyboardLayoutLoader(getActivity().getBaseContext(), mInputDeviceIdentifier); | |
| } | |
| @Override | |
| public void onLoadFinished(Loader<Keyboards> loader, Keyboards data) { | |
| mAdapter.clear(); | |
| mAdapter.addAll(data.keyboardLayouts); | |
| mAdapter.setCheckedItem(data.current); | |
| AlertDialog dialog = (AlertDialog)getDialog(); | |
| if (dialog != null) { | |
| dialog.getListView().setItemChecked(data.current, true); | |
| } | |
| updateSwitchHintVisibility(); | |
| showSetupKeyboardLayoutsIfNecessary(); | |
| } | |
| @Override | |
| public void onLoaderReset(Loader<Keyboards> loader) { | |
| mAdapter.clear(); | |
| updateSwitchHintVisibility(); | |
| } | |
| @Override | |
| public void onInputDeviceAdded(int deviceId) { | |
| } | |
| @Override | |
| public void onInputDeviceChanged(int deviceId) { | |
| if (mInputDeviceId >= 0 && deviceId == mInputDeviceId) { | |
| getLoaderManager().restartLoader(0, null, this); | |
| } | |
| } | |
| @Override | |
| public void onInputDeviceRemoved(int deviceId) { | |
| if (mInputDeviceId >= 0 && deviceId == mInputDeviceId) { | |
| dismiss(); | |
| } | |
| } | |
| private void updateSwitchHintVisibility() { | |
| AlertDialog dialog = (AlertDialog)getDialog(); | |
| if (dialog != null) { | |
| View customPanel = dialog.findViewById(com.android.internal.R.id.customPanel); | |
| customPanel.setVisibility(mAdapter.getCount() > 1 ? View.VISIBLE : View.GONE); | |
| } | |
| } | |
| private void showSetupKeyboardLayoutsIfNecessary() { | |
| AlertDialog dialog = (AlertDialog)getDialog(); | |
| if (dialog != null | |
| && mAdapter.getCount() == 1 && mAdapter.getItem(0) == null | |
| && !mHasShownLayoutSelectionScreen) { | |
| mHasShownLayoutSelectionScreen = true; | |
| ((OnSetupKeyboardLayoutsListener)getTargetFragment()).onSetupKeyboardLayouts( | |
| mInputDeviceIdentifier); | |
| } | |
| } | |
| private static final class KeyboardLayoutAdapter extends ArrayAdapter<KeyboardLayout> { | |
| private final LayoutInflater mInflater; | |
| private int mCheckedItem = -1; | |
| public KeyboardLayoutAdapter(Context context) { | |
| super(context, com.android.internal.R.layout.simple_list_item_2_single_choice); | |
| mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); | |
| } | |
| public void setCheckedItem(int position) { | |
| mCheckedItem = position; | |
| } | |
| @Override | |
| public View getView(int position, View convertView, ViewGroup parent) { | |
| KeyboardLayout item = getItem(position); | |
| String label, collection; | |
| if (item != null) { | |
| label = item.getLabel(); | |
| collection = item.getCollection(); | |
| } else { | |
| label = getContext().getString(R.string.keyboard_layout_default_label); | |
| collection = ""; | |
| } | |
| boolean checked = (position == mCheckedItem); | |
| if (collection.isEmpty()) { | |
| return inflateOneLine(convertView, parent, label, checked); | |
| } else { | |
| return inflateTwoLine(convertView, parent, label, collection, checked); | |
| } | |
| } | |
| private View inflateOneLine(View convertView, ViewGroup parent, | |
| String label, boolean checked) { | |
| View view = convertView; | |
| if (view == null || isTwoLine(view)) { | |
| view = mInflater.inflate( | |
| com.android.internal.R.layout.simple_list_item_single_choice, | |
| parent, false); | |
| setTwoLine(view, false); | |
| } | |
| CheckedTextView headline = (CheckedTextView) view.findViewById(android.R.id.text1); | |
| headline.setText(label); | |
| headline.setChecked(checked); | |
| return view; | |
| } | |
| private View inflateTwoLine(View convertView, ViewGroup parent, | |
| String label, String collection, boolean checked) { | |
| View view = convertView; | |
| if (view == null || !isTwoLine(view)) { | |
| view = mInflater.inflate( | |
| com.android.internal.R.layout.simple_list_item_2_single_choice, | |
| parent, false); | |
| setTwoLine(view, true); | |
| } | |
| TextView headline = (TextView) view.findViewById(android.R.id.text1); | |
| TextView subText = (TextView) view.findViewById(android.R.id.text2); | |
| RadioButton radioButton = | |
| (RadioButton)view.findViewById(com.android.internal.R.id.radio); | |
| headline.setText(label); | |
| subText.setText(collection); | |
| radioButton.setChecked(checked); | |
| return view; | |
| } | |
| private static boolean isTwoLine(View view) { | |
| return view.getTag() == Boolean.TRUE; | |
| } | |
| private static void setTwoLine(View view, boolean twoLine) { | |
| view.setTag(Boolean.valueOf(twoLine)); | |
| } | |
| } | |
| private static final class KeyboardLayoutLoader extends AsyncTaskLoader<Keyboards> { | |
| private final InputDeviceIdentifier mInputDeviceIdentifier; | |
| public KeyboardLayoutLoader(Context context, InputDeviceIdentifier inputDeviceIdentifier) { | |
| super(context); | |
| mInputDeviceIdentifier = inputDeviceIdentifier; | |
| } | |
| @Override | |
| public Keyboards loadInBackground() { | |
| Keyboards keyboards = new Keyboards(); | |
| InputManager im = (InputManager)getContext().getSystemService(Context.INPUT_SERVICE); | |
| String[] keyboardLayoutDescriptors = im.getEnabledKeyboardLayoutsForInputDevice( | |
| mInputDeviceIdentifier); | |
| for (String keyboardLayoutDescriptor : keyboardLayoutDescriptors) { | |
| KeyboardLayout keyboardLayout = im.getKeyboardLayout(keyboardLayoutDescriptor); | |
| if (keyboardLayout != null) { | |
| keyboards.keyboardLayouts.add(keyboardLayout); | |
| } | |
| } | |
| Collections.sort(keyboards.keyboardLayouts); | |
| String currentKeyboardLayoutDescriptor = | |
| im.getCurrentKeyboardLayoutForInputDevice(mInputDeviceIdentifier); | |
| if (currentKeyboardLayoutDescriptor != null) { | |
| final int numKeyboardLayouts = keyboards.keyboardLayouts.size(); | |
| for (int i = 0; i < numKeyboardLayouts; i++) { | |
| if (keyboards.keyboardLayouts.get(i).getDescriptor().equals( | |
| currentKeyboardLayoutDescriptor)) { | |
| keyboards.current = i; | |
| break; | |
| } | |
| } | |
| } | |
| if (keyboards.keyboardLayouts.isEmpty()) { | |
| keyboards.keyboardLayouts.add(null); // default layout | |
| keyboards.current = 0; | |
| } | |
| return keyboards; | |
| } | |
| @Override | |
| protected void onStartLoading() { | |
| super.onStartLoading(); | |
| forceLoad(); | |
| } | |
| @Override | |
| protected void onStopLoading() { | |
| super.onStopLoading(); | |
| cancelLoad(); | |
| } | |
| } | |
| public static final class Keyboards { | |
| public final ArrayList<KeyboardLayout> keyboardLayouts = new ArrayList<KeyboardLayout>(); | |
| public int current = -1; | |
| } | |
| public interface OnSetupKeyboardLayoutsListener { | |
| public void onSetupKeyboardLayouts(InputDeviceIdentifier mInputDeviceIdentifier); | |
| } | |
| } |