1 /*
2  * Copyright (C) 2013 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 
17 package com.android.terminal;
18 
19 import android.graphics.Color;
20 
21 /**
22  * Single terminal session backed by a pseudo terminal on the local device.
23  */
24 public class Terminal {
25     public static final String TAG = "Terminal";
26 
27     public final int key;
28 
29     private static int sNumber = 0;
30 
31     static {
32         System.loadLibrary("jni_terminal");
33     }
34 
35     /**
36      * Represents a run of one or more {@code VTermScreenCell} which all have
37      * the same formatting.
38      */
39     public static class CellRun {
40         char[] data;
41         int dataSize;
42         int colSize;
43 
44         boolean bold;
45         int underline;
46         boolean blink;
47         boolean reverse;
48         boolean strike;
49         int font;
50 
51         int fg = Color.CYAN;
52         int bg = Color.DKGRAY;
53     }
54 
55     // NOTE: clients must not call back into terminal while handling a callback,
56     // since native mutex isn't reentrant.
57     public interface TerminalClient {
onDamage(int startRow, int endRow, int startCol, int endCol)58         public void onDamage(int startRow, int endRow, int startCol, int endCol);
onMoveRect(int destStartRow, int destEndRow, int destStartCol, int destEndCol, int srcStartRow, int srcEndRow, int srcStartCol, int srcEndCol)59         public void onMoveRect(int destStartRow, int destEndRow, int destStartCol, int destEndCol,
60                 int srcStartRow, int srcEndRow, int srcStartCol, int srcEndCol);
onBell()61         public void onBell();
62     }
63 
64     private final long mNativePtr;
65     private final Thread mThread;
66 
67     private String mTitle;
68 
69     private TerminalClient mClient;
70 
71     private final TerminalCallbacks mCallbacks = new TerminalCallbacks() {
72         @Override
73         public int damage(int startRow, int endRow, int startCol, int endCol) {
74             if (mClient != null) {
75                 mClient.onDamage(startRow, endRow, startCol, endCol);
76             }
77             return 1;
78         }
79 
80         @Override
81         public int moveRect(int destStartRow, int destEndRow, int destStartCol, int destEndCol,
82                 int srcStartRow, int srcEndRow, int srcStartCol, int srcEndCol) {
83             if (mClient != null) {
84                 mClient.onMoveRect(destStartRow, destEndRow, destStartCol, destEndCol, srcStartRow,
85                         srcEndRow, srcStartCol, srcEndCol);
86             }
87             return 1;
88         }
89 
90         @Override
91         public int bell() {
92             if (mClient != null) {
93                 mClient.onBell();
94             }
95             return 1;
96         }
97     };
98 
Terminal()99     public Terminal() {
100         mNativePtr = nativeInit(mCallbacks, 25, 80);
101         key = sNumber++;
102         mTitle = TAG + " " + key;
103         mThread = new Thread(mTitle) {
104             @Override
105             public void run() {
106                 nativeRun(mNativePtr);
107             }
108         };
109     }
110 
111     /**
112      * Start thread which internally forks and manages the pseudo terminal.
113      */
start()114     public void start() {
115         mThread.start();
116     }
117 
destroy()118     public void destroy() {
119         if (nativeDestroy(mNativePtr) != 0) {
120             throw new IllegalStateException("destroy failed");
121         }
122     }
123 
setClient(TerminalClient client)124     public void setClient(TerminalClient client) {
125         mClient = client;
126     }
127 
resize(int rows, int cols, int scrollRows)128     public void resize(int rows, int cols, int scrollRows) {
129         if (nativeResize(mNativePtr, rows, cols, scrollRows) != 0) {
130             throw new IllegalStateException("resize failed");
131         }
132     }
133 
getRows()134     public int getRows() {
135         return nativeGetRows(mNativePtr);
136     }
137 
getCols()138     public int getCols() {
139         return nativeGetCols(mNativePtr);
140     }
141 
getScrollRows()142     public int getScrollRows() {
143         return nativeGetScrollRows(mNativePtr);
144     }
145 
getCellRun(int row, int col, CellRun run)146     public void getCellRun(int row, int col, CellRun run) {
147         if (nativeGetCellRun(mNativePtr, row, col, run) != 0) {
148             throw new IllegalStateException("getCell failed");
149         }
150     }
151 
getTitle()152     public String getTitle() {
153         // TODO: hook up to title passed through termprop
154         return mTitle;
155     }
156 
dispatchKey(int modifiers, int key)157     public boolean dispatchKey(int modifiers, int key) {
158         return nativeDispatchKey(mNativePtr, modifiers, key);
159     }
160 
dispatchCharacter(int modifiers, int character)161     public boolean dispatchCharacter(int modifiers, int character) {
162         return nativeDispatchCharacter(mNativePtr, modifiers, character);
163     }
164 
nativeInit(TerminalCallbacks callbacks, int rows, int cols)165     private static native long nativeInit(TerminalCallbacks callbacks, int rows, int cols);
nativeDestroy(long ptr)166     private static native int nativeDestroy(long ptr);
167 
nativeRun(long ptr)168     private static native int nativeRun(long ptr);
nativeResize(long ptr, int rows, int cols, int scrollRows)169     private static native int nativeResize(long ptr, int rows, int cols, int scrollRows);
nativeGetCellRun(long ptr, int row, int col, CellRun run)170     private static native int nativeGetCellRun(long ptr, int row, int col, CellRun run);
nativeGetRows(long ptr)171     private static native int nativeGetRows(long ptr);
nativeGetCols(long ptr)172     private static native int nativeGetCols(long ptr);
nativeGetScrollRows(long ptr)173     private static native int nativeGetScrollRows(long ptr);
174 
nativeDispatchKey(long ptr, int modifiers, int key)175     private static native boolean nativeDispatchKey(long ptr, int modifiers, int key);
nativeDispatchCharacter(long ptr, int modifiers, int character)176     private static native boolean nativeDispatchCharacter(long ptr, int modifiers, int character);
177 }
178