├── .gitignore
├── .idea
├── .name
├── codeStyleSettings.xml
├── compiler.xml
├── dictionaries
│ └── elias.xml
├── encodings.xml
├── inspectionProfiles
│ ├── Project_Default.xml
│ └── profiles_settings.xml
├── libraries
│ └── guava_17_0.xml
├── misc.xml
├── modules.xml
├── runConfigurations
│ └── Test.xml
├── scopes
│ └── scope_settings.xml
├── uiDesigner.xml
└── vcs.xml
├── build-tools
├── .dir-locals.el
├── Makefile
├── android.cc
├── android.hh
├── eval_expression.cc
├── generate_headers.sh
├── java_ostream.cc
├── java_ostream.hh
├── org_gnu_apl_Native.h
├── utils.cc
└── utils.hh
├── client
├── AndroidManifest.xml
├── ant.properties
├── assets
│ ├── files
│ │ ├── etc
│ │ │ └── gnu-apl.d
│ │ │ │ └── preferences
│ │ └── lib
│ │ │ └── apl
│ │ │ ├── wslib3
│ │ │ └── meta.apl
│ │ │ ├── wslib4
│ │ │ └── dummy.apl
│ │ │ └── wslib5
│ │ │ └── HTML.apl
│ └── fonts
│ │ ├── FreeMono.ttf
│ │ ├── FreeMonoBold.ttf
│ │ ├── FreeMonoBoldOblique.ttf
│ │ └── FreeMonoOblique.ttf
├── build.xml
├── client.iml
├── gen
│ └── com
│ │ └── dhsdevelopments
│ │ └── aplandroid
│ │ ├── BuildConfig.java
│ │ ├── Manifest.java
│ │ └── R.java
├── libs
│ └── armeabi
│ │ └── libapl.so
├── local.properties
├── proguard-project.txt
├── project.properties
├── res
│ ├── drawable-hdpi
│ │ ├── ic_launcher.png
│ │ ├── icon_en_gb.png
│ │ ├── icon_en_us.png
│ │ ├── sym_keyboard_delete.png
│ │ ├── sym_keyboard_done.png
│ │ ├── sym_keyboard_return.png
│ │ ├── sym_keyboard_search.png
│ │ ├── sym_keyboard_shift.png
│ │ └── sym_keyboard_space.png
│ ├── drawable-ldpi
│ │ └── ic_launcher.png
│ ├── drawable-mdpi
│ │ ├── ic_launcher.png
│ │ ├── icon_en_gb.png
│ │ ├── icon_en_us.png
│ │ ├── sym_keyboard_delete.png
│ │ ├── sym_keyboard_done.png
│ │ ├── sym_keyboard_return.png
│ │ ├── sym_keyboard_search.png
│ │ ├── sym_keyboard_shift.png
│ │ └── sym_keyboard_space.png
│ ├── drawable-xhdpi
│ │ └── ic_launcher.png
│ ├── layout
│ │ ├── apl_input.xml
│ │ ├── input.xml
│ │ ├── interpreter.xml
│ │ ├── interpreter_log.xml
│ │ └── result_text.xml
│ ├── menu
│ │ └── main_activity_actions.xml
│ ├── values-land
│ │ └── dimens.xml
│ ├── values
│ │ ├── attrs.xml
│ │ ├── colors.xml
│ │ ├── dimens.xml
│ │ └── strings.xml
│ └── xml
│ │ ├── ime_preferences.xml
│ │ ├── keyboard_layout.xml
│ │ ├── method.xml
│ │ ├── qwerty.xml
│ │ ├── symbols.xml
│ │ ├── symbols_apl.xml
│ │ ├── symbols_apl_shift.xml
│ │ └── symbols_shift.xml
└── src
│ └── com
│ └── dhsdevelopments
│ └── aplandroid
│ ├── AplAndroidApp.java
│ ├── AplNative.java
│ ├── EvalRequest.java
│ ├── Installer.java
│ ├── Interpreter.java
│ ├── InterpreterFragment.java
│ ├── Log.java
│ ├── ResultListAdapter.java
│ ├── ResultListEntry.java
│ ├── input1
│ ├── AplInput.java
│ ├── AplKeyboardView.java
│ └── CustomKeyboard.java
│ └── input2
│ ├── CandidateView.java
│ ├── ImePreferences.java
│ ├── InputMethodSettingsFragment.java
│ ├── InputMethodSettingsImpl.java
│ ├── InputMethodSettingsInterface.java
│ ├── LatinKeyboard.java
│ ├── LatinKeyboardView.java
│ ├── PaintOverride.java
│ └── SoftKeyboard.java
├── gnu-apl-api
├── gnu-apl-api.iml
└── src
│ └── org
│ └── gnu
│ └── apl
│ ├── AplException.java
│ ├── AplExecException.java
│ ├── AplValue.java
│ ├── Native.java
│ └── Test.java
├── lib
└── guava-17.0.jar
└── notes.txt
/.gitignore:
--------------------------------------------------------------------------------
1 | out
2 | /.idea/workspace.xml
3 | *~
4 | *.o
5 | /build-tools/libapl.dylib
6 | /build-tools/libapl.so
7 | /build-tools/.apl.history
8 |
--------------------------------------------------------------------------------
/.idea/.name:
--------------------------------------------------------------------------------
1 | android-gnu-apl
--------------------------------------------------------------------------------
/.idea/codeStyleSettings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/.idea/dictionaries/elias.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | aplandroid
5 | dest
6 | eval
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/inspectionProfiles/Project_Default.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/.idea/inspectionProfiles/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/.idea/libraries/guava_17_0.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/.idea/runConfigurations/Test.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/.idea/scopes/scope_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/.idea/uiDesigner.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | -
6 |
7 |
8 | -
9 |
10 |
11 | -
12 |
13 |
14 | -
15 |
16 |
17 | -
18 |
19 |
20 |
21 |
22 |
23 | -
24 |
25 |
26 |
27 |
28 |
29 | -
30 |
31 |
32 |
33 |
34 |
35 | -
36 |
37 |
38 |
39 |
40 |
41 | -
42 |
43 |
44 |
45 |
46 | -
47 |
48 |
49 |
50 |
51 | -
52 |
53 |
54 |
55 |
56 | -
57 |
58 |
59 |
60 |
61 | -
62 |
63 |
64 |
65 |
66 | -
67 |
68 |
69 |
70 |
71 | -
72 |
73 |
74 | -
75 |
76 |
77 |
78 |
79 | -
80 |
81 |
82 |
83 |
84 | -
85 |
86 |
87 |
88 |
89 | -
90 |
91 |
92 |
93 |
94 | -
95 |
96 |
97 |
98 |
99 | -
100 |
101 |
102 | -
103 |
104 |
105 | -
106 |
107 |
108 | -
109 |
110 |
111 | -
112 |
113 |
114 |
115 |
116 | -
117 |
118 |
119 | -
120 |
121 |
122 |
123 |
124 |
125 |
126 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/build-tools/.dir-locals.el:
--------------------------------------------------------------------------------
1 | ((c++-mode . ((eval . (progn
2 | (em-append-include-dirs (append (list (expand-file-name "~/src/apl-android/src"))
3 | (if (eq system-type 'darwin)
4 | (list "/Library/Java/JavaVirtualMachines/jdk1.7.0_45.jdk/Contents/Home/include"
5 | "/Library/Java/JavaVirtualMachines/jdk1.7.0_45.jdk/Contents/Home/include/darwin")
6 | (list "/usr/local/jdk1.7.0_45/include"
7 | "/usr/local/jdk1.7.0_45/include/linux"))))
8 | (when (eq system-type 'darwin)
9 | (em-append-include-dirs (list "/usr/local/Cellar/gettext/0.18.3.2/include")))
10 | (flycheck-mode 1)
11 | (company-mode 1))))))
12 |
--------------------------------------------------------------------------------
/build-tools/Makefile:
--------------------------------------------------------------------------------
1 | OBJS = android.o eval_expression.o utils.o java_ostream.o
2 |
3 | GNU_APL_SRC = $(HOME)/src/apl-android
4 |
5 | UNAME = $(shell uname)
6 | ifeq ($(UNAME),Darwin)
7 | JAVA_HOME = /Library/Java/JavaVirtualMachines/jdk1.7.0_60.jdk/Contents/Home
8 | JAVA_INCLUDES = -I$(JAVA_HOME)/include -I$(JAVA_HOME)/include/darwin
9 | else
10 | JAVA_HOME = /usr/local/jdk1.7.0_45
11 | JAVA_INCLUDES = -I$(JAVA_HOME)/include -I$(JAVA_HOME)/include/linux
12 | endif
13 |
14 | CROSSBUILD = $(shell sh -c "cat $(GNU_APL_SRC)/config.status | grep androideabi >/dev/null && echo androideabi")
15 | ifeq ($(CROSSBUILD),androideabi)
16 | CC=arm-linux-androideabi-gcc
17 | CXX=arm-linux-androideabi-g++
18 | LIBRARY_EXT = so
19 | SHARED_FLAGS = -shared
20 | APL_LIBRARIES = -ldl -lm -lgomp -llog
21 | else
22 | ifeq ($(UNAME),Darwin)
23 | LIBRARY_EXT = dylib
24 | SHARED_FLAGS = -dynamiclib -Wl,-undefined,dynamic_lookup
25 | APL_LIBRARIES = -lreadline -ldl -lncurses -lpthread -lm -lblas -llapack -lcurses
26 | else
27 | LIBRARY_EXT = so
28 | SHARED_FLAGS = -shared
29 | APL_LIBRARIES = -lreadline -ldl -lncurses -lpthread -lrt -lm -lgomp -lblas -llapack -lcurses -lnsl
30 | endif
31 | endif
32 |
33 | LIBNAME = libapl.$(LIBRARY_EXT)
34 |
35 | CXXFLAGS = -g -Wall -fPIC $(JAVA_INCLUDES) -I$(GNU_APL_SRC)/src
36 |
37 | all: $(LIBNAME)
38 |
39 | $(LIBNAME): $(OBJS)
40 | $(CXX) -g -fPIC -rdynamic $(SHARED_FLAGS) -o $(LIBNAME) $(GNU_APL_SRC)/src/*.o $(OBJS) $(APL_LIBRARIES)
41 |
42 | copylib: $(LIBNAME)
43 | cp $(LIBNAME) ../client/libs/armeabi/$(LIBNAME)
44 |
45 | clean:
46 | rm -f $(OBJS) $(LIBNAME)
47 |
--------------------------------------------------------------------------------
/build-tools/android.cc:
--------------------------------------------------------------------------------
1 | //#include
2 | #include
3 | #include
4 | #include
5 | #include
6 |
7 | #include "android.hh"
8 | #include "utils.hh"
9 | #include "java_ostream.hh"
10 |
11 | #include "org_gnu_apl_Native.h"
12 |
13 | #include "Command.hh"
14 |
15 | static jmethodID append;
16 |
17 | template >
18 | class JavaAplStreambuf : public std::basic_streambuf
19 | {
20 | public:
21 | JavaAplStreambuf() : env( NULL ), writer( NULL ) {}
22 | void set_writer( JNIEnv *env_in, jobject writer_in ) { env = env_in; writer = writer_in; }
23 | void unset_writer( void ) { env = NULL; writer = NULL; }
24 |
25 | protected:
26 | void put_buffer( const typename traits::char_type *s, std::streamsize n ) {
27 | if( env != NULL && writer != NULL ) {
28 | for( int i = 0 ; i < n ; i++ ) {
29 | buf.push_back( s[i] );
30 | }
31 | int end = buf.size();
32 | // At this point we might have a broken UTF-8 sequence at the end
33 | if( (buf[buf.size() - 1] & 0x80) == 0x80 ) {
34 | // OK, last character is part of a multibyte sequence
35 | // Find the start of the sequence
36 | int p = end - 1;
37 | while( p > 0 && (buf[p] & 0xC0) != 0xC0 ) {
38 | p--;
39 | }
40 | if( (buf[p] & 0xC0) == 0xC0 ) {
41 | // p now points to the start of the final multibyte sequence
42 | // Check if this sequence is broken
43 | int num_ones = 0;
44 | int v = static_cast(buf[p]) & 0xFF;
45 | while( v & 0x80 ) {
46 | v <<= 1;
47 | num_ones++;
48 | }
49 | // v now contains the number of left-most bits
50 | // this number is equal to the size of the multibyte sequence
51 | if( num_ones > end - p ) {
52 | end = p;
53 | }
54 | }
55 | else {
56 | end = p;
57 | }
58 | }
59 |
60 | if( end > 0 ) {
61 | char result_buf[end + 1];
62 | for( int i = 0 ; i < end ; i++ ) {
63 | result_buf[i] = buf[i];
64 | }
65 | result_buf[end] = 0;
66 |
67 | jstring buf_javastring = env->NewStringUTF( result_buf );
68 | if( buf_javastring == NULL ) {
69 | throw new JavaExceptionThrown( "Error creating string" );
70 | }
71 |
72 | jobject ret = env->CallObjectMethod( writer, append, buf_javastring );
73 | if( env->ExceptionCheck() ) {
74 | env->DeleteLocalRef( buf_javastring );
75 | throw JavaExceptionThrown( "Error writing string" );
76 | }
77 |
78 | buf.erase( buf.begin(), buf.begin() + end );
79 |
80 | env->DeleteLocalRef( ret );
81 | env->DeleteLocalRef( buf_javastring );
82 | }
83 | }
84 | }
85 |
86 | typename traits::int_type overflow( typename traits::int_type c ) {
87 | typename traits::char_type buf[2];
88 | buf[0] = c;
89 | buf[1] = 0;
90 | put_buffer( buf, 1 );
91 | return traits::not_eof( c );
92 | }
93 |
94 | std::streamsize xsputn( const typename traits::char_type *s, std::streamsize n ) {
95 | put_buffer( s, n );
96 | return n;
97 | }
98 |
99 | JNIEnv *env;
100 | jobject writer;
101 | std::vector buf;
102 | };
103 |
104 | JavaAplStreambuf cin_streambuf;
105 | JavaAplStreambuf cout_streambuf;
106 | JavaAplStreambuf cerr_streambuf;
107 | JavaAplStreambuf uerr_streambuf;
108 |
109 | std::ostream CIN( &cin_streambuf );
110 | std::ostream COUT( &cout_streambuf );
111 | std::ostream CERR( &cerr_streambuf );
112 | std::ostream UERR( &uerr_streambuf );
113 |
114 | int init_apl( int argc, const char *argv[] );
115 |
116 | JNIEXPORT jint JNICALL Java_org_gnu_apl_Native_init( JNIEnv *env, jclass, jstring path_jstring )
117 | {
118 | const char *argv[] = { "apl", "--silent", "--rawCIN", NULL };
119 |
120 | JniStringWrapper path_string( env, path_jstring );
121 |
122 | setenv( "APL_LIB_ROOT", path_string.get_string(), 1 );
123 |
124 | jclass javaIoWriterCl = env->FindClass( "java/io/Writer" );
125 | if( javaIoWriterCl == NULL ) {
126 | return 0;
127 | }
128 |
129 | append = env->GetMethodID( javaIoWriterCl, "append", "(Ljava/lang/CharSequence;)Ljava/io/Writer;");
130 | if( append == NULL ) {
131 | return 0;
132 | }
133 |
134 | int ret = init_apl( 3, argv );
135 | return ret;
136 | }
137 |
138 | JNIEXPORT void JNICALL Java_org_gnu_apl_Native_evalWithIo( JNIEnv *env, jclass,
139 | jstring expr,
140 | jobject cin,
141 | jobject cout,
142 | jobject cerr,
143 | jobject uerr )
144 | {
145 | cin_streambuf.set_writer( env, cin );
146 | cout_streambuf.set_writer( env, cout );
147 | cerr_streambuf.set_writer( env, cerr );
148 | uerr_streambuf.set_writer( env, uerr );
149 |
150 | JniStringWrapper expr_java_str( env, expr );
151 | UTF8_string utf8( expr_java_str.get_string() );
152 | UCS_string expr_ucs( utf8 );
153 |
154 | try {
155 | Command::process_line( expr_ucs );
156 | }
157 | catch( JavaExceptionThrown &e ) {
158 | // Exception is already set to the correct value
159 | }
160 | catch( ErrorWithComment &e ) {
161 | jclass exceptionCl = env->FindClass( "org/gnu/apl/AplException" );
162 | if( exceptionCl != NULL ) {
163 | env->ThrowNew( exceptionCl, e.get_message().c_str() );
164 | }
165 | }
166 |
167 | cin_streambuf.unset_writer();
168 | cout_streambuf.unset_writer();
169 | cerr_streambuf.unset_writer();
170 | uerr_streambuf.unset_writer();
171 | }
172 |
--------------------------------------------------------------------------------
/build-tools/android.hh:
--------------------------------------------------------------------------------
1 | #ifndef ANDROID_HH
2 | #define ANDROID_HH
3 |
4 | #pragma GCC diagnostic push
5 | #pragma GCC diagnostic ignored "-Wunknown-pragmas"
6 | #pragma GCC diagnostic ignored "-Wpragmas"
7 | #pragma GCC diagnostic ignored "-Wunused-variable"
8 | #pragma GCC diagnostic ignored "-Wsign-compare"
9 | #pragma GCC diagnostic ignored "-Wreturn-type"
10 | #pragma GCC diagnostic ignored "-Wparentheses"
11 | #pragma GCC diagnostic ignored "-Wreorder"
12 | #pragma GCC diagnostic ignored "-Wmismatched-tags"
13 | #pragma GCC diagnostic ignored "-Woverloaded-virtual"
14 | #include "Native_interface.hh"
15 | #include "Executable.hh"
16 | #include "IndexExpr.hh"
17 | #include "main.hh"
18 | #pragma GCC diagnostic pop
19 |
20 | #endif
21 |
--------------------------------------------------------------------------------
/build-tools/eval_expression.cc:
--------------------------------------------------------------------------------
1 | #include "android.hh"
2 | #include "utils.hh"
3 |
4 | #include "org_gnu_apl_Native.h"
5 |
6 | JNIEXPORT jobject JNICALL Java_org_gnu_apl_Native_evalExpression( JNIEnv *env, jclass cl, jstring expr )
7 | {
8 | JniStringWrapper s( env, expr );
9 |
10 | Executable *statements = 0;
11 | try {
12 | statements = StatementList::fix( s.get_string(), LOC );
13 | }
14 | catch( Error err ) {
15 | jclass execptionCl = env->FindClass( "org/gnu/apl/AplExecException" );
16 | if( execptionCl == NULL ) {
17 | return NULL;
18 | }
19 | jmethodID constructor = env->GetMethodID( execptionCl, "", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V" );
20 | if( constructor == NULL ) {
21 | return NULL;
22 | }
23 | jstring line1 = env->NewStringUTF( UTF8_string( err.get_error_line_1() ).c_str() );
24 | jstring line2 = env->NewStringUTF( UTF8_string( err.get_error_line_2() ).c_str() );
25 | jstring line3 = env->NewStringUTF( UTF8_string( err.get_error_line_3() ).c_str() );
26 | jobject ex = env->NewObject( execptionCl, constructor, line1, line2, line3 );
27 | if( ex != NULL ) {
28 | env->Throw( (jthrowable)ex );
29 | }
30 | return NULL;
31 | }
32 |
33 | if( statements == NULL ) {
34 | throw_apl_exception( env, "Parse error" );
35 | return NULL;
36 | }
37 |
38 | // Section grabbed from Command.cc
39 | {
40 | const Token_string & body = statements->get_body();
41 | if( body.size() == 3
42 | && body[0].get_tag() == TOK_ESCAPE
43 | && body[1].get_Class() == TC_END
44 | && body[2].get_tag() == TOK_RETURN_STATS )
45 | {
46 | delete statements;
47 |
48 | // remove all SI entries up to (including) the next immediate
49 | // execution context
50 | //
51 | for(bool goon = true ; goon ; ) {
52 | StateIndicator * si = Workspace::SI_top();
53 | if( si == 0 ) {
54 | break; // SI empty
55 | }
56 |
57 | const Executable * exec = si->get_executable();
58 | Assert(exec);
59 | goon = exec->get_parse_mode() != PM_STATEMENT_LIST;
60 | si->escape(); // pop local vars of user defined functions
61 | Workspace::pop_SI(LOC);
62 | }
63 | // TODO: is null the right thing to return at this point?
64 | return NULL;
65 | }
66 | }
67 |
68 | Workspace::push_SI(statements, LOC);
69 |
70 | for (;;) {
71 | //
72 | // NOTE that the entire SI may change while executing this loop.
73 | // We should therefore avoid references to SI entries.
74 | //
75 | Token token = Workspace::SI_top()->get_executable()->execute_body();
76 |
77 | // Q(token)
78 |
79 | // start over if execution has pushed a new context
80 | //
81 | if (token.get_tag() == TOK_SI_PUSHED) {
82 | continue;
83 | }
84 |
85 | // maybe call EOC handler and repeat if true returned
86 | //
87 | check_EOC:
88 | if (Workspace::SI_top()->call_eoc_handler(token)) {
89 | continue;
90 | }
91 |
92 | // the far most frequent cases are TC_VALUE and TOK_VOID
93 | // so we handle them first.
94 | //
95 | if (token.get_Class() == TC_VALUE || token.get_tag() == TOK_VOID ) {
96 | if (Workspace::SI_top()->get_executable()->get_parse_mode() == PM_STATEMENT_LIST) {
97 | if (attention_raised) {
98 | attention_raised = false;
99 | interrupt_raised = false;
100 | ATTENTION;
101 | }
102 |
103 | break; // will return to calling context
104 | }
105 |
106 | Workspace::pop_SI(LOC);
107 |
108 | // we are back in the calling SI. There should be a TOK_SI_PUSHED
109 | // token at the top of stack. Replace it with the result from
110 | // the called (just poped) SI.
111 | //
112 | {
113 | Prefix & prefix =
114 | Workspace::SI_top()->get_prefix();
115 | Assert(prefix.at0().get_tag() == TOK_SI_PUSHED);
116 |
117 | copy_1(prefix.tos().tok, token, LOC);
118 | }
119 | if (attention_raised) {
120 | attention_raised = false;
121 | interrupt_raised = false;
122 | ATTENTION;
123 | }
124 |
125 | continue;
126 | }
127 |
128 | if (token.get_tag() == TOK_BRANCH) {
129 | StateIndicator * si = Workspace::SI_top_fun();
130 |
131 | if (si == 0) {
132 | Workspace::more_error() = UCS_string(
133 | "branch back into function (→N) without "
134 | "suspended function");
135 | SYNTAX_ERROR; // →N without function,
136 | }
137 |
138 | // pop contexts above defined function
139 | //
140 | while (si != Workspace::SI_top()) {
141 | Workspace::pop_SI(LOC);
142 | }
143 |
144 | const Function_Line line = Function_Line(token.get_int_val());
145 |
146 | if (line == Function_Retry) {
147 | si->retry(LOC);
148 | }
149 | else {
150 | si->goon(line, LOC);
151 | }
152 | continue;
153 | }
154 |
155 | if (token.get_tag() == TOK_ESCAPE) {
156 | // remove all SI entries up to (including) the next immediate
157 | // execution context
158 | //
159 | for (bool goon = true ; goon ;) {
160 | StateIndicator * si = Workspace::SI_top();
161 | if (si == 0) break; // SI empty
162 |
163 | const Executable * exec = si->get_executable();
164 | Assert(exec);
165 | goon = exec->get_parse_mode() != PM_STATEMENT_LIST;
166 | si->escape(); // pop local vars of user defined functions
167 | Workspace::pop_SI(LOC);
168 | }
169 | return NULL;
170 |
171 | Assert(0 && "not reached");
172 | }
173 |
174 | if (token.get_tag() == TOK_ERROR) {
175 | // clear attention and interrupt flags
176 | //
177 | attention_raised = false;
178 | interrupt_raised = false;
179 |
180 | // check for safe execution mode. Entries in safe execution mode
181 | // can be far above the current SI entry. The EOC handler will
182 | // unroll the SI stack.
183 | //
184 | for (StateIndicator * si = Workspace::SI_top() ; si ; si = si->get_parent()) {
185 | if (si->get_safe_execution()) {
186 | // pop SI entries above the entry with safe_execution
187 | //
188 | while (Workspace::SI_top() != si) {
189 | Workspace::pop_SI(LOC);
190 | }
191 |
192 | goto check_EOC;
193 | }
194 | }
195 |
196 | Workspace::get_error()->print(CERR);
197 | if (Workspace::SI_top()->get_level() == 0) {
198 | Value::erase_stale(LOC);
199 | IndexExpr::erase_stale(LOC);
200 | }
201 | return NULL;
202 | }
203 |
204 | // we should not come here.
205 | //
206 | Q1(token) Q1(token.get_Class()) Q1(token.get_tag()) FIXME;
207 | }
208 |
209 | // pop the context for the statements
210 | //
211 | Workspace::pop_SI(LOC);
212 |
213 | return NULL;
214 | }
215 |
--------------------------------------------------------------------------------
/build-tools/generate_headers.sh:
--------------------------------------------------------------------------------
1 | /usr/local/jdk1.7.0_45/bin/javah -d ../../build-tools org.gnu.apl.Native
2 |
--------------------------------------------------------------------------------
/build-tools/java_ostream.cc:
--------------------------------------------------------------------------------
1 | #include "java_ostream.hh"
2 |
3 | #include
4 |
5 | void write_string_to_java_stream( JNIEnv *env, jobject writer, const char *s, std::streamsize n )
6 | {
7 | char str_buf[n + 1];
8 | memcpy( str_buf, s, n );
9 | str_buf[n] = 0;
10 | jstring java_string = env->NewStringUTF( str_buf );
11 | if( java_string == NULL ) {
12 | throw "Unable to allocate string";
13 | }
14 |
15 | jclass cl = env->FindClass( "java/io/Writer" );
16 | if( cl == NULL ) {
17 | throw "foo";
18 | }
19 | jmethodID append = env->GetMethodID( cl, "append", "(Ljava/lang/CharSequence;)Ljava/io/Writer;" );
20 | if( append == NULL ) {
21 | throw "bar";
22 | }
23 |
24 | env->CallObjectMethod( writer, append, java_string );
25 | if( env->ExceptionCheck() ) {
26 | throw JavaExceptionThrown( "Exception when writing stream" );
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/build-tools/java_ostream.hh:
--------------------------------------------------------------------------------
1 | #ifndef JAVA_OSTREAM_HH
2 | #define JAVA_OSTREAM_HH
3 |
4 | #include
5 | #include
6 | #include
7 |
8 | #include
9 |
10 | class ErrorWithComment
11 | {
12 | public:
13 | ErrorWithComment( const std::string &message_in ) : message( message_in ) {}
14 | std::string get_message( void ) { return message; }
15 |
16 | private:
17 | std::string message;
18 | };
19 |
20 | class JavaExceptionThrown : public ErrorWithComment
21 | {
22 | public:
23 | JavaExceptionThrown( const std::string &message_in ) : ErrorWithComment( message_in ) {}
24 | };
25 |
26 | void write_string_to_java_stream( JNIEnv *env, jobject writer, const char *s, std::streamsize n );
27 |
28 | template >
29 | class JavaStreambuf : public std::basic_streambuf
30 | {
31 | protected:
32 | typename traits::int_type overflow( typename traits::int_type c ) {
33 | std::cout << "overflow called" << std::endl;
34 | return traits::not_eof( c );
35 | }
36 |
37 | std::streamsize xsputn( const char *s, std::streamsize n ) {
38 | write_string_to_java_stream( env, java_writer, s, n );
39 | return n;
40 | }
41 |
42 | JNIEnv *env;
43 | jobject java_writer;
44 |
45 | public:
46 | void init( JNIEnv *env_in, jobject java_writer_in ) { env = env_in; java_writer = java_writer_in; }
47 | };
48 |
49 | template >
50 | class BasicJavaOStream : public std::basic_ostream
51 | {
52 | public:
53 | BasicJavaOStream ( JNIEnv *env, jobject java_writer )
54 | : std::basic_ios( &sbuf ), std::basic_ostream( &sbuf ) {
55 | sbuf.init( env, java_writer );
56 | }
57 |
58 | private:
59 | JavaStreambuf sbuf;
60 | };
61 |
62 | typedef BasicJavaOStream JavaOStream;
63 | typedef BasicJavaOStream WJavaOStream;
64 |
65 | #endif
66 |
--------------------------------------------------------------------------------
/build-tools/org_gnu_apl_Native.h:
--------------------------------------------------------------------------------
1 | /* DO NOT EDIT THIS FILE - it is machine generated */
2 | #include
3 | /* Header for class org_gnu_apl_Native */
4 |
5 | #ifndef _Included_org_gnu_apl_Native
6 | #define _Included_org_gnu_apl_Native
7 | #ifdef __cplusplus
8 | extern "C" {
9 | #endif
10 | /*
11 | * Class: org_gnu_apl_Native
12 | * Method: init
13 | * Signature: (Ljava/lang/String;)I
14 | */
15 | JNIEXPORT jint JNICALL Java_org_gnu_apl_Native_init
16 | (JNIEnv *, jclass, jstring);
17 |
18 | /*
19 | * Class: org_gnu_apl_Native
20 | * Method: evalExpression
21 | * Signature: (Ljava/lang/String;)Lorg/gnu/apl/AplValue;
22 | */
23 | JNIEXPORT jobject JNICALL Java_org_gnu_apl_Native_evalExpression
24 | (JNIEnv *, jclass, jstring);
25 |
26 | /*
27 | * Class: org_gnu_apl_Native
28 | * Method: evalWithIo
29 | * Signature: (Ljava/lang/String;Ljava/io/Writer;Ljava/io/Writer;Ljava/io/Writer;Ljava/io/Writer;)V
30 | */
31 | JNIEXPORT void JNICALL Java_org_gnu_apl_Native_evalWithIo
32 | (JNIEnv *, jclass, jstring, jobject, jobject, jobject, jobject);
33 |
34 | #ifdef __cplusplus
35 | }
36 | #endif
37 | #endif
38 |
--------------------------------------------------------------------------------
/build-tools/utils.cc:
--------------------------------------------------------------------------------
1 | #include "utils.hh"
2 |
3 | #include
4 |
5 | void throw_apl_exception( JNIEnv *env, const std::string &message )
6 | {
7 | jclass exceptionCl = env->FindClass( "org/gnu/apl/AplException" );
8 | if( exceptionCl != NULL ) {
9 | env->ThrowNew( exceptionCl, message.c_str() );
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/build-tools/utils.hh:
--------------------------------------------------------------------------------
1 | #ifndef UTILS_HH
2 | #define UTILS_HH
3 |
4 | #include "jni.h"
5 |
6 | #include
7 |
8 | class JniStringWrapper
9 | {
10 | public:
11 | JniStringWrapper( JNIEnv *env_in, jstring jnistring_in )
12 | : env( env_in ), jnistring( jnistring_in )
13 | {
14 | native_string = env->GetStringUTFChars( jnistring, 0 );
15 | }
16 |
17 | ~JniStringWrapper() { env->ReleaseStringUTFChars( jnistring, native_string ); }
18 | const char *get_string( void ) { return native_string; }
19 |
20 | private:
21 | JNIEnv *env;
22 | jstring jnistring;
23 | const char *native_string;
24 | };
25 |
26 | void throw_apl_exception( JNIEnv *env, const std::string &message );
27 |
28 | #endif
29 |
--------------------------------------------------------------------------------
/client/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
9 |
12 |
13 |
14 |
15 |
16 |
17 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/client/ant.properties:
--------------------------------------------------------------------------------
1 | # This file is used to override default values used by the Ant build system.
2 | #
3 | # This file must be checked into Version Control Systems, as it is
4 | # integral to the build system of your project.
5 |
6 | # This file is only used by the Ant script.
7 |
8 | # You can use this to override default values such as
9 | # 'source.dir' for the location of your java source folder and
10 | # 'out.dir' for the location of your output folder.
11 |
12 | # You can also use it define how the release builds are signed by declaring
13 | # the following properties:
14 | # 'key.store' for the location of your keystore and
15 | # 'key.alias' for the name of the key to use.
16 | # The password will be asked during the build when you use the 'release' target.
17 |
18 |
--------------------------------------------------------------------------------
/client/assets/files/etc/gnu-apl.d/preferences:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | #
3 | # this file contains user preferences for GNU APL.
4 | #
5 | # It should live in:
6 | #
7 | # (1) in folder gnu-apl of the system configuration directory. or
8 | # (2) in folder .gnu-apl in the user's home
9 | #
10 | # In both cases the file name should be 'preferences'
11 | #
12 | # The system configuration directory is usually /etc or /etc/local
13 | # It can be overridden by ./configure --sysconfdir=something-else
14 | #
15 | # If both files are present then (1) is read before (2) so that for
16 | # duplicate settings in both files (2) prevails.
17 | #
18 | # Command line options take precedence over settings in any of these files.
19 | #
20 | # The initial content of this files contains all possible settings, but
21 | # commented out. You should not remove lines but rather comment or
22 | # uncomment them.
23 | #
24 |
25 |
26 | ###############################################################################
27 | #
28 | # WELCOME MESSAGE
29 | #
30 | # Print (or don't) a welcome message on start-up
31 | #
32 | # The corresponding command line options is --silent
33 | #
34 | Welcome Yes (default)
35 | # Welcome No
36 |
37 |
38 | ###############################################################################
39 | #
40 | # OUTPUT COLORING
41 | #
42 | # Output coloring can cause problems when, for example:
43 | #
44 | # (a) you run GNU APL as script
45 | # (b) you use a black background
46 | # (c) you run GNU APL from emacs
47 | # (d) you run GNU APL from a different terminal than color xterm
48 | #
49 | # In case (a) you should use the --script command line option and
50 | # leave Color as is.
51 | #
52 | # In cases (b), (c), and (d) you can uncomment the 'Color No' line below.
53 | # This only affects the initial state of output coloring; you can
54 | # re-enable colors later with APL command ]XTERM ON.
55 | #
56 | # The corresponding command line options are --Color and --noColor
57 | #
58 | # If your terminal does not understand the ANSI escape sequences,
59 | # or if you don't like to provide escape sequences, then you can set Color
60 | # to "curses" and set color numbers instead of escape sequences below. This
61 | # requires that certain environment variables (e.g. TERM) are set properly
62 | # and that your terminfo database contains the terminal you use.
63 | #
64 | Color ANSI (default)
65 | # Color CURSES
66 | # Color No
67 | #
68 | # If you want to disable coloring initially, but switch to curses if the
69 | # command ]COLOR (or the equivalent but now obsolete command ]XTERM)
70 | # is given later on, then you can give the color command twice:
71 | #
72 | # Color CURSES
73 | # Color No
74 | #
75 |
76 |
77 | ###############################################################################
78 | #
79 | # OUTPUT COLOR ESCAPE SEQUENCES FOR ANSI TERMINALS
80 | #
81 | # Output coloring is implemented as follows:
82 | #
83 | # There are 4 output channels called CIN, COUT, CERR, and UERR
84 | #
85 | # CIN is the echo of the input typed by the user,
86 | # COUT is the normal output of the APL interpreter,
87 | # CERR is additional error information, in particular logging.
88 | # UERR is output of the APL interpreter cotaining error messages,
89 | #
90 | # CIN, COUT, and UERR appear on stdout while CERR appears on stderr.
91 | # Normally stdout and stderr are both displayed on the same terminal,
92 | # but output redirection in the shell can make a difference.
93 | #
94 | # When the interpreter changes from one output channel to another, for
95 | # instance from CIN to COUT after the user has entered a line, then an
96 | # escape sequence (actually, any short sequence of characters) is sent
97 | # to the real output channel (i,e. stdout or stderr). The new channel
98 | # determines which sequence is sent:
99 | #
100 | # CIN: CIN-SEQUENCE CLEAR-EOL
101 | # COUT: COUT-SEQUENCE CLEAR-EOL
102 | # CERR: CERR-SEQUENCE CLEAR-EOL
103 | #UCERR: UERR-SEQUENCE CLEAR-EOL
104 | #
105 | # In addition, when the interpreter exists, then a sequence
106 | #
107 | # RESET-SEQUENCE CLEAR-EOL
108 | #
109 | # is sent which should set the colors to their initial state.
110 | #
111 | # The reason for sending CLEAR-EOL (i.e. clear to end of line) is to color
112 | # the entire next line not only the chars printed on the next line.
113 | #
114 | # Unfortunately it is difficult, if not impossible, to read the current
115 | # color setting from the terminal. Therefore the following is assumed:
116 | #
117 | # "GNU APL is started in a color xterm with white background".
118 | #
119 | # Color xterm is a VT100 (or ANSI) compatible terminal emulation.
120 | # If this assumption is correct, then everything should be fine. Otherwise
121 | # you may want to change the escape sequence sent to the terminal below.
122 | # The numbers below are the decimal values of the bytes sent to the terminal;
123 | # 27 is the escape character, for example. In order to change some or all
124 | # sequences, uncomment the corresponding line and change the hex numbers
125 | # (most likely the columns background and foreground).
126 | # Each sequence can be up to 20 characters long.
127 | #
128 | # The default setting (i.e. for a white background) is this:
129 | #
130 | # VT100: foreground background
131 | # color | | color
132 | # V V
133 | # // ESC [ 0 ; 3 fg ; 4 bg m
134 | # CIN-SEQUENCE 1b 5b 30 3b 33 30 3b 34 37 6d // ESC [0;30;47m
135 | # COUT-SEQUENCE 1b 5b 30 3b 33 30 3b 34 38 6d // ESC [0;30;48m
136 | # CERR-SEQUENCE 1b 5b 30 3b 33 35 3b 34 38 6d // ESC [0;35;48m
137 | # UERR-SEQUENCE 1b 5b 30 3b 33 35 3b 34 38 6d // ESC [0;35;48m
138 | # RESET-SEQUENCE 1b 5b 30 3b 33 38 3b 34 38 6d // ESC [0;38;48m
139 | # CLEAR-EOL-SEQUENCE 1b 5b 4B // ESC [K
140 | #
141 | # On a black background (still assuming VT100 so that the CLEAR-EOL-SEQUENCE
142 | # does not need to be re-defined), the following may be more suitable:
143 | #
144 | # CIN-SEQUENCE 1b 5b 30 3b 33 32 3b 34 30 6d // ESC [0;32;40m
145 | # COUT-SEQUENCE 1b 5b 30 3b 33 37 3b 34 30 6d // ESC [0;37;40m
146 | # CERR-SEQUENCE 1b 5b 30 3b 33 31 3b 34 30 6d // ESC [0;31;40m
147 | # UERR-SEQUENCE 1b 5b 30 3b 33 31 3b 34 30 6d // ESC [0;31;40m
148 | # RESET-SEQUENCE 1b 5b 30 3b 33 37 3b 34 30 6d // ESC [0;37;48m
149 | #
150 | #
151 |
152 |
153 | ###############################################################################
154 | #
155 | # OUTPUT COLOR NUMBER FOR CURSES
156 | #
157 | # There is second way of specifying colors that uses the curses library.
158 | # Instead of specifying the escape sequences sent to the terminal you
159 | # only need to specify the colors wanted and curses will provide the escape
160 | # sequences needed.
161 | #
162 | # Numbers for colors seem to be (nota bene: the author is color-blind):
163 | #
164 | # 0: black
165 | # 1: blue
166 | # 2: green
167 | # 3: cyan
168 | # 4: red
169 | # 5: magenta
170 | # 6: yellow
171 | # 7: white
172 | #
173 | # The colors are specified as numbers like this:
174 | #
175 | # CIN-FOREGROUND 0
176 | # CIN-BACKGROUND 7
177 | # COUT-FOREGROUND 2
178 | # COUT-BACKGROUND 7
179 | # CERR-FOREGROUND 5
180 | # CERR-BACKGROUND 8
181 | # UERR-FOREGROUND 5
182 | # UERR-BACKGROUND 8
183 | #
184 | # or, for dark background:
185 | #
186 | # CIN-FOREGROUND 2
187 | # CIN-BACKGROUND 0
188 | # COUT-FOREGROUND 7
189 | # COUT-BACKGROUND 0
190 | # CERR-FOREGROUND 5
191 | # CERR-BACKGROUND 0
192 | # UERR-FOREGROUND 5
193 | # UERR-BACKGROUND 0
194 | #
195 | # Normally the two methods (escape sequences vs. color numbers) shall not
196 | # be mixed. If they are mixed then the last entry in this file determines
197 | # which method will be used. Also, the numbers for colors are different
198 | # in both methods.
199 | #
200 |
201 |
202 | ###############################################################################
203 | #
204 | # SHARED VARIABLES
205 | #
206 | # shared variables ⎕SVO, ⎕SVR, ... fork a helper process (APnnn) to
207 | # communicate with other APL processors. If you do not need these functions
208 | # then you can prevent starting of APnnn by setting SharedVars to Disabled.
209 | # If SharedVars are disabled then GNU APL starts a little faster and, of
210 | # course, ⎕SVO and friends won't work.
211 | #
212 | # The corresponding command line options are --SV and --noSV
213 | #
214 | SharedVars Enabled (default)
215 | # SharedVars Disabled
216 |
217 |
218 | ###############################################################################
219 | #
220 | # LOGGING FACILITIES
221 | #
222 | # If dynamic logging is disabled then these settings have no effect.
223 | #
224 | # Otherwise you can specify the Logging facilities (numbered 1-37 or more)
225 | # that shall be turned on when the APL interpreter starts, This option can
226 | # be used several times.
227 | #
228 | # See command ]LOG for available logging facilities
229 | #
230 | # The corresponding command line option is -l
231 | #
232 | # Logging 1
233 | # Logging 2
234 | # ...
235 | # Logging 37
236 |
237 |
238 | ###############################################################################
239 | #
240 | # GNU APL uses library numbers from 0 to 0 in commands )LOAD, )SAVE, and )COPY,
241 | # for example:
242 | #
243 | # )LOAD 1 workspace
244 | #
245 | # Commands )IN and )OUT use library number 0 implicitly;
246 | # )LOAD, )SAVE, and )COPY use library number 0 implicitly when no
247 | # library number is given.
248 | #
249 | # The directories corresponding to the library numbers can be configured below.
250 | # library numbers 3, 4, and 5 are used (and overridden) libraries shipped with
251 | # GNU APL
252 | #
253 | # LIBREF-0 /home/xyz/my-own-libs
254 | # LIBREF-1 /home/xyz/my-group-libs
255 | # LIBREF-2 /group/abc/other-libs
256 | LIBREF-3 /usr/local/lib/apl/wslib3
257 | LIBREF-4 /usr/local/lib/apl/wslib4
258 | LIBREF-5 /usr/local/lib/apl/wslib5
259 | # LIBREF-6 /usr/lib/gnu-apl/lib-6
260 | # LIBREF-7 /usr/lib/gnu-apl/lib-7
261 | # LIBREF-8 /usr/lib/gnu-apl/lib-8
262 | # LIBREF-9 /usr/lib/gnu-apl/lib-9
263 | #
264 |
265 | ###############################################################################
266 | #
267 | # READLINE HISTORY PARAMETERS
268 | #
269 | # GNU APL normally uses GNU Readline for obtaining input from the user.
270 | # Below the number of history lines and the location of the history file
271 | # can be configured.
272 | #
273 | READLINE_HISTORY_LEN 500
274 | READLINE_HISTORY_PATH .apl.history
275 |
276 |
277 | ###############################################################################
278 | #
279 | # CREATE BACKUP BEFORE )SAVE or )DUMP WOKRSPACE
280 | #
281 | BACKUP_BEFORE_SAVE yes
282 |
283 |
--------------------------------------------------------------------------------
/client/assets/files/lib/apl/wslib3/meta.apl:
--------------------------------------------------------------------------------
1 | ⍝! apl
2 | ⍝ meta: a library for creating and checking meta functions in a library
3 | ⍝
4 |
5 | ⍝ return the meta functions to be provided by Package
6 | ⍝
7 | ∇Z←meta∆functions Package;MP
8 | MP←Package,'⍙' ⍝ the meta prefix
9 | Z← ,⊂MP,'Author'
10 | Z←Z,⊂MP,'Version'
11 | Z←Z,⊂MP,'Portability'
12 | Z←Z,⊂MP,'License'
13 | Z←Z,⊂MP,'BugEmail'
14 | Z←Z,⊂MP,'Requires'
15 | Z←Z,⊂MP,'Provides'
16 | Z←Z,⊂MP,'Download'
17 | Z←Z,⊂MP,'Documentation'
18 | ∇
19 |
20 | ⍝ create all meta functions to be provided by Package
21 | ⍝
22 | ∇meta∆make_functions Package;Funs
23 | Funs←meta∆functions Package
24 | meta∆make_function ¨ Funs
25 | ∇
26 |
27 | ⍝ create one meta function, asking for its value
28 | ⍝
29 | ∇meta∆make_function Fun;Value;Q
30 | ⍞←Q←50↑' Value to be returned by ',Fun,':'
31 | Value←(⍴Q)↓⍞ ◊ ''
32 | L0←'Z←' , Fun
33 | L1←'Z←,⊂''', Value, ''''
34 | Q←⎕FX L0 L1
35 | ∇
36 |
37 | meta∆make_functions 'meta'
38 |
39 | )FNS
40 | )OFF
41 |
42 |
--------------------------------------------------------------------------------
/client/assets/files/lib/apl/wslib4/dummy.apl:
--------------------------------------------------------------------------------
1 | ⍝!/usr/bin/apl --script
2 |
3 | 'This is a placeholder to trigger the creation of its parent directory'
4 | )OFF
5 |
6 |
--------------------------------------------------------------------------------
/client/assets/files/lib/apl/wslib5/HTML.apl:
--------------------------------------------------------------------------------
1 | ⍝! apl --script
2 | ⍝
3 | ⍝ HTML.apl
4 | ⍝
5 | ⍝ This file is a GNU APL L1 library containing functions for generating some
6 | ⍝ frequently used HTML tags.
7 | ⍝
8 | ⍝ The library is used by means of the )COPY command:
9 | ⍝
10 | ⍝ )COPY 5 HTML
11 | ⍝
12 | ⍝
13 | ⍝ The library provides the following functions (meta functions omitted):
14 | ⍝
15 | ⍝ HTML∆debug return debug info to be displayed in a HTML page
16 | ⍝ HTML∆Assert check a condition and complain if not met
17 | ⍝ HTML∆xbox append text matrices A and B horizontally
18 | ⍝ HTML∆HTTP_header CGI header (if started from a web server)
19 | ⍝ HTML∆attr HTML attribute xA with value xB
20 | ⍝
21 | ⍝ HTML∆_alt HTML attribute 'alt' with value xB
22 | ⍝ HTML∆_content HTML attribute 'content' with value xB
23 | ⍝ HTML∆_height HTML attribute 'height' with value xB
24 | ⍝ HTML∆_href HTML attribute 'href' with value xB
25 | ⍝ HTML∆_http_eq HTML attribute 'http-equiv' with value xB
26 | ⍝ HTML∆_name HTML attribute 'name' with value xB
27 | ⍝ HTML∆__rel HTML attribute 'rel' with value xB
28 | ⍝ HTML∆__src HTML attribute 'src' with value xB
29 | ⍝ HTML∆__type HTML attribute 'type' with value xB
30 | ⍝ HTML∆__width HTML attribute 'width' with value xB
31 | ⍝ HTML∆__h_w HTML attributes 'height' and 'width' with value xB
32 | ⍝
33 | ⍝ HTML∆T HTML tag
34 | ⍝ HTML∆TX_B_E multi-line yB tagged with xA and /xA
35 | ⍝ HTML∆TX_B_E_1 single-line xB tagged with xA and /xA
36 | ⍝ HTML∆TX_B_1 single-line xB tagged with xA and no /xA
37 | ⍝ HTML∆x2y convert single-line xB to multi-line yZ
38 | ⍝ HTML∆indent_2 indent single-line xB
39 | ⍝ HTML∆indent_2 indent multi-line xB
40 | ⍝ HTML∆emit_1 disclose one-line yB and print it
41 | ⍝ HTML∆emit disclose multi-line yB and print it
42 | ⍝ HTML∆A xB
43 | ⍝ HTML∆Title xB
44 | ⍝ HTML∆Img
45 | ⍝ HTML∆Link
46 | ⍝ HTML∆Style
365 | ⍝
366 | ∇yZ←HTML∆Style[xX] yB
367 | HTML∆Assert 1 ≡ ≡xX ◊ HTML∆Assert 1 ≡ ''⍴⍴⍴xX
368 | HTML∆Assert 2 ≡ ≡yB ◊ HTML∆Assert 1 ≡ ''⍴⍴⍴yB
369 | yZ←'STYLE' HTML∆TX_B_E[xX] yB
370 | HTML∆Assert 2 ≡ ≡yZ ◊ HTML∆Assert 1 ≡ ''⍴⍴⍴yZ
371 | ∇
372 |
373 | ⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝
374 | ⍝ tag xB as LIST ITEM
375 | ⍝ xB
376 | ⍝
377 | ∇xZ←HTML∆Li xB
378 | HTML∆Assert 1 ≡ ≡xB ◊ HTML∆Assert 1 ≡ ''⍴⍴⍴xB
379 | xZ←' ', xB
380 | HTML∆Assert 1 ≡ ≡xZ ◊ HTML∆Assert 1 ≡ ''⍴⍴⍴xZ
381 | ∇
382 |
383 | ⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝
384 | ⍝ tag yB as ORDERED LIST
385 | ⍝
386 | ⍝ - B[1]
387 | ⍝
- B[2]
388 | ⍝ ...
389 | ⍝
390 | ⍝
391 | ∇yZ←HTML∆Ol[xX] yB
392 | →1+(0≠⎕NC 'xX')⍴⎕LC ◊ xX←''
393 | yZ←'OL' HTML∆TX_B_E[xX] HTML∆Li¨yB
394 | ∇
395 |
396 | ⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝
397 | ⍝ tag yB as UNORDERED LIST
398 | ⍝
399 | ⍝ - B[1]
400 | ⍝
- B[2]
401 | ⍝ ...
402 | ⍝
403 | ⍝
404 | ∇yZ←HTML∆Ul[xX] yB
405 | →1+(0≠⎕NC 'xX')⍴⎕LC ◊ xX←''
406 | yZ←'UL' HTML∆TX_B_E[xX] HTML∆Li¨yB
407 | ∇
408 |
409 | ⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝
410 | ⍝ popular HTML elements
411 | ⍝
412 | ∇yZ←HTML∆H1[xX] xB
413 | yZ←"H1" HTML∆TX_B_E_1[xX] xB
414 | ∇
415 |
416 | ∇yZ←HTML∆H2[xX] xB
417 | yZ←"H2" HTML∆TX_B_E_1[xX] xB
418 | ∇
419 |
420 | ∇yZ←HTML∆H3[xX] xB
421 | yZ←"H3" HTML∆TX_B_E_1[xX] xB
422 | ∇
423 |
424 | ∇yZ←HTML∆H4[xX] xB
425 | yZ←"H4" HTML∆TX_B_E_1[xX] xB
426 | ∇
427 |
428 | ⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝
429 | ⍝ return HEAD using xTITLE
430 | ⍝
431 | ⍝ B
432 | ⍝
433 | ⍝
434 | ∇yZ←HTML∆Head;yB
435 | yB←HTML∆Title xTITLE
436 | yB←yB,,⊂'META' HTML∆T[(HTML∆_http_eq 'Content-Type'), HTML∆_content 'text/html; charset=UTF-8'] 1
437 | yB←yB,,⊂'META' HTML∆T[(HTML∆_name 'description'), HTML∆_content xDESCRIPTION] 1
438 | yB←yB,HTML∆Link (HTML∆__rel 'stylesheet'),(HTML∆__type 'text/css'), HTML∆_href 'apl-home.css'
439 | yB←yB,HTML∆Style[HTML∆__type 'text/css'] ,⊂''
440 |
441 | yZ←'HEAD' HTML∆TX_B_E yB
442 | HTML∆Assert 2 ≡ ≡yZ ◊ HTML∆Assert 1 ≡ ''⍴⍴⍴yZ
443 | ∇
444 |
445 | ⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝
446 | ⍝ tag yB as BODY
447 | ⍝
448 | ⍝ B
449 | ⍝
450 | ⍝
451 | ∇yZ←HTML∆Body[xX] yB
452 | HTML∆Assert 2 ≡ ≡yB ◊ HTML∆Assert 1 ≡ ''⍴⍴⍴yB
453 | yZ←'BODY' HTML∆TX_B_E[xX] yB
454 | HTML∆Assert 2 ≡ ≡yZ ◊ HTML∆Assert 1 ≡ ''⍴⍴⍴yZ
455 | ∇
456 |
457 | ⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝
458 | ⍝ HTML document with body yB
459 | ⍝
460 | ⍝ B
461 | ⍝
462 | ⍝
463 | ∇yZ←HTML∆Html[xX] yB
464 | →1+(0≠⎕NC 'xX')⍴⎕LC ◊ xX←''
465 | HTML∆Assert 2 ≡ ≡yB ◊ HTML∆Assert 1 ≡ ''⍴⍴⍴yB
466 | yZ←'HTML' HTML∆TX_B_E HTML∆Head, HTML∆Body[xX] yB
467 | HTML∆Assert 2 ≡ ≡yZ ◊ HTML∆Assert 1 ≡ ''⍴⍴⍴yZ
468 | ∇
469 |
470 | ⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝
471 | ⍝ The entire document
472 | ⍝
473 | ∇yZ←HTML∆Document
474 | yZ← HTML∆x2y HTML∆HTTP_header
475 | yZ←yZ, HTML∆x2y ''
476 | yZ←yZ, HTML∆Html yBODY
477 | HTML∆Assert 2 ≡ ≡yZ ◊ HTML∆Assert 1 ≡ ''⍴⍴⍴yZ
478 | ∇
479 |
480 |
481 | ⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝
482 | ⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝
483 | ⍝⍝ ⍝⍝
484 | ⍝⍝ library meta information... ⍝⍝
485 | ⍝⍝ ⍝⍝
486 | ⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝
487 | ⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝
488 |
489 | ∇Z←HTML⍙Author
490 | Z←,⊂'Jürgen Sauermann'
491 | ∇
492 |
493 | ∇Z←HTML⍙Version
494 | Z←,⊂'1.0'
495 | ∇
496 |
497 | ∇Z←HTML⍙Portability
498 | ⍝ this library is L3 because it uses user-defined function with axis, which
499 | ⍝ is a GNU APL only feature.
500 | ⍝
501 | Z←,⊂'L3'
502 | ∇
503 |
504 | ∇Z←HTML⍙License
505 | Z←,⊂'LGPL (GNU Lesser General Public License)''
506 | ∇
507 |
508 | ∇Z←HTML⍙BugEmail
509 | Z←,⊂'bug-apl@gnu.org'
510 | ∇
511 |
512 | ∇Z←HTML⍙Requires
513 | Z←0⍴⊂''
514 | ∇
515 |
516 | ∇Z←HTML⍙Provides
517 | Z←,⊂'HTML encoding functions'
518 | ∇
519 |
520 | ∇Z←HTML⍙Download;URI;OPTS
521 | URI←'http://svn.savannah.gnu.org/viewvc/*checkout*/trunk/wslib3/HTML.apl'
522 | OPTS←'root=apl'
523 | Z←,⊂URI,'?',OPTS
524 | ∇
525 |
526 | ∇Z←HTML⍙Documentaion
527 | Z←,⊂'http://www.gnu.org/software/apl/Library-Guidelines.html'
528 | ∇
529 |
530 |
--------------------------------------------------------------------------------
/client/assets/fonts/FreeMono.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lokedhs/android-gnu-apl/2385d564b5c6de2106cb995fdfac35d00db22e21/client/assets/fonts/FreeMono.ttf
--------------------------------------------------------------------------------
/client/assets/fonts/FreeMonoBold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lokedhs/android-gnu-apl/2385d564b5c6de2106cb995fdfac35d00db22e21/client/assets/fonts/FreeMonoBold.ttf
--------------------------------------------------------------------------------
/client/assets/fonts/FreeMonoBoldOblique.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lokedhs/android-gnu-apl/2385d564b5c6de2106cb995fdfac35d00db22e21/client/assets/fonts/FreeMonoBoldOblique.ttf
--------------------------------------------------------------------------------
/client/assets/fonts/FreeMonoOblique.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lokedhs/android-gnu-apl/2385d564b5c6de2106cb995fdfac35d00db22e21/client/assets/fonts/FreeMonoOblique.ttf
--------------------------------------------------------------------------------
/client/build.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
9 |
29 |
30 |
31 |
35 |
36 |
37 |
38 |
39 |
40 |
49 |
50 |
51 |
52 |
56 |
57 |
69 |
70 |
71 |
89 |
90 |
91 |
92 |
93 |
--------------------------------------------------------------------------------
/client/client.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/client/gen/com/dhsdevelopments/aplandroid/BuildConfig.java:
--------------------------------------------------------------------------------
1 | /*___Generated_by_IDEA___*/
2 |
3 | package com.dhsdevelopments.aplandroid;
4 |
5 | /* This stub is only used by the IDE. It is NOT the BuildConfig class actually packed into the APK */
6 | public final class BuildConfig {
7 | public final static boolean DEBUG = Boolean.parseBoolean(null);
8 | }
--------------------------------------------------------------------------------
/client/gen/com/dhsdevelopments/aplandroid/Manifest.java:
--------------------------------------------------------------------------------
1 | /*___Generated_by_IDEA___*/
2 |
3 | package com.dhsdevelopments.aplandroid;
4 |
5 | /* This stub is only used by the IDE. It is NOT the Manifest class actually packed into the APK */
6 | public final class Manifest {
7 | }
--------------------------------------------------------------------------------
/client/gen/com/dhsdevelopments/aplandroid/R.java:
--------------------------------------------------------------------------------
1 | /*___Generated_by_IDEA___*/
2 |
3 | package com.dhsdevelopments.aplandroid;
4 |
5 | /* This stub is only used by the IDE. It is NOT the R class actually packed into the APK */
6 | public final class R {
7 | }
--------------------------------------------------------------------------------
/client/libs/armeabi/libapl.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lokedhs/android-gnu-apl/2385d564b5c6de2106cb995fdfac35d00db22e21/client/libs/armeabi/libapl.so
--------------------------------------------------------------------------------
/client/local.properties:
--------------------------------------------------------------------------------
1 | # This file is automatically generated by Android Tools.
2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED!
3 | #
4 | # This file must *NOT* be checked into Version Control Systems,
5 | # as it contains information specific to your local configuration.
6 |
7 | # location of the SDK. This is only used by Ant
8 | # For customization when using a Version Control System, please read the
9 | # header note.
10 | sdk.dir=/home/elias/src/android-sdk-linux_86
11 |
--------------------------------------------------------------------------------
/client/proguard-project.txt:
--------------------------------------------------------------------------------
1 | # To enable ProGuard in your project, edit project.properties
2 | # to define the proguard.config property as described in that file.
3 | #
4 | # Add project specific ProGuard rules here.
5 | # By default, the flags in this file are appended to flags specified
6 | # in ${sdk.dir}/tools/proguard/proguard-android.txt
7 | # You can edit the include path and order by changing the ProGuard
8 | # include property in project.properties.
9 | #
10 | # For more details, see
11 | # http://developer.android.com/guide/developing/tools/proguard.html
12 |
13 | # Add any project specific keep options here:
14 |
15 | # If your project uses WebView with JS, uncomment the following
16 | # and specify the fully qualified class name to the JavaScript interface
17 | # class:
18 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
19 | # public *;
20 | #}
21 |
--------------------------------------------------------------------------------
/client/project.properties:
--------------------------------------------------------------------------------
1 | # This file is automatically generated by Android Tools.
2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED!
3 | #
4 | # This file must be checked in Version Control Systems.
5 | #
6 | # To customize properties used by the Ant build system edit
7 | # "ant.properties", and override values to adapt the script to your
8 | # project structure.
9 | #
10 | # To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
11 | #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
12 |
13 | # Project target.
14 | target=Google Inc.:Google APIs:21
15 |
--------------------------------------------------------------------------------
/client/res/drawable-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lokedhs/android-gnu-apl/2385d564b5c6de2106cb995fdfac35d00db22e21/client/res/drawable-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/client/res/drawable-hdpi/icon_en_gb.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lokedhs/android-gnu-apl/2385d564b5c6de2106cb995fdfac35d00db22e21/client/res/drawable-hdpi/icon_en_gb.png
--------------------------------------------------------------------------------
/client/res/drawable-hdpi/icon_en_us.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lokedhs/android-gnu-apl/2385d564b5c6de2106cb995fdfac35d00db22e21/client/res/drawable-hdpi/icon_en_us.png
--------------------------------------------------------------------------------
/client/res/drawable-hdpi/sym_keyboard_delete.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lokedhs/android-gnu-apl/2385d564b5c6de2106cb995fdfac35d00db22e21/client/res/drawable-hdpi/sym_keyboard_delete.png
--------------------------------------------------------------------------------
/client/res/drawable-hdpi/sym_keyboard_done.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lokedhs/android-gnu-apl/2385d564b5c6de2106cb995fdfac35d00db22e21/client/res/drawable-hdpi/sym_keyboard_done.png
--------------------------------------------------------------------------------
/client/res/drawable-hdpi/sym_keyboard_return.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lokedhs/android-gnu-apl/2385d564b5c6de2106cb995fdfac35d00db22e21/client/res/drawable-hdpi/sym_keyboard_return.png
--------------------------------------------------------------------------------
/client/res/drawable-hdpi/sym_keyboard_search.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lokedhs/android-gnu-apl/2385d564b5c6de2106cb995fdfac35d00db22e21/client/res/drawable-hdpi/sym_keyboard_search.png
--------------------------------------------------------------------------------
/client/res/drawable-hdpi/sym_keyboard_shift.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lokedhs/android-gnu-apl/2385d564b5c6de2106cb995fdfac35d00db22e21/client/res/drawable-hdpi/sym_keyboard_shift.png
--------------------------------------------------------------------------------
/client/res/drawable-hdpi/sym_keyboard_space.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lokedhs/android-gnu-apl/2385d564b5c6de2106cb995fdfac35d00db22e21/client/res/drawable-hdpi/sym_keyboard_space.png
--------------------------------------------------------------------------------
/client/res/drawable-ldpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lokedhs/android-gnu-apl/2385d564b5c6de2106cb995fdfac35d00db22e21/client/res/drawable-ldpi/ic_launcher.png
--------------------------------------------------------------------------------
/client/res/drawable-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lokedhs/android-gnu-apl/2385d564b5c6de2106cb995fdfac35d00db22e21/client/res/drawable-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/client/res/drawable-mdpi/icon_en_gb.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lokedhs/android-gnu-apl/2385d564b5c6de2106cb995fdfac35d00db22e21/client/res/drawable-mdpi/icon_en_gb.png
--------------------------------------------------------------------------------
/client/res/drawable-mdpi/icon_en_us.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lokedhs/android-gnu-apl/2385d564b5c6de2106cb995fdfac35d00db22e21/client/res/drawable-mdpi/icon_en_us.png
--------------------------------------------------------------------------------
/client/res/drawable-mdpi/sym_keyboard_delete.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lokedhs/android-gnu-apl/2385d564b5c6de2106cb995fdfac35d00db22e21/client/res/drawable-mdpi/sym_keyboard_delete.png
--------------------------------------------------------------------------------
/client/res/drawable-mdpi/sym_keyboard_done.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lokedhs/android-gnu-apl/2385d564b5c6de2106cb995fdfac35d00db22e21/client/res/drawable-mdpi/sym_keyboard_done.png
--------------------------------------------------------------------------------
/client/res/drawable-mdpi/sym_keyboard_return.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lokedhs/android-gnu-apl/2385d564b5c6de2106cb995fdfac35d00db22e21/client/res/drawable-mdpi/sym_keyboard_return.png
--------------------------------------------------------------------------------
/client/res/drawable-mdpi/sym_keyboard_search.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lokedhs/android-gnu-apl/2385d564b5c6de2106cb995fdfac35d00db22e21/client/res/drawable-mdpi/sym_keyboard_search.png
--------------------------------------------------------------------------------
/client/res/drawable-mdpi/sym_keyboard_shift.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lokedhs/android-gnu-apl/2385d564b5c6de2106cb995fdfac35d00db22e21/client/res/drawable-mdpi/sym_keyboard_shift.png
--------------------------------------------------------------------------------
/client/res/drawable-mdpi/sym_keyboard_space.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lokedhs/android-gnu-apl/2385d564b5c6de2106cb995fdfac35d00db22e21/client/res/drawable-mdpi/sym_keyboard_space.png
--------------------------------------------------------------------------------
/client/res/drawable-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lokedhs/android-gnu-apl/2385d564b5c6de2106cb995fdfac35d00db22e21/client/res/drawable-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/client/res/layout/apl_input.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
--------------------------------------------------------------------------------
/client/res/layout/input.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
--------------------------------------------------------------------------------
/client/res/layout/interpreter.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
11 |
12 |
--------------------------------------------------------------------------------
/client/res/layout/interpreter_log.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
13 |
20 |
25 |
26 |
--------------------------------------------------------------------------------
/client/res/layout/result_text.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
14 |
19 |
20 |
--------------------------------------------------------------------------------
/client/res/menu/main_activity_actions.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
--------------------------------------------------------------------------------
/client/res/values-land/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 46dip
4 |
5 |
--------------------------------------------------------------------------------
/client/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/client/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FF000000
4 | #FFE35900
5 | #ff808080
6 | #bbffffff
7 |
--------------------------------------------------------------------------------
/client/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 50dip
4 | 16sp
5 | 6sp
6 | 20sp
7 | 8sp
8 |
--------------------------------------------------------------------------------
/client/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | GNU APL
4 | Send
5 | APL Input
6 | Go
7 | Next
8 | Send
9 | \u0020.,;:!?\n()[]*&@{}/<>_+=|"
10 | Input languages
11 | Select input languages
12 | Settings
13 | APL %s
14 | APL (GB)
15 | Save workspace
16 |
17 |
--------------------------------------------------------------------------------
/client/res/xml/ime_preferences.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
--------------------------------------------------------------------------------
/client/res/xml/keyboard_layout.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
9 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
68 |
69 |
--------------------------------------------------------------------------------
/client/res/xml/method.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
12 |
24 |
25 |
--------------------------------------------------------------------------------
/client/res/xml/qwerty.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
49 |
50 |
51 |
52 |
56 |
57 |
58 |
59 |
61 |
63 |
65 |
66 |
67 |
--------------------------------------------------------------------------------
/client/res/xml/symbols.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
49 |
50 |
51 |
52 |
56 |
57 |
58 |
60 |
61 |
64 |
65 |
--------------------------------------------------------------------------------
/client/res/xml/symbols_apl.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 | ∼
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
49 |
50 |
51 |
52 |
56 |
57 |
58 |
60 |
61 |
64 |
65 |
--------------------------------------------------------------------------------
/client/res/xml/symbols_apl_shift.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 | ∼
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
49 |
50 |
51 |
52 |
56 |
57 |
58 |
60 |
61 |
64 |
65 |
--------------------------------------------------------------------------------
/client/res/xml/symbols_shift.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
49 |
50 |
51 |
52 |
56 |
57 |
58 |
60 |
61 |
63 |
64 |
65 |
--------------------------------------------------------------------------------
/client/src/com/dhsdevelopments/aplandroid/AplAndroidApp.java:
--------------------------------------------------------------------------------
1 | package com.dhsdevelopments.aplandroid;
2 |
3 | import android.app.Application;
4 |
5 | import java.io.File;
6 | import java.io.IOException;
7 |
8 | public class AplAndroidApp extends Application
9 | {
10 | private AplNative aplNative;
11 |
12 | @Override
13 | public void onCreate() {
14 | super.onCreate();
15 | try {
16 | File destDir = Installer.install( this );
17 | aplNative = new AplNative( destDir );
18 | }
19 | catch( IOException e ) {
20 | throw new RuntimeException( "Exception when installing support files", e );
21 | }
22 | }
23 |
24 | public AplNative getAplNative() {
25 | return aplNative;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/client/src/com/dhsdevelopments/aplandroid/AplNative.java:
--------------------------------------------------------------------------------
1 | package com.dhsdevelopments.aplandroid;
2 |
3 | import org.gnu.apl.AplException;
4 | import org.gnu.apl.Native;
5 |
6 | import java.io.File;
7 | import java.io.StringWriter;
8 | import java.util.ArrayList;
9 | import java.util.List;
10 | import java.util.concurrent.BlockingQueue;
11 | import java.util.concurrent.CopyOnWriteArrayList;
12 | import java.util.concurrent.LinkedBlockingQueue;
13 |
14 | public class AplNative
15 | {
16 | private List results = new ArrayList<>();
17 | private List resultListListeners = new CopyOnWriteArrayList<>();
18 | private BlockingQueue evalQueue = new LinkedBlockingQueue<>();
19 | private AplEvalThread evalThread;
20 |
21 | public AplNative( File path ) {
22 | Native.init( path.getPath() );
23 | evalThread = new AplEvalThread();
24 | evalThread.start();
25 | }
26 |
27 | public String eval( String expr ) throws AplException {
28 | String trimmed = expr.trim();
29 | if( trimmed.length() == 0 ) {
30 | return "";
31 | }
32 |
33 | StringWriter writer = new StringWriter();
34 | Native.evalWithIo( expr, writer, writer, writer, writer );
35 | String res = writer.toString();
36 | ResultListEntry entry = new ResultListEntry( expr, res );
37 | synchronized( this ) {
38 | results.add( entry );
39 | }
40 | for( ResultListListener l : resultListListeners ) {
41 | l.resultUpdated( entry );
42 | }
43 | return res;
44 | }
45 |
46 | public void evalAsAsync( String expr, EvalRequest.EvalRequestCallback callback ) {
47 | evalQueue.add( new EvalRequest( expr, callback ) );
48 | }
49 |
50 | public void addResultListListener( ResultListListener listener ) {
51 | resultListListeners.add( listener );
52 | }
53 |
54 | public void removeResultListListener( ResultListListener listener ) {
55 | if( !resultListListeners.remove( listener ) ) {
56 | throw new IllegalStateException( "Attempting to remove non existent listener" );
57 | }
58 | }
59 |
60 | /**
61 | * The return value of this list has to be processed inside a
62 | * synchronised block protecting this instance.
63 | *
64 | * @return the underlying result list
65 | */
66 | public List getResultEntries() {
67 | return results;
68 | }
69 |
70 | public interface ResultListListener
71 | {
72 | void resultUpdated( ResultListEntry entry );
73 | }
74 |
75 | private class AplEvalThread extends Thread
76 | {
77 | @Override
78 | public void run() {
79 | try {
80 | while( !Thread.interrupted() ) {
81 | EvalRequest req = evalQueue.take();
82 | String result = null;
83 | AplException ex = null;
84 | try {
85 | result = eval( req.getExpr() );
86 | }
87 | catch( AplException e ) {
88 | ex = e;
89 | }
90 | if( req.getCallback() != null ) {
91 | callCallback( result, ex, req.getCallback() );
92 | }
93 | }
94 | }
95 | catch( InterruptedException e ) {
96 | Log.e( "Eval thread stopped", e );
97 | }
98 | }
99 |
100 | private void callCallback( String result, AplException ex, EvalRequest.EvalRequestCallback callback ) {
101 | if( ex == null ) {
102 | callback.evalComplete( result );
103 | }
104 | else {
105 | callback.evalException( ex );
106 | }
107 | }
108 | }
109 | }
110 |
--------------------------------------------------------------------------------
/client/src/com/dhsdevelopments/aplandroid/EvalRequest.java:
--------------------------------------------------------------------------------
1 | package com.dhsdevelopments.aplandroid;
2 |
3 | import com.google.common.base.Preconditions;
4 | import org.gnu.apl.AplException;
5 |
6 | public class EvalRequest
7 | {
8 | private String expr;
9 | private EvalRequestCallback callback;
10 |
11 | EvalRequest( String expr, EvalRequestCallback callback ) {
12 | Preconditions.checkNotNull( expr );
13 | this.expr = expr;
14 | this.callback = callback;
15 | }
16 |
17 | public String getExpr() {
18 | return expr;
19 | }
20 |
21 | public EvalRequestCallback getCallback() {
22 | return callback;
23 | }
24 |
25 | public interface EvalRequestCallback
26 | {
27 | void evalComplete( CharSequence result );
28 |
29 | void evalException( AplException exception );
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/client/src/com/dhsdevelopments/aplandroid/Installer.java:
--------------------------------------------------------------------------------
1 | package com.dhsdevelopments.aplandroid;
2 |
3 | import android.content.Context;
4 | import android.content.res.AssetManager;
5 |
6 | import java.io.*;
7 |
8 | public class Installer
9 | {
10 | private static final String BASENAME = "files";
11 |
12 | public static File install( Context context ) throws IOException {
13 | File dest = context.getDir( BASENAME, Context.MODE_PRIVATE );
14 | File prefsFile = new File( dest, "etc/gnu-apl.d/preferences" );
15 | if( !prefsFile.exists() ) {
16 | Log.d( "trigger file not found, installing data" );
17 | AssetManager am = context.getAssets();
18 | copyDirs( am, BASENAME, dest );
19 | symlink( "lib_file_io.so", "lib_file_io.so.0.0.0" );
20 | symlink( "lib_file_io.so.0", "lib_file_io.so.0.0.0" );
21 | symlink( "lib_template_F0.so", "lib_template_F0.so.0.0.0" );
22 | symlink( "lib_template_F0.so.0", "lib_template_F0.so.0.0.0" );
23 | symlink( "lib_template_F12.so", "lib_template_F12.so.0.0.0" );
24 | symlink( "lib_template_F12.so.0", "lib_template_F12.so.0.0.0" );
25 | symlink( "lib_template_OP1.so", "lib_template_OP1.so.0.0.0" );
26 | symlink( "lib_template_OP1.so.0", "lib_template_OP1.so.0.0.0" );
27 | symlink( "lib_template_OP2.so", "lib_template_OP2.so.0.0.0" );
28 | symlink( "lib_template_OP2.so.0", "lib_template_OP2.so.0.0.0" );
29 | }
30 | else {
31 | Log.d( "files already installed" );
32 | }
33 | return dest;
34 | }
35 |
36 | private static void symlink( String linkName, String file ) {
37 |
38 | }
39 |
40 | private static void copyDirs( AssetManager am, String srcRoot, File destRoot ) throws IOException {
41 | ensureDir( destRoot, "etc" );
42 | ensureDir( destRoot, "etc/gnu-apl.d" );
43 |
44 | copyFile( am, srcRoot, destRoot, "etc/gnu-apl.d", "preferences" );
45 | }
46 |
47 | private static void ensureDir( File destRoot, String name ) {
48 | File dir = new File( destRoot, name );
49 | if( dir.isFile() ) {
50 | throw new RuntimeException( dir.getPath() + " should be a directory, was a file" );
51 | }
52 | if( !dir.mkdir() ) {
53 | Log.w( "Directory already exists: " + dir.getPath() );
54 | }
55 | }
56 |
57 | private static void copyFile( AssetManager am, String srcRoot, File destRoot, String dir, String fileName ) throws IOException {
58 | InputStream in = am.open( srcRoot + "/" + dir + "/" + fileName );
59 | try {
60 | OutputStream out = new FileOutputStream( new File( destRoot, dir + "/" + fileName ) );
61 | try {
62 | byte[] buf = new byte[1024 * 16];
63 | int n;
64 | while( (n = in.read( buf )) != -1 ) {
65 | out.write( buf, 0, n );
66 | }
67 | }
68 | finally {
69 | out.close();
70 | }
71 | }
72 | finally {
73 | in.close();
74 | }
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/client/src/com/dhsdevelopments/aplandroid/Interpreter.java:
--------------------------------------------------------------------------------
1 | package com.dhsdevelopments.aplandroid;
2 |
3 | import android.app.Activity;
4 | import android.os.Bundle;
5 | import android.view.Menu;
6 | import android.view.MenuInflater;
7 |
8 | public class Interpreter extends Activity
9 | {
10 | @Override
11 | public void onCreate( Bundle savedInstanceState ) {
12 | super.onCreate( savedInstanceState );
13 | setContentView( R.layout.interpreter );
14 | }
15 |
16 | @Override
17 | public boolean onCreateOptionsMenu( Menu menu ) {
18 | MenuInflater menuInflater = getMenuInflater();
19 | menuInflater.inflate( R.menu.main_activity_actions, menu );
20 | return super.onCreateOptionsMenu( menu );
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/client/src/com/dhsdevelopments/aplandroid/InterpreterFragment.java:
--------------------------------------------------------------------------------
1 | package com.dhsdevelopments.aplandroid;
2 |
3 | import android.app.Fragment;
4 | import android.database.DataSetObserver;
5 | import android.graphics.Typeface;
6 | import android.os.Bundle;
7 | import android.view.LayoutInflater;
8 | import android.view.View;
9 | import android.view.ViewGroup;
10 | import android.widget.AdapterView;
11 | import android.widget.Button;
12 | import android.widget.EditText;
13 | import android.widget.ListView;
14 |
15 | public class InterpreterFragment extends Fragment
16 | {
17 | private EditText expressionEntry;
18 | private ListView resultList;
19 | private ResultListAdapter resultListAdapter;
20 |
21 | @Override
22 | public void onCreate( Bundle savedInstanceState ) {
23 | super.onCreate( savedInstanceState );
24 | }
25 |
26 | @Override
27 | public View onCreateView( LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState ) {
28 | View rootView = inflater.inflate( R.layout.interpreter_log, container, false );
29 |
30 | expressionEntry = (EditText)rootView.findViewById( R.id.expression_entry );
31 | Typeface typeface = Typeface.createFromAsset( getActivity().getAssets(), "fonts/FreeMono.ttf" );
32 | expressionEntry.setTypeface( typeface );
33 |
34 | resultList = (ListView)rootView.findViewById( R.id.result_list_view );
35 | resultListAdapter = new ResultListAdapter( getActivity(), inflater, typeface );
36 | resultList.setAdapter( resultListAdapter );
37 | resultList.setOnItemClickListener( new AdapterView.OnItemClickListener()
38 | {
39 | @Override
40 | public void onItemClick( AdapterView> parent, View view, int position, long id ) {
41 | resultEntryClicked( position );
42 | }
43 | } );
44 | resultListAdapter.registerDataSetObserver( new ResultUpdatedObserver() );
45 |
46 | Button sendButton = (Button)rootView.findViewById( R.id.send_expr_button );
47 | sendButton.setOnClickListener( new View.OnClickListener()
48 | {
49 | @Override
50 | public void onClick( View v ) {
51 | sendClicked();
52 | }
53 | } );
54 |
55 | return rootView;
56 | }
57 |
58 | @Override
59 | public void onDestroyView() {
60 | super.onDestroyView();
61 | resultListAdapter.close();
62 | }
63 |
64 | private void resultEntryClicked( int position ) {
65 | ResultListEntry entry = resultListAdapter.getResultListEntry( position );
66 | expressionEntry.setText( entry.getExpr() );
67 | }
68 |
69 | public void sendClicked() {
70 | String expr = expressionEntry.getText().toString().trim();
71 | expressionEntry.setText( "" );
72 |
73 | if( expr.length() > 0 ) {
74 | AplNative aplNative = ((AplAndroidApp)getActivity().getApplicationContext()).getAplNative();
75 | aplNative.evalAsAsync( expr, null );
76 | }
77 | }
78 |
79 | private class ResultUpdatedObserver extends DataSetObserver
80 | {
81 | @Override
82 | public void onChanged() {
83 | resultList.setSelection( resultListAdapter.getCount() - 1 );
84 | }
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/client/src/com/dhsdevelopments/aplandroid/Log.java:
--------------------------------------------------------------------------------
1 | package com.dhsdevelopments.aplandroid;
2 |
3 | @SuppressWarnings("UnusedDeclaration")
4 | public class Log
5 | {
6 | public static final String LOG_TAG = "aplandroid";
7 |
8 | private Log() {
9 | // Prevent instantiation
10 | }
11 |
12 | public static void e( String message ) {
13 | android.util.Log.e( LOG_TAG, message );
14 | }
15 |
16 | public static void e( String message, Throwable throwable ) {
17 | android.util.Log.e( LOG_TAG, message, throwable );
18 | }
19 |
20 | public static void w( String message ) {
21 | android.util.Log.w( LOG_TAG, message );
22 | }
23 |
24 | public static void w( String message, Throwable throwable ) {
25 | android.util.Log.w( LOG_TAG, message, throwable );
26 | }
27 |
28 | public static void i( String message ) {
29 | android.util.Log.i( LOG_TAG, message );
30 | }
31 |
32 | public static void i( String message, Throwable throwable ) {
33 | android.util.Log.i( LOG_TAG, message, throwable );
34 | }
35 |
36 | public static void d( String message ) {
37 | android.util.Log.d( LOG_TAG, message );
38 | }
39 |
40 | public static void d( String message, Throwable throwable ) {
41 | android.util.Log.d( LOG_TAG, message, throwable );
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/client/src/com/dhsdevelopments/aplandroid/ResultListAdapter.java:
--------------------------------------------------------------------------------
1 | package com.dhsdevelopments.aplandroid;
2 |
3 | import android.app.Activity;
4 | import android.database.DataSetObserver;
5 | import android.graphics.Typeface;
6 | import android.view.LayoutInflater;
7 | import android.view.View;
8 | import android.view.ViewGroup;
9 | import android.widget.ListAdapter;
10 | import android.widget.TextView;
11 |
12 | import java.util.ArrayList;
13 | import java.util.List;
14 |
15 | public class ResultListAdapter implements ListAdapter
16 | {
17 | private final AplNative aplNative;
18 | private final AplResultListener resultListener;
19 | private List observers = new ArrayList<>();
20 | private List entries;
21 | private LayoutInflater layoutInflater;
22 | private Typeface typeface;
23 |
24 | public ResultListAdapter( final Activity context, LayoutInflater layoutInflater, Typeface typeface ) {
25 | this.layoutInflater = layoutInflater;
26 | this.typeface = typeface;
27 |
28 | AplAndroidApp app = (AplAndroidApp)context.getApplicationContext();
29 | aplNative = app.getAplNative();
30 | synchronized( aplNative ) {
31 | List list = aplNative.getResultEntries();
32 | entries = new ArrayList<>( list );
33 | resultListener = new AplResultListener( context );
34 | aplNative.addResultListListener( resultListener );
35 | }
36 | }
37 |
38 | public void close() {
39 | aplNative.removeResultListListener( resultListener );
40 | }
41 |
42 | private void fireModelChanged() {
43 | for( DataSetObserver o : observers ) {
44 | o.onChanged();
45 | }
46 | }
47 |
48 | @Override
49 | public boolean areAllItemsEnabled() {
50 | return false;
51 | }
52 |
53 | @Override
54 | public boolean isEnabled( int position ) {
55 | return true;
56 | }
57 |
58 | @Override
59 | public void registerDataSetObserver( DataSetObserver observer ) {
60 | observers.add( observer );
61 | }
62 |
63 | @Override
64 | public void unregisterDataSetObserver( DataSetObserver observer ) {
65 | observers.remove( observer );
66 | }
67 |
68 | @Override
69 | public int getCount() {
70 | return entries.size();
71 | }
72 |
73 | @Override
74 | public Object getItem( int position ) {
75 | return entries.get( position );
76 | }
77 |
78 | @Override
79 | public long getItemId( int position ) {
80 | return position;
81 | }
82 |
83 | @Override
84 | public boolean hasStableIds() {
85 | return false;
86 | }
87 |
88 | @Override
89 | public View getView( int position, View convertView, ViewGroup parent ) {
90 | View resultText;
91 | if( convertView != null && convertView.getId() == R.id.result_text_view ) {
92 | resultText = convertView;
93 | }
94 | else {
95 | resultText = layoutInflater.inflate( R.layout.result_text, parent, false );
96 | }
97 |
98 | ResultListEntry entry = entries.get( position );
99 |
100 | TextView expr = (TextView)resultText.findViewById( R.id.expr );
101 | expr.setTypeface( typeface );
102 | expr.setText( entry.getExpr() );
103 |
104 | TextView content = (TextView)resultText.findViewById( R.id.content );
105 | content.setTypeface( typeface );
106 | content.setText( entry.getResult() );
107 |
108 | return resultText;
109 | }
110 |
111 | @Override
112 | public int getItemViewType( int position ) {
113 | return 0;
114 | }
115 |
116 | @Override
117 | public int getViewTypeCount() {
118 | return 1;
119 | }
120 |
121 | @Override
122 | public boolean isEmpty() {
123 | return entries.isEmpty();
124 | }
125 |
126 | public ResultListEntry getResultListEntry( int position ) {
127 | return entries.get( position );
128 | }
129 |
130 | private class AplResultListener implements AplNative.ResultListListener
131 | {
132 | private Activity context;
133 |
134 | public AplResultListener( Activity context ) {
135 | this.context = context;
136 | }
137 |
138 | @Override
139 | public void resultUpdated( final ResultListEntry entry ) {
140 | context.runOnUiThread( new Runnable()
141 | {
142 | @Override
143 | public void run() {
144 | entries.add( entry );
145 | fireModelChanged();
146 | }
147 | } );
148 | }
149 | }
150 | }
151 |
--------------------------------------------------------------------------------
/client/src/com/dhsdevelopments/aplandroid/ResultListEntry.java:
--------------------------------------------------------------------------------
1 | package com.dhsdevelopments.aplandroid;
2 |
3 | public class ResultListEntry
4 | {
5 | private String expr;
6 | private String result;
7 |
8 | public ResultListEntry( String expr, String result ) {
9 | this.expr = expr;
10 | this.result = result;
11 | }
12 |
13 | public String getExpr() {
14 | return expr;
15 | }
16 |
17 | public String getResult() {
18 | return result;
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/client/src/com/dhsdevelopments/aplandroid/input1/AplInput.java:
--------------------------------------------------------------------------------
1 | package com.dhsdevelopments.aplandroid.input1;
2 |
3 | import android.inputmethodservice.InputMethodService;
4 | import android.inputmethodservice.Keyboard;
5 | import android.inputmethodservice.KeyboardView;
6 | import android.view.View;
7 | import com.dhsdevelopments.aplandroid.Log;
8 | import com.dhsdevelopments.aplandroid.R;
9 |
10 | import java.util.Arrays;
11 |
12 | public class AplInput extends InputMethodService
13 | {
14 | @Override
15 | public View onCreateInputView() {
16 | AplKeyboardView v = (AplKeyboardView)getLayoutInflater().inflate( R.layout.apl_input, null );
17 | v.setOnKeyboardActionListener( new KeyboardAction() );
18 | Keyboard keyboard = new Keyboard( this, R.xml.keyboard_layout );
19 | v.setKeyboard( keyboard );
20 | Log.i( "modifiers:" + keyboard.getModifierKeys() );
21 | Log.i( "keys:" + keyboard.getKeys() );
22 | return v;
23 | }
24 |
25 | private class KeyboardAction implements KeyboardView.OnKeyboardActionListener
26 | {
27 | @Override
28 | public void onPress( int primaryCode ) {
29 | Log.i( "onPress:" + primaryCode );
30 | }
31 |
32 | @Override
33 | public void onRelease( int primaryCode ) {
34 | Log.i( "onRelease:" + primaryCode );
35 | }
36 |
37 | @Override
38 | public void onKey( int primaryCode, int[] keyCodes ) {
39 | Log.i( "onKey:" + primaryCode + "," + Arrays.toString( keyCodes ) );
40 | }
41 |
42 | @Override
43 | public void onText( CharSequence text ) {
44 | Log.i( "onText:'" + text + "'" );
45 | }
46 |
47 | @Override
48 | public void swipeLeft() {
49 | Log.i( "swipeLeft" );
50 | }
51 |
52 | @Override
53 | public void swipeRight() {
54 | Log.i( "swipeRight" );
55 | }
56 |
57 | @Override
58 | public void swipeDown() {
59 | Log.i( "swipeDown" );
60 | }
61 |
62 | @Override
63 | public void swipeUp() {
64 | Log.i( "swipeUp" );
65 | }
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/client/src/com/dhsdevelopments/aplandroid/input1/AplKeyboardView.java:
--------------------------------------------------------------------------------
1 | package com.dhsdevelopments.aplandroid.input1;
2 |
3 | import android.content.Context;
4 | import android.inputmethodservice.KeyboardView;
5 | import android.util.AttributeSet;
6 |
7 | public class AplKeyboardView extends KeyboardView
8 | {
9 | public AplKeyboardView( Context context, AttributeSet attrs ) {
10 | super( context, attrs );
11 | }
12 |
13 | public AplKeyboardView( Context context, AttributeSet attrs, int defStyle ) {
14 | super( context, attrs, defStyle );
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/client/src/com/dhsdevelopments/aplandroid/input1/CustomKeyboard.java:
--------------------------------------------------------------------------------
1 | package com.dhsdevelopments.aplandroid.input1;
2 |
3 | import android.app.Activity;
4 | import android.app.AlertDialog;
5 | import android.content.DialogInterface;
6 | import android.inputmethodservice.Keyboard;
7 | import android.inputmethodservice.KeyboardView;
8 | import android.inputmethodservice.KeyboardView.OnKeyboardActionListener;
9 | import android.text.Editable;
10 | import android.text.InputType;
11 | import android.text.Layout;
12 | import android.view.HapticFeedbackConstants;
13 | import android.view.MotionEvent;
14 | import android.view.View;
15 | import android.view.View.OnClickListener;
16 | import android.view.View.OnFocusChangeListener;
17 | import android.view.View.OnTouchListener;
18 | import android.view.WindowManager;
19 | import android.view.inputmethod.InputMethodManager;
20 | import android.widget.EditText;
21 |
22 | class CustomKeyboard implements android.content.DialogInterface.OnClickListener
23 | {
24 |
25 | /**
26 | * A link to the KeyboardView that is used to render this CustomKeyboard.
27 | */
28 | private KeyboardView mKeyboardView;
29 | /**
30 | * A link to the activity that hosts the {@link #mKeyboardView}.
31 | */
32 | private Activity mHostActivity;
33 | private boolean hapticFeedback;
34 |
35 | /**
36 | * The key (code) handler.
37 | */
38 | private OnKeyboardActionListener mOnKeyboardActionListener = new OnKeyboardActionListener()
39 | {
40 |
41 | // add your own special keys here:
42 | public final static int CodeDelete = -5; // Keyboard.KEYCODE_DELETE
43 | public final static int CodeCancel = -3; // Keyboard.KEYCODE_CANCEL
44 | public final static int CodePrev = 55000;
45 | public final static int CodeAllLeft = 55001;
46 | public final static int CodeLeft = 55002;
47 | public final static int CodeRight = 55003;
48 | public final static int CodeAllRight = 55004;
49 | public final static int CodeNext = 55005;
50 | public final static int CodeClear = 55006;
51 | public final static int CodeConst = 55009;
52 | public final static int CodeLog = 55010;
53 | public final static int CodeConv = 55011; // Conversions like round or degrees
54 | public final static int CodeTrig = 55012;
55 |
56 | @Override
57 | public void onKey( int primaryCode, int[] keyCodes ) {
58 | // NOTE We can say '' in the xml file; all codes come in keyCodes, the first in this list in primaryCode
59 | // Get the EditText and its Editable
60 | View focusCurrent = mHostActivity.getWindow().getCurrentFocus();
61 | if( focusCurrent == null || focusCurrent.getClass() != EditText.class ) {
62 | return;
63 | }
64 | EditText edittext = (EditText)focusCurrent;
65 | Editable editable = edittext.getText();
66 | int start = edittext.getSelectionStart();
67 | // delete the selection, if chars are selected:
68 | int end = edittext.getSelectionEnd();
69 | if( end > start ) {
70 | editable.delete( start, end );
71 | }
72 | // Apply the key to the edittext
73 | if( primaryCode == CodeCancel ) {
74 | hideCustomKeyboard();
75 | }
76 | else if( primaryCode == CodeDelete ) {
77 | if( editable != null && start > 0 ) {
78 | editable.delete( start - 1, start );
79 | }
80 | }
81 | else if( primaryCode == CodeClear ) {
82 | if( editable != null ) {
83 | editable.clear();
84 | }
85 | }
86 | else if( primaryCode == CodeLeft ) {
87 | if( start > 0 ) {
88 | edittext.setSelection( start - 1 );
89 | }
90 | }
91 | else if( primaryCode == CodeRight ) {
92 | if( start < edittext.length() ) {
93 | edittext.setSelection( start + 1 );
94 | }
95 | }
96 | else if( primaryCode == CodeAllLeft ) {
97 | edittext.setSelection( 0 );
98 | }
99 | else if( primaryCode == CodeAllRight ) {
100 | edittext.setSelection( edittext.length() );
101 | }
102 | else if( primaryCode == CodePrev ) {
103 | View focusNew = edittext.focusSearch( View.FOCUS_LEFT );
104 | if( focusNew != null ) {
105 | focusNew.requestFocus();
106 | }
107 | }
108 | else if( primaryCode == CodeNext ) {
109 | View focusNew = edittext.focusSearch( View.FOCUS_RIGHT );
110 | if( focusNew != null ) {
111 | focusNew.requestFocus();
112 | }
113 | }
114 | /*
115 | else if( primaryCode == CodeConst ) {
116 | popupCode = CodeConst;
117 | showNewInsertDialog( R.array.insert_const );
118 | }
119 | else if( primaryCode == CodeLog ) {
120 | // idea for the log, use log2() for a log base 3
121 | popupCode = CodeLog;
122 | showNewInsertDialog( R.array.insert_log );
123 | }
124 | else if( primaryCode == CodeConv ) {
125 | popupCode = CodeConv;
126 | showNewInsertDialog( R.array.insert_conv );
127 | }
128 | else if( primaryCode == CodeTrig ) {
129 | popupCode = CodeTrig;
130 | showNewInsertDialog( R.array.insert_trig );
131 | }
132 | */
133 | else { // insert character
134 | editable.insert( start, Character.toString( (char)primaryCode ) );
135 | }
136 | }
137 |
138 | @Override
139 | public void onPress( int arg0 ) {
140 | // vibrate if haptic feedback is enabled:
141 | if( hapticFeedback && arg0 != 0 ) {
142 | mKeyboardView.performHapticFeedback( HapticFeedbackConstants.VIRTUAL_KEY );
143 | }
144 | }
145 |
146 | @Override
147 | public void onRelease( int primaryCode ) {
148 | }
149 |
150 | @Override
151 | public void onText( CharSequence text ) {
152 | }
153 |
154 | @Override
155 | public void swipeDown() {
156 | }
157 |
158 | @Override
159 | public void swipeLeft() {
160 | }
161 |
162 | @Override
163 | public void swipeRight() {
164 | }
165 |
166 | @Override
167 | public void swipeUp() {
168 | }
169 | };
170 |
171 | /**
172 | * Create a custom keyboard, that uses the KeyboardView (with resource id viewid) of the host activity,
173 | * and load the keyboard layout from xml file layoutid (see {@link Keyboard} for description).
174 | * Note that the host activity must have a KeyboardView in its layout (typically aligned with the bottom of the activity).
175 | * Note that the keyboard layout xml file may include key codes for navigation; see the constants in this class for their values.
176 | * Note that to enable EditText's to use this custom keyboard, call the {@link #registerEditText(int)}.
177 | *
178 | * @param host The hosting activity.
179 | * @param viewid The id of the KeyboardView.
180 | * @param layoutid The id of the xml file containing the keyboard layout.
181 | */
182 | public CustomKeyboard( Activity host, int viewid, int layoutid ) {
183 | mHostActivity = host;
184 | mKeyboardView = (KeyboardView)mHostActivity.findViewById( viewid );
185 | mKeyboardView.setKeyboard( new Keyboard( mHostActivity, layoutid ) );
186 | mKeyboardView.setPreviewEnabled( false ); // NOTE Do not show the preview balloons
187 | mKeyboardView.setOnKeyboardActionListener( mOnKeyboardActionListener );
188 | // Hide the standard keyboard initially
189 | mHostActivity.getWindow().setSoftInputMode( WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN );
190 | }
191 |
192 | /**
193 | * Returns whether the CustomKeyboard is visible.
194 | */
195 | public boolean isCustomKeyboardVisible() {
196 | return mKeyboardView.getVisibility() == View.VISIBLE;
197 | }
198 |
199 | /**
200 | * Make the CustomKeyboard visible, and hide the system keyboard for view v.
201 | */
202 | public void showCustomKeyboard( View v ) {
203 | mKeyboardView.setVisibility( View.VISIBLE );
204 | mKeyboardView.setEnabled( true );
205 | if( v != null ) {
206 | ((InputMethodManager)mHostActivity.getSystemService( Activity.INPUT_METHOD_SERVICE )).hideSoftInputFromWindow( v.getWindowToken(), 0 );
207 | }
208 | }
209 |
210 | /**
211 | * Make the CustomKeyboard invisible.
212 | */
213 | public void hideCustomKeyboard() {
214 | mKeyboardView.setVisibility( View.GONE );
215 | mKeyboardView.setEnabled( false );
216 | }
217 |
218 | /**
219 | * Register EditText with resource id resid (on the hosting activity) for using this custom keyboard.
220 | *
221 | * @param resid The resource id of the EditText that registers to the custom keyboard.
222 | */
223 | public void registerEditText( int resid ) {
224 | // Find the EditText 'resid'
225 | final EditText edittext = (EditText)mHostActivity.findViewById( resid );
226 | // Make the custom keyboard appear
227 | edittext.setOnFocusChangeListener( new OnFocusChangeListener()
228 | {
229 | // NOTE By setting the on focus listener, we can show the custom keyboard when the edit box gets focus, but also hide it when the edit box loses focus
230 | @Override
231 | public void onFocusChange( View v, boolean hasFocus ) {
232 | if( hasFocus ) {
233 | showCustomKeyboard( v );
234 | }
235 | else {
236 | hideCustomKeyboard();
237 | }
238 | }
239 | } );
240 | edittext.setOnClickListener( new OnClickListener()
241 | {
242 | // NOTE By setting the on click listener, we can show the custom keyboard again, by tapping on an edit box that already had focus (but that had the keyboard hidden).
243 | @Override
244 | public void onClick( View v ) {
245 | showCustomKeyboard( v );
246 | }
247 | } );
248 | // Disable standard keyboard hard way
249 | // NOTE There is also an easy way: 'edittext.setInputType(InputType.TYPE_NULL)' (but you will not have a cursor, and no 'edittext.setCursorVisible(true)' doesn't work )
250 | edittext.setOnTouchListener( new OnTouchListener()
251 | {
252 | @Override
253 | public boolean onTouch( View v, MotionEvent event ) {
254 | EditText edittext = (EditText)v;
255 | int inType = edittext.getInputType(); // Backup the input type
256 | edittext.setInputType( InputType.TYPE_NULL ); // Disable standard keyboard
257 | edittext.onTouchEvent( event ); // Call native handler
258 | edittext.setInputType( inType ); // Restore input type
259 | edittext.setCursorVisible( true );
260 | return true; // Consume touch event
261 | }
262 | } );
263 | // Disable spell check (hex strings look like words to Android)
264 | edittext.setInputType( edittext.getInputType() | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS );
265 | /**
266 | * Try to show cursor the complicated way:
267 | * @source http://androidpadanam.wordpress.com/2013/05/29/customkeyboard-example/
268 | * fixes the cursor not movable bug
269 | */
270 | OnTouchListener otl = new OnTouchListener()
271 | {
272 |
273 | @Override
274 | public boolean onTouch( View v, MotionEvent event ) {
275 | if( !(isCustomKeyboardVisible()) ) {
276 | showCustomKeyboard( v );
277 | }
278 | switch( event.getAction() ) {
279 | case MotionEvent.ACTION_DOWN:
280 | Layout layout = ((EditText)v).getLayout();
281 | float x = event.getX() + edittext.getScrollX();
282 | int offset = layout.getOffsetForHorizontal( 0, x );
283 | if( offset > 0 ) {
284 | if( x > layout.getLineMax( 0 ) ) {
285 | edittext.setSelection( offset ); // touch was at the end of the text
286 | }
287 | else {
288 | edittext.setSelection( offset - 1 );
289 | }
290 | }
291 | break;
292 | case MotionEvent.ACTION_MOVE:
293 | layout = ((EditText)v).getLayout();
294 | x = event.getX() + edittext.getScrollX();
295 | offset = layout.getOffsetForHorizontal( 0, x );
296 | if( offset > 0 ) {
297 | if( x > layout.getLineMax( 0 ) ) {
298 | edittext.setSelection( offset ); // Touchpoint was at the end of the text
299 | }
300 | else {
301 | edittext.setSelection( offset - 1 );
302 | }
303 | }
304 | break;
305 |
306 | }
307 | return true;
308 | }
309 | };
310 | edittext.setOnTouchListener( otl );
311 | }
312 |
313 | /*
314 | * Added methods: (may need additional resource files)
315 | */
316 |
317 | /**
318 | * Shows a simple dialog containing a list from the itemsId resource.
319 | * The onClickListener is set to this, see onClick(...) below
320 | */
321 | private void showNewInsertDialog( int itemsId ) {
322 | AlertDialog.Builder builder = new AlertDialog.Builder( mHostActivity );
323 | builder.setItems( itemsId, this );
324 | builder.create().show();
325 | }
326 |
327 | /**
328 | * @param popupCode Code indicating which popup is currently opened for the onClick getter
329 | */
330 | private int popupCode;
331 |
332 | @Override
333 | public void onClick( DialogInterface dialog, int which ) { // insert one of the additional popups to the current Focus field
334 | String insertion = "";
335 | switch( popupCode ) {
336 | /*
337 | case 55009:
338 | insertion = mHostActivity.getResources().getStringArray( R.array.insert_const_values )[which];
339 | break;
340 | case 55010:
341 | insertion = mHostActivity.getResources().getStringArray( R.array.insert_log_values )[which];
342 | break;
343 | case 55011:
344 | insertion = mHostActivity.getResources().getStringArray( R.array.insert_conv_values )[which];
345 | break;
346 | case 55012:
347 | insertion = mHostActivity.getResources().getStringArray( R.array.insert_trig_values )[which];
348 | break;
349 | */
350 | }
351 | View focusCurrent = mHostActivity.getWindow().getCurrentFocus();
352 | if( focusCurrent == null || focusCurrent.getClass() != EditText.class ) {
353 | return;
354 | }
355 | EditText edittext = (EditText)focusCurrent;
356 | Editable editable = edittext.getText();
357 | int start = edittext.getSelectionStart();
358 | // delete the selection, if chars are selected:
359 | int end = edittext.getSelectionEnd();
360 | editable.replace( start, end, insertion );
361 | }
362 |
363 | /**
364 | * Enables or disables the Haptic feedback on keyboard touches
365 | *
366 | * @param goEnabled true if you want haptic feedback, false otherwise
367 | */
368 | public void enableHapticFeedback( boolean goEnabled ) {
369 | mKeyboardView.setHapticFeedbackEnabled( goEnabled );
370 | hapticFeedback = goEnabled;
371 | }
372 | }
373 |
--------------------------------------------------------------------------------
/client/src/com/dhsdevelopments/aplandroid/input2/CandidateView.java:
--------------------------------------------------------------------------------
1 | package com.dhsdevelopments.aplandroid.input2;
2 |
3 | import android.content.Context;
4 | import android.content.res.Resources;
5 | import android.graphics.Canvas;
6 | import android.graphics.Paint;
7 | import android.graphics.Rect;
8 | import android.graphics.drawable.Drawable;
9 | import android.view.GestureDetector;
10 | import android.view.MotionEvent;
11 | import android.view.View;
12 | import com.dhsdevelopments.aplandroid.R;
13 | import org.jetbrains.annotations.NotNull;
14 |
15 | import java.util.ArrayList;
16 | import java.util.List;
17 |
18 | @SuppressWarnings({ "MismatchedReadAndWriteOfArray", "UnusedDeclaration" })
19 | public class CandidateView extends View
20 | {
21 | private static final int OUT_OF_BOUNDS = -1;
22 |
23 | private SoftKeyboard mService;
24 | private List mSuggestions;
25 | private int mSelectedIndex;
26 | private int mTouchX = OUT_OF_BOUNDS;
27 | private Drawable mSelectionHighlight;
28 | private boolean mTypedWordValid;
29 |
30 | private Rect mBgPadding;
31 |
32 | private static final int MAX_SUGGESTIONS = 32;
33 | private static final int SCROLL_PIXELS = 20;
34 |
35 | private int[] mWordWidth = new int[MAX_SUGGESTIONS];
36 | private int[] mWordX = new int[MAX_SUGGESTIONS];
37 |
38 | private static final int X_GAP = 10;
39 |
40 | private static final List EMPTY_LIST = new ArrayList<>();
41 |
42 | private int mColorNormal;
43 | private int mColorRecommended;
44 | private int mColorOther;
45 | private int mVerticalPadding;
46 | private Paint mPaint;
47 | private boolean mScrolled;
48 | private int mTargetScrollX;
49 |
50 | private int mTotalWidth;
51 |
52 | private GestureDetector mGestureDetector;
53 |
54 | /**
55 | * Construct a CandidateView for showing suggested words for completion.
56 | */
57 | @SuppressWarnings("deprecation")
58 | public CandidateView( Context context ) {
59 | super( context );
60 | mSelectionHighlight = context.getResources().getDrawable(
61 | android.R.drawable.list_selector_background );
62 | mSelectionHighlight.setState( new int[] {
63 | android.R.attr.state_enabled,
64 | android.R.attr.state_focused,
65 | android.R.attr.state_window_focused,
66 | android.R.attr.state_pressed
67 | } );
68 |
69 | Resources r = context.getResources();
70 |
71 | setBackgroundColor( r.getColor( R.color.candidate_background ) );
72 |
73 | mColorNormal = r.getColor( R.color.candidate_normal );
74 | mColorRecommended = r.getColor( R.color.candidate_recommended );
75 | mColorOther = r.getColor( R.color.candidate_other );
76 | mVerticalPadding = r.getDimensionPixelSize( R.dimen.candidate_vertical_padding );
77 |
78 | mPaint = new Paint();
79 | mPaint.setColor( mColorNormal );
80 | mPaint.setAntiAlias( true );
81 | mPaint.setTextSize( r.getDimensionPixelSize( R.dimen.candidate_font_height ) );
82 | mPaint.setStrokeWidth( 0 );
83 |
84 | mGestureDetector = new GestureDetector( new GestureDetector.SimpleOnGestureListener()
85 | {
86 | @Override
87 | public boolean onScroll( MotionEvent e1, MotionEvent e2,
88 | float distanceX, float distanceY ) {
89 | mScrolled = true;
90 | int sx = getScrollX();
91 | sx += distanceX;
92 | if( sx < 0 ) {
93 | sx = 0;
94 | }
95 | if( sx + getWidth() > mTotalWidth ) {
96 | sx -= distanceX;
97 | }
98 | mTargetScrollX = sx;
99 | scrollTo( sx, getScrollY() );
100 | invalidate();
101 | return true;
102 | }
103 | } );
104 | setHorizontalFadingEdgeEnabled( true );
105 | setWillNotDraw( false );
106 | setHorizontalScrollBarEnabled( false );
107 | setVerticalScrollBarEnabled( false );
108 | }
109 |
110 | /**
111 | * A connection back to the service to communicate with the text field
112 | */
113 | public void setService( SoftKeyboard listener ) {
114 | mService = listener;
115 | }
116 |
117 | @Override
118 | public int computeHorizontalScrollRange() {
119 | return mTotalWidth;
120 | }
121 |
122 | @Override
123 | protected void onMeasure( int widthMeasureSpec, int heightMeasureSpec ) {
124 | int measuredWidth = resolveSize( 50, widthMeasureSpec );
125 |
126 | // Get the desired height of the icon menu view (last row of items does
127 | // not have a divider below)
128 | Rect padding = new Rect();
129 | mSelectionHighlight.getPadding( padding );
130 | final int desiredHeight = ((int)mPaint.getTextSize()) + mVerticalPadding
131 | + padding.top + padding.bottom;
132 |
133 | // Maximum possible width and desired height
134 | setMeasuredDimension( measuredWidth,
135 | resolveSize( desiredHeight, heightMeasureSpec ) );
136 | }
137 |
138 | /**
139 | * If the canvas is null, then only touch calculations are performed to pick the target
140 | * candidate.
141 | */
142 | @Override
143 | protected void onDraw( Canvas canvas ) {
144 | if( canvas != null ) {
145 | super.onDraw( canvas );
146 | }
147 | mTotalWidth = 0;
148 | if( mSuggestions == null ) {
149 | return;
150 | }
151 |
152 | if( mBgPadding == null ) {
153 | mBgPadding = new Rect( 0, 0, 0, 0 );
154 | if( getBackground() != null ) {
155 | getBackground().getPadding( mBgPadding );
156 | }
157 | }
158 | int x = 0;
159 | final int count = mSuggestions.size();
160 | final int height = getHeight();
161 | final Rect bgPadding = mBgPadding;
162 | final Paint paint = mPaint;
163 | final int touchX = mTouchX;
164 | final int scrollX = getScrollX();
165 | final boolean scrolled = mScrolled;
166 | final boolean typedWordValid = mTypedWordValid;
167 | final int y = (int)(((height - mPaint.getTextSize()) / 2) - mPaint.ascent());
168 |
169 | for( int i = 0 ; i < count ; i++ ) {
170 | String suggestion = mSuggestions.get( i );
171 | float textWidth = paint.measureText( suggestion );
172 | final int wordWidth = (int)textWidth + X_GAP * 2;
173 |
174 | mWordX[i] = x;
175 | mWordWidth[i] = wordWidth;
176 | paint.setColor( mColorNormal );
177 | if( touchX + scrollX >= x && touchX + scrollX < x + wordWidth && !scrolled ) {
178 | if( canvas != null ) {
179 | canvas.translate( x, 0 );
180 | mSelectionHighlight.setBounds( 0, bgPadding.top, wordWidth, height );
181 | mSelectionHighlight.draw( canvas );
182 | canvas.translate( -x, 0 );
183 | }
184 | mSelectedIndex = i;
185 | }
186 |
187 | if( canvas != null ) {
188 | if( (i == 1 && !typedWordValid) || (i == 0 && typedWordValid) ) {
189 | paint.setFakeBoldText( true );
190 | paint.setColor( mColorRecommended );
191 | }
192 | else if( i != 0 ) {
193 | paint.setColor( mColorOther );
194 | }
195 | canvas.drawText( suggestion, x + X_GAP, y, paint );
196 | paint.setColor( mColorOther );
197 | canvas.drawLine( x + wordWidth + 0.5f, bgPadding.top,
198 | x + wordWidth + 0.5f, height + 1, paint );
199 | paint.setFakeBoldText( false );
200 | }
201 | x += wordWidth;
202 | }
203 | mTotalWidth = x;
204 | if( mTargetScrollX != getScrollX() ) {
205 | scrollToTarget();
206 | }
207 | }
208 |
209 | private void scrollToTarget() {
210 | int sx = getScrollX();
211 | if( mTargetScrollX > sx ) {
212 | sx += SCROLL_PIXELS;
213 | if( sx >= mTargetScrollX ) {
214 | sx = mTargetScrollX;
215 | requestLayout();
216 | }
217 | }
218 | else {
219 | sx -= SCROLL_PIXELS;
220 | if( sx <= mTargetScrollX ) {
221 | sx = mTargetScrollX;
222 | requestLayout();
223 | }
224 | }
225 | scrollTo( sx, getScrollY() );
226 | invalidate();
227 | }
228 |
229 | public void setSuggestions( List suggestions, boolean completions,
230 | boolean typedWordValid ) {
231 | clear();
232 | if( suggestions != null ) {
233 | mSuggestions = new ArrayList<>( suggestions );
234 | }
235 | mTypedWordValid = typedWordValid;
236 | scrollTo( 0, 0 );
237 | mTargetScrollX = 0;
238 | // Compute the total width
239 | onDraw( null );
240 | invalidate();
241 | requestLayout();
242 | }
243 |
244 | public void clear() {
245 | mSuggestions = EMPTY_LIST;
246 | mTouchX = OUT_OF_BOUNDS;
247 | mSelectedIndex = -1;
248 | invalidate();
249 | }
250 |
251 | @Override
252 | public boolean onTouchEvent( @NotNull MotionEvent me ) {
253 |
254 | if( mGestureDetector.onTouchEvent( me ) ) {
255 | return true;
256 | }
257 |
258 | int action = me.getAction();
259 | int x = (int)me.getX();
260 | int y = (int)me.getY();
261 | mTouchX = x;
262 |
263 | switch( action ) {
264 | case MotionEvent.ACTION_DOWN:
265 | mScrolled = false;
266 | invalidate();
267 | break;
268 | case MotionEvent.ACTION_MOVE:
269 | if( y <= 0 ) {
270 | // Fling up!?
271 | if( mSelectedIndex >= 0 ) {
272 | mService.pickSuggestionManually( mSelectedIndex );
273 | mSelectedIndex = -1;
274 | }
275 | }
276 | invalidate();
277 | break;
278 | case MotionEvent.ACTION_UP:
279 | if( !mScrolled ) {
280 | if( mSelectedIndex >= 0 ) {
281 | mService.pickSuggestionManually( mSelectedIndex );
282 | }
283 | }
284 | mSelectedIndex = -1;
285 | removeHighlight();
286 | requestLayout();
287 | break;
288 | }
289 | return true;
290 | }
291 |
292 | /**
293 | * For flick through from keyboard, call this method with the x coordinate of the flick
294 | * gesture.
295 | */
296 | public void takeSuggestionAt( float x ) {
297 | mTouchX = (int)x;
298 | // To detect candidate
299 | onDraw( null );
300 | if( mSelectedIndex >= 0 ) {
301 | mService.pickSuggestionManually( mSelectedIndex );
302 | }
303 | invalidate();
304 | }
305 |
306 | private void removeHighlight() {
307 | mTouchX = OUT_OF_BOUNDS;
308 | invalidate();
309 | }
310 | }
311 |
--------------------------------------------------------------------------------
/client/src/com/dhsdevelopments/aplandroid/input2/ImePreferences.java:
--------------------------------------------------------------------------------
1 | package com.dhsdevelopments.aplandroid.input2;
2 |
3 | import android.content.Intent;
4 | import android.os.Bundle;
5 | import android.preference.PreferenceActivity;
6 | import com.dhsdevelopments.aplandroid.R;
7 |
8 | /**
9 | * Displays the IME preferences inside the input method setting.
10 | */
11 | public class ImePreferences extends PreferenceActivity
12 | {
13 | @Override
14 | public Intent getIntent() {
15 | final Intent modIntent = new Intent( super.getIntent() );
16 | modIntent.putExtra( EXTRA_SHOW_FRAGMENT, Settings.class.getName() );
17 | modIntent.putExtra( EXTRA_NO_HEADERS, true );
18 | return modIntent;
19 | }
20 |
21 | @Override
22 | protected void onCreate( Bundle savedInstanceState ) {
23 | super.onCreate( savedInstanceState );
24 |
25 | // We overwrite the title of the activity, as the default one is "Voice Search".
26 | setTitle( "Settings" );
27 | }
28 |
29 | public static class Settings extends InputMethodSettingsFragment
30 | {
31 | @Override
32 | public void onCreate( Bundle savedInstanceState ) {
33 | super.onCreate( savedInstanceState );
34 | setInputMethodSettingsCategoryTitle( R.string.language_selection_title );
35 | setSubtypeEnablerTitle( R.string.select_language );
36 |
37 | // Load the preferences from an XML resource
38 | addPreferencesFromResource( R.xml.ime_preferences );
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/client/src/com/dhsdevelopments/aplandroid/input2/InputMethodSettingsFragment.java:
--------------------------------------------------------------------------------
1 | package com.dhsdevelopments.aplandroid.input2;
2 |
3 | import android.content.Context;
4 | import android.graphics.drawable.Drawable;
5 | import android.os.Bundle;
6 | import android.preference.PreferenceFragment;
7 |
8 | /**
9 | * This is a helper class for an IME's settings preference fragment. It's recommended for every
10 | * IME to have its own settings preference fragment which inherits this class.
11 | */
12 | public abstract class InputMethodSettingsFragment extends PreferenceFragment
13 | implements InputMethodSettingsInterface
14 | {
15 | private final InputMethodSettingsImpl mSettings = new InputMethodSettingsImpl();
16 |
17 | @Override
18 | public void onCreate( Bundle savedInstanceState ) {
19 | super.onCreate( savedInstanceState );
20 | final Context context = getActivity();
21 | setPreferenceScreen( getPreferenceManager().createPreferenceScreen( context ) );
22 | mSettings.init( context, getPreferenceScreen() );
23 | }
24 |
25 | /**
26 | * {@inheritDoc}
27 | */
28 | @Override
29 | public void setInputMethodSettingsCategoryTitle( int resId ) {
30 | mSettings.setInputMethodSettingsCategoryTitle( resId );
31 | }
32 |
33 | /**
34 | * {@inheritDoc}
35 | */
36 | @Override
37 | public void setInputMethodSettingsCategoryTitle( CharSequence title ) {
38 | mSettings.setInputMethodSettingsCategoryTitle( title );
39 | }
40 |
41 | /**
42 | * {@inheritDoc}
43 | */
44 | @Override
45 | public void setSubtypeEnablerTitle( int resId ) {
46 | mSettings.setSubtypeEnablerTitle( resId );
47 | }
48 |
49 | /**
50 | * {@inheritDoc}
51 | */
52 | @Override
53 | public void setSubtypeEnablerTitle( CharSequence title ) {
54 | mSettings.setSubtypeEnablerTitle( title );
55 | }
56 |
57 | /**
58 | * {@inheritDoc}
59 | */
60 | @Override
61 | public void setSubtypeEnablerIcon( int resId ) {
62 | mSettings.setSubtypeEnablerIcon( resId );
63 | }
64 |
65 | /**
66 | * {@inheritDoc}
67 | */
68 | @Override
69 | public void setSubtypeEnablerIcon( Drawable drawable ) {
70 | mSettings.setSubtypeEnablerIcon( drawable );
71 | }
72 |
73 | /**
74 | * {@inheritDoc}
75 | */
76 | @Override
77 | public void onResume() {
78 | super.onResume();
79 | mSettings.updateSubtypeEnabler();
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/client/src/com/dhsdevelopments/aplandroid/input2/InputMethodSettingsImpl.java:
--------------------------------------------------------------------------------
1 | package com.dhsdevelopments.aplandroid.input2;
2 |
3 | import android.content.Context;
4 | import android.content.Intent;
5 | import android.graphics.drawable.Drawable;
6 | import android.preference.Preference;
7 | import android.preference.Preference.OnPreferenceClickListener;
8 | import android.preference.PreferenceScreen;
9 | import android.provider.Settings;
10 | import android.text.TextUtils;
11 | import android.view.inputmethod.InputMethodInfo;
12 | import android.view.inputmethod.InputMethodManager;
13 | import android.view.inputmethod.InputMethodSubtype;
14 |
15 | import java.util.List;
16 |
17 | /* package private */ class InputMethodSettingsImpl implements InputMethodSettingsInterface
18 | {
19 | private Preference mSubtypeEnablerPreference;
20 | private int mInputMethodSettingsCategoryTitleRes;
21 | private CharSequence mInputMethodSettingsCategoryTitle;
22 | private int mSubtypeEnablerTitleRes;
23 | private CharSequence mSubtypeEnablerTitle;
24 | private int mSubtypeEnablerIconRes;
25 | private Drawable mSubtypeEnablerIcon;
26 | private InputMethodManager mImm;
27 | private InputMethodInfo mImi;
28 | private Context mContext;
29 |
30 | /**
31 | * Initialize internal states of this object.
32 | *
33 | * @param context the context for this application.
34 | * @param prefScreen a PreferenceScreen of PreferenceActivity or PreferenceFragment.
35 | * @return true if this application is an IME and has two or more subtypes, false otherwise.
36 | */
37 | public boolean init( final Context context, final PreferenceScreen prefScreen ) {
38 | mContext = context;
39 | mImm = (InputMethodManager)context.getSystemService( Context.INPUT_METHOD_SERVICE );
40 | mImi = getMyImi( context, mImm );
41 | if( mImi == null || mImi.getSubtypeCount() <= 1 ) {
42 | return false;
43 | }
44 | mSubtypeEnablerPreference = new Preference( context );
45 | mSubtypeEnablerPreference
46 | .setOnPreferenceClickListener( new OnPreferenceClickListener()
47 | {
48 | @Override
49 | public boolean onPreferenceClick( Preference preference ) {
50 | final CharSequence title = getSubtypeEnablerTitle( context );
51 | final Intent intent =
52 | new Intent( Settings.ACTION_INPUT_METHOD_SUBTYPE_SETTINGS );
53 | intent.putExtra( Settings.EXTRA_INPUT_METHOD_ID, mImi.getId() );
54 | if( !TextUtils.isEmpty( title ) ) {
55 | intent.putExtra( Intent.EXTRA_TITLE, title );
56 | }
57 | intent.setFlags( Intent.FLAG_ACTIVITY_NEW_TASK
58 | | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
59 | | Intent.FLAG_ACTIVITY_CLEAR_TOP );
60 | context.startActivity( intent );
61 | return true;
62 | }
63 | } );
64 | prefScreen.addPreference( mSubtypeEnablerPreference );
65 | updateSubtypeEnabler();
66 | return true;
67 | }
68 |
69 | private static InputMethodInfo getMyImi( Context context, InputMethodManager imm ) {
70 | final List imis = imm.getInputMethodList();
71 | for( int i = 0 ; i < imis.size() ; ++i ) {
72 | final InputMethodInfo imi = imis.get( i );
73 | if( imis.get( i ).getPackageName().equals( context.getPackageName() ) ) {
74 | return imi;
75 | }
76 | }
77 | return null;
78 | }
79 |
80 | private static String getEnabledSubtypesLabel(
81 | Context context, InputMethodManager imm, InputMethodInfo imi ) {
82 | if( context == null || imm == null || imi == null ) {
83 | return null;
84 | }
85 | final List subtypes = imm.getEnabledInputMethodSubtypeList( imi, true );
86 | final StringBuilder sb = new StringBuilder();
87 | final int N = subtypes.size();
88 | for( int i = 0 ; i < N ; ++i ) {
89 | final InputMethodSubtype subtype = subtypes.get( i );
90 | if( sb.length() > 0 ) {
91 | sb.append( ", " );
92 | }
93 | sb.append( subtype.getDisplayName( context, imi.getPackageName(),
94 | imi.getServiceInfo().applicationInfo ) );
95 | }
96 | return sb.toString();
97 | }
98 |
99 | /**
100 | * {@inheritDoc}
101 | */
102 | @Override
103 | public void setInputMethodSettingsCategoryTitle( int resId ) {
104 | mInputMethodSettingsCategoryTitleRes = resId;
105 | updateSubtypeEnabler();
106 | }
107 |
108 | /**
109 | * {@inheritDoc}
110 | */
111 | @Override
112 | public void setInputMethodSettingsCategoryTitle( CharSequence title ) {
113 | mInputMethodSettingsCategoryTitleRes = 0;
114 | mInputMethodSettingsCategoryTitle = title;
115 | updateSubtypeEnabler();
116 | }
117 |
118 | /**
119 | * {@inheritDoc}
120 | */
121 | @Override
122 | public void setSubtypeEnablerTitle( int resId ) {
123 | mSubtypeEnablerTitleRes = resId;
124 | updateSubtypeEnabler();
125 | }
126 |
127 | /**
128 | * {@inheritDoc}
129 | */
130 | @Override
131 | public void setSubtypeEnablerTitle( CharSequence title ) {
132 | mSubtypeEnablerTitleRes = 0;
133 | mSubtypeEnablerTitle = title;
134 | updateSubtypeEnabler();
135 | }
136 |
137 | /**
138 | * {@inheritDoc}
139 | */
140 | @Override
141 | public void setSubtypeEnablerIcon( int resId ) {
142 | mSubtypeEnablerIconRes = resId;
143 | updateSubtypeEnabler();
144 | }
145 |
146 | /**
147 | * {@inheritDoc}
148 | */
149 | @Override
150 | public void setSubtypeEnablerIcon( Drawable drawable ) {
151 | mSubtypeEnablerIconRes = 0;
152 | mSubtypeEnablerIcon = drawable;
153 | updateSubtypeEnabler();
154 | }
155 |
156 | private CharSequence getSubtypeEnablerTitle( Context context ) {
157 | if( mSubtypeEnablerTitleRes != 0 ) {
158 | return context.getString( mSubtypeEnablerTitleRes );
159 | }
160 | else {
161 | return mSubtypeEnablerTitle;
162 | }
163 | }
164 |
165 | public void updateSubtypeEnabler() {
166 | if( mSubtypeEnablerPreference != null ) {
167 | if( mSubtypeEnablerTitleRes != 0 ) {
168 | mSubtypeEnablerPreference.setTitle( mSubtypeEnablerTitleRes );
169 | }
170 | else if( !TextUtils.isEmpty( mSubtypeEnablerTitle ) ) {
171 | mSubtypeEnablerPreference.setTitle( mSubtypeEnablerTitle );
172 | }
173 | final String summary = getEnabledSubtypesLabel( mContext, mImm, mImi );
174 | if( !TextUtils.isEmpty( summary ) ) {
175 | mSubtypeEnablerPreference.setSummary( summary );
176 | }
177 | if( mSubtypeEnablerIconRes != 0 ) {
178 | mSubtypeEnablerPreference.setIcon( mSubtypeEnablerIconRes );
179 | }
180 | else if( mSubtypeEnablerIcon != null ) {
181 | mSubtypeEnablerPreference.setIcon( mSubtypeEnablerIcon );
182 | }
183 | }
184 | }
185 | }
186 |
--------------------------------------------------------------------------------
/client/src/com/dhsdevelopments/aplandroid/input2/InputMethodSettingsInterface.java:
--------------------------------------------------------------------------------
1 | package com.dhsdevelopments.aplandroid.input2;
2 |
3 | import android.graphics.drawable.Drawable;
4 |
5 | /**
6 | * InputMethodSettingsInterface is the interface for adding IME related preferences to
7 | * PreferenceActivity or PreferenceFragment.
8 | */
9 | public interface InputMethodSettingsInterface
10 | {
11 | /**
12 | * Sets the title for the input method settings category with a resource ID.
13 | *
14 | * @param resId The resource ID of the title.
15 | */
16 | public void setInputMethodSettingsCategoryTitle( int resId );
17 |
18 | /**
19 | * Sets the title for the input method settings category with a CharSequence.
20 | *
21 | * @param title The title for this preference.
22 | */
23 | public void setInputMethodSettingsCategoryTitle( CharSequence title );
24 |
25 | /**
26 | * Sets the title for the input method enabler preference for launching subtype enabler with a
27 | * resource ID.
28 | *
29 | * @param resId The resource ID of the title.
30 | */
31 | public void setSubtypeEnablerTitle( int resId );
32 |
33 | /**
34 | * Sets the title for the input method enabler preference for launching subtype enabler with a
35 | * CharSequence.
36 | *
37 | * @param title The title for this preference.
38 | */
39 | public void setSubtypeEnablerTitle( CharSequence title );
40 |
41 | /**
42 | * Sets the icon for the preference for launching subtype enabler with a resource ID.
43 | *
44 | * @param resId The resource id of an optional icon for the preference.
45 | */
46 | public void setSubtypeEnablerIcon( int resId );
47 |
48 | /**
49 | * Sets the icon for the Preference for launching subtype enabler with a Drawable.
50 | *
51 | * @param drawable The drawable of an optional icon for the preference.
52 | */
53 | public void setSubtypeEnablerIcon( Drawable drawable );
54 | }
55 |
--------------------------------------------------------------------------------
/client/src/com/dhsdevelopments/aplandroid/input2/LatinKeyboard.java:
--------------------------------------------------------------------------------
1 | package com.dhsdevelopments.aplandroid.input2;
2 |
3 | import android.content.Context;
4 | import android.content.res.Resources;
5 | import android.content.res.XmlResourceParser;
6 | import android.graphics.Typeface;
7 | import android.graphics.drawable.Drawable;
8 | import android.inputmethodservice.Keyboard;
9 | import android.view.inputmethod.EditorInfo;
10 | import com.dhsdevelopments.aplandroid.R;
11 |
12 | public class LatinKeyboard extends Keyboard
13 | {
14 | private Key enterKey;
15 | private Key spaceKey;
16 | private Typeface typeface;
17 |
18 | public LatinKeyboard( Context context, int xmlLayoutResId ) {
19 | super( context, xmlLayoutResId );
20 | init( context );
21 | }
22 |
23 | public LatinKeyboard( Context context, int layoutTemplateResId,
24 | CharSequence characters, int columns, int horizontalPadding ) {
25 | super( context, layoutTemplateResId, characters, columns, horizontalPadding );
26 | init( context );
27 | }
28 |
29 | private void init( Context context ) {
30 | typeface = Typeface.createFromAsset( context.getAssets(), "fonts/FreeMono.ttf" );
31 | }
32 |
33 | @Override
34 | protected Key createKeyFromXml( Resources res, Row parent, int x, int y,
35 | XmlResourceParser parser ) {
36 | Key key = new LatinKey( res, parent, x, y, parser, typeface );
37 |
38 | if( key.codes[0] == 10 ) {
39 | enterKey = key;
40 | }
41 | else if( key.codes[0] == ' ' ) {
42 | spaceKey = key;
43 | }
44 | return key;
45 | }
46 |
47 | /**
48 | * This looks at the ime options given by the current editor, to set the
49 | * appropriate label on the keyboard's enter key (if it has one).
50 | */
51 | void setImeOptions( Resources res, int options ) {
52 | if( enterKey == null ) {
53 | return;
54 | }
55 |
56 | switch( options & (EditorInfo.IME_MASK_ACTION | EditorInfo.IME_FLAG_NO_ENTER_ACTION) ) {
57 | case EditorInfo.IME_ACTION_GO:
58 | enterKey.iconPreview = null;
59 | enterKey.icon = null;
60 | enterKey.label = res.getText( R.string.label_go_key );
61 | break;
62 | case EditorInfo.IME_ACTION_NEXT:
63 | enterKey.iconPreview = null;
64 | enterKey.icon = null;
65 | enterKey.label = res.getText( R.string.label_next_key );
66 | break;
67 | case EditorInfo.IME_ACTION_SEARCH:
68 | enterKey.icon = res.getDrawable( R.drawable.sym_keyboard_search );
69 | enterKey.label = null;
70 | break;
71 | case EditorInfo.IME_ACTION_SEND:
72 | enterKey.iconPreview = null;
73 | enterKey.icon = null;
74 | enterKey.label = res.getText( R.string.label_send_key );
75 | break;
76 | default:
77 | enterKey.icon = res.getDrawable( R.drawable.sym_keyboard_return );
78 | enterKey.label = null;
79 | break;
80 | }
81 | }
82 |
83 | void setSpaceIcon( final Drawable icon ) {
84 | if( spaceKey != null ) {
85 | spaceKey.icon = icon;
86 | }
87 | }
88 |
89 | static class LatinKey extends Keyboard.Key
90 | {
91 | public LatinKey( Resources res, Row parent, int x, int y, XmlResourceParser parser, Typeface typeface ) {
92 | super( res, parent, x, y, parser );
93 | // if( label != null ) {
94 | // SpannableString s = new SpannableString( label );
95 | // s.setSpan( new CustomTypefaceSpan( "monospace", typeface ), 0, s.length(), 0 );
96 | // label = s;
97 | // }
98 | }
99 |
100 | /**
101 | * Overriding this method so that we can reduce the target area for the key that
102 | * closes the keyboard.
103 | */
104 | @Override
105 | public boolean isInside( int x, int y ) {
106 | return super.isInside( x, codes[0] == KEYCODE_CANCEL ? y - 10 : y );
107 | }
108 | }
109 | }
110 |
--------------------------------------------------------------------------------
/client/src/com/dhsdevelopments/aplandroid/input2/LatinKeyboardView.java:
--------------------------------------------------------------------------------
1 | package com.dhsdevelopments.aplandroid.input2;
2 |
3 | import android.content.Context;
4 | import android.graphics.Paint;
5 | import android.graphics.Typeface;
6 | import android.inputmethodservice.Keyboard;
7 | import android.inputmethodservice.Keyboard.Key;
8 | import android.inputmethodservice.KeyboardView;
9 | import android.util.AttributeSet;
10 | import com.dhsdevelopments.aplandroid.Log;
11 | import org.jetbrains.annotations.NotNull;
12 |
13 | import java.lang.reflect.Field;
14 |
15 | public class LatinKeyboardView extends KeyboardView
16 | {
17 | static final int KEYCODE_OPTIONS = -100;
18 |
19 | @SuppressWarnings("UnusedDeclaration")
20 | public LatinKeyboardView( Context context, AttributeSet attrs ) {
21 | super( context, attrs );
22 | init();
23 | }
24 |
25 | @SuppressWarnings("UnusedDeclaration")
26 | public LatinKeyboardView( Context context, AttributeSet attrs, int defStyle ) {
27 | super( context, attrs, defStyle );
28 | init();
29 | }
30 |
31 | private void init() {
32 | Typeface typeface = Typeface.createFromAsset( getContext().getAssets(), "fonts/FreeMono.ttf" );
33 | try {
34 | Field paintField = KeyboardView.class.getDeclaredField( "mPaint" );
35 | Log.i( "paintField = " + paintField );
36 | paintField.setAccessible( true );
37 | Log.i( "is accessible:" + paintField.isAccessible() );
38 | Paint origPaint = (Paint)paintField.get( this );
39 | PaintOverride newPaint = new PaintOverride( origPaint, typeface );
40 | paintField.set( this, newPaint );
41 | }
42 | catch( NoSuchFieldException e ) {
43 | Log.e( "can't find field", e );
44 | }
45 | catch( IllegalAccessException e ) {
46 | Log.e( "Error accessing paint member", e );
47 | }
48 | }
49 |
50 | @Override
51 | protected boolean onLongPress( @NotNull Key key ) {
52 | if( key.codes[0] == Keyboard.KEYCODE_CANCEL ) {
53 | getOnKeyboardActionListener().onKey( KEYCODE_OPTIONS, null );
54 | return true;
55 | }
56 | else {
57 | return super.onLongPress( key );
58 | }
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/client/src/com/dhsdevelopments/aplandroid/input2/PaintOverride.java:
--------------------------------------------------------------------------------
1 | package com.dhsdevelopments.aplandroid.input2;
2 |
3 | import android.graphics.Paint;
4 | import android.graphics.Typeface;
5 |
6 | public class PaintOverride extends Paint
7 | {
8 | private Typeface overrideTypeface;
9 |
10 | public PaintOverride( Paint paint, Typeface overrideTypeface ) {
11 | super( paint );
12 | this.overrideTypeface = overrideTypeface;
13 | }
14 |
15 | @Override
16 | public Typeface setTypeface( Typeface typeface ) {
17 | return super.setTypeface( overrideTypeface == null ? typeface : overrideTypeface );
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/client/src/com/dhsdevelopments/aplandroid/input2/SoftKeyboard.java:
--------------------------------------------------------------------------------
1 | package com.dhsdevelopments.aplandroid.input2;
2 |
3 | import android.annotation.SuppressLint;
4 | import android.inputmethodservice.InputMethodService;
5 | import android.inputmethodservice.Keyboard;
6 | import android.inputmethodservice.KeyboardView;
7 | import android.text.InputType;
8 | import android.text.method.MetaKeyKeyListener;
9 | import android.view.KeyCharacterMap;
10 | import android.view.KeyEvent;
11 | import android.view.View;
12 | import android.view.inputmethod.CompletionInfo;
13 | import android.view.inputmethod.EditorInfo;
14 | import android.view.inputmethod.InputConnection;
15 | import android.view.inputmethod.InputMethodManager;
16 | import com.dhsdevelopments.aplandroid.R;
17 | import org.jetbrains.annotations.NotNull;
18 |
19 | import java.util.ArrayList;
20 | import java.util.List;
21 |
22 | /**
23 | * Example of writing an input method for a soft keyboard. This code is
24 | * focused on simplicity over completeness, so it should in no way be considered
25 | * to be a complete soft keyboard implementation. Its purpose is to provide
26 | * a basic example for how you would get started writing an input method, to
27 | * be fleshed out as appropriate.
28 | */
29 | public class SoftKeyboard extends InputMethodService
30 | implements KeyboardView.OnKeyboardActionListener
31 | {
32 | /**
33 | * This boolean indicates the optional example code for performing
34 | * processing of hard keys in addition to regular text generation
35 | * from on-screen interaction. It would be used for input methods that
36 | * perform language translations (such as converting text entered on
37 | * a QWERTY keyboard to Chinese), but may not be used for input methods
38 | * that are primarily intended to be used for on-screen text entry.
39 | */
40 | static final boolean PROCESS_HARD_KEYS = true;
41 |
42 | private InputMethodManager inputMethodManager;
43 |
44 | private LatinKeyboardView inputView;
45 | private CandidateView candidateView;
46 | private CompletionInfo[] completions;
47 |
48 | private StringBuilder composing = new StringBuilder();
49 | private boolean predictionOn;
50 | private boolean completionOn;
51 | private int lastDisplayWidth;
52 | private boolean capsLock;
53 | private long lastShiftTime;
54 | private long metaState;
55 |
56 | private LatinKeyboard symbolsKeyboard;
57 | private LatinKeyboard symbolsShiftedKeyboard;
58 | private LatinKeyboard qwertyKeyboard;
59 | private LatinKeyboard symbolsAplKeyboard;
60 | private LatinKeyboard symbolsAplShiftedKeyboard;
61 |
62 | private LatinKeyboard curKeyboard;
63 |
64 | private String wordSeparators;
65 |
66 | /**
67 | * Main initialization of the input method component. Be sure to call
68 | * to super class.
69 | */
70 | @Override
71 | public void onCreate() {
72 | super.onCreate();
73 | inputMethodManager = (InputMethodManager)getSystemService( INPUT_METHOD_SERVICE );
74 | wordSeparators = getResources().getString( R.string.word_separators );
75 | }
76 |
77 | /**
78 | * This is the point where you can do all of your UI initialization. It
79 | * is called after creation and any configuration change.
80 | */
81 | @Override
82 | public void onInitializeInterface() {
83 | if( qwertyKeyboard != null ) {
84 | // Configuration changes can happen after the keyboard gets recreated,
85 | // so we need to be able to re-build the keyboards if the available
86 | // space has changed.
87 | int displayWidth = getMaxWidth();
88 | if( displayWidth == lastDisplayWidth ) {
89 | return;
90 | }
91 | lastDisplayWidth = displayWidth;
92 | }
93 | qwertyKeyboard = new LatinKeyboard( this, R.xml.qwerty );
94 | symbolsKeyboard = new LatinKeyboard( this, R.xml.symbols );
95 | symbolsShiftedKeyboard = new LatinKeyboard( this, R.xml.symbols_shift );
96 | symbolsAplKeyboard = new LatinKeyboard( this, R.xml.symbols_apl );
97 | symbolsAplShiftedKeyboard = new LatinKeyboard( this, R.xml.symbols_apl_shift );
98 | }
99 |
100 | /**
101 | * Called by the framework when your view for creating input needs to
102 | * be generated. This will be called the first time your input method
103 | * is displayed, and every time it needs to be re-created such as due to
104 | * a configuration change.
105 | */
106 | @SuppressLint("InflateParams")
107 | @Override
108 | public View onCreateInputView() {
109 | inputView = (LatinKeyboardView)getLayoutInflater().inflate( R.layout.input, null );
110 | inputView.setOnKeyboardActionListener( this );
111 | inputView.setKeyboard( qwertyKeyboard );
112 | return inputView;
113 | }
114 |
115 | /**
116 | * Called by the framework when your view for showing candidates needs to
117 | * be generated, like {@link #onCreateInputView}.
118 | */
119 | @Override
120 | public View onCreateCandidatesView() {
121 | // candidateView = new CandidateView( this );
122 | // candidateView.setService( this );
123 | // return candidateView;
124 | return null;
125 | }
126 |
127 | /**
128 | * This is the main point where we do our initialization of the input method
129 | * to begin operating on an application. At this point we have been
130 | * bound to the client, and are now receiving all of the detailed information
131 | * about the target of our edits.
132 | */
133 | @Override
134 | public void onStartInput( EditorInfo attribute, boolean restarting ) {
135 | super.onStartInput( attribute, restarting );
136 |
137 | // Reset our state. We want to do this even if restarting, because
138 | // the underlying state of the text editor could have changed in any way.
139 | composing.setLength( 0 );
140 | updateCandidates();
141 |
142 | if( !restarting ) {
143 | // Clear shift states.
144 | metaState = 0;
145 | }
146 |
147 | predictionOn = false;
148 | completionOn = false;
149 | completions = null;
150 |
151 | // We are now going to initialize our state based on the type of
152 | // text being edited.
153 | switch( attribute.inputType & InputType.TYPE_MASK_CLASS ) {
154 | case InputType.TYPE_CLASS_NUMBER:
155 | case InputType.TYPE_CLASS_DATETIME:
156 | // Numbers and dates default to the symbols keyboard, with
157 | // no extra features.
158 | curKeyboard = symbolsKeyboard;
159 | break;
160 |
161 | case InputType.TYPE_CLASS_PHONE:
162 | // Phones will also default to the symbols keyboard, though
163 | // often you will want to have a dedicated phone keyboard.
164 | curKeyboard = symbolsKeyboard;
165 | break;
166 |
167 | case InputType.TYPE_CLASS_TEXT:
168 | // This is general text editing. We will default to the
169 | // normal alphabetic keyboard, and assume that we should
170 | // be doing predictive text (showing candidates as the
171 | // user types).
172 | curKeyboard = qwertyKeyboard;
173 | predictionOn = true;
174 |
175 | // We now look for a few special variations of text that will
176 | // modify our behavior.
177 | int variation = attribute.inputType & InputType.TYPE_MASK_VARIATION;
178 | if( variation == InputType.TYPE_TEXT_VARIATION_PASSWORD ||
179 | variation == InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD ) {
180 | // Do not display predictions / what the user is typing
181 | // when they are entering a password.
182 | predictionOn = false;
183 | }
184 |
185 | if( variation == InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS
186 | || variation == InputType.TYPE_TEXT_VARIATION_URI
187 | || variation == InputType.TYPE_TEXT_VARIATION_FILTER ) {
188 | // Our predictions are not useful for e-mail addresses
189 | // or URIs.
190 | predictionOn = false;
191 | }
192 |
193 | if( (attribute.inputType & InputType.TYPE_TEXT_FLAG_AUTO_COMPLETE) != 0 ) {
194 | // If this is an auto-complete text view, then our predictions
195 | // will not be shown and instead we will allow the editor
196 | // to supply their own. We only show the editor's
197 | // candidates when in fullscreen mode, otherwise relying
198 | // own it displaying its own UI.
199 | predictionOn = false;
200 | completionOn = isFullscreenMode();
201 | }
202 |
203 | // We also want to look at the current state of the editor
204 | // to decide whether our alphabetic keyboard should start out
205 | // shifted.
206 | updateShiftKeyState( attribute );
207 | break;
208 |
209 | default:
210 | // For all unknown input types, default to the alphabetic
211 | // keyboard with no special features.
212 | curKeyboard = qwertyKeyboard;
213 | updateShiftKeyState( attribute );
214 | }
215 |
216 | // Update the label on the enter key, depending on what the application
217 | // says it will do.
218 | curKeyboard.setImeOptions( getResources(), attribute.imeOptions );
219 | }
220 |
221 | /**
222 | * This is called when the user is done editing a field. We can use
223 | * this to reset our state.
224 | */
225 | @Override
226 | public void onFinishInput() {
227 | super.onFinishInput();
228 |
229 | // Clear current composing text and candidates.
230 | composing.setLength( 0 );
231 | updateCandidates();
232 |
233 | // We only hide the candidates window when finishing input on
234 | // a particular editor, to avoid popping the underlying application
235 | // up and down if the user is entering text into the bottom of
236 | // its window.
237 | setCandidatesViewShown( false );
238 |
239 | curKeyboard = qwertyKeyboard;
240 | if( inputView != null ) {
241 | inputView.closing();
242 | }
243 | }
244 |
245 | @Override
246 | public void onStartInputView( EditorInfo attribute, boolean restarting ) {
247 | super.onStartInputView( attribute, restarting );
248 | // Apply the selected keyboard to the input view.
249 | inputView.setKeyboard( curKeyboard );
250 | inputView.closing();
251 | // final InputMethodSubtype subtype = inputMethodManager.getCurrentInputMethodSubtype();
252 | // inputView.setSubtypeOnSpaceKey( subtype );
253 | }
254 |
255 | // @Override
256 | // public void onCurrentInputMethodSubtypeChanged( InputMethodSubtype subtype ) {
257 | // inputView.setSubtypeOnSpaceKey( subtype );
258 | // }
259 |
260 | /**
261 | * Deal with the editor reporting movement of its cursor.
262 | */
263 | @Override
264 | public void onUpdateSelection( int oldSelStart, int oldSelEnd,
265 | int newSelStart, int newSelEnd,
266 | int candidatesStart, int candidatesEnd ) {
267 | super.onUpdateSelection( oldSelStart, oldSelEnd, newSelStart, newSelEnd,
268 | candidatesStart, candidatesEnd );
269 |
270 | // If the current selection in the text view changes, we should
271 | // clear whatever candidate text we have.
272 | if( composing.length() > 0 && (newSelStart != candidatesEnd
273 | || newSelEnd != candidatesEnd) ) {
274 | composing.setLength( 0 );
275 | updateCandidates();
276 | InputConnection ic = getCurrentInputConnection();
277 | if( ic != null ) {
278 | ic.finishComposingText();
279 | }
280 | }
281 | }
282 |
283 | /**
284 | * This tells us about completions that the editor has determined based
285 | * on the current text in it. We want to use this in fullscreen mode
286 | * to show the completions ourself, since the editor can not be seen
287 | * in that situation.
288 | */
289 | @Override
290 | public void onDisplayCompletions( CompletionInfo[] completions ) {
291 | if( completionOn ) {
292 | this.completions = completions;
293 | if( completions == null ) {
294 | setSuggestions( null, false, false );
295 | return;
296 | }
297 |
298 | List stringList = new ArrayList<>();
299 | for( CompletionInfo ci : completions ) {
300 | if( ci != null ) {
301 | stringList.add( ci.getText().toString() );
302 | }
303 | }
304 | setSuggestions( stringList, true, true );
305 | }
306 | }
307 |
308 | /**
309 | * This translates incoming hard key events in to edit operations on an
310 | * InputConnection. It is only needed when using the
311 | * PROCESS_HARD_KEYS option.
312 | */
313 | private boolean translateKeyDown( int keyCode, KeyEvent event ) {
314 | metaState = MetaKeyKeyListener.handleKeyDown( metaState,
315 | keyCode, event );
316 | int c = event.getUnicodeChar( MetaKeyKeyListener.getMetaState( metaState ) );
317 | metaState = MetaKeyKeyListener.adjustMetaAfterKeypress( metaState );
318 | InputConnection ic = getCurrentInputConnection();
319 | if( c == 0 || ic == null ) {
320 | return false;
321 | }
322 |
323 | boolean dead = false;
324 |
325 | if( (c & KeyCharacterMap.COMBINING_ACCENT) != 0 ) {
326 | dead = true;
327 | c = c & KeyCharacterMap.COMBINING_ACCENT_MASK;
328 | }
329 |
330 | if( composing.length() > 0 ) {
331 | char accent = composing.charAt( composing.length() - 1 );
332 | int composed = KeyEvent.getDeadChar( accent, c );
333 |
334 | if( composed != 0 ) {
335 | c = composed;
336 | composing.setLength( composing.length() - 1 );
337 | }
338 | }
339 |
340 | onKey( c, null );
341 |
342 | return true;
343 | }
344 |
345 | /**
346 | * Use this to monitor key events being delivered to the application.
347 | * We get first crack at them, and can either resume them or let them
348 | * continue to the app.
349 | */
350 | @Override
351 | public boolean onKeyDown( int keyCode, @NotNull KeyEvent event ) {
352 | switch( keyCode ) {
353 | case KeyEvent.KEYCODE_BACK:
354 | // The InputMethodService already takes care of the back
355 | // key for us, to dismiss the input method if it is shown.
356 | // However, our keyboard could be showing a pop-up window
357 | // that back should dismiss, so we first allow it to do that.
358 | if( event.getRepeatCount() == 0 && inputView != null ) {
359 | if( inputView.handleBack() ) {
360 | return true;
361 | }
362 | }
363 | break;
364 |
365 | case KeyEvent.KEYCODE_DEL:
366 | // Special handling of the delete key: if we currently are
367 | // composing text for the user, we want to modify that instead
368 | // of let the application to the delete itself.
369 | if( composing.length() > 0 ) {
370 | onKey( Keyboard.KEYCODE_DELETE, null );
371 | return true;
372 | }
373 | break;
374 |
375 | case KeyEvent.KEYCODE_ENTER:
376 | // Let the underlying text editor always handle these.
377 | return false;
378 |
379 | default:
380 | // For all other keys, if we want to do transformations on
381 | // text being entered with a hard keyboard, we need to process
382 | // it and do the appropriate action.
383 | if( PROCESS_HARD_KEYS ) {
384 | if( keyCode == KeyEvent.KEYCODE_SPACE
385 | && (event.getMetaState() & KeyEvent.META_ALT_ON) != 0 ) {
386 | // A silly example: in our input method, Alt+Space
387 | // is a shortcut for 'android' in lower case.
388 | InputConnection ic = getCurrentInputConnection();
389 | if( ic != null ) {
390 | // First, tell the editor that it is no longer in the
391 | // shift state, since we are consuming this.
392 | ic.clearMetaKeyStates( KeyEvent.META_ALT_ON );
393 | keyDownUp( KeyEvent.KEYCODE_A );
394 | keyDownUp( KeyEvent.KEYCODE_N );
395 | keyDownUp( KeyEvent.KEYCODE_D );
396 | keyDownUp( KeyEvent.KEYCODE_R );
397 | keyDownUp( KeyEvent.KEYCODE_O );
398 | keyDownUp( KeyEvent.KEYCODE_I );
399 | keyDownUp( KeyEvent.KEYCODE_D );
400 | // And we consume this event.
401 | return true;
402 | }
403 | }
404 | if( predictionOn && translateKeyDown( keyCode, event ) ) {
405 | return true;
406 | }
407 | }
408 | }
409 |
410 | return super.onKeyDown( keyCode, event );
411 | }
412 |
413 | /**
414 | * Use this to monitor key events being delivered to the application.
415 | * We get first crack at them, and can either resume them or let them
416 | * continue to the app.
417 | */
418 | @Override
419 | public boolean onKeyUp( int keyCode, @NotNull KeyEvent event ) {
420 | // If we want to do transformations on text being entered with a hard
421 | // keyboard, we need to process the up events to update the meta key
422 | // state we are tracking.
423 | if( PROCESS_HARD_KEYS ) {
424 | if( predictionOn ) {
425 | metaState = MetaKeyKeyListener.handleKeyUp( metaState,
426 | keyCode, event );
427 | }
428 | }
429 |
430 | return super.onKeyUp( keyCode, event );
431 | }
432 |
433 | /**
434 | * Helper function to commit any text being composed in to the editor.
435 | */
436 | private void commitTyped( InputConnection inputConnection ) {
437 | if( composing.length() > 0 ) {
438 | inputConnection.commitText( composing, composing.length() );
439 | composing.setLength( 0 );
440 | updateCandidates();
441 | }
442 | }
443 |
444 | /**
445 | * Helper to update the shift state of our keyboard based on the initial
446 | * editor state.
447 | */
448 | private void updateShiftKeyState( EditorInfo attr ) {
449 | if( attr != null
450 | && inputView != null && qwertyKeyboard == inputView.getKeyboard() ) {
451 | int caps = 0;
452 | EditorInfo ei = getCurrentInputEditorInfo();
453 | if( ei != null && ei.inputType != InputType.TYPE_NULL ) {
454 | caps = getCurrentInputConnection().getCursorCapsMode( attr.inputType );
455 | }
456 | inputView.setShifted( capsLock || caps != 0 );
457 | }
458 | }
459 |
460 | /**
461 | * Helper to determine if a given character code is alphabetic.
462 | */
463 | private boolean isAlphabet( int code ) {
464 | return Character.isLetter( code );
465 | }
466 |
467 | /**
468 | * Helper to send a key down / key up pair to the current editor.
469 | */
470 | private void keyDownUp( int keyEventCode ) {
471 | getCurrentInputConnection().sendKeyEvent(
472 | new KeyEvent( KeyEvent.ACTION_DOWN, keyEventCode ) );
473 | getCurrentInputConnection().sendKeyEvent(
474 | new KeyEvent( KeyEvent.ACTION_UP, keyEventCode ) );
475 | }
476 |
477 | /**
478 | * Helper to send a character to the editor as raw key events.
479 | */
480 | private void sendKey( int keyCode ) {
481 | switch( keyCode ) {
482 | case '\n':
483 | keyDownUp( KeyEvent.KEYCODE_ENTER );
484 | break;
485 | default:
486 | if( keyCode >= '0' && keyCode <= '9' ) {
487 | keyDownUp( keyCode - '0' + KeyEvent.KEYCODE_0 );
488 | }
489 | else {
490 | getCurrentInputConnection().commitText( String.valueOf( (char)keyCode ), 1 );
491 | }
492 | break;
493 | }
494 | }
495 |
496 | // Implementation of KeyboardViewListener
497 |
498 | public void onKey( int primaryCode, int[] keyCodes ) {
499 | if( isWordSeparator( primaryCode ) ) {
500 | // Handle separator
501 | if( composing.length() > 0 ) {
502 | commitTyped( getCurrentInputConnection() );
503 | }
504 | sendKey( primaryCode );
505 | updateShiftKeyState( getCurrentInputEditorInfo() );
506 | }
507 | else if( primaryCode == Keyboard.KEYCODE_DELETE ) {
508 | handleBackspace();
509 | }
510 | else if( primaryCode == Keyboard.KEYCODE_SHIFT ) {
511 | handleShift();
512 | }
513 | else if( primaryCode == Keyboard.KEYCODE_CANCEL ) {
514 | handleClose();
515 | }
516 | else if( primaryCode == LatinKeyboardView.KEYCODE_OPTIONS ) {
517 | // A menu should possible be displayed here
518 | }
519 | else if( primaryCode == Keyboard.KEYCODE_MODE_CHANGE
520 | && inputView != null ) {
521 | Keyboard current = inputView.getKeyboard();
522 | if( current == symbolsKeyboard || current == symbolsShiftedKeyboard ) {
523 | current = qwertyKeyboard;
524 | }
525 | else {
526 | current = symbolsKeyboard;
527 | }
528 | inputView.setKeyboard( current );
529 | if( current == symbolsKeyboard ) {
530 | current.setShifted( false );
531 | }
532 | }
533 | else if( primaryCode == -1000 && inputView != null ) {
534 | // Keyboard current = inputView.getKeyboard();
535 | // if( current == qwertyKeyboard ) {
536 | // current = symbolsAplKeyboard;
537 | // }
538 | // else {
539 | // current = symbolsKeyboard;
540 | // }
541 | // inputView.setKeyboard( current );
542 | // current.setShifted( false );
543 | Keyboard current = symbolsAplKeyboard;
544 | inputView.setKeyboard( current );
545 | current.setShifted( false );
546 | }
547 | else if( primaryCode == -1001 && inputView != null ) {
548 | Keyboard current = symbolsKeyboard;
549 | inputView.setKeyboard( current );
550 | current.setShifted( false );
551 | }
552 | else {
553 | handleCharacter( primaryCode, keyCodes );
554 | }
555 | }
556 |
557 | public void onText( CharSequence text ) {
558 | InputConnection ic = getCurrentInputConnection();
559 | if( ic == null ) {
560 | return;
561 | }
562 | ic.beginBatchEdit();
563 | if( composing.length() > 0 ) {
564 | commitTyped( ic );
565 | }
566 | ic.commitText( text, 0 );
567 | ic.endBatchEdit();
568 | updateShiftKeyState( getCurrentInputEditorInfo() );
569 | }
570 |
571 | /**
572 | * Update the list of available candidates from the current composing
573 | * text. This will need to be filled in by however you are determining
574 | * candidates.
575 | */
576 | private void updateCandidates() {
577 | if( !completionOn ) {
578 | if( composing.length() > 0 ) {
579 | ArrayList list = new ArrayList<>();
580 | list.add( composing.toString() );
581 | setSuggestions( list, true, true );
582 | }
583 | else {
584 | setSuggestions( null, false, false );
585 | }
586 | }
587 | }
588 |
589 | public void setSuggestions( List suggestions, boolean completions,
590 | boolean typedWordValid ) {
591 | if( suggestions != null && suggestions.size() > 0 ) {
592 | setCandidatesViewShown( true );
593 | }
594 | else if( isExtractViewShown() ) {
595 | setCandidatesViewShown( true );
596 | }
597 | if( candidateView != null ) {
598 | candidateView.setSuggestions( suggestions, completions, typedWordValid );
599 | }
600 | }
601 |
602 | private void handleBackspace() {
603 | final int length = composing.length();
604 | if( length > 1 ) {
605 | composing.delete( length - 1, length );
606 | getCurrentInputConnection().setComposingText( composing, 1 );
607 | updateCandidates();
608 | }
609 | else if( length > 0 ) {
610 | composing.setLength( 0 );
611 | getCurrentInputConnection().commitText( "", 0 );
612 | updateCandidates();
613 | }
614 | else {
615 | keyDownUp( KeyEvent.KEYCODE_DEL );
616 | }
617 | updateShiftKeyState( getCurrentInputEditorInfo() );
618 | }
619 |
620 | private void handleShift() {
621 | if( inputView == null ) {
622 | return;
623 | }
624 |
625 | Keyboard currentKeyboard = inputView.getKeyboard();
626 | if( qwertyKeyboard == currentKeyboard ) {
627 | // Alphabet keyboard
628 | checkToggleCapsLock();
629 | inputView.setShifted( capsLock || !inputView.isShifted() );
630 | }
631 | else if( currentKeyboard == symbolsKeyboard ) {
632 | symbolsKeyboard.setShifted( true );
633 | inputView.setKeyboard( symbolsShiftedKeyboard );
634 | symbolsShiftedKeyboard.setShifted( true );
635 | }
636 | else if( currentKeyboard == symbolsShiftedKeyboard ) {
637 | symbolsShiftedKeyboard.setShifted( false );
638 | inputView.setKeyboard( symbolsKeyboard );
639 | symbolsKeyboard.setShifted( false );
640 | }
641 | else if( currentKeyboard == symbolsAplKeyboard ) {
642 | symbolsAplKeyboard.setShifted( true );
643 | inputView.setKeyboard( symbolsAplShiftedKeyboard );
644 | symbolsAplShiftedKeyboard.setShifted( true );
645 | }
646 | else if( currentKeyboard == symbolsAplShiftedKeyboard ) {
647 | symbolsAplShiftedKeyboard.setShifted( false );
648 | inputView.setKeyboard( symbolsAplKeyboard );
649 | symbolsKeyboard.setShifted( false );
650 | }
651 | }
652 |
653 | private void handleCharacter( int primaryCode, int[] keyCodes ) {
654 | if( isInputViewShown() ) {
655 | if( inputView.isShifted() ) {
656 | primaryCode = Character.toUpperCase( primaryCode );
657 | }
658 | }
659 | if( isAlphabet( primaryCode ) && predictionOn ) {
660 | composing.append( (char)primaryCode );
661 | getCurrentInputConnection().setComposingText( composing, 1 );
662 | updateShiftKeyState( getCurrentInputEditorInfo() );
663 | updateCandidates();
664 | }
665 | else {
666 | getCurrentInputConnection().commitText(
667 | String.valueOf( (char)primaryCode ), 1 );
668 | }
669 | }
670 |
671 | private void handleClose() {
672 | commitTyped( getCurrentInputConnection() );
673 | requestHideSelf( 0 );
674 | inputView.closing();
675 | }
676 |
677 | private void checkToggleCapsLock() {
678 | long now = System.currentTimeMillis();
679 | if( lastShiftTime + 800 > now ) {
680 | capsLock = !capsLock;
681 | lastShiftTime = 0;
682 | }
683 | else {
684 | lastShiftTime = now;
685 | }
686 | }
687 |
688 | private String getWordSeparators() {
689 | return wordSeparators;
690 | }
691 |
692 | public boolean isWordSeparator( int code ) {
693 | String separators = getWordSeparators();
694 | return separators.contains( String.valueOf( (char)code ) );
695 | }
696 |
697 | public void pickDefaultCandidate() {
698 | pickSuggestionManually( 0 );
699 | }
700 |
701 | public void pickSuggestionManually( int index ) {
702 | if( completionOn && completions != null && index >= 0
703 | && index < completions.length ) {
704 | CompletionInfo ci = completions[index];
705 | getCurrentInputConnection().commitCompletion( ci );
706 | if( candidateView != null ) {
707 | candidateView.clear();
708 | }
709 | updateShiftKeyState( getCurrentInputEditorInfo() );
710 | }
711 | else if( composing.length() > 0 ) {
712 | // If we were generating candidate suggestions for the current
713 | // text, we would commit one of them here. But for this sample,
714 | // we will just commit the current text.
715 | commitTyped( getCurrentInputConnection() );
716 | }
717 | }
718 |
719 | public void swipeRight() {
720 | if( completionOn ) {
721 | pickDefaultCandidate();
722 | }
723 | }
724 |
725 | public void swipeLeft() {
726 | handleBackspace();
727 | }
728 |
729 | public void swipeDown() {
730 | handleClose();
731 | }
732 |
733 | public void swipeUp() {
734 | }
735 |
736 | public void onPress( int primaryCode ) {
737 | }
738 |
739 | public void onRelease( int primaryCode ) {
740 | }
741 | }
742 |
--------------------------------------------------------------------------------
/gnu-apl-api/gnu-apl-api.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/gnu-apl-api/src/org/gnu/apl/AplException.java:
--------------------------------------------------------------------------------
1 | package org.gnu.apl;
2 |
3 | @SuppressWarnings("UnusedDeclaration")
4 | public class AplException extends Exception
5 | {
6 | public AplException() {
7 | super();
8 | }
9 |
10 | public AplException( String detailMessage ) {
11 | super( detailMessage );
12 | }
13 |
14 | public AplException( String detailMessage, Throwable throwable ) {
15 | super( detailMessage, throwable );
16 | }
17 |
18 | public AplException( Throwable throwable ) {
19 | super( throwable );
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/gnu-apl-api/src/org/gnu/apl/AplExecException.java:
--------------------------------------------------------------------------------
1 | package org.gnu.apl;
2 |
3 | @SuppressWarnings("UnusedDeclaration")
4 | public class AplExecException extends AplException
5 | {
6 | private String line1;
7 | private String line2;
8 | private String line3;
9 |
10 | public AplExecException( String line1, String line2, String line3 ) {
11 | super( line1 + "\n" + line2 + "\n" + line3 );
12 |
13 | this.line1 = line1;
14 | this.line2 = line2;
15 | this.line3 = line3;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/gnu-apl-api/src/org/gnu/apl/AplValue.java:
--------------------------------------------------------------------------------
1 | package org.gnu.apl;
2 |
3 | /**
4 | * Wrapper for the APL Value_P object.
5 | */
6 | public final class AplValue
7 | {
8 | private long ptr;
9 |
10 | protected AplValue( long ptr ) {
11 | this.ptr = ptr;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/gnu-apl-api/src/org/gnu/apl/Native.java:
--------------------------------------------------------------------------------
1 | package org.gnu.apl;
2 |
3 | import java.io.Writer;
4 |
5 | public class Native
6 | {
7 | static {
8 | System.loadLibrary( "apl" );
9 | }
10 |
11 | public static native int init( String files );
12 |
13 | public static native AplValue evalExpression( String expr ) throws AplException;
14 |
15 | public static native void evalWithIo( String s, Writer cin, Writer cout, Writer cerr, Writer uerr ) throws AplException;
16 | }
17 |
--------------------------------------------------------------------------------
/gnu-apl-api/src/org/gnu/apl/Test.java:
--------------------------------------------------------------------------------
1 | package org.gnu.apl;
2 |
3 | import java.io.StringWriter;
4 |
5 | public class Test
6 | {
7 | public static void main( String[] args ) {
8 | try {
9 | Native.init( "foo" );
10 |
11 | StringWriter cin = new StringWriter();
12 | StringWriter cout = new StringWriter();
13 | StringWriter cerr = new StringWriter();
14 | StringWriter uerr = new StringWriter();
15 | Native.evalWithIo( "⎕←'foo' ◊ ⎕←'blopp' ◊ palle", cin, cout, cerr, uerr );
16 | System.out.printf( "cin='%s'%n", cin.toString() );
17 | System.out.printf( "cout='%s'%n", cout.toString() );
18 | System.out.printf( "cerr='%s'%n", cerr.toString() );
19 | System.out.printf( "uerr='%s'%n", uerr.toString() );
20 | } catch( AplException e ) {
21 | e.printStackTrace();
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/lib/guava-17.0.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lokedhs/android-gnu-apl/2385d564b5c6de2106cb995fdfac35d00db22e21/lib/guava-17.0.jar
--------------------------------------------------------------------------------
/notes.txt:
--------------------------------------------------------------------------------
1 | Set environment variables from cross-build:
2 |
3 | export PATH=$HOME/src/android-toolchain/bin:$PATH
4 | export CC=arm-linux-androideabi-gcc
5 | export CXX=arm-linux-androideabi-g++
6 |
7 | Configure GNU APL:
8 |
9 | CXXFLAGS='-g -fPIC' ./configure --host=x86_64-linux --build=arm --prefix=$HOME/prog/android-gnu-apl/client/assets/dist
10 |
11 | CXXFLAGS='-g -fPIC' ./configure --host=x86_64-linux --build=arm --with-android
12 | make
13 |
14 | (setenv "PATH" (concat (expand-file-name "~/src/android-toolchain/bin") ":" (getenv "PATH")))
15 |
16 | Keyboard layout experiments:
17 |
18 | ◊⍨ ¨ ¯≢ ≤ ≥ ≠ ∨ ⍱∧ ⍲× ≡ ÷⌹
19 |
20 | ⍳ ⍸ ⍵ ⌽ ∊ ⍷ ∼ ⍉ ↑ ↓ ○ ⍥ ⋆ ⍟ ← → ⍬ ⍝ ⍀ ⍴
21 |
22 | ⍺ ⊖ ⌈ ⌊ _ ⍫ ∇ ⍒ ∆ ⍋ ∘ ⍤ ' ⌺ ⎕ ⍞ ⊢ ⊣
23 |
24 | ⊂ ⊃ ∩ ∪ ⊥ ⍎ ⊤ ⍕ | ⌶ ⌷ ⍪ ⍙ ⌿
25 |
26 | <>
27 |
--------------------------------------------------------------------------------