com_android_terminal_Terminal.cpp revision 410e0da343fd581f3112037deb475db9fb0da850
1ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey/*
2ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey * Copyright (C) 2013 The Android Open Source Project
3ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey *
4ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey * Licensed under the Apache License, Version 2.0 (the "License");
5ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey * you may not use this file except in compliance with the License.
6ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey * You may obtain a copy of the License at
7ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey *
8ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey *      http://www.apache.org/licenses/LICENSE-2.0
9ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey *
10ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey * Unless required by applicable law or agreed to in writing, software
11ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey * distributed under the License is distributed on an "AS IS" BASIS,
12ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey * See the License for the specific language governing permissions and
14ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey * limitations under the License.
15ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey */
16ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey
17ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey#define LOG_TAG "Terminal"
18ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey
19ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey#include <utils/Log.h>
20ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey#include "jni.h"
21ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey#include "JNIHelp.h"
228c040334130cea6e44dda03516d86e774d18d376Kenny Root#include <ScopedLocalRef.h>
23ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey
245d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkey#include <termios.h>
255d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkey#include <util.h>
265d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkey//#include <pty.h>
275d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkey#include <utmp.h>
285d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkey#include <unistd.h>
295d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkey//#include <stdlib.h>
305d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkey
31ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey#include <vterm.h>
32ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey
33ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey#include <string.h>
34ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey
35ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkeynamespace android {
36ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey
378c040334130cea6e44dda03516d86e774d18d376Kenny Root/*
388c040334130cea6e44dda03516d86e774d18d376Kenny Root * JavaVM reference
398c040334130cea6e44dda03516d86e774d18d376Kenny Root */
408c040334130cea6e44dda03516d86e774d18d376Kenny Rootstatic JavaVM* gJavaVM;
418c040334130cea6e44dda03516d86e774d18d376Kenny Root
428c040334130cea6e44dda03516d86e774d18d376Kenny Root/*
438c040334130cea6e44dda03516d86e774d18d376Kenny Root * Callback class reference
448c040334130cea6e44dda03516d86e774d18d376Kenny Root */
458c040334130cea6e44dda03516d86e774d18d376Kenny Rootstatic jclass terminalCallbacksClass;
468c040334130cea6e44dda03516d86e774d18d376Kenny Root
478c040334130cea6e44dda03516d86e774d18d376Kenny Root/*
488c040334130cea6e44dda03516d86e774d18d376Kenny Root * Callback methods
498c040334130cea6e44dda03516d86e774d18d376Kenny Root */
508c040334130cea6e44dda03516d86e774d18d376Kenny Rootstatic jmethodID damageMethod;
518c040334130cea6e44dda03516d86e774d18d376Kenny Rootstatic jmethodID prescrollMethod;
528c040334130cea6e44dda03516d86e774d18d376Kenny Rootstatic jmethodID moveRectMethod;
538c040334130cea6e44dda03516d86e774d18d376Kenny Rootstatic jmethodID moveCursorMethod;
548c040334130cea6e44dda03516d86e774d18d376Kenny Rootstatic jmethodID setTermPropBooleanMethod;
558c040334130cea6e44dda03516d86e774d18d376Kenny Rootstatic jmethodID setTermPropIntMethod;
568c040334130cea6e44dda03516d86e774d18d376Kenny Rootstatic jmethodID setTermPropStringMethod;
578c040334130cea6e44dda03516d86e774d18d376Kenny Rootstatic jmethodID setTermPropColorMethod;
588c040334130cea6e44dda03516d86e774d18d376Kenny Rootstatic jmethodID bellMethod;
598c040334130cea6e44dda03516d86e774d18d376Kenny Rootstatic jmethodID resizeMethod;
608c040334130cea6e44dda03516d86e774d18d376Kenny Root
61410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey/*
62410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey * Cell class
63410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey */
64410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkeystatic jclass cellClass;
65410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkeystatic jfieldID cellCharsField;
66410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey
678c040334130cea6e44dda03516d86e774d18d376Kenny Root
688c040334130cea6e44dda03516d86e774d18d376Kenny Root/*
698c040334130cea6e44dda03516d86e774d18d376Kenny Root * Terminal session
708c040334130cea6e44dda03516d86e774d18d376Kenny Root */
718c040334130cea6e44dda03516d86e774d18d376Kenny Root
728c040334130cea6e44dda03516d86e774d18d376Kenny Rootclass Terminal {
738c040334130cea6e44dda03516d86e774d18d376Kenny Rootpublic:
748c040334130cea6e44dda03516d86e774d18d376Kenny Root    Terminal(jobject callbacks, int rows, int cols);
758c040334130cea6e44dda03516d86e774d18d376Kenny Root    ~Terminal();
768c040334130cea6e44dda03516d86e774d18d376Kenny Root
775d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkey    size_t write(const char *bytes, size_t len);
78410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey
79410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey    int resize(short unsigned int rows, short unsigned int cols);
80410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey    int getCell(VTermPos pos, VTermScreenCell* cell);
815d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkey
828c040334130cea6e44dda03516d86e774d18d376Kenny Root    int getRows() const;
83410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey    int getCols() const;
848c040334130cea6e44dda03516d86e774d18d376Kenny Root
858c040334130cea6e44dda03516d86e774d18d376Kenny Root    jobject getCallbacks() const;
868c040334130cea6e44dda03516d86e774d18d376Kenny Root
878c040334130cea6e44dda03516d86e774d18d376Kenny Rootprivate:
885d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkey    int mMasterFd;
898c040334130cea6e44dda03516d86e774d18d376Kenny Root    VTerm *mVt;
908c040334130cea6e44dda03516d86e774d18d376Kenny Root    VTermScreen *mVts;
918c040334130cea6e44dda03516d86e774d18d376Kenny Root
92410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey    jobject mCallbacks;
935d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkey    short unsigned int mRows;
945d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkey    short unsigned int mCols;
958c040334130cea6e44dda03516d86e774d18d376Kenny Root};
968c040334130cea6e44dda03516d86e774d18d376Kenny Root
978c040334130cea6e44dda03516d86e774d18d376Kenny Rootstatic JNIEnv* getEnv() {
988c040334130cea6e44dda03516d86e774d18d376Kenny Root    JNIEnv* env;
998c040334130cea6e44dda03516d86e774d18d376Kenny Root
1008c040334130cea6e44dda03516d86e774d18d376Kenny Root    if (gJavaVM->AttachCurrentThread(&env, NULL) < 0) {
1018c040334130cea6e44dda03516d86e774d18d376Kenny Root        return NULL;
1028c040334130cea6e44dda03516d86e774d18d376Kenny Root    }
1038c040334130cea6e44dda03516d86e774d18d376Kenny Root
1048c040334130cea6e44dda03516d86e774d18d376Kenny Root    return env;
1058c040334130cea6e44dda03516d86e774d18d376Kenny Root}
106ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey
107ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey/*
108ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey * VTerm event handlers
109ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey */
110ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey
111ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkeystatic int term_damage(VTermRect rect, void *user) {
112ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey    Terminal* term = reinterpret_cast<Terminal*>(user);
113ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey    ALOGW("term_damage");
1148c040334130cea6e44dda03516d86e774d18d376Kenny Root
1158c040334130cea6e44dda03516d86e774d18d376Kenny Root    JNIEnv* env = getEnv();
1168c040334130cea6e44dda03516d86e774d18d376Kenny Root    if (env == NULL) {
1178c040334130cea6e44dda03516d86e774d18d376Kenny Root        ALOGE("term_damage: couldn't get JNIEnv");
1188c040334130cea6e44dda03516d86e774d18d376Kenny Root        return 0;
1198c040334130cea6e44dda03516d86e774d18d376Kenny Root    }
1208c040334130cea6e44dda03516d86e774d18d376Kenny Root
1218c040334130cea6e44dda03516d86e774d18d376Kenny Root    return env->CallIntMethod(term->getCallbacks(), damageMethod, rect.start_row, rect.end_row,
1228c040334130cea6e44dda03516d86e774d18d376Kenny Root            rect.start_col, rect.end_col);
123ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey}
124ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey
125ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkeystatic int term_prescroll(VTermRect rect, void *user) {
126ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey    Terminal* term = reinterpret_cast<Terminal*>(user);
127ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey    ALOGW("term_prescroll");
1288c040334130cea6e44dda03516d86e774d18d376Kenny Root
1298c040334130cea6e44dda03516d86e774d18d376Kenny Root    JNIEnv* env = getEnv();
1308c040334130cea6e44dda03516d86e774d18d376Kenny Root    if (env == NULL) {
1318c040334130cea6e44dda03516d86e774d18d376Kenny Root        ALOGE("term_prescroll: couldn't get JNIEnv");
1328c040334130cea6e44dda03516d86e774d18d376Kenny Root        return 0;
1338c040334130cea6e44dda03516d86e774d18d376Kenny Root    }
1348c040334130cea6e44dda03516d86e774d18d376Kenny Root
1358c040334130cea6e44dda03516d86e774d18d376Kenny Root    return env->CallIntMethod(term->getCallbacks(), prescrollMethod);
136ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey}
137ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey
138ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkeystatic int term_moverect(VTermRect dest, VTermRect src, void *user) {
139ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey    Terminal* term = reinterpret_cast<Terminal*>(user);
140ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey    ALOGW("term_moverect");
1418c040334130cea6e44dda03516d86e774d18d376Kenny Root
1428c040334130cea6e44dda03516d86e774d18d376Kenny Root    JNIEnv* env = getEnv();
1438c040334130cea6e44dda03516d86e774d18d376Kenny Root    if (env == NULL) {
1448c040334130cea6e44dda03516d86e774d18d376Kenny Root        ALOGE("term_moverect: couldn't get JNIEnv");
1458c040334130cea6e44dda03516d86e774d18d376Kenny Root        return 0;
1468c040334130cea6e44dda03516d86e774d18d376Kenny Root    }
1478c040334130cea6e44dda03516d86e774d18d376Kenny Root
1488c040334130cea6e44dda03516d86e774d18d376Kenny Root    return env->CallIntMethod(term->getCallbacks(), moveRectMethod);
149ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey}
150ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey
151ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkeystatic int term_movecursor(VTermPos pos, VTermPos oldpos, int visible, void *user) {
152ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey    Terminal* term = reinterpret_cast<Terminal*>(user);
153ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey    ALOGW("term_movecursor");
1548c040334130cea6e44dda03516d86e774d18d376Kenny Root
1558c040334130cea6e44dda03516d86e774d18d376Kenny Root    JNIEnv* env = getEnv();
1568c040334130cea6e44dda03516d86e774d18d376Kenny Root    if (env == NULL) {
1578c040334130cea6e44dda03516d86e774d18d376Kenny Root        ALOGE("term_movecursor: couldn't get JNIEnv");
1588c040334130cea6e44dda03516d86e774d18d376Kenny Root        return 0;
1598c040334130cea6e44dda03516d86e774d18d376Kenny Root    }
1608c040334130cea6e44dda03516d86e774d18d376Kenny Root
1618c040334130cea6e44dda03516d86e774d18d376Kenny Root    return env->CallIntMethod(term->getCallbacks(), moveCursorMethod);
162ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey}
163ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey
164ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkeystatic int term_settermprop(VTermProp prop, VTermValue *val, void *user) {
165ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey    Terminal* term = reinterpret_cast<Terminal*>(user);
166ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey    ALOGW("term_settermprop");
1678c040334130cea6e44dda03516d86e774d18d376Kenny Root
1688c040334130cea6e44dda03516d86e774d18d376Kenny Root    JNIEnv* env = getEnv();
1698c040334130cea6e44dda03516d86e774d18d376Kenny Root    if (env == NULL) {
1708c040334130cea6e44dda03516d86e774d18d376Kenny Root        ALOGE("term_settermprop: couldn't get JNIEnv");
1718c040334130cea6e44dda03516d86e774d18d376Kenny Root        return 0;
1728c040334130cea6e44dda03516d86e774d18d376Kenny Root    }
1738c040334130cea6e44dda03516d86e774d18d376Kenny Root
1748c040334130cea6e44dda03516d86e774d18d376Kenny Root    switch (vterm_get_prop_type(prop)) {
1758c040334130cea6e44dda03516d86e774d18d376Kenny Root    case VTERM_VALUETYPE_BOOL:
1768c040334130cea6e44dda03516d86e774d18d376Kenny Root        return env->CallIntMethod(term->getCallbacks(), setTermPropBooleanMethod,
1778c040334130cea6e44dda03516d86e774d18d376Kenny Root                static_cast<jboolean>(val->boolean));
1788c040334130cea6e44dda03516d86e774d18d376Kenny Root    case VTERM_VALUETYPE_INT:
1798c040334130cea6e44dda03516d86e774d18d376Kenny Root        return env->CallIntMethod(term->getCallbacks(), setTermPropIntMethod, prop, val->number);
1808c040334130cea6e44dda03516d86e774d18d376Kenny Root    case VTERM_VALUETYPE_STRING:
1818c040334130cea6e44dda03516d86e774d18d376Kenny Root        return env->CallIntMethod(term->getCallbacks(), setTermPropStringMethod, prop,
1828c040334130cea6e44dda03516d86e774d18d376Kenny Root                env->NewStringUTF(val->string));
1838c040334130cea6e44dda03516d86e774d18d376Kenny Root    case VTERM_VALUETYPE_COLOR:
1848c040334130cea6e44dda03516d86e774d18d376Kenny Root        return env->CallIntMethod(term->getCallbacks(), setTermPropIntMethod, prop, val->color.red,
1858c040334130cea6e44dda03516d86e774d18d376Kenny Root                val->color.green, val->color.blue);
1868c040334130cea6e44dda03516d86e774d18d376Kenny Root    default:
1878c040334130cea6e44dda03516d86e774d18d376Kenny Root        ALOGE("unknown callback type");
1888c040334130cea6e44dda03516d86e774d18d376Kenny Root        return 0;
1898c040334130cea6e44dda03516d86e774d18d376Kenny Root    }
190ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey}
191ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey
192ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkeystatic int term_setmousefunc(VTermMouseFunc func, void *data, void *user) {
193ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey    Terminal* term = reinterpret_cast<Terminal*>(user);
194ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey    ALOGW("term_setmousefunc");
195ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey    return 1;
196ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey}
197ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey
198ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkeystatic int term_bell(void *user) {
199ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey    Terminal* term = reinterpret_cast<Terminal*>(user);
200ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey    ALOGW("term_bell");
2018c040334130cea6e44dda03516d86e774d18d376Kenny Root
2028c040334130cea6e44dda03516d86e774d18d376Kenny Root    JNIEnv* env = getEnv();
2038c040334130cea6e44dda03516d86e774d18d376Kenny Root    if (env == NULL) {
2048c040334130cea6e44dda03516d86e774d18d376Kenny Root        ALOGE("term_bell: couldn't get JNIEnv");
2058c040334130cea6e44dda03516d86e774d18d376Kenny Root        return 0;
2068c040334130cea6e44dda03516d86e774d18d376Kenny Root    }
2078c040334130cea6e44dda03516d86e774d18d376Kenny Root
2088c040334130cea6e44dda03516d86e774d18d376Kenny Root    return env->CallIntMethod(term->getCallbacks(), bellMethod);
209ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey}
210ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey
211ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkeystatic int term_resize(int rows, int cols, void *user) {
212ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey    Terminal* term = reinterpret_cast<Terminal*>(user);
213ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey    ALOGW("term_resize");
2148c040334130cea6e44dda03516d86e774d18d376Kenny Root
2158c040334130cea6e44dda03516d86e774d18d376Kenny Root    JNIEnv* env = getEnv();
2168c040334130cea6e44dda03516d86e774d18d376Kenny Root    if (env == NULL) {
2178c040334130cea6e44dda03516d86e774d18d376Kenny Root        ALOGE("term_bell: couldn't get JNIEnv");
2188c040334130cea6e44dda03516d86e774d18d376Kenny Root        return 0;
2198c040334130cea6e44dda03516d86e774d18d376Kenny Root    }
2208c040334130cea6e44dda03516d86e774d18d376Kenny Root
2218c040334130cea6e44dda03516d86e774d18d376Kenny Root    return env->CallIntMethod(term->getCallbacks(), resizeMethod);
222ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey}
223ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey
224ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkeystatic VTermScreenCallbacks cb = {
225ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey    .damage = term_damage,
226ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey    .prescroll = term_prescroll,
227ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey    .moverect = term_moverect,
228ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey    .movecursor = term_movecursor,
229ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey    .settermprop = term_settermprop,
230ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey    .setmousefunc = term_setmousefunc,
231ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey    .bell = term_bell,
232ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey    .resize = term_resize,
233ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey};
234ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey
2358c040334130cea6e44dda03516d86e774d18d376Kenny RootTerminal::Terminal(jobject callbacks, int rows, int cols) :
2368c040334130cea6e44dda03516d86e774d18d376Kenny Root        mCallbacks(callbacks), mRows(rows), mCols(cols) {
237ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey    /* Create VTerm */
238ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey    mVt = vterm_new(rows, cols);
239ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey    vterm_parser_set_utf8(mVt, 1);
240ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey
241ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey    /* Set up screen */
242ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey    mVts = vterm_obtain_screen(mVt);
243ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey    vterm_screen_enable_altscreen(mVts, 1);
244ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey    vterm_screen_set_callbacks(mVts, &cb, this);
245ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey    vterm_screen_set_damage_merge(mVts, VTERM_DAMAGE_SCROLL);
246ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey
2475d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkey    /* None of the docs about termios explain how to construct a new one of
2485d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkey     * these, so this is largely a guess */
2495d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkey    struct termios termios = {
2505d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkey        .c_iflag = ICRNL|IXON|IUTF8,
2515d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkey        .c_oflag = OPOST|ONLCR|NL0|CR0|TAB0|BS0|VT0|FF0,
2525d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkey        .c_cflag = CS8|CREAD,
2535d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkey        .c_lflag = ISIG|ICANON|IEXTEN|ECHO|ECHOE|ECHOK,
2545d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkey        /* c_cc later */
2555d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkey    };
2565d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkey
2575d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkey//    cfsetspeed(&termios, 38400);
2585d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkey//
2595d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkey//    termios.c_cc[VINTR]    = 0x1f & 'C';
2605d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkey//    termios.c_cc[VQUIT]    = 0x1f & '\\';
2615d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkey//    termios.c_cc[VERASE]   = 0x7f;
2625d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkey//    termios.c_cc[VKILL]    = 0x1f & 'U';
2635d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkey//    termios.c_cc[VEOF]     = 0x1f & 'D';
2645d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkey//    termios.c_cc[VEOL]     = _POSIX_VDISABLE;
2655d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkey//    termios.c_cc[VEOL2]    = _POSIX_VDISABLE;
2665d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkey//    termios.c_cc[VSTART]   = 0x1f & 'Q';
2675d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkey//    termios.c_cc[VSTOP]    = 0x1f & 'S';
2685d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkey//    termios.c_cc[VSUSP]    = 0x1f & 'Z';
2695d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkey//    termios.c_cc[VREPRINT] = 0x1f & 'R';
2705d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkey//    termios.c_cc[VWERASE]  = 0x1f & 'W';
2715d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkey//    termios.c_cc[VLNEXT]   = 0x1f & 'V';
2725d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkey//    termios.c_cc[VMIN]     = 1;
2735d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkey//    termios.c_cc[VTIME]    = 0;
2745d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkey//
2755d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkey//    struct winsize size = { mRows, mCols, 0, 0 };
2765d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkey//
2775d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkey//    pid_t kid = forkpty(&mMasterFd, NULL, &termios, &size);
2785d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkey//    if(kid == 0) {
2795d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkey//        /* Restore the ISIG signals back to defaults */
2805d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkey//        signal(SIGINT, SIG_DFL);
2815d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkey//        signal(SIGQUIT, SIG_DFL);
2825d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkey//        signal(SIGSTOP, SIG_DFL);
2835d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkey//        signal(SIGCONT, SIG_DFL);
2845d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkey//
2855d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkey//        gchar *term = g_strdup_printf("TERM=%s", CONF_term);
2865d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkey//        putenv(term);
2875d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkey//        /* Do not free 'term', it is part of the environment */
2885d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkey//
2895d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkey//        char *shell = getenv("SHELL");
2905d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkey//        char *args[2] = {shell, NULL};
2915d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkey//        execvp(shell, args);
2925d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkey//        fprintf(stderr_save, "Cannot exec(%s) - %s\n", shell, strerror(errno));
2935d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkey//        _exit(1);
2945d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkey//    }
2955d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkey//
2965d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkey//    fcntl(mMasterFd, F_SETFL, fcntl(mMasterFd, F_GETFL) | O_NONBLOCK);
297ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey}
298ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey
299ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff SharkeyTerminal::~Terminal() {
3005d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkey    close(mMasterFd);
301ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey    vterm_free(mVt);
302ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey}
303ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey
3045d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkeysize_t Terminal::write(const char *bytes, size_t len) {
3055d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkey    return ::write(mMasterFd, bytes, len);
3065d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkey}
3075d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkey
308410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkeyint Terminal::resize(short unsigned int rows, short unsigned int cols) {
309410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey    ALOGD("resize(%d, %d)", rows, cols);
3105d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkey    mRows = rows;
3115d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkey    mCols = cols;
3125d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkey    struct winsize size = { rows, cols, 0, 0 };
3135d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkey    ioctl(mMasterFd, TIOCSWINSZ, &size);
314410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey    return 0;
315410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey}
316410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey
317410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkeyint Terminal::getCell(VTermPos pos, VTermScreenCell* cell) {
318410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey    return vterm_screen_get_cell(mVts, pos, cell);
3195d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkey}
3205d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkey
3218c040334130cea6e44dda03516d86e774d18d376Kenny Rootint Terminal::getRows() const {
322ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey    return mRows;
323ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey}
324ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey
325410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkeyint Terminal::getCols() const {
326410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey    return mCols;
327410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey}
328410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey
3298c040334130cea6e44dda03516d86e774d18d376Kenny Rootjobject Terminal::getCallbacks() const {
3308c040334130cea6e44dda03516d86e774d18d376Kenny Root    return mCallbacks;
3318c040334130cea6e44dda03516d86e774d18d376Kenny Root}
3328c040334130cea6e44dda03516d86e774d18d376Kenny Root
333ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey/*
334ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey * JNI glue
335ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey */
336ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey
3378c040334130cea6e44dda03516d86e774d18d376Kenny Rootstatic jint com_android_terminal_Terminal_nativeInit(JNIEnv* env, jclass clazz, jobject callbacks,
338ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey        jint rows, jint cols) {
3398c040334130cea6e44dda03516d86e774d18d376Kenny Root    return reinterpret_cast<jint>(new Terminal(env->NewGlobalRef(callbacks), rows, cols));
340ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey}
341ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey
3425d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkeystatic void com_android_terminal_Terminal_nativeWrite(JNIEnv* env,
3435d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkey        jclass clazz, jint ptr) {
3445d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkey    Terminal* term = reinterpret_cast<Terminal*>(ptr);
3455d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkey    // const char *bytes, size_t len
3465d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkey    term->write(NULL, 0);
3475d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkey}
3485d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkey
349410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkeystatic jint com_android_terminal_Terminal_nativeResize(JNIEnv* env,
3505d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkey        jclass clazz, jint ptr, jint rows, jint cols) {
3515d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkey    Terminal* term = reinterpret_cast<Terminal*>(ptr);
352410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey    return term->resize(rows, cols);
353410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey}
354410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey
355410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkeystatic jint com_android_terminal_Terminal_nativeGetCell(JNIEnv* env,
356410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey        jclass clazz, jint ptr, jint row, jint col, jobject cell) {
357410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey    //ALOGD("getCell(%d, %d)", row, col);
358410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey    Terminal* term = reinterpret_cast<Terminal*>(ptr);
359410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey
360410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey    VTermPos pos = {
361410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey        .row = row,
362410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey        .col = col,
363410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey    };
364410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey
365410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey    VTermScreenCell termCell;
366410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey    memset(&termCell, 0, sizeof(VTermScreenCell));
367410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey    int res = term->getCell(pos, &termCell);
368410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey
369410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey    // TODO: support full UTF-32 characters
370410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey    // for testing, 0x00020000 should become 0xD840 0xDC00
371410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey
372410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey    jintArray charsArray = (jintArray)env->GetObjectField(cell, cellCharsField);
373410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey    jint *chars = env->GetIntArrayElements(charsArray, 0);
374410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey    chars[0] = '$';
375410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey    chars[1] = 0x00;
376410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey    env->ReleaseIntArrayElements(charsArray, chars, 0);
377410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey
378410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey    return 0;
3795d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkey}
3805d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkey
381ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkeystatic jint com_android_terminal_Terminal_nativeGetRows(JNIEnv* env, jclass clazz, jint ptr) {
382ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey    Terminal* term = reinterpret_cast<Terminal*>(ptr);
383ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey    return term->getRows();
384ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey}
385ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey
386410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkeystatic jint com_android_terminal_Terminal_nativeGetCols(JNIEnv* env, jclass clazz, jint ptr) {
387410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey    Terminal* term = reinterpret_cast<Terminal*>(ptr);
388410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey    return term->getCols();
389410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey}
390410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey
391ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkeystatic JNINativeMethod gMethods[] = {
3928c040334130cea6e44dda03516d86e774d18d376Kenny Root    { "nativeInit", "(Lcom/android/terminal/TerminalCallbacks;II)I", (void*)com_android_terminal_Terminal_nativeInit },
393410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey    { "nativeResize", "(III)I", (void*)com_android_terminal_Terminal_nativeResize },
394410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey    { "nativeGetCell", "(IIILcom/android/terminal/Terminal$Cell;)I", (void*)com_android_terminal_Terminal_nativeGetCell },
395ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey    { "nativeGetRows", "(I)I", (void*)com_android_terminal_Terminal_nativeGetRows },
396410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey    { "nativeGetCols", "(I)I", (void*)com_android_terminal_Terminal_nativeGetCols },
397ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey};
398ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey
399ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkeyint register_com_android_terminal_Terminal(JNIEnv* env) {
4008c040334130cea6e44dda03516d86e774d18d376Kenny Root    ScopedLocalRef<jclass> localClass(env,
4018c040334130cea6e44dda03516d86e774d18d376Kenny Root            env->FindClass("com/android/terminal/TerminalCallbacks"));
4028c040334130cea6e44dda03516d86e774d18d376Kenny Root
4038c040334130cea6e44dda03516d86e774d18d376Kenny Root    android::terminalCallbacksClass = reinterpret_cast<jclass>(env->NewGlobalRef(localClass.get()));
4048c040334130cea6e44dda03516d86e774d18d376Kenny Root
4058c040334130cea6e44dda03516d86e774d18d376Kenny Root    android::damageMethod = env->GetMethodID(terminalCallbacksClass, "damage", "(IIII)I");
4068c040334130cea6e44dda03516d86e774d18d376Kenny Root    android::prescrollMethod = env->GetMethodID(terminalCallbacksClass, "prescroll", "(IIII)I");
4078c040334130cea6e44dda03516d86e774d18d376Kenny Root    android::moveRectMethod = env->GetMethodID(terminalCallbacksClass, "moveRect", "(IIIIIIII)I");
4088c040334130cea6e44dda03516d86e774d18d376Kenny Root    android::moveCursorMethod = env->GetMethodID(terminalCallbacksClass, "moveCursor",
4098c040334130cea6e44dda03516d86e774d18d376Kenny Root            "(IIIIIIIII)I");
4108c040334130cea6e44dda03516d86e774d18d376Kenny Root    android::setTermPropBooleanMethod = env->GetMethodID(terminalCallbacksClass,
4118c040334130cea6e44dda03516d86e774d18d376Kenny Root            "setTermPropBoolean", "(IZ)I");
4128c040334130cea6e44dda03516d86e774d18d376Kenny Root    android::setTermPropIntMethod = env->GetMethodID(terminalCallbacksClass, "setTermPropInt",
4138c040334130cea6e44dda03516d86e774d18d376Kenny Root            "(II)I");
4148c040334130cea6e44dda03516d86e774d18d376Kenny Root    android::setTermPropStringMethod = env->GetMethodID(terminalCallbacksClass, "setTermPropString",
4158c040334130cea6e44dda03516d86e774d18d376Kenny Root            "(ILjava/lang/String;)I");
4168c040334130cea6e44dda03516d86e774d18d376Kenny Root    android::setTermPropColorMethod = env->GetMethodID(terminalCallbacksClass, "setTermPropColor",
4178c040334130cea6e44dda03516d86e774d18d376Kenny Root            "(IIII)I");
4188c040334130cea6e44dda03516d86e774d18d376Kenny Root    android::bellMethod = env->GetMethodID(terminalCallbacksClass, "bell", "()I");
4198c040334130cea6e44dda03516d86e774d18d376Kenny Root    android::resizeMethod = env->GetMethodID(terminalCallbacksClass, "resize", "(II)I");
4208c040334130cea6e44dda03516d86e774d18d376Kenny Root
421410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey    ScopedLocalRef<jclass> cellLocal(env,
422410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey            env->FindClass("com/android/terminal/Terminal$Cell"));
423410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey    cellClass = reinterpret_cast<jclass>(env->NewGlobalRef(cellLocal.get()));
424410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey    cellCharsField = env->GetFieldID(cellClass, "chars", "[C");
425410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey
4268c040334130cea6e44dda03516d86e774d18d376Kenny Root    env->GetJavaVM(&gJavaVM);
4278c040334130cea6e44dda03516d86e774d18d376Kenny Root
428ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey    return jniRegisterNativeMethods(env, "com/android/terminal/Terminal",
429ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey            gMethods, NELEM(gMethods));
430ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey}
431ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey
432ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey} /* namespace android */
433