summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeff Sharkey <jsharkey@android.com>2013-02-23 15:42:10 -0800
committerJeff Sharkey <jsharkey@android.com>2013-02-23 15:48:24 -0800
commitde15e79aadde33fd8c880c19bd4fc6caca0bf795 (patch)
treed6f5867abab2baaf174e2066c5389971c3681e9d
parentcedf158c17dc147163734ad1070032ff934d1b2e (diff)
downloadandroid_packages_apps_Terminal-de15e79aadde33fd8c880c19bd4fc6caca0bf795.tar.gz
android_packages_apps_Terminal-de15e79aadde33fd8c880c19bd4fc6caca0bf795.tar.bz2
android_packages_apps_Terminal-de15e79aadde33fd8c880c19bd4fc6caca0bf795.zip
Service to host long-lived terminals, tab UI.
Bind to new TerminalService when UI is running, and keep service started as long as terminals are active. Use ViewPager to show multiple active terminals, and menu items to open/close terminals. Anti-alias terminal text. Reduce callback logging. Add method to stop a running shell; still need to kill child process. Change-Id: I8efcb43aeaf8813762cd0ceebcd5388fc51ebaab
-rw-r--r--Android.mk2
-rw-r--r--AndroidManifest.xml9
-rw-r--r--jni/com_android_terminal_Terminal.cpp48
-rw-r--r--res/layout/activity.xml30
-rw-r--r--res/menu/activity.xml28
-rw-r--r--res/values/strings.xml4
-rw-r--r--src/com/android/terminal/Terminal.java17
-rw-r--r--src/com/android/terminal/TerminalActivity.java141
-rw-r--r--src/com/android/terminal/TerminalService.java73
-rw-r--r--src/com/android/terminal/TerminalView.java41
10 files changed, 372 insertions, 21 deletions
diff --git a/Android.mk b/Android.mk
index 5e545b6..198c11e 100644
--- a/Android.mk
+++ b/Android.mk
@@ -5,6 +5,8 @@ LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES := $(call all-subdir-java-files)
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4
+
LOCAL_JNI_SHARED_LIBRARIES := libjni_terminal
LOCAL_PROGUARD_FLAG_FILES := proguard.flags
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 397c79f..078ace7 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -16,14 +16,19 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.terminal">
- <application android:label="@string/app_label">
+ <application
+ android:label="@string/app_label"
+ android:persistent="true">
+
<activity android:name=".TerminalActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
- </activity>
+ </activity>
+
+ <service android:name=".TerminalService" />
</application>
</manifest>
diff --git a/jni/com_android_terminal_Terminal.cpp b/jni/com_android_terminal_Terminal.cpp
index 2439346..c84f323 100644
--- a/jni/com_android_terminal_Terminal.cpp
+++ b/jni/com_android_terminal_Terminal.cpp
@@ -34,7 +34,9 @@
#include <string.h>
-#define USE_TEST_SHELL true
+#define USE_TEST_SHELL 1
+#define DEBUG_CALLBACKS 0
+#define DEBUG_IO 0
namespace android {
@@ -81,6 +83,7 @@ public:
~Terminal();
int run();
+ int stop();
size_t write(const char *bytes, size_t len);
@@ -102,6 +105,7 @@ private:
jobject mCallbacks;
short unsigned int mRows;
short unsigned int mCols;
+ bool mStopped;
};
static JNIEnv* getEnv() {
@@ -120,7 +124,9 @@ static JNIEnv* getEnv() {
static int term_damage(VTermRect rect, void *user) {
Terminal* term = reinterpret_cast<Terminal*>(user);
+#if DEBUG_CALLBACKS
ALOGW("term_damage");
+#endif
JNIEnv* env = getEnv();
if (env == NULL) {
@@ -134,7 +140,9 @@ static int term_damage(VTermRect rect, void *user) {
static int term_prescroll(VTermRect rect, void *user) {
Terminal* term = reinterpret_cast<Terminal*>(user);
+#if DEBUG_CALLBACKS
ALOGW("term_prescroll");
+#endif
JNIEnv* env = getEnv();
if (env == NULL) {
@@ -148,7 +156,9 @@ static int term_prescroll(VTermRect rect, void *user) {
static int term_moverect(VTermRect dest, VTermRect src, void *user) {
Terminal* term = reinterpret_cast<Terminal*>(user);
+#if DEBUG_CALLBACKS
ALOGW("term_moverect");
+#endif
JNIEnv* env = getEnv();
if (env == NULL) {
@@ -163,7 +173,9 @@ static int term_moverect(VTermRect dest, VTermRect src, void *user) {
static int term_movecursor(VTermPos pos, VTermPos oldpos, int visible, void *user) {
Terminal* term = reinterpret_cast<Terminal*>(user);
+#if DEBUG_CALLBACKS
ALOGW("term_movecursor");
+#endif
JNIEnv* env = getEnv();
if (env == NULL) {
@@ -177,7 +189,9 @@ static int term_movecursor(VTermPos pos, VTermPos oldpos, int visible, void *use
static int term_settermprop(VTermProp prop, VTermValue *val, void *user) {
Terminal* term = reinterpret_cast<Terminal*>(user);
+#if DEBUG_CALLBACKS
ALOGW("term_settermprop");
+#endif
JNIEnv* env = getEnv();
if (env == NULL) {
@@ -205,13 +219,17 @@ static int term_settermprop(VTermProp prop, VTermValue *val, void *user) {
static int term_setmousefunc(VTermMouseFunc func, void *data, void *user) {
Terminal* term = reinterpret_cast<Terminal*>(user);
+#if DEBUG_CALLBACKS
ALOGW("term_setmousefunc");
+#endif
return 1;
}
static int term_bell(void *user) {
Terminal* term = reinterpret_cast<Terminal*>(user);
+#if DEBUG_CALLBACKS
ALOGW("term_bell");
+#endif
JNIEnv* env = getEnv();
if (env == NULL) {
@@ -224,7 +242,9 @@ static int term_bell(void *user) {
static int term_resize(int rows, int cols, void *user) {
Terminal* term = reinterpret_cast<Terminal*>(user);
+#if DEBUG_CALLBACKS
ALOGW("term_resize");
+#endif
JNIEnv* env = getEnv();
if (env == NULL) {
@@ -247,7 +267,7 @@ static VTermScreenCallbacks cb = {
};
Terminal::Terminal(jobject callbacks, int rows, int cols) :
- mCallbacks(callbacks), mRows(rows), mCols(cols) {
+ mCallbacks(callbacks), mRows(rows), mCols(cols), mStopped(false) {
/* Create VTerm */
mVt = vterm_new(rows, cols);
vterm_parser_set_utf8(mVt, 1);
@@ -315,7 +335,7 @@ int Terminal::run() {
}
char *shell = "/system/bin/sh"; //getenv("SHELL");
-#ifdef USE_TEST_SHELL
+#if USE_TEST_SHELL
char *args[4] = {shell, "-c", "x=1; c=0; while true; do echo -e \"stop \e[00;3${c}mechoing\e[00m yourself! ($x)\"; x=$(( $x + 1 )); c=$((($c+1)%7)); sleep 0.5; done", NULL};
#else
char *args[2] = {shell, NULL};
@@ -330,8 +350,14 @@ int Terminal::run() {
while (1) {
char buffer[4096];
ssize_t bytes = ::read(mMasterFd, buffer, sizeof buffer);
- ALOGD("Read %d bytes:", bytes);
+#if DEBUG_IO
+ ALOGD("read() returned %d bytes", bytes);
+#endif
+ if (mStopped) {
+ ALOGD("stop() requested");
+ break;
+ }
if (bytes == 0) {
ALOGD("read() found EOF");
break;
@@ -346,7 +372,13 @@ int Terminal::run() {
vterm_screen_flush_damage(mVts);
}
- return 1;
+ return 0;
+}
+
+int Terminal::stop() {
+ // TODO: explicitly kill forked child process
+ mStopped = true;
+ return 0;
}
size_t Terminal::write(const char *bytes, size_t len) {
@@ -403,6 +435,11 @@ static jint com_android_terminal_Terminal_nativeRun(JNIEnv* env, jclass clazz, j
return term->run();
}
+static jint com_android_terminal_Terminal_nativeStop(JNIEnv* env, jclass clazz, jint ptr) {
+ Terminal* term = reinterpret_cast<Terminal*>(ptr);
+ return term->stop();
+}
+
static jint com_android_terminal_Terminal_nativeFlushDamage(JNIEnv* env, jclass clazz, jint ptr) {
Terminal* term = reinterpret_cast<Terminal*>(ptr);
return term->flushDamage();
@@ -502,6 +539,7 @@ static jint com_android_terminal_Terminal_nativeGetCols(JNIEnv* env, jclass claz
static JNINativeMethod gMethods[] = {
{ "nativeInit", "(Lcom/android/terminal/TerminalCallbacks;II)I", (void*)com_android_terminal_Terminal_nativeInit },
{ "nativeRun", "(I)I", (void*)com_android_terminal_Terminal_nativeRun },
+ { "nativeStop", "(I)I", (void*)com_android_terminal_Terminal_nativeStop },
{ "nativeFlushDamage", "(I)I", (void*)com_android_terminal_Terminal_nativeFlushDamage },
{ "nativeResize", "(III)I", (void*)com_android_terminal_Terminal_nativeResize },
{ "nativeGetCellRun", "(IIILcom/android/terminal/Terminal$CellRun;)I", (void*)com_android_terminal_Terminal_nativeGetCellRun },
diff --git a/res/layout/activity.xml b/res/layout/activity.xml
new file mode 100644
index 0000000..1ec603d
--- /dev/null
+++ b/res/layout/activity.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<android.support.v4.view.ViewPager
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/pager"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <android.support.v4.view.PagerTitleStrip
+ android:id="@+id/titles"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="top"
+ />
+
+</android.support.v4.view.ViewPager>
diff --git a/res/menu/activity.xml b/res/menu/activity.xml
new file mode 100644
index 0000000..d1be0ae
--- /dev/null
+++ b/res/menu/activity.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+ <item
+ android:id="@+id/menu_new_tab"
+ android:title="@string/menu_new_tab"
+ android:icon="@android:drawable/ic_menu_add"
+ android:showAsAction="always" />
+ <item
+ android:id="@+id/menu_close_tab"
+ android:title="@string/menu_close_tab"
+ android:icon="@android:drawable/ic_menu_close_clear_cancel"
+ android:showAsAction="ifRoom" />
+</menu>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 1aca939..cbcaef3 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -17,4 +17,8 @@
<resources>
<!-- Title of the Terminal activity. -->
<string name="app_label">Terminal</string>
+
+ <string name="menu_new_tab">New tab</string>
+ <string name="menu_close_tab">Close tab</string>
+
</resources>
diff --git a/src/com/android/terminal/Terminal.java b/src/com/android/terminal/Terminal.java
index d37e6a8..c9e45e7 100644
--- a/src/com/android/terminal/Terminal.java
+++ b/src/com/android/terminal/Terminal.java
@@ -24,6 +24,8 @@ import android.graphics.Color;
public class Terminal {
private static final String TAG = "Terminal";
+ private static int sNumber = 0;
+
static {
System.loadLibrary("jni_terminal");
}
@@ -58,6 +60,8 @@ public class Terminal {
private final int mNativePtr;
private final Thread mThread;
+ private String mTitle;
+
private TerminalClient mClient;
private final TerminalCallbacks mCallbacks = new TerminalCallbacks() {
@@ -90,6 +94,7 @@ public class Terminal {
public Terminal() {
mNativePtr = nativeInit(mCallbacks, 25, 80);
+ mTitle = TAG + " " + sNumber++;
mThread = new Thread(TAG) {
@Override
public void run() {
@@ -105,6 +110,12 @@ public class Terminal {
mThread.start();
}
+ public void stop() {
+ if (nativeStop(mNativePtr) != 0) {
+ throw new IllegalStateException("stop failed");
+ }
+ }
+
public void setClient(TerminalClient client) {
mClient = client;
}
@@ -135,8 +146,14 @@ public class Terminal {
}
}
+ public String getTitle() {
+ // TODO: hook up to title passed through termprop
+ return mTitle;
+ }
+
private static native int nativeInit(TerminalCallbacks callbacks, int rows, int cols);
private static native int nativeRun(int ptr);
+ private static native int nativeStop(int ptr);
private static native int nativeFlushDamage(int ptr);
private static native int nativeResize(int ptr, int rows, int cols);
diff --git a/src/com/android/terminal/TerminalActivity.java b/src/com/android/terminal/TerminalActivity.java
index bef1859..99d2be6 100644
--- a/src/com/android/terminal/TerminalActivity.java
+++ b/src/com/android/terminal/TerminalActivity.java
@@ -17,23 +17,154 @@
package com.android.terminal;
import android.app.Activity;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
import android.os.Bundle;
+import android.os.IBinder;
+import android.support.v4.view.PagerAdapter;
+import android.support.v4.view.PagerTitleStrip;
+import android.support.v4.view.ViewPager;
import android.util.Log;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+/**
+ * Activity that displays all {@link Terminal} instances running in a bound
+ * {@link TerminalService}.
+ */
public class TerminalActivity extends Activity {
private static final String TAG = "Terminal";
+ private TerminalService mService;
+
+ private ViewPager mPager;
+ private PagerTitleStrip mTitles;
+
+ private final ServiceConnection mServiceConn = new ServiceConnection() {
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ mService = ((TerminalService.ServiceBinder) service).getService();
+
+ final int size = mService.getTerminals().size();
+ Log.d(TAG, "Bound to service with " + size + " active terminals");
+
+ // Give ourselves at least one terminal session
+ if (size == 0) {
+ mService.createTerminal();
+ }
+
+ // Bind UI to known terminals
+ mTermAdapter.notifyDataSetChanged();
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ mService = null;
+ throw new RuntimeException("Service in same process disconnected?");
+ }
+ };
+
+ private final PagerAdapter mTermAdapter = new PagerAdapter() {
+ @Override
+ public int getCount() {
+ if (mService != null) {
+ return mService.getTerminals().size();
+ } else {
+ return 0;
+ }
+ }
+
+ @Override
+ public Object instantiateItem(ViewGroup container, int position) {
+ final Terminal term = mService.getTerminals().get(position);
+ final TerminalView view = new TerminalView(container.getContext());
+ view.setTerminal(term);
+ container.addView(view);
+ return view;
+ }
+
+ @Override
+ public void destroyItem(ViewGroup container, int position, Object object) {
+ final TerminalView view = (TerminalView) object;
+ view.setTerminal(null);
+ container.removeView(view);
+ }
+
+ @Override
+ public int getItemPosition(Object object) {
+ final int index = mService.getTerminals().indexOf(object);
+ if (index == -1) {
+ return POSITION_NONE;
+ } else {
+ return index;
+ }
+ }
+
+ @Override
+ public boolean isViewFromObject(View view, Object object) {
+ return view == object;
+ }
+
+ @Override
+ public CharSequence getPageTitle(int position) {
+ return mService.getTerminals().get(position).getTitle();
+ }
+ };
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- final Terminal term = new Terminal();
- term.start();
+ setContentView(R.layout.activity);
+
+ mPager = (ViewPager) findViewById(R.id.pager);
+ mTitles = (PagerTitleStrip) findViewById(R.id.titles);
+
+ mPager.setAdapter(mTermAdapter);
+ }
+
+ @Override
+ protected void onStart() {
+ super.onStart();
+ bindService(
+ new Intent(this, TerminalService.class), mServiceConn, Context.BIND_AUTO_CREATE);
+ }
- final TerminalView view = new TerminalView(this, term);
+ @Override
+ protected void onStop() {
+ super.onStop();
+ unbindService(mServiceConn);
+ }
- setContentView(view);
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ getMenuInflater().inflate(R.menu.activity, menu);
+ return true;
+ }
- Log.d(TAG, "Rows: " + term.getRows());
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch (item.getItemId()) {
+ case R.id.menu_new_tab: {
+ mService.createTerminal();
+ mTermAdapter.notifyDataSetChanged();
+ final int index = mService.getTerminals().size() - 1;
+ mPager.setCurrentItem(index, true);
+ return true;
+ }
+ case R.id.menu_close_tab: {
+ final int index = mPager.getCurrentItem();
+ final Terminal term = mService.getTerminals().get(index);
+ mService.destroyTerminal(term);
+ // TODO: ask adamp about buggy zero item behavior
+ mTermAdapter.notifyDataSetChanged();
+ return true;
+ }
+ }
+ return false;
}
}
diff --git a/src/com/android/terminal/TerminalService.java b/src/com/android/terminal/TerminalService.java
new file mode 100644
index 0000000..ebbdcce
--- /dev/null
+++ b/src/com/android/terminal/TerminalService.java
@@ -0,0 +1,73 @@
+/*
+ * 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.app.Service;
+import android.content.Intent;
+import android.os.Binder;
+import android.os.IBinder;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Background service that keeps {@link Terminal} instances running and warm
+ * when UI isn't present.
+ */
+public class TerminalService extends Service {
+ private static final String TAG = "Terminal";
+
+ private final ArrayList<Terminal> mTerminals = new ArrayList<Terminal>();
+
+ public class ServiceBinder extends Binder {
+ public TerminalService getService() {
+ return TerminalService.this;
+ }
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return new ServiceBinder();
+ }
+
+ public List<Terminal> getTerminals() {
+ return Collections.unmodifiableList(mTerminals);
+ }
+
+ public Terminal createTerminal() {
+ // If our first terminal, start ourselves as long-lived service
+ if (mTerminals.isEmpty()) {
+ startService(new Intent(this, TerminalService.class));
+ }
+
+ final Terminal term = new Terminal();
+ term.start();
+ mTerminals.add(term);
+ return term;
+ }
+
+ public void destroyTerminal(Terminal term) {
+ term.stop();
+ mTerminals.remove(term);
+
+ // If our last terminal, tear down long-lived service
+ if (mTerminals.isEmpty()) {
+ stopService(new Intent(this, TerminalService.class));
+ }
+ }
+}
diff --git a/src/com/android/terminal/TerminalView.java b/src/com/android/terminal/TerminalView.java
index 35192e9..64aeabd 100644
--- a/src/com/android/terminal/TerminalView.java
+++ b/src/com/android/terminal/TerminalView.java
@@ -35,11 +35,11 @@ import com.android.terminal.Terminal.TerminalClient;
*/
public class TerminalView extends View {
private static final String TAG = "Terminal";
+ private static final boolean LOGD = true;
private static final int MAX_RUN_LENGTH = 128;
private final Context mContext;
- private final Terminal mTerm;
private final Paint mBgPaint = new Paint();
private final Paint mTextPaint = new Paint();
@@ -49,6 +49,8 @@ public class TerminalView extends View {
/** Screen coordinates to draw chars into */
private final float[] mPos;
+ private Terminal mTerm;
+
private int mCharTop;
private int mCharWidth;
private int mCharHeight;
@@ -59,7 +61,7 @@ public class TerminalView extends View {
private TerminalClient mClient = new TerminalClient() {
@Override
public void damage(int startRow, int endRow, int startCol, int endCol) {
- Log.d(TAG, "damage(" + startRow + ", " + endRow + ", " + startCol + ", " + endCol + ")");
+ if (LOGD) Log.d(TAG, "damage(" + startRow + ", " + endRow + ", " + startCol + ", " + endCol + ")");
// Invalidate region on screen
final int top = startRow * mCharHeight;
@@ -86,10 +88,9 @@ public class TerminalView extends View {
}
};
- public TerminalView(Context context, Terminal term) {
+ public TerminalView(Context context) {
super(context);
mContext = context;
- mTerm = term;
mRun = new Terminal.CellRun();
mRun.data = new char[MAX_RUN_LENGTH];
@@ -110,20 +111,37 @@ public class TerminalView extends View {
});
}
+ public void setTerminal(Terminal term) {
+ final Terminal orig = mTerm;
+ if (orig != null) {
+ orig.setClient(null);
+ }
+ mTerm = term;
+ if (term != null) {
+ term.setClient(mClient);
+ }
+ updateTerminalSize();
+ }
+
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
- mTerm.setClient(mClient);
+ if (mTerm != null) {
+ mTerm.setClient(mClient);
+ }
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
- mTerm.setClient(null);
+ if (mTerm != null) {
+ mTerm.setClient(null);
+ }
}
public void setTextSize(float textSize) {
mTextPaint.setTypeface(Typeface.MONOSPACE);
+ mTextPaint.setAntiAlias(true);
mTextPaint.setTextSize(textSize);
// Read metrics to get exact pixel dimensions
@@ -149,11 +167,10 @@ public class TerminalView extends View {
* and request that {@link Terminal} change to that size.
*/
public void updateTerminalSize() {
- if (getWidth() > 0 && getHeight() > 0) {
+ if (getWidth() > 0 && getHeight() > 0 && mTerm != null) {
final int rows = getHeight() / mCharHeight;
final int cols = getWidth() / mCharWidth;
mTerm.resize(rows, cols);
- mTerm.flushDamage();
}
}
@@ -169,6 +186,12 @@ public class TerminalView extends View {
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
+ if (mTerm == null) {
+ Log.w(TAG, "onDraw() without a terminal");
+ canvas.drawColor(Color.MAGENTA);
+ return;
+ }
+
final long start = SystemClock.elapsedRealtime();
// Only draw dirty region of console
@@ -210,6 +233,6 @@ public class TerminalView extends View {
}
final long delta = SystemClock.elapsedRealtime() - start;
- Log.d(TAG, "onDraw() took " + delta + "ms");
+ if (LOGD) Log.d(TAG, "onDraw() took " + delta + "ms");
}
}