/* * 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.graphics.Color; /** * Single terminal session backed by a pseudo terminal on the local device. */ public class Terminal { public static final String TAG = "Terminal"; public final int key; private static int sNumber = 0; static { System.loadLibrary("jni_terminal"); } /** * Represents a run of one or more {@code VTermScreenCell} which all have * the same formatting. */ public static class CellRun { char[] data; int dataSize; int colSize; boolean bold; int underline; boolean blink; boolean reverse; boolean strike; int font; int fg = Color.CYAN; int bg = Color.DKGRAY; } // NOTE: clients must not call back into terminal while handling a callback, // since native mutex isn't reentrant. public interface TerminalClient { public void onDamage(int startRow, int endRow, int startCol, int endCol); public void onMoveRect(int destStartRow, int destEndRow, int destStartCol, int destEndCol, int srcStartRow, int srcEndRow, int srcStartCol, int srcEndCol); public void onMoveCursor(int posRow, int posCol, int oldPosRow, int oldPosCol, int visible); public void onBell(); } private final long mNativePtr; private final Thread mThread; private String mTitle; private TerminalClient mClient; private boolean mCursorVisible; private int mCursorRow; private int mCursorCol; private final TerminalCallbacks mCallbacks = new TerminalCallbacks() { @Override public int damage(int startRow, int endRow, int startCol, int endCol) { if (mClient != null) { mClient.onDamage(startRow, endRow, startCol, endCol); } return 1; } @Override public int moveRect(int destStartRow, int destEndRow, int destStartCol, int destEndCol, int srcStartRow, int srcEndRow, int srcStartCol, int srcEndCol) { if (mClient != null) { mClient.onMoveRect(destStartRow, destEndRow, destStartCol, destEndCol, srcStartRow, srcEndRow, srcStartCol, srcEndCol); } return 1; } @Override public int moveCursor(int posRow, int posCol, int oldPosRow, int oldPosCol, int visible) { mCursorVisible = (visible != 0); mCursorRow = posRow; mCursorCol = posCol; if (mClient != null) { mClient.onMoveCursor(posRow, posCol, oldPosRow, oldPosCol, visible); } return 1; } @Override public int bell() { if (mClient != null) { mClient.onBell(); } return 1; } }; public Terminal() { mNativePtr = nativeInit(mCallbacks); key = sNumber++; mTitle = TAG + " " + key; mThread = new Thread(mTitle) { @Override public void run() { nativeRun(mNativePtr); } }; } /** * Start thread which internally forks and manages the pseudo terminal. */ public void start() { mThread.start(); } public void destroy() { if (nativeDestroy(mNativePtr) != 0) { throw new IllegalStateException("destroy failed"); } } public void setClient(TerminalClient client) { mClient = client; } public void resize(int rows, int cols, int scrollRows) { if (nativeResize(mNativePtr, rows, cols, scrollRows) != 0) { throw new IllegalStateException("resize failed"); } } public void setColors(int fg, int bg) { if (nativeSetColors(mNativePtr, fg, bg) != 0) { throw new IllegalStateException("setColors failed"); } } public int getRows() { return nativeGetRows(mNativePtr); } public int getCols() { return nativeGetCols(mNativePtr); } public int getScrollRows() { return nativeGetScrollRows(mNativePtr); } public void getCellRun(int row, int col, CellRun run) { if (nativeGetCellRun(mNativePtr, row, col, run) != 0) { throw new IllegalStateException("getCell failed"); } } public boolean getCursorVisible() { return mCursorVisible; } public int getCursorRow() { return mCursorRow; } public int getCursorCol() { return mCursorCol; } public String getTitle() { // TODO: hook up to title passed through termprop return mTitle; } public boolean dispatchKey(int modifiers, int key) { return nativeDispatchKey(mNativePtr, modifiers, key); } public boolean dispatchCharacter(int modifiers, int character) { return nativeDispatchCharacter(mNativePtr, modifiers, character); } private static native long nativeInit(TerminalCallbacks callbacks); private static native int nativeDestroy(long ptr); private static native int nativeRun(long ptr); private static native int nativeResize(long ptr, int rows, int cols, int scrollRows); private static native int nativeSetColors(long ptr, int fg, int bg); private static native int nativeGetCellRun(long ptr, int row, int col, CellRun run); private static native int nativeGetRows(long ptr); private static native int nativeGetCols(long ptr); private static native int nativeGetScrollRows(long ptr); private static native boolean nativeDispatchKey(long ptr, int modifiers, int key); private static native boolean nativeDispatchCharacter(long ptr, int modifiers, int character); }