├── app
├── src
│ └── main
│ │ ├── res
│ │ ├── mipmap-xhdpi
│ │ │ └── ic_launcher.png
│ │ ├── mipmap-xxhdpi
│ │ │ └── ic_launcher.png
│ │ ├── mipmap-xxxhdpi
│ │ │ └── ic_launcher.png
│ │ ├── values
│ │ │ ├── styles.xml
│ │ │ └── strings.xml
│ │ ├── xml
│ │ │ └── accessibility_service.xml
│ │ └── layout
│ │ │ ├── ExplorerActivity.xml
│ │ │ └── ExploreItem.xml
│ │ ├── assets
│ │ └── modules
│ │ │ ├── executor.lua
│ │ │ └── notes.lua
│ │ ├── AndroidManifest.xml
│ │ └── java
│ │ └── com
│ │ └── dm
│ │ └── inline
│ │ ├── utils.java
│ │ ├── activities
│ │ ├── ExplorerAdapter.java
│ │ └── ExplorerActivity.java
│ │ ├── tools
│ │ └── ArgumentTokenizer.java
│ │ └── InlineService.java
├── build.gradle
└── proguard-rules.pro
├── .gitignore
└── LICENSE
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dmitrijkotov634/Inline/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dmitrijkotov634/Inline/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dmitrijkotov634/Inline/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/assets/modules/executor.lua:
--------------------------------------------------------------------------------
1 | function exec(context, arg)
2 | return load(arg)()
3 | end
4 |
5 | function eval(context, arg)
6 | return load("return " .. arg)()
7 | end
8 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Inline
3 | Explorer
4 | ...
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/accessibility_service.xml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/ExplorerActivity.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | defaultConfig {
5 | applicationId "com.dm.inline"
6 | minSdkVersion 22
7 | targetSdkVersion 28
8 | versionCode 4
9 | versionName "0.6.1"
10 | }
11 |
12 | buildTypes {
13 | release {
14 | minifyEnabled true
15 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
16 | }
17 | }
18 | }
19 |
20 | dependencies {
21 | implementation 'org.luaj:luaj-jse:3.0.1'
22 | implementation fileTree(dir: 'libs', include: ['*.jar'])
23 | }
24 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/ExploreItem.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
13 |
14 |
20 |
21 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/app/src/main/assets/modules/notes.lua:
--------------------------------------------------------------------------------
1 | local prefs = inline.prefs("notes")
2 | local list = prefs:getstringset("notes", {})
3 |
4 | local function find(t, e)
5 | for n, v in pairs(t) do
6 | if v == e then
7 | return n
8 | end
9 | end
10 | end
11 |
12 | function save(context, name)
13 | prefs[name] = context:gettext():gsub("%{save .*%}%$", "")
14 | if not find(list, name) then
15 | list[#list + 1] = name
16 | prefs.notes = list
17 | end
18 | return ""
19 | end
20 |
21 | function delnote(context, name)
22 | local index = find(list, name)
23 | if index then
24 | prefs[name] = nil
25 | list[index] = nil
26 | prefs.notes = list
27 | end
28 | return ""
29 | end
30 |
31 | function note(context, name)
32 | if find(list, name) then
33 | return prefs[name]
34 | else
35 | return ""
36 | end
37 | end
38 |
39 | function notes(context)
40 | local result = "Notes:"
41 | for k, v in ipairs(list) do
42 | result = result .. ("– %s\n"):format(v)
43 | end
44 | return result
45 | end
46 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
9 |
12 |
13 |
16 |
17 |
18 |
19 |
20 |
21 |
24 |
25 |
26 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Built application files
2 | *.apk
3 | *.aar
4 | *.ap_
5 | *.aab
6 |
7 | # Files for the ART/Dalvik VM
8 | *.dex
9 |
10 | # Java class files
11 | *.class
12 |
13 | # Generated files
14 | bin/
15 | gen/
16 | out/
17 | # Uncomment the following line in case you need and you don't have the release build type files in your app
18 | # release/
19 |
20 | # Gradle files
21 | .gradle/
22 | build/
23 |
24 | # Local configuration file (sdk path, etc)
25 | local.properties
26 |
27 | # Proguard folder generated by Eclipse
28 | proguard/
29 |
30 | # Log Files
31 | *.log
32 |
33 | # Android Studio Navigation editor temp files
34 | .navigation/
35 |
36 | # Android Studio captures folder
37 | captures/
38 |
39 | # IntelliJ
40 | *.iml
41 | .idea/workspace.xml
42 | .idea/tasks.xml
43 | .idea/gradle.xml
44 | .idea/assetWizardSettings.xml
45 | .idea/dictionaries
46 | .idea/libraries
47 | # Android Studio 3 in .gitignore file.
48 | .idea/caches
49 | .idea/modules.xml
50 | # Comment next line if keeping position of elements in Navigation Editor is relevant for you
51 | .idea/navEditor.xml
52 |
53 | # Keystore files
54 | # Uncomment the following lines if you do not want to check your keystore files in.
55 | #*.jks
56 | #*.keystore
57 |
58 | # External native build folder generated in Android Studio 2.2 and later
59 | .externalNativeBuild
60 | .cxx/
61 |
62 | # Google Services (e.g. APIs or Firebase)
63 | # google-services.json
64 |
65 | # Freeline
66 | freeline.py
67 | freeline/
68 | freeline_project_description.json
69 |
70 | # fastlane
71 | fastlane/report.xml
72 | fastlane/Preview.html
73 | fastlane/screenshots
74 | fastlane/test_output
75 | fastlane/readme.md
76 |
77 | # Version control
78 | vcs.xml
79 |
80 | # lint
81 | lint/intermediates/
82 | lint/generated/
83 | lint/outputs/
84 | lint/tmp/
85 | # lint/reports/
86 |
--------------------------------------------------------------------------------
/app/src/main/java/com/dm/inline/utils.java:
--------------------------------------------------------------------------------
1 | package com.dm.inline;
2 |
3 | import org.luaj.vm2.lib.TwoArgFunction;
4 | import org.luaj.vm2.lib.ThreeArgFunction;
5 | import org.luaj.vm2.LuaValue;
6 | import org.luaj.vm2.LuaTable;
7 | import java.util.List;
8 | import com.dm.inline.tools.ArgumentTokenizer;
9 | import org.luaj.vm2.lib.OneArgFunction;
10 |
11 | public class utils extends TwoArgFunction {
12 |
13 | public utils() {}
14 |
15 | public LuaValue call(LuaValue name, LuaValue env) {
16 | LuaValue library = tableOf();
17 | library.set("getargs", new getArgs());
18 | library.set("split", new split());
19 | library.set("lenght", new lenght());
20 |
21 | env.set("utils", library);
22 | return library;
23 | }
24 |
25 | public class getArgs extends TwoArgFunction {
26 | public LuaValue call(LuaValue string, LuaValue maxSplit) {
27 | LuaTable value = new LuaTable();
28 | int index = 1;
29 | for (String arg : ArgumentTokenizer.tokenize(string.tojstring(), maxSplit.isint() ? maxSplit.toint() : -1, false)) {
30 | value.set(index++, arg);
31 | }
32 | return value;
33 | }
34 | }
35 |
36 | public class split extends ThreeArgFunction {
37 | public LuaValue call(LuaValue string, LuaValue pattern, LuaValue maxCount) {
38 | LuaTable value = new LuaTable();
39 | int index = 1;
40 | for (String sub : string.tojstring().split(pattern.isnil() ? " " : pattern.tojstring(),
41 | maxCount.isint() ? maxCount.toint() : -1)) {
42 | value.set(index++, sub);
43 | }
44 | return value;
45 | }
46 | }
47 |
48 | public class lenght extends OneArgFunction {
49 | public LuaValue call(LuaValue string) {
50 | return valueOf(string.checkjstring().length());
51 | }
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/app/src/main/java/com/dm/inline/activities/ExplorerAdapter.java:
--------------------------------------------------------------------------------
1 | package com.dm.inline.activities;
2 |
3 | import android.content.Context;
4 | import android.view.LayoutInflater;
5 | import android.view.View;
6 | import android.view.ViewGroup;
7 | import android.widget.BaseAdapter;
8 | import android.widget.TextView;
9 | import com.dm.inline.R;
10 | import java.util.ArrayList;
11 | import org.luaj.vm2.LuaValue;
12 | import org.luaj.vm2.Varargs;
13 |
14 | public class ExplorerAdapter extends BaseAdapter {
15 | private Context context;
16 | private ArrayList data;
17 |
18 | public TextView key;
19 | public TextView string;
20 |
21 | public ExplorerAdapter(Context context, ArrayList data) {
22 | this.context = context;
23 | this.data = data;
24 | }
25 |
26 | @Override
27 | public int getCount() {
28 | return data.size();
29 | }
30 |
31 | @Override
32 | public Varargs getItem(int position) {
33 | return data.get(position);
34 | }
35 |
36 | @Override
37 | public long getItemId(int position) {
38 | return position;
39 | }
40 |
41 | @Override
42 | public View getView(int position, View convertView, ViewGroup parent) {
43 | convertView = LayoutInflater.from(context).inflate(R.layout.ExploreItem, parent, false);
44 |
45 | key = convertView.findViewById(R.id.key);
46 | string = convertView.findViewById(R.id.string);
47 |
48 | switch (data.get(position).arg(2).type()) {
49 | case LuaValue.TSTRING:
50 | convertView.setBackgroundColor(0xFFEAABAB);
51 | key.setTextColor(0xFFC00000);
52 | break;
53 | case LuaValue.TNUMBER:
54 | convertView.setBackgroundColor(0xFFB2E7AB);
55 | key.setTextColor(0xFF15B500);
56 | break;
57 | case LuaValue.TFUNCTION:
58 | convertView.setBackgroundColor(0xFFABABD5);
59 | key.setTextColor(0xFF000081);
60 | break;
61 | case LuaValue.TTABLE:
62 | convertView.setBackgroundColor(0xFFEAE2AB);
63 | key.setTextColor(0xFFBFA600);
64 | break;
65 | case LuaValue.TBOOLEAN:
66 | convertView.setBackgroundColor(0xFFCFABEA);
67 | key.setTextColor(0xFF6F00BF);
68 | break;
69 | case LuaValue.TNIL:
70 | convertView.setBackgroundColor(0xFFCDCDCD);
71 | key.setTextColor(0xFF676767);
72 | break;
73 | default:
74 | convertView.setBackgroundColor(0xFFABE5D6);
75 | key.setTextColor(0xFF00AF82);
76 | }
77 |
78 | key.setText(data.get(position).arg1().tojstring());
79 | string.setText(data.get(position).arg(2).tojstring());
80 | return convertView;
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/app/src/main/java/com/dm/inline/activities/ExplorerActivity.java:
--------------------------------------------------------------------------------
1 | package com.dm.inline.activities;
2 |
3 | import android.app.Activity;
4 | import android.os.Bundle;
5 | import android.view.View;
6 | import android.widget.AdapterView;
7 | import android.widget.ListView;
8 | import com.dm.inline.InlineService;
9 | import com.dm.inline.R;
10 | import java.util.ArrayList;
11 | import org.luaj.vm2.LuaValue;
12 | import org.luaj.vm2.Varargs;
13 |
14 | public class ExplorerActivity extends Activity {
15 |
16 | public InlineService service;
17 | public ListView explorer;
18 | public ExplorerAdapter adapter;
19 |
20 | public int lastPos = 0;
21 |
22 | public ArrayList path = new ArrayList();
23 | public void onCreate(Bundle savedInstanceState) {
24 | super.onCreate(savedInstanceState);
25 |
26 | setContentView(R.layout.ExplorerActivity);
27 |
28 | explorer = findViewById(R.id.explorer);
29 | service = InlineService.getSharedInstance();
30 |
31 | explorer.setOnItemClickListener(new AdapterView.OnItemClickListener() {
32 | @Override
33 | public void onItemClick(AdapterView> parent, View view, int position, long id) {
34 | Varargs item = adapter.getItem(position);
35 |
36 | if (item.arg(2).istable()) {
37 | path.add(item.arg1());
38 |
39 | lastPos = position;
40 | show(find(service.env, path));
41 | updateTitle(path);
42 | }
43 | }
44 | });
45 |
46 | if (service != null)
47 | show(service.env);
48 | }
49 |
50 | public void onBackPressed() {
51 | if (path.isEmpty()) {
52 | super.onBackPressed();
53 | } else {
54 | path.remove(path.size() - 1);
55 | show(find(service.env, path));
56 | updateTitle(path);
57 |
58 | explorer.setSelection(lastPos);
59 | }
60 | }
61 |
62 | public LuaValue find(LuaValue value, ArrayList path) {
63 | for (LuaValue item : path) {
64 | if (value.istable())
65 | value = value.get(item);
66 | }
67 | return value;
68 | }
69 |
70 | public void updateTitle(ArrayList path) {
71 | StringBuilder title = new StringBuilder();
72 | title.append("/");
73 | for (LuaValue item : path) {
74 | title.append(item.tojstring());
75 | title.append("/");
76 | }
77 |
78 | getWindow().setTitle(title);
79 | }
80 |
81 | public void show(LuaValue value) {
82 | ArrayList data = new ArrayList();
83 | LuaValue k = LuaValue.NIL;
84 | while (true) {
85 | Varargs n = value.next(k);
86 | if ((k = n.arg1()).isnil())
87 | break;
88 |
89 | data.add(n);
90 | }
91 |
92 | adapter = new ExplorerAdapter(this, data);
93 | explorer.setAdapter(adapter);
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/app/src/main/java/com/dm/inline/tools/ArgumentTokenizer.java:
--------------------------------------------------------------------------------
1 | package com.dm.inline.tools;
2 |
3 | import java.util.LinkedList;
4 | import java.util.List;
5 |
6 | public abstract class ArgumentTokenizer {
7 | private static final int NO_TOKEN_STATE = 0;
8 | private static final int NORMAL_TOKEN_STATE = 1;
9 | private static final int SINGLE_QUOTE_STATE = 2;
10 | private static final int DOUBLE_QUOTE_STATE = 3;
11 |
12 | public static List tokenize(String arguments, int maxSplit, boolean stringify) {
13 | LinkedList argList = new LinkedList();
14 | StringBuilder currArg = new StringBuilder();
15 | boolean escaped = false;
16 | int state = NO_TOKEN_STATE;
17 |
18 | for (int i = 0; i < arguments.length(); i++) {
19 | char c = arguments.charAt(i);
20 | if (escaped) {
21 | escaped = false;
22 | currArg.append(c);
23 | } else {
24 | if (maxSplit > 0 && argList.size() < maxSplit) {
25 | currArg.append(arguments.substring(i));
26 | state = NORMAL_TOKEN_STATE;
27 | break;
28 | } else {
29 | switch (state) {
30 | case SINGLE_QUOTE_STATE:
31 | if (c == '\'') {
32 | state = NORMAL_TOKEN_STATE;
33 | } else {
34 | currArg.append(c);
35 | }
36 | break;
37 | case DOUBLE_QUOTE_STATE:
38 | if (c == '"') {
39 | state = NORMAL_TOKEN_STATE;
40 | } else if (c == '\\') {
41 | i++;
42 | char next = arguments.charAt(i);
43 | if (next == '"' || next == '\\') {
44 | currArg.append(next);
45 | } else {
46 | currArg.append(c);
47 | currArg.append(next);
48 | }
49 | } else {
50 | currArg.append(c);
51 | }
52 | break;
53 | case NO_TOKEN_STATE:
54 | case NORMAL_TOKEN_STATE:
55 | switch (c) {
56 | case '\\':
57 | escaped = true;
58 | state = NORMAL_TOKEN_STATE;
59 | break;
60 | case '\'':
61 | state = SINGLE_QUOTE_STATE;
62 | break;
63 | case '"':
64 | state = DOUBLE_QUOTE_STATE;
65 | break;
66 | default:
67 | if (!Character.isWhitespace(c)) {
68 | currArg.append(c);
69 | state = NORMAL_TOKEN_STATE;
70 | } else if (state == NORMAL_TOKEN_STATE) {
71 | argList.add(currArg.toString());
72 | currArg = new StringBuilder();
73 | state = NO_TOKEN_STATE;
74 | }
75 | }
76 | break;
77 | default:
78 | throw new IllegalStateException("ArgumentTokenizer state " + state + " is invalid!");
79 | }
80 | }
81 | }
82 | }
83 |
84 | if (escaped) {
85 | currArg.append('\\');
86 | argList.add(currArg.toString());
87 | } else if (state != NO_TOKEN_STATE) {
88 | argList.add(currArg.toString());
89 | }
90 |
91 | if (stringify) {
92 | for (int i = 0; i < argList.size(); i++) {
93 | argList.set(i, "\"" + _escapeQuotesAndBackslashes(argList.get(i)) + "\"");
94 | }
95 | }
96 | return argList;
97 | }
98 |
99 | protected static String _escapeQuotesAndBackslashes(String s) {
100 | final StringBuilder buf = new StringBuilder(s);
101 |
102 | for (int i = s.length() - 1; i >= 0; i--) {
103 | char c = s.charAt(i);
104 | if ((c == '\\') || (c == '"')) {
105 | buf.insert(i, '\\');
106 | } else if (c == '\n') {
107 | buf.deleteCharAt(i);
108 | buf.insert(i, "\\n");
109 | } else if (c == '\t') {
110 | buf.deleteCharAt(i);
111 | buf.insert(i, "\\t");
112 | } else if (c == '\r') {
113 | buf.deleteCharAt(i);
114 | buf.insert(i, "\\r");
115 | } else if (c == '\b') {
116 | buf.deleteCharAt(i);
117 | buf.insert(i, "\\b");
118 | } else if (c == '\f') {
119 | buf.deleteCharAt(i);
120 | buf.insert(i, "\\f");
121 | }
122 | }
123 | return buf.toString();
124 | }
125 | }
126 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/app/src/main/java/com/dm/inline/InlineService.java:
--------------------------------------------------------------------------------
1 | package com.dm.inline;
2 |
3 | import android.accessibilityservice.AccessibilityService;
4 | import android.accessibilityservice.AccessibilityServiceInfo;
5 | import android.content.ClipData;
6 | import android.content.ClipboardManager;
7 | import android.content.Intent;
8 | import android.content.SharedPreferences;
9 | import android.content.res.AssetManager;
10 | import android.os.Build;
11 | import android.os.Bundle;
12 | import android.os.Handler;
13 | import android.os.Looper;
14 | import android.view.Gravity;
15 | import android.view.accessibility.AccessibilityEvent;
16 | import android.view.accessibility.AccessibilityNodeInfo;
17 | import android.widget.Toast;
18 | import java.io.BufferedReader;
19 | import java.io.File;
20 | import java.io.FileReader;
21 | import java.io.IOException;
22 | import java.io.InputStream;
23 | import java.util.HashMap;
24 | import java.util.HashSet;
25 | import java.util.Set;
26 | import java.util.Timer;
27 | import java.util.TimerTask;
28 | import java.util.regex.Matcher;
29 | import java.util.regex.Pattern;
30 | import org.luaj.vm2.Globals;
31 | import org.luaj.vm2.LuaTable;
32 | import org.luaj.vm2.LuaValue;
33 | import org.luaj.vm2.Varargs;
34 | import org.luaj.vm2.lib.OneArgFunction;
35 | import org.luaj.vm2.lib.ThreeArgFunction;
36 | import org.luaj.vm2.lib.TwoArgFunction;
37 | import org.luaj.vm2.lib.VarArgFunction;
38 | import org.luaj.vm2.lib.ZeroArgFunction;
39 | import org.luaj.vm2.lib.jse.JsePlatform;
40 | import java.util.ArrayList;
41 | import android.transition.PathMotion;
42 |
43 | public class InlineService extends AccessibilityService {
44 | static final String PATH = "/assets/modules/;/sdcard/inline/;/sdcard/.inline/";
45 |
46 | private static InlineService sharedInstance;
47 |
48 | public ClipboardManager clipboard;
49 | public Bundle arg;
50 |
51 | public Globals env;
52 | public SharedPreferences prefs;
53 |
54 | public HashMap watchers = new HashMap();
55 |
56 | @Override
57 | protected void onServiceConnected() {
58 | super.onServiceConnected();
59 |
60 | AccessibilityServiceInfo info = new AccessibilityServiceInfo();
61 |
62 | info.flags = AccessibilityServiceInfo.DEFAULT |
63 | AccessibilityServiceInfo.FLAG_RETRIEVE_INTERACTIVE_WINDOWS;
64 |
65 | info.eventTypes = AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED;
66 | info.feedbackType = AccessibilityServiceInfo.FEEDBACK_ALL_MASK;
67 | setServiceInfo(info);
68 |
69 | sharedInstance = this;
70 |
71 | clipboard = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
72 | prefs = getSharedPreferences("inline", MODE_PRIVATE);
73 |
74 | env = JsePlatform.standardGlobals();
75 |
76 | LuaValue loader = new loadModules();
77 |
78 | LuaTable inline = new LuaTable();
79 | inline.set("toast", new toast());
80 | inline.set("timer", new InlineTimer());
81 | inline.set("context", new InlineContext());
82 | inline.set("prefs", new InlinePrefs(prefs));
83 | inline.set("loadmodules", loader);
84 |
85 | LuaTable watchers = new LuaTable();
86 | watchers.set(LuaValue.INDEX, new getWatcher());
87 | watchers.set(LuaValue.NEWINDEX, new setWatcher());
88 | watchers.set(LuaValue.LEN, new lenWatcher());
89 |
90 | inline.set("watchers", new LuaTable().setmetatable(watchers));
91 |
92 | LuaTable clipboard = new LuaTable();
93 | clipboard.set("sethtml", new setHtml());
94 | clipboard.set("set", new setClip());
95 | clipboard.set("get", new getClip());
96 | clipboard.set("has", new hasClip());
97 | clipboard.set("clear", new clearClip());
98 |
99 | inline.set("clipboard", clipboard);
100 |
101 | LuaTable fmt = new LuaTable();
102 | fmt.set("fromhtml", new fromHtml());
103 | fmt.set("fromclipboard", new FromClipboardFlag());
104 |
105 | inline.set("fmt", fmt);
106 |
107 | env.set("inline", inline);
108 | env.set("cake", LuaValue.FALSE);
109 |
110 | loader.call();
111 | }
112 |
113 | public void onAccessibilityEvent(AccessibilityEvent event) {
114 | AccessibilityNodeInfo node = event.getSource();
115 |
116 | InlineContext context = new InlineContext(node);
117 | for (LuaValue watcher : watchers.values()) {
118 | try {
119 | watcher.call(context);
120 | } catch (Exception e) {
121 | logError(e);
122 | }
123 | }
124 |
125 | if (Build.VERSION.SDK_INT >= 26 ? !node.isShowingHintText() : true) {
126 |
127 | String text = node.getText() == null ? "" : node.getText().toString();
128 | Matcher m = Pattern.compile("\\{.+\\}\\$", Pattern.DOTALL).matcher(text);
129 |
130 | expressions:
131 | while (m.find()) {
132 | String[] args = m.group(0).substring(1, m.group(0).length() - 2).split(" ", 2);
133 |
134 | if (args.length > 0) {
135 | LuaValue value = env;
136 |
137 | for (String path : args[0].split("\\.")) {
138 | if ((value = value.get(path)).isnil())
139 | break;
140 | }
141 |
142 | try {
143 | find:
144 | while (true) {
145 | switch (value.type()) {
146 | case LuaValue.TFUNCTION:
147 | value = args.length == 1 ? value.call(context) : value.call(context, LuaValue.valueOf(args[1]));
148 | break;
149 |
150 | case LuaValue.TNUMBER:
151 | case LuaValue.TSTRING:
152 | case LuaValue.TBOOLEAN:
153 | text = text.replace(m.group(0), value.tojstring());
154 | break find;
155 |
156 | case 10:
157 | arg = new Bundle();
158 | arg.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT, m.start());
159 | arg.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT, m.end());
160 | node.performAction(AccessibilityNodeInfo.ACTION_SET_SELECTION, arg);
161 | node.performAction(AccessibilityNodeInfo.ACTION_PASTE);
162 |
163 | default:
164 | continue expressions;
165 | }
166 | }
167 |
168 | arg = new Bundle();
169 | arg.putCharSequence(AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE, text);
170 | node.performAction(AccessibilityNodeInfo.ACTION_SET_TEXT, arg);
171 |
172 | arg = new Bundle();
173 | arg.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT, node.getTextSelectionStart());
174 | arg.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT, node.getTextSelectionEnd());
175 | node.performAction(AccessibilityNodeInfo.ACTION_SET_SELECTION, arg);
176 |
177 | } catch (Exception e) {
178 | logError(e);
179 | }
180 | }
181 | }
182 | }
183 | }
184 |
185 | public void onInterrupt() {}
186 |
187 | public boolean onUnbind(Intent intent) {
188 | sharedInstance = null;
189 | return super.onUnbind(intent);
190 | }
191 |
192 | public static InlineService getSharedInstance() {
193 | return sharedInstance;
194 | }
195 |
196 | public void logError(Exception e) {
197 | Toast toast = Toast.makeText(this, e.toString(), 1);
198 | toast.setGravity(Gravity.CENTER, 0, 0);
199 | toast.show();
200 |
201 | e.printStackTrace();
202 | }
203 |
204 | public class InlineContext extends LuaTable {
205 | public AccessibilityNodeInfo node;
206 |
207 | public InlineContext(AccessibilityNodeInfo node) {
208 | this();
209 | this.node = node;
210 | }
211 |
212 | public InlineContext() {
213 | set("settext", new setText());
214 | set("gettext", new getText());
215 | set("setselection", new setSelection());
216 | set("getselection", new getSelection());
217 | set("cut", new cut());
218 | set("copy", new copy());
219 | set("paste", new paste());
220 | set("isfocused", new isFocused());
221 | set("ismultiline", new isMultiLine());
222 | set("isshowinghinttext", new isShowingHintText());
223 | set("refresh", new refresh());
224 | set("getpackage", new getPackage());
225 | }
226 |
227 | public class setText extends TwoArgFunction {
228 | public LuaValue call(LuaValue self, LuaValue text) {
229 | Bundle args = new Bundle();
230 | args.putCharSequence(AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE, text.isnil() ? "" : text.checkjstring());
231 | ((InlineContext)self).node.performAction(AccessibilityNodeInfo.ACTION_SET_TEXT, args);
232 |
233 | return NIL;
234 | }
235 | }
236 |
237 | public class getText extends OneArgFunction {
238 | public LuaValue call(LuaValue self) {
239 | CharSequence text = ((InlineContext)self).node.getText();
240 | return valueOf(text == null ? "" : text.toString());
241 | }
242 | }
243 |
244 | public class setSelection extends ThreeArgFunction {
245 | public LuaValue call(LuaValue self, LuaValue start, LuaValue end) {
246 | Bundle args = new Bundle();
247 | args.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT, start.checkint() - 1);
248 | args.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT, end.isnil() ? start.checkint() - 1 : end.checkint() - 1);
249 | ((InlineContext)self).node.performAction(AccessibilityNodeInfo.ACTION_SET_SELECTION, args);
250 | return NIL;
251 | }
252 | }
253 |
254 | public class getSelection extends VarArgFunction {
255 | public Varargs invoke(Varargs v) {
256 | return varargsOf(valueOf(((InlineContext)v.arg1()).node.getTextSelectionStart() + 1),
257 | valueOf(((InlineContext)v.arg1()).node.getTextSelectionEnd() + 1));
258 | }
259 | }
260 |
261 | public class cut extends OneArgFunction {
262 | public LuaValue call(LuaValue self) {
263 | ((InlineContext)self).node.performAction(AccessibilityNodeInfo.ACTION_CUT);
264 | return NIL;
265 | }
266 | }
267 |
268 | public class copy extends OneArgFunction {
269 | public LuaValue call(LuaValue self) {
270 | ((InlineContext)self).node.performAction(AccessibilityNodeInfo.ACTION_COPY);
271 | return NIL;
272 | }
273 | }
274 |
275 | public class paste extends OneArgFunction {
276 | public LuaValue call(LuaValue self) {
277 | ((InlineContext)self).node.performAction(AccessibilityNodeInfo.ACTION_PASTE);
278 | return NIL;
279 | }
280 | }
281 |
282 | public class isMultiLine extends OneArgFunction {
283 | public LuaValue call(LuaValue self) {
284 | return valueOf(((InlineContext)self).node.isMultiLine());
285 | }
286 | }
287 |
288 | public class isShowingHintText extends OneArgFunction {
289 | public LuaValue call(LuaValue self) {
290 | return valueOf(Build.VERSION.SDK_INT >= 26 ? ((InlineContext)self).node.isShowingHintText() : false);
291 | }
292 | }
293 |
294 | public class isFocused extends OneArgFunction {
295 | public LuaValue call(LuaValue self) {
296 | return valueOf(((InlineContext)self).node.isFocused());
297 | }
298 | }
299 |
300 | public class refresh extends OneArgFunction {
301 | public LuaValue call(LuaValue self) {
302 | ((InlineContext)self).node.refresh();
303 | return NIL;
304 | }
305 | }
306 |
307 | public class getPackage extends OneArgFunction {
308 | public LuaValue call(LuaValue self) {
309 | return valueOf(((InlineContext)self).node.getPackageName().toString());
310 | }
311 | }
312 | }
313 |
314 | public class InlinePrefs extends LuaTable {
315 | public SharedPreferences prefs;
316 |
317 | public InlinePrefs(String name) {
318 | this();
319 | this.prefs = getSharedPreferences(name, MODE_PRIVATE);
320 | }
321 |
322 | public InlinePrefs(SharedPreferences sprefs) {
323 | this();
324 | this.prefs = sprefs;
325 | }
326 |
327 | public InlinePrefs() {
328 | set("getstring", new getString());
329 | set("getstringset", new getStringSet());
330 | set("getint", new getInt());
331 | set("getfloat", new getFloat());
332 | set("getlong", new getLong());
333 | set("getboolean", new getBoolean());
334 | set("contains", new contains());
335 |
336 | LuaTable m = new LuaTable();
337 | m.set(CALL, new call());
338 | m.set(INDEX, new getStringDefault());
339 | m.set(NEWINDEX, new putKey());
340 |
341 | this.setmetatable(m);
342 | }
343 |
344 | public class call extends TwoArgFunction {
345 | public LuaValue call(LuaValue self, LuaValue name) {
346 | return (LuaValue) new InlinePrefs(name.checkjstring());
347 | }
348 | }
349 |
350 | public class getStringDefault extends TwoArgFunction {
351 | public LuaValue call(LuaValue self, LuaValue key) {
352 | return valueOf(((InlinePrefs)self).prefs.getString(key.checkjstring(), ""));
353 | }
354 | }
355 |
356 | public class getString extends ThreeArgFunction {
357 | public LuaValue call(LuaValue self, LuaValue key, LuaValue defaultVal) {
358 | return valueOf(((InlinePrefs)self).prefs.getString(key.checkjstring(), defaultVal.isnil() ? "" : defaultVal.checkjstring()));
359 | }
360 | }
361 |
362 | public class getStringSet extends ThreeArgFunction {
363 | public LuaValue call(LuaValue self, LuaValue key, LuaValue defaultVal) {
364 | HashSet items = new HashSet();
365 |
366 | if (!defaultVal.isnil() && defaultVal.checktable() != null) {
367 | LuaValue k = NIL;
368 | while (true) {
369 | Varargs n = defaultVal.next(k);
370 | if ((k = n.arg1()).isnil() || !k.isint())
371 | break;
372 | LuaValue v = n.arg(2);
373 |
374 | items.add(v.tojstring());
375 | }
376 | }
377 |
378 | LuaTable table = new LuaTable();
379 | Set set = ((InlinePrefs)self).prefs.getStringSet(key.checkjstring(), items);
380 |
381 | int index = 1;
382 | for (String item : set) {
383 | table.set(index++, valueOf(item));
384 | }
385 |
386 | return table;
387 | }
388 | }
389 |
390 | public class getInt extends ThreeArgFunction {
391 | public LuaValue call(LuaValue self, LuaValue key, LuaValue defaultVal) {
392 | return valueOf(((InlinePrefs)self).prefs.getInt(key.checkjstring(), defaultVal.isnil() ? 0 : defaultVal.checknumber().toint()));
393 | }
394 | }
395 |
396 | public class getFloat extends ThreeArgFunction {
397 | public LuaValue call(LuaValue self, LuaValue key, LuaValue defaultVal) {
398 | return valueOf(((InlinePrefs)self).prefs.getFloat(key.checkjstring(), defaultVal.isnil() ? 0 : defaultVal.checknumber().tofloat()));
399 | }
400 | }
401 |
402 | public class getLong extends ThreeArgFunction {
403 | public LuaValue call(LuaValue self, LuaValue key, LuaValue defaultVal) {
404 | return valueOf(((InlinePrefs)self).prefs.getLong(key.checkjstring(), defaultVal.isnil() ? 0 : defaultVal.checknumber().tolong()));
405 | }
406 | }
407 |
408 | public class getBoolean extends ThreeArgFunction {
409 | public LuaValue call(LuaValue self, LuaValue key, LuaValue defaultVal) {
410 | return valueOf(((InlinePrefs)self).prefs.getBoolean(key.checkjstring(), defaultVal.toboolean()));
411 | }
412 | }
413 |
414 | public class contains extends TwoArgFunction {
415 | public LuaValue call(LuaValue self, LuaValue key) {
416 | return valueOf(((InlinePrefs)self).prefs.contains(key.checkjstring()));
417 | }
418 | }
419 |
420 | public class putKey extends ThreeArgFunction {
421 | public LuaValue call(LuaValue self, LuaValue key, LuaValue value) {
422 | String k = key.checkjstring();
423 |
424 | SharedPreferences.Editor editor = ((InlinePrefs)self).prefs.edit();
425 |
426 | switch (value.type()) {
427 | case TNIL:
428 | editor.remove(k).apply();
429 | break;
430 |
431 | case TNUMBER:
432 | if (value.isint())
433 | editor.putInt(k, value.toint());
434 | else if (value.islong())
435 | editor.putLong(k, value.tolong());
436 | else
437 | editor.putFloat(k, value.tofloat());
438 | break;
439 | case TBOOLEAN:
440 | editor.putBoolean(k, value.toboolean());
441 | break;
442 | case TTABLE:
443 | HashSet items = new HashSet();
444 |
445 | LuaValue q = NIL;
446 | while (true) {
447 | Varargs n = value.next(q);
448 | if ((q = n.arg1()).isnil() || !q.isint())
449 | break;
450 | LuaValue v = n.arg(2);
451 | items.add(v.tojstring());
452 | }
453 |
454 | editor.putStringSet(k, items);
455 | break;
456 |
457 | case TSTRING:
458 | default:
459 | editor.putString(k, value.tojstring());
460 | }
461 |
462 | editor.apply();
463 | return NIL;
464 | }
465 | }
466 | }
467 |
468 | public class InlineTimer extends LuaTable {
469 | public Timer timer;
470 |
471 | public InlineTimer() {
472 | this.timer = new Timer();
473 |
474 | set("schedule", new schedule());
475 | set("cancel", new cancel());
476 |
477 | LuaTable m = new LuaTable();
478 | m.set(CALL, new call());
479 | this.setmetatable(m);
480 | }
481 |
482 | public class call extends ZeroArgFunction {
483 | public LuaValue call() {
484 | return (LuaValue) new InlineTimer();
485 | }
486 | }
487 |
488 | public class cancel extends OneArgFunction {
489 | public LuaValue call(LuaValue self) {
490 | ((InlineTimer)self).timer.cancel();
491 | return NIL;
492 | }
493 | }
494 |
495 | public class schedule extends VarArgFunction {
496 | public Varargs invoke(final Varargs v) {
497 | TimerTask task = new TimerTask() {
498 | public void run() {
499 | new Handler(Looper.getMainLooper()).post(new Runnable() {
500 | @Override
501 | public void run() {
502 | if (v.arg(2).call().toboolean())
503 | cancel();
504 | }});
505 | }
506 | };
507 |
508 | if (v.arg(4).isnil())
509 | ((InlineTimer)v.arg1()).timer.schedule(task, v.arg(3).checkint());
510 | else
511 | ((InlineTimer)v.arg1()).timer.scheduleAtFixedRate(task, v.arg(3).checkint(), v.arg(4).checkint());
512 |
513 | return NIL;
514 | }
515 | }
516 | }
517 |
518 | public class toast extends OneArgFunction {
519 | public LuaValue call(LuaValue text) {
520 | Toast.makeText(getApplicationContext(), text.tojstring(), 1).show();
521 | return NIL;
522 | }
523 | }
524 |
525 | public class loadModules extends ZeroArgFunction {
526 | private AssetManager assets;
527 |
528 | public void loadFile(String path, File file) throws IOException {
529 | BufferedReader reader = new BufferedReader(new FileReader(file));
530 |
531 | reader.mark(1);
532 | int ch = reader.read();
533 | if (ch != 65279)
534 | reader.reset();
535 |
536 | prepare(path, env.load(reader, path).call());
537 |
538 | }
539 |
540 | public void loadAsset(String path) throws IOException {
541 | InputStream stream = assets.open(path);
542 | byte[] buffer = new byte[stream.available()];
543 | stream.read(buffer);
544 |
545 | prepare(path, env.load(new String(buffer), path).call());
546 | }
547 |
548 | public void prepare(String path, LuaValue value) {
549 | if (value.isfunction())
550 | watchers.put(valueOf(path), value);
551 | }
552 |
553 | public LuaValue call() {
554 | watchers.clear();
555 |
556 | try {
557 | for (String path : prefs.getString("path", PATH).split(";"))
558 | if (path.startsWith("/assets/")) {
559 | assets = getResources().getAssets();
560 |
561 | String assetPath = path.substring(8);
562 | String[] files = assets.list(assetPath.substring(0, assetPath.length() - 1));
563 |
564 | if (files.length > 0)
565 | for (String file : files)
566 | loadAsset(assetPath + file);
567 | else
568 | loadAsset(assetPath);
569 | } else {
570 | File module = new File(path);
571 |
572 | if (module.isDirectory()) {
573 | for (File file : module.listFiles())
574 | if (file.isFile())
575 | loadFile(path + file.getName(), file);
576 | } else if (module.isFile()) {
577 | loadFile(path, module);
578 | }
579 | }
580 | } catch (Exception e) {
581 | logError(e);
582 | }
583 |
584 | return TRUE;
585 | }
586 | }
587 |
588 |
589 | public class getWatcher extends TwoArgFunction {
590 | public LuaValue call(LuaValue table, LuaValue name) {
591 | return watchers.containsKey(name) ? watchers.get(name) : NIL;
592 | }
593 | }
594 |
595 | public class lenWatcher extends ZeroArgFunction {
596 | public LuaValue call() {
597 | return valueOf(watchers.size());
598 | }
599 | }
600 |
601 | public class setWatcher extends ThreeArgFunction {
602 | public LuaValue call(LuaValue table, LuaValue name, LuaValue function) {
603 | if (function.isnil()) {
604 | if (watchers.containsKey(name))
605 | watchers.remove(name);
606 | } else {
607 | watchers.put(name, function);
608 | }
609 |
610 | return NIL;
611 | }
612 | }
613 |
614 |
615 | public class setHtml extends TwoArgFunction {
616 | public LuaValue call(LuaValue text, LuaValue html) {
617 | clipboard.setPrimaryClip(ClipData.newHtmlText(null, text.checkjstring(), html.checkjstring()));
618 | return NIL;
619 | }
620 | }
621 |
622 | public class setClip extends OneArgFunction {
623 | public LuaValue call(LuaValue text) {
624 | clipboard.setPrimaryClip(ClipData.newPlainText(null, text.checkjstring()));
625 | return NIL;
626 | }
627 | }
628 |
629 | public class getClip extends ZeroArgFunction {
630 | public LuaValue call() {
631 | ClipData clip = clipboard.getPrimaryClip();
632 | return valueOf(clip.getItemAt(0).coerceToHtmlText(getApplicationContext()));
633 | }
634 | }
635 |
636 | public class hasClip extends ZeroArgFunction {
637 | public LuaValue call() {
638 | return valueOf(clipboard.hasPrimaryClip());
639 | }
640 | }
641 |
642 | public class clearClip extends ZeroArgFunction {
643 | public LuaValue call() {
644 | clipboard.clearPrimaryClip();
645 | return NIL;
646 | }
647 | }
648 |
649 | public class fromHtml extends OneArgFunction {
650 | public LuaValue call(LuaValue html) {
651 | clipboard.setPrimaryClip(ClipData.newHtmlText(null, "", html.checkjstring()));
652 | return new FromClipboardFlag();
653 | }
654 | }
655 |
656 | public class FromClipboardFlag extends LuaValue {
657 | public int type() {
658 | return 10;
659 | }
660 |
661 | public String typename() {
662 | return "formatflag";
663 | }
664 | }
665 | }
666 |
667 |
--------------------------------------------------------------------------------