pull/3/head
luyao 2 years ago
parent d868acc839
commit aa5d61194b

10
.gitignore vendored

@ -0,0 +1,10 @@
*.iml
.gradle
/local.properties
/.idea/workspace.xml
/.idea/libraries
.DS_Store
/build
/app/build
/captures
.externalNativeBuild

@ -0,0 +1,674 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. [http://fsf.org/]
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
{one line to give the program's name and a brief idea of what it does.}
Copyright (C) {year} {fullname}
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see [http://www.gnu.org/licenses/].
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
ship_gunner Copyright (C) 2018 rocket049
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
[http://www.gnu.org/licenses/].
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
[http://www.gnu.org/philosophy/why-not-lgpl.html].

@ -0,0 +1,63 @@
apply plugin: 'com.android.application'
android {
compileSdkVersion 28
buildToolsVersion '28.0.2'
defaultConfig {
applicationId "org.xing.android"
minSdkVersion 15
targetSdkVersion 26
versionCode 20
versionName "1.4.2"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
vectorDrawables.useSupportLibrary = true
}
buildTypes {
debug {
manifestPlaceholders = [bd_speech_appid : "9080060",
bd_speech_key : "TgEpVmjjELkIf3FKc1gj2jsj",
bd_speech_secret: "87c4d13cf12a83191e4b4ec23d98530e",
umeng_appkey : "none",
umeng_channel : "none"]
}
release {
minifyEnabled false
manifestPlaceholders = [bd_speech_appid : "9080060",
bd_speech_key : "TgEpVmjjELkIf3FKc1gj2jsj",
bd_speech_secret: "87c4d13cf12a83191e4b4ec23d98530e",
umeng_appkey : "586213d5ae1bf81811000768",
umeng_channel : "xing"]
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
//
applicationVariants.all { variant ->
variant.outputs.all {
outputFileName = rootProject.getName() +"-"+defaultConfig.versionName +"-"+defaultConfig.versionCode +".apk"
}
}
}
}
sourceSets {
main {
jniLibs.srcDirs = ['libs']
}
}
}
dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
compile files('libs/antlr-runtime-4.6.jar')
compile files('libs/utdid4all-1.0.4.jar')
compile files('libs/umeng-analytics-v6.0.7.jar')
compile files('libs/Msc.jar')
compile 'com.zhy:okhttputils:2.4.1'
compile 'com.tencent.mm.opensdk:wechat-sdk-android-without-mta:1.0.2'
compile 'com.android.support:appcompat-v7:28.+'
compile 'com.android.support:support-v4:28.+'
compile 'com.android.support:support-vector-drawable:28.+'
testCompile 'junit:junit:4.12'
compile files('libs/open_sdk_r5785_lite.jar')
compile files('libs/bdasr_V3_20180320_9066860.jar')
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

@ -0,0 +1,17 @@
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in C:\Users\Administrator\AppData\Local\Android\Sdk/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}

@ -0,0 +1,72 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.xing.android">
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<!-- 百度语音识别设置 -->
<meta-data
android:name="com.baidu.speech.APP_ID"
android:value="${bd_speech_appid}" />
<meta-data
android:name="com.baidu.speech.API_KEY"
android:value="${bd_speech_key}" />
<meta-data
android:name="com.baidu.speech.SECRET_KEY"
android:value="${bd_speech_secret}" />
<service
android:name="com.baidu.speech.VoiceRecognitionService"
android:exported="false" />
<!-- 友盟统计 -->
<meta-data
android:name="UMENG_APPKEY"
android:value="${umeng_appkey}" />
<meta-data
android:name="UMENG_CHANNEL"
android:value="${umeng_channel}" />
<!-- 橫屏切换不会导致Activity重新生成 -->
<activity
android:name=".MainActivity"
android:configChanges="orientation|keyboardHidden|screenSize">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".SimpleHelpActivity"
android:configChanges="orientation|keyboardHidden|screenSize" />
<!--腾讯QQ分享 -->
<activity
android:name="com.tencent.tauth.AuthActivity"
android:noHistory="true"
android:launchMode="singleTask" >
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="tencent1105840771" />
</intent-filter>
</activity>
<activity android:name="com.tencent.connect.common.AssistActivity"
android:theme="@android:style/Theme.Translucent.NoTitleBar"
android:configChanges="orientation|keyboardHidden|screenSize" />
</application>
</manifest>

@ -0,0 +1,113 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name=”viewport” content=”width=device-width, initial-scale=1″ />
<link rel="stylesheet" href="./js/KaTeX/katex.min.css" />
<script src="./js/KaTeX/katex.min.js"></script>
<style>
*{
margin : 0;
padding : 0;
}
body {
color: #444444;
}
.list li {
word-break : break-all;
word-wrap: break-word;
box-sizing: border-box;
border-radius:5px;
margin: 5px 5px;
}
.base span {
float: left;
}
#history ul {
list-style:none;
-webkit-margin-before: -0.1em;
font-size : 175%;
}
.hide-block {
display : none;
}
</style>
</head>
<body>
<div id="history" class = "list history">
<ul id="list"></ul>
</div>
<script type="text/javascript">
disColort = "rgba(8,8,8,0.05)";
function replaceMultiply(expr) {
return expr.replace(new RegExp(/\/g), "×").replace(new RegExp(/>\/</g), ">÷<");
}
function clearHistory() {
var list = document.getElementById("list");
list.innerHTML = "";
}
function historyPop() {
var list = document.getElementById("list");
if(list.childNodes != null && list.childNodes.length > 0) {
list.removeChild(list.childNodes[0]);
}
}
function addItem(item) {
var li = document.createElement("li");
li.innerHTML = replaceMultiply(katex.renderToString(item));
//删除多余的标签,防止复制操作得到重复的数据
var span = li.childNodes[0];
span.removeChild(span.childNodes[0]);
var list = document.getElementById("list");
if(list.childNodes == null || list.childNodes.length == 0) {
list.appendChild(li);
} else {
if(list.childNodes.length % 2 == 1) {
li.style.backgroundColor = disColort;
}
list.insertBefore(li, list.childNodes[0]);
}
}
function setTextColor(color) {
var body = document.body;
body.style.color = color;
}
function setDistinguishColor(color) {
disColort = color;
var list = document.getElementById("list");
if(list.childNodes != null && list.childNodes.length != 0) {
for(var i=0;i<list.childNodes.length;i++) {
if(i % 2 == 1) {
var c = list.childNodes[i];
c.style.backgroundColor = disColort;
}
}
}
}
/*
//仅用于测试的代码
addItem("1 + 2 + 3 + 4 + 4 + 5 + 6 + 7 + 8 + 9 + 10 = 55");
*/
</script>
</body>
</html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 138 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 147 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 148 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 372 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

@ -0,0 +1,147 @@
package org.xing.android;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.preference.PreferenceManager;
import android.text.TextUtils;
/**
* Created by Administrator on 2017/1/9 0009.
*/
public class AppConfig {
private static String packageName;
private static int versionCode;
private static String versionName;
private static String channel;
private static String themeId;
private static String preferedEngine;
private static int shareCount;
private static boolean isFirstStart;
private static boolean checkUpdate;
private static Context mContext;
private static SharedPreferences prefs;
public static void loadConfig(Context mContext) {
isFirstStart = false;
checkUpdate = false;
mContext = mContext;
packageName = mContext.getApplicationContext().getPackageName();
prefs = PreferenceManager.getDefaultSharedPreferences(mContext);
try {
PackageInfo info = mContext.getPackageManager().getPackageInfo(packageName, 0);
versionCode = info.versionCode;
versionName = info.versionName;
int lastVersionCode = prefs.getInt("versionCode", 0);
if (versionCode > lastVersionCode) {
isFirstStart = true;
prefs.edit().putInt("versionCode", versionCode).commit();
//第一次启动,检查版本更新的字段重设
prefs.edit().putBoolean("checkUpdate", true).commit();
checkUpdate = true;
} else {
checkUpdate = prefs.getBoolean("checkUpdate", true);
}
channel = getAppMetaData(mContext, "UMENG_CHANNEL");
themeId = prefs.getString("themeId", "0");
preferedEngine = prefs.getString("preferedEngine", "baidu");
shareCount = prefs.getInt("shareCount", 0);
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
}
public static String getPackageName() {
return packageName;
}
public static int getVersionCode() {
return versionCode;
}
public static String getVersionName() {
return versionName;
}
public static String getThemeId() {
return themeId;
}
public static void setThemeId(String themeId) {
AppConfig.themeId = themeId;
prefs.edit().putString("themeId", themeId).commit();
}
public static String getPreferedEngine() {
return preferedEngine;
}
public static void setPreferedEngine(String preferedEngine) {
AppConfig.preferedEngine = preferedEngine;
prefs.edit().putString("preferedEngine", preferedEngine).commit();
}
public static int getShareCount() {
return shareCount;
}
public static void setShareCount(int shareCount) {
AppConfig.shareCount = shareCount;
prefs.edit().putInt("shareCount", shareCount).commit();
}
public static void addShareCount() {
AppConfig.shareCount ++;
prefs.edit().putInt("shareCount", shareCount).commit();
}
public static boolean getIsFirstStart() {
return isFirstStart;
}
public static void setIsFirstStart(boolean b) {
isFirstStart = b;
}
public static boolean getCheckUpdate() {
return checkUpdate;
}
public static void setCheckUpdate(boolean b) {
checkUpdate = b;
prefs.edit().putBoolean("checkUpdate", b).commit();
}
/**
* applicationmeta-data
* @return ()
*/
public static String getAppMetaData(Context ctx, String key) {
if (ctx == null || TextUtils.isEmpty(key)) {
return null;
}
String resultData = null;
try {
PackageManager packageManager = ctx.getPackageManager();
if (packageManager != null) {
ApplicationInfo applicationInfo = packageManager.getApplicationInfo(ctx.getPackageName(), PackageManager.GET_META_DATA);
if (applicationInfo != null) {
if (applicationInfo.metaData != null) {
resultData = applicationInfo.metaData.getString(key);
}
}
}
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
return resultData;
}
}

@ -0,0 +1,752 @@
package org.xing.android;
import android.Manifest;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.res.Configuration;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Handler;
import android.provider.Settings;
import android.speech.SpeechRecognizer;
import android.support.v7.app.AppCompatActivity;
import android.view.GestureDetector;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import com.umeng.analytics.MobclickAgent;
import org.xing.calc.Calculator;
import org.xing.calc.Tips;
import org.xing.calc.cmd.CmdParser;
import org.xing.calc.filter.ExprFilterChain;
import org.xing.calc.filter.PinyinExprFilter;
import org.xing.engine.BaiduSpeechEngine;
import org.xing.engine.IflySpeechEngine;
import org.xing.engine.SpeechEngine;
import org.xing.engine.SpeechListener;
import org.xing.logger.impl.EventLogger;
import org.xing.share.ShareManager;
import org.xing.theme.Theme;
import org.xing.theme.ThemeChangeListener;
import org.xing.theme.ThemeManager;
import org.xing.update.UpdateManager;
import org.xing.utils.DeviceUtil;
import org.xing.utils.NumberUtil;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Stack;
public class MainActivity extends AppCompatActivity implements SpeechListener, ThemeChangeListener {
private boolean hasAudioError;
private boolean isListening;
private SpeechEngine speechEngine;
private Calculator calculator;
private boolean newFeatureShowed;
private boolean shareTipsShowed;
public static EventLogger eventLogger;
private Tips tips;
private EditText inputText;
private TextView msgText;
private ProgressBar recordDynamic;
private Button stateButton;
private Button startButton;
private WebView historyList;
/*
*/
private Stack<Double> historyResult;
private ExprFilterChain cmdFilterChain;
private Map<String, Integer> cmdName;
private CmdParser cmdParser;
/*
*/
private Theme currentTheme;
private ThemeManager themeManager;
/*
*/
private LinearLayout shareLayout;
private ShareManager shareManager;
/*
maxNoInputCount
*/
private int noInputCount = 0;
private int maxNoInputCount = 5;
protected void showHelp() {
MobclickAgent.onEvent(this, "help");
eventLogger.onEvent("help");
Intent intent =new Intent(MainActivity.this, SimpleHelpActivity.class);
intent.putExtra("url", getString(R.string.helpUrl));
startActivity(intent);
}
/*
10s
*/
protected void showTips(int delaySecond) {
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
@Override
public void run() {
//防止当前页面没有显示的时候显示对话框,从而导致程序崩溃
if(!isListening) return;
AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
builder.setTitle("小技巧");
builder.setMessage(" 说'引擎',切换到讯飞识别引擎,计算速度更快。" +
"立即切换?");
builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
stopListening();
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
@Override
public void run() {
changeSpeechEngine(null);
startListening(true);
}
}, 1000);
}
});
builder.setNegativeButton("知道", null);
builder.show();
}
}, delaySecond*1000);
}
private void initSpeechRecognizer() {
if(speechEngine != null) {
stopListening();
speechEngine.destroy();
}
hasAudioError = false;
isListening = false;
String preferedEngine = AppConfig.getPreferedEngine();
eventLogger.onEvent("engine-"+preferedEngine);
if(preferedEngine.equals("ifly")) {
//速度快,准确性差一点
speechEngine = new IflySpeechEngine(this);
} else {
//准确性高,速度稍慢
speechEngine = new BaiduSpeechEngine(this);
}
speechEngine.setSpeechListener(this);
}
private void changeSpeechEngine(String engine) {
eventLogger.onEvent("changeEngine");
String preferedEngine = AppConfig.getPreferedEngine();
if(preferedEngine.equals("ifly") && (engine == null || engine.equals("baidu"))){
AppConfig.setPreferedEngine("baidu");
Toast.makeText(this, "切换到百度语音引擎(更准确)\n" +
"说'引擎'或'讯飞'可以切换", Toast.LENGTH_LONG).show();
initSpeechRecognizer();
}else if(preferedEngine.equals("baidu") && (engine == null || engine.equals("ifly"))){
AppConfig.setPreferedEngine("ifly");
Toast.makeText(this, "切换到科大讯飞引擎(更快速)\n" +
"说'引擎'或'百度'可以切换", Toast.LENGTH_LONG).show();
initSpeechRecognizer();
} else {
if(preferedEngine.equals("baidu")) {
Toast.makeText(this, "已经是百度语音引擎,无需重新设置\n" +
"说'引擎'或'讯飞'可以切换", Toast.LENGTH_LONG).show();
}else {
Toast.makeText(this, "已经是科大讯飞引擎,无需重新设置\n" +
"说'引擎'或'百度'可以切换", Toast.LENGTH_LONG).show();
}
}
}
private void initUserView() {
stateButton = (Button) this.findViewById(R.id.stateButton);
stateButton = (Button) this.findViewById(R.id.stateButton);
stateButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
MobclickAgent.onEvent(MainActivity.this, "statusClick");
eventLogger.onEvent("statusClick");
Toast toast = Toast.makeText(MainActivity.this,
"图标为绿色可以开始输入\n灰色表示已暂停或者正在识别。",
Toast.LENGTH_SHORT);
toast.setGravity(Gravity.TOP, 0, 0);
toast.show();
}
});
startButton = (Button) this.findViewById(R.id.ctrl_start);
startButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
MobclickAgent.onEvent(MainActivity.this, "startClick");
eventLogger.onEvent("startClick");
if(isListening) {
stopListening();
startButton.setBackgroundResource(R.mipmap.start);
msgText.setText("已暂停");
if(AppConfig.getIsFirstStart() && (!shareTipsShowed)) {
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
@Override
public void run() {
Toast.makeText(MainActivity.this,
"小技巧每一次微信分享或QQ分享都可以减少广告分享三次即可彻底删除广告。",
Toast.LENGTH_LONG).show();
}
}, 10 * 1000);
shareTipsShowed = true;
}
} else {
//再次检查录音设备授权,部分用户误操作禁止了录音授权,这行代码可以让用户再次授权
if(hasAudioError) {
PermissionChecker.requestAudioPermission(MainActivity.this);
}
startListening(true);
startButton.setBackgroundResource(R.mipmap.stop);
msgText.setText("");
}
}
});
this.findViewById(R.id.help_mark).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
showHelp();
}
});
inputText = (EditText) this.findViewById(R.id.input);
inputText.setKeyListener(null);
msgText = (TextView) this.findViewById(R.id.msg);
recordDynamic = (ProgressBar) this.findViewById(R.id.recordDynamic);
}
private void initCalculator(HashMap<Character, String> pinyin) {
newFeatureShowed = false;
calculator = Calculator.createDefault(pinyin);
historyList = (WebView) this.findViewById(R.id.historylist);
historyList.setBackgroundColor(0);
historyList.getSettings().setJavaScriptEnabled(true);
historyList.getSettings().setAppCacheEnabled(true);
historyList.setWebViewClient(new WebViewClient() {
@Override
public void onPageFinished(WebView view, String url)
{
super.onPageFinished(view, url);
if(currentTheme != null) {
String jsCode = "javascript:setTextColor('" + currentTheme.getStyle("historyColor") + "')";
historyList.loadUrl(jsCode);
}
}
});
//设置单击和双击触发事件
historyList.setOnTouchListener(new View.OnTouchListener() {
GestureDetector detector = null;
@Override
public boolean onTouch(View v, MotionEvent event) {
if(detector == null) {
detector = new GestureDetector(MainActivity.this,
new GestureDetector.SimpleOnGestureListener() {
@Override
public boolean onDoubleTap(MotionEvent e) {
themeManager.randomTheme();
return super.onDoubleTap(e);
}
@Override
public boolean onSingleTapConfirmed(MotionEvent e) {
startListening(true);
startButton.setBackgroundResource(R.mipmap.stop);
msgText.setText("");
return super.onSingleTapConfirmed(e);
}
}
);
}
detector.onTouchEvent(event);
return false;
}
});
historyList.loadUrl("javascript:var isFirstStart="+AppConfig.getIsFirstStart()+";");
historyList.loadUrl("file:///android_asset/history.html");
historyResult = new Stack<>();
}
private void initCommand(HashMap<Character, String> pinyin) {
cmdName = new HashMap<String, Integer>();
cmdName.put("清屏", 1);
cmdName.put("清空", 1);
cmdName.put("清除", 1);
cmdName.put("全部删除", 1);
cmdName.put("撤销", 2);
cmdName.put("取消", 2);
cmdName.put("倒退", 2);
cmdName.put("后退", 2);
cmdName.put("删除", 2);
cmdName.put("帮助", 3);
cmdName.put("示例", 3);
cmdName.put("说明", 3);
cmdName.put("升级", 4);
cmdName.put("版本", 4);
cmdName.put("主题", 5);
cmdName.put("背景", 5);
cmdName.put("风格", 5);
cmdName.put("引擎", 6);
cmdName.put("百度", 6);
cmdName.put("讯飞", 6);
cmdName.put("退出", 7);
cmdName.put("关闭", 7);
cmdName.put("暂停", 8);
StringBuilder allowedChars = new StringBuilder();
for(String key : cmdName.keySet()) {
allowedChars.append(key);
}
cmdFilterChain = new ExprFilterChain(allowedChars.toString(), pinyin);
cmdParser = new CmdParser();
}
private void initTheme() {
themeManager = new ThemeManager(this);
themeManager.addThemeChangeListener(this);
themeManager.applyTheme(AppConfig.getThemeId());
}
private void initShare() {
shareTipsShowed = false;
shareManager = new ShareManager(this);
shareLayout = (LinearLayout) findViewById(R.id.share_board);
this.findViewById(R.id.share_mark).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
shareLayout.setVisibility(View.VISIBLE);
}
});
this.findViewById(R.id.cancel_btn).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
shareLayout.setVisibility(View.GONE);
}
});
this.findViewById(R.id.share_weixin).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
shareManager.shareToWeixin(0);
}
});
this.findViewById(R.id.share_pengyouquan).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
shareManager.shareToWeixin(1);
}
});
this.findViewById(R.id.share_qq).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
shareManager.shareToQQ(0);
}
});
this.findViewById(R.id.share_kongjian).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
shareManager.shareToQQ(1);
}
});
}
private void initPermission() {
PermissionChecker.requestPermission(this, new String[] {
Manifest.permission.RECORD_AUDIO,
Manifest.permission.ACCESS_NETWORK_STATE,
Manifest.permission.INTERNET,
Manifest.permission.READ_PHONE_STATE
});
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
AppConfig.loadConfig(this);
String uniqueId = DeviceUtil.getUniqueId(this);
eventLogger = new EventLogger(uniqueId, AppConfig.getVersionName(),
this.getString(R.string.recordUrl));
if(AppConfig.getIsFirstStart()) {
eventLogger.onEvent("new-start");
} else {
eventLogger.onEvent("start");
}
tips = Tips.createSimpleTips();
//10s后检查更新
UpdateManager.postUpdate(this, 10);
MobclickAgent.setScenarioType(this, MobclickAgent.EScenarioType.E_UM_NORMAL);
initPermission();
initUserView();
HashMap<Character, String> pinyin =
PinyinExprFilter.loadTokens(getResources().openRawResource(R.raw.token));
initCalculator(pinyin);
initCommand(pinyin);
initTheme();
initShare();
initSpeechRecognizer();
}
@Override
public void onResume() {
super.onResume();
startListening(true);
startButton.setBackgroundResource(R.mipmap.stop);
msgText.setText(tips.randomGet());
MobclickAgent.onResume(this);
}
@Override
public void onPause() {
super.onPause();
stopListening();
startButton.setBackgroundResource(R.mipmap.start);
MobclickAgent.onPause(this);
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
}
public synchronized void startListening(boolean resetInputCount) {
if (isListening) return;
hasAudioError = false;
speechEngine.startListening();
isListening = true;
lastRmsdB = 0;
if (resetInputCount) {
noInputCount = 0;
}
}
public void stopListening() {
if(isListening) {
speechEngine.cancel();
}
listeningStopped();
}
public synchronized void listeningStopped() {
isListening = false;
stateButton.setBackgroundResource(R.mipmap.input_sleep);
}
public void onReadyForSpeech() {
stateButton.setBackgroundResource(R.mipmap.input_ready);
}
public void onBeginningOfSpeech() {
}
private float lastRmsdB=0;
public void onRmsChanged(float rmsdB) {
lastRmsdB = (rmsdB*3+lastRmsdB*7) /10;
recordDynamic.setProgress((int) lastRmsdB);
}
public void onEndOfSpeech() {
stateButton.setBackgroundResource(R.mipmap.input_sleep);
msgText.setText("正在识别...");
}
public void onError(int error) {
listeningStopped();
StringBuilder sb = new StringBuilder();
switch (error) {
case SpeechRecognizer.ERROR_AUDIO:
sb.append("请读出表达式");
startListening(true);
MobclickAgent.onEvent(this, "noAudio");
eventLogger.onEvent("noAudio");
break;
case SpeechRecognizer.ERROR_SPEECH_TIMEOUT:
noInputCount++;
if (noInputCount >= maxNoInputCount) {
sb.append("已暂停");
startButton.setBackgroundResource(R.mipmap.start);
} else {
startListening(false);
}
break;
case SpeechRecognizer.ERROR_CLIENT:
sb.append("客户端错误");
startButton.setBackgroundResource(R.mipmap.start);
eventLogger.onEvent("errorClient");
break;
case SpeechRecognizer.ERROR_INSUFFICIENT_PERMISSIONS:
sb.append("录音设备未授权");
startButton.setBackgroundResource(R.mipmap.start);
eventLogger.onEvent("errorPermissions");
hasAudioError = true;
break;
case SpeechRecognizer.ERROR_NETWORK:
sb.append("请检查网络连接");
MobclickAgent.onEvent(this, "errorNetwork");
eventLogger.onEvent("errorNetwork");
startButton.setBackgroundResource(R.mipmap.start);
break;
case SpeechRecognizer.ERROR_NO_MATCH:
sb.append("未识别");
MobclickAgent.onEvent(this, "failMatch");
eventLogger.onEvent("failMatch");
startListening(true);
break;
case SpeechRecognizer.ERROR_RECOGNIZER_BUSY:
sb.append("引擎忙");
MobclickAgent.onEvent(this, "busy");
eventLogger.onEvent("busy");
startButton.setBackgroundResource(R.mipmap.start);
break;
case SpeechRecognizer.ERROR_SERVER:
sb.append("未识别");
startListening(true);
MobclickAgent.onEvent(this, "failServer");
eventLogger.onEvent("failServer");
break;
case SpeechRecognizer.ERROR_NETWORK_TIMEOUT:
sb.append("网络连接连接超时");
MobclickAgent.onEvent(this, "errorNetworkTimeout");
eventLogger.onEvent("errorNetworkTimeout");
startButton.setBackgroundResource(R.mipmap.start);
break;
}
msgText.setText(sb.toString());
}
private String buildExpr(Bundle results) {
ArrayList<String> nbest = results.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION);
StringBuilder expr = new StringBuilder();
for (String w : nbest) {
expr.append(w);
}
return expr.toString();
}
private void showResult(String expr, Double evalResult, String readExpr) {
//界面上显示结果
if (!Double.isNaN(evalResult)) {
historyResult.push(evalResult);
String text = NumberUtil.format(evalResult, 8);
String item = readExpr + "=" + text;
historyList.loadUrl("javascript:addItem('" + item + "')");
inputText.setText(text);
msgText.setText("");
} else {
String errMsg = calculator.getErrMsg();
if(errMsg != null) {
msgText.setText("未识别,'"+errMsg+"'表达错误");
} else {
msgText.setText("未识别,'"+expr+"'表达错误");
}
}
}
public int handleCommand(String expr) {
String cmd = cmdFilterChain.call(expr);
int type = cmdParser.parse(cmd);
if(type > 0) {
this.eventLogger.onEvent("NaN", expr.toString(), "null", type);
switch (type) {
case 1:
historyResult.clear();
historyList.loadUrl("javascript:clearHistory()");
calculator.setLastResult(0);
inputText.setText("0");
break;
case 2:
if(historyResult.size() > 0) {
historyResult.pop();
historyList.loadUrl("javascript:historyPop()");
if(historyResult.size() > 0) {
Double lastResult = historyResult.peek();
calculator.setLastResult(lastResult);
inputText.setText(NumberUtil.format(lastResult, 8));
} else {
calculator.setLastResult(0);
inputText.setText("0");
}
}
break;
case 3:
showHelp();
break;
case 4:
UpdateManager.update(this, true);
break;
case 5:
themeManager.randomTheme();
break;
case 6:
if(cmd.contains("引擎")) {
changeSpeechEngine(null);
}else if(cmd.contains("百度")){
changeSpeechEngine("baidu");
}else {
changeSpeechEngine("ifly");
}
break;
case 7:
stopListening();
finish();
break;
case 8:
stopListening();
startButton.setBackgroundResource(R.mipmap.start);
msgText.setText("已暂停");
break;
default:
break;
}
if(type != 8) {
msgText.setText("");
}
}
return type;
}
public void onResults(String expr) {
int cmdType = handleCommand(expr);
if(expr != null &&expr.length()>0 &&
(!expr.equals("。")) && cmdType == 0) {
//结算结果
String readExpr = null;
Double evalResult = calculator.eval(expr.toString());
if (evalResult != null && (!evalResult.isNaN())) {
readExpr = calculator.getReadExpr();
}
this.eventLogger.onEvent(NumberUtil.format(evalResult, 8),
expr.toString(), readExpr, 0);
showResult(expr.toString(), evalResult, readExpr);
if(AppConfig.getIsFirstStart() && (!newFeatureShowed)) {
showTips(10);
newFeatureShowed = true;
}
}
//不是暂停命令的时候继续开启语音输入
if(cmdType != 8) {
isListening = false;
startListening(true);
}
}
public boolean isAlive() {
return !this.isFinishing();
}
public void onThemeChange(Theme theme) {
if(theme == null) return;
eventLogger.onEvent("theme-"+theme.getId());
try {
currentTheme = theme;
AppConfig.setThemeId(theme.getId());
int color;
List<String> backgroundImages = theme.getImagePaths();
LinearLayout layout = (LinearLayout) this.findViewById(R.id.backgroundLayout);
if(backgroundImages != null && backgroundImages.size() > 0) {
InputStream is = this.getAssets().open(backgroundImages.get(0));
Drawable background = Drawable.createFromStream(is, "theme");
layout.setBackgroundDrawable(background);
is.close();
} else {
layout.setBackgroundDrawable(null);
color = Color.parseColor(theme.getStyle("background"));
layout.setBackgroundColor(color);
}
String jsCode = "javascript:setTextColor('"+currentTheme.getStyle("historyColor")+"')";
historyList.loadUrl(jsCode);
color = Color.parseColor(theme.getStyle("resultColor"));
inputText.setTextColor(color);
color = Color.parseColor(theme.getStyle("msgColor"));
msgText.setTextColor(color);
}catch (Exception e) {
e.printStackTrace();
}
}
}

