├── .gitignore ├── LICENSE.txt ├── NOTICE.txt ├── README.ja.md ├── README.md ├── UiAutomatorInputSample ├── build.xml ├── project.properties └── src │ ├── com │ └── beetstra │ │ └── jutf7 │ │ ├── Base64Util.java │ │ ├── CharsetProvider.java │ │ ├── ModifiedUTF7Charset.java │ │ ├── UTF7Charset.java │ │ ├── UTF7StyleCharset.java │ │ ├── UTF7StyleCharsetDecoder.java │ │ └── UTF7StyleCharsetEncoder.java │ └── jp │ └── jun_nama │ └── test │ └── utf7ime │ ├── helper │ └── Utf7ImeHelper.java │ └── sample │ └── UiAutomatorInputTest.java ├── Utf7Ime ├── AndroidManifest.xml ├── libs │ └── jutf7-1.0.0.jar ├── proguard-project.txt ├── project.properties ├── res │ ├── drawable-hdpi │ │ └── ic_launcher.png │ ├── drawable-mdpi │ │ └── ic_launcher.png │ ├── drawable-xhdpi │ │ └── ic_launcher.png │ ├── values-v11 │ │ └── styles.xml │ ├── values-v14 │ │ └── styles.xml │ ├── values │ │ ├── strings.xml │ │ └── styles.xml │ └── xml │ │ └── method.xml └── src │ └── jp │ └── jun_nama │ └── test │ └── utf7ime │ └── Utf7ImeService.java ├── helper-library └── src │ ├── com │ └── beetstra │ │ └── jutf7 │ │ ├── Base64Util.java │ │ ├── CharsetProvider.java │ │ ├── ModifiedUTF7Charset.java │ │ ├── UTF7Charset.java │ │ ├── UTF7StyleCharset.java │ │ ├── UTF7StyleCharsetDecoder.java │ │ └── UTF7StyleCharsetEncoder.java │ └── jp │ └── jun_nama │ └── test │ └── utf7ime │ └── helper │ └── Utf7ImeHelper.java └── images └── sample-screenshot.png /.gitignore: -------------------------------------------------------------------------------- 1 | ### /cygdrive/c/Users/sumio/.gitignore-boilerplates/Android.gitignore 2 | 3 | # built application files 4 | *.apk 5 | *.ap_ 6 | 7 | # files for the dex VM 8 | *.dex 9 | 10 | # Java class files 11 | *.class 12 | 13 | # generated files 14 | bin/ 15 | gen/ 16 | 17 | # Local configuration file (sdk path, etc) 18 | local.properties 19 | 20 | # Eclipse project files 21 | .classpath 22 | .project 23 | 24 | # Proguard folder generated by Eclipse 25 | proguard/ 26 | 27 | # Intellij project files 28 | *.iml 29 | *.ipr 30 | *.iws 31 | .idea/ 32 | 33 | 34 | 35 | ### /cygdrive/c/Users/sumio/.gitignore-boilerplates/Global/Eclipse.gitignore 36 | 37 | *.pydevproject 38 | .project 39 | .metadata 40 | bin/** 41 | tmp/** 42 | tmp/**/* 43 | *.tmp 44 | *.bak 45 | *.swp 46 | *~.nib 47 | local.properties 48 | .classpath 49 | .settings/ 50 | .loadpath 51 | 52 | # External tool builders 53 | .externalToolBuilders/ 54 | 55 | # Locally stored "Eclipse launch configurations" 56 | *.launch 57 | 58 | # CDT-specific 59 | .cproject 60 | 61 | # PDT-specific 62 | .buildpath 63 | 64 | # Emacs backup 65 | *~ 66 | \#*# 67 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /NOTICE.txt: -------------------------------------------------------------------------------- 1 | Uiautomator Unicode Input Helper 2 | Copyright 2013 TOYAMA Sumio 3 | 4 | This product includes software written by 5 | TOYAMA Sumio 6 | 7 | ========================================================================= 8 | == NOTICE file for the jutf7 (Java UTF-7 Charset support) License. == 9 | ========================================================================= 10 | 11 | This software contains jutf7 (Java UTF-7 Charset support), which is available at 12 | http://sourceforge.net/projects/jutf7/ and licensed under a MIT license as follows: 13 | 14 | Copyright (c) 2006 J.T. Beetstra 15 | 16 | Permission is hereby granted, free of charge, to any person obtaining 17 | a copy of this software and associated documentation files (the 18 | "Software"), to deal in the Software without restriction, including 19 | without limitation the rights to use, copy, modify, merge, publish, 20 | distribute, sublicense, and/or sell copies of the Software, and to 21 | permit persons to whom the Software is furnished to do so, subject to 22 | the following conditions: 23 | 24 | The above copyright notice and this permission notice shall be 25 | included in all copies or substantial portions of the Software. 26 | 27 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 28 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 29 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 30 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 31 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 32 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 33 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 34 | 35 | ========================================================================= 36 | == NOTICE file corresponding to the section 4 d of == 37 | == the Apache License, Version 2.0, == 38 | == in this case for the Android-specific code. == 39 | ========================================================================= 40 | 41 | Android Code 42 | Copyright 2005-2008 The Android Open Source Project 43 | 44 | This product includes software developed as part of 45 | The Android Open Source Project (http://source.android.com). 46 | 47 | ========================================================================= 48 | == NOTICE file corresponding to the section 4 d of == 49 | == the Apache License, Version 2.0, == 50 | == in this case for the Apache Harmony distribution. == 51 | ========================================================================= 52 | 53 | Apache Harmony 54 | Copyright 2006 The Apache Software Foundation 55 | 56 | This product includes software developed at 57 | The Apache Software Foundation (http://www.apache.org/). 58 | 59 | Portions of Harmony were originally developed by 60 | Intel Corporation and are licensed to the Apache Software 61 | Foundation under the "Software Grant and Corporate Contribution 62 | License Agreement", informally known as the "Intel Harmony CLA". 63 | 64 | 65 | ========================================================================= 66 | == NOTICE file for the ICU License. == 67 | ========================================================================= 68 | 69 | Copyright (c) 1995-2009 International Business Machines Corporation and others 70 | 71 | All rights reserved. 72 | 73 | Permission is hereby granted, free of charge, to any person obtaining 74 | a copy of this software and associated documentation files (the 75 | "Software"), to deal in the Software without restriction, including 76 | without limitation the rights to use, copy, modify, merge, publish, 77 | distribute, and/or sell copies of the Software, and to permit persons 78 | to whom the Software is furnished to do so, provided that the above 79 | copyright notice(s) and this permission notice appear in all copies of 80 | the Software and that both the above copyright notice(s) and this 81 | permission notice appear in supporting documentation. 82 | 83 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 84 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 85 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT 86 | OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 87 | HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY 88 | SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER 89 | RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF 90 | CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 91 | CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 92 | 93 | Except as contained in this notice, the name of a copyright holder 94 | shall not be used in advertising or otherwise to promote the sale, use 95 | or other dealings in this Software without prior written authorization 96 | of the copyright holder. 97 | 98 | All trademarks and registered trademarks mentioned herein are the 99 | property of their respective owners. 100 | 101 | 102 | ========================================================================= 103 | == NOTICE file for the JUnit License. == 104 | ========================================================================= 105 | 106 | Common Public License - v 1.0 107 | 108 | THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS COMMON 109 | PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF 110 | THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. 111 | 112 | 1. DEFINITIONS 113 | 114 | "Contribution" means: 115 | 116 | a) in the case of the initial Contributor, the initial code and 117 | documentation distributed under this Agreement, and 118 | b) in the case of each subsequent Contributor: 119 | 120 | i) changes to the Program, and 121 | 122 | ii) additions to the Program; 123 | 124 | where such changes and/or additions to the Program originate 125 | from and are distributed by that particular Contributor. A 126 | Contribution 'originates' from a Contributor if it was added to 127 | the Program by such Contributor itself or anyone acting on such 128 | Contributor's behalf. Contributions do not include additions to 129 | the Program which: (i) are separate modules of software 130 | distributed in conjunction with the Program under their own 131 | license agreement, and (ii) are not derivative works of the 132 | Program. 133 | 134 | "Contributor" means any person or entity that distributes the Program. 135 | 136 | "Licensed Patents " mean patent claims licensable by a Contributor 137 | which are necessarily infringed by the use or sale of its Contribution 138 | alone or when combined with the Program. 139 | 140 | "Program" means the Contributions distributed in accordance with this 141 | Agreement. 142 | 143 | "Recipient" means anyone who receives the Program under this 144 | Agreement, including all Contributors. 145 | 146 | 2. GRANT OF RIGHTS 147 | 148 | a) Subject to the terms of this Agreement, each Contributor 149 | hereby grants Recipient a non-exclusive, worldwide, royalty-free 150 | copyright license to reproduce, prepare derivative works of, 151 | publicly display, publicly perform, distribute and sublicense 152 | the Contribution of such Contributor, if any, and such 153 | derivative works, in source code and object code form. 154 | 155 | b) Subject to the terms of this Agreement, each Contributor 156 | hereby grants Recipient a non-exclusive, worldwide, royalty-free 157 | patent license under Licensed Patents to make, use, sell, offer 158 | to sell, import and otherwise transfer the Contribution of such 159 | Contributor, if any, in source code and object code form. This 160 | patent license shall apply to the combination of the 161 | Contribution and the Program if, at the time the Contribution is 162 | added by the Contributor, such addition of the Contribution 163 | causes such combination to be covered by the Licensed Patents. 164 | The patent license shall not apply to any other combinations 165 | which include the Contribution. No hardware per se is licensed 166 | hereunder. 167 | 168 | c) Recipient understands that although each Contributor grants 169 | the licenses to its Contributions set forth herein, no 170 | assurances are provided by any Contributor that the Program does 171 | not infringe the patent or other intellectual property rights of 172 | any other entity. Each Contributor disclaims any liability to 173 | Recipient for claims brought by any other entity based on 174 | infringement of intellectual property rights or otherwise. As a 175 | condition to exercising the rights and licenses granted 176 | hereunder, each Recipient hereby assumes sole responsibility to 177 | secure any other intellectual property rights needed, if any. 178 | For example, if a third party patent license is required to 179 | allow Recipient to distribute the Program, it is Recipient's 180 | responsibility to acquire that license before distributing the 181 | Program. 182 | 183 | d) Each Contributor represents that to its knowledge it has 184 | sufficient copyright rights in its Contribution, if any, to 185 | grant the copyright license set forth in this Agreement. 186 | 187 | 3. REQUIREMENTS 188 | 189 | A Contributor may choose to distribute the Program in object code form 190 | under its own license agreement, provided that: 191 | 192 | a) it complies with the terms and conditions of this Agreement; and 193 | 194 | b) its license agreement: 195 | 196 | i) effectively disclaims on behalf of all Contributors all 197 | warranties and conditions, express and implied, including 198 | warranties or conditions of title and non-infringement, and 199 | implied warranties or conditions of merchantability and fitness 200 | for a particular purpose; 201 | 202 | ii) effectively excludes on behalf of all Contributors all 203 | liability for damages, including direct, indirect, special, 204 | incidental and consequential damages, such as lost profits; 205 | 206 | iii) states that any provisions which differ from this Agreement 207 | are offered by that Contributor alone and not by any other 208 | party; and 209 | 210 | iv) states that source code for the Program is available from 211 | such Contributor, and informs licensees how to obtain it in a 212 | reasonable manner on or through a medium customarily used for 213 | software exchange. 214 | 215 | When the Program is made available in source code form: 216 | 217 | a) it must be made available under this Agreement; and 218 | 219 | b) a copy of this Agreement must be included with each copy of 220 | the Program. 221 | 222 | Contributors may not remove or alter any copyright notices contained 223 | within the Program. 224 | 225 | Each Contributor must identify itself as the originator of its 226 | Contribution, if any, in a manner that reasonably allows subsequent 227 | Recipients to identify the originator of the Contribution. 228 | 229 | 4. COMMERCIAL DISTRIBUTION 230 | 231 | Commercial distributors of software may accept certain 232 | responsibilities with respect to end users, business partners and the 233 | like. While this license is intended to facilitate the commercial use 234 | of the Program, the Contributor who includes the Program in a 235 | commercial product offering should do so in a manner which does not 236 | create potential liability for other Contributors. Therefore, if a 237 | Contributor includes the Program in a commercial product offering, 238 | such Contributor ("Commercial Contributor") hereby agrees to defend 239 | and indemnify every other Contributor ("Indemnified Contributor") 240 | against any losses, damages and costs (collectively "Losses") arising 241 | from claims, lawsuits and other legal actions brought by a third party 242 | against the Indemnified Contributor to the extent caused by the acts 243 | or omissions of such Commercial Contributor in connection with its 244 | distribution of the Program in a commercial product offering. The 245 | obligations in this section do not apply to any claims or Losses 246 | relating to any actual or alleged intellectual property infringement. 247 | In order to qualify, an Indemnified Contributor must: a) promptly 248 | notify the Commercial Contributor in writing of such claim, and b) 249 | allow the Commercial Contributor to control, and cooperate with the 250 | Commercial Contributor in, the defense and any related settlement 251 | negotiations. The Indemnified Contributor may participate in any such 252 | claim at its own expense. 253 | 254 | For example, a Contributor might include the Program in a commercial 255 | product offering, Product X. That Contributor is then a Commercial 256 | Contributor. If that Commercial Contributor then makes performance 257 | claims, or offers warranties related to Product X, those performance 258 | claims and warranties are such Commercial Contributor's responsibility 259 | alone. Under this section, the Commercial Contributor would have to 260 | defend claims against the other Contributors related to those 261 | performance claims and warranties, and if a court requires any other 262 | Contributor to pay any damages as a result, the Commercial Contributor 263 | must pay those damages. 264 | 265 | 5. NO WARRANTY 266 | 267 | EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS 268 | PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 269 | KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY 270 | WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY 271 | OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely 272 | responsible for determining the appropriateness of using and 273 | distributing the Program and assumes all risks associated with its 274 | exercise of rights under this Agreement, including but not limited to 275 | the risks and costs of program errors, compliance with applicable 276 | laws, damage to or loss of data, programs or equipment, and 277 | unavailability or interruption of operations. 278 | 279 | 6. DISCLAIMER OF LIABILITY 280 | 281 | EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR 282 | ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, 283 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING 284 | WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF 285 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 286 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR 287 | DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED 288 | HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 289 | 290 | 7. GENERAL 291 | 292 | If any provision of this Agreement is invalid or unenforceable under 293 | applicable law, it shall not affect the validity or enforceability of 294 | the remainder of the terms of this Agreement, and without further 295 | action by the parties hereto, such provision shall be reformed to the 296 | minimum extent necessary to make such provision valid and enforceable. 297 | 298 | If Recipient institutes patent litigation against a Contributor with 299 | respect to a patent applicable to software (including a cross-claim or 300 | counterclaim in a lawsuit), then any patent licenses granted by that 301 | Contributor to such Recipient under this Agreement shall terminate as 302 | of the date such litigation is filed. In addition, if Recipient 303 | institutes patent litigation against any entity (including a 304 | cross-claim or counterclaim in a lawsuit) alleging that the Program 305 | itself (excluding combinations of the Program with other software or 306 | hardware) infringes such Recipient's patent(s), then such Recipient's 307 | rights granted under Section 2(b) shall terminate as of the date such 308 | litigation is filed. 309 | 310 | All Recipient's rights under this Agreement shall terminate if it 311 | fails to comply with any of the material terms or conditions of this 312 | Agreement and does not cure such failure in a reasonable period of 313 | time after becoming aware of such noncompliance. If all Recipient's 314 | rights under this Agreement terminate, Recipient agrees to cease use 315 | and distribution of the Program as soon as reasonably practicable. 316 | However, Recipient's obligations under this Agreement and any licenses 317 | granted by Recipient relating to the Program shall continue and 318 | survive. 319 | 320 | Everyone is permitted to copy and distribute copies of this Agreement, 321 | but in order to avoid inconsistency the Agreement is copyrighted and 322 | may only be modified in the following manner. The Agreement Steward 323 | reserves the right to publish new versions (including revisions) of 324 | this Agreement from time to time. No one other than the Agreement 325 | Steward has the right to modify this Agreement. IBM is the initial 326 | Agreement Steward. IBM may assign the responsibility to serve as the 327 | Agreement Steward to a suitable separate entity. Each new version of 328 | the Agreement will be given a distinguishing version number. The 329 | Program (including Contributions) may always be distributed subject to 330 | the version of the Agreement under which it was received. In addition, 331 | after a new version of the Agreement is published, Contributor may 332 | elect to distribute the Program (including its Contributions) under 333 | the new version. Except as expressly stated in Sections 2(a) and 2(b) 334 | above, Recipient receives no rights or licenses to the intellectual 335 | property of any Contributor under this Agreement, whether expressly, 336 | by implication, estoppel or otherwise. All rights in the Program not 337 | expressly granted under this Agreement are reserved. 338 | 339 | This Agreement is governed by the laws of the State of New York and 340 | the intellectual property laws of the United States of America. No 341 | party to this Agreement will bring a legal action under this Agreement 342 | more than one year after the cause of action arose. Each party waives 343 | its rights to a jury trial in any resulting litigation. 344 | 345 | 346 | ========================================================================= 347 | == NOTICE file for the KXML License. == 348 | ========================================================================= 349 | 350 | Copyright (c) 2002,2003, Stefan Haustein, Oberhausen, Rhld., Germany 351 | 352 | Permission is hereby granted, free of charge, to any person obtaining 353 | a copy of this software and associated documentation files (the 354 | "Software"), to deal in the Software without restriction, including 355 | without limitation the rights to use, copy, modify, merge, publish, 356 | distribute, sublicense, and/or sell copies of the Software, and to 357 | permit persons to whom the Software is furnished to do so, subject to 358 | the following conditions: 359 | 360 | The above copyright notice and this permission notice shall be 361 | included in all copies or substantial portions of the Software. 362 | 363 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 364 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 365 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 366 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 367 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 368 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 369 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 370 | 371 | 372 | ========================================================================= 373 | == NOTICE file for the SQLite Java Wrapper License. == 374 | ========================================================================= 375 | 376 | This software is copyrighted by Christian Werner 377 | and others. The following terms apply to all files associated with the 378 | software unless explicitly disclaimed in individual files. 379 | 380 | The authors hereby grant permission to use, copy, modify, distribute, 381 | and license this software and its documentation for any purpose, provided 382 | that existing copyright notices are retained in all copies and that this 383 | notice is included verbatim in any distributions. No written agreement, 384 | license, or royalty fee is required for any of the authorized uses. 385 | Modifications to this software may be copyrighted by their authors 386 | and need not follow the licensing terms described here, provided that 387 | the new terms are clearly indicated on the first page of each file where 388 | they apply. 389 | 390 | IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY 391 | FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 392 | ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY 393 | DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE 394 | POSSIBILITY OF SUCH DAMAGE. 395 | 396 | THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, 397 | INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, 398 | FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE 399 | IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE 400 | NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR 401 | MODIFICATIONS. 402 | 403 | 404 | ========================================================================= 405 | == NOTICE file for the W3C License. == 406 | ========================================================================= 407 | 408 | Copyright (c) 2000 World Wide Web Consortium, (Massachusetts Institute 409 | of Technology, Institut National de Recherche en Informatique et en 410 | Automatique, Keio University). All Rights Reserved. This program is 411 | distributed under the W3C's Software Intellectual Property License. 412 | This program is distributed in the hope that it will be useful, but 413 | WITHOUT ANY WARRANTY; without even the implied warranty of 414 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 415 | 416 | See W3C License http://www.w3.org/Consortium/Legal/ for more details. 417 | 418 | -------------------------------------------------------------------------------- /README.ja.md: -------------------------------------------------------------------------------- 1 | Uiautomator Unicode Input Helper 2 | ====================== 3 | Androidの自動テストツール 4 | [uiautomator](http://developer.android.com/tools/help/uiautomator/index.html) 5 | で、日本語のような非ASCII文字の入力を実現します。 6 | 7 | uiautomatorには、テキストボックスに文字を入力するためのメソッド 8 | [UiObject.setText(String)](http://developer.android.com/tools/help/uiautomator/UiObject.html#setText%28java.lang.String%29) 9 | がありますが、このメソッドの引数にはASCII以外の文字列 10 | (正確には、QWERTYキーボードを使って入力できない文字列) 11 | を指定することができません。 12 | 13 | このプロジェクトでは、Modified UTF-7形式で入力された文字列を、デコードしてから 14 | テキストボックスに送り込むIMEを提供することで、上記制限を解決します。 15 | 16 | Usage 17 | ------ 18 | ここでは、uiautomatorを使ったテストプロジェクトの作り方や、実行方法については 19 | 説明しません。既にuiautomatorを使ったテストプロジェクトが存在しているものとします。 20 | 21 | uiautomatorを使ったことの無い方は、Android Developersのサイトにある、 22 | [UI Testing](http://developer.android.com/tools/testing/testing_ui.html) 23 | を参考にしてください。 24 | 25 | ### 注意事項 26 | ここでインストールしたUtf7Imeは、自動テスト用途のみを想定しているため、ソフトウェアキーボード 27 | は実装されていません。 28 | そのため、以下の手順に従ってUtf7Imeを有効化した状態では、テキストボックスにフォーカスを当てても、 29 | ソフトウェアキーボードが表示されず、全く文字を入力することができなくなってしまいます。 30 | 31 | **テストが終了したら、デフォルトのIMEを、通常利用するIMEに戻しておいてください。** 32 | IMEを元に戻す手順は以下の通りです。 33 | 34 | * ホームキーを押し、ホーム画面を表示します。 35 | * [Settings]アプリを起動します。 36 | * [Language & input]を開きます。 37 | * [KEYBOARD & INPUT METHODS]カテゴリにある、[Default]を押下し、 38 | 普段利用しているIMEを選択し直します。 39 | 40 | ### 準備 41 | #### Utf7ImeのインストールとデフォルトIMEへの設定 42 | * ``Utf7Ime/``ディレクトリ配下をEclipseにインポートします。 43 | [Import...]>[Existing Android Code Into Workspace] でインポートできます。 44 | * ``Utf7Ime``プロジェクトをビルドし、テスト対象端末へインストールします。 45 | * テスト対象端末の[Settings]>[Language & input]を開きます。 46 | * [KEYBOARD & INPUT METHODS]カテゴリにある、[UTF7 IME for UI Testing] 47 | のチェックボックスをチェックします。 48 | IMEを有効化する時の警告ダイアログが表示されるため[OK]を押します。 49 | * [KEYBOARD & INPUT METHODS]カテゴリにある、 50 | [Default]を選択し、[UTF7 IME for UI Testing]をデフォルトのIMEに指定します。 51 | 52 | #### ヘルパーライブラリのコピー 53 | ``helper-library/src``ディレクトリ配下のソースコードを、自分のuiautomatorプロジェクトの 54 | ``src/``ディレクトリ配下へコピーします。 55 | 56 | uiautomatorのプロジェクトでは、``libs/``ディレクトリ配下にJARファイルを保存しても、 57 | 無視されてしまう点に注意してください。 58 | 59 | ### 使い方 60 | 以下のように、``UiObject.setText()``の引数に指定する文字列について、``Utf7ImeHelper.e()`` 61 | でラップしてください。 62 | 63 | import jp.jun_nama.test.utf7ime.helper.Utf7ImeHelper; 64 | 65 | .... 66 | 67 | UiObject editText = ...; 68 | editText.setText(Utf7ImeHelper.e("こんにちは")); 69 | .... 70 | 71 | ``UiAutomatorInputSample/``ディレクトリ配下の実装例も参考にしてください。 72 | 73 | なお、``&``以外のASCII文字を入力するのであれば、``Utf7ImeHelper.e()``でラップせずに、 74 | ``setText()``の引数に直接入力しても問題ありません。 75 | 76 | ### サンプルについて 77 | ``UiAutomatorInputSample/``ディレクトリ配下に、 78 | uiautomatorで日本語を入力するサンプルプロジェクトが同梱されています。 79 | このサンプルでは、Googleの検索ボックスに 80 | 「こんにちは!UiAutomatorで入力しています。」 81 | と自動的に入力します。 82 | ![Result Screenshot](/images/sample-screenshot.png) 83 | 84 | サンプルプロジェクトをビルド・実行するには、``ANDROID_HOME``環境変数を適切に設定した上で、 85 | 以下のコマンドを実行してください(antが必要です)。 86 | なお、**テスト対象端末のロケールは英語(English (United States))に設定しておく必要があります**。 87 | 88 | cd UiAutomatorInputSample 89 | ant clean build install 90 | adb shell uiautomator runtest UiAutomatorInputSample.jar \ 91 | -c jp.jun_nama.test.utf7ime.sample.UiAutomatorInputTest 92 | 93 | このサンプルは、Android 4.4のNexus 7 (2013)上で動作を確認しています。 94 | 他のバージョンでは、Googleの検索ボックスのクラス名が異なるため、サンプルそのままでは動作しません。 95 | その場合でも、検索条件部分を書き換えることで動作させることができると思います。 96 | 97 | なお、このAndroidバージョンによる制限は、あくまでもサンプルアプリの制限です。Utf7Imeとヘルパーライブラリ自身は、uiautomatorが動作する端末であれば問題なく動作します。 98 | 99 | License 100 | ------ 101 | Copyright 2013 TOYAMA Sumio <> 102 | Licensed under the 103 | [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0). 104 | 105 | This software contains 106 | [jutf7-1.0.0](http://sourceforge.net/projects/jutf7/) written by J.T. Beetstra, 107 | which is available under a MIT license. 108 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Uiautomator Unicode Input Helper 2 | ====================== 3 | (Japanese Version is [here](README.ja.md).) 4 | 5 | _Uiautomator Unicode Input Helper_ enables you to input any Unicode 6 | (including non-ASCII) characters by using Android 7 | [uiautomator](http://developer.android.com/tools/help/uiautomator/index.html). 8 | 9 | Uiautomator has 10 | [UiObject.setText(String)](http://developer.android.com/tools/help/uiautomator/UiObject.html#setText%28java.lang.String%29) 11 | API to set text in an editable field. 12 | The API works well if the text consists of only the ASCII character, 13 | but can not input any non-ASCII characters, such as Japanese. 14 | This limitation has prevented developers of non-English 15 | applications from using uiautomator for testing. 16 | 17 | Uiautomator Unicode Input Helper solves it by providing an IME, 18 | which converts encoded text using only ASCII characters into 19 | Unicode text. 20 | Modified UTF-7 ([RFC 3501](http://tools.ietf.org/html/rfc3501)) 21 | is used for the encoding scheme. 22 | 23 | Getting Started 24 | ------ 25 | ### Precaution 26 | _Utf7Ime_, which is installed by the following instructions, 27 | prevents you from inputting any text via software keyboard. 28 | **Do not use Utf7Ime as a human interface.** 29 | It is intended for only test automation. 30 | 31 | To avoid your confusion, change the default IME to your favorite 32 | one after using it: 33 | 34 | 1. Show home screen by tapping home key. 35 | 2. Launch ``Settings``. 36 | 3. Open ``Language & input``. 37 | 4. Tap ``Default`` belonging to ``KEYBOARD & INPUT METHODS`` 38 | category. 39 | 5. Select your favorite IME. 40 | 41 | ### Prerequisites 42 | #### Install Utf7Ime and change the default IME 43 | * Import ``Utf7Ime/`` directory into your Eclipse workspace. 44 | You can import by 45 | ``File -> Import... -> Existing Android Code Into Workspace``. 46 | * Build ``Utf7Ime`` project and install it on your 47 | Android-powered device (or emulator) for UI testing. 48 | * Launch ``Settings`` App in the device. 49 | * Open ``Language & input``. 50 | * Switch on the ``UTF7 IME for UI Testing`` checkbox belonging to 51 | ``KEYBOARD & INPUT METHODS`` category. 52 | * Tap ``Default`` belonging to ``KEYBOARD & INPUT METHODS`` 53 | category. 54 | * Change the default IME to Utf7Ime by selecting 55 | ``UTF7 IME for UI Testing``. 56 | 57 | #### Prepare your Uiautomator tests 58 | Prepare (or create) your test that runs in the uiautomator 59 | framework. 60 | If you have not written a test for uiautomator yet, you can see 61 | detailed instruction 62 | [here](http://developer.android.com/tools/testing/testing_ui.html). 63 | 64 | #### Copy the helper library to your Uiautomator project 65 | Copy ``helper-library/src/*`` to 66 | ``/src/``. 67 | Note that a uiautomator project does not recognize any JAR 68 | libraries in ``libs`` directory. 69 | 70 | ### Usage 71 | Apply ``Utf7ImeHelper.e()`` to a string used for 72 | ``UiObject.setText()``. Any Unicode (including non-ASCII) 73 | characters are accepted. 74 | 75 | ```java 76 | import jp.jun_nama.test.utf7ime.helper.Utf7ImeHelper; 77 | 78 | .... 79 | 80 | // gets UiObject which refers to editable text 81 | UiObject editText = ...; 82 | // inputs German umlaut characters 83 | editText.setText(Utf7ImeHelper.e("Danke schön")); 84 | // inputs Japanese characters 85 | editText.setText(Utf7ImeHelper.e("ありがとう")); 86 | .... 87 | ``` 88 | 89 | Note that you can set a string to ``UiObject.setText()`` 90 | directly as long as the string consists of only the ASCII 91 | characters **except ``&``**. 92 | 93 | ```java 94 | .... 95 | UiObject editText = ...; 96 | // inputs ASCII text not containing '&'. 97 | // Utf7ImeHelper.e() is not needed. 98 | editText.setText("Thank you very much."); 99 | 100 | // inputs ASCII text containing '&'. 101 | // You must use Utf7ImeHelper.e(). 102 | editText.setText(Utf7ImeHelper.e("fish & chips")); 103 | .... 104 | ``` 105 | 106 | ### Sample 107 | You can see a sample project which resides in 108 | ``UiAutomatorInputSample/`` directory. 109 | This sample code simulates the following instructions: 110 | 111 | * Press on the HOME button. 112 | * Launch the "Google" app. 113 | * Input Japanese sentences into Google search box. 114 | ![Result Screenshot](/images/sample-screenshot.png) 115 | 116 | #### How to run 117 | * Change the Locale of your testing device to ``English (United States)``. 118 | * Set ``ANDROID_HOME`` environment variable properly. 119 | * Connect your testing device. 120 | * Change directories to the root of the sample project. 121 | * Build and run by typing the following commands (ant is required): 122 | 123 | ant clean build install 124 | adb shell uiautomator runtest UiAutomatorInputSample.jar \ 125 | -c jp.jun_nama.test.utf7ime.sample.UiAutomatorInputTest 126 | 127 | The sample code is tested under Nexus7 (2013) based on Android 4.4. 128 | 129 | It is not run properly for Android emulators based on Android 4.3 130 | or earlier because the class name of Google search box is 131 | different. Rewrite search criteria in the sample code so that it 132 | can be run under such a device or emulator. 133 | 134 | Note that such restrictions are applied to only the sample code. 135 | Utf7Ime and the helper library are run properly under devices 136 | supporting uiautomator. 137 | 138 | License 139 | ------ 140 | Copyright 2013 TOYAMA Sumio <> 141 | Licensed under the 142 | [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0). 143 | 144 | This software contains 145 | [jutf7-1.0.0](http://sourceforge.net/projects/jutf7/) written by J.T. Beetstra, 146 | which is available under a MIT license. 147 | -------------------------------------------------------------------------------- /UiAutomatorInputSample/build.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | 29 | 30 | 31 | 35 | 36 | 37 | 38 | 39 | 40 | 49 | 50 | 51 | 52 | 56 | 57 | 69 | 70 | 71 | 89 | 90 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /UiAutomatorInputSample/project.properties: -------------------------------------------------------------------------------- 1 | # This file is automatically generated by Android Tools. 2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED! 3 | # 4 | # This file must be checked in Version Control Systems. 5 | # 6 | # To customize properties used by the Ant build system edit 7 | # "ant.properties", and override values to adapt the script to your 8 | # project structure. 9 | # 10 | # To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): 11 | #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt 12 | 13 | # Project target. 14 | target=android-17 15 | -------------------------------------------------------------------------------- /UiAutomatorInputSample/src/com/beetstra/jutf7/Base64Util.java: -------------------------------------------------------------------------------- 1 | /* ==================================================================== 2 | * Copyright (c) 2006 J.T. Beetstra 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 18 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 19 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 20 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 21 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | * ==================================================================== 23 | */ 24 | package com.beetstra.jutf7; 25 | 26 | import java.util.Arrays; 27 | 28 | /** 29 | *

