diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/com/android/terminal/Terminal.java | 68 | ||||
-rw-r--r-- | src/com/android/terminal/TerminalActivity.java | 8 | ||||
-rw-r--r-- | src/com/android/terminal/TerminalView.java | 167 |
3 files changed, 236 insertions, 7 deletions
diff --git a/src/com/android/terminal/Terminal.java b/src/com/android/terminal/Terminal.java index 9f3016b..8067b9a 100644 --- a/src/com/android/terminal/Terminal.java +++ b/src/com/android/terminal/Terminal.java @@ -16,30 +16,88 @@ package com.android.terminal; -public class Terminal { - private TerminalCallbacks mCallbacks; +import android.graphics.Color; +/** + * Single terminal session backed by a pseudo terminal on the local device. + */ +public class Terminal { static { System.loadLibrary("jni_terminal"); } + public static class Cell { + char[] chars = new char[2]; + int width = 1; + + boolean bold; + int underline; + boolean blink; + boolean reverse; + boolean strike; + int font; + + int fgColor = Color.RED; + int bgColor = Color.BLUE; + } + + public interface TerminalClient { + public void damage(int startRow, int endRow, int startCol, int endCol); + public void bell(); + } + private final int mNativePtr; + private TerminalClient mClient; + + private final TerminalCallbacks mCallbacks = new TerminalCallbacks() { + @Override + public int damage(int startRow, int endRow, int startCol, int endCol) { + if (mClient != null) { + mClient.damage(startRow, endRow, startCol, endCol); + } + return 1; + } + + @Override + public int bell() { + if (mClient != null) { + mClient.bell(); + } + return 1; + } + }; public Terminal() { - mCallbacks = new TerminalCallbacks() { - }; mNativePtr = nativeInit(mCallbacks, 25, 80); } + public void setClient(TerminalClient client) { + mClient = client; + } + public void resize(int rows, int cols) { - nativeResize(mNativePtr, rows, cols); + if (nativeResize(mNativePtr, rows, cols) != 0) { + throw new IllegalStateException("resize failed"); + } } public int getRows() { return nativeGetRows(mNativePtr); } + public int getCols() { + return nativeGetCols(mNativePtr); + } + + public void getCell(int row, int col, Cell cell) { + if (nativeGetCell(mNativePtr, row, col, cell) != 0) { + throw new IllegalStateException("getCell failed"); + } + } + private static native int nativeInit(TerminalCallbacks callbacks, int rows, int cols); private static native int nativeResize(int ptr, int rows, int cols); + private static native int nativeGetCell(int ptr, int row, int col, Cell cell); private static native int nativeGetRows(int ptr); + private static native int nativeGetCols(int ptr); } diff --git a/src/com/android/terminal/TerminalActivity.java b/src/com/android/terminal/TerminalActivity.java index 0bb73ff..601fd98 100644 --- a/src/com/android/terminal/TerminalActivity.java +++ b/src/com/android/terminal/TerminalActivity.java @@ -27,7 +27,11 @@ public class TerminalActivity extends Activity { protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - Terminal t = new Terminal(); - Log.d(TAG, "Rows: " + t.getRows()); + final Terminal term = new Terminal(); + final TerminalView view = new TerminalView(this, term); + + setContentView(view); + + Log.d(TAG, "Rows: " + term.getRows()); } } diff --git a/src/com/android/terminal/TerminalView.java b/src/com/android/terminal/TerminalView.java new file mode 100644 index 0000000..adbb0a7 --- /dev/null +++ b/src/com/android/terminal/TerminalView.java @@ -0,0 +1,167 @@ +/* + * 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.terminal; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.Paint.FontMetrics; +import android.graphics.Rect; +import android.view.View; + +import android.os.SystemClock; +import android.util.Log; + +import com.android.terminal.Terminal.TerminalClient; + +/** + * Rendered contents of a {@link Terminal} session. + */ +public class TerminalView extends View { + private static final String TAG = "Terminal"; + + private final Context mContext; + private final Terminal mTerm; + + private final Paint mBgPaint = new Paint(); + private final Paint mTextPaint = new Paint(); + + private int mCharTop; + private int mCharWidth; + private int mCharHeight; + + private TerminalClient mClient = new TerminalClient() { + @Override + public void damage(int startRow, int endRow, int startCol, int endCol) { + final int top = startRow * mCharHeight; + final int bottom = (endRow + 1) * mCharHeight; + final int left = startCol * mCharWidth; + final int right = (endCol + 1) * mCharWidth; + + // Invalidate region on screen + postInvalidate(left, top, right, bottom); + } + + @Override + public void bell() { + Log.i(TAG, "DING!"); + } + }; + + public TerminalView(Context context, Terminal term) { + super(context); + mContext = context; + mTerm = term; + + setBackgroundColor(Color.BLACK); + setTextSize(20); + + // TODO: remove this test code that triggers invalidates + setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + v.invalidate(); + } + }); + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + mTerm.setClient(mClient); + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + mTerm.setClient(null); + } + + public void setTextSize(float textSize) { + mTextPaint.setTextSize(textSize); + + // Read metrics to get exact pixel dimensions + final FontMetrics fm = mTextPaint.getFontMetrics(); + mCharTop = (int) Math.ceil(fm.top); + + final float[] widths = new float[1]; + mTextPaint.getTextWidths("X", widths); + mCharWidth = (int) Math.ceil(widths[0]); + mCharHeight = (int) Math.ceil(fm.descent - fm.top); + + updateTerminalSize(); + } + + /** + * Determine terminal dimensions based on current dimensions and font size, + * and request that {@link Terminal} change to that size. + */ + public void updateTerminalSize() { + if (getWidth() > 0 && getHeight() > 0) { + final int rows = getHeight() / mCharHeight; + final int cols = getWidth() / mCharWidth; + mTerm.resize(rows, cols); + } + } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + super.onLayout(changed, left, top, right, bottom); + if (changed) { + updateTerminalSize(); + } + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + + final long start = SystemClock.elapsedRealtime(); + + // Only draw dirty region of console + final Rect dirty = canvas.getClipBounds(); + + final int startRow = dirty.top / mCharHeight; + final int endRow = dirty.bottom / mCharHeight; + final int startCol = dirty.left / mCharWidth; + final int endCol = dirty.right / mCharWidth; + + final Terminal.Cell cell = new Terminal.Cell(); + + for (int row = startRow; row <= endRow; row++) { + for (int col = startCol; col <= endCol;) { + mTerm.getCell(row, col, cell); + + mBgPaint.setColor(cell.bgColor); + mTextPaint.setColor(cell.fgColor); + + final int y = row * mCharHeight; + final int x = col * mCharWidth; + final int xEnd = x + (cell.width * mCharWidth); + + canvas.drawRect(x, y, xEnd, y + mCharHeight, mBgPaint); + canvas.drawText(cell.chars, 0, cell.chars.length, x, y - mCharTop, mTextPaint); + + col += cell.width; + } + } + + final long delta = SystemClock.elapsedRealtime() - start; + Log.d(TAG, "onDraw() took " + delta + "ms"); + } +} |