@ -0,0 +1,83 @@
package org.xing.android;
import android.Manifest;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Handler;
import android.provider.Settings;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.widget.Toast;
import java.util.Vector;
/**
* Created by Administrator on 2017/3/18 0018.
*/
public class PermissionChecker {
public final static int REQUEST_CODE_ALL = 1;
public static void requestPermission(Activity activity, String[] permissions) {
Vector<String> lackedPermissions = new Vector<String>();
for(String per : permissions) {
if(ContextCompat.checkSelfPermission(activity, per) == PackageManager.PERMISSION_DENIED) {
lackedPermissions.add(per);
}
}
if(lackedPermissions.size() > 0) {
String[] tempPermissions = new String[lackedPermissions.size()];
for(int i=0;i<lackedPermissions.size();i++) {
tempPermissions[i] = lackedPermissions.get(i);
}
ActivityCompat.requestPermissions(activity, tempPermissions, REQUEST_CODE_ALL);
}
}
public static void requestAudioPermission(final Activity activity) {
final String per = Manifest.permission.RECORD_AUDIO;
int state = ContextCompat.checkSelfPermission(activity, per);
if(state != PackageManager.PERMISSION_GRANTED
&& ActivityCompat.shouldShowRequestPermissionRationale(activity, per)) {
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
builder.setTitle("授权提醒");
builder.setMessage("计算器需要使用录音设备输入数字,请授权,否则无法使用。");
builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
ActivityCompat.requestPermissions(activity, new String[] {per}, REQUEST_CODE_ALL);
}
});
builder.show();
} else {
startSetting(activity , "\t计算器需要使用录音设备(麦克风)输入数字,请打开设置界面授权,否则无法使用。\n" +
"参考步骤:'权限设置'->'录音'->'星星声控计算器'->'允许'。");
}
}
public static void startSetting(final Activity activity, String msg) {
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
builder.setTitle("应用未授权");
builder.setMessage(msg);
builder.setPositiveButton("打开", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
try {
Intent intent = new Intent(Settings.ACTION_SETTINGS);
activity.startActivity(intent);
}catch (Exception ex) {
Toast.makeText(activity,
"抱歉,无法自动跳转到设置页面,请手动操作。",
Toast.LENGTH_SHORT).show();
}
}
});
builder.setNegativeButton("忽略", null);
builder.show();
}
}

@ -0,0 +1,254 @@
package org.xing.android;
import android.content.ActivityNotFoundException;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.net.Uri;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.text.TextUtils;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.webkit.WebChromeClient;
import android.webkit.WebResourceResponse;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView;
import com.umeng.analytics.MobclickAgent;
import java.io.ByteArrayInputStream;
public class SimpleHelpActivity extends AppCompatActivity {
private WebView helpWeb;
private View videoView;
private FrameLayout videoContainerView;
LinearLayout toolBar;
private ProgressBar progressBar;
private TextView titleText;
private WebChromeClient chromeClient;
/**
*
*/
private void setFullScreen() {
// 设置全屏的相关属性,获取当前的屏幕状态,然后设置全屏
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
// 全屏下的状态码1098974464
// 窗口下的状态吗1098973440
}
/**
* 退
*/
private void quitFullScreen() {
// 声明当前屏幕状态的参数并获取
final WindowManager.LayoutParams attrs = getWindow().getAttributes();
attrs.flags &= (~WindowManager.LayoutParams.FLAG_FULLSCREEN);
getWindow().setAttributes(attrs);
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_simple_help);
videoView = null;
videoContainerView = (FrameLayout) findViewById(R.id.video);
toolBar = (LinearLayout) findViewById(R.id.toolBar);
progressBar = (ProgressBar) findViewById(R.id.webProgress);
titleText = (TextView) findViewById(R.id.help_title);
Button closeButton = (Button) findViewById(R.id.help_close);
closeButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
finish();
}
});
helpWeb = (WebView) this.findViewById(R.id.simple_help);
helpWeb.setBackgroundColor(0);
WebSettings settings = helpWeb.getSettings();
settings.setJavaScriptEnabled(true);
settings.setJavaScriptCanOpenWindowsAutomatically(true);
settings.setDatabaseEnabled(true);
settings.setAppCacheEnabled(true);
settings.setCacheMode(WebSettings.LOAD_DEFAULT);
settings.setPluginState(WebSettings.PluginState.ON);
settings.setAllowFileAccess(true);
settings.setLoadWithOverviewMode(false);
settings.setDomStorageEnabled(true);
chromeClient = new WebChromeClient() {
private CustomViewCallback callBack;
// 播放网络视频时全屏会被调用的方法
@Override
public void onShowCustomView(View view, CustomViewCallback callback) {
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
toolBar.setVisibility(View.INVISIBLE);
helpWeb.setVisibility(View.INVISIBLE);
// 如果一个视图已经存在,那么立刻终止并新建一个
if (videoView != null) {
callback.onCustomViewHidden();
return;
}
videoContainerView.addView(view);
videoView = view;
callBack = callback;
videoContainerView.setVisibility(View.VISIBLE);
setFullScreen();
}
// 视频播放退出全屏会被调用的
@Override
public void onHideCustomView() {
if (videoView == null)// 不是全屏播放状态
return;
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
videoView.setVisibility(View.GONE);
videoContainerView.removeView(videoView);
videoView = null;
videoContainerView.setVisibility(View.GONE);
callBack.onCustomViewHidden();
toolBar.setVisibility(View.VISIBLE);
helpWeb.setVisibility(View.VISIBLE);
quitFullScreen();
}
@Override
public void onProgressChanged(WebView view, int newProgress) {
if (newProgress == 100) {
progressBar.setVisibility(View.GONE);
} else {
if (View.INVISIBLE == progressBar.getVisibility()) {
progressBar.setVisibility(View.VISIBLE);
titleText.setText("页面加载中...");
}
progressBar.setProgress(newProgress);
}
super.onProgressChanged(view, newProgress);
}
};
helpWeb.setWebChromeClient(chromeClient);
helpWeb.setWebViewClient(new WebViewClient() {
@Override
public void onPageFinished(WebView view, String url) {
WebView.HitTestResult hitTestResult = view.getHitTestResult();
if (!TextUtils.isEmpty(url) && hitTestResult == null) {
return;
}
titleText.setText(view.getTitle());
}
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
return true;
}
@Override
public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
if (url.startsWith("http") || url.startsWith("https")
|| url.startsWith("javascript") || url.startsWith("file")) {
return super.shouldInterceptRequest(view, url);
} else {
String tips = "启动外部应用...";
try {
Intent in = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
startActivity(in);
} catch (ActivityNotFoundException ex) {
tips = "启动外部应用失败,请安装最新版应用。";
}
return new WebResourceResponse("text/plain", "utf-8", new ByteArrayInputStream(tips.getBytes()));
}
}
});
helpWeb.setOnTouchListener(new View.OnTouchListener() {
private float x1 = 0;
private float x2 = 0;
private float y1 = 0;
private float y2 = 0;
@Override
public boolean onTouch(View v, MotionEvent event) {
//继承了Activity的onTouchEvent方法直接监听点击事件
if (event.getAction() == MotionEvent.ACTION_DOWN) {
//当手指按下的时候
x1 = event.getX();
y1 = event.getY();
}
if (event.getAction() == MotionEvent.ACTION_UP) {
//当手指离开的时候
x2 = event.getX();
y2 = event.getY();
if (y1 - y2 > 50) {
toolBar.setVisibility(View.GONE);
} else if (y2 - y1 > 50) {
toolBar.setVisibility(View.VISIBLE);
}
}
return false;
}
});
String url = getIntent().getStringExtra("url");
helpWeb.loadUrl(url);
}
@Override
public void onResume() {
super.onResume();
MobclickAgent.onResume(this);
helpWeb.onResume();
}
@Override
public void onPause() {
super.onPause();
MobclickAgent.onPause(this);
helpWeb.onPause();
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK && helpWeb.canGoBack()) {
helpWeb.goBack();// 返回前一个页面
return true;
}
return super.onKeyDown(keyCode, event);
}
@Override
public void onBackPressed() {
if (videoView == null) {
super.onBackPressed();
} else {
chromeClient.onHideCustomView();
}
}
}

@ -0,0 +1,282 @@
package org.xing.calc;
import org.antlr.v4.runtime.ANTLRErrorListener;
import org.antlr.v4.runtime.ANTLRInputStream;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.Parser;
import org.antlr.v4.runtime.RecognitionException;
import org.antlr.v4.runtime.Recognizer;
import org.antlr.v4.runtime.atn.ATNConfigSet;
import org.antlr.v4.runtime.dfa.DFA;
import org.antlr.v4.runtime.tree.ParseTree;
import org.xing.calc.filter.CorrectionExprFilter;
import org.xing.calc.filter.ExprFilter;
import org.xing.calc.filter.PinyinExprFilter;
import org.xing.calc.parser.CalculatorEvalVisitor;
import org.xing.calc.parser.CalculatorLatexExprVisitor;
import org.xing.calc.parser.grammer.calculatorLexer;
import org.xing.calc.parser.grammer.calculatorParser;
import org.xing.utils.NumberUtil;
import java.io.InputStream;
import java.util.BitSet;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
/**
* @author Administrator
*
*/
public class Calculator implements ANTLRErrorListener{
/**
*
*/
private double lastResult;
/*
*
*/
private String lastReadExpr;
/*
*/
private String orgExpr;
/*
*/
private int errPos;
private String errMsg;
private String reason;
/**
*
*/
private List<ExprFilter> filters;
/*
*
*/
private Set<Character> continuousInputTag;
/*
*
*/
private Set<String> continuousFuncTag;
/*
*
*/
private Set<String> continuousPostFuncTag;
/*
*/
private Set<String> continuousPowTag;
public Calculator() {
setLastResult(0.0);
filters = new LinkedList<ExprFilter>();
String inputTags = "加+减-乘*×除/÷";
continuousInputTag = new HashSet<>();
for (int i = 0; i < inputTags.length(); i++) {
continuousInputTag.add(inputTags.charAt(i));
}
String[] funcTags = new String[]{"cos", "余弦", "sin",
"正弦", "tan", "正切", "acos", "反余弦", "asin", "反正弦",
"atan", "反正切", "ln", "log", "lg", "对数", "根号"};
continuousFuncTag = new HashSet<>();
for (int i = 0; i < funcTags.length; i++) {
continuousFuncTag.add(funcTags[i]);
}
String[] postFuncTags = new String[]{"开方", "开平方", "开立方", "平方根", "立方根"};
continuousPostFuncTag = new HashSet<>();
for (int i = 0; i < postFuncTags.length; i++) {
continuousPostFuncTag.add(postFuncTags[i]);
}
String[] powTags = new String[]{"平方", "立方"};
continuousPowTag = new HashSet<>();
for (int i = 0; i < powTags.length; i++) {
continuousPowTag.add(powTags[i]);
}
}
public void addFilter(ExprFilter filter) {
filters.add(filter);
}
public String execFilter(String expr) {
if(expr == null) return null;
for (ExprFilter filter : filters) {
expr = filter.call(expr);
}
return expr;
}
public double getLastResult() {
return lastResult;
}
public void setLastResult(double lastResult) {
this.lastResult = lastResult;
}
public String getErrMsg() {
return errMsg;
}
public String getReason() {
return reason;
}
public String getReadExpr() {
return lastReadExpr;
}
public void setErrorMsg(int pos, String r) {
int offset = 5;
if(errPos != -1) return;
if(orgExpr == null || pos < 0
|| pos >= orgExpr.length()) errMsg = null;
errPos = pos;
reason = r;
int start = pos > offset ? pos-offset:0;
int end = pos + offset < orgExpr.length() ? pos+offset:orgExpr.length();
errMsg = orgExpr.substring(start, end);
}
public Double innerEval(String expr) {
Double result = Double.NaN;
String readExpr = null;
ANTLRInputStream input = new ANTLRInputStream(expr);
calculatorLexer lexer = new calculatorLexer(input);
CommonTokenStream tokens = new CommonTokenStream(lexer);
calculatorParser parser = new calculatorParser(tokens);
parser.addErrorListener(this);
ParseTree tree = parser.expression();
CalculatorEvalVisitor evalVisitor = new CalculatorEvalVisitor();
result = evalVisitor.visit(tree);
CalculatorLatexExprVisitor exprVisitor = new CalculatorLatexExprVisitor();
readExpr = exprVisitor.visit(tree);
if (result != null && !result.isNaN()) {
lastResult = result;
lastReadExpr = readExpr;
}
return result != null? result:Double.NaN;
}
public double eval(String expr) {
errMsg = null;
Double result = Double.NaN;
if(expr == null || expr.length() == 0) return result;
expr = expr.replace("再", "");
expr = expr.replace("等于", "");
expr = expr.replace("多少", "");
orgExpr = expr;
try {
for (ExprFilter filter : filters) {
expr = filter.call(expr);
}
//过滤的文字太多,视为无效表达式
if(orgExpr.length() - expr.length() > 4) {
return Double.NaN;
}
String currentExpr = null;
while(true) {
errPos = -1;
currentExpr = expr;
if(continuousInputTag.contains(expr.charAt(0))) {
expr = NumberUtil.format(this.lastResult, 8)+expr;
}else if(continuousFuncTag.contains(expr)) {
expr = expr + NumberUtil.format(this.lastResult, 8);
}else if(continuousPostFuncTag.contains(expr)) {
expr = NumberUtil.format(this.lastResult, 8)+ expr;
}else if(continuousPowTag.contains(expr)) {
expr = NumberUtil.format(this.lastResult, 8) + "的" + expr;
}
result = innerEval(expr);
if(errPos >= 0 && errPos <= currentExpr.length()) {
if(errPos < currentExpr.length() && currentExpr.charAt(errPos) == '点') {
char[] seq = currentExpr.toCharArray();
seq[errPos] = '减';
expr = String.valueOf(seq);
}else if(reason != null && reason.contains("次方")) {
//21的三九减四点六 中间的“的”改为“点”
char[] seq = currentExpr.toCharArray();
while(errPos >= 0) {
if(errPos < currentExpr.length() && seq[errPos] == '的') {
seq[errPos] = '点';
expr = String.valueOf(seq);
break;
}
errPos --;
}
if(errPos < 0) break;
} else {
break;
}
} else {
break;
}
}
} catch (Exception ex) {
ex.printStackTrace();
}
return result;
}
public static Calculator createDefault(HashMap<Character, String> pinyin) {
String allowedChars =
"0123456789.零一二三四五六七八九点负个十百千万亿+-*/括号加上减去乘以除÷×根号开方的平方次方立方分之" +
"sincostanlglogln反正弦反余弦反正切对数()|^度°派π又";
Calculator calc = new Calculator();
calc.addFilter(new CorrectionExprFilter());
calc.addFilter(new PinyinExprFilter(allowedChars, pinyin));
return calc;
}
@Override
public void syntaxError(Recognizer<?, ?> recognizer, Object o, int i, int i1, String s, RecognitionException e) {
setErrorMsg(i1, s);
}
@Override
public void reportAmbiguity(Parser parser, DFA dfa, int i, int i1, boolean b, BitSet bitSet, ATNConfigSet atnConfigSet) {
setErrorMsg(i1, "");
}
@Override
public void reportAttemptingFullContext(Parser parser, DFA dfa, int i, int i1, BitSet bitSet, ATNConfigSet atnConfigSet) {
setErrorMsg(i1, "");
}
@Override
public void reportContextSensitivity(Parser parser, DFA dfa, int i, int i1, int i2, ATNConfigSet atnConfigSet) {
setErrorMsg(i1, "");
}
}

@ -0,0 +1,65 @@
package org.xing.calc;
import java.util.Random;
import java.util.Vector;
/**
* Created by Administrator on 2017/2/21 0021.
*/
public class Tips {
private Random random;
private Vector<String> tipsStr;
public Tips() {
random = new Random();
tipsStr = new Vector<>();
}
public void add(String tip) {
tipsStr.add(tip);
}
public String get(int index) {
if(index >= 0 && index < tipsStr.size())
return tipsStr.get(index);
else
return null;
}
public String randomGet() {
if(tipsStr.size() > 0) {
return tipsStr.get(
random.nextInt(tipsStr.size())
);
}
return null;
}
public static Tips createSimpleTips() {
Tips tips = new Tips();
tips.add("试一下:'帮助'");
tips.add("试一下:'升级'");
tips.add("试一下:'主题'");
tips.add("试一下:'三分之一'");
tips.add("试一下:'加一千'");
tips.add("试一下:'删除'");
tips.add("试一下:'对数三'");
tips.add("试一下:'三对数五'");
tips.add("试一下:'清空'");
tips.add("试一下:'二乘括号二加一括号'");
tips.add("试一下:'正弦零点二'");
tips.add("试一下:'正弦三分之派'");
tips.add("试一下:'正弦三十度'");
tips.add("试一下:'根号五'");
tips.add("试一下:'三根号五'");
tips.add("试一下:'三的平方'");
tips.add("试一下:'三的四次方'");
tips.add("试一下:'百度'");
tips.add("试一下:'讯飞'");
tips.add("试一下:'引擎'");
tips.add("试一下:'退出'");
tips.add("提示:分享三次可彻底删除广告");
return tips;
}
}

@ -0,0 +1,28 @@
package org.xing.calc.cmd;
import org.xing.calc.cmd.grammer.cmdBaseVisitor;
import org.xing.calc.cmd.grammer.cmdParser;
public class CmdDefaultVisitor extends cmdBaseVisitor<Integer>{
@Override public Integer visitCommand(cmdParser.CommandContext ctx) {
if(ctx.qingping() != null) {
return 1;
}else if(ctx.goback() != null) {
return 2;
}else if(ctx.help() != null) {
return 3;
}else if(ctx.update() != null) {
return 4;
}else if(ctx.theme() != null) {
return 5;
}else if(ctx.engine() != null) {
return 6;
}else if(ctx.close() != null) {
return 7;
}else if(ctx.stop() != null) {
return 8;
}
return 0;
}
}

@ -0,0 +1,31 @@
package org.xing.calc.cmd;
import org.antlr.v4.runtime.ANTLRInputStream;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.tree.ParseTree;
import org.xing.calc.cmd.grammer.cmdLexer;
import org.xing.calc.cmd.grammer.cmdParser;
public class CmdParser {
public CmdParser() {
}
public int parse(String expr) {
try {
ANTLRInputStream input = new ANTLRInputStream(expr);
cmdLexer lexer = new cmdLexer(input);
CommonTokenStream tokens = new CommonTokenStream(lexer);
cmdParser parser = new cmdParser(tokens);
ParseTree tree = parser.command();
if(tree == null) return 0;
else {
CmdDefaultVisitor visitor = new CmdDefaultVisitor();
return visitor.visit(tree);
}
}catch (Exception ex) {
ex.printStackTrace();
}
return 0;
}
}

