KeyboardLayoutDialogFragment.java revision 813a54d216010a16d714355c61d606dd3eb589aa
1/* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.settings.inputmethod; 18 19import com.android.settings.R; 20import com.android.settings.Settings.KeyboardLayoutPickerActivity; 21 22import android.app.AlertDialog; 23import android.app.Activity; 24import android.app.Dialog; 25import android.app.DialogFragment; 26import android.app.LoaderManager.LoaderCallbacks; 27import android.content.AsyncTaskLoader; 28import android.content.Context; 29import android.content.DialogInterface; 30import android.content.Intent; 31import android.content.Loader; 32import android.content.res.Resources; 33import android.hardware.input.InputDeviceIdentifier; 34import android.hardware.input.InputManager; 35import android.hardware.input.KeyboardLayout; 36import android.hardware.input.InputManager.InputDeviceListener; 37import android.os.Bundle; 38import android.view.InputDevice; 39import android.view.LayoutInflater; 40import android.view.View; 41import android.view.ViewGroup; 42import android.widget.ArrayAdapter; 43import android.widget.CheckedTextView; 44import android.widget.RadioButton; 45import android.widget.TextView; 46 47import java.util.ArrayList; 48import java.util.Collections; 49 50public class KeyboardLayoutDialogFragment extends DialogFragment 51 implements InputDeviceListener, LoaderCallbacks<KeyboardLayoutDialogFragment.Keyboards> { 52 private static final String KEY_INPUT_DEVICE_IDENTIFIER = "inputDeviceIdentifier"; 53 54 private InputDeviceIdentifier mInputDeviceIdentifier; 55 private int mInputDeviceId = -1; 56 private InputManager mIm; 57 private KeyboardLayoutAdapter mAdapter; 58 59 public KeyboardLayoutDialogFragment() { 60 } 61 62 public KeyboardLayoutDialogFragment(InputDeviceIdentifier inputDeviceIdentifier) { 63 mInputDeviceIdentifier = inputDeviceIdentifier; 64 } 65 66 @Override 67 public void onAttach(Activity activity) { 68 super.onAttach(activity); 69 70 Context context = activity.getBaseContext(); 71 mIm = (InputManager)context.getSystemService(Context.INPUT_SERVICE); 72 mAdapter = new KeyboardLayoutAdapter(context); 73 } 74 75 @Override 76 public void onCreate(Bundle savedInstanceState) { 77 super.onCreate(savedInstanceState); 78 79 if (savedInstanceState != null) { 80 mInputDeviceIdentifier = savedInstanceState.getParcelable(KEY_INPUT_DEVICE_IDENTIFIER); 81 } 82 83 getLoaderManager().initLoader(0, null, this); 84 } 85 86 @Override 87 public void onSaveInstanceState(Bundle outState) { 88 super.onSaveInstanceState(outState); 89 outState.putParcelable(KEY_INPUT_DEVICE_IDENTIFIER, mInputDeviceIdentifier); 90 } 91 92 @Override 93 public Dialog onCreateDialog(Bundle savedInstanceState) { 94 Context context = getActivity(); 95 LayoutInflater inflater = LayoutInflater.from(context); 96 AlertDialog.Builder builder = new AlertDialog.Builder(context) 97 .setTitle(R.string.keyboard_layout_dialog_title) 98 .setPositiveButton(R.string.keyboard_layout_dialog_setup_button, 99 new DialogInterface.OnClickListener() { 100 @Override 101 public void onClick(DialogInterface dialog, int which) { 102 onSetupLayoutsButtonClicked(); 103 } 104 }) 105 .setSingleChoiceItems(mAdapter, -1, 106 new DialogInterface.OnClickListener() { 107 @Override 108 public void onClick(DialogInterface dialog, int which) { 109 onKeyboardLayoutClicked(which); 110 } 111 }) 112 .setView(inflater.inflate(R.layout.keyboard_layout_dialog_switch_hint, null)); 113 updateSwitchHintVisibility(); 114 return builder.create(); 115 } 116 117 @Override 118 public void onResume() { 119 super.onResume(); 120 121 mIm.registerInputDeviceListener(this, null); 122 123 InputDevice inputDevice = 124 mIm.getInputDeviceByDescriptor(mInputDeviceIdentifier.getDescriptor()); 125 if (inputDevice == null) { 126 dismiss(); 127 return; 128 } 129 mInputDeviceId = inputDevice.getId(); 130 } 131 132 @Override 133 public void onPause() { 134 mIm.unregisterInputDeviceListener(this); 135 mInputDeviceId = -1; 136 137 super.onPause(); 138 } 139 140 @Override 141 public void onCancel(DialogInterface dialog) { 142 super.onCancel(dialog); 143 dismiss(); 144 } 145 146 private void onSetupLayoutsButtonClicked() { 147 ((OnSetupKeyboardLayoutsListener)getTargetFragment()).onSetupKeyboardLayouts( 148 mInputDeviceIdentifier); 149 } 150 151 @Override 152 public void onActivityResult(int requestCode, int resultCode, Intent data) { 153 super.onActivityResult(requestCode, resultCode, data); 154 show(getActivity().getFragmentManager(), "layout"); 155 } 156 157 private void onKeyboardLayoutClicked(int which) { 158 if (which >= 0 && which < mAdapter.getCount()) { 159 KeyboardLayout keyboardLayout = mAdapter.getItem(which); 160 if (keyboardLayout != null) { 161 mIm.setCurrentKeyboardLayoutForInputDevice(mInputDeviceIdentifier, 162 keyboardLayout.getDescriptor()); 163 } 164 dismiss(); 165 } 166 } 167 168 @Override 169 public Loader<Keyboards> onCreateLoader(int id, Bundle args) { 170 return new KeyboardLayoutLoader(getActivity().getBaseContext(), mInputDeviceIdentifier); 171 } 172 173 @Override 174 public void onLoadFinished(Loader<Keyboards> loader, Keyboards data) { 175 mAdapter.clear(); 176 mAdapter.addAll(data.keyboardLayouts); 177 mAdapter.setCheckedItem(data.current); 178 AlertDialog dialog = (AlertDialog)getDialog(); 179 if (dialog != null) { 180 dialog.getListView().setItemChecked(data.current, true); 181 } 182 updateSwitchHintVisibility(); 183 } 184 185 @Override 186 public void onLoaderReset(Loader<Keyboards> loader) { 187 mAdapter.clear(); 188 updateSwitchHintVisibility(); 189 } 190 191 @Override 192 public void onInputDeviceAdded(int deviceId) { 193 } 194 195 @Override 196 public void onInputDeviceChanged(int deviceId) { 197 if (mInputDeviceId >= 0 && deviceId == mInputDeviceId) { 198 getLoaderManager().restartLoader(0, null, this); 199 } 200 } 201 202 @Override 203 public void onInputDeviceRemoved(int deviceId) { 204 if (mInputDeviceId >= 0 && deviceId == mInputDeviceId) { 205 dismiss(); 206 } 207 } 208 209 private void updateSwitchHintVisibility() { 210 AlertDialog dialog = (AlertDialog)getDialog(); 211 if (dialog != null) { 212 View customPanel = dialog.findViewById(com.android.internal.R.id.customPanel); 213 customPanel.setVisibility(mAdapter.getCount() > 1 ? View.VISIBLE : View.GONE); 214 } 215 } 216 217 private static final class KeyboardLayoutAdapter extends ArrayAdapter<KeyboardLayout> { 218 private final LayoutInflater mInflater; 219 private int mCheckedItem = -1; 220 221 public KeyboardLayoutAdapter(Context context) { 222 super(context, com.android.internal.R.layout.simple_list_item_2_single_choice); 223 mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 224 } 225 226 public void setCheckedItem(int position) { 227 mCheckedItem = position; 228 } 229 230 @Override 231 public View getView(int position, View convertView, ViewGroup parent) { 232 KeyboardLayout item = getItem(position); 233 String label, collection; 234 if (item != null) { 235 label = item.getLabel(); 236 collection = item.getCollection(); 237 } else { 238 label = getContext().getString(R.string.keyboard_layout_default_label); 239 collection = ""; 240 } 241 242 boolean checked = (position == mCheckedItem); 243 if (collection.isEmpty()) { 244 return inflateOneLine(convertView, parent, label, checked); 245 } else { 246 return inflateTwoLine(convertView, parent, label, collection, checked); 247 } 248 } 249 250 private View inflateOneLine(View convertView, ViewGroup parent, 251 String label, boolean checked) { 252 View view = convertView; 253 if (view == null || isTwoLine(view)) { 254 view = mInflater.inflate( 255 com.android.internal.R.layout.simple_list_item_single_choice, 256 parent, false); 257 setTwoLine(view, false); 258 } 259 CheckedTextView headline = (CheckedTextView) view.findViewById(android.R.id.text1); 260 headline.setText(label); 261 headline.setChecked(checked); 262 return view; 263 } 264 265 private View inflateTwoLine(View convertView, ViewGroup parent, 266 String label, String collection, boolean checked) { 267 View view = convertView; 268 if (view == null || !isTwoLine(view)) { 269 view = mInflater.inflate( 270 com.android.internal.R.layout.simple_list_item_2_single_choice, 271 parent, false); 272 setTwoLine(view, true); 273 } 274 TextView headline = (TextView) view.findViewById(android.R.id.text1); 275 TextView subText = (TextView) view.findViewById(android.R.id.text2); 276 RadioButton radioButton = 277 (RadioButton)view.findViewById(com.android.internal.R.id.radio); 278 headline.setText(label); 279 subText.setText(collection); 280 radioButton.setChecked(checked); 281 return view; 282 } 283 284 private static boolean isTwoLine(View view) { 285 return view.getTag() == Boolean.TRUE; 286 } 287 288 private static void setTwoLine(View view, boolean twoLine) { 289 view.setTag(Boolean.valueOf(twoLine)); 290 } 291 } 292 293 private static final class KeyboardLayoutLoader extends AsyncTaskLoader<Keyboards> { 294 private final InputDeviceIdentifier mInputDeviceIdentifier; 295 296 public KeyboardLayoutLoader(Context context, InputDeviceIdentifier inputDeviceIdentifier) { 297 super(context); 298 mInputDeviceIdentifier = inputDeviceIdentifier; 299 } 300 301 @Override 302 public Keyboards loadInBackground() { 303 Keyboards keyboards = new Keyboards(); 304 InputManager im = (InputManager)getContext().getSystemService(Context.INPUT_SERVICE); 305 String[] keyboardLayoutDescriptors = im.getKeyboardLayoutsForInputDevice( 306 mInputDeviceIdentifier); 307 for (String keyboardLayoutDescriptor : keyboardLayoutDescriptors) { 308 KeyboardLayout keyboardLayout = im.getKeyboardLayout(keyboardLayoutDescriptor); 309 if (keyboardLayout != null) { 310 keyboards.keyboardLayouts.add(keyboardLayout); 311 } 312 } 313 Collections.sort(keyboards.keyboardLayouts); 314 315 String currentKeyboardLayoutDescriptor = 316 im.getCurrentKeyboardLayoutForInputDevice(mInputDeviceIdentifier); 317 if (currentKeyboardLayoutDescriptor != null) { 318 final int numKeyboardLayouts = keyboards.keyboardLayouts.size(); 319 for (int i = 0; i < numKeyboardLayouts; i++) { 320 if (keyboards.keyboardLayouts.get(i).getDescriptor().equals( 321 currentKeyboardLayoutDescriptor)) { 322 keyboards.current = i; 323 break; 324 } 325 } 326 } 327 328 if (keyboards.keyboardLayouts.isEmpty()) { 329 keyboards.keyboardLayouts.add(null); // default layout 330 keyboards.current = 0; 331 } 332 return keyboards; 333 } 334 335 @Override 336 protected void onStartLoading() { 337 super.onStartLoading(); 338 forceLoad(); 339 } 340 341 @Override 342 protected void onStopLoading() { 343 super.onStopLoading(); 344 cancelLoad(); 345 } 346 } 347 348 public static final class Keyboards { 349 public final ArrayList<KeyboardLayout> keyboardLayouts = new ArrayList<KeyboardLayout>(); 350 public int current = -1; 351 } 352 353 public interface OnSetupKeyboardLayoutsListener { 354 public void onSetupKeyboardLayouts(InputDeviceIdentifier mInputDeviceIdentifier); 355 } 356}