Represent a base 64 mapping. The 64 characters used in the encoding can be specified, 30 | * since modified-UTF-7 uses other characters than UTF-7 (',' instead of '/').

31 | * 32 | *

The exact type of the arguments and result values is adapted to the needs of the 33 | * encoder and decoder, as opposed to following a strict interpretation of base 64.

34 | *

Base 64, as specified in RFC 2045, is an encoding used to encode bytes as characters. 35 | * In (modified-)UTF-7 however, it is used to encode characters as bytes, using some 36 | * intermediate steps:

37 | *
    38 | *
  1. Encode all characters as a 16-bit (UTF-16) integer value
  2. 39 | *
  3. Write this as stream of bytes (most-significant first)
  4. 40 | *
  5. Encode these bytes using (modified) base 64 encoding
  6. 41 | *
  7. Write the thus formed stream of characters as a stream of bytes, using ASCII encoding
  8. 42 | *
43 | * 44 | * @author Jaap Beetstra 45 | */ 46 | class Base64Util { 47 | private static final int ALPHABET_LENGTH = 64; 48 | private final char[] alphabet; 49 | private final int[] inverseAlphabet; 50 | 51 | /** 52 | * Initializes the class with the specified encoding/decoding alphabet. 53 | * 54 | * @param alphabet 55 | * @throws IllegalArgumentException if alphabet is not 64 characters long or 56 | * contains characters which are not 7-bit ASCII 57 | */ 58 | Base64Util(final String alphabet) { 59 | this.alphabet = alphabet.toCharArray(); 60 | if (alphabet.length() != ALPHABET_LENGTH) 61 | throw new IllegalArgumentException("alphabet has incorrect length (should be 64, not " 62 | + alphabet.length() + ")"); 63 | inverseAlphabet = new int[128]; 64 | Arrays.fill(inverseAlphabet, -1); 65 | for (int i = 0; i < this.alphabet.length; i++) { 66 | final char ch = this.alphabet[i]; 67 | if (ch >= 128) 68 | throw new IllegalArgumentException("invalid character in alphabet: " + ch); 69 | inverseAlphabet[ch] = i; 70 | } 71 | } 72 | 73 | /** 74 | * Returns the integer value of the six bits represented by the specified character. 75 | * 76 | * @param ch The character, as a ASCII encoded byte 77 | * @return The six bits, as an integer value, or -1 if the byte is not in the alphabet 78 | */ 79 | int getSextet(final byte ch) { 80 | if (ch >= 128) 81 | return -1; 82 | return inverseAlphabet[ch]; 83 | } 84 | 85 | /** 86 | * Tells whether the alphabet contains the specified character. 87 | * 88 | * @param ch The character 89 | * @return true if the alphabet contains ch, false otherwise 90 | */ 91 | boolean contains(final char ch) { 92 | if (ch >= 128) 93 | return false; 94 | return inverseAlphabet[ch] >= 0; 95 | } 96 | 97 | /** 98 | * Encodes the six bit group as a character. 99 | * 100 | * @param sextet The six bit group to be encoded 101 | * @return The ASCII value of the character 102 | */ 103 | byte getChar(final int sextet) { 104 | return (byte) alphabet[sextet]; 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /UiAutomatorInputSample/src/com/beetstra/jutf7/CharsetProvider.java: -------------------------------------------------------------------------------- 1 | /* ==================================================================== 2 | * Copyright (c) 2006 J.T. Beetstra 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 18 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 19 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 20 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 21 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | * ==================================================================== 23 | */ 24 | package com.beetstra.jutf7; 25 | 26 | import java.io.UnsupportedEncodingException; 27 | import java.nio.charset.Charset; 28 | import java.util.Arrays; 29 | import java.util.Iterator; 30 | import java.util.List; 31 | import java.util.Locale; 32 | 33 | /** 34 | *

Charset service-provider class used for both variants of the UTF-7 charset 35 | * and the modified-UTF-7 charset.

36 | * 37 | * @author Jaap Beetstra 38 | */ 39 | public class CharsetProvider extends java.nio.charset.spi.CharsetProvider { 40 | private static final String UTF7_NAME = "UTF-7"; 41 | private static final String UTF7_O_NAME = "X-UTF-7-OPTIONAL"; 42 | private static final String UTF7_M_NAME = "X-MODIFIED-UTF-7"; 43 | private static final String[] UTF7_ALIASES = new String[] { "UNICODE-1-1-UTF-7", 44 | "CSUNICODE11UTF7", "X-RFC2152", "X-RFC-2152" }; 45 | private static final String[] UTF7_O_ALIASES = new String[] { "X-RFC2152-OPTIONAL", 46 | "X-RFC-2152-OPTIONAL" }; 47 | private static final String[] UTF7_M_ALIASES = new String[] { "X-IMAP-MODIFIED-UTF-7", 48 | "X-IMAP4-MODIFIED-UTF7", "X-IMAP4-MODIFIED-UTF-7", "X-RFC3501", "X-RFC-3501" }; 49 | private Charset utf7charset = new UTF7Charset(UTF7_NAME, UTF7_ALIASES, false); 50 | private Charset utf7oCharset = new UTF7Charset(UTF7_O_NAME, UTF7_O_ALIASES, true); 51 | private Charset imap4charset = new ModifiedUTF7Charset(UTF7_M_NAME, UTF7_M_ALIASES); 52 | private List charsets; 53 | 54 | public CharsetProvider() { 55 | charsets = Arrays.asList(new Object[] { utf7charset, imap4charset, utf7oCharset }); 56 | } 57 | 58 | /** 59 | * {@inheritDoc} 60 | */ 61 | public Charset charsetForName(String charsetName) { 62 | charsetName = charsetName.toUpperCase(Locale.US); 63 | for (Iterator iter = charsets.iterator(); iter.hasNext();) { 64 | Charset charset = (Charset) iter.next(); 65 | if (charset.name().equals(charsetName)) 66 | return charset; 67 | } 68 | for (Iterator iter = charsets.iterator(); iter.hasNext();) { 69 | Charset charset = (Charset) iter.next(); 70 | if (charset.aliases().contains(charsetName)) 71 | return charset; 72 | } 73 | return null; 74 | } 75 | 76 | /** 77 | * {@inheritDoc} 78 | */ 79 | public Iterator charsets() { 80 | return charsets.iterator(); 81 | } 82 | 83 | public static void main(String[] args) throws UnsupportedEncodingException { 84 | if (args.length < 2) { 85 | showUsage(); 86 | } else if ("encode".equalsIgnoreCase(args[0])) { 87 | byte[] encoded = args[1].getBytes(UTF7_NAME); 88 | System.out.println(new String(encoded, "US-ASCII")); 89 | } else if ("decode".equalsIgnoreCase(args[0])) { 90 | byte[] bytes = args[1].getBytes("US-ASCII"); 91 | System.out.println(new String(bytes, UTF7_NAME)); 92 | } else 93 | showUsage(); 94 | } 95 | 96 | private static void showUsage() { 97 | System.out.println("Usage: java -jar jutf7.jar [encode|decode] "); 98 | System.out.println(); 99 | System.out.println("Example: java -jar jutf7 encode caf�"); 100 | System.out.println("Result: caf+AOk-"); 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /UiAutomatorInputSample/src/com/beetstra/jutf7/ModifiedUTF7Charset.java: -------------------------------------------------------------------------------- 1 | /* ==================================================================== 2 | * Copyright (c) 2006 J.T. Beetstra 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 18 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 19 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 20 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 21 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | * ==================================================================== 23 | */ 24 | package com.beetstra.jutf7; 25 | 26 | 27 | /** 28 | *

The character set specified in RFC 3501 to use for IMAP4rev1 mailbox name encoding.

29 | * 30 | * @see RFC 3501 31 | * @author Jaap Beetstra 32 | */ 33 | class ModifiedUTF7Charset extends UTF7StyleCharset { 34 | private static final String MODIFIED_BASE64_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 35 | + "abcdefghijklmnopqrstuvwxyz" + "0123456789+,"; 36 | 37 | ModifiedUTF7Charset(String name, String[] aliases) { 38 | super(name, aliases, MODIFIED_BASE64_ALPHABET, true); 39 | } 40 | 41 | boolean canEncodeDirectly(char ch) { 42 | if (ch == shift()) 43 | return false; 44 | return ch >= 0x20 && ch <= 0x7E; 45 | } 46 | 47 | byte shift() { 48 | return '&'; 49 | } 50 | 51 | byte unshift() { 52 | return '-'; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /UiAutomatorInputSample/src/com/beetstra/jutf7/UTF7Charset.java: -------------------------------------------------------------------------------- 1 | /* ==================================================================== 2 | * Copyright (c) 2006 J.T. Beetstra 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 18 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 19 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 20 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 21 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | * ==================================================================== 23 | */ 24 | package com.beetstra.jutf7; 25 | 26 | /** 27 | *

The character set specified in RFC 2152. Two variants are supported using the encodeOptional 28 | * constructor flag

29 | * 30 | * @see RFC 2152 31 | * @author Jaap Beetstra 32 | */ 33 | class UTF7Charset extends UTF7StyleCharset { 34 | private static final String BASE64_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 35 | + "abcdefghijklmnopqrstuvwxyz" + "0123456789+/"; 36 | private static final String SET_D = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'(),-./:?"; 37 | private static final String SET_O = "!\"#$%&*;<=>@[]^_`{|}"; 38 | private static final String RULE_3 = " \t\r\n"; 39 | final String directlyEncoded; 40 | 41 | UTF7Charset(String name, String[] aliases, boolean includeOptional) { 42 | super(name, aliases, BASE64_ALPHABET, false); 43 | if (includeOptional) 44 | this.directlyEncoded = SET_D + SET_O + RULE_3; 45 | else 46 | this.directlyEncoded = SET_D + RULE_3; 47 | } 48 | 49 | /* (non-Javadoc) 50 | * @see com.beetstra.jutf7.UTF7StyleCharset#canEncodeDirectly(char) 51 | */ 52 | boolean canEncodeDirectly(char ch) { 53 | return directlyEncoded.indexOf(ch) >= 0; 54 | } 55 | 56 | /* (non-Javadoc) 57 | * @see com.beetstra.jutf7.UTF7StyleCharset#shift() 58 | */ 59 | byte shift() { 60 | return '+'; 61 | } 62 | 63 | /* (non-Javadoc) 64 | * @see com.beetstra.jutf7.UTF7StyleCharset#unshift() 65 | */ 66 | byte unshift() { 67 | return '-'; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /UiAutomatorInputSample/src/com/beetstra/jutf7/UTF7StyleCharset.java: -------------------------------------------------------------------------------- 1 | /* ==================================================================== 2 | * Copyright (c) 2006 J.T. Beetstra 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 18 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 19 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 20 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 21 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | * ==================================================================== 23 | */ 24 | package com.beetstra.jutf7; 25 | 26 | import java.nio.charset.Charset; 27 | import java.nio.charset.CharsetDecoder; 28 | import java.nio.charset.CharsetEncoder; 29 | import java.util.Arrays; 30 | import java.util.List; 31 | 32 | /** 33 | *

Abstract base class for UTF-7 style encoding and decoding.

34 | * 35 | * @author Jaap Beetstra 36 | */ 37 | abstract class UTF7StyleCharset extends Charset { 38 | private static final List CONTAINED = Arrays.asList(new String[] { "US-ASCII", "ISO-8859-1", 39 | "UTF-8", "UTF-16", "UTF-16LE", "UTF-16BE" }); 40 | final boolean strict; 41 | Base64Util base64; 42 | 43 | /** 44 | *

Besides the name and aliases, two additional parameters are required. First the 45 | * base 64 alphabet used; in modified UTF-7 a slightly different alphabet is used. 46 | * Additionally, it should be specified if encoders and decoders should be strict 47 | * about the interpretation of malformed encoded sequences. This is used since 48 | * modified UTF-7 specifically disallows some constructs which are allowed (or not 49 | * specifically disallowed) in UTF-7 (RFC 2152).

50 | * 51 | * @param canonicalName The name as defined in java.nio.charset.Charset 52 | * @param aliases The aliases as defined in java.nio.charset.Charset 53 | * @param alphabet The base 64 alphabet used 54 | * @param strict True if strict handling of sequences is requested 55 | */ 56 | protected UTF7StyleCharset(String canonicalName, String[] aliases, String alphabet, 57 | boolean strict) { 58 | super(canonicalName, aliases); 59 | this.base64 = new Base64Util(alphabet); 60 | this.strict = strict; 61 | } 62 | 63 | /* (non-Javadoc) 64 | * @see java.nio.charset.Charset#contains(java.nio.charset.Charset) 65 | */ 66 | public boolean contains(final Charset cs) { 67 | return CONTAINED.contains(cs.name()); 68 | } 69 | 70 | /* (non-Javadoc) 71 | * @see java.nio.charset.Charset#newDecoder() 72 | */ 73 | public CharsetDecoder newDecoder() { 74 | return new UTF7StyleCharsetDecoder(this, base64, strict); 75 | } 76 | 77 | /* (non-Javadoc) 78 | * @see java.nio.charset.Charset#newEncoder() 79 | */ 80 | public CharsetEncoder newEncoder() { 81 | return new UTF7StyleCharsetEncoder(this, base64, strict); 82 | } 83 | 84 | /** 85 | * Tells if a character can be encoded using simple (US-ASCII) encoding or 86 | * requires base 64 encoding. 87 | * 88 | * @param ch The character 89 | * @return True if the character can be encoded directly, false otherwise 90 | */ 91 | abstract boolean canEncodeDirectly(char ch); 92 | 93 | /** 94 | * Returns character used to switch to base 64 encoding. 95 | * @return The shift character 96 | */ 97 | abstract byte shift(); 98 | 99 | /** 100 | * Returns character used to switch from base 64 encoding to simple encoding. 101 | * @return The unshift character 102 | */ 103 | abstract byte unshift(); 104 | } 105 | -------------------------------------------------------------------------------- /UiAutomatorInputSample/src/com/beetstra/jutf7/UTF7StyleCharsetDecoder.java: -------------------------------------------------------------------------------- 1 | /* ==================================================================== 2 | * Copyright (c) 2006 J.T. Beetstra 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 18 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 19 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 20 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 21 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | * ==================================================================== 23 | */ 24 | package com.beetstra.jutf7; 25 | 26 | import java.nio.ByteBuffer; 27 | import java.nio.CharBuffer; 28 | import java.nio.charset.CharsetDecoder; 29 | import java.nio.charset.CoderResult; 30 | 31 | /** 32 | *

The CharsetDecoder used to decode both variants of the UTF-7 charset and the 33 | * modified-UTF-7 charset.

34 | * 35 | * @author Jaap Beetstra 36 | */ 37 | class UTF7StyleCharsetDecoder extends CharsetDecoder { 38 | private final Base64Util base64; 39 | private final byte shift; 40 | private final byte unshift; 41 | private final boolean strict; 42 | private boolean base64mode; 43 | private int bitsRead; 44 | private int tempChar; 45 | private boolean justShifted; 46 | private boolean justUnshifted; 47 | 48 | UTF7StyleCharsetDecoder(UTF7StyleCharset cs, Base64Util base64, boolean strict) { 49 | super(cs, 0.6f, 1.0f); 50 | this.base64 = base64; 51 | this.strict = strict; 52 | this.shift = cs.shift(); 53 | this.unshift = cs.unshift(); 54 | } 55 | 56 | /* (non-Javadoc) 57 | * @see java.nio.charset.CharsetDecoder#decodeLoop(java.nio.ByteBuffer, java.nio.CharBuffer) 58 | */ 59 | protected CoderResult decodeLoop(ByteBuffer in, CharBuffer out) { 60 | while (in.hasRemaining()) { 61 | byte b = in.get(); 62 | if (base64mode) { 63 | if (b == unshift) { 64 | if (base64bitsWaiting()) 65 | return malformed(in); 66 | if (justShifted) { 67 | if (!out.hasRemaining()) 68 | return overflow(in); 69 | out.put((char) shift); 70 | } else 71 | justUnshifted = true; 72 | setUnshifted(); 73 | } else { 74 | if (!out.hasRemaining()) 75 | return overflow(in); 76 | CoderResult result = handleBase64(in, out, b); 77 | if (result != null) 78 | return result; 79 | } 80 | justShifted = false; 81 | } else { 82 | if (b == shift) { 83 | base64mode = true; 84 | if (justUnshifted && strict) 85 | return malformed(in); 86 | justShifted = true; 87 | continue; 88 | } 89 | if (!out.hasRemaining()) 90 | return overflow(in); 91 | out.put((char) b); 92 | justUnshifted = false; 93 | } 94 | } 95 | return CoderResult.UNDERFLOW; 96 | } 97 | 98 | private CoderResult overflow(ByteBuffer in) { 99 | in.position(in.position() - 1); 100 | return CoderResult.OVERFLOW; 101 | } 102 | 103 | /** 104 | *

Decodes a byte in base 64 mode. Will directly write a character to the output 105 | * buffer if completed.

106 | * 107 | * @param in The input buffer 108 | * @param out The output buffer 109 | * @param lastRead Last byte read from the input buffer 110 | * @return CoderResult.malformed if a non-base 64 character was encountered in strict 111 | * mode, null otherwise 112 | */ 113 | private CoderResult handleBase64(ByteBuffer in, CharBuffer out, byte lastRead) { 114 | CoderResult result = null; 115 | int sextet = base64.getSextet(lastRead); 116 | if (sextet >= 0) { 117 | bitsRead += 6; 118 | if (bitsRead < 16) { 119 | tempChar += sextet << (16 - bitsRead); 120 | } else { 121 | bitsRead -= 16; 122 | tempChar += sextet >> (bitsRead); 123 | out.put((char) tempChar); 124 | tempChar = (sextet << (16 - bitsRead)) & 0xFFFF; 125 | } 126 | } else { 127 | if (strict) 128 | return malformed(in); 129 | out.put((char) lastRead); 130 | if (base64bitsWaiting()) 131 | result = malformed(in); 132 | setUnshifted(); 133 | } 134 | return result; 135 | } 136 | 137 | /* (non-Javadoc) 138 | * @see java.nio.charset.CharsetDecoder#implFlush(java.nio.CharBuffer) 139 | */ 140 | protected CoderResult implFlush(CharBuffer out) { 141 | if ((base64mode && strict) || base64bitsWaiting()) 142 | return CoderResult.malformedForLength(1); 143 | return CoderResult.UNDERFLOW; 144 | } 145 | 146 | /* (non-Javadoc) 147 | * @see java.nio.charset.CharsetDecoder#implReset() 148 | */ 149 | protected void implReset() { 150 | setUnshifted(); 151 | justUnshifted = false; 152 | } 153 | 154 | /** 155 | *

Resets the input buffer position to just before the last byte read, and returns 156 | * a result indicating to skip the last byte.

157 | * 158 | * @param in The input buffer 159 | * @return CoderResult.malformedForLength(1); 160 | */ 161 | private CoderResult malformed(ByteBuffer in) { 162 | in.position(in.position() - 1); 163 | return CoderResult.malformedForLength(1); 164 | } 165 | 166 | /** 167 | * @return True if there are base64 encoded characters waiting to be written 168 | */ 169 | private boolean base64bitsWaiting() { 170 | return tempChar != 0 || bitsRead >= 6; 171 | } 172 | 173 | /** 174 | *

Updates internal state to reflect the decoder is no longer in base 64 175 | * mode

176 | */ 177 | private void setUnshifted() { 178 | base64mode = false; 179 | bitsRead = 0; 180 | tempChar = 0; 181 | } 182 | } -------------------------------------------------------------------------------- /UiAutomatorInputSample/src/com/beetstra/jutf7/UTF7StyleCharsetEncoder.java: -------------------------------------------------------------------------------- 1 | /* ==================================================================== 2 | * Copyright (c) 2006 J.T. Beetstra 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 18 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 19 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 20 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 21 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | * ==================================================================== 23 | */ 24 | package com.beetstra.jutf7; 25 | 26 | import java.nio.ByteBuffer; 27 | import java.nio.CharBuffer; 28 | import java.nio.charset.CharsetEncoder; 29 | import java.nio.charset.CoderResult; 30 | 31 | /** 32 | *

The CharsetEncoder used to encode both variants of the UTF-7 charset and the 33 | * modified-UTF-7 charset.

34 | * 35 | *

Please note this class does not behave strictly according to the specification in 36 | * Sun Java VMs before 1.6. This is done to get around a bug in the implementation 37 | * of {@link java.nio.charset.CharsetEncoder#encode(CharBuffer)}. Unfortunately, that method 38 | * cannot be overridden.

39 | * 40 | * @see JDK bug 6221056 41 | * 42 | * @author Jaap Beetstra 43 | */ 44 | class UTF7StyleCharsetEncoder extends CharsetEncoder { 45 | private static final float AVG_BYTES_PER_CHAR = 1.5f; 46 | private static final float MAX_BYTES_PER_CHAR = 5.0f; 47 | private final UTF7StyleCharset cs; 48 | private final Base64Util base64; 49 | private final byte shift; 50 | private final byte unshift; 51 | private final boolean strict; 52 | private boolean base64mode; 53 | private int bitsToOutput; 54 | private int sextet; 55 | static boolean useUglyHackToForceCallToFlushInJava5; 56 | static { 57 | String version = System.getProperty("java.specification.version"); 58 | String vendor = System.getProperty("java.vm.vendor"); 59 | useUglyHackToForceCallToFlushInJava5 = "1.4".equals(version) || "1.5".equals(version); 60 | useUglyHackToForceCallToFlushInJava5 &= "Sun Microsystems Inc.".equals(vendor); 61 | } 62 | 63 | UTF7StyleCharsetEncoder(UTF7StyleCharset cs, Base64Util base64, boolean strict) { 64 | super(cs, AVG_BYTES_PER_CHAR, MAX_BYTES_PER_CHAR); 65 | this.cs = cs; 66 | this.base64 = base64; 67 | this.strict = strict; 68 | this.shift = cs.shift(); 69 | this.unshift = cs.unshift(); 70 | } 71 | 72 | /* (non-Javadoc) 73 | * @see java.nio.charset.CharsetEncoder#implReset() 74 | */ 75 | protected void implReset() { 76 | base64mode = false; 77 | sextet = 0; 78 | bitsToOutput = 0; 79 | } 80 | 81 | /** 82 | * {@inheritDoc} 83 | * 84 | *

Note that this method might return CoderResult.OVERFLOW (as is 85 | * required by the specification) if insufficient space is available in the output 86 | * buffer. However, calling it again on JDKs before Java 6 triggers a bug in 87 | * {@link java.nio.charset.CharsetEncoder#flush(ByteBuffer)} causing it to throw an 88 | * IllegalStateException (the buggy method is final, thus cannot be 89 | * overridden).

90 | * 91 | * @see JDK bug 6227608 92 | * @param out The output byte buffer 93 | * @return A coder-result object describing the reason for termination 94 | */ 95 | protected CoderResult implFlush(ByteBuffer out) { 96 | if (base64mode) { 97 | if (out.remaining() < 2) 98 | return CoderResult.OVERFLOW; 99 | if (bitsToOutput != 0) 100 | out.put(base64.getChar(sextet)); 101 | out.put(unshift); 102 | } 103 | return CoderResult.UNDERFLOW; 104 | } 105 | 106 | /** 107 | * {@inheritDoc} 108 | * 109 | *

Note that this method might return CoderResult.OVERFLOW, even 110 | * though there is sufficient space available in the output buffer. This is done 111 | * to force the broken implementation of 112 | * {@link java.nio.charset.CharsetEncoder#encode(CharBuffer)} to call flush 113 | * (the buggy method is final, thus cannot be overridden).

114 | *

However, String.getBytes() fails if CoderResult.OVERFLOW is returned, since 115 | * this assumes it always allocates sufficient bytes (maxBytesPerChar * nr_of_chars). 116 | * Thus, as an extra check, the size of the input buffer is compared against the size 117 | * of the output buffer. 118 | * A static variable is used to indicate if a broken java version is used.

119 | *

It is not possible to directly write the last few bytes, since more bytes 120 | * might be waiting to be encoded then those available in the input buffer.

121 | * 122 | * @see JDK bug 6221056 123 | * @param in The input character buffer 124 | * @param out The output byte buffer 125 | * @return A coder-result object describing the reason for termination 126 | */ 127 | protected CoderResult encodeLoop(CharBuffer in, ByteBuffer out) { 128 | while (in.hasRemaining()) { 129 | if (out.remaining() < 4) 130 | return CoderResult.OVERFLOW; 131 | char ch = in.get(); 132 | if (cs.canEncodeDirectly(ch)) { 133 | unshift(out, ch); 134 | out.put((byte) ch); 135 | } else if (!base64mode && ch == shift) { 136 | out.put(shift); 137 | out.put(unshift); 138 | } else 139 | encodeBase64(ch, out); 140 | } 141 | /* 142 | These lines are required to trick JDK 1.5 and earlier into flushing when using 143 | Charset.encode(String), Charset.encode(CharBuffer) or CharsetEncoder.encode(CharBuffer) 144 | Without them, the last few bytes may be missing. 145 | */ 146 | if (base64mode && useUglyHackToForceCallToFlushInJava5 147 | && out.limit() != MAX_BYTES_PER_CHAR * in.limit()) 148 | return CoderResult.OVERFLOW; 149 | /* */ 150 | return CoderResult.UNDERFLOW; 151 | } 152 | 153 | /** 154 | *

Writes the bytes necessary to leave base 64 mode. This might include an unshift 155 | * character.

156 | * 157 | * @param out 158 | * @param ch 159 | */ 160 | private void unshift(ByteBuffer out, char ch) { 161 | if (!base64mode) 162 | return; 163 | if (bitsToOutput != 0) 164 | out.put(base64.getChar(sextet)); 165 | if (base64.contains(ch) || ch == unshift || strict) 166 | out.put(unshift); 167 | base64mode = false; 168 | sextet = 0; 169 | bitsToOutput = 0; 170 | } 171 | 172 | /** 173 | *

Writes the bytes necessary to encode a character in base 64 mode. All bytes 174 | * which are fully determined will be written. The fields bitsToOutput and 175 | * sextet are used to remember the bytes not yet fully determined.

176 | * 177 | * @param out 178 | * @param ch 179 | */ 180 | private void encodeBase64(char ch, ByteBuffer out) { 181 | if (!base64mode) 182 | out.put(shift); 183 | base64mode = true; 184 | bitsToOutput += 16; 185 | while (bitsToOutput >= 6) { 186 | bitsToOutput -= 6; 187 | sextet += (ch >> bitsToOutput); 188 | sextet &= 0x3F; 189 | out.put(base64.getChar(sextet)); 190 | sextet = 0; 191 | } 192 | sextet = (ch << (6 - bitsToOutput)) & 0x3F; 193 | } 194 | } -------------------------------------------------------------------------------- /UiAutomatorInputSample/src/jp/jun_nama/test/utf7ime/helper/Utf7ImeHelper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 TOYAMA Sumio 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * ---- 17 | * getBytes(), encode() and allocateMore() are modifications based on 18 | * work copyrighted and licensed as follows: 19 | * 20 | * Licensed to the Apache Software Foundation (ASF) under one or more 21 | * contributor license agreements. See the NOTICE file distributed with 22 | * this work for additional information regarding copyright ownership. 23 | * The ASF licenses this file to You under the Apache License, Version 2.0 24 | * (the "License"); you may not use this file except in compliance with 25 | * the License. You may obtain a copy of the License at 26 | * 27 | * http://www.apache.org/licenses/LICENSE-2.0 28 | * 29 | * Unless required by applicable law or agreed to in writing, software 30 | * distributed under the License is distributed on an "AS IS" BASIS, 31 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 32 | * See the License for the specific language governing permissions and 33 | * limitations under the License. 34 | */ 35 | package jp.jun_nama.test.utf7ime.helper; 36 | 37 | import java.nio.ByteBuffer; 38 | import java.nio.CharBuffer; 39 | import java.nio.charset.Charset; 40 | import java.nio.charset.CharsetEncoder; 41 | import java.nio.charset.CoderResult; 42 | import java.nio.charset.CodingErrorAction; 43 | 44 | import com.beetstra.jutf7.CharsetProvider; 45 | 46 | /** 47 | * Utf7ImeHelper provides a simple Modified UTF-7 encoder.
48 | * If you use it in uiautomator, you can write simply as follows: 49 | * 50 | *
 51 |  * ....
 52 |  * 
 53 |  * UiObject editText = ...; 
 54 |  * editText.setText(Utf7ImeHelper.e("こんにちは")); // any Unicode String
 55 |  * 
 56 |  * ....
 57 |  * 
58 | * 59 | * @author TOYAMA Sumio 60 | * 61 | */ 62 | public class Utf7ImeHelper { 63 | 64 | private static final Charset CHARSET_MODIFIED_UTF7 = new CharsetProvider().charsetForName("X-MODIFIED-UTF-7"); 65 | 66 | /** 67 | * Encodes the specified text into modified UTF-7. 68 | * 69 | * @param text 70 | * plain unicode text 71 | * @return encoded text in modified UTF-7. 72 | */ 73 | public static String e(String text) { 74 | byte[] encoded = getBytes(text, CHARSET_MODIFIED_UTF7); 75 | return new String(encoded, Charset.forName("US-ASCII")); 76 | } 77 | 78 | /** 79 | * Returns a new byte array containing the characters of the specified 80 | * string encoded using the given charset. 81 | * 82 | * It is equivalent to input.getBytes(charset) except it has 83 | * workaround for the bug ID 61917. 84 | * 85 | * @see https://code.google.com/p/android/issues/detail?id=61917 86 | */ 87 | //@formatter:off 88 | /* 89 | * The original code is available from 90 | * https://android.googlesource.com/platform/libcore/+/master/libdvm/src/main/java/java/lang/String.java 91 | */ 92 | //@formatter:on 93 | public static byte[] getBytes(String input, Charset charset) { 94 | CharBuffer chars = CharBuffer.wrap(input.toCharArray()); 95 | // @formatter:off 96 | CharsetEncoder encoder = charset.newEncoder() 97 | .onMalformedInput(CodingErrorAction.REPLACE) 98 | .onUnmappableCharacter(CodingErrorAction.REPLACE); 99 | // @formatter:on 100 | ByteBuffer buffer; 101 | buffer = encode(chars.asReadOnlyBuffer(), encoder); 102 | byte[] bytes = new byte[buffer.limit()]; 103 | buffer.get(bytes); 104 | return bytes; 105 | 106 | } 107 | 108 | //@formatter:off 109 | /* 110 | * The original code is available from 111 | * https://android.googlesource.com/platform/libcore/+/master/luni/src/main/java/java/nio/charset/CharsetEncoder.java 112 | */ 113 | //@formatter:on 114 | private static ByteBuffer encode(CharBuffer in, CharsetEncoder encoder) { 115 | int length = (int) (in.remaining() * (double) encoder.averageBytesPerChar()); 116 | ByteBuffer out = ByteBuffer.allocate(length); 117 | 118 | encoder.reset(); 119 | CoderResult flushResult = null; 120 | 121 | while (flushResult != CoderResult.UNDERFLOW) { 122 | CoderResult encodeResult = encoder.encode(in, out, true); 123 | if (encodeResult == CoderResult.OVERFLOW) { 124 | out = allocateMore(out); 125 | continue; 126 | } 127 | 128 | flushResult = encoder.flush(out); 129 | if (flushResult == CoderResult.OVERFLOW) { 130 | out = allocateMore(out); 131 | } 132 | } 133 | 134 | out.flip(); 135 | return out; 136 | } 137 | 138 | //@formatter:off 139 | /* 140 | * The original code is available from 141 | * https://android.googlesource.com/platform/libcore/+/master/luni/src/main/java/java/nio/charset/CharsetEncoder.java 142 | */ 143 | //@formatter:on 144 | private static ByteBuffer allocateMore(ByteBuffer output) { 145 | if (output.capacity() == 0) { 146 | return ByteBuffer.allocate(1); 147 | } 148 | ByteBuffer result = ByteBuffer.allocate(output.capacity() * 2); 149 | output.flip(); 150 | result.put(output); 151 | return result; 152 | } 153 | 154 | } 155 | -------------------------------------------------------------------------------- /UiAutomatorInputSample/src/jp/jun_nama/test/utf7ime/sample/UiAutomatorInputTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 TOYAMA Sumio 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package jp.jun_nama.test.utf7ime.sample; 17 | 18 | import jp.jun_nama.test.utf7ime.helper.Utf7ImeHelper; 19 | 20 | import com.android.uiautomator.core.UiObject; 21 | import com.android.uiautomator.core.UiObjectNotFoundException; 22 | import com.android.uiautomator.core.UiScrollable; 23 | import com.android.uiautomator.core.UiSelector; 24 | import com.android.uiautomator.testrunner.UiAutomatorTestCase; 25 | 26 | public class UiAutomatorInputTest extends UiAutomatorTestCase { 27 | public void testDemo() throws UiObjectNotFoundException { 28 | 29 | // Press on the HOME button. 30 | getUiDevice().pressHome(); 31 | 32 | // Launch the "Google" apps via the All Apps screen. 33 | UiObject allAppsButton = new UiObject(new UiSelector().description("Apps")); 34 | allAppsButton.clickAndWaitForNewWindow(); 35 | UiObject appsTab = new UiObject(new UiSelector().text("Apps")); 36 | appsTab.click(); 37 | UiScrollable appViews = new UiScrollable(new UiSelector().scrollable(true)); 38 | appViews.setAsHorizontalList(); 39 | UiObject testApp = appViews.getChildByText(new UiSelector().className(android.widget.TextView.class.getName()), 40 | "Google"); 41 | testApp.clickAndWaitForNewWindow(); 42 | 43 | // Get the google search text box 44 | UiObject searchBox = new UiObject( 45 | new UiSelector().className("com.google.android.search.shared.ui.SimpleSearchText")); 46 | 47 | // do Japanese Input! 48 | searchBox.setText(Utf7ImeHelper.e("こんにちは!UiAutomatorで入力しています。")); 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /Utf7Ime/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 18 | 19 | 23 | 24 | 27 | 28 | 33 | 37 | 38 | 39 | 40 | 41 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /Utf7Ime/libs/jutf7-1.0.0.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sumio/uiautomator-unicode-input-helper/791abc5a1a0b6dc25c39f011cf3b1f1fc3ec3df6/Utf7Ime/libs/jutf7-1.0.0.jar -------------------------------------------------------------------------------- /Utf7Ime/proguard-project.txt: -------------------------------------------------------------------------------- 1 | # To enable ProGuard in your project, edit project.properties 2 | # to define the proguard.config property as described in that file. 3 | # 4 | # Add project specific ProGuard rules here. 5 | # By default, the flags in this file are appended to flags specified 6 | # in ${sdk.dir}/tools/proguard/proguard-android.txt 7 | # You can edit the include path and order by changing the ProGuard 8 | # include property in project.properties. 9 | # 10 | # For more details, see 11 | # http://developer.android.com/guide/developing/tools/proguard.html 12 | 13 | # Add any project specific keep options here: 14 | 15 | # If your project uses WebView with JS, uncomment the following 16 | # and specify the fully qualified class name to the JavaScript interface 17 | # class: 18 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 19 | # public *; 20 | #} 21 | -------------------------------------------------------------------------------- /Utf7Ime/project.properties: -------------------------------------------------------------------------------- 1 | # This file is automatically generated by Android Tools. 2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED! 3 | # 4 | # This file must be checked in Version Control Systems. 5 | # 6 | # To customize properties used by the Ant build system edit 7 | # "ant.properties", and override values to adapt the script to your 8 | # project structure. 9 | # 10 | # To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): 11 | #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt 12 | 13 | # Project target. 14 | target=android-18 15 | -------------------------------------------------------------------------------- /Utf7Ime/res/drawable-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sumio/uiautomator-unicode-input-helper/791abc5a1a0b6dc25c39f011cf3b1f1fc3ec3df6/Utf7Ime/res/drawable-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /Utf7Ime/res/drawable-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sumio/uiautomator-unicode-input-helper/791abc5a1a0b6dc25c39f011cf3b1f1fc3ec3df6/Utf7Ime/res/drawable-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /Utf7Ime/res/drawable-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sumio/uiautomator-unicode-input-helper/791abc5a1a0b6dc25c39f011cf3b1f1fc3ec3df6/Utf7Ime/res/drawable-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /Utf7Ime/res/values-v11/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /Utf7Ime/res/values-v14/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /Utf7Ime/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | UTF7 IME for UI Testing 4 | 5 | 6 | -------------------------------------------------------------------------------- /Utf7Ime/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 14 | 15 | 16 | 19 | 20 | -------------------------------------------------------------------------------- /Utf7Ime/res/xml/method.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 18 | 19 | -------------------------------------------------------------------------------- /Utf7Ime/src/jp/jun_nama/test/utf7ime/Utf7ImeService.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 TOYAMA Sumio 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package jp.jun_nama.test.utf7ime; 17 | 18 | import java.nio.charset.Charset; 19 | 20 | import android.inputmethodservice.InputMethodService; 21 | import android.text.method.MetaKeyKeyListener; 22 | import android.view.KeyEvent; 23 | import android.view.inputmethod.EditorInfo; 24 | import android.view.inputmethod.InputConnection; 25 | 26 | import com.beetstra.jutf7.CharsetProvider; 27 | 28 | /** 29 | *

30 | * Utf7ImeService enables users to input any Unicode character by using only the 31 | * hardware keyboard. The selection of word candidates is not necessary.
32 | * Using automated testing tools such as Uiautomator, it is impossible to input 33 | * non-ASCII characters directly. Utf7ImeService helps you to input any 34 | * characters by using Uiautomator. 35 | *

36 | *

37 | * String that is input from the keyboard, must be encoded in Modified UTF-7 38 | * (see RFC 3501). 39 | *

40 | * 41 | * @author TOYAMA Sumio 42 | * 43 | */ 44 | public class Utf7ImeService extends InputMethodService { 45 | 46 | private static final String TAG = "Utf7ImeService"; 47 | 48 | /** Expected encoding for hardware key input. */ 49 | private static final String CHARSET_MODIFIED_UTF7 = "X-MODIFIED-UTF-7"; 50 | 51 | /** Special character to shift to Modified BASE64 in modified UTF-7. */ 52 | private static final char MODIFIED_UTF7_SHIFT = '&'; 53 | 54 | /** Special character to shift back to US-ASCII in modified UTF-7. */ 55 | private static final char MODIFIED_UTF7_UNSHIFT = '-'; 56 | 57 | /** Indicates if current UTF-7 state is Modified BASE64 or not. */ 58 | private boolean mIsShifted; 59 | private long mMetaState; 60 | private StringBuilder mComposing; 61 | 62 | private Charset mModifiedUtf7Charset; 63 | 64 | @Override 65 | public void onStartInput(EditorInfo attribute, boolean restarting) { 66 | super.onStartInput(attribute, restarting); 67 | 68 | if (!restarting) { 69 | mMetaState = 0; 70 | mIsShifted = false; 71 | mModifiedUtf7Charset = new CharsetProvider().charsetForName(CHARSET_MODIFIED_UTF7); 72 | } 73 | mComposing = null; 74 | 75 | } 76 | 77 | @Override 78 | public void onFinishInput() { 79 | super.onFinishInput(); 80 | mModifiedUtf7Charset = null; 81 | mComposing = null; 82 | } 83 | 84 | @Override 85 | public boolean onEvaluateFullscreenMode() { 86 | return false; 87 | } 88 | 89 | @Override 90 | public boolean onEvaluateInputViewShown() { 91 | return false; 92 | } 93 | 94 | /** 95 | * Translates key events encoded in modified UTF-7 into Unicode text. 96 | */ 97 | @Override 98 | public boolean onKeyDown(int keyCode, KeyEvent event) { 99 | // Log.d(TAG, String.format("onKeyDown(): keyCode = %x", keyCode)); 100 | int c = getUnicodeChar(keyCode, event); 101 | 102 | if (c == 0) { 103 | return super.onKeyDown(keyCode, event); 104 | } 105 | 106 | // Log.d(TAG, String.format("onKeyDown(): char = %c [%x]", c, c)); 107 | 108 | if (!mIsShifted) { 109 | if (c == MODIFIED_UTF7_SHIFT) { 110 | toShifted(); 111 | return true; 112 | } else if (isAsciiPrintable(c)) { 113 | commitCharacter(c); 114 | return true; 115 | } 116 | // In unshifted (direct encoding) state, any non-printable character 117 | // is sent directly. 118 | return super.onKeyDown(keyCode, event); 119 | } 120 | 121 | // Shifted State 122 | if (c == MODIFIED_UTF7_UNSHIFT) { 123 | toUnshifted(); 124 | } else { 125 | appendComposing(c); 126 | } 127 | return true; 128 | } 129 | 130 | @Override 131 | public boolean onKeyUp(int keyCode, KeyEvent event) { 132 | // Log.d(TAG, String.format("onKeyUp (%x)", keyCode)); 133 | mMetaState = MetaKeyKeyListener.handleKeyUp(mMetaState, keyCode, event); 134 | return super.onKeyUp(keyCode, event); 135 | } 136 | 137 | private void toShifted() { 138 | // Log.d(TAG, "SHIFTED!!"); 139 | mIsShifted = true; 140 | mComposing = new StringBuilder(); 141 | appendComposing(MODIFIED_UTF7_SHIFT); 142 | } 143 | 144 | private void toUnshifted() { 145 | // Log.d(TAG, "toUnshifted()"); 146 | mIsShifted = false; 147 | mComposing.append(MODIFIED_UTF7_UNSHIFT); 148 | String decoded = decodeUtf7(mComposing.toString()); 149 | InputConnection ic = getCurrentInputConnection(); 150 | ic.commitText(decoded, 1); 151 | mComposing = null; 152 | } 153 | 154 | private int getUnicodeChar(int keyCode, KeyEvent event) { 155 | mMetaState = MetaKeyKeyListener.handleKeyDown(mMetaState, keyCode, event); 156 | int c = event.getUnicodeChar(MetaKeyKeyListener.getMetaState(mMetaState)); 157 | mMetaState = MetaKeyKeyListener.adjustMetaAfterKeypress(mMetaState); 158 | return c; 159 | } 160 | 161 | private void commitCharacter(int c) { 162 | getCurrentInputConnection().commitText(String.valueOf((char) c), 1); 163 | } 164 | 165 | private void appendComposing(int c) { 166 | mComposing.append((char) c); 167 | getCurrentInputConnection().setComposingText(mComposing, 1); 168 | } 169 | 170 | private String decodeUtf7(String encStr) { 171 | byte[] encoded = encStr.getBytes(Charset.forName("US-ASCII")); 172 | return new String(encoded, mModifiedUtf7Charset); 173 | } 174 | 175 | private boolean isAsciiPrintable(int c) { 176 | return c >= 0x20 && c <= 0x7E; 177 | } 178 | 179 | } 180 | -------------------------------------------------------------------------------- /helper-library/src/com/beetstra/jutf7/Base64Util.java: -------------------------------------------------------------------------------- 1 | /* ==================================================================== 2 | * Copyright (c) 2006 J.T. Beetstra 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 18 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 19 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 20 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 21 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | * ==================================================================== 23 | */ 24 | package com.beetstra.jutf7; 25 | 26 | import java.util.Arrays; 27 | 28 | /** 29 | *

Represent a base 64 mapping. The 64 characters used in the encoding can be specified, 30 | * since modified-UTF-7 uses other characters than UTF-7 (',' instead of '/').

31 | * 32 | *

The exact type of the arguments and result values is adapted to the needs of the 33 | * encoder and decoder, as opposed to following a strict interpretation of base 64.

34 | *

Base 64, as specified in RFC 2045, is an encoding used to encode bytes as characters. 35 | * In (modified-)UTF-7 however, it is used to encode characters as bytes, using some 36 | * intermediate steps:

37 | *
    38 | *
  1. Encode all characters as a 16-bit (UTF-16) integer value
  2. 39 | *
  3. Write this as stream of bytes (most-significant first)
  4. 40 | *
  5. Encode these bytes using (modified) base 64 encoding
  6. 41 | *
  7. Write the thus formed stream of characters as a stream of bytes, using ASCII encoding
  8. 42 | *
43 | * 44 | * @author Jaap Beetstra 45 | */ 46 | class Base64Util { 47 | private static final int ALPHABET_LENGTH = 64; 48 | private final char[] alphabet; 49 | private final int[] inverseAlphabet; 50 | 51 | /** 52 | * Initializes the class with the specified encoding/decoding alphabet. 53 | * 54 | * @param alphabet 55 | * @throws IllegalArgumentException if alphabet is not 64 characters long or 56 | * contains characters which are not 7-bit ASCII 57 | */ 58 | Base64Util(final String alphabet) { 59 | this.alphabet = alphabet.toCharArray(); 60 | if (alphabet.length() != ALPHABET_LENGTH) 61 | throw new IllegalArgumentException("alphabet has incorrect length (should be 64, not " 62 | + alphabet.length() + ")"); 63 | inverseAlphabet = new int[128]; 64 | Arrays.fill(inverseAlphabet, -1); 65 | for (int i = 0; i < this.alphabet.length; i++) { 66 | final char ch = this.alphabet[i]; 67 | if (ch >= 128) 68 | throw new IllegalArgumentException("invalid character in alphabet: " + ch); 69 | inverseAlphabet[ch] = i; 70 | } 71 | } 72 | 73 | /** 74 | * Returns the integer value of the six bits represented by the specified character. 75 | * 76 | * @param ch The character, as a ASCII encoded byte 77 | * @return The six bits, as an integer value, or -1 if the byte is not in the alphabet 78 | */ 79 | int getSextet(final byte ch) { 80 | if (ch >= 128) 81 | return -1; 82 | return inverseAlphabet[ch]; 83 | } 84 | 85 | /** 86 | * Tells whether the alphabet contains the specified character. 87 | * 88 | * @param ch The character 89 | * @return true if the alphabet contains ch, false otherwise 90 | */ 91 | boolean contains(final char ch) { 92 | if (ch >= 128) 93 | return false; 94 | return inverseAlphabet[ch] >= 0; 95 | } 96 | 97 | /** 98 | * Encodes the six bit group as a character. 99 | * 100 | * @param sextet The six bit group to be encoded 101 | * @return The ASCII value of the character 102 | */ 103 | byte getChar(final int sextet) { 104 | return (byte) alphabet[sextet]; 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /helper-library/src/com/beetstra/jutf7/CharsetProvider.java: -------------------------------------------------------------------------------- 1 | /* ==================================================================== 2 | * Copyright (c) 2006 J.T. Beetstra 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 18 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 19 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 20 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 21 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | * ==================================================================== 23 | */ 24 | package com.beetstra.jutf7; 25 | 26 | import java.io.UnsupportedEncodingException; 27 | import java.nio.charset.Charset; 28 | import java.util.Arrays; 29 | import java.util.Iterator; 30 | import java.util.List; 31 | import java.util.Locale; 32 | 33 | /** 34 | *

Charset service-provider class used for both variants of the UTF-7 charset 35 | * and the modified-UTF-7 charset.

36 | * 37 | * @author Jaap Beetstra 38 | */ 39 | public class CharsetProvider extends java.nio.charset.spi.CharsetProvider { 40 | private static final String UTF7_NAME = "UTF-7"; 41 | private static final String UTF7_O_NAME = "X-UTF-7-OPTIONAL"; 42 | private static final String UTF7_M_NAME = "X-MODIFIED-UTF-7"; 43 | private static final String[] UTF7_ALIASES = new String[] { "UNICODE-1-1-UTF-7", 44 | "CSUNICODE11UTF7", "X-RFC2152", "X-RFC-2152" }; 45 | private static final String[] UTF7_O_ALIASES = new String[] { "X-RFC2152-OPTIONAL", 46 | "X-RFC-2152-OPTIONAL" }; 47 | private static final String[] UTF7_M_ALIASES = new String[] { "X-IMAP-MODIFIED-UTF-7", 48 | "X-IMAP4-MODIFIED-UTF7", "X-IMAP4-MODIFIED-UTF-7", "X-RFC3501", "X-RFC-3501" }; 49 | private Charset utf7charset = new UTF7Charset(UTF7_NAME, UTF7_ALIASES, false); 50 | private Charset utf7oCharset = new UTF7Charset(UTF7_O_NAME, UTF7_O_ALIASES, true); 51 | private Charset imap4charset = new ModifiedUTF7Charset(UTF7_M_NAME, UTF7_M_ALIASES); 52 | private List charsets; 53 | 54 | public CharsetProvider() { 55 | charsets = Arrays.asList(new Object[] { utf7charset, imap4charset, utf7oCharset }); 56 | } 57 | 58 | /** 59 | * {@inheritDoc} 60 | */ 61 | public Charset charsetForName(String charsetName) { 62 | charsetName = charsetName.toUpperCase(Locale.US); 63 | for (Iterator iter = charsets.iterator(); iter.hasNext();) { 64 | Charset charset = (Charset) iter.next(); 65 | if (charset.name().equals(charsetName)) 66 | return charset; 67 | } 68 | for (Iterator iter = charsets.iterator(); iter.hasNext();) { 69 | Charset charset = (Charset) iter.next(); 70 | if (charset.aliases().contains(charsetName)) 71 | return charset; 72 | } 73 | return null; 74 | } 75 | 76 | /** 77 | * {@inheritDoc} 78 | */ 79 | public Iterator charsets() { 80 | return charsets.iterator(); 81 | } 82 | 83 | public static void main(String[] args) throws UnsupportedEncodingException { 84 | if (args.length < 2) { 85 | showUsage(); 86 | } else if ("encode".equalsIgnoreCase(args[0])) { 87 | byte[] encoded = args[1].getBytes(UTF7_NAME); 88 | System.out.println(new String(encoded, "US-ASCII")); 89 | } else if ("decode".equalsIgnoreCase(args[0])) { 90 | byte[] bytes = args[1].getBytes("US-ASCII"); 91 | System.out.println(new String(bytes, UTF7_NAME)); 92 | } else 93 | showUsage(); 94 | } 95 | 96 | private static void showUsage() { 97 | System.out.println("Usage: java -jar jutf7.jar [encode|decode] "); 98 | System.out.println(); 99 | System.out.println("Example: java -jar jutf7 encode caf�"); 100 | System.out.println("Result: caf+AOk-"); 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /helper-library/src/com/beetstra/jutf7/ModifiedUTF7Charset.java: -------------------------------------------------------------------------------- 1 | /* ==================================================================== 2 | * Copyright (c) 2006 J.T. Beetstra 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 18 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 19 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 20 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 21 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | * ==================================================================== 23 | */ 24 | package com.beetstra.jutf7; 25 | 26 | 27 | /** 28 | *

The character set specified in RFC 3501 to use for IMAP4rev1 mailbox name encoding.

29 | * 30 | * @see RFC 3501 31 | * @author Jaap Beetstra 32 | */ 33 | class ModifiedUTF7Charset extends UTF7StyleCharset { 34 | private static final String MODIFIED_BASE64_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 35 | + "abcdefghijklmnopqrstuvwxyz" + "0123456789+,"; 36 | 37 | ModifiedUTF7Charset(String name, String[] aliases) { 38 | super(name, aliases, MODIFIED_BASE64_ALPHABET, true); 39 | } 40 | 41 | boolean canEncodeDirectly(char ch) { 42 | if (ch == shift()) 43 | return false; 44 | return ch >= 0x20 && ch <= 0x7E; 45 | } 46 | 47 | byte shift() { 48 | return '&'; 49 | } 50 | 51 | byte unshift() { 52 | return '-'; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /helper-library/src/com/beetstra/jutf7/UTF7Charset.java: -------------------------------------------------------------------------------- 1 | /* ==================================================================== 2 | * Copyright (c) 2006 J.T. Beetstra 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 18 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 19 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 20 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 21 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | * ==================================================================== 23 | */ 24 | package com.beetstra.jutf7; 25 | 26 | /** 27 | *

The character set specified in RFC 2152. Two variants are supported using the encodeOptional 28 | * constructor flag

29 | * 30 | * @see RFC 2152 31 | * @author Jaap Beetstra 32 | */ 33 | class UTF7Charset extends UTF7StyleCharset { 34 | private static final String BASE64_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 35 | + "abcdefghijklmnopqrstuvwxyz" + "0123456789+/"; 36 | private static final String SET_D = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'(),-./:?"; 37 | private static final String SET_O = "!\"#$%&*;<=>@[]^_`{|}"; 38 | private static final String RULE_3 = " \t\r\n"; 39 | final String directlyEncoded; 40 | 41 | UTF7Charset(String name, String[] aliases, boolean includeOptional) { 42 | super(name, aliases, BASE64_ALPHABET, false); 43 | if (includeOptional) 44 | this.directlyEncoded = SET_D + SET_O + RULE_3; 45 | else 46 | this.directlyEncoded = SET_D + RULE_3; 47 | } 48 | 49 | /* (non-Javadoc) 50 | * @see com.beetstra.jutf7.UTF7StyleCharset#canEncodeDirectly(char) 51 | */ 52 | boolean canEncodeDirectly(char ch) { 53 | return directlyEncoded.indexOf(ch) >= 0; 54 | } 55 | 56 | /* (non-Javadoc) 57 | * @see com.beetstra.jutf7.UTF7StyleCharset#shift() 58 | */ 59 | byte shift() { 60 | return '+'; 61 | } 62 | 63 | /* (non-Javadoc) 64 | * @see com.beetstra.jutf7.UTF7StyleCharset#unshift() 65 | */ 66 | byte unshift() { 67 | return '-'; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /helper-library/src/com/beetstra/jutf7/UTF7StyleCharset.java: -------------------------------------------------------------------------------- 1 | /* ==================================================================== 2 | * Copyright (c) 2006 J.T. Beetstra 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 18 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 19 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 20 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 21 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | * ==================================================================== 23 | */ 24 | package com.beetstra.jutf7; 25 | 26 | import java.nio.charset.Charset; 27 | import java.nio.charset.CharsetDecoder; 28 | import java.nio.charset.CharsetEncoder; 29 | import java.util.Arrays; 30 | import java.util.List; 31 | 32 | /** 33 | *

Abstract base class for UTF-7 style encoding and decoding.

34 | * 35 | * @author Jaap Beetstra 36 | */ 37 | abstract class UTF7StyleCharset extends Charset { 38 | private static final List CONTAINED = Arrays.asList(new String[] { "US-ASCII", "ISO-8859-1", 39 | "UTF-8", "UTF-16", "UTF-16LE", "UTF-16BE" }); 40 | final boolean strict; 41 | Base64Util base64; 42 | 43 | /** 44 | *

Besides the name and aliases, two additional parameters are required. First the 45 | * base 64 alphabet used; in modified UTF-7 a slightly different alphabet is used. 46 | * Additionally, it should be specified if encoders and decoders should be strict 47 | * about the interpretation of malformed encoded sequences. This is used since 48 | * modified UTF-7 specifically disallows some constructs which are allowed (or not 49 | * specifically disallowed) in UTF-7 (RFC 2152).

50 | * 51 | * @param canonicalName The name as defined in java.nio.charset.Charset 52 | * @param aliases The aliases as defined in java.nio.charset.Charset 53 | * @param alphabet The base 64 alphabet used 54 | * @param strict True if strict handling of sequences is requested 55 | */ 56 | protected UTF7StyleCharset(String canonicalName, String[] aliases, String alphabet, 57 | boolean strict) { 58 | super(canonicalName, aliases); 59 | this.base64 = new Base64Util(alphabet); 60 | this.strict = strict; 61 | } 62 | 63 | /* (non-Javadoc) 64 | * @see java.nio.charset.Charset#contains(java.nio.charset.Charset) 65 | */ 66 | public boolean contains(final Charset cs) { 67 | return CONTAINED.contains(cs.name()); 68 | } 69 | 70 | /* (non-Javadoc) 71 | * @see java.nio.charset.Charset#newDecoder() 72 | */ 73 | public CharsetDecoder newDecoder() { 74 | return new UTF7StyleCharsetDecoder(this, base64, strict); 75 | } 76 | 77 | /* (non-Javadoc) 78 | * @see java.nio.charset.Charset#newEncoder() 79 | */ 80 | public CharsetEncoder newEncoder() { 81 | return new UTF7StyleCharsetEncoder(this, base64, strict); 82 | } 83 | 84 | /** 85 | * Tells if a character can be encoded using simple (US-ASCII) encoding or 86 | * requires base 64 encoding. 87 | * 88 | * @param ch The character 89 | * @return True if the character can be encoded directly, false otherwise 90 | */ 91 | abstract boolean canEncodeDirectly(char ch); 92 | 93 | /** 94 | * Returns character used to switch to base 64 encoding. 95 | * @return The shift character 96 | */ 97 | abstract byte shift(); 98 | 99 | /** 100 | * Returns character used to switch from base 64 encoding to simple encoding. 101 | * @return The unshift character 102 | */ 103 | abstract byte unshift(); 104 | } 105 | -------------------------------------------------------------------------------- /helper-library/src/com/beetstra/jutf7/UTF7StyleCharsetDecoder.java: -------------------------------------------------------------------------------- 1 | /* ==================================================================== 2 | * Copyright (c) 2006 J.T. Beetstra 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 18 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 19 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 20 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 21 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | * ==================================================================== 23 | */ 24 | package com.beetstra.jutf7; 25 | 26 | import java.nio.ByteBuffer; 27 | import java.nio.CharBuffer; 28 | import java.nio.charset.CharsetDecoder; 29 | import java.nio.charset.CoderResult; 30 | 31 | /** 32 | *

The CharsetDecoder used to decode both variants of the UTF-7 charset and the 33 | * modified-UTF-7 charset.

34 | * 35 | * @author Jaap Beetstra 36 | */ 37 | class UTF7StyleCharsetDecoder extends CharsetDecoder { 38 | private final Base64Util base64; 39 | private final byte shift; 40 | private final byte unshift; 41 | private final boolean strict; 42 | private boolean base64mode; 43 | private int bitsRead; 44 | private int tempChar; 45 | private boolean justShifted; 46 | private boolean justUnshifted; 47 | 48 | UTF7StyleCharsetDecoder(UTF7StyleCharset cs, Base64Util base64, boolean strict) { 49 | super(cs, 0.6f, 1.0f); 50 | this.base64 = base64; 51 | this.strict = strict; 52 | this.shift = cs.shift(); 53 | this.unshift = cs.unshift(); 54 | } 55 | 56 | /* (non-Javadoc) 57 | * @see java.nio.charset.CharsetDecoder#decodeLoop(java.nio.ByteBuffer, java.nio.CharBuffer) 58 | */ 59 | protected CoderResult decodeLoop(ByteBuffer in, CharBuffer out) { 60 | while (in.hasRemaining()) { 61 | byte b = in.get(); 62 | if (base64mode) { 63 | if (b == unshift) { 64 | if (base64bitsWaiting()) 65 | return malformed(in); 66 | if (justShifted) { 67 | if (!out.hasRemaining()) 68 | return overflow(in); 69 | out.put((char) shift); 70 | } else 71 | justUnshifted = true; 72 | setUnshifted(); 73 | } else { 74 | if (!out.hasRemaining()) 75 | return overflow(in); 76 | CoderResult result = handleBase64(in, out, b); 77 | if (result != null) 78 | return result; 79 | } 80 | justShifted = false; 81 | } else { 82 | if (b == shift) { 83 | base64mode = true; 84 | if (justUnshifted && strict) 85 | return malformed(in); 86 | justShifted = true; 87 | continue; 88 | } 89 | if (!out.hasRemaining()) 90 | return overflow(in); 91 | out.put((char) b); 92 | justUnshifted = false; 93 | } 94 | } 95 | return CoderResult.UNDERFLOW; 96 | } 97 | 98 | private CoderResult overflow(ByteBuffer in) { 99 | in.position(in.position() - 1); 100 | return CoderResult.OVERFLOW; 101 | } 102 | 103 | /** 104 | *

Decodes a byte in base 64 mode. Will directly write a character to the output 105 | * buffer if completed.

106 | * 107 | * @param in The input buffer 108 | * @param out The output buffer 109 | * @param lastRead Last byte read from the input buffer 110 | * @return CoderResult.malformed if a non-base 64 character was encountered in strict 111 | * mode, null otherwise 112 | */ 113 | private CoderResult handleBase64(ByteBuffer in, CharBuffer out, byte lastRead) { 114 | CoderResult result = null; 115 | int sextet = base64.getSextet(lastRead); 116 | if (sextet >= 0) { 117 | bitsRead += 6; 118 | if (bitsRead < 16) { 119 | tempChar += sextet << (16 - bitsRead); 120 | } else { 121 | bitsRead -= 16; 122 | tempChar += sextet >> (bitsRead); 123 | out.put((char) tempChar); 124 | tempChar = (sextet << (16 - bitsRead)) & 0xFFFF; 125 | } 126 | } else { 127 | if (strict) 128 | return malformed(in); 129 | out.put((char) lastRead); 130 | if (base64bitsWaiting()) 131 | result = malformed(in); 132 | setUnshifted(); 133 | } 134 | return result; 135 | } 136 | 137 | /* (non-Javadoc) 138 | * @see java.nio.charset.CharsetDecoder#implFlush(java.nio.CharBuffer) 139 | */ 140 | protected CoderResult implFlush(CharBuffer out) { 141 | if ((base64mode && strict) || base64bitsWaiting()) 142 | return CoderResult.malformedForLength(1); 143 | return CoderResult.UNDERFLOW; 144 | } 145 | 146 | /* (non-Javadoc) 147 | * @see java.nio.charset.CharsetDecoder#implReset() 148 | */ 149 | protected void implReset() { 150 | setUnshifted(); 151 | justUnshifted = false; 152 | } 153 | 154 | /** 155 | *

Resets the input buffer position to just before the last byte read, and returns 156 | * a result indicating to skip the last byte.

157 | * 158 | * @param in The input buffer 159 | * @return CoderResult.malformedForLength(1); 160 | */ 161 | private CoderResult malformed(ByteBuffer in) { 162 | in.position(in.position() - 1); 163 | return CoderResult.malformedForLength(1); 164 | } 165 | 166 | /** 167 | * @return True if there are base64 encoded characters waiting to be written 168 | */ 169 | private boolean base64bitsWaiting() { 170 | return tempChar != 0 || bitsRead >= 6; 171 | } 172 | 173 | /** 174 | *

Updates internal state to reflect the decoder is no longer in base 64 175 | * mode

176 | */ 177 | private void setUnshifted() { 178 | base64mode = false; 179 | bitsRead = 0; 180 | tempChar = 0; 181 | } 182 | } -------------------------------------------------------------------------------- /helper-library/src/com/beetstra/jutf7/UTF7StyleCharsetEncoder.java: -------------------------------------------------------------------------------- 1 | /* ==================================================================== 2 | * Copyright (c) 2006 J.T. Beetstra 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 18 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 19 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 20 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 21 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | * ==================================================================== 23 | */ 24 | package com.beetstra.jutf7; 25 | 26 | import java.nio.ByteBuffer; 27 | import java.nio.CharBuffer; 28 | import java.nio.charset.CharsetEncoder; 29 | import java.nio.charset.CoderResult; 30 | 31 | /** 32 | *

The CharsetEncoder used to encode both variants of the UTF-7 charset and the 33 | * modified-UTF-7 charset.

34 | * 35 | *

Please note this class does not behave strictly according to the specification in 36 | * Sun Java VMs before 1.6. This is done to get around a bug in the implementation 37 | * of {@link java.nio.charset.CharsetEncoder#encode(CharBuffer)}. Unfortunately, that method 38 | * cannot be overridden.

39 | * 40 | * @see JDK bug 6221056 41 | * 42 | * @author Jaap Beetstra 43 | */ 44 | class UTF7StyleCharsetEncoder extends CharsetEncoder { 45 | private static final float AVG_BYTES_PER_CHAR = 1.5f; 46 | private static final float MAX_BYTES_PER_CHAR = 5.0f; 47 | private final UTF7StyleCharset cs; 48 | private final Base64Util base64; 49 | private final byte shift; 50 | private final byte unshift; 51 | private final boolean strict; 52 | private boolean base64mode; 53 | private int bitsToOutput; 54 | private int sextet; 55 | static boolean useUglyHackToForceCallToFlushInJava5; 56 | static { 57 | String version = System.getProperty("java.specification.version"); 58 | String vendor = System.getProperty("java.vm.vendor"); 59 | useUglyHackToForceCallToFlushInJava5 = "1.4".equals(version) || "1.5".equals(version); 60 | useUglyHackToForceCallToFlushInJava5 &= "Sun Microsystems Inc.".equals(vendor); 61 | } 62 | 63 | UTF7StyleCharsetEncoder(UTF7StyleCharset cs, Base64Util base64, boolean strict) { 64 | super(cs, AVG_BYTES_PER_CHAR, MAX_BYTES_PER_CHAR); 65 | this.cs = cs; 66 | this.base64 = base64; 67 | this.strict = strict; 68 | this.shift = cs.shift(); 69 | this.unshift = cs.unshift(); 70 | } 71 | 72 | /* (non-Javadoc) 73 | * @see java.nio.charset.CharsetEncoder#implReset() 74 | */ 75 | protected void implReset() { 76 | base64mode = false; 77 | sextet = 0; 78 | bitsToOutput = 0; 79 | } 80 | 81 | /** 82 | * {@inheritDoc} 83 | * 84 | *

Note that this method might return CoderResult.OVERFLOW (as is 85 | * required by the specification) if insufficient space is available in the output 86 | * buffer. However, calling it again on JDKs before Java 6 triggers a bug in 87 | * {@link java.nio.charset.CharsetEncoder#flush(ByteBuffer)} causing it to throw an 88 | * IllegalStateException (the buggy method is final, thus cannot be 89 | * overridden).

90 | * 91 | * @see JDK bug 6227608 92 | * @param out The output byte buffer 93 | * @return A coder-result object describing the reason for termination 94 | */ 95 | protected CoderResult implFlush(ByteBuffer out) { 96 | if (base64mode) { 97 | if (out.remaining() < 2) 98 | return CoderResult.OVERFLOW; 99 | if (bitsToOutput != 0) 100 | out.put(base64.getChar(sextet)); 101 | out.put(unshift); 102 | } 103 | return CoderResult.UNDERFLOW; 104 | } 105 | 106 | /** 107 | * {@inheritDoc} 108 | * 109 | *

Note that this method might return CoderResult.OVERFLOW, even 110 | * though there is sufficient space available in the output buffer. This is done 111 | * to force the broken implementation of 112 | * {@link java.nio.charset.CharsetEncoder#encode(CharBuffer)} to call flush 113 | * (the buggy method is final, thus cannot be overridden).

114 | *

However, String.getBytes() fails if CoderResult.OVERFLOW is returned, since 115 | * this assumes it always allocates sufficient bytes (maxBytesPerChar * nr_of_chars). 116 | * Thus, as an extra check, the size of the input buffer is compared against the size 117 | * of the output buffer. 118 | * A static variable is used to indicate if a broken java version is used.

119 | *

It is not possible to directly write the last few bytes, since more bytes 120 | * might be waiting to be encoded then those available in the input buffer.

121 | * 122 | * @see JDK bug 6221056 123 | * @param in The input character buffer 124 | * @param out The output byte buffer 125 | * @return A coder-result object describing the reason for termination 126 | */ 127 | protected CoderResult encodeLoop(CharBuffer in, ByteBuffer out) { 128 | while (in.hasRemaining()) { 129 | if (out.remaining() < 4) 130 | return CoderResult.OVERFLOW; 131 | char ch = in.get(); 132 | if (cs.canEncodeDirectly(ch)) { 133 | unshift(out, ch); 134 | out.put((byte) ch); 135 | } else if (!base64mode && ch == shift) { 136 | out.put(shift); 137 | out.put(unshift); 138 | } else 139 | encodeBase64(ch, out); 140 | } 141 | /* 142 | These lines are required to trick JDK 1.5 and earlier into flushing when using 143 | Charset.encode(String), Charset.encode(CharBuffer) or CharsetEncoder.encode(CharBuffer) 144 | Without them, the last few bytes may be missing. 145 | */ 146 | if (base64mode && useUglyHackToForceCallToFlushInJava5 147 | && out.limit() != MAX_BYTES_PER_CHAR * in.limit()) 148 | return CoderResult.OVERFLOW; 149 | /* */ 150 | return CoderResult.UNDERFLOW; 151 | } 152 | 153 | /** 154 | *

Writes the bytes necessary to leave base 64 mode. This might include an unshift 155 | * character.

156 | * 157 | * @param out 158 | * @param ch 159 | */ 160 | private void unshift(ByteBuffer out, char ch) { 161 | if (!base64mode) 162 | return; 163 | if (bitsToOutput != 0) 164 | out.put(base64.getChar(sextet)); 165 | if (base64.contains(ch) || ch == unshift || strict) 166 | out.put(unshift); 167 | base64mode = false; 168 | sextet = 0; 169 | bitsToOutput = 0; 170 | } 171 | 172 | /** 173 | *

Writes the bytes necessary to encode a character in base 64 mode. All bytes 174 | * which are fully determined will be written. The fields bitsToOutput and 175 | * sextet are used to remember the bytes not yet fully determined.

176 | * 177 | * @param out 178 | * @param ch 179 | */ 180 | private void encodeBase64(char ch, ByteBuffer out) { 181 | if (!base64mode) 182 | out.put(shift); 183 | base64mode = true; 184 | bitsToOutput += 16; 185 | while (bitsToOutput >= 6) { 186 | bitsToOutput -= 6; 187 | sextet += (ch >> bitsToOutput); 188 | sextet &= 0x3F; 189 | out.put(base64.getChar(sextet)); 190 | sextet = 0; 191 | } 192 | sextet = (ch << (6 - bitsToOutput)) & 0x3F; 193 | } 194 | } -------------------------------------------------------------------------------- /helper-library/src/jp/jun_nama/test/utf7ime/helper/Utf7ImeHelper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 TOYAMA Sumio 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * ---- 17 | * getBytes(), encode() and allocateMore() are modifications based on 18 | * work copyrighted and licensed as follows: 19 | * 20 | * Licensed to the Apache Software Foundation (ASF) under one or more 21 | * contributor license agreements. See the NOTICE file distributed with 22 | * this work for additional information regarding copyright ownership. 23 | * The ASF licenses this file to You under the Apache License, Version 2.0 24 | * (the "License"); you may not use this file except in compliance with 25 | * the License. You may obtain a copy of the License at 26 | * 27 | * http://www.apache.org/licenses/LICENSE-2.0 28 | * 29 | * Unless required by applicable law or agreed to in writing, software 30 | * distributed under the License is distributed on an "AS IS" BASIS, 31 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 32 | * See the License for the specific language governing permissions and 33 | * limitations under the License. 34 | */ 35 | package jp.jun_nama.test.utf7ime.helper; 36 | 37 | import java.nio.ByteBuffer; 38 | import java.nio.CharBuffer; 39 | import java.nio.charset.Charset; 40 | import java.nio.charset.CharsetEncoder; 41 | import java.nio.charset.CoderResult; 42 | import java.nio.charset.CodingErrorAction; 43 | 44 | import com.beetstra.jutf7.CharsetProvider; 45 | 46 | /** 47 | * Utf7ImeHelper provides a simple Modified UTF-7 encoder.
48 | * If you use it in uiautomator, you can write simply as follows: 49 | * 50 | *
 51 |  * ....
 52 |  * 
 53 |  * UiObject editText = ...; 
 54 |  * editText.setText(Utf7ImeHelper.e("こんにちは")); // any Unicode String
 55 |  * 
 56 |  * ....
 57 |  * 
58 | * 59 | * @author TOYAMA Sumio 60 | * 61 | */ 62 | public class Utf7ImeHelper { 63 | 64 | private static final Charset CHARSET_MODIFIED_UTF7 = new CharsetProvider().charsetForName("X-MODIFIED-UTF-7"); 65 | 66 | /** 67 | * Encodes the specified text into modified UTF-7. 68 | * 69 | * @param text 70 | * plain unicode text 71 | * @return encoded text in modified UTF-7. 72 | */ 73 | public static String e(String text) { 74 | byte[] encoded = getBytes(text, CHARSET_MODIFIED_UTF7); 75 | return new String(encoded, Charset.forName("US-ASCII")); 76 | } 77 | 78 | /** 79 | * Returns a new byte array containing the characters of the specified 80 | * string encoded using the given charset. 81 | * 82 | * It is equivalent to input.getBytes(charset) except it has 83 | * workaround for the bug ID 61917. 84 | * 85 | * @see https://code.google.com/p/android/issues/detail?id=61917 86 | */ 87 | //@formatter:off 88 | /* 89 | * The original code is available from 90 | * https://android.googlesource.com/platform/libcore/+/android-4.4_r1.2/libdvm/src/main/java/java/lang/String.java 91 | */ 92 | //@formatter:on 93 | public static byte[] getBytes(String input, Charset charset) { 94 | CharBuffer chars = CharBuffer.wrap(input.toCharArray()); 95 | // @formatter:off 96 | CharsetEncoder encoder = charset.newEncoder() 97 | .onMalformedInput(CodingErrorAction.REPLACE) 98 | .onUnmappableCharacter(CodingErrorAction.REPLACE); 99 | // @formatter:on 100 | ByteBuffer buffer; 101 | buffer = encode(chars.asReadOnlyBuffer(), encoder); 102 | byte[] bytes = new byte[buffer.limit()]; 103 | buffer.get(bytes); 104 | return bytes; 105 | 106 | } 107 | 108 | //@formatter:off 109 | /* 110 | * The original code is available from 111 | * https://android.googlesource.com/platform/libcore/+/android-4.4_r1.2/luni/src/main/java/java/nio/charset/CharsetEncoder.java 112 | */ 113 | //@formatter:on 114 | private static ByteBuffer encode(CharBuffer in, CharsetEncoder encoder) { 115 | int length = (int) (in.remaining() * (double) encoder.averageBytesPerChar()); 116 | ByteBuffer out = ByteBuffer.allocate(length); 117 | 118 | encoder.reset(); 119 | CoderResult flushResult = null; 120 | 121 | while (flushResult != CoderResult.UNDERFLOW) { 122 | CoderResult encodeResult = encoder.encode(in, out, true); 123 | if (encodeResult == CoderResult.OVERFLOW) { 124 | out = allocateMore(out); 125 | continue; 126 | } 127 | 128 | flushResult = encoder.flush(out); 129 | if (flushResult == CoderResult.OVERFLOW) { 130 | out = allocateMore(out); 131 | } 132 | } 133 | 134 | out.flip(); 135 | return out; 136 | } 137 | 138 | //@formatter:off 139 | /* 140 | * The original code is available from 141 | * https://android.googlesource.com/platform/libcore/+/master/luni/src/main/java/java/nio/charset/CharsetEncoder.java 142 | */ 143 | //@formatter:on 144 | private static ByteBuffer allocateMore(ByteBuffer output) { 145 | if (output.capacity() == 0) { 146 | return ByteBuffer.allocate(1); 147 | } 148 | ByteBuffer result = ByteBuffer.allocate(output.capacity() * 2); 149 | output.flip(); 150 | result.put(output); 151 | return result; 152 | } 153 | 154 | } 155 | -------------------------------------------------------------------------------- /images/sample-screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sumio/uiautomator-unicode-input-helper/791abc5a1a0b6dc25c39f011cf3b1f1fc3ec3df6/images/sample-screenshot.png --------------------------------------------------------------------------------