/** * MicroEmulator * Copyright (C) 2008 Bartek Teodorczyk <barteo@barteo.net> * * It is licensed under the following two licenses as alternatives: * 1. GNU Lesser General Public License (the "LGPL") version 2.1 or any newer version * 2. Apache License (the "AL") Version 2.0 * * You may not use this file except in compliance with at least one of * the above two licenses. * * You may obtain a copy of the LGPL at * http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt * * You may obtain a copy of the AL 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 LGPL or the AL for the specific language governing permissions and * limitations. * * @version $Id: AndroidTextBoxUI.java 2450 2010-12-07 13:55:14Z barteo@gmail.com $ */ package org.microemu.android.device.ui; import javax.microedition.lcdui.TextBox; import javax.microedition.lcdui.TextField; import javax.microedition.lcdui.Command; import android.view.View; import android.widget.*; import org.microemu.DisplayAccess; import org.microemu.MIDletBridge; import org.microemu.android.MicroEmulatorActivity; import org.microemu.device.ui.CommandUI; import org.microemu.device.ui.TextBoxUI; import android.content.Context; import android.content.res.Configuration; import android.content.res.Resources; import android.graphics.Typeface; import android.text.InputType; import android.text.method.PasswordTransformationMethod; import android.view.Gravity; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputConnection; import android.view.inputmethod.InputMethodManager; import java.util.Collections; import java.util.Comparator; import java.util.Vector; public class AndroidTextBoxUI extends AndroidDisplayableUI<TextBox> implements TextBoxUI { private View view; private EditText editView; private TableLayout commandGrid; private TextView titleView; public AndroidTextBoxUI(final MicroEmulatorActivity activity, final TextBox textBox) { super(activity, textBox); activity.post(new Runnable() { public void run() { view = createMainView(); } }); } public void invalidate() { activity.post(new Runnable() { public void run() { titleView.setText(displayable.getTitle()); } }); } private LinearLayout createMainView() { titleView = new TextView(activity); titleView.setText(displayable.getTitle()); commandGrid = new TableLayout(activity); editView = createEditor(activity, displayable); editView.setGravity(Gravity.TOP); editView.setScroller(new Scroller(activity)); editView.setVerticalScrollBarEnabled(true); titleView.setId(2); editView.setId(3); commandGrid.setId(4); initCommands(); RelativeLayout layout = new RelativeLayout(activity); layout.addView(editView, set(create(RelativeLayout.LayoutParams.FILL_PARENT), RelativeLayout.ABOVE, commandGrid.getId())); layout.addView(commandGrid, set(create(RelativeLayout.LayoutParams.WRAP_CONTENT), RelativeLayout.ALIGN_PARENT_BOTTOM)); LinearLayout all = new LinearLayout(activity); all.setOrientation(LinearLayout.VERTICAL); all.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.FILL_PARENT, LinearLayout.LayoutParams.FILL_PARENT)); all.addView(titleView, createLinear(LinearLayout.LayoutParams.WRAP_CONTENT)); all.addView(layout, createLinear(LinearLayout.LayoutParams.FILL_PARENT)); return all; } private LinearLayout.LayoutParams createLinear(int h) { return new LinearLayout.LayoutParams(LinearLayout.LayoutParams.FILL_PARENT, h); } private RelativeLayout.LayoutParams create(int h) { return new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.FILL_PARENT, h); } private RelativeLayout.LayoutParams set(RelativeLayout.LayoutParams params, int verb, int anchor) { params.addRule(verb, anchor); return params; } private RelativeLayout.LayoutParams set(RelativeLayout.LayoutParams params, int verb) { params.addRule(verb); return params; } private void turnKeyboard(final EditText textEditor, final boolean on) { activity.post(new Runnable() { @Override public void run() { if (on) { Configuration conf = Resources.getSystem().getConfiguration(); if (conf.hardKeyboardHidden != Configuration.HARDKEYBOARDHIDDEN_NO) { getInputMethodManager().showSoftInput(textEditor, InputMethodManager.SHOW_FORCED | InputMethodManager.SHOW_IMPLICIT); } } else { //getInputMethodManager().hideSoftInputFromWindow(textEditor.getWindowToken(), // InputMethodManager.HIDE_IMPLICIT_ONLY | InputMethodManager.HIDE_NOT_ALWAYS); getInputMethodManager().hideSoftInputFromWindow(textEditor.getWindowToken(), 0); } } }); } private EditText createEditor(final MicroEmulatorActivity activity, final TextBox textBox) { final EditText editor = new EditText(activity) { @Override public InputConnection onCreateInputConnection(EditorInfo outAttrs) { InputConnection connection = super.onCreateInputConnection(outAttrs); //showNotify(); return connection; } @Override protected void onWindowVisibilityChanged(int visibility) { if (View.VISIBLE != visibility) { turnKeyboard(this, View.VISIBLE == visibility); } super.onWindowVisibilityChanged(visibility); if (View.VISIBLE == visibility) { turnKeyboard(this, View.VISIBLE == visibility); } } }; int constraints = textBox.getConstraints(); if ((constraints & TextField.CONSTRAINT_MASK) == TextField.URL) { editor.setSingleLine(true); } else if ((constraints & TextField.CONSTRAINT_MASK) == TextField.NUMERIC) { editor.setSingleLine(true); editor.setInputType(InputType.TYPE_CLASS_NUMBER); } else if ((constraints & TextField.CONSTRAINT_MASK) == TextField.DECIMAL) { editor.setSingleLine(true); editor.setInputType(InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_SIGNED | InputType.TYPE_NUMBER_FLAG_DECIMAL); } else if ((constraints & TextField.CONSTRAINT_MASK) == TextField.PHONENUMBER) { editor.setSingleLine(true); editor.setInputType(InputType.TYPE_CLASS_PHONE); } else { editor.setSingleLine(false); editor.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_MULTI_LINE | InputType.TYPE_TEXT_FLAG_CAP_SENTENCES); } if ((constraints & TextField.PASSWORD) != 0) { editor.setTransformationMethod(PasswordTransformationMethod.getInstance()); editor.setTypeface(Typeface.MONOSPACE); } /* editor.addTextChangedListener(new TextWatcher() { private String previousText; public void afterTextChanged(Editable s) { } public void beforeTextChanged(CharSequence s, int start, int count, int after) { previousText = s.toString(); } public void onTextChanged(CharSequence s, int start, int before, int count) { if (s.toString().length() <= textBox.getMaxSize() && InputMethod.validate(s.toString(), textBox.getConstraints())) { } else { editor.setText(previousText); editor.setSelection(start); } } }); */ return editor; } @Override public void showNotify() { activity.post(new Runnable() { @Override public void run() { if (null == view) { EditText old = editView; view = createMainView(); editView.setText(old.getText().toString()); editView.setSelection(old.getSelectionEnd()); } activity.setContentView(view); view.requestLayout(); view.requestFocus(); turnKeyboard(editView, true); //getInputMethodManager().hideSoftInputFromWindow(editView.getWindowToken(), // InputMethodManager.HIDE_IMPLICIT_ONLY | InputMethodManager.HIDE_NOT_ALWAYS); //turnKeyboard(editView, true); } }); } @Override public void hideNotify() { activity.post(new Runnable() { @Override public void run() { view = null; } }); } private InputMethodManager getInputMethodManager() { return (InputMethodManager) activity.getSystemService(Context.INPUT_METHOD_SERVICE); } // // TextBoxUI // public int getCaretPosition() { return editView.getSelectionStart(); } public String getString() { final String[] getStringTransfer = new String[1]; if (activity.isActivityThread()) { getStringTransfer[0] = editView.getText().toString(); } else { getStringTransfer[0] = null; activity.post(new Runnable() { public void run() { synchronized (AndroidTextBoxUI.this) { getStringTransfer[0] = editView.getText().toString(); AndroidTextBoxUI.this.notify(); } } }); synchronized (AndroidTextBoxUI.this) { if (getStringTransfer[0] == null) { try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } } return getStringTransfer[0]; } public void setString(final String text) { activity.post(new Runnable() { public void run() { editView.setText(text); if (text != null) { editView.setSelection(text.length()); } } }); } public void insert(final String text, final int position) { activity.post(new Runnable() { public void run() { String newtext = getString(); if (position > 0) { newtext = newtext.substring(0, position) + text + newtext.substring(position); } else { newtext = text + newtext; } editView.setText(newtext); editView.setSelection(position + text.length()); } }); } public void delete(final int offset, final int length) { activity.post(new Runnable() { public void run() { String newtext = getString(); if (offset > 0) { newtext = newtext.substring(0, offset) + newtext.substring(offset + length); } else { newtext = newtext.substring(length); } editView.setText(newtext); editView.setSelection(offset); } }); } private final Commands commands = new Commands(); public Commands getCommandsUI() { synchronized (this) { return new Commands(commands); } } public void addCommandUI(CommandUI cmd) { synchronized (this) { if (!commands.contains(cmd)) { commands.add((AndroidCommandUI) cmd); } // TODO decide whether this is the best way for keeping sorted commands Collections.sort(commands, commandsPriorityComparator); initCommands(); } } public void removeCommandUI(CommandUI cmd) { synchronized (this) { commands.remove(cmd); initCommands(); } } private void initCommands() { activity.post(new Runnable() { public void run() { TableLayout table = commandGrid; table.setStretchAllColumns(true); table.removeAllViews(); LinearLayout row = createRow(table); Vector<AndroidCommandUI> commands = getCommandsUI(); for (AndroidCommandUI c : commands) { if (Command.SCREEN != c.getCommand().getCommandType()) continue; if (3 == row.getChildCount()) { row = createRow(table); } addToRow(row, createButton(row.getContext(), c)); } for (AndroidCommandUI c : commands) { if (Command.OK != c.getCommand().getCommandType()) continue; if (3 == row.getChildCount()) { row = createRow(table); } addToRow(row, createButton(row.getContext(), c)); } } }); } private LinearLayout createRow(TableLayout table) { LinearLayout row = new LinearLayout(table.getContext()); row.setOrientation(LinearLayout.HORIZONTAL); table.addView(row, new TableRow.LayoutParams( TableRow.LayoutParams.FILL_PARENT, TableRow.LayoutParams.FILL_PARENT, 1.0f)); return row; } private void addToRow(TableRow row, View view) { row.addView(view, new TableRow.LayoutParams( TableRow.LayoutParams.FILL_PARENT, TableRow.LayoutParams.FILL_PARENT, 1.0f)); } private void addToRow(LinearLayout row, View view) { row.addView(view, new LinearLayout.LayoutParams( LinearLayout.LayoutParams.FILL_PARENT, LinearLayout.LayoutParams.FILL_PARENT, 1.0f)); } private Button createButton(Context context, final AndroidCommandUI c) { Button button = new Button(context); button.setText(c.getCommand().getLabel()); button.setCompoundDrawables(c.getDrawable(), null, null, null); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { execCommand(c); } }); return button; } private boolean execCommand(CommandUI c) { try { final DisplayAccess da = MIDletBridge.getMIDletAccess().getDisplayAccess(); AndroidDisplayableUI ui = (AndroidDisplayableUI) da.getDisplayableUI(da.getCurrent()); da.commandAction(c.getCommand(), da.getCurrent()); return true; } catch (Exception e) { // Exception when: // MIDletBridge.getMIDletAccess() is null // MIDletBridge.getMIDletAccess().getDisplayAccess() is null // da.getDisplayableUI(da.getCurrent()) is null // Exception in commandAction return false; } } private static Comparator<CommandUI> commandsPriorityComparator = new Comparator<CommandUI>() { public int compare(CommandUI first, CommandUI second) { if (first.getCommand().getPriority() == second.getCommand().getPriority()) { return 0; } else if (first.getCommand().getPriority() < second.getCommand().getPriority()) { return -1; } else { return 1; } } }; }