@ -0,0 +1,77 @@
// Generated from src/org/xing/calc/cmd/grammer/cmd.g4 by ANTLR 4.6
package org.xing.calc.cmd.grammer;
import org.antlr.v4.runtime.tree.AbstractParseTreeVisitor;
/**
* This class provides an empty implementation of {@link cmdVisitor},
* which can be extended to create a visitor which only needs to handle a subset
* of the available methods.
*
* @param <T> The return type of the visit operation. Use {@link Void} for
* operations with no return type.
*/
public class cmdBaseVisitor<T> extends AbstractParseTreeVisitor<T> implements cmdVisitor<T> {
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitCommand(cmdParser.CommandContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitQingping(cmdParser.QingpingContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitGoback(cmdParser.GobackContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitHelp(cmdParser.HelpContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitUpdate(cmdParser.UpdateContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitTheme(cmdParser.ThemeContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitEngine(cmdParser.EngineContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitClose(cmdParser.CloseContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitStop(cmdParser.StopContext ctx) { return visitChildren(ctx); }
}

@ -0,0 +1,140 @@
// Generated from src/org/xing/calc/cmd/grammer/cmd.g4 by ANTLR 4.6
package org.xing.calc.cmd.grammer;
import org.antlr.v4.runtime.Lexer;
import org.antlr.v4.runtime.CharStream;
import org.antlr.v4.runtime.Token;
import org.antlr.v4.runtime.TokenStream;
import org.antlr.v4.runtime.*;
import org.antlr.v4.runtime.atn.*;
import org.antlr.v4.runtime.dfa.DFA;
import org.antlr.v4.runtime.misc.*;
@SuppressWarnings({"all", "warnings", "unchecked", "unused", "cast"})
public class cmdLexer extends Lexer {
static { RuntimeMetaData.checkVersion("4.6", RuntimeMetaData.VERSION); }
protected static final DFA[] _decisionToDFA;
protected static final PredictionContextCache _sharedContextCache =
new PredictionContextCache();
public static final int
T__0=1, T__1=2, T__2=3, T__3=4, T__4=5, T__5=6, T__6=7, T__7=8, T__8=9,
T__9=10, T__10=11, T__11=12, T__12=13, T__13=14, T__14=15, T__15=16, T__16=17,
T__17=18, T__18=19, T__19=20, T__20=21, T__21=22, T__22=23, WS=24;
public static String[] modeNames = {
"DEFAULT_MODE"
};
public static final String[] ruleNames = {
"T__0", "T__1", "T__2", "T__3", "T__4", "T__5", "T__6", "T__7", "T__8",
"T__9", "T__10", "T__11", "T__12", "T__13", "T__14", "T__15", "T__16",
"T__17", "T__18", "T__19", "T__20", "T__21", "T__22", "WS"
};
private static final String[] _LITERAL_NAMES = {
null, "'清屏'", "'清空'", "'清除'", "'全部'", "'撤销'", "'取消'", "'倒退'", "'后退'",
"'删除'", "'帮助'", "'示例'", "'说明'", "'升级'", "'版本'", "'主题'", "'风格'", "'背景'",
"'引擎'", "'百度'", "'讯飞'", "'退出'", "'关闭'", "'暂停'"
};
private static final String[] _SYMBOLIC_NAMES = {
null, null, null, null, null, null, null, null, null, null, null, null,
null, null, null, null, null, null, null, null, null, null, null, null,
"WS"
};
public static final Vocabulary VOCABULARY = new VocabularyImpl(_LITERAL_NAMES, _SYMBOLIC_NAMES);
/**
* @deprecated Use {@link #VOCABULARY} instead.
*/
@Deprecated
public static final String[] tokenNames;
static {
tokenNames = new String[_SYMBOLIC_NAMES.length];
for (int i = 0; i < tokenNames.length; i++) {
tokenNames[i] = VOCABULARY.getLiteralName(i);
if (tokenNames[i] == null) {
tokenNames[i] = VOCABULARY.getSymbolicName(i);
}
if (tokenNames[i] == null) {
tokenNames[i] = "<INVALID>";
}
}
}
@Override
@Deprecated
public String[] getTokenNames() {
return tokenNames;
}
@Override
public Vocabulary getVocabulary() {
return VOCABULARY;
}
public cmdLexer(CharStream input) {
super(input);
_interp = new LexerATNSimulator(this,_ATN,_decisionToDFA,_sharedContextCache);
}
@Override
public String getGrammarFileName() { return "cmd.g4"; }
@Override
public String[] getRuleNames() { return ruleNames; }
@Override
public String getSerializedATN() { return _serializedATN; }
@Override
public String[] getModeNames() { return modeNames; }
@Override
public ATN getATN() { return _ATN; }
public static final String _serializedATN =
"\3\u0430\ud6d1\u8206\uad2d\u4417\uaef1\u8d80\uaadd\2\32\177\b\1\4\2\t"+
"\2\4\3\t\3\4\4\t\4\4\5\t\5\4\6\t\6\4\7\t\7\4\b\t\b\4\t\t\t\4\n\t\n\4\13"+
"\t\13\4\f\t\f\4\r\t\r\4\16\t\16\4\17\t\17\4\20\t\20\4\21\t\21\4\22\t\22"+
"\4\23\t\23\4\24\t\24\4\25\t\25\4\26\t\26\4\27\t\27\4\30\t\30\4\31\t\31"+
"\3\2\3\2\3\2\3\3\3\3\3\3\3\4\3\4\3\4\3\5\3\5\3\5\3\6\3\6\3\6\3\7\3\7\3"+
"\7\3\b\3\b\3\b\3\t\3\t\3\t\3\n\3\n\3\n\3\13\3\13\3\13\3\f\3\f\3\f\3\r"+
"\3\r\3\r\3\16\3\16\3\16\3\17\3\17\3\17\3\20\3\20\3\20\3\21\3\21\3\21\3"+
"\22\3\22\3\22\3\23\3\23\3\23\3\24\3\24\3\24\3\25\3\25\3\25\3\26\3\26\3"+
"\26\3\27\3\27\3\27\3\30\3\30\3\30\3\31\6\31z\n\31\r\31\16\31{\3\31\3\31"+
"\2\2\32\3\3\5\4\7\5\t\6\13\7\r\b\17\t\21\n\23\13\25\f\27\r\31\16\33\17"+
"\35\20\37\21!\22#\23%\24\'\25)\26+\27-\30/\31\61\32\3\2\3\5\2\13\f\17"+
"\17\"\"\177\2\3\3\2\2\2\2\5\3\2\2\2\2\7\3\2\2\2\2\t\3\2\2\2\2\13\3\2\2"+
"\2\2\r\3\2\2\2\2\17\3\2\2\2\2\21\3\2\2\2\2\23\3\2\2\2\2\25\3\2\2\2\2\27"+
"\3\2\2\2\2\31\3\2\2\2\2\33\3\2\2\2\2\35\3\2\2\2\2\37\3\2\2\2\2!\3\2\2"+
"\2\2#\3\2\2\2\2%\3\2\2\2\2\'\3\2\2\2\2)\3\2\2\2\2+\3\2\2\2\2-\3\2\2\2"+
"\2/\3\2\2\2\2\61\3\2\2\2\3\63\3\2\2\2\5\66\3\2\2\2\79\3\2\2\2\t<\3\2\2"+
"\2\13?\3\2\2\2\rB\3\2\2\2\17E\3\2\2\2\21H\3\2\2\2\23K\3\2\2\2\25N\3\2"+
"\2\2\27Q\3\2\2\2\31T\3\2\2\2\33W\3\2\2\2\35Z\3\2\2\2\37]\3\2\2\2!`\3\2"+
"\2\2#c\3\2\2\2%f\3\2\2\2\'i\3\2\2\2)l\3\2\2\2+o\3\2\2\2-r\3\2\2\2/u\3"+
"\2\2\2\61y\3\2\2\2\63\64\7\u6e07\2\2\64\65\7\u5c51\2\2\65\4\3\2\2\2\66"+
"\67\7\u6e07\2\2\678\7\u7a7c\2\28\6\3\2\2\29:\7\u6e07\2\2:;\7\u9666\2\2"+
";\b\3\2\2\2<=\7\u516a\2\2=>\7\u90ea\2\2>\n\3\2\2\2?@\7\u64a6\2\2@A\7\u9502"+
"\2\2A\f\3\2\2\2BC\7\u53d8\2\2CD\7\u6d8a\2\2D\16\3\2\2\2EF\7\u5014\2\2"+
"FG\7\u9002\2\2G\20\3\2\2\2HI\7\u5410\2\2IJ\7\u9002\2\2J\22\3\2\2\2KL\7"+
"\u5222\2\2LM\7\u9666\2\2M\24\3\2\2\2NO\7\u5e30\2\2OP\7\u52ab\2\2P\26\3"+
"\2\2\2QR\7\u793c\2\2RS\7\u4f8d\2\2S\30\3\2\2\2TU\7\u8bf6\2\2UV\7\u6610"+
"\2\2V\32\3\2\2\2WX\7\u5349\2\2XY\7\u7ea9\2\2Y\34\3\2\2\2Z[\7\u724a\2\2"+
"[\\\7\u672e\2\2\\\36\3\2\2\2]^\7\u4e3d\2\2^_\7\u989a\2\2_ \3\2\2\2`a\7"+
"\u98d0\2\2ab\7\u683e\2\2b\"\3\2\2\2cd\7\u80ce\2\2de\7\u6671\2\2e$\3\2"+
"\2\2fg\7\u5f17\2\2gh\7\u64d0\2\2h&\3\2\2\2ij\7\u7680\2\2jk\7\u5ea8\2\2"+
"k(\3\2\2\2lm\7\u8bb1\2\2mn\7\u98e0\2\2n*\3\2\2\2op\7\u9002\2\2pq\7\u51fc"+
"\2\2q,\3\2\2\2rs\7\u5175\2\2st\7\u95ef\2\2t.\3\2\2\2uv\7\u6684\2\2vw\7"+
"\u505e\2\2w\60\3\2\2\2xz\t\2\2\2yx\3\2\2\2z{\3\2\2\2{y\3\2\2\2{|\3\2\2"+
"\2|}\3\2\2\2}~\b\31\2\2~\62\3\2\2\2\4\2{\3\2\3\2";
public static final ATN _ATN =
new ATNDeserializer().deserialize(_serializedATN.toCharArray());
static {
_decisionToDFA = new DFA[_ATN.getNumberOfDecisions()];
for (int i = 0; i < _ATN.getNumberOfDecisions(); i++) {
_decisionToDFA[i] = new DFA(_ATN.getDecisionState(i), i);
}
}
}

@ -0,0 +1,597 @@
// Generated from src/org/xing/calc/cmd/grammer/cmd.g4 by ANTLR 4.6
package org.xing.calc.cmd.grammer;
import org.antlr.v4.runtime.atn.*;
import org.antlr.v4.runtime.dfa.DFA;
import org.antlr.v4.runtime.*;
import org.antlr.v4.runtime.misc.*;
import org.antlr.v4.runtime.tree.*;
import java.util.List;
import java.util.Iterator;
import java.util.ArrayList;
@SuppressWarnings({"all", "warnings", "unchecked", "unused", "cast"})
public class cmdParser extends Parser {
static { RuntimeMetaData.checkVersion("4.6", RuntimeMetaData.VERSION); }
protected static final DFA[] _decisionToDFA;
protected static final PredictionContextCache _sharedContextCache =
new PredictionContextCache();
public static final int
T__0=1, T__1=2, T__2=3, T__3=4, T__4=5, T__5=6, T__6=7, T__7=8, T__8=9,
T__9=10, T__10=11, T__11=12, T__12=13, T__13=14, T__14=15, T__15=16, T__16=17,
T__17=18, T__18=19, T__19=20, T__20=21, T__21=22, T__22=23, WS=24;
public static final int
RULE_command = 0, RULE_qingping = 1, RULE_goback = 2, RULE_help = 3, RULE_update = 4,
RULE_theme = 5, RULE_engine = 6, RULE_close = 7, RULE_stop = 8;
public static final String[] ruleNames = {
"command", "qingping", "goback", "help", "update", "theme", "engine",
"close", "stop"
};
private static final String[] _LITERAL_NAMES = {
null, "'清屏'", "'清空'", "'清除'", "'全部'", "'撤销'", "'取消'", "'倒退'", "'后退'",
"'删除'", "'帮助'", "'示例'", "'说明'", "'升级'", "'版本'", "'主题'", "'风格'", "'背景'",
"'引擎'", "'百度'", "'讯飞'", "'退出'", "'关闭'", "'暂停'"
};
private static final String[] _SYMBOLIC_NAMES = {
null, null, null, null, null, null, null, null, null, null, null, null,
null, null, null, null, null, null, null, null, null, null, null, null,
"WS"
};
public static final Vocabulary VOCABULARY = new VocabularyImpl(_LITERAL_NAMES, _SYMBOLIC_NAMES);
/**
* @deprecated Use {@link #VOCABULARY} instead.
*/
@Deprecated
public static final String[] tokenNames;
static {
tokenNames = new String[_SYMBOLIC_NAMES.length];
for (int i = 0; i < tokenNames.length; i++) {
tokenNames[i] = VOCABULARY.getLiteralName(i);
if (tokenNames[i] == null) {
tokenNames[i] = VOCABULARY.getSymbolicName(i);
}
if (tokenNames[i] == null) {
tokenNames[i] = "<INVALID>";
}
}
}
@Override
@Deprecated
public String[] getTokenNames() {
return tokenNames;
}
@Override
public Vocabulary getVocabulary() {
return VOCABULARY;
}
@Override
public String getGrammarFileName() { return "cmd.g4"; }
@Override
public String[] getRuleNames() { return ruleNames; }
@Override
public String getSerializedATN() { return _serializedATN; }
@Override
public ATN getATN() { return _ATN; }
public cmdParser(TokenStream input) {
super(input);
_interp = new ParserATNSimulator(this,_ATN,_decisionToDFA,_sharedContextCache);
}
public static class CommandContext extends ParserRuleContext {
public QingpingContext qingping() {
return getRuleContext(QingpingContext.class,0);
}
public GobackContext goback() {
return getRuleContext(GobackContext.class,0);
}
public HelpContext help() {
return getRuleContext(HelpContext.class,0);
}
public UpdateContext update() {
return getRuleContext(UpdateContext.class,0);
}
public ThemeContext theme() {
return getRuleContext(ThemeContext.class,0);
}
public EngineContext engine() {
return getRuleContext(EngineContext.class,0);
}
public CloseContext close() {
return getRuleContext(CloseContext.class,0);
}
public StopContext stop() {
return getRuleContext(StopContext.class,0);
}
public CommandContext(ParserRuleContext parent, int invokingState) {
super(parent, invokingState);
}
@Override public int getRuleIndex() { return RULE_command; }
@Override
public <T> T accept(ParseTreeVisitor<? extends T> visitor) {
if ( visitor instanceof cmdVisitor ) return ((cmdVisitor<? extends T>)visitor).visitCommand(this);
else return visitor.visitChildren(this);
}
}
public final CommandContext command() throws RecognitionException {
CommandContext _localctx = new CommandContext(_ctx, getState());
enterRule(_localctx, 0, RULE_command);
try {
setState(26);
_errHandler.sync(this);
switch (_input.LA(1)) {
case T__0:
case T__1:
case T__2:
case T__3:
enterOuterAlt(_localctx, 1);
{
setState(18);
qingping();
}
break;
case T__4:
case T__5:
case T__6:
case T__7:
case T__8:
enterOuterAlt(_localctx, 2);
{
setState(19);
goback();
}
break;
case T__9:
case T__10:
case T__11:
enterOuterAlt(_localctx, 3);
{
setState(20);
help();
}
break;
case T__12:
case T__13:
enterOuterAlt(_localctx, 4);
{
setState(21);
update();
}
break;
case T__14:
case T__15:
case T__16:
enterOuterAlt(_localctx, 5);
{
setState(22);
theme();
}
break;
case T__17:
case T__18:
case T__19:
enterOuterAlt(_localctx, 6);
{
setState(23);
engine();
}
break;
case T__20:
case T__21:
enterOuterAlt(_localctx, 7);
{
setState(24);
close();
}
break;
case T__22:
enterOuterAlt(_localctx, 8);
{
setState(25);
stop();
}
break;
default:
throw new NoViableAltException(this);
}
}
catch (RecognitionException re) {
_localctx.exception = re;
_errHandler.reportError(this, re);
_errHandler.recover(this, re);
}
finally {
exitRule();
}
return _localctx;
}
public static class QingpingContext extends ParserRuleContext {
public GobackContext goback() {
return getRuleContext(GobackContext.class,0);
}
public QingpingContext(ParserRuleContext parent, int invokingState) {
super(parent, invokingState);
}
@Override public int getRuleIndex() { return RULE_qingping; }
@Override
public <T> T accept(ParseTreeVisitor<? extends T> visitor) {
if ( visitor instanceof cmdVisitor ) return ((cmdVisitor<? extends T>)visitor).visitQingping(this);
else return visitor.visitChildren(this);
}
}
public final QingpingContext qingping() throws RecognitionException {
QingpingContext _localctx = new QingpingContext(_ctx, getState());
enterRule(_localctx, 2, RULE_qingping);
try {
setState(33);
_errHandler.sync(this);
switch (_input.LA(1)) {
case T__0:
enterOuterAlt(_localctx, 1);
{
setState(28);
match(T__0);
}
break;
case T__1:
enterOuterAlt(_localctx, 2);
{
setState(29);
match(T__1);
}
break;
case T__2:
enterOuterAlt(_localctx, 3);
{
setState(30);
match(T__2);
}
break;
case T__3:
enterOuterAlt(_localctx, 4);
{
{
setState(31);
match(T__3);
setState(32);
goback();
}
}
break;
default:
throw new NoViableAltException(this);
}
}
catch (RecognitionException re) {
_localctx.exception = re;
_errHandler.reportError(this, re);
_errHandler.recover(this, re);
}
finally {
exitRule();
}
return _localctx;
}
public static class GobackContext extends ParserRuleContext {
public GobackContext(ParserRuleContext parent, int invokingState) {
super(parent, invokingState);
}
@Override public int getRuleIndex() { return RULE_goback; }
@Override
public <T> T accept(ParseTreeVisitor<? extends T> visitor) {
if ( visitor instanceof cmdVisitor ) return ((cmdVisitor<? extends T>)visitor).visitGoback(this);
else return visitor.visitChildren(this);
}
}
public final GobackContext goback() throws RecognitionException {
GobackContext _localctx = new GobackContext(_ctx, getState());
enterRule(_localctx, 4, RULE_goback);
int _la;
try {
enterOuterAlt(_localctx, 1);
{
setState(35);
_la = _input.LA(1);
if ( !((((_la) & ~0x3f) == 0 && ((1L << _la) & ((1L << T__4) | (1L << T__5) | (1L << T__6) | (1L << T__7) | (1L << T__8))) != 0)) ) {
_errHandler.recoverInline(this);
}
else {
if ( _input.LA(1)==Token.EOF ) matchedEOF = true;
_errHandler.reportMatch(this);
consume();
}
}
}
catch (RecognitionException re) {
_localctx.exception = re;
_errHandler.reportError(this, re);
_errHandler.recover(this, re);
}
finally {
exitRule();
}
return _localctx;
}
public static class HelpContext extends ParserRuleContext {
public HelpContext(ParserRuleContext parent, int invokingState) {
super(parent, invokingState);
}
@Override public int getRuleIndex() { return RULE_help; }
@Override
public <T> T accept(ParseTreeVisitor<? extends T> visitor) {
if ( visitor instanceof cmdVisitor ) return ((cmdVisitor<? extends T>)visitor).visitHelp(this);
else return visitor.visitChildren(this);
}
}
public final HelpContext help() throws RecognitionException {
HelpContext _localctx = new HelpContext(_ctx, getState());
enterRule(_localctx, 6, RULE_help);
int _la;
try {
enterOuterAlt(_localctx, 1);
{
setState(37);
_la = _input.LA(1);
if ( !((((_la) & ~0x3f) == 0 && ((1L << _la) & ((1L << T__9) | (1L << T__10) | (1L << T__11))) != 0)) ) {
_errHandler.recoverInline(this);
}
else {
if ( _input.LA(1)==Token.EOF ) matchedEOF = true;
_errHandler.reportMatch(this);
consume();
}
}
}
catch (RecognitionException re) {
_localctx.exception = re;
_errHandler.reportError(this, re);
_errHandler.recover(this, re);
}
finally {
exitRule();
}
return _localctx;
}
public static class UpdateContext extends ParserRuleContext {
public UpdateContext(ParserRuleContext parent, int invokingState) {
super(parent, invokingState);
}
@Override public int getRuleIndex() { return RULE_update; }
@Override
public <T> T accept(ParseTreeVisitor<? extends T> visitor) {
if ( visitor instanceof cmdVisitor ) return ((cmdVisitor<? extends T>)visitor).visitUpdate(this);
else return visitor.visitChildren(this);
}
}
public final UpdateContext update() throws RecognitionException {
UpdateContext _localctx = new UpdateContext(_ctx, getState());
enterRule(_localctx, 8, RULE_update);
int _la;
try {
enterOuterAlt(_localctx, 1);
{
setState(39);
_la = _input.LA(1);
if ( !(_la==T__12 || _la==T__13) ) {
_errHandler.recoverInline(this);
}
else {
if ( _input.LA(1)==Token.EOF ) matchedEOF = true;
_errHandler.reportMatch(this);
consume();
}
}
}
catch (RecognitionException re) {
_localctx.exception = re;
_errHandler.reportError(this, re);
_errHandler.recover(this, re);
}
finally {
exitRule();
}
return _localctx;
}
public static class ThemeContext extends ParserRuleContext {
public ThemeContext(ParserRuleContext parent, int invokingState) {
super(parent, invokingState);
}
@Override public int getRuleIndex() { return RULE_theme; }
@Override
public <T> T accept(ParseTreeVisitor<? extends T> visitor) {
if ( visitor instanceof cmdVisitor ) return ((cmdVisitor<? extends T>)visitor).visitTheme(this);
else return visitor.visitChildren(this);
}
}
public final ThemeContext theme() throws RecognitionException {
ThemeContext _localctx = new ThemeContext(_ctx, getState());
enterRule(_localctx, 10, RULE_theme);
int _la;
try {
enterOuterAlt(_localctx, 1);
{
setState(41);
_la = _input.LA(1);
if ( !((((_la) & ~0x3f) == 0 && ((1L << _la) & ((1L << T__14) | (1L << T__15) | (1L << T__16))) != 0)) ) {
_errHandler.recoverInline(this);
}
else {
if ( _input.LA(1)==Token.EOF ) matchedEOF = true;
_errHandler.reportMatch(this);
consume();
}
}
}
catch (RecognitionException re) {
_localctx.exception = re;
_errHandler.reportError(this, re);
_errHandler.recover(this, re);
}
finally {
exitRule();
}
return _localctx;
}
public static class EngineContext extends ParserRuleContext {
public EngineContext(ParserRuleContext parent, int invokingState) {
super(parent, invokingState);
}
@Override public int getRuleIndex() { return RULE_engine; }
@Override
public <T> T accept(ParseTreeVisitor<? extends T> visitor) {
if ( visitor instanceof cmdVisitor ) return ((cmdVisitor<? extends T>)visitor).visitEngine(this);
else return visitor.visitChildren(this);
}
}
public final EngineContext engine() throws RecognitionException {
EngineContext _localctx = new EngineContext(_ctx, getState());
enterRule(_localctx, 12, RULE_engine);
int _la;
try {
enterOuterAlt(_localctx, 1);
{
setState(43);
_la = _input.LA(1);
if ( !((((_la) & ~0x3f) == 0 && ((1L << _la) & ((1L << T__17) | (1L << T__18) | (1L << T__19))) != 0)) ) {
_errHandler.recoverInline(this);
}
else {
if ( _input.LA(1)==Token.EOF ) matchedEOF = true;
_errHandler.reportMatch(this);
consume();
}
}
}
catch (RecognitionException re) {
_localctx.exception = re;
_errHandler.reportError(this, re);
_errHandler.recover(this, re);
}
finally {
exitRule();
}
return _localctx;
}
public static class CloseContext extends ParserRuleContext {
public CloseContext(ParserRuleContext parent, int invokingState) {
super(parent, invokingState);
}
@Override public int getRuleIndex() { return RULE_close; }
@Override
public <T> T accept(ParseTreeVisitor<? extends T> visitor) {
if ( visitor instanceof cmdVisitor ) return ((cmdVisitor<? extends T>)visitor).visitClose(this);
else return visitor.visitChildren(this);
}
}
public final CloseContext close() throws RecognitionException {
CloseContext _localctx = new CloseContext(_ctx, getState());
enterRule(_localctx, 14, RULE_close);
int _la;
try {
enterOuterAlt(_localctx, 1);
{
setState(45);
_la = _input.LA(1);
if ( !(_la==T__20 || _la==T__21) ) {
_errHandler.recoverInline(this);
}
else {
if ( _input.LA(1)==Token.EOF ) matchedEOF = true;
_errHandler.reportMatch(this);
consume();
}
}
}
catch (RecognitionException re) {
_localctx.exception = re;
_errHandler.reportError(this, re);
_errHandler.recover(this, re);
}
finally {
exitRule();
}
return _localctx;
}
public static class StopContext extends ParserRuleContext {
public StopContext(ParserRuleContext parent, int invokingState) {
super(parent, invokingState);
}
@Override public int getRuleIndex() { return RULE_stop; }
@Override
public <T> T accept(ParseTreeVisitor<? extends T> visitor) {
if ( visitor instanceof cmdVisitor ) return ((cmdVisitor<? extends T>)visitor).visitStop(this);
else return visitor.visitChildren(this);
}
}
public final StopContext stop() throws RecognitionException {
StopContext _localctx = new StopContext(_ctx, getState());
enterRule(_localctx, 16, RULE_stop);
try {
enterOuterAlt(_localctx, 1);
{
setState(47);
match(T__22);
}
}
catch (RecognitionException re) {
_localctx.exception = re;
_errHandler.reportError(this, re);
_errHandler.recover(this, re);
}
finally {
exitRule();
}
return _localctx;
}
public static final String _serializedATN =
"\3\u0430\ud6d1\u8206\uad2d\u4417\uaef1\u8d80\uaadd\3\32\64\4\2\t\2\4\3"+
"\t\3\4\4\t\4\4\5\t\5\4\6\t\6\4\7\t\7\4\b\t\b\4\t\t\t\4\n\t\n\3\2\3\2\3"+
"\2\3\2\3\2\3\2\3\2\3\2\5\2\35\n\2\3\3\3\3\3\3\3\3\3\3\5\3$\n\3\3\4\3\4"+
"\3\5\3\5\3\6\3\6\3\7\3\7\3\b\3\b\3\t\3\t\3\n\3\n\3\n\2\2\13\2\4\6\b\n"+
"\f\16\20\22\2\b\3\2\7\13\3\2\f\16\3\2\17\20\3\2\21\23\3\2\24\26\3\2\27"+
"\30\64\2\34\3\2\2\2\4#\3\2\2\2\6%\3\2\2\2\b\'\3\2\2\2\n)\3\2\2\2\f+\3"+
"\2\2\2\16-\3\2\2\2\20/\3\2\2\2\22\61\3\2\2\2\24\35\5\4\3\2\25\35\5\6\4"+
"\2\26\35\5\b\5\2\27\35\5\n\6\2\30\35\5\f\7\2\31\35\5\16\b\2\32\35\5\20"+
"\t\2\33\35\5\22\n\2\34\24\3\2\2\2\34\25\3\2\2\2\34\26\3\2\2\2\34\27\3"+
"\2\2\2\34\30\3\2\2\2\34\31\3\2\2\2\34\32\3\2\2\2\34\33\3\2\2\2\35\3\3"+
"\2\2\2\36$\7\3\2\2\37$\7\4\2\2 $\7\5\2\2!\"\7\6\2\2\"$\5\6\4\2#\36\3\2"+
"\2\2#\37\3\2\2\2# \3\2\2\2#!\3\2\2\2$\5\3\2\2\2%&\t\2\2\2&\7\3\2\2\2\'"+
"(\t\3\2\2(\t\3\2\2\2)*\t\4\2\2*\13\3\2\2\2+,\t\5\2\2,\r\3\2\2\2-.\t\6"+
"\2\2.\17\3\2\2\2/\60\t\7\2\2\60\21\3\2\2\2\61\62\7\31\2\2\62\23\3\2\2"+
"\2\4\34#";
public static final ATN _ATN =
new ATNDeserializer().deserialize(_serializedATN.toCharArray());
static {
_decisionToDFA = new DFA[_ATN.getNumberOfDecisions()];
for (int i = 0; i < _ATN.getNumberOfDecisions(); i++) {
_decisionToDFA[i] = new DFA(_ATN.getDecisionState(i), i);
}
}
}

@ -0,0 +1,67 @@
// Generated from src/org/xing/calc/cmd/grammer/cmd.g4 by ANTLR 4.6
package org.xing.calc.cmd.grammer;
import org.antlr.v4.runtime.tree.ParseTreeVisitor;
/**
* This interface defines a complete generic visitor for a parse tree produced
* by {@link cmdParser}.
*
* @param <T> The return type of the visit operation. Use {@link Void} for
* operations with no return type.
*/
public interface cmdVisitor<T> extends ParseTreeVisitor<T> {
/**
* Visit a parse tree produced by {@link cmdParser#command}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitCommand(cmdParser.CommandContext ctx);
/**
* Visit a parse tree produced by {@link cmdParser#qingping}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitQingping(cmdParser.QingpingContext ctx);
/**
* Visit a parse tree produced by {@link cmdParser#goback}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitGoback(cmdParser.GobackContext ctx);
/**
* Visit a parse tree produced by {@link cmdParser#help}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitHelp(cmdParser.HelpContext ctx);
/**
* Visit a parse tree produced by {@link cmdParser#update}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitUpdate(cmdParser.UpdateContext ctx);
/**
* Visit a parse tree produced by {@link cmdParser#theme}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitTheme(cmdParser.ThemeContext ctx);
/**
* Visit a parse tree produced by {@link cmdParser#engine}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitEngine(cmdParser.EngineContext ctx);
/**
* Visit a parse tree produced by {@link cmdParser#close}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitClose(cmdParser.CloseContext ctx);
/**
* Visit a parse tree produced by {@link cmdParser#stop}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitStop(cmdParser.StopContext ctx);
}

@ -0,0 +1,210 @@
package org.xing.calc.filter;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class CorrectionExprFilter implements ExprFilter {
private StringBuilder regStr;
private Map<String, String> correctionStringMap;
public CorrectionExprFilter() {
regStr = new StringBuilder();
correctionStringMap = new HashMap<>();
addWord("佛", "负");
addWord("塑", "负");
addWord("僵", "加");
addWord("讲", "加");
addWord("将", "加");
addWord("奖", "加");
addWord("缉", "减");
addWord("倍", "乘");
addWord("澄", "乘");
addWord("橙", "乘");
addWord("盛", "乘");
addWord("重", "乘");
addWord("层", "乘");
addWord("曾", "乘");
addWord("城里", "乘以");
addWord("成语", "乘以");
addWord("初一", "除以");
addWord("乘与", "除以");
addWord("完了", "");
addWord("区", "除");
addWord("褚", "除");
addWord("括弧", "括号");
//一块二这种金额的表达方式
addWord("块", "点");
addWord(":", "点");
addWord("", "点");
addWord("幺", "一");
addWord("e", "一");
addWord("两", "二");
addWord("俩", "二");
addWord("山", "3");
addWord("善", "3");
addWord("潘", "3");
addWord("仨", "三");
addWord("是", "4");
addWord("事", "4");
addWord("士", "4");
addWord("式", "4");
addWord("氏", "4");
addWord("市", "4");
addWord("世", "4");
addWord("师", "4");
addWord("我", "5");
addWord("陆", "6");
addWord("料", "6");
addWord("乐", "6");
addWord("榴", "6");
addWord("亲", "7");
addWord("鸡", "7");
addWord("夕", "7");
addWord("欹", "7");
addWord("班", "8");
addWord("发", "8");
addWord("近", "9");
addWord("教", "9");
addWord("鱼线", "余弦");
addWord("预先", "余弦");
addWord("遇险", "余弦");
addWord("鱼鲜", "余弦");
addWord("玉仙", "余弦");
addWord("欲仙", "余弦");
addWord("预选", "余弦");
addWord("雨轩", "余弦");
addWord("宇轩", "余弦");
addWord("预选", "余弦");
addWord("玉轩", "余弦");
addWord("范玉献", "反余弦");
addWord("范瑜轩", "反余弦");
addWord("赣榆县", "反余弦");
addWord("争先", "正弦");
addWord("正线", "正弦");
addWord("争鲜", "正弦");
addWord("正选", "正弦");
addWord("郑玄", "正弦");
addWord("郑璇", "正弦");
addWord("反正选", "反正弦");
addWord("反正旋", "反正弦");
addWord("正确", "正切");
addWord("争取", "正切");
addWord("证券", "正切");
addWord("挣钱", "正切");
addWord("正气", "正切");
addWord("争气", "正切");
addWord("政权", "正切");
addWord("征求", "正切");
addWord("反正钱", "反正切");
addWord("反正去", "反正切");
addWord("括回", "括号");
addWord("货号", "括号");
addWord("对手", "对数");
addWord("开封", "开方");
addWord("次幂", "次方");
addWord("等于", "");
addWord("多少", "");
addWord("的差", "");
addWord("的和", "");
addWord("的积", "");
addWord("的商", "");
addWord("%", "/100");
addWord("", "/100");
addWord("以前", "一千");
addWord("^2", "的平方");
addWord("佳茵", "加一");
addWord("捡漏", "减六");
addWord("捡了", "减六");
addWord("图六", "除六");
addWord("除了", "除六");
addWord("成龙", "乘六");
addWord("成了", "乘六");
addWord("天气", "减七");
addWord("欹", "七");
addWord("成绩", "乘七");
addWord("长期", "乘七");
addWord("城西", "乘七");
addWord("晨曦", "乘七");
addWord("城邦", "乘八");
addWord("乘邦", "乘八");
addWord("主角", "除九");
addWord("图九", "除九");
addWord("圆周率", "派");
addWord("请您", "清零");
addWord("清平", "清屏");
addWord("青平", "清屏");
addWord("青萍", "清屏");
addWord("青苹", "清屏");
addWord("蜻蜓", "清屏");
addWord("金瓶", "清屏");
addWord("金平", "清屏");
addWord("亲萍", "清屏");
addWord("星空", "清空");
addWord("净空", "清空");
addWord("浙江", "撤销");
addWord("大腿", "倒退");
addWord("车享", "倒退");
addWord("阴茎", "引擎");
addWord("隐形", "引擎");
}
private void addWord(String tar, String with) {
if(regStr.length() > 0) {
regStr.append("|");
}
regStr.append("(");
String temp = tar;
temp = temp.replace("^", "\\^");
temp = temp.replace("%", "\\%");
regStr.append(temp);
regStr.append(")");
correctionStringMap.put(tar, with);
}
@Override
public String call(String expr) {
int start = 0;
StringBuilder str = new StringBuilder();
Pattern correctionPattern = Pattern.compile(regStr.toString());
Matcher mch = correctionPattern.matcher(expr);
while(mch.find()) {
if(mch.start() > start) {
str.append(expr.substring(start, mch.start()));
}
str.append(correctionStringMap.get(mch.group()));
start = mch.end();
}
if(start < expr.length()) {
str.append(expr.substring(start));
}
return str.toString();
}
}

@ -0,0 +1,5 @@
package org.xing.calc.filter;
public interface ExprFilter {
String call(String expr);
}

@ -0,0 +1,33 @@
package org.xing.calc.filter;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
/**
* Created by xing on 2017/5/10.
*/
public class ExprFilterChain implements ExprFilter {
private LinkedList<ExprFilter> filters;
public ExprFilterChain() {
filters = new LinkedList<>();
}
public ExprFilterChain(String allowedChars, HashMap<Character, String> pinyin) {
filters = new LinkedList<>();
filters.add(new CorrectionExprFilter());
filters.add(new PinyinExprFilter(allowedChars, pinyin));
}
public void addExprFilter(ExprFilter filter) {
filters.add(filter);
}
public String call(String expr) {
String temp = expr;
for(ExprFilter filter : filters) {
temp = filter.call(temp);
}
return temp;
}
}

@ -0,0 +1,106 @@
package org.xing.calc.filter;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
public class PinyinExprFilter implements ExprFilter{
private Set<Character> allowedChars;
private Map<String, Character> allowedCharsPinyin;
private HashMap<Character, String> pinyin;
public PinyinExprFilter(String legalChars, HashMap<Character, String> pinyin) {
this.pinyin = (HashMap<Character, String> )pinyin.clone();
allowedChars = new HashSet<Character>();
allowedCharsPinyin = new HashMap<String, Character>();
for(int i=0;i<legalChars.length();i++) {
Character c = legalChars.charAt(i);
allowedChars.add(c);
if(pinyin!= null && pinyin.containsKey(c)) {
if(allowedCharsPinyin.containsKey(pinyin.get(c))) {
System.err.println("严重错误,有拼音相同的字:"+c);
}else {
allowedCharsPinyin.put(pinyin.get(c), c);
}
}
}
//通过拼音来加入纠正一批由于用户读音不准确导致的识别错误
allowedCharsPinyin.put("qu", '除');
allowedCharsPinyin.put("ceng", '乘');
allowedCharsPinyin.put("xuan", '弦');
allowedCharsPinyin.put("yao", '一');
}
public static HashMap<Character, String> loadTokens(InputStream input) {
HashMap<Character, String> pinyin = new HashMap<Character, String>();
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(input, "utf-8"));
String line = null;
while((line = reader.readLine()) != null) {
if(line.length() > 0) {
String[] fields = line.split("\\s+");
String charPinyin = fields[1];
String chars = fields[2];
for(int i=0;i<chars.length();i++) {
pinyin.put(chars.charAt(i), charPinyin);
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
return pinyin;
}
@Override
public String call(String expr) {
StringBuilder str = new StringBuilder();
for(int i=0;i<expr.length();i++) {
Character c = expr.charAt(i);
if(allowedChars.contains(c)) {
str.append(c);
}else if(pinyin!= null && pinyin.containsKey(c)){
String py = pinyin.get(c);
if(allowedCharsPinyin.containsKey(py)) {
str.append(allowedCharsPinyin.get(py));
}else {
//很多人前后鼻音不分
py = py+"g";
if(allowedCharsPinyin.containsKey(py)) {
str.append(allowedCharsPinyin.get(py));
}
}
}
}
/*
*/
String result = str.toString();
if(result.endsWith("加") || result.endsWith("减")
|| result.endsWith("乘") || result.endsWith("点")
|| result.endsWith("+") || result.endsWith("-")
|| result.endsWith("×") || result.endsWith("/") ) {
result = result.substring(0, result.length()-1);
} else if(result.endsWith("加上") || result.endsWith("减去")
|| result.endsWith("乘以") || result.endsWith("除以")) {
result = result.substring(0, result.length()-2);
} else if(result.startsWith("-")){
/*讯飞语音直接将‘负’改成了‘-’号,导致错误的识别为连续计算*/
result = "负" + result.substring(1, result.length());
}
return result;
}
}

@ -0,0 +1,223 @@
package org.xing.calc.parser;
import org.antlr.v4.runtime.tree.TerminalNode;
import org.xing.calc.parser.grammer.calculatorBaseVisitor;
import org.xing.calc.parser.grammer.calculatorParser;
import org.xing.calc.parser.grammer.calculatorParser.FuncnameContext;
import org.xing.calc.parser.grammer.calculatorParser.FuncnameExContext;
import org.xing.calc.parser.grammer.calculatorParser.FunctionContext;
import org.xing.calc.parser.grammer.calculatorParser.PostFuncnameContext;
public class CalculatorEvalVisitor extends calculatorBaseVisitor<Double> {
private NumberParser numParser;
public CalculatorEvalVisitor() {
numParser = new NumberParser();
}
@Override
public Double visitExpression(calculatorParser.ExpressionContext ctx) {
Double result = visit(ctx.getChild(0));
if(ctx.getChildCount() > 2) {
for(int i=1;i<ctx.getChildCount();i+=2) {
TerminalNode oper = (TerminalNode)ctx.getChild(i);
Double exprValue = visit(ctx.getChild(i+1));
if(oper.getSymbol().getType() == calculatorParser.PLUS) {
result = result + exprValue;
} else {
result = result - exprValue;
}
}
}
return result;
}
@Override
public Double visitMultiplyingExpression(
calculatorParser.MultiplyingExpressionContext ctx) {
Double result = visit(ctx.getChild(0));
if(ctx.getChildCount() > 2) {
for(int i=1;i<ctx.getChildCount();i+=2) {
TerminalNode oper = (TerminalNode)ctx.getChild(i);
Double exprValue = visit(ctx.getChild(i+1));
if(oper.getSymbol().getType() == calculatorParser.DIV) {
result = result / exprValue;
} else {
result = result * exprValue;
}
}
}
return result;
}
@Override
public Double visitPowExpression(calculatorParser.PowExpressionContext ctx) {
Double result = Double.NaN;
int index = 0;
result = visit(ctx.getChild(index++));
while (index < ctx.getChildCount()) {
TerminalNode node = (TerminalNode) ctx.getChild(index);
if(node.getSymbol().getType() == calculatorParser.DE) {
if (ctx.getChild(index + 1) instanceof TerminalNode) {
int type = ((TerminalNode) ctx.getChild(index + 1)).getSymbol()
.getType();
if (type == calculatorParser.PINGFANG) {
result = Math.pow(result, 2);
} else if (type == calculatorParser.LIFANG) {
result = Math.pow(result, 3);
} else {
System.err.println("未处理的终端节点:visitChinaPowExpression");
}
index += 2;
} else {
Double pow = visit(ctx.getChild(index + 1));
result = Math.pow(result, pow);
index += 3;
}
} else {
Double pow = visit(ctx.getChild(index + 1));
result = Math.pow(result, pow);
index += 2;
}
}
return result;
}
@Override
public Double visitAtom(calculatorParser.AtomContext ctx) {
if(ctx.MINUS() != null) {
return -visit(ctx.getChild(1));
}else if(ctx.PLUS() != null) {
return visit(ctx.getChild(1));
}if(ctx.getChildCount() == 3) {
if(ctx.FRAC() != null) {
if(ctx.FRAC().getText().equals("分之")) {
return visit(ctx.getChild(2)) / visit(ctx.getChild(0));
}else {
//分数用'/'表示,这是语音识别的结果导致的,它偶尔自动把分数转化成了'/'
return visit(ctx.getChild(0)) / visit(ctx.getChild(2));
}
}else {
return visit(ctx.expression());
}
}else if(ctx.getChildCount() == 5) {
Double firstNumber = visit(ctx.getChild(0));
Double secondNumber = visit(ctx.getChild(2));
Double thirdNumber = visit(ctx.getChild(4));
//三又2/3 这种被语音识别引擎处理过的表达方式
if(ctx.getChild(3).getText().equals("/")) {
secondNumber = visit(ctx.getChild(4));
thirdNumber = visit(ctx.getChild(2));
}
if(firstNumber < 0) {
return (firstNumber * secondNumber - thirdNumber) / secondNumber;
} else {
return (firstNumber * secondNumber + thirdNumber) / secondNumber;
}
}else {
Double result = visit(ctx.getChild(0));
return result == null? Double.NaN:result;
}
}
@Override
public Double visitFunction(FunctionContext ctx) {
Double result = Double.NaN;
if(ctx.funcnameEx() != null) {
FuncnameExContext func = ctx.funcnameEx();
Double firstNum = visit(ctx.getChild(0));
Double secondNum = visit(ctx.getChild(2));
if(func.DUISHU() != null) {
result = Math.log(secondNum) / Math.log(firstNum);
}else if(func.GENHAO() != null) {
result = Math.pow(secondNum, 1/firstNum);
}
} else if(ctx.funcname() != null){
FuncnameContext func = ctx.funcname();
Double exprValue = visit(ctx.getChild(1));
if(exprValue.isNaN()) return result;
if(func.SIN() != null) {
result = Math.sin(exprValue);
}else if(func.COS() != null) {
result = Math.cos(exprValue);
}else if(func.TAN() != null) {
result = Math.tan(exprValue);
}else if(func.ASIN() != null) {
result = Math.asin(exprValue);
}else if(func.ACOS() != null) {
result = Math.acos(exprValue);
}else if(func.ATAN() != null) {
result = Math.atan(exprValue);
}else if(func.LG() != null) {
result = Math.log10(exprValue);
}else if(func.LOG() != null) {
result = Math.log(exprValue) / Math.log(2);
}else if(func.LN() != null) {
result = Math.log(exprValue);
}else if(func.GENHAO() != null) {
result = Math.pow(exprValue, 0.5);
}else if(func.DUISHU() != null) {
result = Math.log(exprValue);
}else{
System.err.println("Not supported function '"+ctx.funcname()+"'");
}
}else if(ctx.postFuncname() != null) {
PostFuncnameContext postFuncname = ctx.postFuncname();
Double exprValue = visit(ctx.getChild(0));
if(postFuncname.KAIFANG() != null
|| postFuncname.KAIPINGFANG() != null) {
result = Math.pow(exprValue, 0.5);
}else if(postFuncname.PINGFANG() != null){
if(postFuncname.GEN() != null) {
result = Math.pow(exprValue, 0.5);
}else {
result = Math.pow(exprValue, 2);
}
}else if(postFuncname.KAILIFANG() != null) {
result = Math.pow(exprValue, 1.0/3);
}else if(postFuncname.LIFANG() != null) {
if(postFuncname.GEN() != null) {
result = Math.pow(exprValue, 1.0/3);
}else {
result = Math.pow(exprValue, 3);
}
}
}
return result;
}
@Override
public Double visitNumber(calculatorParser.NumberContext ctx) {
try{
String expr = ctx.getText();
if(ctx.PAI() != null || ctx.DU() != null) {
if(ctx.DIGIT().isEmpty()) {
return Math.PI;
}
numParser.parse(expr.substring(0, expr.length()-1));
Double result = Double.parseDouble(numParser.getEvalExpr());
if(ctx.PAI() != null) {
return result * Math.PI;
}else {
return result * Math.PI / 180;
}
} else {
numParser.parse(expr);
return Double.parseDouble(numParser.getEvalExpr());
}
}catch(Exception ex) {
return Double.NaN;
}
}
}

@ -0,0 +1,335 @@
package org.xing.calc.parser;
import org.antlr.v4.runtime.tree.ParseTree;
import org.antlr.v4.runtime.tree.TerminalNode;
import org.xing.calc.parser.grammer.calculatorBaseVisitor;
import org.xing.calc.parser.grammer.calculatorParser;
import java.util.Stack;
/**
* Created by xing on 2017/1/1.
*/
public class CalculatorLatexExprVisitor extends calculatorBaseVisitor<String> {
protected NumberParser numParser;
public CalculatorLatexExprVisitor() {
numParser = new NumberParser();
}
public enum AtomType{
None, PosNumber, NegNumber, Sqrt, Frac, Log, Brack, Pow, Mixed
}
private boolean bracketsLeggal(String expr) {
Stack<Character> brackets = new Stack<>();
for(int i=0;i<expr.length();i++) {
Character c = expr.charAt(i);
if(c == '(') {
brackets.add(c);
} else if(c== ')') {
if((!brackets.empty()) && brackets.peek() == '(') {
brackets.pop();
}else {
return false;
}
}
}
if(brackets.empty()) return true;
return false;
}
protected String trimBrackets(String expr) {
if(expr == null) return null;
if(expr.startsWith("(") && expr.endsWith(")")) {
String substr = expr.substring(1, expr.length()-1);
if(bracketsLeggal(substr)) return substr;
}
return expr;
}
public static AtomType getAtomType(String expr) {
if(expr == null) return AtomType.None;
if(expr.startsWith("-")) {
return AtomType.NegNumber;
}else if(expr.startsWith("\\\\sqrt")) {
return AtomType.Sqrt;
}else if(expr.startsWith("\\\\frac")) {
return AtomType.Frac;
}else if(expr.startsWith("log")) {
return AtomType.Log;
}else if(expr.startsWith("(") && expr.endsWith(")")) {
return AtomType.Brack;
}else if(expr.contains("^")) {
return AtomType.Pow;
}else if(expr.contains("\\\\frac")) {
return AtomType.Frac;
}else if(expr.contains("+") || expr.contains("-")
|| expr.contains("÷") || expr.contains("×") ) {
return AtomType.Mixed;
}
return AtomType.PosNumber;
}
public String[] getBrackExpr(String expr) {
String brackResult = expr;
String nonbrackResult = expr;
AtomType atomType = getAtomType(expr);
if(atomType == AtomType.NegNumber || atomType == AtomType.Frac
|| atomType == AtomType.Pow || atomType == AtomType.Log
|| atomType == AtomType.Sqrt || atomType == AtomType.Mixed) {
brackResult = "("+expr + ")";
}else if(atomType == AtomType.Brack) {
nonbrackResult = trimBrackets(expr);
}
return new String[] {brackResult, nonbrackResult};
}
@Override
public String visitExpression(calculatorParser.ExpressionContext ctx) {
StringBuilder result = new StringBuilder();
for(int i=0;i<ctx.getChildCount();i++) {
ParseTree child = ctx.getChild(i);
if(child instanceof TerminalNode) {
int type = ((TerminalNode) child).getSymbol().getType();
if(type == calculatorParser.PLUS) {
result.append("+");
} else {
result.append("-");
}
}else {
String expr = visit(child);
AtomType atomType = getAtomType(expr);
if(atomType == AtomType.NegNumber && result.length() > 0) {
result.append("("+expr+")");
}else {
result.append(expr);
}
}
}
return result.toString();
}
@Override
public String visitMultiplyingExpression(
calculatorParser.MultiplyingExpressionContext ctx) {
StringBuilder result = new StringBuilder();
for(int i=0;i<ctx.getChildCount();i++) {
ParseTree child = ctx.getChild(i);
if(child instanceof TerminalNode) {
int type = ((TerminalNode) child).getSymbol().getType();
if(type == calculatorParser.DIV) {
result.append("/");
} else {
result.append("*");
}
}else {
String expr = visit(child);
AtomType atomType = getAtomType(expr);
if(atomType == AtomType.NegNumber && result.length() > 0) {
result.append("("+expr+")");
}else {
result.append(expr);
}
}
}
return result.toString();
}
@Override
public String visitPowExpression(calculatorParser.PowExpressionContext ctx) {
int index = 0;
String result = visit(ctx.getChild(index++));
while (index < ctx.getChildCount()) {
String[] brackExpr = getBrackExpr(result);
TerminalNode node = (TerminalNode) ctx.getChild(index);
if(node.getSymbol().getType() == calculatorParser.DE) {
if (ctx.getChild(index + 1) instanceof TerminalNode) {
int type = ((TerminalNode) ctx.getChild(index + 1)).getSymbol()
.getType();
if (type == calculatorParser.PINGFANG) {
result = "{" + brackExpr[0] + "}^2";
} else if (type == calculatorParser.LIFANG) {
result = "{" + brackExpr[0] + "}^3";
} else if (type == calculatorParser.KAIFANG) {
result = "\\\\sqrt{" + brackExpr[1] + "}";
} else {
System.err.println("未处理的终端节点:visitChinaPowExpression");
}
index += 2;
} else {
String pow = visit(ctx.getChild(index + 1));
result = "{" + brackExpr[0] + "}^{" + pow + "}";
index += 3;
}
} else {
String pow = visit(ctx.getChild(index + 1));
result = "{" + brackExpr[0] + "}^{" + pow + "}";
index += 2;
}
}
return result;
}
@Override
public String visitAtom(calculatorParser.AtomContext ctx) {
if(ctx.MINUS() != null) {
return "-" + visit(ctx.getChild(1));
}else if(ctx.PLUS() != null) {
return visit(ctx.getChild(1));
}if(ctx.getChildCount() == 3) {
if(ctx.FRAC() != null) {
String expr0 = visit(ctx.getChild(0));
String expr2 = visit(ctx.getChild(2));
//对于负的分数特殊处理
String negTag = "";
boolean neg0 = expr0.startsWith("-");
boolean neg2 = expr2.startsWith("-");
if(neg0 != neg2) {
if(neg0) {
expr0 = expr0.substring(1);
}else {
expr2 = expr2.substring(1);
}
negTag = "-";
}
String[] brackExpr0 = getBrackExpr(expr0);
String[] brackExpr2 = getBrackExpr(expr2);
if(ctx.FRAC().getText().equals("分之")) {
return negTag+"\\\\frac{"+brackExpr2[1]+"}{"+brackExpr0[1]+"}";
}else {
return negTag+"\\\\frac{"+brackExpr0[1]+"}{"+brackExpr2[1]+"}";
}
}else {
String[] brackExpr = getBrackExpr(visit(ctx.expression()));
return "("+brackExpr[1]+")";
}
}else if(ctx.getChildCount() == 5) {
String expr0 = visit(ctx.getChild(0));
String expr2 = visit(ctx.getChild(2));
String expr4 = visit(ctx.getChild(4));
//三又2/3 这种被语音识别引擎处理过的表达方式
if(ctx.getChild(3).getText().equals("/")) {
expr2 = visit(ctx.getChild(4));
expr4 = visit(ctx.getChild(2));
}
return expr0+"\\\\frac{"+expr4+"}{"+expr2+"}";
}else {
return visit(ctx.getChild(0));
}
}
@Override
public String visitFunction(calculatorParser.FunctionContext ctx) {
if(ctx.funcnameEx() != null) {
calculatorParser.FuncnameExContext func = ctx.funcnameEx();
String firstNum = visit(ctx.getChild(0));
String secondNum = visit(ctx.getChild(2));
if(firstNum == null || secondNum == null) return null;
String[] brackFirstNum = getBrackExpr(firstNum);
String[] brackSecondNum = getBrackExpr(secondNum);
if(func.DUISHU() != null) {
return "log_{"+brackFirstNum[0]+"}"+brackSecondNum[0];
}else if(func.GENHAO() != null) {
return "\\\\sqrt["+brackFirstNum[0]+"]{"+brackSecondNum[1]+"}";
}
} else if(ctx.funcname() != null){
String expr = visit(ctx.getChild(1));
calculatorParser.FuncnameContext func = ctx.funcname();
if(expr == null) return null;
String[] brackExpr = getBrackExpr(expr);
if(func.SIN() != null) {
return "sin("+brackExpr[1]+")";
}else if(func.COS() != null) {
return "cos("+brackExpr[1]+")";
}else if(func.TAN() != null) {
return "tan("+brackExpr[1]+")";
}else if(func.ASIN() != null) {
return "asin("+brackExpr[1]+")";
}else if(func.ACOS() != null) {
return "acos("+brackExpr[1]+")";
}else if(func.ATAN() != null) {
return "atan("+brackExpr[1]+")";
}else if(func.LG() != null) {
return "lg("+brackExpr[1]+")";
}else if(func.LOG() != null) {
return "log("+brackExpr[1]+")";
}else if(func.LN() != null) {
return "ln("+brackExpr[1]+")";
}else if(func.GENHAO() != null) {
return "\\\\sqrt{"+brackExpr[1]+"}";
}else if(func.DUISHU() != null) {
return "ln("+brackExpr[1]+")";
}else{
System.err.println("Not supported function '"+ctx.funcname()+"'");
}
}else if(ctx.postFuncname() != null) {
calculatorParser.PostFuncnameContext postFuncname = ctx.postFuncname();
String expr = visit(ctx.getChild(0));
String[] brackExpr = getBrackExpr(expr);
if(postFuncname.KAIFANG() != null
|| postFuncname.KAIPINGFANG() != null) {
return "\\\\sqrt{"+brackExpr[1]+"}";
}else if(postFuncname.PINGFANG() != null) {
if(postFuncname.GEN() != null) {
return "\\\\sqrt{"+brackExpr[1]+"}";
}else {
return expr+"^2";
}
}else if(postFuncname.KAILIFANG() != null) {
return "\\\\sqrt[3]{"+brackExpr[1]+"}";
}else if(postFuncname.LIFANG() != null) {
if(postFuncname.GEN() != null) {
return "\\\\sqrt[3]{"+brackExpr[1]+"}";
}else {
return expr+"^3";
}
}
}
return null;
}
@Override
public String visitNumber(calculatorParser.NumberContext ctx) {
try{
String expr = ctx.getText();
StringBuilder result = new StringBuilder();
if(ctx.PAI() != null || ctx.DU() != null) {
if (ctx.DIGIT().isEmpty()) {
result.append("\\\\pi");
}else {
numParser.parse(expr.substring(0, expr.length() - 1));
result.append(numParser.getReadExpr());
if (ctx.PAI() != null) {
result.append("\\\\pi");
} else {
result.append("\\\\degree");
}
}
} else {
numParser.parse(ctx.getText());
result.append(numParser.getReadExpr());
}
return result.toString();
}catch(Exception ex) {
return null;
}
}
}

@ -0,0 +1,170 @@
package org.xing.calc.parser;
import java.util.HashMap;
import java.util.Map;
public class NumberParser extends Parser {
private Map<Character, String> chineseToMathMap;
private Map<Character, Integer> numberDigitsMap;
public NumberParser() {
chineseToMathMap = new HashMap<Character, String>();
chineseToMathMap.put('零', "0");
chineseToMathMap.put('一', "1");
chineseToMathMap.put('二', "2");
chineseToMathMap.put('三', "3");
chineseToMathMap.put('四', "4");
chineseToMathMap.put('五', "5");
chineseToMathMap.put('六', "6");
chineseToMathMap.put('七', "7");
chineseToMathMap.put('八', "8");
chineseToMathMap.put('九', "9");
numberDigitsMap = new HashMap<Character, Integer>();
numberDigitsMap.put('个', 0);
numberDigitsMap.put('十', 1);
numberDigitsMap.put('百', 2);
numberDigitsMap.put('千', 3);
numberDigitsMap.put('万', 4);
numberDigitsMap.put('亿', 8);
}
private boolean isNumber(char c) {
if(c >= '0' && c <= '9') return true;
if(chineseToMathMap.containsKey(c)) return true;
return false;
}
public void parse(String inputNumber) {
StringBuilder str = new StringBuilder();
StringBuilder reversedInputNumber = new StringBuilder(inputNumber).reverse();
int numDigits = 0; //整数位的位数
int maxNumZero = 0; //专门处理类似于三百万这种连续两个单位的数字
int secondaryMaxNumZero = 0; //二级最大值
int index = 0;
while(index < reversedInputNumber.length()) {
char c = reversedInputNumber.charAt(index);
if(isNumber(c)) {
if(chineseToMathMap.containsKey(c)) {
str.append(chineseToMathMap.get(c));
} else {
str.append(c);
}
numDigits ++;
} else if (c == '-' || c == '负'){
str.append('-');
} else if(c == '.' || c == '点') {
str.append('.');
numDigits = 0;
} else if(numberDigitsMap.containsKey(c)){
int numZero = numberDigitsMap.get(c);
if(numZero <= maxNumZero) {
if(numZero <= secondaryMaxNumZero) {
numZero += secondaryMaxNumZero;
} else {
secondaryMaxNumZero = numZero;
}
numZero += maxNumZero;
} else {
maxNumZero = numZero;
secondaryMaxNumZero = 0;
}
if(index == 1
&& (!numberDigitsMap.containsKey(reversedInputNumber.charAt(0)))
) {
//处理‘一万二’、‘三千四’这种简略说法
int headFilledNumZero = numberDigitsMap.get(c) - numDigits;
for(int i=0;i<headFilledNumZero;i++) {
str.insert(0, '0');
numDigits ++;
}
} else {
//处理通用说法
int filledNumZero = numZero - numDigits;
for(int i=0;i<filledNumZero;i++) {
str.append('0');
numDigits ++;
}
}
//处理'十四',‘十’,'百''千''万''一千零十四'这种简略说法
if(numberDigitsMap.get(c) <= 4) {
if(index == reversedInputNumber.length() - 1 ||
reversedInputNumber.charAt(index+1) == '零' ||
reversedInputNumber.charAt(index+1) == '负') {
str.append('1');
numDigits ++;
}
}
} else {
//System.err.println("错误的符号:'"+c+"'");
}
index ++;
}
this.evalExpr = this.readExpr = str.reverse().toString();
}
//测试代码
public static void testParseNumber(String[] argv) {
Map<String, String> chnMap = new HashMap<String, String>();
chnMap.put("一", "1");
chnMap.put("一十五", "15");
chnMap.put("零点三五", "0.35");
chnMap.put("负十五", "-15");
chnMap.put("十五", "15");
chnMap.put("二十", "20");
chnMap.put("二十三", "23");
chnMap.put("一百", "100");
chnMap.put("一百一", "110");
chnMap.put("一百零一", "101");
chnMap.put("一百一十", "110");
chnMap.put("一百一十一", "111");
chnMap.put("一千", "1000");
chnMap.put("一千一", "1100");
chnMap.put("一千零一", "1001");
chnMap.put("一千零一十", "1010");
chnMap.put("一千零三十一", "1031");
chnMap.put("一万零一", "10001");
chnMap.put("一万一", "11000");
chnMap.put("一万零一百", "10100");
chnMap.put("一万零二十一", "10021");
chnMap.put("一万零三百二十一.三五", "10321.35");
chnMap.put("一万一千三百二十一", "11321");
chnMap.put("三千零十五万点二零", "30150000.20");
chnMap.put("三千零一十五万", "30150000");
chnMap.put("三千五百六十八万零一百零一", "35680101");
chnMap.put("五十亿三千零七十五万零六百二十二", "5030750622");
chnMap.put("十三亿三千零十五万零三百一十二", "1330150312");
chnMap.put("负三千零七十八亿三千零十五万零三百一十二", "-307830150312");
chnMap.put("一千二百五十八亿", "125800000000");
chnMap.put("一千二百五十8万亿零三千三百二十一点124", "1258000000003321.124");
int correctNum = 0;
int wrongNum = 0;
NumberParser parser = new NumberParser();
for(String num : chnMap.keySet()) {
String value = chnMap.get(num);
parser.parse(num);
String result = parser.getEvalExpr();
if(!result.equals(value)) {
System.err.println("错误:"+num+", "+value+", 错误结果:"+result);
wrongNum ++;
} else {
correctNum ++;
}
}
System.out.println("总计:\n\t正确 "+correctNum+", 错误 "+wrongNum);
}
public static void main(String[] argv) {
testParseNumber(argv);
}
}

@ -0,0 +1,41 @@
package org.xing.calc.parser;
public abstract class Parser {
//用于计算的表达式
protected String evalExpr;
//易于阅读的表达式
protected String readExpr;
//用于语音朗读的表达式
protected String speechExpr;
public String getEvalExpr() {
return evalExpr;
}
public void setEvalExpr(String evalExpr) {
this.evalExpr = evalExpr;
}
public String getReadExpr() {
return readExpr;
}
public void setReadExpr(String readExpr) {
this.readExpr = readExpr;
}
public String getSpeechExpr() {
return speechExpr;
}
public void setSpeechExpr(String speechExpr) {
this.speechExpr = speechExpr;
}
public void parse(String expr) {
}
}

@ -0,0 +1,77 @@
// Generated from src/org/xing/calc/parser/grammer/calculator.g4 by ANTLR 4.6
package org.xing.calc.parser.grammer;
import org.antlr.v4.runtime.tree.AbstractParseTreeVisitor;
/**
* This class provides an empty implementation of {@link calculatorVisitor},
* which can be extended to create a visitor which only needs to handle a subset
* of the available methods.
*
* @param <T> The return type of the visit operation. Use {@link Void} for
* operations with no return type.
*/
public class calculatorBaseVisitor<T> extends AbstractParseTreeVisitor<T> implements calculatorVisitor<T> {
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitExpression(calculatorParser.ExpressionContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitMultiplyingExpression(calculatorParser.MultiplyingExpressionContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitPowExpression(calculatorParser.PowExpressionContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitAtom(calculatorParser.AtomContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitFunction(calculatorParser.FunctionContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitFuncname(calculatorParser.FuncnameContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitFuncnameEx(calculatorParser.FuncnameExContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitPostFuncname(calculatorParser.PostFuncnameContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitNumber(calculatorParser.NumberContext ctx) { return visitChildren(ctx); }
}

@ -0,0 +1,193 @@
// Generated from src/org/xing/calc/parser/grammer/calculator.g4 by ANTLR 4.6
package org.xing.calc.parser.grammer;
import org.antlr.v4.runtime.Lexer;
import org.antlr.v4.runtime.CharStream;
import org.antlr.v4.runtime.Token;
import org.antlr.v4.runtime.TokenStream;
import org.antlr.v4.runtime.*;
import org.antlr.v4.runtime.atn.*;
import org.antlr.v4.runtime.dfa.DFA;
import org.antlr.v4.runtime.misc.*;
@SuppressWarnings({"all", "warnings", "unchecked", "unused", "cast"})
public class calculatorLexer extends Lexer {
static { RuntimeMetaData.checkVersion("4.6", RuntimeMetaData.VERSION); }
protected static final DFA[] _decisionToDFA;
protected static final PredictionContextCache _sharedContextCache =
new PredictionContextCache();
public static final int
COS=1, SIN=2, TAN=3, ACOS=4, ASIN=5, ATAN=6, LN=7, LOG=8, LG=9, DUISHU=10,
GENHAO=11, KUOHAO=12, LPAREN=13, RPAREN=14, PLUS=15, MINUS=16, TIMES=17,
DIV=18, FRAC=19, YOU=20, PINGFANG=21, LIFANG=22, CIFANG=23, KAIFANG=24,
KAIPINGFANG=25, KAILIFANG=26, DE=27, GEN=28, DU=29, PAI=30, POINT=31,
E=32, POW=33, LETTER=34, DIGIT=35, WS=36;
public static String[] modeNames = {
"DEFAULT_MODE"
};
public static final String[] ruleNames = {
"COS", "SIN", "TAN", "ACOS", "ASIN", "ATAN", "LN", "LOG", "LG", "DUISHU",
"GENHAO", "KUOHAO", "LPAREN", "RPAREN", "PLUS", "MINUS", "TIMES", "DIV",
"FRAC", "YOU", "PINGFANG", "LIFANG", "CIFANG", "KAIFANG", "KAIPINGFANG",
"KAILIFANG", "DE", "GEN", "DU", "PAI", "POINT", "E", "POW", "LETTER",
"DIGIT", "WS"
};
private static final String[] _LITERAL_NAMES = {
null, null, null, null, null, null, null, "'ln'", "'log'", "'lg'", "'对数'",
"'根号'", null, "'('", "')'", null, null, null, null, null, "'又'", "'平方'",
"'立方'", "'次方'", "'开方'", "'开平方'", "'开立方'", "'的'", "'根'", null, null, null,
null, "'^'"
};
private static final String[] _SYMBOLIC_NAMES = {
null, "COS", "SIN", "TAN", "ACOS", "ASIN", "ATAN", "LN", "LOG", "LG",
"DUISHU", "GENHAO", "KUOHAO", "LPAREN", "RPAREN", "PLUS", "MINUS", "TIMES",
"DIV", "FRAC", "YOU", "PINGFANG", "LIFANG", "CIFANG", "KAIFANG", "KAIPINGFANG",
"KAILIFANG", "DE", "GEN", "DU", "PAI", "POINT", "E", "POW", "LETTER",
"DIGIT", "WS"
};
public static final Vocabulary VOCABULARY = new VocabularyImpl(_LITERAL_NAMES, _SYMBOLIC_NAMES);
/**
* @deprecated Use {@link #VOCABULARY} instead.
*/
@Deprecated
public static final String[] tokenNames;
static {
tokenNames = new String[_SYMBOLIC_NAMES.length];
for (int i = 0; i < tokenNames.length; i++) {
tokenNames[i] = VOCABULARY.getLiteralName(i);
if (tokenNames[i] == null) {
tokenNames[i] = VOCABULARY.getSymbolicName(i);
}
if (tokenNames[i] == null) {
tokenNames[i] = "<INVALID>";
}
}
}
@Override
@Deprecated
public String[] getTokenNames() {
return tokenNames;
}
@Override
public Vocabulary getVocabulary() {
return VOCABULARY;
}
public calculatorLexer(CharStream input) {
super(input);
_interp = new LexerATNSimulator(this,_ATN,_decisionToDFA,_sharedContextCache);
}
@Override
public String getGrammarFileName() { return "calculator.g4"; }
@Override
public String[] getRuleNames() { return ruleNames; }
@Override
public String getSerializedATN() { return _serializedATN; }
@Override
public String[] getModeNames() { return modeNames; }
@Override
public ATN getATN() { return _ATN; }
public static final String _serializedATN =
"\3\u0430\ud6d1\u8206\uad2d\u4417\uaef1\u8d80\uaadd\2&\u00e6\b\1\4\2\t"+
"\2\4\3\t\3\4\4\t\4\4\5\t\5\4\6\t\6\4\7\t\7\4\b\t\b\4\t\t\t\4\n\t\n\4\13"+
"\t\13\4\f\t\f\4\r\t\r\4\16\t\16\4\17\t\17\4\20\t\20\4\21\t\21\4\22\t\22"+
"\4\23\t\23\4\24\t\24\4\25\t\25\4\26\t\26\4\27\t\27\4\30\t\30\4\31\t\31"+
"\4\32\t\32\4\33\t\33\4\34\t\34\4\35\t\35\4\36\t\36\4\37\t\37\4 \t \4!"+
"\t!\4\"\t\"\4#\t#\4$\t$\4%\t%\3\2\3\2\3\2\3\2\3\2\5\2Q\n\2\3\3\3\3\3\3"+
"\3\3\3\3\5\3X\n\3\3\4\3\4\3\4\3\4\3\4\5\4_\n\4\3\5\3\5\3\5\3\5\3\5\3\5"+
"\3\5\5\5h\n\5\3\6\3\6\3\6\3\6\3\6\3\6\3\6\5\6q\n\6\3\7\3\7\3\7\3\7\3\7"+
"\3\7\3\7\5\7z\n\7\3\b\3\b\3\b\3\t\3\t\3\t\3\t\3\n\3\n\3\n\3\13\3\13\3"+
"\13\3\f\3\f\3\f\3\r\3\r\3\r\5\r\u008f\n\r\3\16\3\16\3\17\3\17\3\20\3\20"+
"\3\20\5\20\u0098\n\20\5\20\u009a\n\20\3\21\3\21\3\21\5\21\u009f\n\21\5"+
"\21\u00a1\n\21\3\22\3\22\3\22\5\22\u00a6\n\22\5\22\u00a8\n\22\3\23\3\23"+
"\3\23\5\23\u00ad\n\23\5\23\u00af\n\23\3\24\3\24\3\24\5\24\u00b4\n\24\3"+
"\25\3\25\3\26\3\26\3\26\3\27\3\27\3\27\3\30\3\30\3\30\3\31\3\31\3\31\3"+
"\32\3\32\3\32\3\32\3\33\3\33\3\33\3\33\3\34\3\34\3\35\3\35\3\36\3\36\3"+
"\37\3\37\3 \3 \3!\3!\3\"\3\"\3#\5#\u00db\n#\3$\5$\u00de\n$\3%\6%\u00e1"+
"\n%\r%\16%\u00e2\3%\3%\2\2&\3\3\5\4\7\5\t\6\13\7\r\b\17\t\21\n\23\13\25"+
"\f\27\r\31\16\33\17\35\20\37\21!\22#\23%\24\'\25)\26+\27-\30/\31\61\32"+
"\63\33\65\34\67\359\36;\37= ?!A\"C#E$G%I&\3\2\13\4\2//\u8d21\u8d21\4\2"+
",,\u00d9\u00d9\4\2\u00b2\u00b2\u5ea8\u5ea8\4\2\u03c2\u03c2\u6d40\u6d40"+
"\4\2\60\60\u70bb\u70bb\4\2GGgg\4\2C\\c|\22\2\62;\u4e02\u4e02\u4e05\u4e05"+
"\u4e09\u4e09\u4e0b\u4e0b\u4e5f\u4e5f\u4e8e\u4e8e\u4e96\u4e96\u4ec1\u4ec1"+
"\u516d\u516d\u516f\u516f\u5343\u5343\u5345\u5345\u56dd\u56dd\u7680\u7680"+
"\u96f8\u96f8\5\2\13\f\17\17\"\"\u00f6\2\3\3\2\2\2\2\5\3\2\2\2\2\7\3\2"+
"\2\2\2\t\3\2\2\2\2\13\3\2\2\2\2\r\3\2\2\2\2\17\3\2\2\2\2\21\3\2\2\2\2"+
"\23\3\2\2\2\2\25\3\2\2\2\2\27\3\2\2\2\2\31\3\2\2\2\2\33\3\2\2\2\2\35\3"+
"\2\2\2\2\37\3\2\2\2\2!\3\2\2\2\2#\3\2\2\2\2%\3\2\2\2\2\'\3\2\2\2\2)\3"+
"\2\2\2\2+\3\2\2\2\2-\3\2\2\2\2/\3\2\2\2\2\61\3\2\2\2\2\63\3\2\2\2\2\65"+
"\3\2\2\2\2\67\3\2\2\2\29\3\2\2\2\2;\3\2\2\2\2=\3\2\2\2\2?\3\2\2\2\2A\3"+
"\2\2\2\2C\3\2\2\2\2E\3\2\2\2\2G\3\2\2\2\2I\3\2\2\2\3P\3\2\2\2\5W\3\2\2"+
"\2\7^\3\2\2\2\tg\3\2\2\2\13p\3\2\2\2\ry\3\2\2\2\17{\3\2\2\2\21~\3\2\2"+
"\2\23\u0082\3\2\2\2\25\u0085\3\2\2\2\27\u0088\3\2\2\2\31\u008e\3\2\2\2"+
"\33\u0090\3\2\2\2\35\u0092\3\2\2\2\37\u0099\3\2\2\2!\u00a0\3\2\2\2#\u00a7"+
"\3\2\2\2%\u00ae\3\2\2\2\'\u00b3\3\2\2\2)\u00b5\3\2\2\2+\u00b7\3\2\2\2"+
"-\u00ba\3\2\2\2/\u00bd\3\2\2\2\61\u00c0\3\2\2\2\63\u00c3\3\2\2\2\65\u00c7"+
"\3\2\2\2\67\u00cb\3\2\2\29\u00cd\3\2\2\2;\u00cf\3\2\2\2=\u00d1\3\2\2\2"+
"?\u00d3\3\2\2\2A\u00d5\3\2\2\2C\u00d7\3\2\2\2E\u00da\3\2\2\2G\u00dd\3"+
"\2\2\2I\u00e0\3\2\2\2KL\7e\2\2LM\7q\2\2MQ\7u\2\2NO\7\u4f5b\2\2OQ\7\u5f28"+
"\2\2PK\3\2\2\2PN\3\2\2\2Q\4\3\2\2\2RS\7u\2\2ST\7k\2\2TX\7p\2\2UV\7\u6b65"+
"\2\2VX\7\u5f28\2\2WR\3\2\2\2WU\3\2\2\2X\6\3\2\2\2YZ\7v\2\2Z[\7c\2\2[_"+
"\7p\2\2\\]\7\u6b65\2\2]_\7\u5209\2\2^Y\3\2\2\2^\\\3\2\2\2_\b\3\2\2\2`"+
"a\7c\2\2ab\7e\2\2bc\7q\2\2ch\7u\2\2de\7\u53cf\2\2ef\7\u4f5b\2\2fh\7\u5f28"+
"\2\2g`\3\2\2\2gd\3\2\2\2h\n\3\2\2\2ij\7c\2\2jk\7u\2\2kl\7k\2\2lq\7p\2"+
"\2mn\7\u53cf\2\2no\7\u6b65\2\2oq\7\u5f28\2\2pi\3\2\2\2pm\3\2\2\2q\f\3"+
"\2\2\2rs\7c\2\2st\7v\2\2tu\7c\2\2uz\7p\2\2vw\7\u53cf\2\2wx\7\u6b65\2\2"+
"xz\7\u5209\2\2yr\3\2\2\2yv\3\2\2\2z\16\3\2\2\2{|\7n\2\2|}\7p\2\2}\20\3"+
"\2\2\2~\177\7n\2\2\177\u0080\7q\2\2\u0080\u0081\7i\2\2\u0081\22\3\2\2"+
"\2\u0082\u0083\7n\2\2\u0083\u0084\7i\2\2\u0084\24\3\2\2\2\u0085\u0086"+
"\7\u5bfb\2\2\u0086\u0087\7\u6572\2\2\u0087\26\3\2\2\2\u0088\u0089\7\u683b"+
"\2\2\u0089\u008a\7\u53f9\2\2\u008a\30\3\2\2\2\u008b\u008f\7~\2\2\u008c"+
"\u008d\7\u62ee\2\2\u008d\u008f\7\u53f9\2\2\u008e\u008b\3\2\2\2\u008e\u008c"+
"\3\2\2\2\u008f\32\3\2\2\2\u0090\u0091\7*\2\2\u0091\34\3\2\2\2\u0092\u0093"+
"\7+\2\2\u0093\36\3\2\2\2\u0094\u009a\7-\2\2\u0095\u0097\7\u52a2\2\2\u0096"+
"\u0098\7\u4e0c\2\2\u0097\u0096\3\2\2\2\u0097\u0098\3\2\2\2\u0098\u009a"+
"\3\2\2\2\u0099\u0094\3\2\2\2\u0099\u0095\3\2\2\2\u009a \3\2\2\2\u009b"+
"\u00a1\t\2\2\2\u009c\u009e\7\u51d1\2\2\u009d\u009f\7\u53bd\2\2\u009e\u009d"+
"\3\2\2\2\u009e\u009f\3\2\2\2\u009f\u00a1\3\2\2\2\u00a0\u009b\3\2\2\2\u00a0"+
"\u009c\3\2\2\2\u00a1\"\3\2\2\2\u00a2\u00a8\t\3\2\2\u00a3\u00a5\7\u4e5a"+
"\2\2\u00a4\u00a6\7\u4ee7\2\2\u00a5\u00a4\3\2\2\2\u00a5\u00a6\3\2\2\2\u00a6"+
"\u00a8\3\2\2\2\u00a7\u00a2\3\2\2\2\u00a7\u00a3\3\2\2\2\u00a8$\3\2\2\2"+
"\u00a9\u00af\7\u00f9\2\2\u00aa\u00ac\7\u9666\2\2\u00ab\u00ad\7\u4ee7\2"+
"\2\u00ac\u00ab\3\2\2\2\u00ac\u00ad\3\2\2\2\u00ad\u00af\3\2\2\2\u00ae\u00a9"+
"\3\2\2\2\u00ae\u00aa\3\2\2\2\u00af&\3\2\2\2\u00b0\u00b4\7\61\2\2\u00b1"+
"\u00b2\7\u5208\2\2\u00b2\u00b4\7\u4e4d\2\2\u00b3\u00b0\3\2\2\2\u00b3\u00b1"+
"\3\2\2\2\u00b4(\3\2\2\2\u00b5\u00b6\7\u53ca\2\2\u00b6*\3\2\2\2\u00b7\u00b8"+
"\7\u5e75\2\2\u00b8\u00b9\7\u65bb\2\2\u00b9,\3\2\2\2\u00ba\u00bb\7\u7acd"+
"\2\2\u00bb\u00bc\7\u65bb\2\2\u00bc.\3\2\2\2\u00bd\u00be\7\u6b23\2\2\u00be"+
"\u00bf\7\u65bb\2\2\u00bf\60\3\2\2\2\u00c0\u00c1\7\u5f02\2\2\u00c1\u00c2"+
"\7\u65bb\2\2\u00c2\62\3\2\2\2\u00c3\u00c4\7\u5f02\2\2\u00c4\u00c5\7\u5e75"+
"\2\2\u00c5\u00c6\7\u65bb\2\2\u00c6\64\3\2\2\2\u00c7\u00c8\7\u5f02\2\2"+
"\u00c8\u00c9\7\u7acd\2\2\u00c9\u00ca\7\u65bb\2\2\u00ca\66\3\2\2\2\u00cb"+
"\u00cc\7\u7686\2\2\u00cc8\3\2\2\2\u00cd\u00ce\7\u683b\2\2\u00ce:\3\2\2"+
"\2\u00cf\u00d0\t\4\2\2\u00d0<\3\2\2\2\u00d1\u00d2\t\5\2\2\u00d2>\3\2\2"+
"\2\u00d3\u00d4\t\6\2\2\u00d4@\3\2\2\2\u00d5\u00d6\t\7\2\2\u00d6B\3\2\2"+
"\2\u00d7\u00d8\7`\2\2\u00d8D\3\2\2\2\u00d9\u00db\t\b\2\2\u00da\u00d9\3"+
"\2\2\2\u00dbF\3\2\2\2\u00dc\u00de\t\t\2\2\u00dd\u00dc\3\2\2\2\u00deH\3"+
"\2\2\2\u00df\u00e1\t\n\2\2\u00e0\u00df\3\2\2\2\u00e1\u00e2\3\2\2\2\u00e2"+
"\u00e0\3\2\2\2\u00e2\u00e3\3\2\2\2\u00e3\u00e4\3\2\2\2\u00e4\u00e5\b%"+
"\2\2\u00e5J\3\2\2\2\26\2PW^gpy\u008e\u0097\u0099\u009e\u00a0\u00a5\u00a7"+
"\u00ac\u00ae\u00b3\u00da\u00dd\u00e2\3\2\3\2";
public static final ATN _ATN =
new ATNDeserializer().deserialize(_serializedATN.toCharArray());
static {
_decisionToDFA = new DFA[_ATN.getNumberOfDecisions()];
for (int i = 0; i < _ATN.getNumberOfDecisions(); i++) {
_decisionToDFA[i] = new DFA(_ATN.getDecisionState(i), i);
}
}
}

@ -0,0 +1,67 @@
// Generated from src/org/xing/calc/parser/grammer/calculator.g4 by ANTLR 4.6
package org.xing.calc.parser.grammer;
import org.antlr.v4.runtime.tree.ParseTreeVisitor;
/**
* This interface defines a complete generic visitor for a parse tree produced
* by {@link calculatorParser}.
*
* @param <T> The return type of the visit operation. Use {@link Void} for
* operations with no return type.
*/
public interface calculatorVisitor<T> extends ParseTreeVisitor<T> {
/**
* Visit a parse tree produced by {@link calculatorParser#expression}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitExpression(calculatorParser.ExpressionContext ctx);
/**
* Visit a parse tree produced by {@link calculatorParser#multiplyingExpression}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitMultiplyingExpression(calculatorParser.MultiplyingExpressionContext ctx);
/**
* Visit a parse tree produced by {@link calculatorParser#powExpression}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitPowExpression(calculatorParser.PowExpressionContext ctx);
/**
* Visit a parse tree produced by {@link calculatorParser#atom}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitAtom(calculatorParser.AtomContext ctx);
/**
* Visit a parse tree produced by {@link calculatorParser#function}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitFunction(calculatorParser.FunctionContext ctx);
/**
* Visit a parse tree produced by {@link calculatorParser#funcname}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitFuncname(calculatorParser.FuncnameContext ctx);
/**
* Visit a parse tree produced by {@link calculatorParser#funcnameEx}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitFuncnameEx(calculatorParser.FuncnameExContext ctx);
/**
* Visit a parse tree produced by {@link calculatorParser#postFuncname}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitPostFuncname(calculatorParser.PostFuncnameContext ctx);
/**
* Visit a parse tree produced by {@link calculatorParser#number}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitNumber(calculatorParser.NumberContext ctx);
}

@ -0,0 +1,105 @@
package org.xing.engine;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.speech.RecognitionListener;
import android.speech.SpeechRecognizer;
import com.baidu.speech.VoiceRecognitionService;
import org.xing.utils.Logger;
import java.util.ArrayList;
/**
* Created by Administrator on 2017/3/8 0008.
*/
public class BaiduSpeechEngine implements SpeechEngine{
private Context ctx;
private SpeechListener listener;
private SpeechRecognizer speechRecognizer;
private InternalRecognitionListener _listener;
public BaiduSpeechEngine(Context ctx) {
this.ctx = ctx;
speechRecognizer = SpeechRecognizer.createSpeechRecognizer(
ctx, new ComponentName(ctx, VoiceRecognitionService.class));
}
public void setSpeechListener(SpeechListener listener){
this.listener = listener;
this._listener = new InternalRecognitionListener(listener);
speechRecognizer.setRecognitionListener(_listener);
}
public void startListening() {
speechRecognizer.startListening(new Intent());
}
public void stopListening() {
speechRecognizer.stopListening();
}
public void cancel() {
speechRecognizer.cancel();
}
public void destroy() {
speechRecognizer.destroy();
}
private static class InternalRecognitionListener implements RecognitionListener {
private SpeechListener listener;
public InternalRecognitionListener(SpeechListener listener) {
this.listener = listener;
}
public void onResults(Bundle results) {
ArrayList<String> nbest = results.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION);
StringBuilder expr = new StringBuilder();
for (String w : nbest) {
expr.append(w);
}
listener.onResults(expr.toString());
}
public void onReadyForSpeech(Bundle bundle) {
listener.onReadyForSpeech();
}
//会话发生错误回调接口
public void onError(int error) {
listener.onError(error);
}
//开始录音
public void onBeginningOfSpeech() {
listener.onBeginningOfSpeech();
}
//音量值
public void onRmsChanged(float rms){
listener.onRmsChanged(rms/20);
}
//结束录音
public void onEndOfSpeech() {
listener.onEndOfSpeech();
}
public void onPartialResults(Bundle partialResults) {
}
public void onEvent(int eventType, Bundle params) {
Logger.info("xing", String.valueOf(eventType)+": "+params.toString());
}
public void onBufferReceived(byte[] buffer) {
}
};
}

@ -0,0 +1,132 @@
package org.xing.engine;
import android.content.Context;
import android.os.Bundle;
import com.iflytek.cloud.RecognizerListener;
import com.iflytek.cloud.RecognizerResult;
import com.iflytek.cloud.SpeechConstant;
import com.iflytek.cloud.SpeechError;
import com.iflytek.cloud.SpeechRecognizer;
import com.iflytek.cloud.SpeechUtility;
import org.xing.android.MainActivity;
import org.xing.logger.impl.EventLogger;
import org.xing.utils.JsonParser;
import static com.iflytek.cloud.ErrorCode.ERROR_AUDIO_RECORD;
import static com.iflytek.cloud.ErrorCode.ERROR_ENGINE_BUSY;
import static com.iflytek.cloud.ErrorCode.ERROR_NETWORK_TIMEOUT;
import static com.iflytek.cloud.ErrorCode.ERROR_NO_MATCH;
import static com.iflytek.cloud.ErrorCode.ERROR_NO_NETWORK;
import static com.iflytek.cloud.ErrorCode.ERROR_PERMISSION_DENIED;
import static com.iflytek.cloud.ErrorCode.MSP_ERROR_NO_DATA;
/**
* Created by Administrator on 2017/3/8 0008.
*/
public class IflySpeechEngine implements SpeechEngine{
private Context ctx;
private SpeechListener listener;
private SpeechRecognizer speechRecognizer;
private InternalRecognizerListener _listener;
private static EventLogger eventLogger;
public IflySpeechEngine(Context ctx) {
this.ctx = ctx;
SpeechUtility.createUtility(ctx, SpeechConstant.APPID +"=585290e7");
speechRecognizer= SpeechRecognizer.createRecognizer(ctx, null);
speechRecognizer.setParameter(SpeechConstant.DOMAIN, "iat"); //{短信和日常用语iat (默认) 视频video 地图poi 音乐music
speechRecognizer.setParameter(SpeechConstant.LANGUAGE, "zh_cn");
speechRecognizer.setParameter(SpeechConstant.ACCENT, "mandarin");
speechRecognizer.setParameter(SpeechConstant.VAD_BOS, "10000"); //十秒超时
speechRecognizer.setParameter(SpeechConstant.ASR_PTT, "0"); //不带标点
eventLogger = MainActivity.eventLogger;
}
public void setSpeechListener(SpeechListener listener){
this.listener = listener;
_listener = new InternalRecognizerListener(listener);
}
public void startListening() {
speechRecognizer.startListening(_listener);
listener.onReadyForSpeech();
}
public void stopListening() {
speechRecognizer.stopListening();
}
public void cancel() {
speechRecognizer.cancel();
}
public void destroy() {
speechRecognizer.destroy();
}
private static class InternalRecognizerListener implements RecognizerListener{
private SpeechListener listener;
public InternalRecognizerListener(SpeechListener listener) {
this.listener = listener;
}
public void onResult(RecognizerResult results, boolean isLast) {
String expr = JsonParser.parseIatResult(results.getResultString());
listener.onResults(expr);
}
//会话发生错误回调接口
public void onError(SpeechError error) {
switch (error.getErrorCode()) {
case ERROR_AUDIO_RECORD:
listener.onError(android.speech.SpeechRecognizer.ERROR_AUDIO);
break;
case ERROR_ENGINE_BUSY:
listener.onError(android.speech.SpeechRecognizer.ERROR_RECOGNIZER_BUSY);
break;
case ERROR_PERMISSION_DENIED:
listener.onError(android.speech.SpeechRecognizer.ERROR_INSUFFICIENT_PERMISSIONS);
break;
case ERROR_NO_NETWORK:
listener.onError(android.speech.SpeechRecognizer.ERROR_NETWORK);
break;
case ERROR_NETWORK_TIMEOUT:
listener.onError(android.speech.SpeechRecognizer.ERROR_NETWORK_TIMEOUT);
break;
case ERROR_NO_MATCH:
listener.onError(android.speech.SpeechRecognizer.ERROR_NO_MATCH);
break;
case MSP_ERROR_NO_DATA:
listener.onError(android.speech.SpeechRecognizer.ERROR_SPEECH_TIMEOUT);
break;
default:
eventLogger.onEvent("ifly-error-"+error.getErrorCode()+": "+error.getErrorDescription());
listener.onError(android.speech.SpeechRecognizer.ERROR_CLIENT);
break;
}
}
//开始录音
public void onBeginOfSpeech() {
listener.onBeginningOfSpeech();
}
//音量值0~30
public void onVolumeChanged(int volume, byte[] data){
listener.onRmsChanged((float)volume * 10);
}
//结束录音
public void onEndOfSpeech() {
listener.onEndOfSpeech();
}
//扩展用接口
public void onEvent(int eventType, int arg1, int arg2, Bundle obj) {
}
};
}

@ -0,0 +1,13 @@
package org.xing.engine;
/**
* Created by Administrator on 2017/3/8 0008.
*/
public interface SpeechEngine {
void setSpeechListener(SpeechListener listener);
void startListening();
void stopListening();
void cancel();
void destroy();
}

@ -0,0 +1,20 @@
package org.xing.engine;
/**
* Created by Administrator on 2017/3/8 0008.
*/
public interface SpeechListener{
void onReadyForSpeech();
void onBeginningOfSpeech();
void onRmsChanged(float rmsdB);
void onEndOfSpeech();
void onError(int error);
void onResults(String expr);
}

@ -0,0 +1,35 @@
package org.xing.logger;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* Created by Administrator on 2016/12/29 0029.
*/
public class AsyncLog implements Log {
private Log syncLog;
private ExecutorService executorService;
public AsyncLog(Log log) {
this.syncLog = log;
executorService = Executors.newSingleThreadExecutor();
}
@Override
public boolean log(final Map<String, Object> params) {
executorService.submit(new Runnable() {
@Override
public void run() {
syncLog.log(params);
}
});
return true;
}
public static AsyncLog createAsyncHttpLog(String url) {
return new AsyncLog(new HttpLog(url));
}
}

@ -0,0 +1,24 @@
package org.xing.logger;
import org.xing.utils.HttpUtil;
import java.util.Map;
/**
* Created by Administrator on 2016/12/29 0029.
*/
public class HttpLog implements Log {
private String url;
public HttpLog(String url) {
this.url = url;
}
@Override
public boolean log(Map<String, Object> params) {
HttpUtil.doPost(this.url, params, "utf-8");
return true;
}
}

@ -0,0 +1,11 @@
package org.xing.logger;
import java.util.Map;
/**
* Created by Administrator on 2016/12/29 0029.
*/
public interface Log {
boolean log(Map<String, Object> params);
}

@ -0,0 +1,53 @@
package org.xing.logger.impl;
import android.os.Build;
import org.xing.logger.AsyncLog;
import org.xing.logger.Log;
import java.util.HashMap;
import java.util.Map;
/**
* Created by Administrator on 2017/2/21 0021.
*/
public class EventLogger {
private String userId;
private String version;
private Log eventLogger;
public EventLogger(String userId, String version, String url) {
this.userId = userId;
this.version = version;
eventLogger = AsyncLog.createAsyncHttpLog(url);
}
/*
*/
public void onEvent(String event) {
Map<String, Object> params = new HashMap<>();
params.put("_eventType", 1);
params.put("version", version);
params.put("userId", userId);
params.put("model", Build.VERSION.SDK_INT + " " + Build.BRAND + " " + Build.MODEL);
params.put("event", event);
eventLogger.log(params);
}
/*
*/
public void onEvent(String result, String inputExpr, String readExpr, int type) {
Map<String, Object> params = new HashMap<>();
params.put("_eventType", 2);
params.put("userId", userId);
params.put("version", version);
params.put("result", result);
params.put("inputExpr", inputExpr);
params.put("readExpr", readExpr == null ? "null" : readExpr);
params.put("type", type);
eventLogger.log(params);
}
}

@ -0,0 +1,114 @@
package org.xing.share;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import com.tencent.connect.share.QQShare;
import com.tencent.connect.share.QzoneShare;
import com.tencent.mm.opensdk.modelmsg.SendMessageToWX;
import com.tencent.mm.opensdk.modelmsg.WXMediaMessage;
import com.tencent.mm.opensdk.modelmsg.WXWebpageObject;
import com.tencent.mm.opensdk.openapi.IWXAPI;
import com.tencent.mm.opensdk.openapi.WXAPIFactory;
import com.tencent.tauth.IUiListener;
import com.tencent.tauth.Tencent;
import com.tencent.tauth.UiError;
import org.xing.android.MainActivity;
import org.xing.android.R;
import org.xing.logger.impl.EventLogger;
import java.util.ArrayList;
/**
* Created by Administrator on 2017/3/19 0019.
*/
public class ShareManager {
private Activity activity;
/*
*/
private String weixinAppid;
private IWXAPI iwxapi;
/*
QQ
*/
private String qqAppid;
private Tencent mTencent;
private EventLogger eventLogger;
public ShareManager(Activity activity) {
eventLogger = MainActivity.eventLogger;
this.activity = activity;
weixinAppid = "wxf3bb46c3047a46dd";
iwxapi = WXAPIFactory.createWXAPI(activity, weixinAppid, true);
iwxapi.registerApp(weixinAppid);
qqAppid = "1105840771";
mTencent = Tencent.createInstance(qqAppid, activity.getApplicationContext());
}
public void shareToWeixin(int flag) {
WXWebpageObject webpage = new WXWebpageObject();
webpage.webpageUrl = activity.getString(R.string.shareUrl);
WXMediaMessage msg = new WXMediaMessage(webpage);
msg.title = activity.getString(R.string.shareTitle);
msg.description = activity.getString(R.string.shareDesc);
//这里替换一张自己工程里的图片资源
Bitmap thumb = BitmapFactory.decodeResource(activity.getResources(), R.mipmap.share_icon);
msg.setThumbImage(thumb);
SendMessageToWX.Req req = new SendMessageToWX.Req();
req.transaction = String.valueOf(System.currentTimeMillis());
req.message = msg;
req.scene = flag == 0? SendMessageToWX.Req.WXSceneSession:SendMessageToWX.Req.WXSceneTimeline;
eventLogger.onEvent(flag == 0? "weixinShare":"pengyouquanShare");
iwxapi.sendReq(req);
}
public void shareToQQ(int flag) {
final Bundle params = new Bundle();
if(flag == 0) {
params.putInt(QQShare.SHARE_TO_QQ_KEY_TYPE, QQShare.SHARE_TO_QQ_TYPE_DEFAULT);
params.putString(QQShare.SHARE_TO_QQ_TITLE, activity.getString(R.string.shareTitle));
params.putString(QQShare.SHARE_TO_QQ_SUMMARY, activity.getString(R.string.shareDesc));
params.putString(QQShare.SHARE_TO_QQ_TARGET_URL, activity.getString(R.string.shareUrl));
params.putString(QQShare.SHARE_TO_QQ_IMAGE_URL, activity.getString(R.string.shareImage));
params.putString(QQShare.SHARE_TO_QQ_APP_NAME, activity.getString(R.string.app_name));
} else {
params.putInt(QzoneShare.SHARE_TO_QZONE_KEY_TYPE, QzoneShare.SHARE_TO_QZONE_TYPE_IMAGE_TEXT );
params.putString(QzoneShare.SHARE_TO_QQ_TITLE, activity.getString(R.string.shareTitle));
params.putString(QzoneShare.SHARE_TO_QQ_SUMMARY, activity.getString(R.string.shareDesc));
params.putString(QzoneShare.SHARE_TO_QQ_TARGET_URL, activity.getString(R.string.shareUrl));
ArrayList<String> imageList = new ArrayList<>();
imageList.add(activity.getString(R.string.shareImage));
params.putStringArrayList(QzoneShare.SHARE_TO_QQ_IMAGE_URL, imageList);
}
IUiListener defaultUiListener = new IUiListener() {
public void onComplete(Object var1){}
public void onError(UiError var1){}
public void onCancel() {}
};
if(flag == 0) {
eventLogger.onEvent("qqShare");
mTencent.shareToQQ(activity, params, defaultUiListener);
} else {
eventLogger.onEvent("qzoneShare");
mTencent.shareToQzone(activity, params, defaultUiListener);
}
}
}

@ -0,0 +1,104 @@
package org.xing.theme;
import org.json.JSONObject;
import java.util.LinkedList;
import java.util.List;
/**
* Created by Administrator on 2017/3/1 0001.
*/
public class Theme {
private String id;
private String name;
private JSONObject style;
private List<String> imagePaths;
public Theme () {
//默认全白色背景,黑色字体
id = "0";
name = "默认主题";
style = null;
imagePaths = new LinkedList<>();
}
public Theme (String id, String name, String style, String imagePathStr) {
this.id = id;
this.name = name;
try {
this.style = new JSONObject(style);
}catch (Exception e) { }
imagePaths = new LinkedList<>();
if(imagePathStr != null) {
String[] fields = imagePathStr.split(";");
for(String path : fields) {
if(path.length() > 0) {
imagePaths.add(path);
}
}
}
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getStyle() {
return style.toString();
}
public String getStyle(String name) {
try {
return style.getString(name);
}catch (Exception e) { }
return null;
}
public void setStyle(String style) {
try {
this.style = new JSONObject(style);
}catch (Exception e) { }
imagePaths = new LinkedList<>();
}
public List<String> getImagePaths() {
return imagePaths;
}
public String getImagePathsStr() {
StringBuilder str= new StringBuilder();
for(String path : imagePaths) {
if(str.length() > 0) {
str.append(";");
}
str.append(path);
}
return str.toString();
}
public void setBackgroundImage(String imagePathStr) {
imagePaths.clear();
if(imagePathStr != null) {
String[] fields = imagePathStr.split(";");
for(String path : fields) {
if(path.length() > 0) {
imagePaths.add(path);
}
}
}
}
}

@ -0,0 +1,10 @@
package org.xing.theme;
/**
* Created by Administrator on 2017/3/1 0001.
*/
public interface ThemeChangeListener {
boolean isAlive();
void onThemeChange(Theme theme);
}

@ -0,0 +1,173 @@
package org.xing.theme;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import org.xing.android.AppConfig;
import org.xing.android.MainActivity;
import org.xing.logger.impl.EventLogger;
import java.util.LinkedList;
import java.util.List;
/**
* Created by Administrator on 2017/3/1 0001.
*/
public class ThemeManager {
private int nextTheme;
private SQLiteDatabase database;
private LinkedList<ThemeChangeListener> listeners;
private EventLogger eventLogger;
public ThemeManager(Context ctx) {
nextTheme = 0;
listeners = new LinkedList<>();
eventLogger = MainActivity.eventLogger;
try {
String databasePath = ctx.getFilesDir().getAbsolutePath() + "/theme.db";
database = SQLiteDatabase.openOrCreateDatabase(databasePath, null);
if(AppConfig.getIsFirstStart()) {
database.execSQL("drop table if exists themes");
String createTableSql = "create table if not exists themes (" +
"id CHAR(32) PRIMARY KEY, " +
"name CHAR(32), " +
"style VARCHAR, " +
"img_paths VARCHAR" +
")";
database.execSQL(createTableSql);
}else {
database.delete("themes", null, null);
}
addTheme(new Theme("0", "白色", "{'resultColor':'#000000', 'historyColor':'#444444', 'msgColor':'#555555', 'background':'#ffffff'}", null));
addTheme(new Theme("1", "大鱼", "{'resultColor':'#FF3300', 'historyColor':'#ee3300', 'msgColor':'#aa3300'}", "theme/01.jpg"));
addTheme(new Theme("2", "银河", "{'resultColor':'#ffffff', 'historyColor':'#f0f0f0', 'msgColor':'#aaaaaa'}", "theme/02.jpg"));
addTheme(new Theme("3", "萌宠", "{'resultColor':'#ffa000', 'historyColor':'#ee9000', 'msgColor':'#cc7000'}", "theme/03.jpg"));
addTheme(new Theme("4", "雪景", "{'resultColor':'#3eb3ed', 'historyColor':'#2ea3dd', 'msgColor':'#ffa066'}", "theme/04.jpg"));
addTheme(new Theme("5", "银色", "{'resultColor':'#333333', 'historyColor':'#444444', 'msgColor':'#555555'}", "theme/05.jpg"));
}catch (Exception e) {
e.printStackTrace();
database = null;
}
}
public boolean addTheme(Theme theme) {
if(database == null) return false;
ContentValues values = new ContentValues();
values.put("id", theme.getId());
values.put("name", theme.getName());
values.put("style", theme.getStyle());
values.put("img_paths", theme.getImagePathsStr());
try {
long result = database.insert("themes", null, values);
if (result > 0) return true;
}catch (Exception e) {
e.printStackTrace();
}
return false;
}
public boolean deleteTheme(String id) {
if(database == null || id == null) return false;
String whereClause = "id=?";
String[] whereArgs = {id};
try {
long result = database.delete("themes", whereClause, whereArgs);
if (result > 0) return true;
}catch (Exception e) {
e.printStackTrace();
}
return false;
}
public boolean deleteTheme(Theme theme) {
return deleteTheme(theme.getId());
}
public Theme getTheme(String id) {
try {
Cursor cursor = database.rawQuery("select id, name, style, img_paths from themes where id='"+id+"'", null);
if(cursor.moveToFirst()) {
Theme theme = new Theme(cursor.getString(0), cursor.getString(1),
cursor.getString(2), cursor.getString(3));
return theme;
}
}catch (Exception e) {
e.printStackTrace();
}
return null;
}
public List<Theme> getAllTheme() {
List<Theme> themes = new LinkedList<>();
try {
Cursor cursor = database.rawQuery("select id, name, style, img_paths from themes", null);
if(cursor.moveToFirst()) {
do {
Theme theme = new Theme(cursor.getString(0), cursor.getString(1),
cursor.getString(2), cursor.getString(3));
themes.add(theme);
}while(cursor.moveToNext());
}
}catch (Exception e) {
e.printStackTrace();
}
return themes;
}
public void addThemeChangeListener(ThemeChangeListener listener) {
listeners.add(listener);
}
public void applyTheme(String id) {
if(id == null) return;
List<Theme> themes = getAllTheme();
nextTheme = 0;
for(Theme theme : themes) {
nextTheme ++;
if(theme.getId().equals(id)) {
break;
}
}
applyTheme(getTheme(id));
}
public void applyTheme(Theme theme) {
if(theme == null) return;
for(ThemeChangeListener listener : listeners) {
if(listener.isAlive()) {
listener.onThemeChange(theme);
}
}
}
public void randomTheme() {
eventLogger.onEvent("changeTheme");
List<Theme> themes = getAllTheme();
if(themes.size() > 0) {
if(nextTheme >= themes.size()) {
nextTheme %= themes.size();
}
applyTheme(
themes.get(nextTheme++)
);
}
}
}

@ -0,0 +1,38 @@
package org.xing.update;
import org.json.JSONException;
import org.json.JSONObject;
import java.math.BigInteger;
/**
* Created by sangbo on 16-5-19.
*/
public class UpdateEntity {
public int versionCode = 0;
public int isForceUpdate = 0;
public int preBaselineCode = 0;
public String versionName = "";
public String downUrl = "";
public String updateLog = "";
public BigInteger md5 = null;
public int fileSize = 0;
public UpdateEntity(String json) throws JSONException {
JSONObject jsonObject = new JSONObject(json);
this.versionCode = jsonObject.getInt("versionCode");
this.versionName = jsonObject.getString("versionName");
this.isForceUpdate = jsonObject.getInt("isForceUpdate");
this.downUrl = jsonObject.getString("downUrl");
this.preBaselineCode = jsonObject.getInt("preBaselineCode");
this.updateLog = jsonObject.getString("updateLog");
String md5String = jsonObject.getString("md5");
if(md5String != null) {
this.md5 = new BigInteger(md5String, 16);
}
this.fileSize = jsonObject.getInt("fileSize");
}
}

@ -0,0 +1,295 @@
package org.xing.update;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.os.Environment;
import android.os.Handler;
import android.text.TextUtils;
import android.util.Log;
import android.widget.Toast;
import com.umeng.analytics.MobclickAgent;
import com.zhy.http.okhttp.OkHttpUtils;
import com.zhy.http.okhttp.callback.FileCallBack;
import com.zhy.http.okhttp.callback.StringCallback;
import org.json.JSONException;
import org.xing.android.AppConfig;
import org.xing.android.MainActivity;
import org.xing.android.R;
import org.xing.logger.impl.EventLogger;
import org.xing.utils.NumberUtil;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.math.BigInteger;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.security.MessageDigest;
import okhttp3.Call;
/**
* app
* Created by sangbo on 16-5-19.
*/
public class UpdateManager {
private static int mAppVersionCode = 0;
private static Context mContext;
private static ProgressDialog mAlertDialog;
private static boolean mIsEnforceCheck = false;
private static EventLogger eventLogger = null;
public static String checkUrl = "";
public static UpdateEntity mUpdateEntity;
public static void postUpdate(final Context context, int delaySecond) {
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
@Override
public void run() {
if(AppConfig.getCheckUpdate()) {
mIsEnforceCheck = false;
update(context);
}
}
}, delaySecond*1000);
}
public static void update(Context context){
update(context,mIsEnforceCheck);
}
public static void update(Context context, final boolean isEnforceCheck){
mContext = context;
mIsEnforceCheck = isEnforceCheck;
mAppVersionCode = AppConfig.getVersionCode();
if(eventLogger == null) {
eventLogger = MainActivity.eventLogger;
}
checkUrl = mContext.getString(R.string.updateCheckUrl);
if(TextUtils.isEmpty(checkUrl)){
Toast.makeText(mContext, "url不能为空请设置url", Toast.LENGTH_SHORT).show();
return;
}
OkHttpUtils.get().url(checkUrl).build().execute(new StringCallback() {
@Override
public void onError(Call call, Exception e) {
if(mIsEnforceCheck)
Toast.makeText(mContext, "更新失败,请检查网络", Toast.LENGTH_SHORT).show();
}
@Override
public void onResponse(String response) {
loadOnlineData(response);
}
});
}
private static void loadOnlineData(String json) {
try {
UpdateEntity updateEntity = new UpdateEntity(json);
if(updateEntity == null){
if(mIsEnforceCheck)
Toast.makeText(mContext, "网络信息获取失败,请重试", Toast.LENGTH_SHORT).show();
return;
}
mUpdateEntity = updateEntity;
if(mAppVersionCode < mUpdateEntity.versionCode){
//启动更新
AlertUpdate();
} else if(mIsEnforceCheck){
AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
builder.setTitle("更新");
builder.setMessage("已是最新版本:"+AppConfig.getVersionName());
builder.setPositiveButton("确定", null);
builder.show();
}
} catch (JSONException e) {
MobclickAgent.reportError(mContext, e);
}
}
private static void AlertUpdate(){
AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
builder.setTitle("发现新版本");
builder.setMessage("当前版本:" + AppConfig.getVersionName() + "\n"
+ "新版本:" + mUpdateEntity.versionName + "\n"
+ "大小:" + NumberUtil.getPrintSize(mUpdateEntity.fileSize) + "\n"
+ mUpdateEntity.updateLog + "\n");
builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
eventLogger.onEvent("updateConfirm");
updateApp();
}
});
builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
eventLogger.onEvent("updateCancel");
//选择取消之后,不再检查更新
AppConfig.setCheckUpdate(false);
}
});
builder.show();
}
private static void updateApp() {
updateApp(false);
}
private static void updateApp(boolean isEnforceDown) {
String filePath = Environment.getExternalStorageDirectory().getAbsolutePath();
String fileName = AppConfig.getPackageName() + mUpdateEntity.versionName +".apk";
if(!isEnforceDown){
File file = new File(filePath+"/"+fileName);
if(file.exists()){
install(file);
return;
}
}
mAlertDialog = new ProgressDialog(mContext);
mAlertDialog.setTitle("更新("+mUpdateEntity.versionName+")");
mAlertDialog.setMessage("正在下载最新版本...");
mAlertDialog.setCancelable(false);
mAlertDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
mAlertDialog.setProgress(0);
mAlertDialog.setMax(100);
mAlertDialog.setIndeterminate(false);
mAlertDialog.setProgressNumberFormat("");
mAlertDialog.show();
OkHttpUtils.get().url(mUpdateEntity.downUrl).build().execute(
new FileCallBack(
filePath,
fileName) {
@Override
public void inProgress(float progress, long total) {
int downloadSize = (int)(progress * total);
if(downloadSize > mAlertDialog.getProgress() + 100 * 1024) {
mAlertDialog.setProgress((int)(100*progress));
mAlertDialog.setProgressNumberFormat(
String.format("%s/%s",
NumberUtil.getPrintSize(downloadSize),
NumberUtil.getPrintSize(total))
);
}
}
@Override
public void onError(Call call, Exception e) {
//下载失败,是否重试
resterAlert();
eventLogger.onEvent("updateError-"+e.getMessage());
}
@Override
public void onResponse(File file) {
//下载成功,开始安装
install(file);
}
@Override
public void onAfter() {
mAlertDialog.dismiss();
}
});
}
public static void install(File file) {
if(!checkMD5(file)){
md5Alert();
return;
}
eventLogger.onEvent("install");
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mContext.startActivity(intent);
}
private static void md5Alert() {
AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
builder.setTitle("提示");
builder.setMessage("\n安装文件不完整是否重新下载\n");
builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
updateApp(true);
}
});
builder.setNegativeButton("取消", null);
builder.show();
}
private static void resterAlert() {
AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
builder.setTitle("提示");
builder.setMessage("\n文件下载失败是否重试\n");
builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
updateApp();
}
});
builder.setNegativeButton("取消", null);
builder.show();
}
private static boolean checkMD5(File file) {
BigInteger md5Value = null;
try {
md5Value = getMd5ByFile(file);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
Log.d("md5:",md5Value.toString(16));
return md5Value != null && mUpdateEntity.md5 != null && md5Value.equals(mUpdateEntity.md5);
}
public static BigInteger getMd5ByFile(File file) throws FileNotFoundException {
BigInteger value = null;
FileInputStream in = new FileInputStream(file);
try {
MappedByteBuffer byteBuffer = in.getChannel().map(FileChannel.MapMode.READ_ONLY, 0, file.length());
MessageDigest md5 = MessageDigest.getInstance("MD5");
md5.update(byteBuffer);
value = new BigInteger(1, md5.digest());
} catch (Exception e) {
e.printStackTrace();
} finally {
if(null != in) {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return value;
}
}

@ -0,0 +1,39 @@
package org.xing.utils;
import android.app.Activity;
import android.content.Context;
import android.os.Build;
import android.telephony.TelephonyManager;
import java.util.UUID;
/**
* Created by Administrator on 2016/12/29 0029.
*/
public class DeviceUtil {
public static String getUniqueId(Activity act) {
TelephonyManager tm = (TelephonyManager) act.getBaseContext().getSystemService(Context.TELEPHONY_SERVICE);
String tmDevice, tmSerial, tmPhone, androidId;
tmDevice = Build.BRAND;
tmSerial = Build.SERIAL;
androidId = Build.MODEL;
try {
//部分机型这里会抛出异常
tmDevice += tm.getDeviceId();
tmSerial += tm.getSimSerialNumber();
androidId += android.provider.Settings.Secure.getString(
act.getContentResolver(), android.provider.Settings.Secure.ANDROID_ID);
}catch (Exception ex) {
ex.printStackTrace();
}
UUID deviceUuid = new UUID(androidId.hashCode(), ((long)tmDevice.hashCode() << 32) | tmSerial.hashCode());
String uniqueId = deviceUuid.toString();
return uniqueId;
}
}

@ -0,0 +1,104 @@
package org.xing.utils;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Collections;
import java.util.Map;
import java.util.Vector;
/**
* Created by Administrator on 2016/12/29 0029.
*/
public class HttpUtil {
public static String bytes2HexString(byte[] b) {
String ret = "";
for (int i = 0; i < b.length; i++) {
String hex = Integer.toHexString(b[i] & 0xFF);
if (hex.length() == 1) {
hex = '0' + hex;
}
ret += hex.toUpperCase();
}
return ret;
}
public static String md5Encode(String str)
throws NoSuchAlgorithmException, UnsupportedEncodingException{
MessageDigest md5=MessageDigest.getInstance("MD5");
String newstr=bytes2HexString(md5.digest(str.getBytes("utf-8")));
return newstr;
}
public static String formPostParams(Map<String, Object> params, String charset, String secret)
throws UnsupportedEncodingException {
StringBuilder str = new StringBuilder();
Vector<String> fields = new Vector<>();
for(Map.Entry<String, Object> en : params.entrySet()) {
fields.add(URLEncoder.encode(en.getKey(), charset)+
"="+URLEncoder.encode(en.getValue().toString(), charset));
}
Collections.sort(fields);
for(String field : fields) {
if(str.length() > 0) {
str.append("&");
}
str.append(field);
}
try {
String sign = md5Encode(str.toString()+secret);
str.append("&sign="+sign);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
//System.out.println(str.toString());
return str.toString();
}
public static String doPost(String urlString, Map<String, Object> params, String charset) {
StringBuilder result = new StringBuilder();
String secret = "862369397363725329";
try{
String bodyData = formPostParams(params, charset, secret);
URL url = new URL(urlString);
HttpURLConnection urlConn=(HttpURLConnection)url.openConnection();
urlConn.setRequestProperty("Content-Type","application/x-www-form-urlencoded");
urlConn.setDoOutput(true);
urlConn.setDoInput(true);
urlConn.setRequestMethod("POST");
urlConn.setUseCaches(false);
urlConn.connect();
DataOutputStream out = new DataOutputStream(urlConn.getOutputStream());
out.writeBytes(bodyData);
String line = null;
BufferedReader reader = new BufferedReader(
new InputStreamReader(urlConn.getInputStream(), "utf-8"));
while((line = reader.readLine()) != null) {
result.append(line);
}
//System.out.println(result.toString());
out.flush();
out.close();
}catch(Exception e){
e.printStackTrace();
}
return result.toString();
}
}

@ -0,0 +1,95 @@
package org.xing.utils;
import org.json.JSONArray;
import org.json.JSONObject;
import org.json.JSONTokener;
/**
* Json
*/
public class JsonParser {
public static String parseIatResult(String json) {
StringBuffer ret = new StringBuffer();
try {
JSONTokener tokener = new JSONTokener(json);
JSONObject joResult = new JSONObject(tokener);
JSONArray words = joResult.getJSONArray("ws");
for (int i = 0; i < words.length(); i++) {
// 转写结果词,默认使用第一个结果
JSONArray items = words.getJSONObject(i).getJSONArray("cw");
JSONObject obj = items.getJSONObject(0);
ret.append(obj.getString("w"));
// 如果需要多候选结果,解析数组其他字段
// for(int j = 0; j < items.length(); j++)
// {
// JSONObject obj = items.getJSONObject(j);
// ret.append(obj.getString("w"));
// }
}
} catch (Exception e) {
e.printStackTrace();
}
return ret.toString();
}
public static String parseGrammarResult(String json) {
StringBuffer ret = new StringBuffer();
try {
JSONTokener tokener = new JSONTokener(json);
JSONObject joResult = new JSONObject(tokener);
JSONArray words = joResult.getJSONArray("ws");
for (int i = 0; i < words.length(); i++) {
JSONArray items = words.getJSONObject(i).getJSONArray("cw");
for(int j = 0; j < items.length(); j++)
{
JSONObject obj = items.getJSONObject(j);
if(obj.getString("w").contains("nomatch"))
{
ret.append("没有匹配结果.");
return ret.toString();
}
ret.append("【结果】" + obj.getString("w"));
ret.append("【置信度】" + obj.getInt("sc"));
ret.append("\n");
}
}
} catch (Exception e) {
e.printStackTrace();
ret.append("没有匹配结果.");
}
return ret.toString();
}
public static String parseLocalGrammarResult(String json) {
StringBuffer ret = new StringBuffer();
try {
JSONTokener tokener = new JSONTokener(json);
JSONObject joResult = new JSONObject(tokener);
JSONArray words = joResult.getJSONArray("ws");
for (int i = 0; i < words.length(); i++) {
JSONArray items = words.getJSONObject(i).getJSONArray("cw");
for(int j = 0; j < items.length(); j++)
{
JSONObject obj = items.getJSONObject(j);
if(obj.getString("w").contains("nomatch"))
{
ret.append("没有匹配结果.");
return ret.toString();
}
ret.append("【结果】" + obj.getString("w"));
ret.append("\n");
}
}
ret.append("【置信度】" + joResult.optInt("sc"));
} catch (Exception e) {
e.printStackTrace();
ret.append("没有匹配结果.");
}
return ret.toString();
}
}

@ -0,0 +1,63 @@
package org.xing.utils;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
/**
* Created by fujiayi on 2017/5/17.
*/
public class Logger {
private static final String TAG = "Logger";
private static final String INFO = "INFO";
private static final String ERROR = "ERROR";
private static boolean ENABLE = true;
private static Handler handler;
public static void info(String message) {
info(TAG, message);
}
public static void info(String tag, String message) {
log(INFO, tag, message);
}
public static void error(String message) {
error(TAG, message);
}
public static void error(String tag, String message) {
log(ERROR, tag, message);
}
public static void setHandler(Handler handler) {
Logger.handler = handler;
}
private static void log(String level, String tag, String message) {
if (!ENABLE) {
return;
}
if (level.equals(INFO)) {
Log.i(tag, message);
} else if (level.equals(ERROR)) {
Log.e(tag, message);
}
if (handler != null) {
Message msg = Message.obtain();
msg.obj = "[" + level + "]" + message + "\n";
handler.sendMessage(msg);
}
}
public static void setEnable(boolean isEnable) {
ENABLE = isEnable;
}
}

@ -0,0 +1,27 @@
package org.xing.utils;
/**
* Created by Administrator on 2016/12/30 0030.
*/
public class NumberUtil {
public static String format(double num, int maxFloat) {
String text = String.format("%."+maxFloat+"f", num);
text = text.replaceAll("(\\.)?0*$", "");
return text;
}
public static String getPrintSize(long size) {
float printSize = (float)size / 1024/ 1024;
return String.format("%.1fMB", printSize);
}
public static String toFraction(Double number) {
if(number == null || number.isNaN() || number.isInfinite()) {
return null;
}
StringBuilder frac = new StringBuilder();
return frac.toString();
}
}

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle" >
<solid android:color="@color/colorBackground" />
<stroke android:width="1dip" android:color="@color/colorBackground"/>
<corners android:topLeftRadius="3dp"
android:topRightRadius="3dp"
android:bottomRightRadius="3dp"
android:bottomLeftRadius="3dp"/>
</shape>

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle" >
<solid android:color="@color/colorFront" />
<stroke android:width="1dip" android:color="@color/colorFront"/>
<corners android:topLeftRadius="3dp"
android:topRightRadius="3dp"
android:bottomRightRadius="3dp"
android:bottomLeftRadius="3dp"/>
</shape>

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@mipmap/btn_close_click" android:state_pressed="true"/>
<item android:drawable="@mipmap/btn_close" android:state_focused="false" android:state_pressed="false"/>
</selector>

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle" >
<solid android:color="#32A091" />
<stroke android:width="1dip" android:color="#32A091"/>
<corners android:topLeftRadius="10dp"
android:topRightRadius="10dp"
android:bottomRightRadius="10dp"
android:bottomLeftRadius="10dp"/>
</shape>

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@color/colorGrey" android:state_pressed="true"/>
<item android:drawable="@color/colorBackground" android:state_focused="false" android:state_pressed="false"/>
</selector>

@ -0,0 +1,54 @@
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:id="@android:id/background">
<shape>
<corners android:radius="5dip" />
<gradient
android:angle="0"
android:centerColor="#aaaaaa"
android:centerY="0.75"
android:endColor="#aaaaaa"
android:startColor="#9d9e9d" />
</shape>
</item>
<item android:id="@android:id/secondaryProgress">
<clip>
<shape>
<corners android:radius="5dip" />
<gradient
android:angle="0"
android:centerColor="#80ffb600"
android:centerY="0.75"
android:endColor="#a0ffcb00"
android:startColor="#80ffd300" />
</shape>
</clip>
</item>
<item android:id="@android:id/progress">
<clip>
<shape>
<corners android:radius="5dip" />
<gradient
android:angle="0"
android:startColor="#00ff00"
android:endColor="#00aa00"
/>
</shape>
</clip>
</item>
</layer-list>

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle" >
<solid android:color="@color/colorBackground" />
<stroke android:width="1dip" android:color="#cccccc"/>
</shape>

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@mipmap/help_mark_click" android:state_pressed="true"/>
<item android:drawable="@mipmap/help_mark" android:state_focused="false" android:state_pressed="false"/>
</selector>

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@mipmap/share_mark_click" android:state_pressed="true"/>
<item android:drawable="@mipmap/share_mark" android:state_focused="false" android:state_pressed="false"/>
</selector>

@ -0,0 +1,247 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:auto="http://schemas.android.com/apk/res-auto"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="org.xing.android.MainActivity" >
<LinearLayout
android:id="@+id/backgroundLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:background="@color/colorBackground" >
<!-- 计算结果显示区 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="60dp"
android:background="@android:color/transparent"
android:orientation="horizontal" >
<EditText
android:id="@+id/input"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="5dp"
android:background="@android:color/transparent"
android:inputType="textPersonName"
android:textIsSelectable="true"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:textColor="@color/colorText"
android:typeface="serif"
android:text="0"
android:textSize="45dp"
android:duplicateParentState="false" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="vertical"
android:layout_gravity="right"
android:gravity="center"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
>
<Button
android:id="@+id/stateButton"
android:layout_height="30dp"
android:layout_width="30dp"
android:background="@mipmap/input_sleep"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:layout_alignBottom="@+id/input" />
</LinearLayout>
</FrameLayout>
<ProgressBar
style="@android:style/Widget.ProgressBar.Horizontal"
android:id="@+id/recordDynamic"
android:max="100"
android:progress="0"
android:visibility="visible"
android:alpha="50"
android:layout_height="2dp"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:indeterminate="false"
android:layout_width="match_parent"
android:paddingLeft="2dp"
android:paddingRight="2dp"
android:progressDrawable="@drawable/record_progress" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:layout_weight="90"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:background="@android:color/transparent"
>
<!-- 计算历史显示区 -->
<WebView
android:id="@+id/historylist"
android:layout_width="match_parent"
android:background="@android:color/transparent"
android:layout_height="0dp"
android:layout_weight="97"
android:layout_margin="5dp"
android:layout_gravity="center"
android:layerType="software" />
<!-- 控制和状态显示区 -->
<FrameLayout
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:layout_alignParentTop="true" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="3dip"
android:orientation="horizontal"
android:layout_gravity="bottom"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:background="@android:color/transparent" >
<TextView
android:id = "@+id/msg"
android:layout_width="0dp"
android:layout_weight="45"
android:layout_height="wrap_content"
android:textColor="#777777"
android:textSize="12dp"
android:padding="1dip"
android:gravity="bottom"
android:background="@android:color/transparent"
android:layout_gravity="bottom" />
<Button
android:id = "@+id/ctrl_start"
android:layout_width="60dp"
android:layout_height="60dp"
android:clickable="true"
android:background="@mipmap/start"
android:gravity="center"
android:layout_gravity="center_horizontal" />
<LinearLayout
android:layout_width="0dp"
android:layout_weight="45"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_gravity="bottom"
android:gravity="right"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:background="@android:color/transparent" >
<Button
android:id = "@+id/share_mark"
android:layout_width="25dp"
android:layout_height="25dp"
android:textColor="#777777"
android:clickable="true"
android:layout_marginRight="5dp"
android:background="@drawable/textview_share_selector"
android:gravity="center" />
<Button
android:id = "@+id/help_mark"
android:layout_width="25dp"
android:layout_height="25dp"
android:textColor="#777777"
android:clickable="true"
android:background="@drawable/textview_help_selector"
android:gravity="center" />
</LinearLayout>
</LinearLayout>
<!-- 分享操作区 -->
<LinearLayout
android:id="@+id/share_board"
android:layout_marginTop="10dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/share_boder"
android:visibility="gone"
android:orientation="vertical" >
<TextView
android:id = "@+id/share_title"
android:layout_width="match_parent"
android:layout_height="25dp"
android:layout_marginLeft="5dp"
android:layout_marginTop="5dp"
android:textColor="#777777"
android:textSize="15dp"
android:text="分享到" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<ImageView
android:id="@+id/share_weixin"
android:layout_width="60dp"
android:layout_height="60dp"
android:background="@drawable/image_selector"
android:src = "@mipmap/socialize_wechat" />
<ImageView
android:id="@+id/share_pengyouquan"
android:layout_width="60dp"
android:layout_height="60dp"
android:background="@drawable/image_selector"
android:src = "@mipmap/socialize_wxcircle" />
<ImageView
android:id="@+id/share_qq"
android:layout_width="60dp"
android:layout_height="60dp"
android:background="@drawable/image_selector"
android:src = "@mipmap/socialize_qq" />
<ImageView
android:id="@+id/share_kongjian"
android:layout_width="60dp"
android:layout_height="60dp"
android:background="@drawable/image_selector"
android:src = "@mipmap/socialize_qzone" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<Button
android:id="@+id/cancel_btn"
android:layout_width="match_parent"
android:layout_height="40dp"
android:background="#eeeeee"
android:textSize="16dp"
android:text="取消" />
</LinearLayout>
</LinearLayout>
</FrameLayout>
</LinearLayout>
</LinearLayout>
</RelativeLayout>

@ -0,0 +1,91 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_simple_help"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/colorBackground"
tools:context="org.xing.android.SimpleHelpActivity">
<FrameLayout
android:id="@+id/video"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="invisible"
android:background="@android:color/transparent"
android:orientation="horizontal" >
</FrameLayout>
<LinearLayout
android:id="@+id/web"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true">
<LinearLayout
android:id="@+id/toolBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_gravity="center"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:background="@color/colorBackground"
>
<Button
android:id="@+id/help_close"
android:layout_height="40dp"
android:layout_width="40dp"
android:background="@drawable/btn_close_selector"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true" />
<TextView
android:id = "@+id/help_title"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:textColor="#333333"
android:maxLines="1"
android:textSize="20dp"
android:gravity="center"
android:layout_gravity="center_vertical" />
<Button
android:id="@+id/help_blank"
android:layout_height="40dp"
android:layout_width="40dp"
android:background="@color/colorBackground"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true" />
</LinearLayout>
<ProgressBar
style="@android:style/Widget.ProgressBar.Horizontal"
android:id="@+id/webProgress"
android:max="100"
android:progress="0"
android:visibility="invisible"
android:alpha="50"
android:layout_height="2dp"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:indeterminate="false"
android:layout_width="match_parent"
android:paddingLeft="2dp"
android:paddingRight="2dp"
android:progressDrawable="@drawable/record_progress" />
<WebView
android:id="@+id/simple_help"
android:background="@color/colorBackground"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:layerType="hardware" />
</LinearLayout>
</RelativeLayout>

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

@ -0,0 +1,401 @@
A a 阿啊
AI ai 哎哀埃挨唉癌矮蔼艾爱嫒暧隘碍
AN an 安氨鞍庵鹌铵俺埯岸按案暗
ANG ang 肮昂盎
AO ao 凹遨嗷獒熬翱拗袄坳傲奥澳懊
BA ba 八扒叭巴芭吧疤捌拔跋把爸罢粑
BAI bai 掰白百佰伯柏摆败拜
BAN ban 扳颁班斑般搬板版办半伴扮瓣
BANG bang 邦帮梆绑榜膀棒谤磅镑
BAO bao 包苞胞剥煲薄饱宝保堡报抱暴瀑曝爆
BET bet 杯卑碑背悲北贝备倍焙被辈臂
BEN ben 奔本苯笨
BENG beng 崩嘣甭绷泵迸蚌蹦
BI bi 逼鼻比彼笔鄙币必毕闭敝弊辟壁避碧
BIAN bian 边编鞭贬扁匾变便遍辩
BIAO biao 标彪膘表婊裱鳔
BIE bie 瘪憋鳖别
BIN bin 宾滨缤彬斌濒殡鬓
BING bing 冰并兵丙柄炳秉饼屏禀摒病
BO bo 拨波玻菠剥播伯泊魄驳勃脖博搏薄卜
BU bu 补捕哺堡不布怖步部埠簿
CA ca 拆擦嚓
CAI cai 猜才材财裁采彩睬踩菜蔡
CAN can 参餐残蚕惭惨灿
CANG cang 仓苍沧舱藏
CAO cao 操糙曹嘈草
CE ce 册厕侧测策
CEN cen 参
CENG ceng 噌层曾蹭
CHA cha 叉杈差插喳茬茶搽查碴察衩岔
CHAI chai 拆钗差柴豺
CHAN chan 掺搀婵谗馋潺缠产铲阐忏颤
CHANG chang 昌猖长场肠尝偿常厂敞畅倡唱
CHAO chao 抄吵钞超朝嘲潮炒
CHE che 车尺扯彻掣撤
CHEN chen 抻琛臣辰晨尘沉陈碜衬称趁
CHENG cheng 称铛撑成诚城丞呈程承乘惩澄逞秤
CHI chi 吃痴池驰迟持匙尺齿耻斥赤翅
CHONG chong 冲充虫重崇宠
CHOU chou 抽仇筹酬愁丑瞅臭
CHU chu 出初雏除厨锄处储楚畜触
CHUAI chuai 揣踹嘬
CHUAN chuan 川穿传船喘串钏
CHUANG chuang 创疮窗床闯
CHUI chui 吹炊垂捶锤槌
CHUN chun 春纯唇淳鹑醇蠢
CHUO chuo 戳龊辍绰
CI ci 刺词祠雌瓷兹慈磁辞此次伺赐
CONG cong 匆葱苁聪从丛淙
COU cou 凑
CU cu 粗猝促醋簇
CUAN cuan 氽撺蹿攒窜篡
CUI cui 崔催摧脆萃啐淬粹翠
CUN cun 村存寸
CUO cuo 搓蹉撮矬挫措错
DA da 搭答达打大瘩
DAI dai 呆待歹逮傣代贷袋殆怠带戴
DAN dan 丹担单眈耽胆旦但诞淡氮弹蛋
DANG dang 当裆挡党档荡
DAO dao 叨刀倒导岛捣祷蹈到盗悼道稻
DE de 得德地的
DENG deng 灯登等邓凳澄瞪
DI di 低堤滴笛敌涤嘀坻抵底地弟递第帝缔
DIAN dian 掂颠典碘点踮电佃店惦垫奠殿
DIAO diao 刁叼凋碉雕貂吊钓调掉
DIE die 爹跌谍喋牒碟蝶叠
DING ding 丁叮盯钉顶鼎订定锭
DIU diu 丢
DONG dong 东冬董懂动冻栋洞
DOU dou 都兜斗抖蚪陡豆逗痘
DU du 都嘟督毒独读渎肚堵赌睹杜妒度渡镀
DUAN duan 端短段缎煅锻断
DUI dui 堆队对兑碓
DUN dun 吨敦墩蹲盹囤炖钝顿盾遁
DUO duo 多哆掇夺朵垛躲驮舵堕惰
E e 阿讹俄哦娥鹅额恶厄扼饿鄂遏噩
EN en 恩
ER er 儿而尔耳饵二贰
FA fa 发乏伐阀筏罚法
FAN fan 帆番翻凡矾烦繁反返犯范饭贩泛
FANG fang 方坊芳防妨房仿访纺放
FEI fei 飞妃非啡肥匪诽翡肺沸费废痱
FEN fen 分芬纷氛坟汾焚粉份忿奋愤粪
FENG feng 丰风疯封峰烽锋蜂逢缝讽凤奉俸
FO fo 佛
FOU fou 否
FU fu 夫肤麸孵敷扶芙拂伏茯袱俘浮符服幅辐福父斧釜抚辅脯府俯腑腐赴付附负妇复腹覆副富赋傅缚咐
GA ga 旮嘎尬
GAI gai 该改丐钙盖溉概
GAN gan 干杆肝矸竿甘泔柑秆赶擀敢感赣
GANG gang 冈刚岗纲钢肛缸罡港杠
GAO gao 皋高膏篙羔糕睾搞镐稿告诰锆
GE ge 戈圪疙咯胳搁哥歌鸽割革蛤阁格隔葛个各
GEI gei 给
GEN gen 根跟
GENG geng 更庚耕羹埂哽梗耿
GONG gong 工功攻弓躬公供宫恭巩拱共贡
GOU gou 勾沟钩佝枸篝苟狗构购垢够
GU gu 估咕沽姑辜孤骨箍古谷股鼓故固顾雇
GUA gua 瓜呱刮剐寡卦挂褂
GUAI guai 乖掴拐怪
GUAN guan 关观官倌棺冠鳏莞馆管贯惯灌罐
GUANG guang 光咣广犷逛
GUI gui 归圭闺硅龟规瑰轨诡鬼癸柜刽贵桂跪
GUN gun 滚磙辊棍
GUO guo 锅郭蝈聒国帼果裹椁过
HA ha 哈蛤
HAI hai 咳还孩骸海亥害
HAN han 鼾酣憨汗含函涵韩寒罕喊汉旱捍悍焊撼憾翰瀚
HANG hang 夯行吭杭航巷
HAO hao 蒿号蚝毫嗥豪壕嚎好郝耗浩皓
HE he 呵喝禾和合盒何河核阖貉吓贺荷褐赫鹤壑
HEI hei 黑嘿
HEN hen 痕很狠恨
HENG heng 亨哼恒衡横
HONG hong 轰哄烘弘红虹鸿宏洪
HOU hou 侯喉猴吼后厚候
HU hu 乎呼忽糊囫狐弧胡葫湖蝴壶虎唬琥浒互户护沪
HUA hua 华哗花划骅猾滑化桦画话
HUAI huai 怀徊淮槐坏
HUAN huan 欢獾还环寰缓幻换唤涣焕宦浣患
HUANG huang 荒慌皇凰遑徨惶黄潢恍晃幌谎
HUI hui 灰诙恢挥晖辉徽回茴悔毁卉汇会荟绘烩讳诲晦贿彗慧秽惠
HUN hun 昏婚荤浑馄魂混
HUO huo 豁和活火伙或惑货获祸霍藿
JI ji 几讥饥机肌击圾芨鸡奇犄畸唧积姬基稽缉跻激及汲级极吉即亟急疾蒺嫉集辑瘠藉籍己纪挤济给脊戟计记纪忌伎技妓系际季悸剂迹既暨继寄祭寂绩稷鲫冀
JIA jia 加枷嘉夹佳家甲钾贾假价驾架嫁稼
JIAN jian 戋浅笺溅尖奸歼坚间肩艰监兼菅渐煎缄拣茧柬俭捡检减碱剪简见舰件涧饯贱践建健毽键荐剑鉴箭
JIANG jiang 江将浆姜僵疆讲奖蒋匠降酱犟
JIAO jiao 交郊茭姣胶跤浇娇骄教椒焦蕉礁嚼角侥狡饺绞铰矫脚搅缴剿叫轿觉校较酵窖
JIE jie 节阶皆结秸接揭街劫杰桀拮洁捷睫竭截姐解介芥界戒诫届借
JIN jin 巾斤今金津筋禁襟仅尽紧谨锦仅进近靳妗劲晋浸
JING jing 茎经京惊荆睛精旌晶兢井阱颈景儆警劲径痉净静竞竟境镜靖敬
JIONG jiong 迥窘
JIU jiu 纠赳究阄揪九久玖灸韭酒旧臼舅咎救就
JU ju 车拘驹居据锯掬鞠局菊橘矩咀举巨拒炬距句具俱惧剧聚
JUAN juan 捐涓娟鹃圈卷倦眷绢
JUE jue 决诀抉角觉绝倔掘厥镢
JUN jun 军均钧君菌俊峻骏竣郡
KA ka 咖喀卡咔咯
KAI kai 开揩凯楷慨忾
KAN kan 刊看勘堪坎砍侃瞰
KANG kang 康慷糠扛亢伉抗炕
KAO kao 考拷烤铐犒靠
KE ke 坷苛柯科蝌棵稞颗磕瞌壳咳可渴克刻恪客课嗑
KEI kei 克
KEN ken 肯啃垦恳
KENG keng 坑吭铿
KONG kong 空孔恐控
KOU kou 抠囗叩扣寇蔻
KU ku 枯骷哭窟苦库裤酷
KUA kua 夸垮挎胯跨
KUAI kuai 会脍块快筷
KUAN kuan 宽髋款
KUANG kuang 匡诓哐筐狂诳旷矿况框眶
KUI kui 亏盔窥奎逵馗魁葵睽傀匮馈溃愧
KUN kun 坤昆捆困
KUO kuo 括阔扩廓
LA la 垃拉啦旯喇辣落腊蜡
LAI lai 来睐赖癞
LAN lan 兰拦栏岚婪阑澜蓝褴篮览揽缆懒烂滥
LANG lang 啷郎廊榔螂狼琅朗浪
LAO lao 捞劳唠痨牢醪老佬姥络烙落酪涝
LE le 肋勒乐了
LEI lei 勒累雷擂垒磊肋泪类嘞
LENG leng 塄棱冷愣
LI li 哩丽厘离漓篱梨犁黎蠡礼李里娌理鲤力荔历沥雳厉励立莅粒笠吏利莉痢例唳隶栗蜊璃
LIA lia 俩
LIAN lian 连莲涟怜帘联廉镰敛脸练炼恋链
LIANG liang 良粮凉梁粱量两亮谅晾踉辆靓
LIAO liao 撩辽疗聊僚獠潦缭燎寥了料撂镣
LIE lie 咧裂列冽烈趔劣猎
LIN lin 拎邻林淋琳霖临粼磷鳞麟凛檩吝蔺躏
LING ling 伶玲铃翎羚零龄灵棂凌陵菱绫岭领另令
LIU liu 溜熘刘浏留馏瘤流琉柳六遛
LONG long 龙茏咙珑胧聋笼隆陇拢垄弄
LOU lou 搂喽楼耧髅篓陋瘘漏露
LU lu 撸噜卢颅芦庐炉卤虏掳鲁陆录绿禄碌赂鹿辘麓路潞鹭露
LUU luu 驴吕侣铝旅偻屡缕履律虑滤率绿
LUAN luan 峦孪挛鸾銮卵乱
LUUE luue 掠略
LUN lun 抡仑伦论沦轮
LUO luo 捋罗逻锣骡螺裸骆络烙落摞漯
MA ma 妈蚂抹摩吗麻马玛码骂么嘛蟆
MAI mai 埋买迈麦卖脉
MAN man 埋蛮蔓馒瞒满曼谩幔漫慢
MANG mang 芒忙盲氓茫莽
MAO mao 猫毛髦矛茅锚卯铆耄茂冒帽贸貌
ME me 么
MEI mei 没玫枚眉莓梅酶霉媒煤每美镁妹昧寐魅袂媚
MEN men 闷门焖懑们
MENG meng 蒙萌盟檬朦瞢猛锰懵孟梦
MI mi 咪眯弥迷谜醚糜米靡觅泌秘密蜜
MIAN mian 眠绵棉免勉娩冕缅腼面
MIAO miao 喵苗描瞄秒渺缈藐妙庙
MIE mie 咩灭蔑篾
MIN min 民岷皿闵悯闽抿泯敏
MING ming 名铭明鸣冥瞑酩命
MIU miu 谬
MO mo 末摸谋馍摹模膜麽摩磨蘑魔抹茉沫没殁陌脉莫漠寞墨默
MOU mou 哞牟眸谋缪某
MU mu 模母拇姆牡亩木沐目苜牧募墓幕暮慕睦穆
NA na 拿哪那娜呐纳钠衲捺
NAI nai 乃奶奈萘耐
NAN nan 囝囡男南喃楠难腩
NANG nang 囊囔馕攮
NAO nao 孬挠铙蛲垴恼脑闹淖
NE ne 哪讷呢
NEI nei 哪馁内那
NEN nen 恁嫩
NENG neng 能
NI ni 妮尼呢泥倪霓拟你昵逆匿腻溺
NIAN nian 拈蔫年粘黏鲶捻辇撵碾廿念
NIANG niang 娘酿
NIAO niao 鸟袅嬲尿溺
NIE nie 捏涅聂嗫镊蹑臬镍孽蘖
NIN nin 您
NING ning 宁拧咛狞柠凝泞佞
NIU niu 妞牛扭忸纽钮拗
NONG nong 农侬哝浓脓弄
Nu nu 奴孥驽努弩怒
NUU nuu 女恧衄
NUAN nuan 暖
NUUE nuue 疟虐
NUO nuo 挪诺喏搦懦糯
O o 噢哦
OU ou 讴瓯欧殴鸥呕偶藕沤怄
PA pa 趴啪葩扒杷爬耙琶帕怕
PAI pai 拍排徘牌迫哌派湃
PAN pan 番潘攀胖盘磐蟠判叛畔盼
PANG pang 乓滂彷庞旁膀磅螃耪胖
PAO pao 抛泡刨咆狍炮袍跑庖
PEI pei 呸胚醅陪培赔锫裴沛霈帔佩配
PEN pen 喷盆
PENG peng 抨怦砰烹嘭澎朋棚硼鹏彭膨蓬篷捧碰
PI pi 丕邳坯批纰砒披劈噼霹皮陂疲枇毗蚍琵貔郫埤啤脾匹否痞擗癖屁媲睥辟僻
PIAN pian 片扁偏篇翩便骈谝骗
PIAO piao 剽漂缥飘朴嫖瓢殍瞟票嘌骠
PIE pie 撇瞥
PIN pin 拚拼姘贫频嫔品骋
PING ping 乒娉平评坪苹萍凭屏瓶
PO po 朴陂坡颇泊泼婆鄱叵迫珀粕魄破
POU pou 剖
PU pu 仆扑铺噗匍葡莆脯蒲菩璞濮朴埔圃浦普谱蹼堡瀑曝
QI qi 七柒沏妻凄萋栖戚嘁期欺蹊漆齐脐祁祈芪祗岐歧其萁棋祺旗麒奇崎骑琦耆鳍畦乞岂杞起企启绮稽气汽讫迄弃妻泣亟契砌器憩荠
QIA qia 掐卡洽恰髌
QIAN qian 千仟阡扦迁钎签牵铅谦骞黔前虔钱钳掮乾潜浅遣谴欠芡嵌纤茜倩堑慊歉
QIANG qiang 呛枪戗羌腔锵强墙蔷抢襁炝跄
QIAO qiao 悄跷雀锹敲橇乔侨荞桥翘谯憔樵瞧巧壳俏峭鞘窍
QIE qie 切伽茄且窃郄妾怯挈锲惬趄慊
QIN qin 钦侵亲芹芩琴秦禽擒噙勤寝沁
QING qing 青圊清蜻轻氢倾卿情晴擎顷请謦庆亲箐磬
QIONG qiong 穷穹琼
QIU qiu 丘邱蚯秋囚泅求俅逑球酋糗
QU qu 区岖驱躯曲蛐诎屈祛蛆趋渠取娶龋去趣觑
QUAN quan 圈权全痊醛泉拳蜷劝券
QUE que 鹊炔缺瘸却确雀榷
QUN qun 裙群
RAN ran 髯然燃冉染
RANG rang 嚷穰瓤壤攘让
RAO rao 饶娆扰绕
RE re 喏惹热
REN ren 人壬任仁忍荏稔刃仞纫韧轫认任饪妊葚
RENG reng 扔仍
RI ri 日
RONG rong 戎绒茸荣嵘容蓉溶榕熔融
ROU rou 柔揉蹂鞣肉
RU ru 如茹儒濡孺蠕汝乳辱入褥
RUAN ruan 阮软
RUI rui 蕊芮锐瑞睿
RUN run 闰润
RUO ruo 若偌弱
SA sa 仨撒洒卅飒萨挲
SAI sai 腮鳃塞噻赛
SAN san 三叁伞散馓糁
SANG sang 丧桑搡嗓
SAO sao 搔骚缫臊扫嫂埽瘙
SE se 色涩啬瑟塞
SEN sen 森
SENG seng 僧
SHA sha 杀刹沙莎痧裟鲨纱砂煞啥傻厦霎
SHAI shai 筛色晒
SHAN shan 山舢杉衫删姗珊栅跚苫扇煽膻闪陕讪汕疝单骟善缮膳鳝擅嬗赡蟮
SHANG shang 伤殇商墒上垧晌赏尚绱裳
SHAO shao 捎梢稍筲艄鞘烧勺芍苕韶少邵劭绍哨
SHE she 奢赊畲猞舌折佘蛇舍设社射麝涉赦摄慑歙
SHEI shei 谁
SHEN shen 申伸呻绅砷身参糁莘娠深什甚神沈审婶肾甚渗蜃慎
SHENG sheng 升生牲笙甥声绳省圣胜晟盛剩嵊
SHI shi 尸失师狮诗虱施湿嘘识十什石时识实拾食蚀史驶矢豕使始屎士仕氏舐示世市柿式试拭弑似势事侍峙恃饰视是适室逝誓莳释谥嗜噬螫匙
SHOU shou 收熟手守首寿受授绶狩售兽瘦
SHU shu 书戍抒纾舒枢叔菽淑姝殊梳疏蔬输秫孰塾熟赎暑署薯曙黍属蜀鼠数术述戍束树竖腧恕庶墅漱澍
SHUA shua 刷唰耍
SHUAI shuai 衰摔甩帅率蟀
SHUAN shuan 闩拴栓涮
SHUANG shuang 双霜孀爽
SHUI shui 谁水说税睡
SHUN shun 吮顺舜瞬
SHUO shuo 说妁烁铄朔硕
SI si 私司丝咝思斯厮撕嘶死巳祀四泗驷寺似姒伺饲嗣俟食肆
SONG song 忪松凇淞嵩怂耸悚讼颂宋送诵
SOU sou 搜嗖馊溲飕艘叟嗾擞嗽
SU su 苏酥俗夙诉肃素嗉速宿缩粟谡塑溯蔌簌
SUAN suan 狻酸蒜算
SUI sui 尿虽荽眭绥隋随遂髓岁碎崇隧燧穗
SUN sun 孙荪狲飧损笋榫
SUO suo 唆梭羧蓑缩所索唢琐锁嗦
TA ta 他她它趿塌踏塔獭拓沓榻
TAI tai 台苔胎抬跆太汰态肽钛泰
TAN tan 坍贪摊滩瘫坛昙谈痰弹覃谭潭檀忐坦袒毯叹炭碳探
TANG tang 汤耥趟镗唐塘搪糖堂棠樘膛螳帑倘淌躺傥烫
TAO tao 叨涛焘绦掏滔韬逃桃陶萄啕淘讨套
TE te 忒特慝忑
TENG teng 疼腾誊滕藤
TI ti 体剔踢梯锑提缇题啼蹄屉剃涕倜惕替嚏
TIAN tian 天添田佃恬甜填忝舔腆掭
TIAO tiao 佻挑条苕迢笤调挑窕眺跳粜
TIE tie 帖贴萜铁
TING ting 厅汀听烃廷莛庭蜓霆亭停婷挺铤艇
TONG tong 通仝同茼桐铜佟彤童僮潼瞳筒统捅桶恸痛
TOU tou 偷头投骰透
TU tu 凸秃突图荼途涂徒屠土吐兔菟
TUAN tuan 湍团抟疃
TUI tui 忒推颓腿退煺褪蜕
TUN tun 吞屯囤饨豚臀氽褪
TUO tuo 托拖脱驮佗陀驼鸵妥椭拓唾魄
WA wa 挖哇洼蛙娲娃瓦佤袜
WAI wai 歪崴外
WAN wan 弯湾剜蜿豌丸纨完玩顽烷宛惋婉碗莞脘皖挽晚绾万腕蔓
WANG wang 亡汪王网罔惘辋魍枉往旺望妄忘
WEI wei 危委逶巍威偎煨微薇韦违围帏为圩桅唯帷惟维潍伟苇纬玮炜伪尾娓诿萎痿猥卫未味位畏喂胃谓猬渭尉蔚慰魏
WEN wen 温瘟文纹蚊雯闻刎吻紊稳问
WENG weng 翁嗡瓮
WO wo 挝莴涡窝蜗倭喔我沃卧握幄龌斡
WU wu 乌呜钨圬污巫诬屋恶无芜毋吾唔梧吴蜈五伍午忤妩武鹉侮捂舞兀勿物坞戊务雾误悟晤焐鹜
XI xi 夕汐矽兮西茜栖牺硒吸希稀昔惜析淅晰蜥息熄螅奚溪悉蟋犀樨锡熙僖嘻嬉熹膝曦醯习席袭媳隰洗铣玺徙屣喜禧戏系细隙
XIA xia 呷虾瞎匣狎侠峡狭硖遐瑕暇霞辖黠下吓夏厦唬
XIAN xian 仙籼先纤掀锨鲜闲娴痫贤弦舷咸涎衔嫌冼显险蚬藓苋现县限线宪陷馅羡腺献
XIANG xiang 乡相厢湘箱香襄镶详祥降翔享响饷想向项巷象像橡
XIAO xiao 肖削逍消宵硝销霄枭骁萧潇箫嚣淆小晓孝哮笑校效啸
XIE xie 些楔歇蝎协胁邪挟斜偕谐携鞋写血泄泻卸屑械亵谢榭解邂懈蟹
XIN xin 心芯辛莘锌新薪忻昕欣歆鑫囟信衅
XING xing 兴星猩惺腥刑形型行饧陉荥省醒擤杏幸悻性姓
XIONG xiong 凶匈汹胸兄芎雄熊
XIU xiu 休咻修羞馐朽宿秀绣锈袖嗅溴
XU xu 圩吁盱戌须胥虚墟嘘需徐许栩旭序叙恤畜蓄酗绪续絮婿煦蓿
XUAN xuan 轩宣萱喧暄玄悬旋漩选癣炫眩绚渲楦
XUE xue 削靴薛穴学雪血谑
XUN xun 勋熏薰醺旬询恂寻荨巡循训驯讯汛迅徇殉逊浚蕈
YA ya 丫压呀鸦押鸭垭哑牙伢芽蚜崖涯衙雅轧亚娅讶迓砑
YAN yan 咽胭烟恹殷焉嫣阉淹腌湮燕延埏蜒筵闫芫严言妍研岩炎沿盐阎颜檐奄掩兖俨衍剡琰魇郾偃眼演鼹厌砚咽唁彦谚艳滟晏宴堰验雁赝焰焱酽
YANG yang 央泱殃鸯秧鞅扬杨炀疡羊佯徉洋阳仰养氧痒怏样恙烊漾
YAO yao 幺吆夭妖约要腰邀爻肴尧姚窑谣摇徭遥瑶杳咬舀窈药钥曜耀
YE ye 耶椰掖噎爷也冶野业叶页曳夜液腋烨谒
YI yi 一伊咿衣依铱医猗椅漪揖壹噫仪夷荑咦姨胰沂诒饴怡贻迤宜移颐遗疑嶷彝乙已以苡尾矣酏蚁舣倚旖弋亿忆义议艺呓仡屹亦弈奕裔异抑邑悒佚轶役疫毅译驿绎易蜴诣羿翊翌翳翼益嗌溢缢谊逸意薏臆镱癔肄熠殪懿劓
YIN yin 因茵姻阴音喑殷吟垠银龈淫寅鄞尹引吲蚓饮隐瘾印荫胤窨
YING ying 应英瑛莺婴撄嘤缨樱鹦罂膺鹰迎茔荧莹萤营蓥滢盈楹蝇嬴瀛颖影映硬
YO yo 哟
YONG yong 佣拥痈邕庸雍壅臃永咏泳甬俑勇涌恿蛹踊用
YOU you 优忧攸悠呦幽尤犹疣鱿由邮油柚铀莜游友有酉莠黝又右佑幼柚釉鼬诱
YU yu 迂纡淤瘀于盂竽与予妤余馀臾谀萸鱼渔於禺隅喁愚俞逾渝愉瑜榆娱虞舆屿伛宇羽雨禹语玉钰驭芋吁聿峪浴欲裕妪雨郁育昱煜狱域预豫谕喻愈尉蔚熨遇寓御誉毓
YUAN yuan 鸳冤渊元芫园沅鼋员圆垣爰援媛袁猿辕原塬源缘橼圜远苑怨院垸瑗愿
YUE yue 曰约乐岳阅悦越跃粤哕月钥
YUN yun 晕云芸纭耘匀员允陨殒孕运酝郓愠韫蕴韵熨
ZA za 拶杂砸咋扎匝咂
ZAI zai 灾甾哉栽仔载宰崽再在
ZAN zan 簪咱拶昝攒趱暂錾赞瓒
ZANG zang 赃脏臧驵奘葬藏
ZAO zao 遭糟凿早枣蚤澡藻皂唣灶造噪燥躁
ZE ze 则责啧咋择泽仄昃
ZEI zei 贼
ZEN zen 怎谮
ZENG zeng 曾增憎锃缯赠甑
ZHA zha 扎吒咋查喳渣楂札轧闸炸铡喋眨乍诈痄蚱榨栅
ZHAI zhai 侧斋摘宅择翟窄债寨
ZHAN zhan 占沾毡粘詹谵瞻斩崭盏展搌辗战站栈绽湛颤蘸
ZHANG zhang 张章獐彰漳嫜樟蟑长涨掌丈仗杖帐账胀障嶂幛瘴
ZHAO zhao 钊招昭着朝爪找沼召诏照兆赵笊棹罩肇
ZHE zhe 折蜇遮螫哲辄蛰谪辙者锗赭褶这柘浙蔗鹧着
ZHEI zhei 这
ZHEN zhen 贞侦帧桢针珍胗真砧蓁榛臻斟甄箴诊畛疹枕缜圳阵鸩振赈震朕镇
ZHENG zheng 丁正征怔症争挣峥狰睁铮筝蒸拯整证政郑诤
ZHI zhi 之芝支吱枝肢祗只织栀汁知蜘脂执絷直值埴植殖侄职跖止址芷祉趾枳咫旨指酯纸至郅致窒蛭膣志痣帜帙秩制质炙治栉峙痔陟挚掷智滞置雉稚
ZHONG zhong 中忠盅钟衷终肿种冢踵仲众重
ZHOU zhou 舟州洲诌周粥妯轴肘帚纣绉皱咒宙胄昼骤
ZHU zhu 朱侏诛茱珠株铢蛛诸猪潴术竹竺逐烛舳主拄煮褚属嘱瞩伫苎贮助住注驻柱炷蛀杼祝著翥箸铸筑
ZHUA zhua 抓爪
ZHUAI zhuai 拽
ZHUAN zhuan 专砖颛转传啭赚撰馔篆
ZHUANG zhuang 妆庄桩装奘壮状僮撞幢戆
ZHUI zhui 椎锥追坠缀惴缒赘
ZHUN zhun 肫谆准
ZHUO zhuo 拙捉桌倬焯涿灼酌茁卓浊镯啄琢著着擢
ZI zi 孜龇咨姿资兹孳滋淄辎子仔籽姊秭紫訾梓滓自字恣渍
ZONG zong 枞宗综棕踪鬃总纵粽
ZOU zou 邹驺诹走奏揍
ZU zu 租足卒族诅阻组俎祖
ZUAN zuan 钻缵纂赚攥
ZUI zui 咀嘴最醉罪
ZUN zun 尊遵樽撙
ZUO zuo 作嘬昨笮琢左佐撮怍柞祚坐唑座做

@ -0,0 +1 @@
<resources></resources>

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save