1410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey/* 2410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey * Copyright (C) 2013 The Android Open Source Project 3410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey * 4410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey * Licensed under the Apache License, Version 2.0 (the "License"); 5410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey * you may not use this file except in compliance with the License. 6410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey * You may obtain a copy of the License at 7410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey * 8410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey * http://www.apache.org/licenses/LICENSE-2.0 9410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey * 10410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey * Unless required by applicable law or agreed to in writing, software 11410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey * distributed under the License is distributed on an "AS IS" BASIS, 12410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey * See the License for the specific language governing permissions and 14410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey * limitations under the License. 15410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey */ 16410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey 17410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkeypackage com.android.terminal; 18410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey 1900b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkeyimport static com.android.terminal.Terminal.TAG; 2000b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey 21410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkeyimport android.content.Context; 22410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkeyimport android.graphics.Paint; 23410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkeyimport android.graphics.Paint.FontMetrics; 24479bd643981271fb0edf756ae5915e44a7352c4dJeff Sharkeyimport android.graphics.Typeface; 2500b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkeyimport android.os.Parcelable; 2600b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkeyimport android.util.AttributeSet; 27410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkeyimport android.util.Log; 2800b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkeyimport android.view.KeyEvent; 2900b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkeyimport android.view.View; 3000b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkeyimport android.view.ViewGroup; 3126c9bb3a573b236f009654903461e496410a4147Michael Wrightimport android.view.inputmethod.BaseInputConnection; 3226c9bb3a573b236f009654903461e496410a4147Michael Wrightimport android.view.inputmethod.EditorInfo; 3326c9bb3a573b236f009654903461e496410a4147Michael Wrightimport android.view.inputmethod.InputConnection; 341c4704e650a86914e3afdc57ce9df4f95d7c7d44Tom Marshallimport android.view.inputmethod.InputMethodManager; 351c4704e650a86914e3afdc57ce9df4f95d7c7d44Tom Marshallimport android.widget.AdapterView; 3600b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkeyimport android.widget.BaseAdapter; 3700b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkeyimport android.widget.ListView; 38410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey 39a76e33884c55bbd5db7e512b7687210cc3f635cfJeff Sharkeyimport com.android.terminal.Terminal.CellRun; 40410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkeyimport com.android.terminal.Terminal.TerminalClient; 41410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey 42410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey/** 43410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey * Rendered contents of a {@link Terminal} session. 44410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey */ 4500b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkeypublic class TerminalView extends ListView { 46de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey private static final boolean LOGD = true; 47410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey 4800b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey private static final boolean SCROLL_ON_DAMAGE = false; 4900b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey private static final boolean SCROLL_ON_INPUT = true; 5000b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey 5100b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey private Terminal mTerm; 52a76e33884c55bbd5db7e512b7687210cc3f635cfJeff Sharkey 5300b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey private boolean mScrolled; 54410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey 5500b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey private int mRows; 5600b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey private int mCols; 5700b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey private int mScrollRows; 58410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey 5900b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey private final TerminalMetrics mMetrics = new TerminalMetrics(); 6000b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey private final TerminalKeys mTermKeys = new TerminalKeys(); 61a76e33884c55bbd5db7e512b7687210cc3f635cfJeff Sharkey 6200b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey /** 6300b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey * Metrics shared between all {@link TerminalLineView} children. Locking 6400b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey * provided by main thread. 6500b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey */ 6600b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey static class TerminalMetrics { 6700b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey private static final int MAX_RUN_LENGTH = 128; 68de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey 6900b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey final Paint bgPaint = new Paint(); 7000b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey final Paint textPaint = new Paint(); 715b68e8ad082625206492ca9baf889f8c5427eb01Tom Marshall final Paint cursorPaint = new Paint(); 7226c9bb3a573b236f009654903461e496410a4147Michael Wright 7300b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey /** Run of cells used when drawing */ 7400b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey final CellRun run; 7500b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey /** Screen coordinates to draw chars into */ 7600b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey final float[] pos; 77410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey 7800b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey int charTop; 7900b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey int charWidth; 8000b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey int charHeight; 81a76e33884c55bbd5db7e512b7687210cc3f635cfJeff Sharkey 8200b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey public TerminalMetrics() { 8300b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey run = new Terminal.CellRun(); 8400b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey run.data = new char[MAX_RUN_LENGTH]; 8500b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey 8600b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey // Positions of each possible cell 8700b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey // TODO: make sure this works with surrogate pairs 8800b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey pos = new float[MAX_RUN_LENGTH * 2]; 8900b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey setTextSize(20); 90410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey } 91410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey 9200b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey public void setTextSize(float textSize) { 9300b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey textPaint.setTypeface(Typeface.MONOSPACE); 9400b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey textPaint.setAntiAlias(true); 9500b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey textPaint.setTextSize(textSize); 9600b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey 9700b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey // Read metrics to get exact pixel dimensions 9800b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey final FontMetrics fm = textPaint.getFontMetrics(); 9900b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey charTop = (int) Math.ceil(fm.top); 10000b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey 10100b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey final float[] widths = new float[1]; 10200b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey textPaint.getTextWidths("X", widths); 10300b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey charWidth = (int) Math.ceil(widths[0]); 10400b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey charHeight = (int) Math.ceil(fm.descent - fm.top); 10500b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey 10600b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey // Update drawing positions 10700b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey for (int i = 0; i < MAX_RUN_LENGTH; i++) { 10800b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey pos[i * 2] = i * charWidth; 10900b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey pos[(i * 2) + 1] = -charTop; 11000b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey } 1116a142b6d4831c3841b6be1705fc97c9b75a7c9d1Jeff Sharkey } 11200b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey } 1136a142b6d4831c3841b6be1705fc97c9b75a7c9d1Jeff Sharkey 1141c4704e650a86914e3afdc57ce9df4f95d7c7d44Tom Marshall private final AdapterView.OnItemClickListener mClickListener = new AdapterView.OnItemClickListener() { 1151c4704e650a86914e3afdc57ce9df4f95d7c7d44Tom Marshall @Override 1161c4704e650a86914e3afdc57ce9df4f95d7c7d44Tom Marshall public void onItemClick(AdapterView<?> parent, View v, int pos, long id) { 1171c4704e650a86914e3afdc57ce9df4f95d7c7d44Tom Marshall if (parent.requestFocus()) { 1181c4704e650a86914e3afdc57ce9df4f95d7c7d44Tom Marshall InputMethodManager imm = (InputMethodManager) parent.getContext().getSystemService(Context.INPUT_METHOD_SERVICE); 1191c4704e650a86914e3afdc57ce9df4f95d7c7d44Tom Marshall imm.showSoftInput(parent, InputMethodManager.SHOW_IMPLICIT); 1201c4704e650a86914e3afdc57ce9df4f95d7c7d44Tom Marshall } 1211c4704e650a86914e3afdc57ce9df4f95d7c7d44Tom Marshall } 1221c4704e650a86914e3afdc57ce9df4f95d7c7d44Tom Marshall }; 1231c4704e650a86914e3afdc57ce9df4f95d7c7d44Tom Marshall 12400b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey private final Runnable mDamageRunnable = new Runnable() { 1256a142b6d4831c3841b6be1705fc97c9b75a7c9d1Jeff Sharkey @Override 12600b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey public void run() { 12700b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey invalidateViews(); 12800b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey if (SCROLL_ON_DAMAGE) { 12900b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey scrollToBottom(true); 13000b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey } 131410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey } 132410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey }; 133410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey 134de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey public TerminalView(Context context) { 13500b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey this(context, null); 13600b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey } 137a76e33884c55bbd5db7e512b7687210cc3f635cfJeff Sharkey 13800b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey public TerminalView(Context context, AttributeSet attrs) { 13900b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey this(context, attrs, com.android.internal.R.attr.listViewStyle); 14000b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey } 141a76e33884c55bbd5db7e512b7687210cc3f635cfJeff Sharkey 14200b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey public TerminalView(Context context, AttributeSet attrs, int defStyle) { 14300b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey super(context, attrs, defStyle); 144410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey 14500b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey setBackground(null); 14600b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey setDivider(null); 14726c9bb3a573b236f009654903461e496410a4147Michael Wright 14826c9bb3a573b236f009654903461e496410a4147Michael Wright setFocusable(true); 14926c9bb3a573b236f009654903461e496410a4147Michael Wright setFocusableInTouchMode(true); 15026c9bb3a573b236f009654903461e496410a4147Michael Wright 15100b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey setAdapter(mAdapter); 15200b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey setOnKeyListener(mKeyListener); 1531c4704e650a86914e3afdc57ce9df4f95d7c7d44Tom Marshall 1541c4704e650a86914e3afdc57ce9df4f95d7c7d44Tom Marshall setOnItemClickListener(mClickListener); 155410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey } 156410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey 15700b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey private final BaseAdapter mAdapter = new BaseAdapter() { 15800b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey @Override 15900b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey public View getView(int position, View convertView, ViewGroup parent) { 16000b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey final TerminalLineView view; 16100b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey if (convertView != null) { 16200b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey view = (TerminalLineView) convertView; 16300b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey } else { 16400b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey view = new TerminalLineView(parent.getContext(), mTerm, mMetrics); 16500b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey } 16600b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey 16700b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey view.pos = position; 16800b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey view.row = posToRow(position); 16900b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey view.cols = mCols; 17000b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey return view; 171de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey } 172de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey 17300b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey @Override 17400b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey public long getItemId(int position) { 17500b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey return position; 176de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey } 177410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey 17800b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey @Override 17900b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey public Object getItem(int position) { 18000b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey return null; 181de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey } 182410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey 18300b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey @Override 18400b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey public int getCount() { 18500b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey if (mTerm != null) { 18600b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey return mRows + mScrollRows; 18700b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey } else { 18800b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey return 0; 18900b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey } 190a76e33884c55bbd5db7e512b7687210cc3f635cfJeff Sharkey } 19100b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey }; 192a76e33884c55bbd5db7e512b7687210cc3f635cfJeff Sharkey 19300b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey private TerminalClient mClient = new TerminalClient() { 19400b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey @Override 19500b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey public void onDamage(final int startRow, final int endRow, int startCol, int endCol) { 19600b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey post(mDamageRunnable); 19700b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey } 198410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey 19900b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey @Override 20000b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey public void onMoveRect(int destStartRow, int destEndRow, int destStartCol, int destEndCol, 20100b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey int srcStartRow, int srcEndRow, int srcStartCol, int srcEndCol) { 20200b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey post(mDamageRunnable); 203410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey } 204410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey 20500b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey @Override 2065b68e8ad082625206492ca9baf889f8c5427eb01Tom Marshall public void onMoveCursor(int posRow, int posCol, int oldPosRow, int oldPosCol, int visible) { 2075b68e8ad082625206492ca9baf889f8c5427eb01Tom Marshall post(mDamageRunnable); 2085b68e8ad082625206492ca9baf889f8c5427eb01Tom Marshall } 2095b68e8ad082625206492ca9baf889f8c5427eb01Tom Marshall 2105b68e8ad082625206492ca9baf889f8c5427eb01Tom Marshall @Override 21100b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey public void onBell() { 21200b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey Log.i(TAG, "DING!"); 213410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey } 21400b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey }; 21500b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey 21600b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey private int rowToPos(int row) { 21700b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey return row + mScrollRows; 218410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey } 219410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey 22000b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey private int posToRow(int pos) { 22100b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey return pos - mScrollRows; 22200b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey } 223410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey 22400b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey private View.OnKeyListener mKeyListener = new OnKeyListener() { 22500b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey @Override 22600b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey public boolean onKey(View v, int keyCode, KeyEvent event) { 22700b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey final boolean res = mTermKeys.onKey(v, keyCode, event); 22800b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey if (res && SCROLL_ON_INPUT) { 22900b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey scrollToBottom(true); 23000b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey } 23100b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey return res; 232de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey } 23300b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey }; 234de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey 23500b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey @Override 23600b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey public void onRestoreInstanceState(Parcelable state) { 23700b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey super.onRestoreInstanceState(state); 23800b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey mScrolled = true; 23900b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey } 240410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey 24100b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey @Override 24200b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey protected void onAttachedToWindow() { 24300b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey super.onAttachedToWindow(); 24400b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey if (!mScrolled) { 24500b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey scrollToBottom(false); 24600b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey } 24700b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey } 248410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey 24900b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey @Override 25000b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey protected void onSizeChanged(int w, int h, int oldw, int oldh) { 25100b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey super.onSizeChanged(w, h, oldw, oldh); 2529cae0a9616b1b71eac7e762d198fe1da47fea901Jeff Sharkey 25300b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey final int rows = h / mMetrics.charHeight; 25400b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey final int cols = w / mMetrics.charWidth; 25500b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey final int scrollRows = mScrollRows; 2569cae0a9616b1b71eac7e762d198fe1da47fea901Jeff Sharkey 25700b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey final boolean sizeChanged = (rows != mRows || cols != mCols || scrollRows != mScrollRows); 25800b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey if (mTerm != null && sizeChanged) { 25900b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey mTerm.resize(rows, cols, scrollRows); 260410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey 26100b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey mRows = rows; 26200b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey mCols = cols; 26300b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey mScrollRows = scrollRows; 264410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey 26500b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey mAdapter.notifyDataSetChanged(); 26600b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey } 26700b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey } 268410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey 26900b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey public void scrollToBottom(boolean animate) { 27000b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey final int dur = animate ? 250 : 0; 27100b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey smoothScrollToPositionFromTop(getCount(), 0, dur); 27200b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey mScrolled = true; 27300b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey } 2749cae0a9616b1b71eac7e762d198fe1da47fea901Jeff Sharkey 27500b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey public void setTerminal(Terminal term) { 27600b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey final Terminal orig = mTerm; 27700b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey if (orig != null) { 27800b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey orig.setClient(null); 27900b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey } 28000b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey mTerm = term; 28100b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey mScrolled = false; 28200b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey if (term != null) { 28300b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey term.setClient(mClient); 28400b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey mTermKeys.setTerminal(term); 2859cae0a9616b1b71eac7e762d198fe1da47fea901Jeff Sharkey 2865b68e8ad082625206492ca9baf889f8c5427eb01Tom Marshall mMetrics.cursorPaint.setColor(0xfff0f0f0); 2875b68e8ad082625206492ca9baf889f8c5427eb01Tom Marshall 28800b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey // Populate any current settings 28900b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey mRows = mTerm.getRows(); 29000b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey mCols = mTerm.getCols(); 29100b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey mScrollRows = mTerm.getScrollRows(); 29200b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey mAdapter.notifyDataSetChanged(); 29300b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey } 29400b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey } 295410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey 29600b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey public Terminal getTerminal() { 29700b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey return mTerm; 29800b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey } 299410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey 30000b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey public void setTextSize(float textSize) { 30100b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey mMetrics.setTextSize(textSize); 302410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey 30300b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey // Layout will kick off terminal resize when needed 30400b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey requestLayout(); 305410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey } 30626c9bb3a573b236f009654903461e496410a4147Michael Wright 30726c9bb3a573b236f009654903461e496410a4147Michael Wright @Override 30826c9bb3a573b236f009654903461e496410a4147Michael Wright public boolean onCheckIsTextEditor() { 30926c9bb3a573b236f009654903461e496410a4147Michael Wright return true; 31026c9bb3a573b236f009654903461e496410a4147Michael Wright } 31126c9bb3a573b236f009654903461e496410a4147Michael Wright 31226c9bb3a573b236f009654903461e496410a4147Michael Wright @Override 31326c9bb3a573b236f009654903461e496410a4147Michael Wright public InputConnection onCreateInputConnection(EditorInfo outAttrs) { 31426c9bb3a573b236f009654903461e496410a4147Michael Wright outAttrs.imeOptions |= 31526c9bb3a573b236f009654903461e496410a4147Michael Wright EditorInfo.IME_FLAG_NO_EXTRACT_UI | 31626c9bb3a573b236f009654903461e496410a4147Michael Wright EditorInfo.IME_FLAG_NO_ENTER_ACTION | 31726c9bb3a573b236f009654903461e496410a4147Michael Wright EditorInfo.IME_ACTION_NONE; 31826c9bb3a573b236f009654903461e496410a4147Michael Wright outAttrs.inputType = EditorInfo.TYPE_NULL; 31926c9bb3a573b236f009654903461e496410a4147Michael Wright return new BaseInputConnection(this, false) { 32026c9bb3a573b236f009654903461e496410a4147Michael Wright @Override 32126c9bb3a573b236f009654903461e496410a4147Michael Wright public boolean deleteSurroundingText (int leftLength, int rightLength) { 32226c9bb3a573b236f009654903461e496410a4147Michael Wright KeyEvent k; 32326c9bb3a573b236f009654903461e496410a4147Michael Wright if (rightLength == 0 && leftLength == 0) { 32426c9bb3a573b236f009654903461e496410a4147Michael Wright k = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL); 32526c9bb3a573b236f009654903461e496410a4147Michael Wright return this.sendKeyEvent(k); 32626c9bb3a573b236f009654903461e496410a4147Michael Wright } 32726c9bb3a573b236f009654903461e496410a4147Michael Wright for (int i = 0; i < leftLength; i++) { 32826c9bb3a573b236f009654903461e496410a4147Michael Wright k = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL); 32926c9bb3a573b236f009654903461e496410a4147Michael Wright this.sendKeyEvent(k); 33026c9bb3a573b236f009654903461e496410a4147Michael Wright } 33126c9bb3a573b236f009654903461e496410a4147Michael Wright for (int i = 0; i < rightLength; i++) { 33226c9bb3a573b236f009654903461e496410a4147Michael Wright k = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_FORWARD_DEL); 33326c9bb3a573b236f009654903461e496410a4147Michael Wright this.sendKeyEvent(k); 33426c9bb3a573b236f009654903461e496410a4147Michael Wright } 33526c9bb3a573b236f009654903461e496410a4147Michael Wright return true; 33626c9bb3a573b236f009654903461e496410a4147Michael Wright } 33726c9bb3a573b236f009654903461e496410a4147Michael Wright }; 33826c9bb3a573b236f009654903461e496410a4147Michael Wright } 339410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey} 340