summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.classpath9
-rw-r--r--.gitignore6
-rw-r--r--.project33
-rw-r--r--AndroidManifest.xml40
-rwxr-xr-xgesturesbin0 -> 77922 bytes
-rw-r--r--libs/android-support-v4.jarbin0 -> 627582 bytes
-rw-r--r--proguard-project.txt20
-rw-r--r--project.properties14
-rw-r--r--res/drawable-hdpi/ic_launcher.pngbin0 -> 4615 bytes
-rw-r--r--res/drawable-mdpi/ic_launcher.pngbin0 -> 1994 bytes
-rw-r--r--res/drawable-xhdpi/ic_launcher.pngbin0 -> 3538 bytes
-rw-r--r--res/icons/keyboard.pngbin0 -> 1977 bytes
-rw-r--r--res/icons/keyboard/drawable-hdpi/ic_launcher.pngbin0 -> 4615 bytes
-rw-r--r--res/icons/keyboard/drawable-mdpi/ic_launcher.pngbin0 -> 1994 bytes
-rw-r--r--res/icons/keyboard/drawable-xhdpi/ic_launcher.pngbin0 -> 3912 bytes
-rw-r--r--res/icons/minak.svg373
-rw-r--r--res/icons/minak/drawable-hdpi/ic_launcher.pngbin0 -> 6727 bytes
-rw-r--r--res/icons/minak/drawable-mdpi/ic_launcher.pngbin0 -> 4052 bytes
-rw-r--r--res/icons/minak/drawable-xhdpi/ic_launcher.pngbin0 -> 15365 bytes
-rw-r--r--res/layout/create_gesture.xml88
-rw-r--r--res/layout/dialog_rename.xml41
-rw-r--r--res/layout/gestures_item.xml31
-rw-r--r--res/layout/gestures_list.xml75
-rw-r--r--res/layout/ime.xml21
-rw-r--r--res/raw/gesturesbin0 -> 93080 bytes
-rw-r--r--res/values-v11/styles.xml11
-rw-r--r--res/values-v14/styles.xml12
-rw-r--r--res/values/colors.xml4
-rw-r--r--res/values/dimens.xml5
-rw-r--r--res/values/strings.xml51
-rw-r--r--res/values/styles.xml20
-rw-r--r--res/xml/method.xml3
-rw-r--r--src/us/minak/CreateGestureActivity.java128
-rw-r--r--src/us/minak/DrawingSpaceView.java60
-rw-r--r--src/us/minak/IMEService.java38
-rw-r--r--src/us/minak/IMEView.java34
-rw-r--r--src/us/minak/Minak.java38
-rw-r--r--src/us/minak/MinakView.java37
-rw-r--r--src/us/minak/NavigationDrawerFragment.java282
-rw-r--r--src/us/minak/OnCharacterEnteredListener.java5
-rw-r--r--src/us/minak/OnGestureRecognizedListener.java23
-rw-r--r--src/us/minak/SettingsActivity.java436
-rw-r--r--src/us/minak/SketchpadView.java42
43 files changed, 1575 insertions, 405 deletions
diff --git a/.classpath b/.classpath
new file mode 100644
index 0000000..5176974
--- /dev/null
+++ b/.classpath
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
+ <classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
+ <classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.DEPENDENCIES"/>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="src" path="gen"/>
+ <classpathentry kind="output" path="bin/classes"/>
+</classpath>
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..f708b53
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,6 @@
+/.settings
+/bin
+/gen
+
+*~
+.nfs*
diff --git a/.project b/.project
new file mode 100644
index 0000000..ef25403
--- /dev/null
+++ b/.project
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>Minak</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>com.android.ide.eclipse.adt.PreCompilerBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>com.android.ide.eclipse.adt.ApkBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>com.android.ide.eclipse.adt.AndroidNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
new file mode 100644
index 0000000..07457fd
--- /dev/null
+++ b/AndroidManifest.xml
@@ -0,0 +1,40 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="us.minak"
+ android:versionCode="1"
+ android:versionName="1.0" >
+
+ <uses-sdk
+ android:minSdkVersion="8"
+ android:targetSdkVersion="19" />
+
+ <application
+ android:allowBackup="true"
+ android:icon="@drawable/ic_launcher"
+ android:label="@string/app_name"
+ android:theme="@style/AppTheme" >
+
+ <!-- The main input service -->
+ <service android:name="IMEService"
+ android:label="@string/minak_ime_label"
+ android:permission="android.permission.BIND_INPUT_METHOD">
+ <intent-filter>
+ <action android:name="android.view.InputMethod" />
+ </intent-filter>
+ <meta-data android:name="android.view.im" android:resource="@xml/method" />
+ </service>
+
+ <!-- The settings menu activity -->
+ <activity android:name=".SettingsActivity" android:label="@string/minak_settings_label">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ </intent-filter>
+ </activity>
+
+ <!-- The individual gesture editor -->
+ <activity
+ android:name="CreateGestureActivity"
+ android:label="@string/label_create_gesture" />
+
+ </application>
+
+</manifest>
diff --git a/gestures b/gestures
new file mode 100755
index 0000000..097ba09
--- /dev/null
+++ b/gestures
Binary files differ
diff --git a/libs/android-support-v4.jar b/libs/android-support-v4.jar
new file mode 100644
index 0000000..a7e9919
--- /dev/null
+++ b/libs/android-support-v4.jar
Binary files differ
diff --git a/proguard-project.txt b/proguard-project.txt
new file mode 100644
index 0000000..f2fe155
--- /dev/null
+++ b/proguard-project.txt
@@ -0,0 +1,20 @@
+# To enable ProGuard in your project, edit project.properties
+# to define the proguard.config property as described in that file.
+#
+# Add project specific ProGuard rules here.
+# By default, the flags in this file are appended to flags specified
+# in ${sdk.dir}/tools/proguard/proguard-android.txt
+# You can edit the include path and order by changing the ProGuard
+# include property in project.properties.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# Add any project specific keep options here:
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
diff --git a/project.properties b/project.properties
new file mode 100644
index 0000000..4ab1256
--- /dev/null
+++ b/project.properties
@@ -0,0 +1,14 @@
+# This file is automatically generated by Android Tools.
+# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
+#
+# This file must be checked in Version Control Systems.
+#
+# To customize properties used by the Ant build system edit
+# "ant.properties", and override values to adapt the script to your
+# project structure.
+#
+# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
+#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
+
+# Project target.
+target=android-19
diff --git a/res/drawable-hdpi/ic_launcher.png b/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..2494b61
--- /dev/null
+++ b/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_launcher.png b/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..deb71bc
--- /dev/null
+++ b/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_launcher.png b/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..50e38d7
--- /dev/null
+++ b/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/res/icons/keyboard.png b/res/icons/keyboard.png
new file mode 100644
index 0000000..e2c3c74
--- /dev/null
+++ b/res/icons/keyboard.png
Binary files differ
diff --git a/res/icons/keyboard/drawable-hdpi/ic_launcher.png b/res/icons/keyboard/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..2494b61
--- /dev/null
+++ b/res/icons/keyboard/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/res/icons/keyboard/drawable-mdpi/ic_launcher.png b/res/icons/keyboard/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..deb71bc
--- /dev/null
+++ b/res/icons/keyboard/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/res/icons/keyboard/drawable-xhdpi/ic_launcher.png b/res/icons/keyboard/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..8944a37
--- /dev/null
+++ b/res/icons/keyboard/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/res/icons/minak.svg b/res/icons/minak.svg
new file mode 100644
index 0000000..bb9b9fc
--- /dev/null
+++ b/res/icons/minak.svg
@@ -0,0 +1,373 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Gnu Emacs Icon
+
+ Copyright (C) 2008, 2009
+ Free Software Foundation, Inc.
+
+ This file is part of GNU Emacs.
+
+ GNU Emacs is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ GNU Emacs is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
+
+-->
+
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ version="1.0"
+ width="48"
+ height="48"
+ viewBox="0.171 0.201 512 512"
+ id="svg4768"
+ xml:space="preserve"
+ inkscape:version="0.48.3.1 r9886"
+ sodipodi:docname="emacs.svg"><metadata
+ id="metadata4071"><rdf:RDF><cc:Work
+ rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="1364"
+ inkscape:window-height="743"
+ id="namedview4069"
+ showgrid="false"
+ inkscape:snap-center="true"
+ inkscape:zoom="9.8333333"
+ inkscape:cx="20.750371"
+ inkscape:cy="18.870747"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="svg4768" />
+<defs
+ id="defs4770"><linearGradient
+ id="linearGradient3294"><stop
+ id="stop3296"
+ style="stop-color:#6376e6;stop-opacity:1"
+ offset="0" /><stop
+ id="stop3302"
+ style="stop-color:#222989;stop-opacity:1"
+ offset="0.50094414" /><stop
+ id="stop3298"
+ style="stop-color:#00003d;stop-opacity:1"
+ offset="1" /></linearGradient><linearGradient
+ id="linearGradient3284"><stop
+ id="stop3286"
+ style="stop-color:#000000;stop-opacity:1"
+ offset="0" /><stop
+ id="stop3292"
+ style="stop-color:#000000;stop-opacity:0.49803922"
+ offset="0.84845906" /><stop
+ id="stop3288"
+ style="stop-color:#000000;stop-opacity:0"
+ offset="1" /></linearGradient><linearGradient
+ id="linearGradient3274"><stop
+ id="stop3276"
+ style="stop-color:#000000;stop-opacity:1"
+ offset="0" /><stop
+ id="stop3278"
+ style="stop-color:#000000;stop-opacity:0"
+ offset="1" /></linearGradient><linearGradient
+ id="linearGradient3262"><stop
+ id="stop3264"
+ style="stop-color:#000000;stop-opacity:1"
+ offset="0" /><stop
+ id="stop3266"
+ style="stop-color:#000000;stop-opacity:0"
+ offset="1" /></linearGradient><linearGradient
+ id="linearGradient3242"><stop
+ id="stop3244"
+ style="stop-color:#282828;stop-opacity:1"
+ offset="0" /><stop
+ id="stop3252"
+ style="stop-color:#808080;stop-opacity:1"
+ offset="0.39253417" /><stop
+ id="stop3246"
+ style="stop-color:#d9d9d9;stop-opacity:1"
+ offset="1" /></linearGradient><linearGradient
+ id="linearGradient3202"><stop
+ id="stop3204"
+ style="stop-color:#2b2b2b;stop-opacity:1"
+ offset="0" /><stop
+ id="stop3250"
+ style="stop-color:#828383;stop-opacity:1"
+ offset="0.5" /><stop
+ id="stop3206"
+ style="stop-color:#dadbdb;stop-opacity:1"
+ offset="1" /></linearGradient><linearGradient
+ id="linearGradient4966"><stop
+ id="stop4968"
+ style="stop-color:#b6b3d8;stop-opacity:1"
+ offset="0" /><stop
+ id="stop4970"
+ style="stop-color:#b6b3d8;stop-opacity:0"
+ offset="1" /></linearGradient><linearGradient
+ id="linearGradient4938"><stop
+ id="stop4940"
+ style="stop-color:#000000;stop-opacity:1"
+ offset="0" /><stop
+ id="stop4942"
+ style="stop-color:#000000;stop-opacity:0"
+ offset="1" /></linearGradient><linearGradient
+ id="linearGradient4898"><stop
+ id="stop4900"
+ style="stop-color:#bab8db;stop-opacity:1"
+ offset="0" /><stop
+ id="stop4902"
+ style="stop-color:#5955a9;stop-opacity:0.99159664"
+ offset="1" /></linearGradient><linearGradient
+ id="linearGradient4876"><stop
+ id="stop4878"
+ style="stop-color:#d3d2e8;stop-opacity:1"
+ offset="0" /><stop
+ id="stop4880"
+ style="stop-color:#5955a9;stop-opacity:0.99159664"
+ offset="1" /></linearGradient>
+<radialGradient
+ cx="20.951529"
+ cy="-108.96888"
+ r="266.76535"
+ fx="20.951529"
+ fy="-108.96888"
+ id="radialGradient4892"
+ xlink:href="#linearGradient4898"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0,0.60368634,0.49558719,0,206.05482,226.70225)" /><radialGradient
+ cx="233.8876"
+ cy="471.26172"
+ r="170.49393"
+ fx="233.8876"
+ fy="471.26172"
+ id="radialGradient4944"
+ xlink:href="#linearGradient4938"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1,0,0,0.1854103,0,383.88493)" /><radialGradient
+ cx="299.70135"
+ cy="371.76376"
+ r="76.696358"
+ fx="299.70135"
+ fy="371.76376"
+ id="radialGradient4972"
+ xlink:href="#linearGradient4966"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1,0,0,0.9121621,0,32.654948)" /><radialGradient
+ cx="289.44067"
+ cy="390.45248"
+ r="17.67668"
+ fx="289.44067"
+ fy="390.45248"
+ id="radialGradient3210"
+ xlink:href="#linearGradient3202"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.414705,0.3300575,-0.5059004,0.6356454,346.95314,49.479585)" /><radialGradient
+ cx="283.50717"
+ cy="382.14804"
+ r="17.67668"
+ fx="283.50717"
+ fy="382.14804"
+ id="radialGradient3238"
+ xlink:href="#linearGradient3202"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.414705,0.3300575,-0.5059004,0.6356454,448.41009,-65.398074)" /><radialGradient
+ cx="418.45551"
+ cy="181.18982"
+ r="63.068935"
+ fx="418.45551"
+ fy="181.18982"
+ id="radialGradient3248"
+ xlink:href="#linearGradient3242"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(-6.5565014e-2,-5.9721765e-2,1.6871024,-1.8521705,171.90774,540.51473)" /><radialGradient
+ cx="354.51709"
+ cy="357.33591"
+ r="33.712105"
+ fx="354.51709"
+ fy="357.33591"
+ id="radialGradient3268"
+ xlink:href="#linearGradient3262"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.4055116,-3.3440123e-2,0.1034174,4.3988695,177.23251,-1191.6649)" /><radialGradient
+ cx="510.58469"
+ cy="223.55537"
+ r="132.28336"
+ fx="510.58469"
+ fy="223.55537"
+ id="radialGradient3280"
+ xlink:href="#linearGradient3274"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(-0.1339874,-0.1146812,0.3079048,-0.3597394,444.23592,395.03849)" /><radialGradient
+ cx="284.4671"
+ cy="-158.17821"
+ r="110.2972"
+ fx="284.4671"
+ fy="-158.17821"
+ id="radialGradient3290"
+ xlink:href="#linearGradient3284"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(-1.2497569,1.3798305,-9.6289463e-2,-7.2974479e-2,674.3826,-70.590682)" /><radialGradient
+ cx="425.51019"
+ cy="356.62274"
+ r="143.34167"
+ fx="425.51019"
+ fy="356.62274"
+ id="radialGradient3300"
+ xlink:href="#linearGradient3294"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(-0.1008165,-8.0872321e-2,1.0745309,-1.3395252,13.843287,784.79288)" /></defs>
+<path
+ d="M 404.38153,471.26172 C 404.40061,488.72268 328.06229,502.87946 233.8876,502.87946 C 139.71291,502.87946 63.374595,488.72268 63.393677,471.26172 C 63.374595,453.80076 139.71291,439.64398 233.8876,439.64398 C 328.06229,439.64398 404.40061,453.80076 404.38153,471.26172 z"
+ id="path4912"
+ style="opacity:1;fill:url(#radialGradient4944);fill-opacity:1;stroke:#7b0000;stroke-width:0;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ transform="matrix(1.3434649,0,0,1.3934426,-81.886873,-193.70595)" /><path
+ d="m 237.03909,475.57196 c 131.79436,0 238.6348,-105.76 238.6348,-236.22155 0,-130.46155 -106.84044,-236.221545 -238.6348,-236.221545 -131.79437,0 -238.634815,105.759995 -238.634815,236.221545 0,130.46155 106.840445,236.22155 238.634815,236.22155 z"
+ id="path4864"
+ style="fill:url(#radialGradient4892);fill-opacity:1;stroke:#7b0000;stroke-width:0;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ inkscape:connector-curvature="0" /><path
+ d="M 376.39771,371.76376 C 376.40956,410.40897 342.06796,441.74284 299.70135,441.74284 C 257.33475,441.74284 222.99315,410.40897 223.005,371.76376 C 222.99315,333.11855 257.33475,301.78468 299.70135,301.78468 C 342.06796,301.78468 376.40956,333.11855 376.39771,371.76376 L 376.39771,371.76376 z"
+ id="path4946"
+ style="opacity:1;fill:url(#radialGradient4972);fill-opacity:1;stroke:#7b0000;stroke-width:0;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ transform="matrix(1.4594595,0,0,1,-195.74111,-13.473684)" /><path
+ d="m 406.99025,128.24724 c 0,0 6.09989,21.0078 9.58704,48.97166 1.41221,11.32467 6.34818,54.41295 6.21863,87.44939 0,0 0.0457,40.23552 -3.10931,62.44534 -3.30118,23.23898 -7.51418,36.40486 -15.92171,43.7321 -2.00464,0.19087 -8.53911,3.53663 -14.84064,-5.49655 -16.11056,-23.09426 -20.52041,-52.94998 -34.29248,-110.9411 -16.1227,-64.127 -31.56149,-83.29128 -42.73463,-92.8653 -11.19791,-9.07685 -34.45383,1.70382 -45.86235,53.37652 -6.36659,26.16241 -7.5364,123.60277 -7.5364,123.60277 -22.19469,-27.95505 -61.93067,-80.43759 -70.38102,-91.16526 -7.41134,-9.40866 -18.78483,-24.57035 -28.94842,-26.20016 -9.89378,-2.19861 -14.65745,13.37492 -15.2071,21.61972 -1.83218,26.56661 1.28253,62.84376 7.69516,95.09012 3.22335,16.20882 2.74827,19.05466 2.74827,19.05466 1.09931,23.08548 -10.99307,41.04084 -36.46037,40.12475 -25.833755,-0.18322 -46.548625,-26.01233 -47.453465,-54.59896 -0.8521,-26.92018 3.84757,-93.25794 3.84757,-93.25794 15.93996,77.31798 20.00775,89.95772 29.314885,93.99081 5.49654,2.38183 10.96153,-3.9787 9.89378,-25.28408 -1.16245,-23.19489 -6.77907,-70.72213 -6.77907,-70.72213 -6.962295,-45.25483 -13.558145,-76.76832 4.39723,-90.50967 11.73047,-8.97739 26.01695,1.28253 34.44497,5.31332 31.33028,17.95537 52.82523,49.00385 67.97387,68.70674 5.69982,7.41341 18.32179,30.04774 18.32179,30.04774 -19.23789,-70.35569 -8.42803,-126.42038 10.2602,-161.964658 24.18477,-40.8576 64.9968,-33.86852 103.15172,30.963828 22.5358,38.29255 33.36184,57.35854 41.05921,120.05537 5.84342,36.6472 8.23437,42.10791 11.2847,41.82939 4.29458,-0.39214 5.92204,-43.37561 6.73685,-55.19029 2.07287,-30.05668 2.59109,-107.78947 2.59109,-108.17813 z"
+ id="path4839"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ inkscape:connector-curvature="0" /><rect
+ width="512"
+ height="512"
+ x="0.171"
+ y="0.20100001"
+ id="rect4772"
+ style="fill:none;display:none" />
+
+
+
+<g
+ id="g4788"
+ style="display:none">
+ <g
+ id="g4790"
+ style="display:inline">
+ </g>
+</g>
+
+
+<g
+ id="g4806"
+ style="display:none">
+ <g
+ id="g4808"
+ style="display:inline">
+ <path
+ d="M 349.098,256.651 C 348.833,256.397 386.735,284.256 388.519,281.663 C 394.881,272.411 470.565,188.526 473.303,165.427 C 473.545,163.424 472.787,161.331 472.787,161.331 C 472.787,161.331 471.597,161.187 466.462,157.017 C 463.77,154.825 460.979,152.436 460.979,152.436 C 444.925,153.434 403.094,193.995 349.917,256.004"
+ id="path4810"
+ style="fill:#050505;display:none" />
+ </g>
+</g>
+
+
+
+<g
+ id="g4796"
+ style="stroke:none">
+
+ <g
+ id="g4800"
+ style="stroke:none">
+
+ </g>
+</g><g
+ id="g4820">
+
+ <path
+ d="M 279.476,404.243 C 279.469,404.239 272.03,400.131 262.672,392.842 L 262.672,392.842 C 254.59,386.557 249.134,380.628 249.128,380.622 L 249.128,380.622 L 249.006,380.489 L 252.652,375.82 L 252.809,375.615 L 252.978,375.812 C 252.995,375.822 258.378,382.107 266.703,388.592 L 266.703,388.592 C 274.616,394.749 283.297,399.178 283.315,399.187 L 283.315,399.187 L 283.544,399.304 L 279.633,404.33 L 279.476,404.243 L 279.476,404.243 z M 262.934,392.506 C 271.479,399.162 278.403,403.15 279.523,403.781 L 279.523,403.781 L 282.895,399.447 C 281.472,398.704 273.642,394.528 266.442,388.926 L 266.442,388.926 C 258.938,383.081 253.805,377.393 252.828,376.281 L 252.828,376.281 L 249.564,380.465 C 250.413,381.37 255.574,386.785 262.934,392.506 L 262.934,392.506 z"
+ id="path4824"
+ style="fill:#4d4d4d" />
+</g><g
+ id="g4774">
+
+</g><rect
+ width="378.89471"
+ height="389.88782"
+ x="129.8893"
+ y="112.05299"
+ id="rect3282"
+ style="opacity:1;fill:url(#radialGradient3290);fill-opacity:1;stroke:#4a4a4a;stroke-width:0;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /><path
+ d="M 279.41935,402.42925 C 279.41935,402.42925 332.64609,345.32574 384.74548,282.44569 L 387.0212,283.14836 C 387.0212,283.14836 495.06978,164.73541 468.64063,155.14837 C 468.64063,155.14837 455.42606,128.97833 351.78234,254.90545 L 351.58303,256.79518 C 303.76315,311.94378 250.62994,379.18477 250.62994,379.18477 C 209.58912,438.18094 185.22113,481.78682 187.23653,486.00083 C 189.97605,491.72893 279.57838,403.0031 279.41935,402.42925 z"
+ id="path3254"
+ style="fill:url(#radialGradient3300);fill-opacity:1;fill-rule:evenodd;stroke:#000030;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /><path
+ d="M 248.88937,380.28407 C 260.52371,392.19325 279.48677,404.28563 279.48677,404.28563 L 283.24273,399.52196 C 270.37465,392.79686 252.46212,375.70363 252.46212,375.70363 L 248.88937,380.28407 z"
+ id="path2430"
+ style="fill:url(#radialGradient3210);fill-opacity:1;fill-rule:evenodd;stroke:#606060;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /><path
+ d="M 349.52184,256.42873 C 370.04225,269.52883 386.16543,285.37718 386.16543,285.37718 L 388.91369,282.17086 C 377.9694,270.59048 352.22755,253.07064 352.22755,253.07064 L 349.52184,256.42873 z"
+ id="path3236"
+ style="fill:url(#radialGradient3238);fill-opacity:1;fill-rule:evenodd;stroke:#606060;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /><path
+ d="M 462.24667,151.81129 C 473.05653,152.72737 474.88872,162.25471 474.88872,162.25471 C 425.60308,213.55574 353.41521,288.12545 353.41521,288.12545 L 349.75085,285.01074 C 413.32748,208.79208 462.24667,151.81129 462.24667,151.81129"
+ id="path3240"
+ style="fill:url(#radialGradient3248);fill-opacity:1;fill-rule:evenodd;stroke:#4a4a4a;stroke-width:0.60000002;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /><text
+ xml:space="preserve"
+ style="font-size:3.99999988px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:DejaVu Sans;-inkscape-font-specification:DejaVu Sans"
+ x="40.677967"
+ y="33.35593"
+ id="text4081"
+ sodipodi:linespacing="125%"
+ transform="matrix(10.666667,0,0,10.666667,0.171,0.201)"><tspan
+ sodipodi:role="line"
+ id="tspan4083"
+ x="40.677967"
+ y="33.35593" /></text>
+<text
+ xml:space="preserve"
+ style="font-size:8px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:DejaVu Sans;-inkscape-font-specification:DejaVu Sans"
+ x="39.864407"
+ y="32.745762"
+ id="text4085"
+ sodipodi:linespacing="125%"
+ transform="matrix(10.666667,0,0,10.666667,0.171,0.201)"><tspan
+ sodipodi:role="line"
+ id="tspan4087"></tspan></text>
+<text
+ xml:space="preserve"
+ style="font-size:4px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:DejaVu Serif;-inkscape-font-specification:DejaVu Serif"
+ x="39.864407"
+ y="31.728813"
+ id="text4089"
+ sodipodi:linespacing="125%"
+ transform="matrix(10.666667,0,0,10.666667,0.171,0.201)"><tspan
+ sodipodi:role="line"
+ id="tspan4091"></tspan></text>
+<text
+ xml:space="preserve"
+ style="font-size:32.45656586px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:DejaVu Serif;-inkscape-font-specification:DejaVu Serif"
+ x="388.10611"
+ y="390.5311"
+ id="text4093"
+ sodipodi:linespacing="125%"
+ transform="scale(1.0800087,0.92591848)"><tspan
+ sodipodi:role="line"
+ id="tspan4095"
+ x="388.10611"
+ y="390.5311">inak</tspan></text>
+</svg> \ No newline at end of file
diff --git a/res/icons/minak/drawable-hdpi/ic_launcher.png b/res/icons/minak/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..80f80a0
--- /dev/null
+++ b/res/icons/minak/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/res/icons/minak/drawable-mdpi/ic_launcher.png b/res/icons/minak/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..9fce689
--- /dev/null
+++ b/res/icons/minak/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/res/icons/minak/drawable-xhdpi/ic_launcher.png b/res/icons/minak/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..7a86237
--- /dev/null
+++ b/res/icons/minak/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/res/layout/create_gesture.xml b/res/layout/create_gesture.xml
new file mode 100644
index 0000000..89e64c6
--- /dev/null
+++ b/res/layout/create_gesture.xml
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+
+ android:orientation="vertical">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+
+ android:orientation="horizontal">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginRight="6dip"
+
+ android:text="@string/prompt_gesture_name"
+ android:textAppearance="?android:attr/textAppearanceMedium" />
+
+ <EditText
+ android:id="@+id/gesture_name"
+ android:layout_width="0dip"
+ android:layout_weight="1.0"
+ android:layout_height="wrap_content"
+
+ android:maxLength="40"
+ android:singleLine="true" />
+
+ </LinearLayout>
+
+ <android.gesture.GestureOverlayView
+ android:id="@+id/gestures_overlay"
+ android:layout_width="match_parent"
+ android:layout_height="0dip"
+ android:layout_weight="1.0"
+
+ android:gestureStrokeType="multiple" />
+
+ <LinearLayout
+ style="@android:style/ButtonBar"
+
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+
+ android:orientation="horizontal">
+
+ <Button
+ android:id="@+id/done"
+
+ android:layout_width="0dip"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+
+ android:enabled="false"
+
+ android:onClick="addGesture"
+ android:text="@string/button_done" />
+
+ <Button
+ android:layout_width="0dip"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+
+ android:onClick="cancelGesture"
+ android:text="@string/button_discard" />
+
+ </LinearLayout>
+
+</LinearLayout>
diff --git a/res/layout/dialog_rename.xml b/res/layout/dialog_rename.xml
new file mode 100644
index 0000000..49df806
--- /dev/null
+++ b/res/layout/dialog_rename.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:padding="20dip"
+ android:orientation="vertical">
+
+ <TextView
+ android:id="@+id/label"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:text="@string/gestures_rename_label"
+ android:gravity="left"
+ android:textAppearance="?android:attr/textAppearanceMedium" />
+
+ <EditText
+ android:id="@+id/name"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:scrollHorizontally="true"
+ android:autoText="false"
+ android:capitalize="none"
+ android:gravity="fill_horizontal"
+ android:textAppearance="?android:attr/textAppearanceMedium" />
+
+</LinearLayout>
diff --git a/res/layout/gestures_item.xml b/res/layout/gestures_item.xml
new file mode 100644
index 0000000..36c93b8
--- /dev/null
+++ b/res/layout/gestures_item.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@android:id/text1"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+
+ android:gravity="center_vertical"
+ android:minHeight="?android:attr/listPreferredItemHeight"
+
+ android:drawablePadding="12dip"
+ android:paddingLeft="6dip"
+ android:paddingRight="6dip"
+
+ android:ellipsize="marquee"
+ android:singleLine="true"
+ android:textAppearance="?android:attr/textAppearanceLarge" />
diff --git a/res/layout/gestures_list.xml b/res/layout/gestures_list.xml
new file mode 100644
index 0000000..d0b5e3d
--- /dev/null
+++ b/res/layout/gestures_list.xml
@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+
+ android:orientation="vertical">
+
+ <ListView
+ android:id="@android:id/list"
+
+ android:layout_width="match_parent"
+ android:layout_height="0dip"
+ android:layout_weight="1.0" />
+
+ <TextView
+ android:id="@android:id/empty"
+ android:layout_width="match_parent"
+ android:layout_height="0dip"
+ android:layout_weight="1.0"
+
+ android:gravity="center"
+
+ android:text="@string/gestures_loading"
+ android:textAppearance="?android:attr/textAppearanceMedium" />
+
+ <LinearLayout
+ style="@android:style/ButtonBar"
+
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+
+ android:orientation="horizontal">
+
+ <Button
+ android:id="@+id/addButton"
+ android:onClick="addGesture"
+
+ android:layout_width="0dip"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+
+ android:enabled="false"
+ android:text="@string/button_add" />
+
+ <Button
+ android:id="@+id/reloadButton"
+ android:onClick="reloadGestures"
+
+ android:layout_width="0dip"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+
+ android:enabled="false"
+ android:text="@string/button_reload" />
+
+ </LinearLayout>
+
+</LinearLayout>
+
diff --git a/res/layout/ime.xml b/res/layout/ime.xml
new file mode 100644
index 0000000..c5e78ef
--- /dev/null
+++ b/res/layout/ime.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<us.minak.IMEView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <us.minak.DrawingSpaceView
+ android:id="@+id/drawing_space"
+ android:layout_width="wrap_content"
+ android:layout_height="200dp"
+ android:layout_centerInParent="true"
+ android:fadeDuration="300"
+ android:fadeEnabled="true"
+ android:fadeOffset="200"
+ android:gestureColor="#000"
+ android:gestureStrokeAngleThreshold="0.0"
+ android:gestureStrokeLengthThreshold="0.0"
+ android:gestureStrokeSquarenessThreshold="0.0"
+ android:gestureStrokeType="multiple">
+ </us.minak.DrawingSpaceView>
+
+</us.minak.IMEView>
diff --git a/res/raw/gestures b/res/raw/gestures
new file mode 100644
index 0000000..3cc9d7c
--- /dev/null
+++ b/res/raw/gestures
Binary files differ
diff --git a/res/values-v11/styles.xml b/res/values-v11/styles.xml
new file mode 100644
index 0000000..3c02242
--- /dev/null
+++ b/res/values-v11/styles.xml
@@ -0,0 +1,11 @@
+<resources>
+
+ <!--
+ Base application theme for API 11+. This theme completely replaces
+ AppBaseTheme from res/values/styles.xml on API 11+ devices.
+ -->
+ <style name="AppBaseTheme" parent="android:Theme.Holo.Light">
+ <!-- API 11 theme customizations can go here. -->
+ </style>
+
+</resources>
diff --git a/res/values-v14/styles.xml b/res/values-v14/styles.xml
new file mode 100644
index 0000000..a91fd03
--- /dev/null
+++ b/res/values-v14/styles.xml
@@ -0,0 +1,12 @@
+<resources>
+
+ <!--
+ Base application theme for API 14+. This theme completely replaces
+ AppBaseTheme from BOTH res/values/styles.xml and
+ res/values-v11/styles.xml on API 14+ devices.
+ -->
+ <style name="AppBaseTheme" parent="android:Theme.Holo.Light.DarkActionBar">
+ <!-- API 14 theme customizations can go here. -->
+ </style>
+
+</resources>
diff --git a/res/values/colors.xml b/res/values/colors.xml
new file mode 100644
index 0000000..c180987
--- /dev/null
+++ b/res/values/colors.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <color name="gesture_color">#FFFFFF00</color>
+</resources>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
new file mode 100644
index 0000000..1a6cbca
--- /dev/null
+++ b/res/values/dimens.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <dimen name="gesture_thumbnail_inset">8dip</dimen>
+ <dimen name="gesture_thumbnail_size">64dip</dimen>
+</resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
new file mode 100644
index 0000000..e6474ea
--- /dev/null
+++ b/res/values/strings.xml
@@ -0,0 +1,51 @@
+<resources xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <string name="app_name">Minak</string>
+ <string name="minak_ime_label">Minak IME Label</string>
+ <string name="minak_settings_label">Minak Settings Label</string>
+
+ <string name="application_name">Gestures Builder</string>
+ <!-- Title, name of the activity used to create a gesture -->
+ <string name="label_create_gesture">Create a gesture</string>
+
+ <!-- Buttons -->
+ <!-- Label, button used to add a gesture -->
+ <string name="button_add">Add gesture</string>
+ <!-- Label, button used to reload all gestures -->
+ <string name="button_reload">Reload</string>
+ <!-- Label, button used to cancel the operation of adding a gesture -->
+ <string name="button_discard">Discard</string>
+ <!-- Label, button used to save a gesture newly created -->
+ <string name="button_done">Done</string>
+
+ <!-- Gestures -->
+ <!-- Label, prompt asking the user to enter the name of the gesture -->
+ <string name="prompt_gesture_name">Name</string>
+ <!-- Error message, informs the user he needs to enter a name before saving a gesture -->
+ <string name="error_missing_name">You must enter a name</string>
+ <!-- success message, tells the user where the gesture was saved -->
+ <string name="save_success">Gesture saved in %s</string>
+ <!-- Buttons in Rename gesture dialog box -->
+ <string name="rename_action">OK</string>
+ <!-- Buttons in Rename gesture dialog box -->
+ <string name="cancel_action">Cancel</string>
+ <!-- Message displayed when the user opens the gestures settings screen -->
+ <string name="gestures_loading">Loading gestures&#8230;</string>
+ <!-- Message displayed when the user has no gestures -->
+ <string name="gestures_empty">No gestures</string>
+ <!-- Title of the screen used to view/manage gestures -->
+ <string name="gestures_activity">Gestures</string>
+ <!-- Noun, menu item used to rename a gesture -->
+ <string name="gestures_rename">Rename</string>
+ <!-- Noun, menu item used to remove a gesture -->
+ <string name="gestures_delete">Delete</string>
+ <!-- Message displayed when a gesture is successfully deleted -->
+ <string name="gestures_delete_success">Gesture deleted</string>
+ <!-- Title of dialog box -->
+ <string name="gestures_rename_title">Rename gesture</string>
+ <!-- Label of gesture name field in Rename gesture dialog box -->
+ <string name="gestures_rename_label">Gesture name</string>
+ <!-- Message, displayed when the sdcard cannot be found, 1st parameter is the name of the file that stores the gestures. CHAR LIMIT=80 -->
+ <string name="gestures_error_loading">Could not load %s. Make sure you have storage available.</string>
+
+</resources>
diff --git a/res/values/styles.xml b/res/values/styles.xml
new file mode 100644
index 0000000..6ce89c7
--- /dev/null
+++ b/res/values/styles.xml
@@ -0,0 +1,20 @@
+<resources>
+
+ <!--
+ Base application theme, dependent on API level. This theme is replaced
+ by AppBaseTheme from res/values-vXX/styles.xml on newer devices.
+ -->
+ <style name="AppBaseTheme" parent="android:Theme.Light">
+ <!--
+ Theme customizations available in newer API levels can go in
+ res/values-vXX/styles.xml, while customizations related to
+ backward-compatibility can go here.
+ -->
+ </style>
+
+ <!-- Application theme. -->
+ <style name="AppTheme" parent="AppBaseTheme">
+ <!-- All customizations that are NOT specific to a particular API-level can go here. -->
+ </style>
+
+</resources>
diff --git a/res/xml/method.xml b/res/xml/method.xml
new file mode 100644
index 0000000..adf59b5
--- /dev/null
+++ b/res/xml/method.xml
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="utf-8"?>
+<input-method xmlns:android="http://schemas.android.com/apk/res/android"
+ android:settingsActivity="us.minak.SettingsActivity" />
diff --git a/src/us/minak/CreateGestureActivity.java b/src/us/minak/CreateGestureActivity.java
new file mode 100644
index 0000000..6844b36
--- /dev/null
+++ b/src/us/minak/CreateGestureActivity.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package us.minak;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.os.Environment;
+import android.view.View;
+import android.view.MotionEvent;
+import android.gesture.GestureOverlayView;
+import android.gesture.Gesture;
+import android.gesture.GestureLibrary;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import java.io.File;
+
+public class CreateGestureActivity extends Activity {
+ private static final float LENGTH_THRESHOLD = 120.0f;
+
+ private Gesture mGesture;
+ private View mDoneButton;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ setContentView(R.layout.create_gesture);
+
+ mDoneButton = findViewById(R.id.done);
+
+ GestureOverlayView overlay = (GestureOverlayView) findViewById(R.id.gestures_overlay);
+ overlay.addOnGestureListener(new GesturesProcessor());
+ }
+
+ @Override
+ protected void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+
+ if (mGesture != null) {
+ outState.putParcelable("gesture", mGesture);
+ }
+ }
+
+ @Override
+ protected void onRestoreInstanceState(Bundle savedInstanceState) {
+ super.onRestoreInstanceState(savedInstanceState);
+
+ mGesture = savedInstanceState.getParcelable("gesture");
+ if (mGesture != null) {
+ final GestureOverlayView overlay =
+ (GestureOverlayView) findViewById(R.id.gestures_overlay);
+ overlay.post(new Runnable() {
+ public void run() {
+ overlay.setGesture(mGesture);
+ }
+ });
+
+ mDoneButton.setEnabled(true);
+ }
+ }
+
+ public void addGesture(View v) {
+ if (mGesture != null) {
+ final TextView input = (TextView) findViewById(R.id.gesture_name);
+ final CharSequence name = input.getText();
+ if (name.length() == 0) {
+ input.setError(getString(R.string.error_missing_name));
+ return;
+ }
+
+ final GestureLibrary store = SettingsActivity.getStore();
+ store.addGesture(name.toString(), mGesture);
+ store.save();
+
+ setResult(RESULT_OK);
+
+ final String path = new File(Environment.getExternalStorageDirectory(),
+ "gestures").getAbsolutePath();
+ Toast.makeText(this, getString(R.string.save_success, path), Toast.LENGTH_LONG).show();
+ } else {
+ setResult(RESULT_CANCELED);
+ }
+
+ finish();
+
+ }
+
+ public void cancelGesture(View v) {
+ setResult(RESULT_CANCELED);
+ finish();
+ }
+
+ private class GesturesProcessor implements GestureOverlayView.OnGestureListener {
+ public void onGestureStarted(GestureOverlayView overlay, MotionEvent event) {
+ mDoneButton.setEnabled(false);
+ mGesture = null;
+ }
+
+ public void onGesture(GestureOverlayView overlay, MotionEvent event) {
+ }
+
+ public void onGestureEnded(GestureOverlayView overlay, MotionEvent event) {
+ mGesture = overlay.getGesture();
+ if (mGesture.getLength() < LENGTH_THRESHOLD) {
+ overlay.clear(false);
+ }
+ mDoneButton.setEnabled(true);
+ }
+
+ public void onGestureCancelled(GestureOverlayView overlay, MotionEvent event) {
+ }
+ }
+}
diff --git a/src/us/minak/DrawingSpaceView.java b/src/us/minak/DrawingSpaceView.java
new file mode 100644
index 0000000..7f9c3fa
--- /dev/null
+++ b/src/us/minak/DrawingSpaceView.java
@@ -0,0 +1,60 @@
+/*
+ ********************************************************************************
+ * Copyright (c) 2012 Samsung Electronics, Inc.
+ * All rights reserved.
+ *
+ * This software is a confidential and proprietary information of Samsung
+ * Electronics, Inc. ("Confidential Information"). You shall not disclose such
+ * Confidential Information and shall use it only in accordance with the terms
+ * of the license agreement you entered into with Samsung Electronics.
+ ********************************************************************************
+ */
+
+package us.minak;
+
+import java.util.List;
+
+import android.content.Context;
+import android.gesture.Gesture;
+import android.gesture.GestureLibraries;
+import android.gesture.GestureLibrary;
+import android.gesture.GestureOverlayView;
+import android.gesture.GestureOverlayView.OnGesturePerformedListener;
+import android.gesture.Prediction;
+import android.util.AttributeSet;
+
+/**
+ * Represent a space where drawing gestures are performed.
+ */
+public class DrawingSpaceView extends GestureOverlayView implements OnGesturePerformedListener {
+ private static final double SCORE_TRESHOLD = 3.0;
+ private final GestureLibrary mGestureLibrary;
+ private OnGestureRecognizedListener mOnGestureRecognizedListener;
+
+ public DrawingSpaceView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ mGestureLibrary = GestureLibraries.fromRawResource(context, R.raw.gestures);
+ mGestureLibrary.load();
+ addOnGesturePerformedListener(this);
+ }
+
+ public void setOnGestureRecognizedListener(OnGestureRecognizedListener onGestureRecognizedListener) {
+ mOnGestureRecognizedListener = onGestureRecognizedListener;
+ }
+
+ @Override
+ public void onGesturePerformed(GestureOverlayView overlay, Gesture gesture) {
+ final List<Prediction> predictions = mGestureLibrary.recognize(gesture);
+ Prediction bestPrediction = null;
+ if (!predictions.isEmpty()) {
+ bestPrediction = predictions.get(0);
+ }
+ if (mOnGestureRecognizedListener != null && bestPrediction != null) {
+ if (bestPrediction.score > SCORE_TRESHOLD) {
+ mOnGestureRecognizedListener.gestureRecognized(bestPrediction.name);
+ } else {
+ clear(false);
+ }
+ }
+ }
+}
diff --git a/src/us/minak/IMEService.java b/src/us/minak/IMEService.java
new file mode 100644
index 0000000..6064be9
--- /dev/null
+++ b/src/us/minak/IMEService.java
@@ -0,0 +1,38 @@
+package us.minak;
+
+import android.inputmethodservice.InputMethodService;
+import android.view.View;
+import android.view.inputmethod.EditorInfo;
+
+public class IMEService extends InputMethodService {
+ private IMEView imeView;
+ /**
+ * Loads the configuration.
+ */
+ @Override
+ public void onInitializeInterface() {
+ // TODO
+ }
+
+ @Override
+ public View onCreateInputView() {
+ final IMEView view = (IMEView) getLayoutInflater().inflate(R.layout.ime, null);
+
+ view.setOnCharacterEnteredListener(new OnCharacterEnteredListener() {
+ @Override
+ public void characterEntered(String character) {
+ getCurrentInputConnection().commitText(character, 1);
+ }
+ });
+
+ this.imeView = view;
+ return view;
+ }
+
+ /**
+ * Called to inform the input method that text input has started in an editor.
+ */
+ public void onStartInput(EditorInfo info, boolean restarting) {
+ // TODO: get characters from this.imeView, and pass them to getCurrentInputConnection().commitText(..., 1);
+ }
+}
diff --git a/src/us/minak/IMEView.java b/src/us/minak/IMEView.java
new file mode 100644
index 0000000..d341ae5
--- /dev/null
+++ b/src/us/minak/IMEView.java
@@ -0,0 +1,34 @@
+package us.minak;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.widget.RelativeLayout;
+
+public class IMEView extends RelativeLayout{
+ private final Context mContext;
+ private OnCharacterEnteredListener mOnCharacterEnteredListener;
+ public IMEView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ mContext = context;
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ DrawingSpaceView drawingSpaceView = (DrawingSpaceView) findViewById(R.id.drawing_space);
+ drawingSpaceView.setOnGestureRecognizedListener(new OnGestureRecognizedListener() {
+ @Override
+ public void gestureRecognized(String character) {
+ enterCharacter(character);
+ }
+
+ });
+ }
+
+ public void setOnCharacterEnteredListener(OnCharacterEnteredListener onCharacterEnteredListener) {
+ mOnCharacterEnteredListener = onCharacterEnteredListener;
+ }
+
+ private void enterCharacter(String character) {
+ mOnCharacterEnteredListener.characterEntered(character);
+ }
+}
diff --git a/src/us/minak/Minak.java b/src/us/minak/Minak.java
deleted file mode 100644
index 30f7989..0000000
--- a/src/us/minak/Minak.java
+++ /dev/null
@@ -1,38 +0,0 @@
-package us.minak;
-
-import android.inputmethodservice.InputMethodService;
-import java.util.Queue;
-import android.view.View;
-import android.view.inputmethod.EditorInfo;
-
-
-public class Minak extends InputMethodService {
- private MinakView minakView;
-
- @Override
- public void onStartInput(EditorInfo attribute, boolean restart) {
- if (minview != null) {
- final Queue<Character> symbolsQueue = minview.getSymbolsQueue();
- while (!symbolsQueue.isEmpty()) {
- final Character character = symbolsQueue.poll();
- getCurrentInputConnection().commitText(String.valueOf(character), 1);
- }
- }
- }
-
- @Override
- public View onCreateInputView() {
- final MinakView mv = getLayoutInflater().inflate(R.layout.minak, null);
-
- // TODO set Listeners here
- mv.setOnCharacterEnteredListener(new OnCharacterEnteredListener()) {
- @Override
- public void characterEntered(String character) {
- getCurrentInputConnection().commitText(character, 1);
- }
- }
-
- minakView = mv;
- return mv;
- }
-}
diff --git a/src/us/minak/MinakView.java b/src/us/minak/MinakView.java
deleted file mode 100644
index e6ec2e0..0000000
--- a/src/us/minak/MinakView.java
+++ /dev/null
@@ -1,37 +0,0 @@
-package us.minak;
-
-import android.content.Context;
-import android.widget.RelativeLayout;
-import android.util.AttributeSet;
-import android.support.v4.content.LocalBroadcastManager;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.BroadcastReceiver;
-import java.util.*;
-
-public class MinakView extends RelativeLayout {
- private final Context mContext;
- private final Queue<Character> minakSymbolsQueue = new LinkedList<Character>();
-
- public MinakView(Context context, AttributeSet attr) {
- super(context, attr);
- mContext = context;
- LocalBroadcastManager.getInstance(mContext).registerReceiver(minakBroadcastReceiver,
- new IntentFilter(SketchpadActivity.INTENT_ACTION));
- }
-
- public Queue<Character> getSymbolsQueue() {
- return minakSymbolsQueue;
- }
-
- private final BroadcastReceiver minakBroadcastReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (SketchpadActivity.INTENT_ACTION.equals(intent.getAction())) {
- minakSymbolsQueue.add(intent.getCharExtra(SketchpadActivity.INTENT_EXTRA_NAME, '?'));
- }
- }
- };
-
-} \ No newline at end of file
diff --git a/src/us/minak/NavigationDrawerFragment.java b/src/us/minak/NavigationDrawerFragment.java
deleted file mode 100644
index 6e704c8..0000000
--- a/src/us/minak/NavigationDrawerFragment.java
+++ /dev/null
@@ -1,282 +0,0 @@
-package us.minak;
-
-;
-import android.app.Activity;
-import android.app.ActionBar;
-import android.app.Fragment;
-import android.support.v4.app.ActionBarDrawerToggle;
-import android.support.v4.view.GravityCompat;
-import android.support.v4.widget.DrawerLayout;
-import android.content.SharedPreferences;
-import android.content.res.Configuration;
-import android.os.Bundle;
-import android.preference.PreferenceManager;
-import android.view.LayoutInflater;
-import android.view.Menu;
-import android.view.MenuInflater;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.AdapterView;
-import android.widget.ArrayAdapter;
-import android.widget.ListView;
-import android.widget.Toast;
-
-/**
- * Fragment used for managing interactions for and presentation of a navigation drawer.
- * See the <a href="https://developer.android.com/design/patterns/navigation-drawer.html#Interaction">
- * design guidelines</a> for a complete explanation of the behaviors implemented here.
- */
-public class NavigationDrawerFragment extends Fragment {
-
- /**
- * Remember the position of the selected item.
- */
- private static final String STATE_SELECTED_POSITION = "selected_navigation_drawer_position";
-
- /**
- * Per the design guidelines, you should show the drawer on launch until the user manually
- * expands it. This shared preference tracks this.
- */
- private static final String PREF_USER_LEARNED_DRAWER = "navigation_drawer_learned";
-
- /**
- * A pointer to the current callbacks instance (the Activity).
- */
- private NavigationDrawerCallbacks mCallbacks;
-
- /**
- * Helper component that ties the action bar to the navigation drawer.
- */
- private ActionBarDrawerToggle mDrawerToggle;
-
- private DrawerLayout mDrawerLayout;
- private ListView mDrawerListView;
- private View mFragmentContainerView;
-
- private int mCurrentSelectedPosition = 0;
- private boolean mFromSavedInstanceState;
- private boolean mUserLearnedDrawer;
-
- public NavigationDrawerFragment() {
- }
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- // Read in the flag indicating whether or not the user has demonstrated awareness of the
- // drawer. See PREF_USER_LEARNED_DRAWER for details.
- SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getActivity());
- mUserLearnedDrawer = sp.getBoolean(PREF_USER_LEARNED_DRAWER, false);
-
- if (savedInstanceState != null) {
- mCurrentSelectedPosition = savedInstanceState.getInt(STATE_SELECTED_POSITION);
- mFromSavedInstanceState = true;
- }
-
- // Select either the default item (0) or the last selected item.
- selectItem(mCurrentSelectedPosition);
- }
-
- @Override
- public void onActivityCreated (Bundle savedInstanceState) {
- super.onActivityCreated(savedInstanceState);
- // Indicate that this fragment would like to influence the set of actions in the action bar.
- setHasOptionsMenu(true);
- }
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
- mDrawerListView = (ListView) inflater.inflate(
- R.layout.fragment_navigation_drawer, container, false);
- mDrawerListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
- @Override
- public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
- selectItem(position);
- }
- });
- mDrawerListView.setAdapter(new ArrayAdapter<String>(
- getActionBar().getThemedContext(),
- android.R.layout.simple_list_item_activated_1,
- android.R.id.text1,
- new String[]{
- getString(R.string.title_section1),
- getString(R.string.title_section2),
- getString(R.string.title_section3),
- }));
- mDrawerListView.setItemChecked(mCurrentSelectedPosition, true);
- return mDrawerListView;
- }
-
- public boolean isDrawerOpen() {
- return mDrawerLayout != null && mDrawerLayout.isDrawerOpen(mFragmentContainerView);
- }
-
- /**
- * Users of this fragment must call this method to set up the navigation drawer interactions.
- *
- * @param fragmentId The android:id of this fragment in its activity's layout.
- * @param drawerLayout The DrawerLayout containing this fragment's UI.
- */
- public void setUp(int fragmentId, DrawerLayout drawerLayout) {
- mFragmentContainerView = getActivity().findViewById(fragmentId);
- mDrawerLayout = drawerLayout;
-
- // set a custom shadow that overlays the main content when the drawer opens
- mDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START);
- // set up the drawer's list view with items and click listener
-
- ActionBar actionBar = getActionBar();
- actionBar.setDisplayHomeAsUpEnabled(true);
- actionBar.setHomeButtonEnabled(true);
-
- // ActionBarDrawerToggle ties together the the proper interactions
- // between the navigation drawer and the action bar app icon.
- mDrawerToggle = new ActionBarDrawerToggle(
- getActivity(), /* host Activity */
- mDrawerLayout, /* DrawerLayout object */
- R.drawable.ic_drawer, /* nav drawer image to replace 'Up' caret */
- R.string.navigation_drawer_open, /* "open drawer" description for accessibility */
- R.string.navigation_drawer_close /* "close drawer" description for accessibility */
- ) {
- @Override
- public void onDrawerClosed(View drawerView) {
- super.onDrawerClosed(drawerView);
- if (!isAdded()) {
- return;
- }
-
- getActivity().invalidateOptionsMenu(); // calls onPrepareOptionsMenu()
- }
-
- @Override
- public void onDrawerOpened(View drawerView) {
- super.onDrawerOpened(drawerView);
- if (!isAdded()) {
- return;
- }
-
- if (!mUserLearnedDrawer) {
- // The user manually opened the drawer; store this flag to prevent auto-showing
- // the navigation drawer automatically in the future.
- mUserLearnedDrawer = true;
- SharedPreferences sp = PreferenceManager
- .getDefaultSharedPreferences(getActivity());
- sp.edit().putBoolean(PREF_USER_LEARNED_DRAWER, true).apply();
- }
-
- getActivity().invalidateOptionsMenu(); // calls onPrepareOptionsMenu()
- }
- };
-
- // If the user hasn't 'learned' about the drawer, open it to introduce them to the drawer,
- // per the navigation drawer design guidelines.
- if (!mUserLearnedDrawer && !mFromSavedInstanceState) {
- mDrawerLayout.openDrawer(mFragmentContainerView);
- }
-
- // Defer code dependent on restoration of previous instance state.
- mDrawerLayout.post(new Runnable() {
- @Override
- public void run() {
- mDrawerToggle.syncState();
- }
- });
-
- mDrawerLayout.setDrawerListener(mDrawerToggle);
- }
-
- private void selectItem(int position) {
- mCurrentSelectedPosition = position;
- if (mDrawerListView != null) {
- mDrawerListView.setItemChecked(position, true);
- }
- if (mDrawerLayout != null) {
- mDrawerLayout.closeDrawer(mFragmentContainerView);
- }
- if (mCallbacks != null) {
- mCallbacks.onNavigationDrawerItemSelected(position);
- }
- }
-
- @Override
- public void onAttach(Activity activity) {
- super.onAttach(activity);
- try {
- mCallbacks = (NavigationDrawerCallbacks) activity;
- } catch (ClassCastException e) {
- throw new ClassCastException("Activity must implement NavigationDrawerCallbacks.");
- }
- }
-
- @Override
- public void onDetach() {
- super.onDetach();
- mCallbacks = null;
- }
-
- @Override
- public void onSaveInstanceState(Bundle outState) {
- super.onSaveInstanceState(outState);
- outState.putInt(STATE_SELECTED_POSITION, mCurrentSelectedPosition);
- }
-
- @Override
- public void onConfigurationChanged(Configuration newConfig) {
- super.onConfigurationChanged(newConfig);
- // Forward the new configuration the drawer toggle component.
- mDrawerToggle.onConfigurationChanged(newConfig);
- }
-
- @Override
- public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
- // If the drawer is open, show the global app actions in the action bar. See also
- // showGlobalContextActionBar, which controls the top-left area of the action bar.
- if (mDrawerLayout != null && isDrawerOpen()) {
- inflater.inflate(R.menu.global, menu);
- showGlobalContextActionBar();
- }
- super.onCreateOptionsMenu(menu, inflater);
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- if (mDrawerToggle.onOptionsItemSelected(item)) {
- return true;
- }
-
- if (item.getItemId() == R.id.action_example) {
- Toast.makeText(getActivity(), "Example action.", Toast.LENGTH_SHORT).show();
- return true;
- }
-
- return super.onOptionsItemSelected(item);
- }
-
- /**
- * Per the navigation drawer design guidelines, updates the action bar to show the global app
- * 'context', rather than just what's in the current screen.
- */
- private void showGlobalContextActionBar() {
- ActionBar actionBar = getActionBar();
- actionBar.setDisplayShowTitleEnabled(true);
- actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
- actionBar.setTitle(R.string.app_name);
- }
-
- private ActionBar getActionBar() {
- return getActivity().getActionBar();
- }
-
- /**
- * Callbacks interface that all activities using this fragment must implement.
- */
- public static interface NavigationDrawerCallbacks {
- /**
- * Called when an item in the navigation drawer is selected.
- */
- void onNavigationDrawerItemSelected(int position);
- }
-}
diff --git a/src/us/minak/OnCharacterEnteredListener.java b/src/us/minak/OnCharacterEnteredListener.java
deleted file mode 100644
index a6c7f56..0000000
--- a/src/us/minak/OnCharacterEnteredListener.java
+++ /dev/null
@@ -1,5 +0,0 @@
-package us.minak;
-
-public interface OnCharacterEnteredListener {
- void CharacterEntered(String character);
-} \ No newline at end of file
diff --git a/src/us/minak/OnGestureRecognizedListener.java b/src/us/minak/OnGestureRecognizedListener.java
index 5c3638f..a30e8b8 100644
--- a/src/us/minak/OnGestureRecognizedListener.java
+++ b/src/us/minak/OnGestureRecognizedListener.java
@@ -1,5 +1,26 @@
+/*
+ ********************************************************************************
+ * Copyright (c) 2012 Samsung Electronics, Inc.
+ * All rights reserved.
+ *
+ * This software is a confidential and proprietary information of Samsung
+ * Electronics, Inc. ("Confidential Information"). You shall not disclose such
+ * Confidential Information and shall use it only in accordance with the terms
+ * of the license agreement you entered into with Samsung Electronics.
+ ********************************************************************************
+ */
+
package us.minak;
+/**
+ * A simple interface for handling recognizing a gesture.
+ */
public interface OnGestureRecognizedListener {
+ /**
+ * Invoked when a gesture is recognized.
+ *
+ * @param character
+ * The character represented by the gesture.
+ */
void gestureRecognized(String character);
-} \ No newline at end of file
+}
diff --git a/src/us/minak/SettingsActivity.java b/src/us/minak/SettingsActivity.java
new file mode 100644
index 0000000..b366826
--- /dev/null
+++ b/src/us/minak/SettingsActivity.java
@@ -0,0 +1,436 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package us.minak;
+
+import android.app.Dialog;
+import android.app.AlertDialog;
+import android.app.ListActivity;
+import android.os.Bundle;
+import android.os.AsyncTask;
+import android.os.Environment;
+import android.view.View;
+import android.view.ContextMenu;
+import android.view.MenuItem;
+import android.view.LayoutInflater;
+import android.view.ViewGroup;
+import android.gesture.GestureLibrary;
+import android.gesture.Gesture;
+import android.gesture.GestureLibraries;
+import android.widget.TextView;
+import android.widget.EditText;
+import android.widget.AdapterView;
+import android.widget.Toast;
+import android.widget.ArrayAdapter;
+import android.content.DialogInterface;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.text.TextUtils;
+import android.graphics.Bitmap;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.BitmapDrawable;
+
+import java.util.Map;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Comparator;
+import java.util.Set;
+import java.io.File;
+
+public class SettingsActivity extends ListActivity {
+ private static final int STATUS_SUCCESS = 0;
+ private static final int STATUS_CANCELLED = 1;
+ private static final int STATUS_NO_STORAGE = 2;
+ private static final int STATUS_NOT_LOADED = 3;
+
+ private static final int MENU_ID_RENAME = 1;
+ private static final int MENU_ID_REMOVE = 2;
+
+ private static final int DIALOG_RENAME_GESTURE = 1;
+
+ private static final int REQUEST_NEW_GESTURE = 1;
+
+ // Type: long (id)
+ private static final String GESTURES_INFO_ID = "gestures.info_id";
+
+ private final File mStoreFile = new File(Environment.getExternalStorageDirectory(), "gestures");
+
+ private final Comparator<NamedGesture> mSorter = new Comparator<NamedGesture>() {
+ public int compare(NamedGesture object1, NamedGesture object2) {
+ return object1.name.compareTo(object2.name);
+ }
+ };
+
+ private static GestureLibrary sStore;
+
+ private GesturesAdapter mAdapter;
+ private GesturesLoadTask mTask;
+ private TextView mEmpty;
+
+ private Dialog mRenameDialog;
+ private EditText mInput;
+ private NamedGesture mCurrentRenameGesture;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ setContentView(R.layout.gestures_list);
+
+ mAdapter = new GesturesAdapter(this);
+ setListAdapter(mAdapter);
+
+ if (sStore == null) {
+ sStore = GestureLibraries.fromFile(mStoreFile);
+ }
+ mEmpty = (TextView) findViewById(android.R.id.empty);
+ loadGestures();
+
+ registerForContextMenu(getListView());
+ }
+
+ static GestureLibrary getStore() {
+ return sStore;
+ }
+
+ public void reloadGestures(View v) {
+ loadGestures();
+ }
+
+ public void addGesture(View v) {
+ Intent intent = new Intent(this, CreateGestureActivity.class);
+ startActivityForResult(intent, REQUEST_NEW_GESTURE);
+ }
+
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ super.onActivityResult(requestCode, resultCode, data);
+
+ if (resultCode == RESULT_OK) {
+ switch (requestCode) {
+ case REQUEST_NEW_GESTURE:
+ loadGestures();
+ break;
+ }
+ }
+ }
+
+ private void loadGestures() {
+ if (mTask != null && mTask.getStatus() != GesturesLoadTask.Status.FINISHED) {
+ mTask.cancel(true);
+ }
+ mTask = (GesturesLoadTask) new GesturesLoadTask().execute();
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+
+ if (mTask != null && mTask.getStatus() != GesturesLoadTask.Status.FINISHED) {
+ mTask.cancel(true);
+ mTask = null;
+ }
+
+ cleanupRenameDialog();
+ }
+
+ private void checkForEmpty() {
+ if (mAdapter.getCount() == 0) {
+ mEmpty.setText(R.string.gestures_empty);
+ }
+ }
+
+ @Override
+ protected void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+
+ if (mCurrentRenameGesture != null) {
+ outState.putLong(GESTURES_INFO_ID, mCurrentRenameGesture.gesture.getID());
+ }
+ }
+
+ @Override
+ protected void onRestoreInstanceState(Bundle state) {
+ super.onRestoreInstanceState(state);
+
+ long id = state.getLong(GESTURES_INFO_ID, -1);
+ if (id != -1) {
+ final Set<String> entries = sStore.getGestureEntries();
+out: for (String name : entries) {
+ for (Gesture gesture : sStore.getGestures(name)) {
+ if (gesture.getID() == id) {
+ mCurrentRenameGesture = new NamedGesture();
+ mCurrentRenameGesture.name = name;
+ mCurrentRenameGesture.gesture = gesture;
+ break out;
+ }
+ }
+ }
+ }
+ }
+
+ @Override
+ public void onCreateContextMenu(ContextMenu menu, View v,
+ ContextMenu.ContextMenuInfo menuInfo) {
+
+ super.onCreateContextMenu(menu, v, menuInfo);
+
+ AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo;
+ menu.setHeaderTitle(((TextView) info.targetView).getText());
+
+ menu.add(0, MENU_ID_RENAME, 0, R.string.gestures_rename);
+ menu.add(0, MENU_ID_REMOVE, 0, R.string.gestures_delete);
+ }
+
+ @Override
+ public boolean onContextItemSelected(MenuItem item) {
+ final AdapterView.AdapterContextMenuInfo menuInfo = (AdapterView.AdapterContextMenuInfo)
+ item.getMenuInfo();
+ final NamedGesture gesture = (NamedGesture) menuInfo.targetView.getTag();
+
+ switch (item.getItemId()) {
+ case MENU_ID_RENAME:
+ renameGesture(gesture);
+ return true;
+ case MENU_ID_REMOVE:
+ deleteGesture(gesture);
+ return true;
+ }
+
+ return super.onContextItemSelected(item);
+ }
+
+ private void renameGesture(NamedGesture gesture) {
+ mCurrentRenameGesture = gesture;
+ showDialog(DIALOG_RENAME_GESTURE);
+ }
+
+ @Override
+ protected Dialog onCreateDialog(int id) {
+ if (id == DIALOG_RENAME_GESTURE) {
+ return createRenameDialog();
+ }
+ return super.onCreateDialog(id);
+ }
+
+ @Override
+ protected void onPrepareDialog(int id, Dialog dialog) {
+ super.onPrepareDialog(id, dialog);
+ if (id == DIALOG_RENAME_GESTURE) {
+ mInput.setText(mCurrentRenameGesture.name);
+ }
+ }
+
+ private Dialog createRenameDialog() {
+ final View layout = View.inflate(this, R.layout.dialog_rename, null);
+ mInput = (EditText) layout.findViewById(R.id.name);
+ ((TextView) layout.findViewById(R.id.label)).setText(R.string.gestures_rename_label);
+
+ AlertDialog.Builder builder = new AlertDialog.Builder(this);
+ builder.setIcon(0);
+ builder.setTitle(getString(R.string.gestures_rename_title));
+ builder.setCancelable(true);
+ builder.setOnCancelListener(new Dialog.OnCancelListener() {
+ public void onCancel(DialogInterface dialog) {
+ cleanupRenameDialog();
+ }
+ });
+ builder.setNegativeButton(getString(R.string.cancel_action),
+ new Dialog.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ cleanupRenameDialog();
+ }
+ }
+ );
+ builder.setPositiveButton(getString(R.string.rename_action),
+ new Dialog.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ changeGestureName();
+ }
+ }
+ );
+ builder.setView(layout);
+ return builder.create();
+ }
+
+ private void changeGestureName() {
+ final String name = mInput.getText().toString();
+ if (!TextUtils.isEmpty(name)) {
+ final NamedGesture renameGesture = mCurrentRenameGesture;
+ final GesturesAdapter adapter = mAdapter;
+ final int count = adapter.getCount();
+
+ // Simple linear search, there should not be enough items to warrant
+ // a more sophisticated search
+ for (int i = 0; i < count; i++) {
+ final NamedGesture gesture = adapter.getItem(i);
+ if (gesture.gesture.getID() == renameGesture.gesture.getID()) {
+ sStore.removeGesture(gesture.name, gesture.gesture);
+ gesture.name = mInput.getText().toString();
+ sStore.addGesture(gesture.name, gesture.gesture);
+ break;
+ }
+ }
+
+ adapter.notifyDataSetChanged();
+ }
+ mCurrentRenameGesture = null;
+ }
+
+ private void cleanupRenameDialog() {
+ if (mRenameDialog != null) {
+ mRenameDialog.dismiss();
+ mRenameDialog = null;
+ }
+ mCurrentRenameGesture = null;
+ }
+
+ private void deleteGesture(NamedGesture gesture) {
+ sStore.removeGesture(gesture.name, gesture.gesture);
+ sStore.save();
+
+ final GesturesAdapter adapter = mAdapter;
+ adapter.setNotifyOnChange(false);
+ adapter.remove(gesture);
+ adapter.sort(mSorter);
+ checkForEmpty();
+ adapter.notifyDataSetChanged();
+
+ Toast.makeText(this, R.string.gestures_delete_success, Toast.LENGTH_SHORT).show();
+ }
+
+ private class GesturesLoadTask extends AsyncTask<Void, NamedGesture, Integer> {
+ private int mThumbnailSize;
+ private int mThumbnailInset;
+ private int mPathColor;
+
+ @Override
+ protected void onPreExecute() {
+ super.onPreExecute();
+
+ final Resources resources = getResources();
+ mPathColor = resources.getColor(R.color.gesture_color);
+ mThumbnailInset = (int) resources.getDimension(R.dimen.gesture_thumbnail_inset);
+ mThumbnailSize = (int) resources.getDimension(R.dimen.gesture_thumbnail_size);
+
+ findViewById(R.id.addButton).setEnabled(false);
+ findViewById(R.id.reloadButton).setEnabled(false);
+
+ mAdapter.setNotifyOnChange(false);
+ mAdapter.clear();
+ }
+
+ @Override
+ protected Integer doInBackground(Void... params) {
+ if (isCancelled()) return STATUS_CANCELLED;
+ if (!Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {
+ return STATUS_NO_STORAGE;
+ }
+
+ final GestureLibrary store = sStore;
+
+ if (store.load()) {
+ for (String name : store.getGestureEntries()) {
+ if (isCancelled()) break;
+
+ for (Gesture gesture : store.getGestures(name)) {
+ final Bitmap bitmap = gesture.toBitmap(mThumbnailSize, mThumbnailSize,
+ mThumbnailInset, mPathColor);
+ final NamedGesture namedGesture = new NamedGesture();
+ namedGesture.gesture = gesture;
+ namedGesture.name = name;
+
+ mAdapter.addBitmap(namedGesture.gesture.getID(), bitmap);
+ publishProgress(namedGesture);
+ }
+ }
+
+ return STATUS_SUCCESS;
+ }
+
+ return STATUS_NOT_LOADED;
+ }
+
+ @Override
+ protected void onProgressUpdate(NamedGesture... values) {
+ super.onProgressUpdate(values);
+
+ final GesturesAdapter adapter = mAdapter;
+ adapter.setNotifyOnChange(false);
+
+ for (NamedGesture gesture : values) {
+ adapter.add(gesture);
+ }
+
+ adapter.sort(mSorter);
+ adapter.notifyDataSetChanged();
+ }
+
+ @Override
+ protected void onPostExecute(Integer result) {
+ super.onPostExecute(result);
+
+ if (result == STATUS_NO_STORAGE) {
+ getListView().setVisibility(View.GONE);
+ mEmpty.setVisibility(View.VISIBLE);
+ mEmpty.setText(getString(R.string.gestures_error_loading,
+ mStoreFile.getAbsolutePath()));
+ } else {
+ findViewById(R.id.addButton).setEnabled(true);
+ findViewById(R.id.reloadButton).setEnabled(true);
+ checkForEmpty();
+ }
+ }
+ }
+
+ static class NamedGesture {
+ String name;
+ Gesture gesture;
+ }
+
+ private class GesturesAdapter extends ArrayAdapter<NamedGesture> {
+ private final LayoutInflater mInflater;
+ private final Map<Long, Drawable> mThumbnails = Collections.synchronizedMap(
+ new HashMap<Long, Drawable>());
+
+ public GesturesAdapter(Context context) {
+ super(context, 0);
+ mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ }
+
+ void addBitmap(Long id, Bitmap bitmap) {
+ mThumbnails.put(id, new BitmapDrawable(bitmap));
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ if (convertView == null) {
+ convertView = mInflater.inflate(R.layout.gestures_item, parent, false);
+ }
+
+ final NamedGesture gesture = getItem(position);
+ final TextView label = (TextView) convertView;
+
+ label.setTag(gesture);
+ label.setText(gesture.name);
+ label.setCompoundDrawablesWithIntrinsicBounds(mThumbnails.get(gesture.gesture.getID()),
+ null, null, null);
+
+ return convertView;
+ }
+ }
+}
diff --git a/src/us/minak/SketchpadView.java b/src/us/minak/SketchpadView.java
deleted file mode 100644
index bbfd471..0000000
--- a/src/us/minak/SketchpadView.java
+++ /dev/null
@@ -1,42 +0,0 @@
-import java.util.List;
-
-import android.gesture.Gesture;
-import android.gesture.GestureLibraries;
-import android.gesture.GestureLibrary;
-import android.gesture.GestureOverlayView;
-import android.gesture.GestureOverlayView.OnGesturePerformedListener;
-import android.gesture.Prediction;
-import android.util.AttributeSet;
-
-public class SketchpadView extends GestureOverlayView implements OnGesturePerformedListener{
- private static final double score_threshold = 3.0;
- private final GestureLibrary gestureLib;
- private onGestureRecognizedListener gestureRecognizer;
-
- public SketchpadView (Context context, AttributeSet attrs){
- super(context, attrs);
- mGestureLibrary = GestureLibraries.fromRawResource(context, R.raw.gestures);
- mGestureLibrary.load();
- addOnGesturePerformedListener(this);
- }
-
- public void setOnGestureRecognizedListener(OnGestureRecognizedListener onGestureRecognizedListener) {
- gestureRecognizer = onGestureRecognizedListener;
- }
-
- @Override
- public void onGesturePerformed(GestureOverlayView view, Gesture gesture){
- List<Prediction> predictions = gestureLib.recognize(gesture);
- Prediction bestPrediction = null;
- if(!predictions.isEmpty()){
- bestPrediction = predictions.get(0);
- }
- if(gestureRecognizer != null && bestPrediction != null){
- if(bestPrediction.score > score_threshold){
- gestureRecognizer.gestureRecognized(bestPrediction.name);
- }else{
- clear(false);
- }
- }
- }
-}