diff options
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 Binary files differnew file mode 100755 index 0000000..097ba09 --- /dev/null +++ b/gestures diff --git a/libs/android-support-v4.jar b/libs/android-support-v4.jar Binary files differnew file mode 100644 index 0000000..a7e9919 --- /dev/null +++ b/libs/android-support-v4.jar 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 Binary files differnew file mode 100644 index 0000000..2494b61 --- /dev/null +++ b/res/drawable-hdpi/ic_launcher.png diff --git a/res/drawable-mdpi/ic_launcher.png b/res/drawable-mdpi/ic_launcher.png Binary files differnew file mode 100644 index 0000000..deb71bc --- /dev/null +++ b/res/drawable-mdpi/ic_launcher.png diff --git a/res/drawable-xhdpi/ic_launcher.png b/res/drawable-xhdpi/ic_launcher.png Binary files differnew file mode 100644 index 0000000..50e38d7 --- /dev/null +++ b/res/drawable-xhdpi/ic_launcher.png diff --git a/res/icons/keyboard.png b/res/icons/keyboard.png Binary files differnew file mode 100644 index 0000000..e2c3c74 --- /dev/null +++ b/res/icons/keyboard.png diff --git a/res/icons/keyboard/drawable-hdpi/ic_launcher.png b/res/icons/keyboard/drawable-hdpi/ic_launcher.png Binary files differnew file mode 100644 index 0000000..2494b61 --- /dev/null +++ b/res/icons/keyboard/drawable-hdpi/ic_launcher.png diff --git a/res/icons/keyboard/drawable-mdpi/ic_launcher.png b/res/icons/keyboard/drawable-mdpi/ic_launcher.png Binary files differnew file mode 100644 index 0000000..deb71bc --- /dev/null +++ b/res/icons/keyboard/drawable-mdpi/ic_launcher.png diff --git a/res/icons/keyboard/drawable-xhdpi/ic_launcher.png b/res/icons/keyboard/drawable-xhdpi/ic_launcher.png Binary files differnew file mode 100644 index 0000000..8944a37 --- /dev/null +++ b/res/icons/keyboard/drawable-xhdpi/ic_launcher.png 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 Binary files differnew file mode 100644 index 0000000..80f80a0 --- /dev/null +++ b/res/icons/minak/drawable-hdpi/ic_launcher.png diff --git a/res/icons/minak/drawable-mdpi/ic_launcher.png b/res/icons/minak/drawable-mdpi/ic_launcher.png Binary files differnew file mode 100644 index 0000000..9fce689 --- /dev/null +++ b/res/icons/minak/drawable-mdpi/ic_launcher.png diff --git a/res/icons/minak/drawable-xhdpi/ic_launcher.png b/res/icons/minak/drawable-xhdpi/ic_launcher.png Binary files differnew file mode 100644 index 0000000..7a86237 --- /dev/null +++ b/res/icons/minak/drawable-xhdpi/ic_launcher.png 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 Binary files differnew file mode 100644 index 0000000..3cc9d7c --- /dev/null +++ b/res/raw/gestures 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…</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); - } - } - } -} |