Remove now unused vendored libraries
This commit is contained in:
parent
3d749120a7
commit
7b4abe46c1
9
extern/AndroidPinning/AndroidManifest.xml
vendored
9
extern/AndroidPinning/AndroidManifest.xml
vendored
@ -1,9 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
package="org.thoughtcrime.ssl.pinning"
|
|
||||||
android:versionCode="1"
|
|
||||||
android:versionName="1.0.0">
|
|
||||||
|
|
||||||
<uses-sdk android:minSdkVersion="5" android:targetSdkVersion="17"/>
|
|
||||||
|
|
||||||
</manifest>
|
|
621
extern/AndroidPinning/LICENSE
vendored
621
extern/AndroidPinning/LICENSE
vendored
@ -1,621 +0,0 @@
|
|||||||
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
|
|
30
extern/AndroidPinning/build.gradle
vendored
30
extern/AndroidPinning/build.gradle
vendored
@ -1,30 +0,0 @@
|
|||||||
buildscript {
|
|
||||||
repositories {
|
|
||||||
mavenCentral()
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
classpath 'com.android.tools.build:gradle:1.0.0'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
apply plugin: 'android-library'
|
|
||||||
|
|
||||||
android {
|
|
||||||
compileSdkVersion 17
|
|
||||||
buildToolsVersion '23.0.1'
|
|
||||||
|
|
||||||
android {
|
|
||||||
sourceSets {
|
|
||||||
main {
|
|
||||||
manifest.srcFile 'AndroidManifest.xml'
|
|
||||||
java.srcDirs = ['src']
|
|
||||||
resources.srcDirs = ['src']
|
|
||||||
aidl.srcDirs = ['src']
|
|
||||||
renderscript.srcDirs = ['src']
|
|
||||||
res.srcDirs = ['res']
|
|
||||||
assets.srcDirs = ['assets']
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
2
extern/AndroidPinning/project.properties
vendored
2
extern/AndroidPinning/project.properties
vendored
@ -1,2 +0,0 @@
|
|||||||
target=android-17
|
|
||||||
android.library=true
|
|
BIN
extern/AndroidPinning/res/raw/cacerts
vendored
BIN
extern/AndroidPinning/res/raw/cacerts
vendored
Binary file not shown.
@ -1,89 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (C) 2011-2013 Moxie Marlinspike
|
|
||||||
*
|
|
||||||
* 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/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.thoughtcrime.ssl.pinning;
|
|
||||||
|
|
||||||
import java.security.GeneralSecurityException;
|
|
||||||
import java.security.cert.CertificateException;
|
|
||||||
import java.security.cert.X509Certificate;
|
|
||||||
import java.util.LinkedList;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Does the work of cleaning up a certificate chain by sifting out any
|
|
||||||
* unrelated certificates and returning something that's signed from
|
|
||||||
* EE to a trust anchor.
|
|
||||||
*
|
|
||||||
* @author Moxie Marlinspike
|
|
||||||
*/
|
|
||||||
class CertificateChainCleaner {
|
|
||||||
|
|
||||||
private CertificateChainCleaner() {}
|
|
||||||
|
|
||||||
public static X509Certificate[] getCleanChain(X509Certificate[] chain,
|
|
||||||
SystemKeyStore systemKeyStore)
|
|
||||||
throws CertificateException
|
|
||||||
{
|
|
||||||
final LinkedList<X509Certificate> cleanChain = new LinkedList<X509Certificate>();
|
|
||||||
boolean trustedChain = false;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if (systemKeyStore.isTrustRoot(chain[0])) {
|
|
||||||
trustedChain = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
cleanChain.add(chain[0]);
|
|
||||||
|
|
||||||
for (i = 1; i < chain.length; i++) {
|
|
||||||
if (systemKeyStore.isTrustRoot(chain[i])) {
|
|
||||||
trustedChain = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isValidLink(chain[i], chain[i - 1])) {
|
|
||||||
cleanChain.add(chain[i]);
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
final X509Certificate trustRoot = systemKeyStore.getTrustRootFor(chain[i - 1]);
|
|
||||||
|
|
||||||
if (trustRoot != null) {
|
|
||||||
cleanChain.add(trustRoot);
|
|
||||||
trustedChain = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (trustedChain) {
|
|
||||||
return cleanChain.toArray(new X509Certificate[cleanChain.size()]);
|
|
||||||
} else {
|
|
||||||
throw new CertificateException("Didn't find a trust anchor in chain cleanup!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean isValidLink(X509Certificate parent, X509Certificate child) {
|
|
||||||
if (!parent.getSubjectX500Principal().equals(child.getIssuerX500Principal())) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
child.verify(parent.getPublicKey());
|
|
||||||
} catch (GeneralSecurityException gse) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,166 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (C) 2011-2013 Moxie Marlinspike
|
|
||||||
*
|
|
||||||
* 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/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.thoughtcrime.ssl.pinning;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
|
|
||||||
import org.apache.http.conn.ssl.SSLSocketFactory;
|
|
||||||
import org.apache.http.conn.ssl.X509HostnameVerifier;
|
|
||||||
import org.apache.http.params.HttpConnectionParams;
|
|
||||||
import org.apache.http.params.HttpParams;
|
|
||||||
|
|
||||||
import javax.net.ssl.SSLContext;
|
|
||||||
import javax.net.ssl.SSLSocket;
|
|
||||||
import javax.net.ssl.TrustManager;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.InetAddress;
|
|
||||||
import java.net.InetSocketAddress;
|
|
||||||
import java.net.Socket;
|
|
||||||
import java.security.KeyManagementException;
|
|
||||||
import java.security.KeyStoreException;
|
|
||||||
import java.security.NoSuchAlgorithmException;
|
|
||||||
import java.security.UnrecoverableKeyException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A standard Apache SSL Socket Factory that uses an pinning trust manager.
|
|
||||||
* <p>
|
|
||||||
* To use:
|
|
||||||
* <pre>
|
|
||||||
*
|
|
||||||
* String[] pins = new String[] {"40c5401d6f8cbaf08b00edefb1ee87d005b3b9cd"};
|
|
||||||
* SchemeRegistry schemeRegistry = new SchemeRegistry();
|
|
||||||
* schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
|
|
||||||
* schemeRegistry.register(new Scheme("https", new PinningSSLSocketFactory(getContext(),pins, 0), 443));
|
|
||||||
*
|
|
||||||
* HttpParams httpParams = new BasicHttpParams();
|
|
||||||
* ClientConnectionManager connectionManager = new ThreadSafeClientConnManager(httpParams, schemeRegistry);
|
|
||||||
* DefaultHttpClient httpClient = new DefaultHttpClient(connectionManager, httpParams);
|
|
||||||
*
|
|
||||||
* HttpResponse response = httpClient.execute(new HttpGet("https://www.google.com/"));
|
|
||||||
*
|
|
||||||
* </pre>
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @author Moxie Marlinspike
|
|
||||||
*/
|
|
||||||
public class PinningSSLSocketFactory extends SSLSocketFactory {
|
|
||||||
|
|
||||||
private final javax.net.ssl.SSLSocketFactory pinningSocketFactory;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs a PinningSSLSocketFactory with a set of valid pins.
|
|
||||||
*
|
|
||||||
* @param pins An array of encoded pins to match a seen certificate
|
|
||||||
* chain against. A pin is a hex-encoded hash of a X.509 certificate's
|
|
||||||
* SubjectPublicKeyInfo. A pin can be generated using the provided pin.py
|
|
||||||
* script: python ./tools/pin.py certificate_file.pem
|
|
||||||
*
|
|
||||||
* @param enforceUntilTimestampMillis A timestamp (in milliseconds) when pins will stop being
|
|
||||||
* enforced. Normal non-pinned certificate validation
|
|
||||||
* will continue. Set this to some period after your build
|
|
||||||
* date, or to 0 to enforce pins forever.
|
|
||||||
*/
|
|
||||||
|
|
||||||
public PinningSSLSocketFactory(Context context, String[] pins, long enforceUntilTimestampMillis)
|
|
||||||
throws UnrecoverableKeyException, KeyManagementException,
|
|
||||||
NoSuchAlgorithmException, KeyStoreException
|
|
||||||
{
|
|
||||||
super(null);
|
|
||||||
|
|
||||||
final SystemKeyStore keyStore = SystemKeyStore.getInstance(context);
|
|
||||||
final SSLContext pinningSslContext = SSLContext.getInstance(TLS);
|
|
||||||
final TrustManager[] pinningTrustManagers = initializePinningTrustManagers(keyStore, pins, enforceUntilTimestampMillis);
|
|
||||||
|
|
||||||
pinningSslContext.init(null, pinningTrustManagers, null);
|
|
||||||
this.pinningSocketFactory = pinningSslContext.getSocketFactory();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Socket createSocket() throws IOException {
|
|
||||||
return pinningSocketFactory.createSocket();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Socket connectSocket(final Socket sock, final String host, final int port,
|
|
||||||
final InetAddress localAddress, int localPort,
|
|
||||||
final HttpParams params) throws IOException {
|
|
||||||
final SSLSocket sslSock = (SSLSocket) ((sock != null) ? sock : createSocket());
|
|
||||||
|
|
||||||
if ((localAddress != null) || (localPort > 0)) {
|
|
||||||
if (localPort < 0) {
|
|
||||||
localPort = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
sslSock.bind(new InetSocketAddress(localAddress, localPort));
|
|
||||||
}
|
|
||||||
|
|
||||||
final int connTimeout = HttpConnectionParams.getConnectionTimeout(params);
|
|
||||||
final int soTimeout = HttpConnectionParams.getSoTimeout(params);
|
|
||||||
|
|
||||||
final InetSocketAddress remoteAddress = new InetSocketAddress(host, port);
|
|
||||||
sslSock.connect(remoteAddress, connTimeout);
|
|
||||||
sslSock.setSoTimeout(soTimeout);
|
|
||||||
|
|
||||||
try {
|
|
||||||
SSLSocketFactory.STRICT_HOSTNAME_VERIFIER.verify(host, sslSock);
|
|
||||||
} catch (IOException iox) {
|
|
||||||
try {
|
|
||||||
sslSock.close();
|
|
||||||
} catch (Exception ignored) {
|
|
||||||
}
|
|
||||||
throw iox;
|
|
||||||
}
|
|
||||||
|
|
||||||
return sslSock;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Socket createSocket(final Socket socket, final String host,
|
|
||||||
int port, final boolean autoClose)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
if (port == -1) {
|
|
||||||
port = 443;
|
|
||||||
}
|
|
||||||
|
|
||||||
final SSLSocket sslSocket = (SSLSocket) pinningSocketFactory.createSocket(socket, host, port, autoClose);
|
|
||||||
SSLSocketFactory.STRICT_HOSTNAME_VERIFIER.verify(host, sslSocket);
|
|
||||||
return sslSocket;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setHostnameVerifier(X509HostnameVerifier hostnameVerifier) {
|
|
||||||
throw new IllegalArgumentException("Only strict hostname verification (default) " +
|
|
||||||
"is supported!");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public X509HostnameVerifier getHostnameVerifier() {
|
|
||||||
return SSLSocketFactory.STRICT_HOSTNAME_VERIFIER;
|
|
||||||
}
|
|
||||||
|
|
||||||
private TrustManager[] initializePinningTrustManagers(SystemKeyStore keyStore,
|
|
||||||
String[] pins,
|
|
||||||
long enforceUntilTimestampMillis)
|
|
||||||
{
|
|
||||||
final TrustManager[] trustManagers = new TrustManager[1];
|
|
||||||
trustManagers[0] = new PinningTrustManager(keyStore, pins, enforceUntilTimestampMillis);
|
|
||||||
|
|
||||||
return trustManagers;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,199 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (C) 2011-2013 Moxie Marlinspike
|
|
||||||
*
|
|
||||||
* 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/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.thoughtcrime.ssl.pinning;
|
|
||||||
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
import java.security.KeyStoreException;
|
|
||||||
import java.security.MessageDigest;
|
|
||||||
import java.security.NoSuchAlgorithmException;
|
|
||||||
import java.security.cert.CertificateException;
|
|
||||||
import java.security.cert.X509Certificate;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Set;
|
|
||||||
import javax.net.ssl.TrustManager;
|
|
||||||
import javax.net.ssl.TrustManagerFactory;
|
|
||||||
import javax.net.ssl.X509TrustManager;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A TrustManager implementation that enforces Certificate "pins."
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* PinningTrustManager is layered on top of the system's default TrustManager,
|
|
||||||
* such that the system continues to validate CA signatures for SSL connections
|
|
||||||
* as usual. Additionally, however, PinningTrustManager will enforce certificate
|
|
||||||
* constraints on the validated certificate chain. Specifically, it
|
|
||||||
* will ensure that one of an arbitrary number of specified SubjectPublicKeyInfos
|
|
||||||
* appears somewhere in the valid certificate chain.
|
|
||||||
* </p>
|
|
||||||
* <p>
|
|
||||||
* To use:
|
|
||||||
* <pre>
|
|
||||||
* TrustManager[] trustManagers = new TrustManager[1];
|
|
||||||
* trustManagers[0] = new PinningTrustManager(SystemKeyStore.getInstance(),
|
|
||||||
* new String[] {"f30012bbc18c231ac1a44b788e410ce754182513"},
|
|
||||||
* 0);
|
|
||||||
*
|
|
||||||
* SSLContext sslContext = SSLContext.getInstance("TLS");
|
|
||||||
* sslContext.init(null, trustManagers, null);
|
|
||||||
*
|
|
||||||
* HttpsURLConnection urlConnection = (HttpsURLConnection)new URL("https://encrypted.google.com/").openConnection();
|
|
||||||
* urlConnection.setSSLSocketFactory(sslContext.getSocketFactory());
|
|
||||||
* InputStream in = urlConnection.getInputStream();
|
|
||||||
* </pre>
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @author Moxie Marlinspike
|
|
||||||
*/
|
|
||||||
public class PinningTrustManager implements X509TrustManager {
|
|
||||||
|
|
||||||
private final TrustManager[] systemTrustManagers;
|
|
||||||
private final SystemKeyStore systemKeyStore;
|
|
||||||
private final long enforceUntilTimestampMillis;
|
|
||||||
|
|
||||||
private final List<byte[]> pins = new LinkedList<byte[]>();
|
|
||||||
private final Set<X509Certificate> cache = Collections.synchronizedSet(new HashSet<X509Certificate>());
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs a PinningTrustManager with a set of valid pins.
|
|
||||||
*
|
|
||||||
* @param keyStore A SystemKeyStore that validation will be based on.
|
|
||||||
*
|
|
||||||
* @param pins An array of encoded pins to match a seen certificate
|
|
||||||
* chain against. A pin is a hex-encoded hash of a X.509 certificate's
|
|
||||||
* SubjectPublicKeyInfo. A pin can be generated using the provided pin.py
|
|
||||||
* script: python ./tools/pin.py certificate_file.pem
|
|
||||||
*
|
|
||||||
* @param enforceUntilTimestampMillis A timestamp (in milliseconds) when pins will stop being
|
|
||||||
* enforced. Normal non-pinned certificate validation
|
|
||||||
* will continue. Set this to some period after your build
|
|
||||||
* date, or to 0 to enforce pins forever.
|
|
||||||
*/
|
|
||||||
public PinningTrustManager(SystemKeyStore keyStore, String[] pins, long enforceUntilTimestampMillis) {
|
|
||||||
this.systemTrustManagers = initializeSystemTrustManagers(keyStore);
|
|
||||||
this.systemKeyStore = keyStore;
|
|
||||||
this.enforceUntilTimestampMillis = enforceUntilTimestampMillis;
|
|
||||||
|
|
||||||
for (String pin : pins) {
|
|
||||||
this.pins.add(hexStringToByteArray(pin));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private TrustManager[] initializeSystemTrustManagers(SystemKeyStore keyStore) {
|
|
||||||
try {
|
|
||||||
final TrustManagerFactory tmf = TrustManagerFactory.getInstance("X509");
|
|
||||||
tmf.init(keyStore.trustStore);
|
|
||||||
|
|
||||||
return tmf.getTrustManagers();
|
|
||||||
} catch (NoSuchAlgorithmException nsae) {
|
|
||||||
throw new AssertionError(nsae);
|
|
||||||
} catch (KeyStoreException e) {
|
|
||||||
throw new AssertionError(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isValidPin(X509Certificate certificate) throws CertificateException {
|
|
||||||
try {
|
|
||||||
final MessageDigest digest = MessageDigest.getInstance("SHA1");
|
|
||||||
final byte[] spki = certificate.getPublicKey().getEncoded();
|
|
||||||
final byte[] pin = digest.digest(spki);
|
|
||||||
|
|
||||||
for (byte[] validPin : this.pins) {
|
|
||||||
if (Arrays.equals(validPin, pin)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
} catch (NoSuchAlgorithmException nsae) {
|
|
||||||
throw new CertificateException(nsae);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void checkSystemTrust(X509Certificate[] chain, String authType)
|
|
||||||
throws CertificateException {
|
|
||||||
for (TrustManager systemTrustManager : systemTrustManagers) {
|
|
||||||
((X509TrustManager) systemTrustManager).checkServerTrusted(chain, authType);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void checkPinTrust(X509Certificate[] chain)
|
|
||||||
throws CertificateException {
|
|
||||||
|
|
||||||
if (enforceUntilTimestampMillis != 0 &&
|
|
||||||
System.currentTimeMillis() > enforceUntilTimestampMillis)
|
|
||||||
{
|
|
||||||
Log.w("PinningTrustManager", "Certificate pins are stale, falling back to system trust.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final X509Certificate[] cleanChain = CertificateChainCleaner.getCleanChain(chain, systemKeyStore);
|
|
||||||
|
|
||||||
for (X509Certificate certificate : cleanChain) {
|
|
||||||
if (isValidPin(certificate)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new CertificateException("No valid pins found in chain!");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void checkClientTrusted(X509Certificate[] chain, String authType)
|
|
||||||
throws CertificateException {
|
|
||||||
throw new CertificateException("Client certificates not supported!");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void checkServerTrusted(X509Certificate[] chain, String authType)
|
|
||||||
throws CertificateException
|
|
||||||
{
|
|
||||||
if (cache.contains(chain[0])) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Note: We do this so that we'll never be doing worse than the default
|
|
||||||
// system validation. It's duplicate work, however, and can be factored
|
|
||||||
// out if we make the verification below more complete.
|
|
||||||
checkSystemTrust(chain, authType);
|
|
||||||
checkPinTrust(chain);
|
|
||||||
cache.add(chain[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public X509Certificate[] getAcceptedIssuers() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private byte[] hexStringToByteArray(String s) {
|
|
||||||
final int len = s.length();
|
|
||||||
final byte[] data = new byte[len / 2];
|
|
||||||
|
|
||||||
for (int i = 0; i < len; i += 2) {
|
|
||||||
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) +
|
|
||||||
Character.digit(s.charAt(i + 1), 16));
|
|
||||||
}
|
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void clearCache() {
|
|
||||||
cache.clear();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,138 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (C) 2011-2013 Moxie Marlinspike
|
|
||||||
*
|
|
||||||
* 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/>.
|
|
||||||
*/
|
|
||||||
package org.thoughtcrime.ssl.pinning;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.res.Resources.NotFoundException;
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
import java.io.BufferedInputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.security.GeneralSecurityException;
|
|
||||||
import java.security.KeyStore;
|
|
||||||
import java.security.KeyStoreException;
|
|
||||||
import java.security.NoSuchAlgorithmException;
|
|
||||||
import java.security.Principal;
|
|
||||||
import java.security.cert.CertificateException;
|
|
||||||
import java.security.cert.X509Certificate;
|
|
||||||
import java.util.Enumeration;
|
|
||||||
import java.util.HashMap;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An interface to the system's trust anchors. We're using our
|
|
||||||
* own truststore, which is just the AOSP default, but in a place
|
|
||||||
* we know to find it for sure.
|
|
||||||
*
|
|
||||||
* @author Moxie Marlinspike
|
|
||||||
*/
|
|
||||||
public class SystemKeyStore {
|
|
||||||
private static final int CACERTS_FILE_SIZE = 1024 * 140;
|
|
||||||
|
|
||||||
private static SystemKeyStore instance;
|
|
||||||
|
|
||||||
public static synchronized SystemKeyStore getInstance(Context context) {
|
|
||||||
if (instance == null) {
|
|
||||||
instance = new SystemKeyStore(context);
|
|
||||||
}
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
private final HashMap<Principal, X509Certificate> trustRoots;
|
|
||||||
final KeyStore trustStore;
|
|
||||||
|
|
||||||
private SystemKeyStore(Context context) {
|
|
||||||
final KeyStore trustStore = getTrustStore(context);
|
|
||||||
this.trustRoots = initializeTrustedRoots(trustStore);
|
|
||||||
this.trustStore = trustStore;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isTrustRoot(X509Certificate certificate) {
|
|
||||||
final X509Certificate trustRoot = trustRoots.get(certificate.getSubjectX500Principal());
|
|
||||||
return trustRoot != null && trustRoot.getPublicKey().equals(certificate.getPublicKey());
|
|
||||||
}
|
|
||||||
|
|
||||||
public X509Certificate getTrustRootFor(X509Certificate certificate) {
|
|
||||||
final X509Certificate trustRoot = trustRoots.get(certificate.getIssuerX500Principal());
|
|
||||||
|
|
||||||
if (trustRoot == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (trustRoot.getSubjectX500Principal().equals(certificate.getSubjectX500Principal())) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
certificate.verify(trustRoot.getPublicKey());
|
|
||||||
} catch (GeneralSecurityException e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return trustRoot;
|
|
||||||
}
|
|
||||||
|
|
||||||
private HashMap<Principal, X509Certificate> initializeTrustedRoots(KeyStore trustStore) {
|
|
||||||
try {
|
|
||||||
final HashMap<Principal, X509Certificate> trusted =
|
|
||||||
new HashMap<Principal, X509Certificate>();
|
|
||||||
|
|
||||||
for (Enumeration<String> aliases = trustStore.aliases(); aliases.hasMoreElements(); ) {
|
|
||||||
final String alias = aliases.nextElement();
|
|
||||||
final X509Certificate cert = (X509Certificate) trustStore.getCertificate(alias);
|
|
||||||
|
|
||||||
if (cert != null) {
|
|
||||||
trusted.put(cert.getSubjectX500Principal(), cert);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return trusted;
|
|
||||||
} catch (KeyStoreException e) {
|
|
||||||
throw new AssertionError(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private KeyStore getTrustStore(Context context) {
|
|
||||||
try {
|
|
||||||
final KeyStore trustStore = KeyStore.getInstance("BKS");
|
|
||||||
final BufferedInputStream bin =
|
|
||||||
new BufferedInputStream(context.getResources().openRawResource(R.raw.cacerts),
|
|
||||||
CACERTS_FILE_SIZE);
|
|
||||||
|
|
||||||
try {
|
|
||||||
trustStore.load(bin, "changeit".toCharArray());
|
|
||||||
} finally {
|
|
||||||
try {
|
|
||||||
bin.close();
|
|
||||||
} catch (IOException ioe) {
|
|
||||||
Log.w("SystemKeyStore", ioe);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return trustStore;
|
|
||||||
} catch (KeyStoreException kse) {
|
|
||||||
throw new AssertionError(kse);
|
|
||||||
} catch (NoSuchAlgorithmException e) {
|
|
||||||
throw new AssertionError(e);
|
|
||||||
} catch (CertificateException e) {
|
|
||||||
throw new AssertionError(e);
|
|
||||||
} catch (NotFoundException e) {
|
|
||||||
throw new AssertionError(e);
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new AssertionError(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,111 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (C) 2011-2013 Moxie Marlinspike
|
|
||||||
*
|
|
||||||
* 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/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.thoughtcrime.ssl.pinning.util;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
|
|
||||||
import org.apache.http.client.HttpClient;
|
|
||||||
import org.apache.http.conn.ClientConnectionManager;
|
|
||||||
import org.apache.http.conn.scheme.PlainSocketFactory;
|
|
||||||
import org.apache.http.conn.scheme.Scheme;
|
|
||||||
import org.apache.http.conn.scheme.SchemeRegistry;
|
|
||||||
import org.apache.http.impl.client.DefaultHttpClient;
|
|
||||||
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
|
|
||||||
import org.apache.http.params.BasicHttpParams;
|
|
||||||
import org.apache.http.params.HttpParams;
|
|
||||||
import org.thoughtcrime.ssl.pinning.PinningSSLSocketFactory;
|
|
||||||
import org.thoughtcrime.ssl.pinning.PinningTrustManager;
|
|
||||||
import org.thoughtcrime.ssl.pinning.SystemKeyStore;
|
|
||||||
|
|
||||||
import javax.net.ssl.HttpsURLConnection;
|
|
||||||
import javax.net.ssl.SSLContext;
|
|
||||||
import javax.net.ssl.TrustManager;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.URL;
|
|
||||||
import java.security.KeyManagementException;
|
|
||||||
import java.security.KeyStoreException;
|
|
||||||
import java.security.NoSuchAlgorithmException;
|
|
||||||
import java.security.UnrecoverableKeyException;
|
|
||||||
|
|
||||||
public class PinningHelper {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs an HttpClient that will validate SSL connections with a PinningTrustManager.
|
|
||||||
*
|
|
||||||
* @param pins An array of encoded pins to match a seen certificate
|
|
||||||
* chain against. A pin is a hex-encoded hash of a X.509 certificate's
|
|
||||||
* SubjectPublicKeyInfo. A pin can be generated using the provided pin.py
|
|
||||||
* script: python ./tools/pin.py certificate_file.pem
|
|
||||||
*/
|
|
||||||
|
|
||||||
public static HttpClient getPinnedHttpClient(Context context, String[] pins) {
|
|
||||||
try {
|
|
||||||
SchemeRegistry schemeRegistry = new SchemeRegistry();
|
|
||||||
schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
|
|
||||||
schemeRegistry.register(new Scheme("https", new PinningSSLSocketFactory(context, pins, 0), 443));
|
|
||||||
|
|
||||||
HttpParams httpParams = new BasicHttpParams();
|
|
||||||
ClientConnectionManager connectionManager = new ThreadSafeClientConnManager(httpParams, schemeRegistry);
|
|
||||||
return new DefaultHttpClient(connectionManager, httpParams);
|
|
||||||
} catch (UnrecoverableKeyException e) {
|
|
||||||
throw new AssertionError(e);
|
|
||||||
} catch (KeyManagementException e) {
|
|
||||||
throw new AssertionError(e);
|
|
||||||
} catch (NoSuchAlgorithmException e) {
|
|
||||||
throw new AssertionError(e);
|
|
||||||
} catch (KeyStoreException e) {
|
|
||||||
throw new AssertionError(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs an HttpsURLConnection that will validate HTTPS connections against a set of
|
|
||||||
* specified pins.
|
|
||||||
*
|
|
||||||
* @param pins An array of encoded pins to match a seen certificate
|
|
||||||
* chain against. A pin is a hex-encoded hash of a X.509 certificate's
|
|
||||||
* SubjectPublicKeyInfo. A pin can be generated using the provided pin.py
|
|
||||||
* script: python ./tools/pin.py certificate_file.pem
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
public static HttpsURLConnection getPinnedHttpsURLConnection(Context context, String[] pins, URL url)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
if (!url.getProtocol().equals("https")) {
|
|
||||||
throw new IllegalArgumentException("Attempt to construct pinned non-https connection!");
|
|
||||||
}
|
|
||||||
|
|
||||||
TrustManager[] trustManagers = new TrustManager[1];
|
|
||||||
trustManagers[0] = new PinningTrustManager(SystemKeyStore.getInstance(context), pins, 0);
|
|
||||||
|
|
||||||
SSLContext sslContext = SSLContext.getInstance("TLS");
|
|
||||||
sslContext.init(null, trustManagers, null);
|
|
||||||
|
|
||||||
HttpsURLConnection urlConnection = (HttpsURLConnection)url.openConnection();
|
|
||||||
urlConnection.setSSLSocketFactory(sslContext.getSocketFactory());
|
|
||||||
|
|
||||||
return urlConnection;
|
|
||||||
} catch (NoSuchAlgorithmException nsae) {
|
|
||||||
throw new AssertionError(nsae);
|
|
||||||
} catch (KeyManagementException e) {
|
|
||||||
throw new AssertionError(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
201
extern/UniversalImageLoader/LICENSE
vendored
201
extern/UniversalImageLoader/LICENSE
vendored
@ -1,201 +0,0 @@
|
|||||||
Apache License
|
|
||||||
Version 2.0, January 2004
|
|
||||||
http://www.apache.org/licenses/
|
|
||||||
|
|
||||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
||||||
|
|
||||||
1. Definitions.
|
|
||||||
|
|
||||||
"License" shall mean the terms and conditions for use, reproduction,
|
|
||||||
and distribution as defined by Sections 1 through 9 of this document.
|
|
||||||
|
|
||||||
"Licensor" shall mean the copyright owner or entity authorized by
|
|
||||||
the copyright owner that is granting the License.
|
|
||||||
|
|
||||||
"Legal Entity" shall mean the union of the acting entity and all
|
|
||||||
other entities that control, are controlled by, or are under common
|
|
||||||
control with that entity. For the purposes of this definition,
|
|
||||||
"control" means (i) the power, direct or indirect, to cause the
|
|
||||||
direction or management of such entity, whether by contract or
|
|
||||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
||||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
||||||
|
|
||||||
"You" (or "Your") shall mean an individual or Legal Entity
|
|
||||||
exercising permissions granted by this License.
|
|
||||||
|
|
||||||
"Source" form shall mean the preferred form for making modifications,
|
|
||||||
including but not limited to software source code, documentation
|
|
||||||
source, and configuration files.
|
|
||||||
|
|
||||||
"Object" form shall mean any form resulting from mechanical
|
|
||||||
transformation or translation of a Source form, including but
|
|
||||||
not limited to compiled object code, generated documentation,
|
|
||||||
and conversions to other media types.
|
|
||||||
|
|
||||||
"Work" shall mean the work of authorship, whether in Source or
|
|
||||||
Object form, made available under the License, as indicated by a
|
|
||||||
copyright notice that is included in or attached to the work
|
|
||||||
(an example is provided in the Appendix below).
|
|
||||||
|
|
||||||
"Derivative Works" shall mean any work, whether in Source or Object
|
|
||||||
form, that is based on (or derived from) the Work and for which the
|
|
||||||
editorial revisions, annotations, elaborations, or other modifications
|
|
||||||
represent, as a whole, an original work of authorship. For the purposes
|
|
||||||
of this License, Derivative Works shall not include works that remain
|
|
||||||
separable from, or merely link (or bind by name) to the interfaces of,
|
|
||||||
the Work and Derivative Works thereof.
|
|
||||||
|
|
||||||
"Contribution" shall mean any work of authorship, including
|
|
||||||
the original version of the Work and any modifications or additions
|
|
||||||
to that Work or Derivative Works thereof, that is intentionally
|
|
||||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
||||||
or by an individual or Legal Entity authorized to submit on behalf of
|
|
||||||
the copyright owner. For the purposes of this definition, "submitted"
|
|
||||||
means any form of electronic, verbal, or written communication sent
|
|
||||||
to the Licensor or its representatives, including but not limited to
|
|
||||||
communication on electronic mailing lists, source code control systems,
|
|
||||||
and issue tracking systems that are managed by, or on behalf of, the
|
|
||||||
Licensor for the purpose of discussing and improving the Work, but
|
|
||||||
excluding communication that is conspicuously marked or otherwise
|
|
||||||
designated in writing by the copyright owner as "Not a Contribution."
|
|
||||||
|
|
||||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
||||||
on behalf of whom a Contribution has been received by Licensor and
|
|
||||||
subsequently incorporated within the Work.
|
|
||||||
|
|
||||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
||||||
copyright license to reproduce, prepare Derivative Works of,
|
|
||||||
publicly display, publicly perform, sublicense, and distribute the
|
|
||||||
Work and such Derivative Works in Source or Object form.
|
|
||||||
|
|
||||||
3. Grant of Patent License. Subject to the terms and conditions of
|
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
||||||
(except as stated in this section) patent license to make, have made,
|
|
||||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
||||||
where such license applies only to those patent claims licensable
|
|
||||||
by such Contributor that are necessarily infringed by their
|
|
||||||
Contribution(s) alone or by combination of their Contribution(s)
|
|
||||||
with the Work to which such Contribution(s) was submitted. If You
|
|
||||||
institute patent litigation against any entity (including a
|
|
||||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
||||||
or a Contribution incorporated within the Work constitutes direct
|
|
||||||
or contributory patent infringement, then any patent licenses
|
|
||||||
granted to You under this License for that Work shall terminate
|
|
||||||
as of the date such litigation is filed.
|
|
||||||
|
|
||||||
4. Redistribution. You may reproduce and distribute copies of the
|
|
||||||
Work or Derivative Works thereof in any medium, with or without
|
|
||||||
modifications, and in Source or Object form, provided that You
|
|
||||||
meet the following conditions:
|
|
||||||
|
|
||||||
(a) You must give any other recipients of the Work or
|
|
||||||
Derivative Works a copy of this License; and
|
|
||||||
|
|
||||||
(b) You must cause any modified files to carry prominent notices
|
|
||||||
stating that You changed the files; and
|
|
||||||
|
|
||||||
(c) You must retain, in the Source form of any Derivative Works
|
|
||||||
that You distribute, all copyright, patent, trademark, and
|
|
||||||
attribution notices from the Source form of the Work,
|
|
||||||
excluding those notices that do not pertain to any part of
|
|
||||||
the Derivative Works; and
|
|
||||||
|
|
||||||
(d) If the Work includes a "NOTICE" text file as part of its
|
|
||||||
distribution, then any Derivative Works that You distribute must
|
|
||||||
include a readable copy of the attribution notices contained
|
|
||||||
within such NOTICE file, excluding those notices that do not
|
|
||||||
pertain to any part of the Derivative Works, in at least one
|
|
||||||
of the following places: within a NOTICE text file distributed
|
|
||||||
as part of the Derivative Works; within the Source form or
|
|
||||||
documentation, if provided along with the Derivative Works; or,
|
|
||||||
within a display generated by the Derivative Works, if and
|
|
||||||
wherever such third-party notices normally appear. The contents
|
|
||||||
of the NOTICE file are for informational purposes only and
|
|
||||||
do not modify the License. You may add Your own attribution
|
|
||||||
notices within Derivative Works that You distribute, alongside
|
|
||||||
or as an addendum to the NOTICE text from the Work, provided
|
|
||||||
that such additional attribution notices cannot be construed
|
|
||||||
as modifying the License.
|
|
||||||
|
|
||||||
You may add Your own copyright statement to Your modifications and
|
|
||||||
may provide additional or different license terms and conditions
|
|
||||||
for use, reproduction, or distribution of Your modifications, or
|
|
||||||
for any such Derivative Works as a whole, provided Your use,
|
|
||||||
reproduction, and distribution of the Work otherwise complies with
|
|
||||||
the conditions stated in this License.
|
|
||||||
|
|
||||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
||||||
any Contribution intentionally submitted for inclusion in the Work
|
|
||||||
by You to the Licensor shall be under the terms and conditions of
|
|
||||||
this License, without any additional terms or conditions.
|
|
||||||
Notwithstanding the above, nothing herein shall supersede or modify
|
|
||||||
the terms of any separate license agreement you may have executed
|
|
||||||
with Licensor regarding such Contributions.
|
|
||||||
|
|
||||||
6. Trademarks. This License does not grant permission to use the trade
|
|
||||||
names, trademarks, service marks, or product names of the Licensor,
|
|
||||||
except as required for reasonable and customary use in describing the
|
|
||||||
origin of the Work and reproducing the content of the NOTICE file.
|
|
||||||
|
|
||||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
||||||
agreed to in writing, Licensor provides the Work (and each
|
|
||||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
||||||
implied, including, without limitation, any warranties or conditions
|
|
||||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
||||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
||||||
appropriateness of using or redistributing the Work and assume any
|
|
||||||
risks associated with Your exercise of permissions under this License.
|
|
||||||
|
|
||||||
8. Limitation of Liability. In no event and under no legal theory,
|
|
||||||
whether in tort (including negligence), contract, or otherwise,
|
|
||||||
unless required by applicable law (such as deliberate and grossly
|
|
||||||
negligent acts) or agreed to in writing, shall any Contributor be
|
|
||||||
liable to You for damages, including any direct, indirect, special,
|
|
||||||
incidental, or consequential damages of any character arising as a
|
|
||||||
result of this License or out of the use or inability to use the
|
|
||||||
Work (including but not limited to damages for loss of goodwill,
|
|
||||||
work stoppage, computer failure or malfunction, or any and all
|
|
||||||
other commercial damages or losses), even if such Contributor
|
|
||||||
has been advised of the possibility of such damages.
|
|
||||||
|
|
||||||
9. Accepting Warranty or Additional Liability. While redistributing
|
|
||||||
the Work or Derivative Works thereof, You may choose to offer,
|
|
||||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
||||||
or other liability obligations and/or rights consistent with this
|
|
||||||
License. However, in accepting such obligations, You may act only
|
|
||||||
on Your own behalf and on Your sole responsibility, not on behalf
|
|
||||||
of any other Contributor, and only if You agree to indemnify,
|
|
||||||
defend, and hold each Contributor harmless for any liability
|
|
||||||
incurred by, or claims asserted against, such Contributor by reason
|
|
||||||
of your accepting any such warranty or additional liability.
|
|
||||||
|
|
||||||
END OF TERMS AND CONDITIONS
|
|
||||||
|
|
||||||
APPENDIX: How to apply the Apache License to your work.
|
|
||||||
|
|
||||||
To apply the Apache License to your work, attach the following
|
|
||||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
|
||||||
replaced with your own identifying information. (Don't include
|
|
||||||
the brackets!) The text should be enclosed in the appropriate
|
|
||||||
comment syntax for the file format. We also recommend that a
|
|
||||||
file or class name and description of purpose be included on the
|
|
||||||
same "printed page" as the copyright notice for easier
|
|
||||||
identification within third-party archives.
|
|
||||||
|
|
||||||
Copyright [yyyy] [name of copyright owner]
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
17
extern/UniversalImageLoader/build.gradle
vendored
17
extern/UniversalImageLoader/build.gradle
vendored
@ -1,17 +0,0 @@
|
|||||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
|
||||||
|
|
||||||
buildscript {
|
|
||||||
repositories {
|
|
||||||
jcenter()
|
|
||||||
}
|
|
||||||
dependencies {
|
|
||||||
classpath 'com.android.tools.build:gradle:1.2.3'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
allprojects {
|
|
||||||
repositories {
|
|
||||||
jcenter()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
package="com.nostra13.universalimageloader"
|
|
||||||
android:versionCode="39"
|
|
||||||
android:versionName="1.9.4" >
|
|
||||||
|
|
||||||
<uses-sdk
|
|
||||||
android:minSdkVersion="5"
|
|
||||||
android:targetSdkVersion="22" />
|
|
||||||
|
|
||||||
</manifest>
|
|
36
extern/UniversalImageLoader/library/build.gradle
vendored
36
extern/UniversalImageLoader/library/build.gradle
vendored
@ -1,36 +0,0 @@
|
|||||||
apply plugin: 'com.android.library'
|
|
||||||
|
|
||||||
android {
|
|
||||||
compileSdkVersion 22
|
|
||||||
buildToolsVersion "23.0.1"
|
|
||||||
|
|
||||||
defaultConfig {
|
|
||||||
minSdkVersion 5
|
|
||||||
targetSdkVersion 22
|
|
||||||
}
|
|
||||||
buildTypes {
|
|
||||||
sourceSets {
|
|
||||||
main {
|
|
||||||
manifest.srcFile 'AndroidManifest.xml'
|
|
||||||
java.srcDirs = ['src']
|
|
||||||
resources.srcDirs = ['src']
|
|
||||||
aidl.srcDirs = ['src']
|
|
||||||
renderscript.srcDirs = ['src']
|
|
||||||
res.srcDirs = ['res']
|
|
||||||
}
|
|
||||||
}
|
|
||||||
release {
|
|
||||||
minifyEnabled false
|
|
||||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
compileOptions {
|
|
||||||
sourceCompatibility JavaVersion.VERSION_1_6
|
|
||||||
targetCompatibility JavaVersion.VERSION_1_6
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
compile 'com.android.support:support-v4:22.1.1'
|
|
||||||
}
|
|
@ -1,12 +0,0 @@
|
|||||||
# This file is automatically generated by Android Tools.
|
|
||||||
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
|
|
||||||
#
|
|
||||||
# This file must be checked in Version Control Systems.
|
|
||||||
#
|
|
||||||
# To customize properties used by the Ant build system use,
|
|
||||||
# "ant.properties", and override values to adapt the script to your
|
|
||||||
# project structure.
|
|
||||||
|
|
||||||
# Project target.
|
|
||||||
target=android-21
|
|
||||||
android.library=true
|
|
@ -1,85 +0,0 @@
|
|||||||
/*******************************************************************************
|
|
||||||
* Copyright 2014 Sergey Tarasevich
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*******************************************************************************/
|
|
||||||
package com.nostra13.universalimageloader.cache.disc;
|
|
||||||
|
|
||||||
import android.graphics.Bitmap;
|
|
||||||
import com.nostra13.universalimageloader.utils.IoUtils;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Interface for disk cache
|
|
||||||
*
|
|
||||||
* @author Sergey Tarasevich (nostra13[at]gmail[dot]com)
|
|
||||||
* @since 1.9.2
|
|
||||||
*/
|
|
||||||
public interface DiskCache {
|
|
||||||
/**
|
|
||||||
* Returns root directory of disk cache
|
|
||||||
*
|
|
||||||
* @return Root directory of disk cache
|
|
||||||
*/
|
|
||||||
File getDirectory();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns file of cached image
|
|
||||||
*
|
|
||||||
* @param imageUri Original image URI
|
|
||||||
* @return File of cached image or <b>null</b> if image wasn't cached
|
|
||||||
*/
|
|
||||||
File get(String imageUri);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Saves image stream in disk cache.
|
|
||||||
* Incoming image stream shouldn't be closed in this method.
|
|
||||||
*
|
|
||||||
* @param imageUri Original image URI
|
|
||||||
* @param imageStream Input stream of image (shouldn't be closed in this method)
|
|
||||||
* @param listener Listener for saving progress, can be ignored if you don't use
|
|
||||||
* {@linkplain com.nostra13.universalimageloader.core.listener.ImageLoadingProgressListener
|
|
||||||
* progress listener} in ImageLoader calls
|
|
||||||
* @return <b>true</b> - if image was saved successfully; <b>false</b> - if image wasn't saved in disk cache.
|
|
||||||
* @throws java.io.IOException
|
|
||||||
*/
|
|
||||||
boolean save(String imageUri, InputStream imageStream, IoUtils.CopyListener listener) throws IOException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Saves image bitmap in disk cache.
|
|
||||||
*
|
|
||||||
* @param imageUri Original image URI
|
|
||||||
* @param bitmap Image bitmap
|
|
||||||
* @return <b>true</b> - if bitmap was saved successfully; <b>false</b> - if bitmap wasn't saved in disk cache.
|
|
||||||
* @throws IOException
|
|
||||||
*/
|
|
||||||
boolean save(String imageUri, Bitmap bitmap) throws IOException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes image file associated with incoming URI
|
|
||||||
*
|
|
||||||
* @param imageUri Image URI
|
|
||||||
* @return <b>true</b> - if image file is deleted successfully; <b>false</b> - if image file doesn't exist for
|
|
||||||
* incoming URI or image file can't be deleted.
|
|
||||||
*/
|
|
||||||
boolean remove(String imageUri);
|
|
||||||
|
|
||||||
/** Closes disk cache, releases resources. */
|
|
||||||
void close();
|
|
||||||
|
|
||||||
/** Clears disk cache. */
|
|
||||||
void clear();
|
|
||||||
}
|
|
@ -1,188 +0,0 @@
|
|||||||
/*******************************************************************************
|
|
||||||
* Copyright 2011-2014 Sergey Tarasevich
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*******************************************************************************/
|
|
||||||
package com.nostra13.universalimageloader.cache.disc.impl;
|
|
||||||
|
|
||||||
import android.graphics.Bitmap;
|
|
||||||
import com.nostra13.universalimageloader.cache.disc.DiskCache;
|
|
||||||
import com.nostra13.universalimageloader.cache.disc.naming.FileNameGenerator;
|
|
||||||
import com.nostra13.universalimageloader.core.DefaultConfigurationFactory;
|
|
||||||
import com.nostra13.universalimageloader.utils.IoUtils;
|
|
||||||
|
|
||||||
import java.io.BufferedOutputStream;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Base disk cache.
|
|
||||||
*
|
|
||||||
* @author Sergey Tarasevich (nostra13[at]gmail[dot]com)
|
|
||||||
* @see FileNameGenerator
|
|
||||||
* @since 1.0.0
|
|
||||||
*/
|
|
||||||
public abstract class BaseDiskCache implements DiskCache {
|
|
||||||
/** {@value */
|
|
||||||
public static final int DEFAULT_BUFFER_SIZE = 32 * 1024; // 32 Kb
|
|
||||||
/** {@value */
|
|
||||||
public static final Bitmap.CompressFormat DEFAULT_COMPRESS_FORMAT = Bitmap.CompressFormat.PNG;
|
|
||||||
/** {@value */
|
|
||||||
public static final int DEFAULT_COMPRESS_QUALITY = 100;
|
|
||||||
|
|
||||||
private static final String ERROR_ARG_NULL = " argument must be not null";
|
|
||||||
private static final String TEMP_IMAGE_POSTFIX = ".tmp";
|
|
||||||
|
|
||||||
protected final File cacheDir;
|
|
||||||
protected final File reserveCacheDir;
|
|
||||||
|
|
||||||
protected final FileNameGenerator fileNameGenerator;
|
|
||||||
|
|
||||||
protected int bufferSize = DEFAULT_BUFFER_SIZE;
|
|
||||||
|
|
||||||
protected Bitmap.CompressFormat compressFormat = DEFAULT_COMPRESS_FORMAT;
|
|
||||||
protected int compressQuality = DEFAULT_COMPRESS_QUALITY;
|
|
||||||
|
|
||||||
/** @param cacheDir Directory for file caching */
|
|
||||||
public BaseDiskCache(File cacheDir) {
|
|
||||||
this(cacheDir, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param cacheDir Directory for file caching
|
|
||||||
* @param reserveCacheDir null-ok; Reserve directory for file caching. It's used when the primary directory isn't available.
|
|
||||||
*/
|
|
||||||
public BaseDiskCache(File cacheDir, File reserveCacheDir) {
|
|
||||||
this(cacheDir, reserveCacheDir, DefaultConfigurationFactory.createFileNameGenerator());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param cacheDir Directory for file caching
|
|
||||||
* @param reserveCacheDir null-ok; Reserve directory for file caching. It's used when the primary directory isn't available.
|
|
||||||
* @param fileNameGenerator {@linkplain com.nostra13.universalimageloader.cache.disc.naming.FileNameGenerator
|
|
||||||
* Name generator} for cached files
|
|
||||||
*/
|
|
||||||
public BaseDiskCache(File cacheDir, File reserveCacheDir, FileNameGenerator fileNameGenerator) {
|
|
||||||
if (cacheDir == null) {
|
|
||||||
throw new IllegalArgumentException("cacheDir" + ERROR_ARG_NULL);
|
|
||||||
}
|
|
||||||
if (fileNameGenerator == null) {
|
|
||||||
throw new IllegalArgumentException("fileNameGenerator" + ERROR_ARG_NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.cacheDir = cacheDir;
|
|
||||||
this.reserveCacheDir = reserveCacheDir;
|
|
||||||
this.fileNameGenerator = fileNameGenerator;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public File getDirectory() {
|
|
||||||
return cacheDir;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public File get(String imageUri) {
|
|
||||||
return getFile(imageUri);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean save(String imageUri, InputStream imageStream, IoUtils.CopyListener listener) throws IOException {
|
|
||||||
File imageFile = getFile(imageUri);
|
|
||||||
File tmpFile = new File(imageFile.getAbsolutePath() + TEMP_IMAGE_POSTFIX);
|
|
||||||
boolean loaded = false;
|
|
||||||
try {
|
|
||||||
OutputStream os = new BufferedOutputStream(new FileOutputStream(tmpFile), bufferSize);
|
|
||||||
try {
|
|
||||||
loaded = IoUtils.copyStream(imageStream, os, listener, bufferSize);
|
|
||||||
} finally {
|
|
||||||
IoUtils.closeSilently(os);
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
if (loaded && !tmpFile.renameTo(imageFile)) {
|
|
||||||
loaded = false;
|
|
||||||
}
|
|
||||||
if (!loaded) {
|
|
||||||
tmpFile.delete();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return loaded;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean save(String imageUri, Bitmap bitmap) throws IOException {
|
|
||||||
File imageFile = getFile(imageUri);
|
|
||||||
File tmpFile = new File(imageFile.getAbsolutePath() + TEMP_IMAGE_POSTFIX);
|
|
||||||
OutputStream os = new BufferedOutputStream(new FileOutputStream(tmpFile), bufferSize);
|
|
||||||
boolean savedSuccessfully = false;
|
|
||||||
try {
|
|
||||||
savedSuccessfully = bitmap.compress(compressFormat, compressQuality, os);
|
|
||||||
} finally {
|
|
||||||
IoUtils.closeSilently(os);
|
|
||||||
if (savedSuccessfully && !tmpFile.renameTo(imageFile)) {
|
|
||||||
savedSuccessfully = false;
|
|
||||||
}
|
|
||||||
if (!savedSuccessfully) {
|
|
||||||
tmpFile.delete();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
bitmap.recycle();
|
|
||||||
return savedSuccessfully;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean remove(String imageUri) {
|
|
||||||
return getFile(imageUri).delete();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void close() {
|
|
||||||
// Nothing to do
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void clear() {
|
|
||||||
File[] files = cacheDir.listFiles();
|
|
||||||
if (files != null) {
|
|
||||||
for (File f : files) {
|
|
||||||
f.delete();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Returns file object (not null) for incoming image URI. File object can reference to non-existing file. */
|
|
||||||
protected File getFile(String imageUri) {
|
|
||||||
String fileName = fileNameGenerator.generate(imageUri);
|
|
||||||
File dir = cacheDir;
|
|
||||||
if (!cacheDir.exists() && !cacheDir.mkdirs()) {
|
|
||||||
if (reserveCacheDir != null && (reserveCacheDir.exists() || reserveCacheDir.mkdirs())) {
|
|
||||||
dir = reserveCacheDir;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return new File(dir, fileName);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setBufferSize(int bufferSize) {
|
|
||||||
this.bufferSize = bufferSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCompressFormat(Bitmap.CompressFormat compressFormat) {
|
|
||||||
this.compressFormat = compressFormat;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCompressQuality(int compressQuality) {
|
|
||||||
this.compressQuality = compressQuality;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,127 +0,0 @@
|
|||||||
/*******************************************************************************
|
|
||||||
* Copyright 2011-2014 Sergey Tarasevich
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*******************************************************************************/
|
|
||||||
package com.nostra13.universalimageloader.cache.disc.impl;
|
|
||||||
|
|
||||||
import android.graphics.Bitmap;
|
|
||||||
import com.nostra13.universalimageloader.cache.disc.naming.FileNameGenerator;
|
|
||||||
import com.nostra13.universalimageloader.core.DefaultConfigurationFactory;
|
|
||||||
import com.nostra13.universalimageloader.utils.IoUtils;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Cache which deletes files which were loaded more than defined time. Cache size is unlimited.
|
|
||||||
*
|
|
||||||
* @author Sergey Tarasevich (nostra13[at]gmail[dot]com)
|
|
||||||
* @since 1.3.1
|
|
||||||
*/
|
|
||||||
public class LimitedAgeDiskCache extends BaseDiskCache {
|
|
||||||
|
|
||||||
private final long maxFileAge;
|
|
||||||
|
|
||||||
private final Map<File, Long> loadingDates = Collections.synchronizedMap(new HashMap<File, Long>());
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param cacheDir Directory for file caching
|
|
||||||
* @param maxAge Max file age (in seconds). If file age will exceed this value then it'll be removed on next
|
|
||||||
* treatment (and therefore be reloaded).
|
|
||||||
*/
|
|
||||||
public LimitedAgeDiskCache(File cacheDir, long maxAge) {
|
|
||||||
this(cacheDir, null, DefaultConfigurationFactory.createFileNameGenerator(), maxAge);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param cacheDir Directory for file caching
|
|
||||||
* @param maxAge Max file age (in seconds). If file age will exceed this value then it'll be removed on next
|
|
||||||
* treatment (and therefore be reloaded).
|
|
||||||
*/
|
|
||||||
public LimitedAgeDiskCache(File cacheDir, File reserveCacheDir, long maxAge) {
|
|
||||||
this(cacheDir, reserveCacheDir, DefaultConfigurationFactory.createFileNameGenerator(), maxAge);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param cacheDir Directory for file caching
|
|
||||||
* @param reserveCacheDir null-ok; Reserve directory for file caching. It's used when the primary directory isn't available.
|
|
||||||
* @param fileNameGenerator Name generator for cached files
|
|
||||||
* @param maxAge Max file age (in seconds). If file age will exceed this value then it'll be removed on next
|
|
||||||
* treatment (and therefore be reloaded).
|
|
||||||
*/
|
|
||||||
public LimitedAgeDiskCache(File cacheDir, File reserveCacheDir, FileNameGenerator fileNameGenerator, long maxAge) {
|
|
||||||
super(cacheDir, reserveCacheDir, fileNameGenerator);
|
|
||||||
this.maxFileAge = maxAge * 1000; // to milliseconds
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public File get(String imageUri) {
|
|
||||||
File file = super.get(imageUri);
|
|
||||||
if (file != null && file.exists()) {
|
|
||||||
boolean cached;
|
|
||||||
Long loadingDate = loadingDates.get(file);
|
|
||||||
if (loadingDate == null) {
|
|
||||||
cached = false;
|
|
||||||
loadingDate = file.lastModified();
|
|
||||||
} else {
|
|
||||||
cached = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (System.currentTimeMillis() - loadingDate > maxFileAge) {
|
|
||||||
file.delete();
|
|
||||||
loadingDates.remove(file);
|
|
||||||
} else if (!cached) {
|
|
||||||
loadingDates.put(file, loadingDate);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return file;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean save(String imageUri, InputStream imageStream, IoUtils.CopyListener listener) throws IOException {
|
|
||||||
boolean saved = super.save(imageUri, imageStream, listener);
|
|
||||||
rememberUsage(imageUri);
|
|
||||||
return saved;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean save(String imageUri, Bitmap bitmap) throws IOException {
|
|
||||||
boolean saved = super.save(imageUri, bitmap);
|
|
||||||
rememberUsage(imageUri);
|
|
||||||
return saved;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean remove(String imageUri) {
|
|
||||||
loadingDates.remove(getFile(imageUri));
|
|
||||||
return super.remove(imageUri);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void clear() {
|
|
||||||
super.clear();
|
|
||||||
loadingDates.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void rememberUsage(String imageUri) {
|
|
||||||
File file = getFile(imageUri);
|
|
||||||
long currentTime = System.currentTimeMillis();
|
|
||||||
file.setLastModified(currentTime);
|
|
||||||
loadingDates.put(file, currentTime);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,52 +0,0 @@
|
|||||||
/*******************************************************************************
|
|
||||||
* Copyright 2011-2014 Sergey Tarasevich
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*******************************************************************************/
|
|
||||||
package com.nostra13.universalimageloader.cache.disc.impl;
|
|
||||||
|
|
||||||
import com.nostra13.universalimageloader.cache.disc.naming.FileNameGenerator;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Default implementation of {@linkplain com.nostra13.universalimageloader.cache.disc.DiskCache disk cache}.
|
|
||||||
* Cache size is unlimited.
|
|
||||||
*
|
|
||||||
* @author Sergey Tarasevich (nostra13[at]gmail[dot]com)
|
|
||||||
* @since 1.0.0
|
|
||||||
*/
|
|
||||||
public class UnlimitedDiskCache extends BaseDiskCache {
|
|
||||||
/** @param cacheDir Directory for file caching */
|
|
||||||
public UnlimitedDiskCache(File cacheDir) {
|
|
||||||
super(cacheDir);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param cacheDir Directory for file caching
|
|
||||||
* @param reserveCacheDir null-ok; Reserve directory for file caching. It's used when the primary directory isn't available.
|
|
||||||
*/
|
|
||||||
public UnlimitedDiskCache(File cacheDir, File reserveCacheDir) {
|
|
||||||
super(cacheDir, reserveCacheDir);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param cacheDir Directory for file caching
|
|
||||||
* @param reserveCacheDir null-ok; Reserve directory for file caching. It's used when the primary directory isn't available.
|
|
||||||
* @param fileNameGenerator {@linkplain com.nostra13.universalimageloader.cache.disc.naming.FileNameGenerator
|
|
||||||
* Name generator} for cached files
|
|
||||||
*/
|
|
||||||
public UnlimitedDiskCache(File cacheDir, File reserveCacheDir, FileNameGenerator fileNameGenerator) {
|
|
||||||
super(cacheDir, reserveCacheDir, fileNameGenerator);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,974 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2011 The Android Open Source Project
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package com.nostra13.universalimageloader.cache.disc.impl.ext;
|
|
||||||
|
|
||||||
import java.io.BufferedWriter;
|
|
||||||
import java.io.Closeable;
|
|
||||||
import java.io.EOFException;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.FilterOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.io.OutputStreamWriter;
|
|
||||||
import java.io.Writer;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.LinkedHashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.concurrent.Callable;
|
|
||||||
import java.util.concurrent.LinkedBlockingQueue;
|
|
||||||
import java.util.concurrent.ThreadPoolExecutor;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
import java.util.regex.Matcher;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A cache that uses a bounded amount of space on a filesystem. Each cache
|
|
||||||
* entry has a string key and a fixed number of values. Each key must match
|
|
||||||
* the regex <strong>[a-z0-9_-]{1,64}</strong>. Values are byte sequences,
|
|
||||||
* accessible as streams or files. Each value must be between {@code 0} and
|
|
||||||
* {@code Integer.MAX_VALUE} bytes in length.
|
|
||||||
*
|
|
||||||
* <p>The cache stores its data in a directory on the filesystem. This
|
|
||||||
* directory must be exclusive to the cache; the cache may delete or overwrite
|
|
||||||
* files from its directory. It is an error for multiple processes to use the
|
|
||||||
* same cache directory at the same time.
|
|
||||||
*
|
|
||||||
* <p>This cache limits the number of bytes that it will store on the
|
|
||||||
* filesystem. When the number of stored bytes exceeds the limit, the cache will
|
|
||||||
* remove entries in the background until the limit is satisfied. The limit is
|
|
||||||
* not strict: the cache may temporarily exceed it while waiting for files to be
|
|
||||||
* deleted. The limit does not include filesystem overhead or the cache
|
|
||||||
* journal so space-sensitive applications should set a conservative limit.
|
|
||||||
*
|
|
||||||
* <p>Clients call {@link #edit} to create or update the values of an entry. An
|
|
||||||
* entry may have only one editor at one time; if a value is not available to be
|
|
||||||
* edited then {@link #edit} will return null.
|
|
||||||
* <ul>
|
|
||||||
* <li>When an entry is being <strong>created</strong> it is necessary to
|
|
||||||
* supply a full set of values; the empty value should be used as a
|
|
||||||
* placeholder if necessary.
|
|
||||||
* <li>When an entry is being <strong>edited</strong>, it is not necessary
|
|
||||||
* to supply data for every value; values default to their previous
|
|
||||||
* value.
|
|
||||||
* </ul>
|
|
||||||
* Every {@link #edit} call must be matched by a call to {@link Editor#commit}
|
|
||||||
* or {@link Editor#abort}. Committing is atomic: a read observes the full set
|
|
||||||
* of values as they were before or after the commit, but never a mix of values.
|
|
||||||
*
|
|
||||||
* <p>Clients call {@link #get} to read a snapshot of an entry. The read will
|
|
||||||
* observe the value at the time that {@link #get} was called. Updates and
|
|
||||||
* removals after the call do not impact ongoing reads.
|
|
||||||
*
|
|
||||||
* <p>This class is tolerant of some I/O errors. If files are missing from the
|
|
||||||
* filesystem, the corresponding entries will be dropped from the cache. If
|
|
||||||
* an error occurs while writing a cache value, the edit will fail silently.
|
|
||||||
* Callers should handle other problems by catching {@code IOException} and
|
|
||||||
* responding appropriately.
|
|
||||||
*/
|
|
||||||
final class DiskLruCache implements Closeable {
|
|
||||||
static final String JOURNAL_FILE = "journal";
|
|
||||||
static final String JOURNAL_FILE_TEMP = "journal.tmp";
|
|
||||||
static final String JOURNAL_FILE_BACKUP = "journal.bkp";
|
|
||||||
static final String MAGIC = "libcore.io.DiskLruCache";
|
|
||||||
static final String VERSION_1 = "1";
|
|
||||||
static final long ANY_SEQUENCE_NUMBER = -1;
|
|
||||||
static final Pattern LEGAL_KEY_PATTERN = Pattern.compile("[a-z0-9_-]{1,64}");
|
|
||||||
private static final String CLEAN = "CLEAN";
|
|
||||||
private static final String DIRTY = "DIRTY";
|
|
||||||
private static final String REMOVE = "REMOVE";
|
|
||||||
private static final String READ = "READ";
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This cache uses a journal file named "journal". A typical journal file
|
|
||||||
* looks like this:
|
|
||||||
* libcore.io.DiskLruCache
|
|
||||||
* 1
|
|
||||||
* 100
|
|
||||||
* 2
|
|
||||||
*
|
|
||||||
* CLEAN 3400330d1dfc7f3f7f4b8d4d803dfcf6 832 21054
|
|
||||||
* DIRTY 335c4c6028171cfddfbaae1a9c313c52
|
|
||||||
* CLEAN 335c4c6028171cfddfbaae1a9c313c52 3934 2342
|
|
||||||
* REMOVE 335c4c6028171cfddfbaae1a9c313c52
|
|
||||||
* DIRTY 1ab96a171faeeee38496d8b330771a7a
|
|
||||||
* CLEAN 1ab96a171faeeee38496d8b330771a7a 1600 234
|
|
||||||
* READ 335c4c6028171cfddfbaae1a9c313c52
|
|
||||||
* READ 3400330d1dfc7f3f7f4b8d4d803dfcf6
|
|
||||||
*
|
|
||||||
* The first five lines of the journal form its header. They are the
|
|
||||||
* constant string "libcore.io.DiskLruCache", the disk cache's version,
|
|
||||||
* the application's version, the value count, and a blank line.
|
|
||||||
*
|
|
||||||
* Each of the subsequent lines in the file is a record of the state of a
|
|
||||||
* cache entry. Each line contains space-separated values: a state, a key,
|
|
||||||
* and optional state-specific values.
|
|
||||||
* o DIRTY lines track that an entry is actively being created or updated.
|
|
||||||
* Every successful DIRTY action should be followed by a CLEAN or REMOVE
|
|
||||||
* action. DIRTY lines without a matching CLEAN or REMOVE indicate that
|
|
||||||
* temporary files may need to be deleted.
|
|
||||||
* o CLEAN lines track a cache entry that has been successfully published
|
|
||||||
* and may be read. A publish line is followed by the lengths of each of
|
|
||||||
* its values.
|
|
||||||
* o READ lines track accesses for LRU.
|
|
||||||
* o REMOVE lines track entries that have been deleted.
|
|
||||||
*
|
|
||||||
* The journal file is appended to as cache operations occur. The journal may
|
|
||||||
* occasionally be compacted by dropping redundant lines. A temporary file named
|
|
||||||
* "journal.tmp" will be used during compaction; that file should be deleted if
|
|
||||||
* it exists when the cache is opened.
|
|
||||||
*/
|
|
||||||
|
|
||||||
private final File directory;
|
|
||||||
private final File journalFile;
|
|
||||||
private final File journalFileTmp;
|
|
||||||
private final File journalFileBackup;
|
|
||||||
private final int appVersion;
|
|
||||||
private long maxSize;
|
|
||||||
private int maxFileCount;
|
|
||||||
private final int valueCount;
|
|
||||||
private long size = 0;
|
|
||||||
private int fileCount = 0;
|
|
||||||
private Writer journalWriter;
|
|
||||||
private final LinkedHashMap<String, Entry> lruEntries =
|
|
||||||
new LinkedHashMap<String, Entry>(0, 0.75f, true);
|
|
||||||
private int redundantOpCount;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* To differentiate between old and current snapshots, each entry is given
|
|
||||||
* a sequence number each time an edit is committed. A snapshot is stale if
|
|
||||||
* its sequence number is not equal to its entry's sequence number.
|
|
||||||
*/
|
|
||||||
private long nextSequenceNumber = 0;
|
|
||||||
|
|
||||||
/** This cache uses a single background thread to evict entries. */
|
|
||||||
final ThreadPoolExecutor executorService =
|
|
||||||
new ThreadPoolExecutor(0, 1, 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
|
|
||||||
private final Callable<Void> cleanupCallable = new Callable<Void>() {
|
|
||||||
public Void call() throws Exception {
|
|
||||||
synchronized (DiskLruCache.this) {
|
|
||||||
if (journalWriter == null) {
|
|
||||||
return null; // Closed.
|
|
||||||
}
|
|
||||||
trimToSize();
|
|
||||||
trimToFileCount();
|
|
||||||
if (journalRebuildRequired()) {
|
|
||||||
rebuildJournal();
|
|
||||||
redundantOpCount = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
private DiskLruCache(File directory, int appVersion, int valueCount, long maxSize, int maxFileCount) {
|
|
||||||
this.directory = directory;
|
|
||||||
this.appVersion = appVersion;
|
|
||||||
this.journalFile = new File(directory, JOURNAL_FILE);
|
|
||||||
this.journalFileTmp = new File(directory, JOURNAL_FILE_TEMP);
|
|
||||||
this.journalFileBackup = new File(directory, JOURNAL_FILE_BACKUP);
|
|
||||||
this.valueCount = valueCount;
|
|
||||||
this.maxSize = maxSize;
|
|
||||||
this.maxFileCount = maxFileCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Opens the cache in {@code directory}, creating a cache if none exists
|
|
||||||
* there.
|
|
||||||
*
|
|
||||||
* @param directory a writable directory
|
|
||||||
* @param valueCount the number of values per cache entry. Must be positive.
|
|
||||||
* @param maxSize the maximum number of bytes this cache should use to store
|
|
||||||
* @param maxFileCount the maximum file count this cache should store
|
|
||||||
* @throws IOException if reading or writing the cache directory fails
|
|
||||||
*/
|
|
||||||
public static DiskLruCache open(File directory, int appVersion, int valueCount, long maxSize, int maxFileCount)
|
|
||||||
throws IOException {
|
|
||||||
if (maxSize <= 0) {
|
|
||||||
throw new IllegalArgumentException("maxSize <= 0");
|
|
||||||
}
|
|
||||||
if (maxFileCount <= 0) {
|
|
||||||
throw new IllegalArgumentException("maxFileCount <= 0");
|
|
||||||
}
|
|
||||||
if (valueCount <= 0) {
|
|
||||||
throw new IllegalArgumentException("valueCount <= 0");
|
|
||||||
}
|
|
||||||
|
|
||||||
// If a bkp file exists, use it instead.
|
|
||||||
File backupFile = new File(directory, JOURNAL_FILE_BACKUP);
|
|
||||||
if (backupFile.exists()) {
|
|
||||||
File journalFile = new File(directory, JOURNAL_FILE);
|
|
||||||
// If journal file also exists just delete backup file.
|
|
||||||
if (journalFile.exists()) {
|
|
||||||
backupFile.delete();
|
|
||||||
} else {
|
|
||||||
renameTo(backupFile, journalFile, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prefer to pick up where we left off.
|
|
||||||
DiskLruCache cache = new DiskLruCache(directory, appVersion, valueCount, maxSize, maxFileCount);
|
|
||||||
if (cache.journalFile.exists()) {
|
|
||||||
try {
|
|
||||||
cache.readJournal();
|
|
||||||
cache.processJournal();
|
|
||||||
cache.journalWriter = new BufferedWriter(
|
|
||||||
new OutputStreamWriter(new FileOutputStream(cache.journalFile, true), Util.US_ASCII));
|
|
||||||
return cache;
|
|
||||||
} catch (IOException journalIsCorrupt) {
|
|
||||||
System.out
|
|
||||||
.println("DiskLruCache "
|
|
||||||
+ directory
|
|
||||||
+ " is corrupt: "
|
|
||||||
+ journalIsCorrupt.getMessage()
|
|
||||||
+ ", removing");
|
|
||||||
cache.delete();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a new empty cache.
|
|
||||||
directory.mkdirs();
|
|
||||||
cache = new DiskLruCache(directory, appVersion, valueCount, maxSize, maxFileCount);
|
|
||||||
cache.rebuildJournal();
|
|
||||||
return cache;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void readJournal() throws IOException {
|
|
||||||
StrictLineReader reader = new StrictLineReader(new FileInputStream(journalFile), Util.US_ASCII);
|
|
||||||
try {
|
|
||||||
String magic = reader.readLine();
|
|
||||||
String version = reader.readLine();
|
|
||||||
String appVersionString = reader.readLine();
|
|
||||||
String valueCountString = reader.readLine();
|
|
||||||
String blank = reader.readLine();
|
|
||||||
if (!MAGIC.equals(magic)
|
|
||||||
|| !VERSION_1.equals(version)
|
|
||||||
|| !Integer.toString(appVersion).equals(appVersionString)
|
|
||||||
|| !Integer.toString(valueCount).equals(valueCountString)
|
|
||||||
|| !"".equals(blank)) {
|
|
||||||
throw new IOException("unexpected journal header: [" + magic + ", " + version + ", "
|
|
||||||
+ valueCountString + ", " + blank + "]");
|
|
||||||
}
|
|
||||||
|
|
||||||
int lineCount = 0;
|
|
||||||
while (true) {
|
|
||||||
try {
|
|
||||||
readJournalLine(reader.readLine());
|
|
||||||
lineCount++;
|
|
||||||
} catch (EOFException endOfJournal) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
redundantOpCount = lineCount - lruEntries.size();
|
|
||||||
} finally {
|
|
||||||
Util.closeQuietly(reader);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void readJournalLine(String line) throws IOException {
|
|
||||||
int firstSpace = line.indexOf(' ');
|
|
||||||
if (firstSpace == -1) {
|
|
||||||
throw new IOException("unexpected journal line: " + line);
|
|
||||||
}
|
|
||||||
|
|
||||||
int keyBegin = firstSpace + 1;
|
|
||||||
int secondSpace = line.indexOf(' ', keyBegin);
|
|
||||||
final String key;
|
|
||||||
if (secondSpace == -1) {
|
|
||||||
key = line.substring(keyBegin);
|
|
||||||
if (firstSpace == REMOVE.length() && line.startsWith(REMOVE)) {
|
|
||||||
lruEntries.remove(key);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
key = line.substring(keyBegin, secondSpace);
|
|
||||||
}
|
|
||||||
|
|
||||||
Entry entry = lruEntries.get(key);
|
|
||||||
if (entry == null) {
|
|
||||||
entry = new Entry(key);
|
|
||||||
lruEntries.put(key, entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (secondSpace != -1 && firstSpace == CLEAN.length() && line.startsWith(CLEAN)) {
|
|
||||||
String[] parts = line.substring(secondSpace + 1).split(" ");
|
|
||||||
entry.readable = true;
|
|
||||||
entry.currentEditor = null;
|
|
||||||
entry.setLengths(parts);
|
|
||||||
} else if (secondSpace == -1 && firstSpace == DIRTY.length() && line.startsWith(DIRTY)) {
|
|
||||||
entry.currentEditor = new Editor(entry);
|
|
||||||
} else if (secondSpace == -1 && firstSpace == READ.length() && line.startsWith(READ)) {
|
|
||||||
// This work was already done by calling lruEntries.get().
|
|
||||||
} else {
|
|
||||||
throw new IOException("unexpected journal line: " + line);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Computes the initial size and collects garbage as a part of opening the
|
|
||||||
* cache. Dirty entries are assumed to be inconsistent and will be deleted.
|
|
||||||
*/
|
|
||||||
private void processJournal() throws IOException {
|
|
||||||
deleteIfExists(journalFileTmp);
|
|
||||||
for (Iterator<Entry> i = lruEntries.values().iterator(); i.hasNext(); ) {
|
|
||||||
Entry entry = i.next();
|
|
||||||
if (entry.currentEditor == null) {
|
|
||||||
for (int t = 0; t < valueCount; t++) {
|
|
||||||
size += entry.lengths[t];
|
|
||||||
fileCount++;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
entry.currentEditor = null;
|
|
||||||
for (int t = 0; t < valueCount; t++) {
|
|
||||||
deleteIfExists(entry.getCleanFile(t));
|
|
||||||
deleteIfExists(entry.getDirtyFile(t));
|
|
||||||
}
|
|
||||||
i.remove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new journal that omits redundant information. This replaces the
|
|
||||||
* current journal if it exists.
|
|
||||||
*/
|
|
||||||
private synchronized void rebuildJournal() throws IOException {
|
|
||||||
if (journalWriter != null) {
|
|
||||||
journalWriter.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
Writer writer = new BufferedWriter(
|
|
||||||
new OutputStreamWriter(new FileOutputStream(journalFileTmp), Util.US_ASCII));
|
|
||||||
try {
|
|
||||||
writer.write(MAGIC);
|
|
||||||
writer.write("\n");
|
|
||||||
writer.write(VERSION_1);
|
|
||||||
writer.write("\n");
|
|
||||||
writer.write(Integer.toString(appVersion));
|
|
||||||
writer.write("\n");
|
|
||||||
writer.write(Integer.toString(valueCount));
|
|
||||||
writer.write("\n");
|
|
||||||
writer.write("\n");
|
|
||||||
|
|
||||||
for (Entry entry : lruEntries.values()) {
|
|
||||||
if (entry.currentEditor != null) {
|
|
||||||
writer.write(DIRTY + ' ' + entry.key + '\n');
|
|
||||||
} else {
|
|
||||||
writer.write(CLEAN + ' ' + entry.key + entry.getLengths() + '\n');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
writer.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (journalFile.exists()) {
|
|
||||||
renameTo(journalFile, journalFileBackup, true);
|
|
||||||
}
|
|
||||||
renameTo(journalFileTmp, journalFile, false);
|
|
||||||
journalFileBackup.delete();
|
|
||||||
|
|
||||||
journalWriter = new BufferedWriter(
|
|
||||||
new OutputStreamWriter(new FileOutputStream(journalFile, true), Util.US_ASCII));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void deleteIfExists(File file) throws IOException {
|
|
||||||
if (file.exists() && !file.delete()) {
|
|
||||||
throw new IOException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void renameTo(File from, File to, boolean deleteDestination) throws IOException {
|
|
||||||
if (deleteDestination) {
|
|
||||||
deleteIfExists(to);
|
|
||||||
}
|
|
||||||
if (!from.renameTo(to)) {
|
|
||||||
throw new IOException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a snapshot of the entry named {@code key}, or null if it doesn't
|
|
||||||
* exist is not currently readable. If a value is returned, it is moved to
|
|
||||||
* the head of the LRU queue.
|
|
||||||
*/
|
|
||||||
public synchronized Snapshot get(String key) throws IOException {
|
|
||||||
checkNotClosed();
|
|
||||||
validateKey(key);
|
|
||||||
Entry entry = lruEntries.get(key);
|
|
||||||
if (entry == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!entry.readable) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Open all streams eagerly to guarantee that we see a single published
|
|
||||||
// snapshot. If we opened streams lazily then the streams could come
|
|
||||||
// from different edits.
|
|
||||||
File[] files = new File[valueCount];
|
|
||||||
InputStream[] ins = new InputStream[valueCount];
|
|
||||||
try {
|
|
||||||
File file;
|
|
||||||
for (int i = 0; i < valueCount; i++) {
|
|
||||||
file = entry.getCleanFile(i);
|
|
||||||
files[i] = file;
|
|
||||||
ins[i] = new FileInputStream(file);
|
|
||||||
}
|
|
||||||
} catch (FileNotFoundException e) {
|
|
||||||
// A file must have been deleted manually!
|
|
||||||
for (int i = 0; i < valueCount; i++) {
|
|
||||||
if (ins[i] != null) {
|
|
||||||
Util.closeQuietly(ins[i]);
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
redundantOpCount++;
|
|
||||||
journalWriter.append(READ + ' ' + key + '\n');
|
|
||||||
if (journalRebuildRequired()) {
|
|
||||||
executorService.submit(cleanupCallable);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Snapshot(key, entry.sequenceNumber, files, ins, entry.lengths);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an editor for the entry named {@code key}, or null if another
|
|
||||||
* edit is in progress.
|
|
||||||
*/
|
|
||||||
public Editor edit(String key) throws IOException {
|
|
||||||
return edit(key, ANY_SEQUENCE_NUMBER);
|
|
||||||
}
|
|
||||||
|
|
||||||
private synchronized Editor edit(String key, long expectedSequenceNumber) throws IOException {
|
|
||||||
checkNotClosed();
|
|
||||||
validateKey(key);
|
|
||||||
Entry entry = lruEntries.get(key);
|
|
||||||
if (expectedSequenceNumber != ANY_SEQUENCE_NUMBER && (entry == null
|
|
||||||
|| entry.sequenceNumber != expectedSequenceNumber)) {
|
|
||||||
return null; // Snapshot is stale.
|
|
||||||
}
|
|
||||||
if (entry == null) {
|
|
||||||
entry = new Entry(key);
|
|
||||||
lruEntries.put(key, entry);
|
|
||||||
} else if (entry.currentEditor != null) {
|
|
||||||
return null; // Another edit is in progress.
|
|
||||||
}
|
|
||||||
|
|
||||||
Editor editor = new Editor(entry);
|
|
||||||
entry.currentEditor = editor;
|
|
||||||
|
|
||||||
// Flush the journal before creating files to prevent file leaks.
|
|
||||||
journalWriter.write(DIRTY + ' ' + key + '\n');
|
|
||||||
journalWriter.flush();
|
|
||||||
return editor;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Returns the directory where this cache stores its data. */
|
|
||||||
public File getDirectory() {
|
|
||||||
return directory;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the maximum number of bytes that this cache should use to store
|
|
||||||
* its data.
|
|
||||||
*/
|
|
||||||
public synchronized long getMaxSize() {
|
|
||||||
return maxSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Returns the maximum number of files that this cache should store */
|
|
||||||
public synchronized int getMaxFileCount() {
|
|
||||||
return maxFileCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Changes the maximum number of bytes the cache can store and queues a job
|
|
||||||
* to trim the existing store, if necessary.
|
|
||||||
*/
|
|
||||||
public synchronized void setMaxSize(long maxSize) {
|
|
||||||
this.maxSize = maxSize;
|
|
||||||
executorService.submit(cleanupCallable);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the number of bytes currently being used to store the values in
|
|
||||||
* this cache. This may be greater than the max size if a background
|
|
||||||
* deletion is pending.
|
|
||||||
*/
|
|
||||||
public synchronized long size() {
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the number of files currently being used to store the values in
|
|
||||||
* this cache. This may be greater than the max file count if a background
|
|
||||||
* deletion is pending.
|
|
||||||
*/
|
|
||||||
public synchronized long fileCount() {
|
|
||||||
return fileCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
private synchronized void completeEdit(Editor editor, boolean success) throws IOException {
|
|
||||||
Entry entry = editor.entry;
|
|
||||||
if (entry.currentEditor != editor) {
|
|
||||||
throw new IllegalStateException();
|
|
||||||
}
|
|
||||||
|
|
||||||
// If this edit is creating the entry for the first time, every index must have a value.
|
|
||||||
if (success && !entry.readable) {
|
|
||||||
for (int i = 0; i < valueCount; i++) {
|
|
||||||
if (!editor.written[i]) {
|
|
||||||
editor.abort();
|
|
||||||
throw new IllegalStateException("Newly created entry didn't create value for index " + i);
|
|
||||||
}
|
|
||||||
if (!entry.getDirtyFile(i).exists()) {
|
|
||||||
editor.abort();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < valueCount; i++) {
|
|
||||||
File dirty = entry.getDirtyFile(i);
|
|
||||||
if (success) {
|
|
||||||
if (dirty.exists()) {
|
|
||||||
File clean = entry.getCleanFile(i);
|
|
||||||
dirty.renameTo(clean);
|
|
||||||
long oldLength = entry.lengths[i];
|
|
||||||
long newLength = clean.length();
|
|
||||||
entry.lengths[i] = newLength;
|
|
||||||
size = size - oldLength + newLength;
|
|
||||||
fileCount++;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
deleteIfExists(dirty);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
redundantOpCount++;
|
|
||||||
entry.currentEditor = null;
|
|
||||||
if (entry.readable | success) {
|
|
||||||
entry.readable = true;
|
|
||||||
journalWriter.write(CLEAN + ' ' + entry.key + entry.getLengths() + '\n');
|
|
||||||
if (success) {
|
|
||||||
entry.sequenceNumber = nextSequenceNumber++;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
lruEntries.remove(entry.key);
|
|
||||||
journalWriter.write(REMOVE + ' ' + entry.key + '\n');
|
|
||||||
}
|
|
||||||
journalWriter.flush();
|
|
||||||
|
|
||||||
if (size > maxSize || fileCount > maxFileCount || journalRebuildRequired()) {
|
|
||||||
executorService.submit(cleanupCallable);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* We only rebuild the journal when it will halve the size of the journal
|
|
||||||
* and eliminate at least 2000 ops.
|
|
||||||
*/
|
|
||||||
private boolean journalRebuildRequired() {
|
|
||||||
final int redundantOpCompactThreshold = 2000;
|
|
||||||
return redundantOpCount >= redundantOpCompactThreshold //
|
|
||||||
&& redundantOpCount >= lruEntries.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Drops the entry for {@code key} if it exists and can be removed. Entries
|
|
||||||
* actively being edited cannot be removed.
|
|
||||||
*
|
|
||||||
* @return true if an entry was removed.
|
|
||||||
*/
|
|
||||||
public synchronized boolean remove(String key) throws IOException {
|
|
||||||
checkNotClosed();
|
|
||||||
validateKey(key);
|
|
||||||
Entry entry = lruEntries.get(key);
|
|
||||||
if (entry == null || entry.currentEditor != null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < valueCount; i++) {
|
|
||||||
File file = entry.getCleanFile(i);
|
|
||||||
if (file.exists() && !file.delete()) {
|
|
||||||
throw new IOException("failed to delete " + file);
|
|
||||||
}
|
|
||||||
size -= entry.lengths[i];
|
|
||||||
fileCount--;
|
|
||||||
entry.lengths[i] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
redundantOpCount++;
|
|
||||||
journalWriter.append(REMOVE + ' ' + key + '\n');
|
|
||||||
lruEntries.remove(key);
|
|
||||||
|
|
||||||
if (journalRebuildRequired()) {
|
|
||||||
executorService.submit(cleanupCallable);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Returns true if this cache has been closed. */
|
|
||||||
public synchronized boolean isClosed() {
|
|
||||||
return journalWriter == null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void checkNotClosed() {
|
|
||||||
if (journalWriter == null) {
|
|
||||||
throw new IllegalStateException("cache is closed");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Force buffered operations to the filesystem. */
|
|
||||||
public synchronized void flush() throws IOException {
|
|
||||||
checkNotClosed();
|
|
||||||
trimToSize();
|
|
||||||
trimToFileCount();
|
|
||||||
journalWriter.flush();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Closes this cache. Stored values will remain on the filesystem. */
|
|
||||||
public synchronized void close() throws IOException {
|
|
||||||
if (journalWriter == null) {
|
|
||||||
return; // Already closed.
|
|
||||||
}
|
|
||||||
for (Entry entry : new ArrayList<Entry>(lruEntries.values())) {
|
|
||||||
if (entry.currentEditor != null) {
|
|
||||||
entry.currentEditor.abort();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
trimToSize();
|
|
||||||
trimToFileCount();
|
|
||||||
journalWriter.close();
|
|
||||||
journalWriter = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void trimToSize() throws IOException {
|
|
||||||
while (size > maxSize) {
|
|
||||||
Map.Entry<String, Entry> toEvict = lruEntries.entrySet().iterator().next();
|
|
||||||
remove(toEvict.getKey());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void trimToFileCount() throws IOException {
|
|
||||||
while (fileCount > maxFileCount) {
|
|
||||||
Map.Entry<String, Entry> toEvict = lruEntries.entrySet().iterator().next();
|
|
||||||
remove(toEvict.getKey());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Closes the cache and deletes all of its stored values. This will delete
|
|
||||||
* all files in the cache directory including files that weren't created by
|
|
||||||
* the cache.
|
|
||||||
*/
|
|
||||||
public void delete() throws IOException {
|
|
||||||
close();
|
|
||||||
Util.deleteContents(directory);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void validateKey(String key) {
|
|
||||||
Matcher matcher = LEGAL_KEY_PATTERN.matcher(key);
|
|
||||||
if (!matcher.matches()) {
|
|
||||||
throw new IllegalArgumentException("keys must match regex [a-z0-9_-]{1,64}: \"" + key + "\"");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String inputStreamToString(InputStream in) throws IOException {
|
|
||||||
return Util.readFully(new InputStreamReader(in, Util.UTF_8));
|
|
||||||
}
|
|
||||||
|
|
||||||
/** A snapshot of the values for an entry. */
|
|
||||||
public final class Snapshot implements Closeable {
|
|
||||||
private final String key;
|
|
||||||
private final long sequenceNumber;
|
|
||||||
private File[] files;
|
|
||||||
private final InputStream[] ins;
|
|
||||||
private final long[] lengths;
|
|
||||||
|
|
||||||
private Snapshot(String key, long sequenceNumber, File[] files, InputStream[] ins, long[] lengths) {
|
|
||||||
this.key = key;
|
|
||||||
this.sequenceNumber = sequenceNumber;
|
|
||||||
this.files = files;
|
|
||||||
this.ins = ins;
|
|
||||||
this.lengths = lengths;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an editor for this snapshot's entry, or null if either the
|
|
||||||
* entry has changed since this snapshot was created or if another edit
|
|
||||||
* is in progress.
|
|
||||||
*/
|
|
||||||
public Editor edit() throws IOException {
|
|
||||||
return DiskLruCache.this.edit(key, sequenceNumber);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Returns file with the value for {@code index}. */
|
|
||||||
public File getFile(int index) {
|
|
||||||
return files[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Returns the unbuffered stream with the value for {@code index}. */
|
|
||||||
public InputStream getInputStream(int index) {
|
|
||||||
return ins[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Returns the string value for {@code index}. */
|
|
||||||
public String getString(int index) throws IOException {
|
|
||||||
return inputStreamToString(getInputStream(index));
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Returns the byte length of the value for {@code index}. */
|
|
||||||
public long getLength(int index) {
|
|
||||||
return lengths[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
public void close() {
|
|
||||||
for (InputStream in : ins) {
|
|
||||||
Util.closeQuietly(in);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final OutputStream NULL_OUTPUT_STREAM = new OutputStream() {
|
|
||||||
@Override
|
|
||||||
public void write(int b) throws IOException {
|
|
||||||
// Eat all writes silently. Nom nom.
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/** Edits the values for an entry. */
|
|
||||||
public final class Editor {
|
|
||||||
private final Entry entry;
|
|
||||||
private final boolean[] written;
|
|
||||||
private boolean hasErrors;
|
|
||||||
private boolean committed;
|
|
||||||
|
|
||||||
private Editor(Entry entry) {
|
|
||||||
this.entry = entry;
|
|
||||||
this.written = (entry.readable) ? null : new boolean[valueCount];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an unbuffered input stream to read the last committed value,
|
|
||||||
* or null if no value has been committed.
|
|
||||||
*/
|
|
||||||
public InputStream newInputStream(int index) throws IOException {
|
|
||||||
synchronized (DiskLruCache.this) {
|
|
||||||
if (entry.currentEditor != this) {
|
|
||||||
throw new IllegalStateException();
|
|
||||||
}
|
|
||||||
if (!entry.readable) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
return new FileInputStream(entry.getCleanFile(index));
|
|
||||||
} catch (FileNotFoundException e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the last committed value as a string, or null if no value
|
|
||||||
* has been committed.
|
|
||||||
*/
|
|
||||||
public String getString(int index) throws IOException {
|
|
||||||
InputStream in = newInputStream(index);
|
|
||||||
return in != null ? inputStreamToString(in) : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a new unbuffered output stream to write the value at
|
|
||||||
* {@code index}. If the underlying output stream encounters errors
|
|
||||||
* when writing to the filesystem, this edit will be aborted when
|
|
||||||
* {@link #commit} is called. The returned output stream does not throw
|
|
||||||
* IOExceptions.
|
|
||||||
*/
|
|
||||||
public OutputStream newOutputStream(int index) throws IOException {
|
|
||||||
synchronized (DiskLruCache.this) {
|
|
||||||
if (entry.currentEditor != this) {
|
|
||||||
throw new IllegalStateException();
|
|
||||||
}
|
|
||||||
if (!entry.readable) {
|
|
||||||
written[index] = true;
|
|
||||||
}
|
|
||||||
File dirtyFile = entry.getDirtyFile(index);
|
|
||||||
FileOutputStream outputStream;
|
|
||||||
try {
|
|
||||||
outputStream = new FileOutputStream(dirtyFile);
|
|
||||||
} catch (FileNotFoundException e) {
|
|
||||||
// Attempt to recreate the cache directory.
|
|
||||||
directory.mkdirs();
|
|
||||||
try {
|
|
||||||
outputStream = new FileOutputStream(dirtyFile);
|
|
||||||
} catch (FileNotFoundException e2) {
|
|
||||||
// We are unable to recover. Silently eat the writes.
|
|
||||||
return NULL_OUTPUT_STREAM;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return new FaultHidingOutputStream(outputStream);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Sets the value at {@code index} to {@code value}. */
|
|
||||||
public void set(int index, String value) throws IOException {
|
|
||||||
Writer writer = null;
|
|
||||||
try {
|
|
||||||
writer = new OutputStreamWriter(newOutputStream(index), Util.UTF_8);
|
|
||||||
writer.write(value);
|
|
||||||
} finally {
|
|
||||||
Util.closeQuietly(writer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Commits this edit so it is visible to readers. This releases the
|
|
||||||
* edit lock so another edit may be started on the same key.
|
|
||||||
*/
|
|
||||||
public void commit() throws IOException {
|
|
||||||
if (hasErrors) {
|
|
||||||
completeEdit(this, false);
|
|
||||||
remove(entry.key); // The previous entry is stale.
|
|
||||||
} else {
|
|
||||||
completeEdit(this, true);
|
|
||||||
}
|
|
||||||
committed = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Aborts this edit. This releases the edit lock so another edit may be
|
|
||||||
* started on the same key.
|
|
||||||
*/
|
|
||||||
public void abort() throws IOException {
|
|
||||||
completeEdit(this, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void abortUnlessCommitted() {
|
|
||||||
if (!committed) {
|
|
||||||
try {
|
|
||||||
abort();
|
|
||||||
} catch (IOException ignored) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class FaultHidingOutputStream extends FilterOutputStream {
|
|
||||||
private FaultHidingOutputStream(OutputStream out) {
|
|
||||||
super(out);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public void write(int oneByte) {
|
|
||||||
try {
|
|
||||||
out.write(oneByte);
|
|
||||||
} catch (IOException e) {
|
|
||||||
hasErrors = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public void write(byte[] buffer, int offset, int length) {
|
|
||||||
try {
|
|
||||||
out.write(buffer, offset, length);
|
|
||||||
} catch (IOException e) {
|
|
||||||
hasErrors = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public void close() {
|
|
||||||
try {
|
|
||||||
out.close();
|
|
||||||
} catch (IOException e) {
|
|
||||||
hasErrors = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public void flush() {
|
|
||||||
try {
|
|
||||||
out.flush();
|
|
||||||
} catch (IOException e) {
|
|
||||||
hasErrors = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private final class Entry {
|
|
||||||
private final String key;
|
|
||||||
|
|
||||||
/** Lengths of this entry's files. */
|
|
||||||
private final long[] lengths;
|
|
||||||
|
|
||||||
/** True if this entry has ever been published. */
|
|
||||||
private boolean readable;
|
|
||||||
|
|
||||||
/** The ongoing edit or null if this entry is not being edited. */
|
|
||||||
private Editor currentEditor;
|
|
||||||
|
|
||||||
/** The sequence number of the most recently committed edit to this entry. */
|
|
||||||
private long sequenceNumber;
|
|
||||||
|
|
||||||
private Entry(String key) {
|
|
||||||
this.key = key;
|
|
||||||
this.lengths = new long[valueCount];
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getLengths() throws IOException {
|
|
||||||
StringBuilder result = new StringBuilder();
|
|
||||||
for (long size : lengths) {
|
|
||||||
result.append(' ').append(size);
|
|
||||||
}
|
|
||||||
return result.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Set lengths using decimal numbers like "10123". */
|
|
||||||
private void setLengths(String[] strings) throws IOException {
|
|
||||||
if (strings.length != valueCount) {
|
|
||||||
throw invalidLengths(strings);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
for (int i = 0; i < strings.length; i++) {
|
|
||||||
lengths[i] = Long.parseLong(strings[i]);
|
|
||||||
}
|
|
||||||
} catch (NumberFormatException e) {
|
|
||||||
throw invalidLengths(strings);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private IOException invalidLengths(String[] strings) throws IOException {
|
|
||||||
throw new IOException("unexpected journal line: " + java.util.Arrays.toString(strings));
|
|
||||||
}
|
|
||||||
|
|
||||||
public File getCleanFile(int i) {
|
|
||||||
return new File(directory, key + "." + i);
|
|
||||||
}
|
|
||||||
|
|
||||||
public File getDirtyFile(int i) {
|
|
||||||
return new File(directory, key + "." + i + ".tmp");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,238 +0,0 @@
|
|||||||
/*******************************************************************************
|
|
||||||
* Copyright 2014 Sergey Tarasevich
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*******************************************************************************/
|
|
||||||
package com.nostra13.universalimageloader.cache.disc.impl.ext;
|
|
||||||
|
|
||||||
import android.graphics.Bitmap;
|
|
||||||
import com.nostra13.universalimageloader.cache.disc.DiskCache;
|
|
||||||
import com.nostra13.universalimageloader.cache.disc.naming.FileNameGenerator;
|
|
||||||
import com.nostra13.universalimageloader.utils.IoUtils;
|
|
||||||
import com.nostra13.universalimageloader.utils.L;
|
|
||||||
|
|
||||||
import java.io.BufferedOutputStream;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Disk cache based on "Least-Recently Used" principle. Adapter pattern, adapts
|
|
||||||
* {@link com.nostra13.universalimageloader.cache.disc.impl.ext.DiskLruCache DiskLruCache} to
|
|
||||||
* {@link com.nostra13.universalimageloader.cache.disc.DiskCache DiskCache}
|
|
||||||
*
|
|
||||||
* @author Sergey Tarasevich (nostra13[at]gmail[dot]com)
|
|
||||||
* @see FileNameGenerator
|
|
||||||
* @since 1.9.2
|
|
||||||
*/
|
|
||||||
public class LruDiskCache implements DiskCache {
|
|
||||||
/** {@value */
|
|
||||||
public static final int DEFAULT_BUFFER_SIZE = 32 * 1024; // 32 Kb
|
|
||||||
/** {@value */
|
|
||||||
public static final Bitmap.CompressFormat DEFAULT_COMPRESS_FORMAT = Bitmap.CompressFormat.PNG;
|
|
||||||
/** {@value */
|
|
||||||
public static final int DEFAULT_COMPRESS_QUALITY = 100;
|
|
||||||
|
|
||||||
private static final String ERROR_ARG_NULL = " argument must be not null";
|
|
||||||
private static final String ERROR_ARG_NEGATIVE = " argument must be positive number";
|
|
||||||
|
|
||||||
protected DiskLruCache cache;
|
|
||||||
private File reserveCacheDir;
|
|
||||||
|
|
||||||
protected final FileNameGenerator fileNameGenerator;
|
|
||||||
|
|
||||||
protected int bufferSize = DEFAULT_BUFFER_SIZE;
|
|
||||||
|
|
||||||
protected Bitmap.CompressFormat compressFormat = DEFAULT_COMPRESS_FORMAT;
|
|
||||||
protected int compressQuality = DEFAULT_COMPRESS_QUALITY;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param cacheDir Directory for file caching
|
|
||||||
* @param fileNameGenerator {@linkplain com.nostra13.universalimageloader.cache.disc.naming.FileNameGenerator
|
|
||||||
* Name generator} for cached files. Generated names must match the regex
|
|
||||||
* <strong>[a-z0-9_-]{1,64}</strong>
|
|
||||||
* @param cacheMaxSize Max cache size in bytes. <b>0</b> means cache size is unlimited.
|
|
||||||
* @throws IOException if cache can't be initialized (e.g. "No space left on device")
|
|
||||||
*/
|
|
||||||
public LruDiskCache(File cacheDir, FileNameGenerator fileNameGenerator, long cacheMaxSize) throws IOException {
|
|
||||||
this(cacheDir, null, fileNameGenerator, cacheMaxSize, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param cacheDir Directory for file caching
|
|
||||||
* @param reserveCacheDir null-ok; Reserve directory for file caching. It's used when the primary directory isn't available.
|
|
||||||
* @param fileNameGenerator {@linkplain com.nostra13.universalimageloader.cache.disc.naming.FileNameGenerator
|
|
||||||
* Name generator} for cached files. Generated names must match the regex
|
|
||||||
* <strong>[a-z0-9_-]{1,64}</strong>
|
|
||||||
* @param cacheMaxSize Max cache size in bytes. <b>0</b> means cache size is unlimited.
|
|
||||||
* @param cacheMaxFileCount Max file count in cache. <b>0</b> means file count is unlimited.
|
|
||||||
* @throws IOException if cache can't be initialized (e.g. "No space left on device")
|
|
||||||
*/
|
|
||||||
public LruDiskCache(File cacheDir, File reserveCacheDir, FileNameGenerator fileNameGenerator, long cacheMaxSize,
|
|
||||||
int cacheMaxFileCount) throws IOException {
|
|
||||||
if (cacheDir == null) {
|
|
||||||
throw new IllegalArgumentException("cacheDir" + ERROR_ARG_NULL);
|
|
||||||
}
|
|
||||||
if (cacheMaxSize < 0) {
|
|
||||||
throw new IllegalArgumentException("cacheMaxSize" + ERROR_ARG_NEGATIVE);
|
|
||||||
}
|
|
||||||
if (cacheMaxFileCount < 0) {
|
|
||||||
throw new IllegalArgumentException("cacheMaxFileCount" + ERROR_ARG_NEGATIVE);
|
|
||||||
}
|
|
||||||
if (fileNameGenerator == null) {
|
|
||||||
throw new IllegalArgumentException("fileNameGenerator" + ERROR_ARG_NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cacheMaxSize == 0) {
|
|
||||||
cacheMaxSize = Long.MAX_VALUE;
|
|
||||||
}
|
|
||||||
if (cacheMaxFileCount == 0) {
|
|
||||||
cacheMaxFileCount = Integer.MAX_VALUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.reserveCacheDir = reserveCacheDir;
|
|
||||||
this.fileNameGenerator = fileNameGenerator;
|
|
||||||
initCache(cacheDir, reserveCacheDir, cacheMaxSize, cacheMaxFileCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initCache(File cacheDir, File reserveCacheDir, long cacheMaxSize, int cacheMaxFileCount)
|
|
||||||
throws IOException {
|
|
||||||
try {
|
|
||||||
cache = DiskLruCache.open(cacheDir, 1, 1, cacheMaxSize, cacheMaxFileCount);
|
|
||||||
} catch (IOException e) {
|
|
||||||
L.e(e);
|
|
||||||
if (reserveCacheDir != null) {
|
|
||||||
initCache(reserveCacheDir, null, cacheMaxSize, cacheMaxFileCount);
|
|
||||||
}
|
|
||||||
if (cache == null) {
|
|
||||||
throw e; //new RuntimeException("Can't initialize disk cache", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public File getDirectory() {
|
|
||||||
return cache.getDirectory();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public File get(String imageUri) {
|
|
||||||
DiskLruCache.Snapshot snapshot = null;
|
|
||||||
try {
|
|
||||||
snapshot = cache.get(getKey(imageUri));
|
|
||||||
return snapshot == null ? null : snapshot.getFile(0);
|
|
||||||
} catch (IOException e) {
|
|
||||||
L.e(e);
|
|
||||||
return null;
|
|
||||||
} finally {
|
|
||||||
if (snapshot != null) {
|
|
||||||
snapshot.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean save(String imageUri, InputStream imageStream, IoUtils.CopyListener listener) throws IOException {
|
|
||||||
DiskLruCache.Editor editor = cache.edit(getKey(imageUri));
|
|
||||||
if (editor == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
OutputStream os = new BufferedOutputStream(editor.newOutputStream(0), bufferSize);
|
|
||||||
boolean copied = false;
|
|
||||||
try {
|
|
||||||
copied = IoUtils.copyStream(imageStream, os, listener, bufferSize);
|
|
||||||
} finally {
|
|
||||||
IoUtils.closeSilently(os);
|
|
||||||
if (copied) {
|
|
||||||
editor.commit();
|
|
||||||
} else {
|
|
||||||
editor.abort();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return copied;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean save(String imageUri, Bitmap bitmap) throws IOException {
|
|
||||||
DiskLruCache.Editor editor = cache.edit(getKey(imageUri));
|
|
||||||
if (editor == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
OutputStream os = new BufferedOutputStream(editor.newOutputStream(0), bufferSize);
|
|
||||||
boolean savedSuccessfully = false;
|
|
||||||
try {
|
|
||||||
savedSuccessfully = bitmap.compress(compressFormat, compressQuality, os);
|
|
||||||
} finally {
|
|
||||||
IoUtils.closeSilently(os);
|
|
||||||
}
|
|
||||||
if (savedSuccessfully) {
|
|
||||||
editor.commit();
|
|
||||||
} else {
|
|
||||||
editor.abort();
|
|
||||||
}
|
|
||||||
return savedSuccessfully;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean remove(String imageUri) {
|
|
||||||
try {
|
|
||||||
return cache.remove(getKey(imageUri));
|
|
||||||
} catch (IOException e) {
|
|
||||||
L.e(e);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void close() {
|
|
||||||
try {
|
|
||||||
cache.close();
|
|
||||||
} catch (IOException e) {
|
|
||||||
L.e(e);
|
|
||||||
}
|
|
||||||
cache = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void clear() {
|
|
||||||
try {
|
|
||||||
cache.delete();
|
|
||||||
} catch (IOException e) {
|
|
||||||
L.e(e);
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
initCache(cache.getDirectory(), reserveCacheDir, cache.getMaxSize(), cache.getMaxFileCount());
|
|
||||||
} catch (IOException e) {
|
|
||||||
L.e(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getKey(String imageUri) {
|
|
||||||
return fileNameGenerator.generate(imageUri);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setBufferSize(int bufferSize) {
|
|
||||||
this.bufferSize = bufferSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCompressFormat(Bitmap.CompressFormat compressFormat) {
|
|
||||||
this.compressFormat = compressFormat;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCompressQuality(int compressQuality) {
|
|
||||||
this.compressQuality = compressQuality;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,191 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2012 The Android Open Source Project
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package com.nostra13.universalimageloader.cache.disc.impl.ext;
|
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.Closeable;
|
|
||||||
import java.io.EOFException;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.UnsupportedEncodingException;
|
|
||||||
import java.nio.charset.Charset;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Buffers input from an {@link InputStream} for reading lines.
|
|
||||||
*
|
|
||||||
* <p>This class is used for buffered reading of lines. For purposes of this class, a line ends
|
|
||||||
* with "\n" or "\r\n". End of input is reported by throwing {@code EOFException}. Unterminated
|
|
||||||
* line at end of input is invalid and will be ignored, the caller may use {@code
|
|
||||||
* hasUnterminatedLine()} to detect it after catching the {@code EOFException}.
|
|
||||||
*
|
|
||||||
* <p>This class is intended for reading input that strictly consists of lines, such as line-based
|
|
||||||
* cache entries or cache journal. Unlike the {@link java.io.BufferedReader} which in conjunction
|
|
||||||
* with {@link java.io.InputStreamReader} provides similar functionality, this class uses different
|
|
||||||
* end-of-input reporting and a more restrictive definition of a line.
|
|
||||||
*
|
|
||||||
* <p>This class supports only charsets that encode '\r' and '\n' as a single byte with value 13
|
|
||||||
* and 10, respectively, and the representation of no other character contains these values.
|
|
||||||
* We currently check in constructor that the charset is one of US-ASCII, UTF-8 and ISO-8859-1.
|
|
||||||
* The default charset is US_ASCII.
|
|
||||||
*/
|
|
||||||
class StrictLineReader implements Closeable {
|
|
||||||
private static final byte CR = (byte) '\r';
|
|
||||||
private static final byte LF = (byte) '\n';
|
|
||||||
|
|
||||||
private final InputStream in;
|
|
||||||
private final Charset charset;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Buffered data is stored in {@code buf}. As long as no exception occurs, 0 <= pos <= end
|
|
||||||
* and the data in the range [pos, end) is buffered for reading. At end of input, if there is
|
|
||||||
* an unterminated line, we set end == -1, otherwise end == pos. If the underlying
|
|
||||||
* {@code InputStream} throws an {@code IOException}, end may remain as either pos or -1.
|
|
||||||
*/
|
|
||||||
private byte[] buf;
|
|
||||||
private int pos;
|
|
||||||
private int end;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs a new {@code LineReader} with the specified charset and the default capacity.
|
|
||||||
*
|
|
||||||
* @param in the {@code InputStream} to read data from.
|
|
||||||
* @param charset the charset used to decode data. Only US-ASCII, UTF-8 and ISO-8859-1 are
|
|
||||||
* supported.
|
|
||||||
* @throws NullPointerException if {@code in} or {@code charset} is null.
|
|
||||||
* @throws IllegalArgumentException if the specified charset is not supported.
|
|
||||||
*/
|
|
||||||
public StrictLineReader(InputStream in, Charset charset) {
|
|
||||||
this(in, 8192, charset);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs a new {@code LineReader} with the specified capacity and charset.
|
|
||||||
*
|
|
||||||
* @param in the {@code InputStream} to read data from.
|
|
||||||
* @param capacity the capacity of the buffer.
|
|
||||||
* @param charset the charset used to decode data. Only US-ASCII, UTF-8 and ISO-8859-1 are
|
|
||||||
* supported.
|
|
||||||
* @throws NullPointerException if {@code in} or {@code charset} is null.
|
|
||||||
* @throws IllegalArgumentException if {@code capacity} is negative or zero
|
|
||||||
* or the specified charset is not supported.
|
|
||||||
*/
|
|
||||||
public StrictLineReader(InputStream in, int capacity, Charset charset) {
|
|
||||||
if (in == null || charset == null) {
|
|
||||||
throw new NullPointerException();
|
|
||||||
}
|
|
||||||
if (capacity < 0) {
|
|
||||||
throw new IllegalArgumentException("capacity <= 0");
|
|
||||||
}
|
|
||||||
if (!(charset.equals(Util.US_ASCII))) {
|
|
||||||
throw new IllegalArgumentException("Unsupported encoding");
|
|
||||||
}
|
|
||||||
|
|
||||||
this.in = in;
|
|
||||||
this.charset = charset;
|
|
||||||
buf = new byte[capacity];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Closes the reader by closing the underlying {@code InputStream} and
|
|
||||||
* marking this reader as closed.
|
|
||||||
*
|
|
||||||
* @throws IOException for errors when closing the underlying {@code InputStream}.
|
|
||||||
*/
|
|
||||||
public void close() throws IOException {
|
|
||||||
synchronized (in) {
|
|
||||||
if (buf != null) {
|
|
||||||
buf = null;
|
|
||||||
in.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reads the next line. A line ends with {@code "\n"} or {@code "\r\n"},
|
|
||||||
* this end of line marker is not included in the result.
|
|
||||||
*
|
|
||||||
* @return the next line from the input.
|
|
||||||
* @throws IOException for underlying {@code InputStream} errors.
|
|
||||||
* @throws EOFException for the end of source stream.
|
|
||||||
*/
|
|
||||||
public String readLine() throws IOException {
|
|
||||||
synchronized (in) {
|
|
||||||
if (buf == null) {
|
|
||||||
throw new IOException("LineReader is closed");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read more data if we are at the end of the buffered data.
|
|
||||||
// Though it's an error to read after an exception, we will let {@code fillBuf()}
|
|
||||||
// throw again if that happens; thus we need to handle end == -1 as well as end == pos.
|
|
||||||
if (pos >= end) {
|
|
||||||
fillBuf();
|
|
||||||
}
|
|
||||||
// Try to find LF in the buffered data and return the line if successful.
|
|
||||||
for (int i = pos; i != end; ++i) {
|
|
||||||
if (buf[i] == LF) {
|
|
||||||
int lineEnd = (i != pos && buf[i - 1] == CR) ? i - 1 : i;
|
|
||||||
String res = new String(buf, pos, lineEnd - pos, charset.name());
|
|
||||||
pos = i + 1;
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Let's anticipate up to 80 characters on top of those already read.
|
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream(end - pos + 80) {
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
int length = (count > 0 && buf[count - 1] == CR) ? count - 1 : count;
|
|
||||||
try {
|
|
||||||
return new String(buf, 0, length, charset.name());
|
|
||||||
} catch (UnsupportedEncodingException e) {
|
|
||||||
throw new AssertionError(e); // Since we control the charset this will never happen.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
out.write(buf, pos, end - pos);
|
|
||||||
// Mark unterminated line in case fillBuf throws EOFException or IOException.
|
|
||||||
end = -1;
|
|
||||||
fillBuf();
|
|
||||||
// Try to find LF in the buffered data and return the line if successful.
|
|
||||||
for (int i = pos; i != end; ++i) {
|
|
||||||
if (buf[i] == LF) {
|
|
||||||
if (i != pos) {
|
|
||||||
out.write(buf, pos, i - pos);
|
|
||||||
}
|
|
||||||
pos = i + 1;
|
|
||||||
return out.toString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reads new input data into the buffer. Call only with pos == end or end == -1,
|
|
||||||
* depending on the desired outcome if the function throws.
|
|
||||||
*/
|
|
||||||
private void fillBuf() throws IOException {
|
|
||||||
int result = in.read(buf, 0, buf.length);
|
|
||||||
if (result == -1) {
|
|
||||||
throw new EOFException();
|
|
||||||
}
|
|
||||||
pos = 0;
|
|
||||||
end = result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,76 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2010 The Android Open Source Project
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package com.nostra13.universalimageloader.cache.disc.impl.ext;
|
|
||||||
|
|
||||||
import java.io.Closeable;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.Reader;
|
|
||||||
import java.io.StringWriter;
|
|
||||||
import java.nio.charset.Charset;
|
|
||||||
|
|
||||||
/** Junk drawer of utility methods. */
|
|
||||||
final class Util {
|
|
||||||
static final Charset US_ASCII = Charset.forName("US-ASCII");
|
|
||||||
static final Charset UTF_8 = Charset.forName("UTF-8");
|
|
||||||
|
|
||||||
private Util() {
|
|
||||||
}
|
|
||||||
|
|
||||||
static String readFully(Reader reader) throws IOException {
|
|
||||||
try {
|
|
||||||
StringWriter writer = new StringWriter();
|
|
||||||
char[] buffer = new char[1024];
|
|
||||||
int count;
|
|
||||||
while ((count = reader.read(buffer)) != -1) {
|
|
||||||
writer.write(buffer, 0, count);
|
|
||||||
}
|
|
||||||
return writer.toString();
|
|
||||||
} finally {
|
|
||||||
reader.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Deletes the contents of {@code dir}. Throws an IOException if any file
|
|
||||||
* could not be deleted, or if {@code dir} is not a readable directory.
|
|
||||||
*/
|
|
||||||
static void deleteContents(File dir) throws IOException {
|
|
||||||
File[] files = dir.listFiles();
|
|
||||||
if (files == null) {
|
|
||||||
throw new IOException("not a readable directory: " + dir);
|
|
||||||
}
|
|
||||||
for (File file : files) {
|
|
||||||
if (file.isDirectory()) {
|
|
||||||
deleteContents(file);
|
|
||||||
}
|
|
||||||
if (!file.delete()) {
|
|
||||||
throw new IOException("failed to delete file: " + file);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void closeQuietly(/*Auto*/Closeable closeable) {
|
|
||||||
if (closeable != null) {
|
|
||||||
try {
|
|
||||||
closeable.close();
|
|
||||||
} catch (RuntimeException rethrown) {
|
|
||||||
throw rethrown;
|
|
||||||
} catch (Exception ignored) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,28 +0,0 @@
|
|||||||
/*******************************************************************************
|
|
||||||
* Copyright 2011-2013 Sergey Tarasevich
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*******************************************************************************/
|
|
||||||
package com.nostra13.universalimageloader.cache.disc.naming;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generates names for files at disk cache
|
|
||||||
*
|
|
||||||
* @author Sergey Tarasevich (nostra13[at]gmail[dot]com)
|
|
||||||
* @since 1.3.1
|
|
||||||
*/
|
|
||||||
public interface FileNameGenerator {
|
|
||||||
|
|
||||||
/** Generates unique file name for image defined by URI */
|
|
||||||
String generate(String imageUri);
|
|
||||||
}
|
|
@ -1,29 +0,0 @@
|
|||||||
/*******************************************************************************
|
|
||||||
* Copyright 2011-2013 Sergey Tarasevich
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*******************************************************************************/
|
|
||||||
package com.nostra13.universalimageloader.cache.disc.naming;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Names image file as image URI {@linkplain String#hashCode() hashcode}
|
|
||||||
*
|
|
||||||
* @author Sergey Tarasevich (nostra13[at]gmail[dot]com)
|
|
||||||
* @since 1.3.1
|
|
||||||
*/
|
|
||||||
public class HashCodeFileNameGenerator implements FileNameGenerator {
|
|
||||||
@Override
|
|
||||||
public String generate(String imageUri) {
|
|
||||||
return String.valueOf(imageUri.hashCode());
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,53 +0,0 @@
|
|||||||
/*******************************************************************************
|
|
||||||
* Copyright 2011-2013 Sergey Tarasevich
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*******************************************************************************/
|
|
||||||
package com.nostra13.universalimageloader.cache.disc.naming;
|
|
||||||
|
|
||||||
import com.nostra13.universalimageloader.utils.L;
|
|
||||||
|
|
||||||
import java.math.BigInteger;
|
|
||||||
import java.security.MessageDigest;
|
|
||||||
import java.security.NoSuchAlgorithmException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Names image file as MD5 hash of image URI
|
|
||||||
*
|
|
||||||
* @author Sergey Tarasevich (nostra13[at]gmail[dot]com)
|
|
||||||
* @since 1.4.0
|
|
||||||
*/
|
|
||||||
public class Md5FileNameGenerator implements FileNameGenerator {
|
|
||||||
|
|
||||||
private static final String HASH_ALGORITHM = "MD5";
|
|
||||||
private static final int RADIX = 10 + 26; // 10 digits + 26 letters
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String generate(String imageUri) {
|
|
||||||
byte[] md5 = getMD5(imageUri.getBytes());
|
|
||||||
BigInteger bi = new BigInteger(md5).abs();
|
|
||||||
return bi.toString(RADIX);
|
|
||||||
}
|
|
||||||
|
|
||||||
private byte[] getMD5(byte[] data) {
|
|
||||||
byte[] hash = null;
|
|
||||||
try {
|
|
||||||
MessageDigest digest = MessageDigest.getInstance(HASH_ALGORITHM);
|
|
||||||
digest.update(data);
|
|
||||||
hash = digest.digest();
|
|
||||||
} catch (NoSuchAlgorithmException e) {
|
|
||||||
L.e(e);
|
|
||||||
}
|
|
||||||
return hash;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,71 +0,0 @@
|
|||||||
/*******************************************************************************
|
|
||||||
* Copyright 2011-2014 Sergey Tarasevich
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*******************************************************************************/
|
|
||||||
package com.nostra13.universalimageloader.cache.memory;
|
|
||||||
|
|
||||||
import android.graphics.Bitmap;
|
|
||||||
|
|
||||||
import java.lang.ref.Reference;
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Base memory cache. Implements common functionality for memory cache. Provides object references (
|
|
||||||
* {@linkplain Reference not strong}) storing.
|
|
||||||
*
|
|
||||||
* @author Sergey Tarasevich (nostra13[at]gmail[dot]com)
|
|
||||||
* @since 1.0.0
|
|
||||||
*/
|
|
||||||
public abstract class BaseMemoryCache implements MemoryCache {
|
|
||||||
|
|
||||||
/** Stores not strong references to objects */
|
|
||||||
private final Map<String, Reference<Bitmap>> softMap = Collections.synchronizedMap(new HashMap<String, Reference<Bitmap>>());
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Bitmap get(String key) {
|
|
||||||
Bitmap result = null;
|
|
||||||
Reference<Bitmap> reference = softMap.get(key);
|
|
||||||
if (reference != null) {
|
|
||||||
result = reference.get();
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean put(String key, Bitmap value) {
|
|
||||||
softMap.put(key, createReference(value));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Bitmap remove(String key) {
|
|
||||||
Reference<Bitmap> bmpRef = softMap.remove(key);
|
|
||||||
return bmpRef == null ? null : bmpRef.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Collection<String> keys() {
|
|
||||||
synchronized (softMap) {
|
|
||||||
return new HashSet<String>(softMap.keySet());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void clear() {
|
|
||||||
softMap.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Creates {@linkplain Reference not strong} reference of value */
|
|
||||||
protected abstract Reference<Bitmap> createReference(Bitmap value);
|
|
||||||
}
|
|
@ -1,112 +0,0 @@
|
|||||||
/*******************************************************************************
|
|
||||||
* Copyright 2011-2014 Sergey Tarasevich
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*******************************************************************************/
|
|
||||||
package com.nostra13.universalimageloader.cache.memory;
|
|
||||||
|
|
||||||
import android.graphics.Bitmap;
|
|
||||||
|
|
||||||
import com.nostra13.universalimageloader.utils.L;
|
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Limited cache. Provides object storing. Size of all stored bitmaps will not to exceed size limit (
|
|
||||||
* {@link #getSizeLimit()}).<br />
|
|
||||||
* <br />
|
|
||||||
* <b>NOTE:</b> This cache uses strong and weak references for stored Bitmaps. Strong references - for limited count of
|
|
||||||
* Bitmaps (depends on cache size), weak references - for all other cached Bitmaps.
|
|
||||||
*
|
|
||||||
* @author Sergey Tarasevich (nostra13[at]gmail[dot]com)
|
|
||||||
* @see BaseMemoryCache
|
|
||||||
* @since 1.0.0
|
|
||||||
*/
|
|
||||||
public abstract class LimitedMemoryCache extends BaseMemoryCache {
|
|
||||||
|
|
||||||
private static final int MAX_NORMAL_CACHE_SIZE_IN_MB = 16;
|
|
||||||
private static final int MAX_NORMAL_CACHE_SIZE = MAX_NORMAL_CACHE_SIZE_IN_MB * 1024 * 1024;
|
|
||||||
|
|
||||||
private final int sizeLimit;
|
|
||||||
|
|
||||||
private final AtomicInteger cacheSize;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Contains strong references to stored objects. Each next object is added last. If hard cache size will exceed
|
|
||||||
* limit then first object is deleted (but it continue exist at {@link #softMap} and can be collected by GC at any
|
|
||||||
* time)
|
|
||||||
*/
|
|
||||||
private final List<Bitmap> hardCache = Collections.synchronizedList(new LinkedList<Bitmap>());
|
|
||||||
|
|
||||||
/** @param sizeLimit Maximum size for cache (in bytes) */
|
|
||||||
public LimitedMemoryCache(int sizeLimit) {
|
|
||||||
this.sizeLimit = sizeLimit;
|
|
||||||
cacheSize = new AtomicInteger();
|
|
||||||
if (sizeLimit > MAX_NORMAL_CACHE_SIZE) {
|
|
||||||
L.w("You set too large memory cache size (more than %1$d Mb)", MAX_NORMAL_CACHE_SIZE_IN_MB);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean put(String key, Bitmap value) {
|
|
||||||
boolean putSuccessfully = false;
|
|
||||||
// Try to add value to hard cache
|
|
||||||
int valueSize = getSize(value);
|
|
||||||
int sizeLimit = getSizeLimit();
|
|
||||||
int curCacheSize = cacheSize.get();
|
|
||||||
if (valueSize < sizeLimit) {
|
|
||||||
while (curCacheSize + valueSize > sizeLimit) {
|
|
||||||
Bitmap removedValue = removeNext();
|
|
||||||
if (hardCache.remove(removedValue)) {
|
|
||||||
curCacheSize = cacheSize.addAndGet(-getSize(removedValue));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
hardCache.add(value);
|
|
||||||
cacheSize.addAndGet(valueSize);
|
|
||||||
|
|
||||||
putSuccessfully = true;
|
|
||||||
}
|
|
||||||
// Add value to soft cache
|
|
||||||
super.put(key, value);
|
|
||||||
return putSuccessfully;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Bitmap remove(String key) {
|
|
||||||
Bitmap value = super.get(key);
|
|
||||||
if (value != null) {
|
|
||||||
if (hardCache.remove(value)) {
|
|
||||||
cacheSize.addAndGet(-getSize(value));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return super.remove(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void clear() {
|
|
||||||
hardCache.clear();
|
|
||||||
cacheSize.set(0);
|
|
||||||
super.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected int getSizeLimit() {
|
|
||||||
return sizeLimit;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected abstract int getSize(Bitmap value);
|
|
||||||
|
|
||||||
protected abstract Bitmap removeNext();
|
|
||||||
}
|
|
@ -1,48 +0,0 @@
|
|||||||
/*******************************************************************************
|
|
||||||
* Copyright 2014 Sergey Tarasevich
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*******************************************************************************/
|
|
||||||
package com.nostra13.universalimageloader.cache.memory;
|
|
||||||
|
|
||||||
import android.graphics.Bitmap;
|
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Interface for memory cache
|
|
||||||
*
|
|
||||||
* @author Sergey Tarasevich (nostra13[at]gmail[dot]com)
|
|
||||||
* @since 1.9.2
|
|
||||||
*/
|
|
||||||
public interface MemoryCache {
|
|
||||||
/**
|
|
||||||
* Puts value into cache by key
|
|
||||||
*
|
|
||||||
* @return <b>true</b> - if value was put into cache successfully, <b>false</b> - if value was <b>not</b> put into
|
|
||||||
* cache
|
|
||||||
*/
|
|
||||||
boolean put(String key, Bitmap value);
|
|
||||||
|
|
||||||
/** Returns value by key. If there is no value for key then null will be returned. */
|
|
||||||
Bitmap get(String key);
|
|
||||||
|
|
||||||
/** Removes item by key */
|
|
||||||
Bitmap remove(String key);
|
|
||||||
|
|
||||||
/** Returns all keys of cache */
|
|
||||||
Collection<String> keys();
|
|
||||||
|
|
||||||
/** Remove all items from cache */
|
|
||||||
void clear();
|
|
||||||
}
|
|
@ -1,84 +0,0 @@
|
|||||||
/*******************************************************************************
|
|
||||||
* Copyright 2011-2014 Sergey Tarasevich
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*******************************************************************************/
|
|
||||||
package com.nostra13.universalimageloader.cache.memory.impl;
|
|
||||||
|
|
||||||
import android.graphics.Bitmap;
|
|
||||||
import com.nostra13.universalimageloader.cache.memory.LimitedMemoryCache;
|
|
||||||
|
|
||||||
import java.lang.ref.Reference;
|
|
||||||
import java.lang.ref.WeakReference;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Limited {@link Bitmap bitmap} cache. Provides {@link Bitmap bitmaps} storing. Size of all stored bitmaps will not to
|
|
||||||
* exceed size limit. When cache reaches limit size then cache clearing is processed by FIFO principle.<br />
|
|
||||||
* <br />
|
|
||||||
* <b>NOTE:</b> This cache uses strong and weak references for stored Bitmaps. Strong references - for limited count of
|
|
||||||
* Bitmaps (depends on cache size), weak references - for all other cached Bitmaps.
|
|
||||||
*
|
|
||||||
* @author Sergey Tarasevich (nostra13[at]gmail[dot]com)
|
|
||||||
* @since 1.0.0
|
|
||||||
*/
|
|
||||||
public class FIFOLimitedMemoryCache extends LimitedMemoryCache {
|
|
||||||
|
|
||||||
private final List<Bitmap> queue = Collections.synchronizedList(new LinkedList<Bitmap>());
|
|
||||||
|
|
||||||
public FIFOLimitedMemoryCache(int sizeLimit) {
|
|
||||||
super(sizeLimit);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean put(String key, Bitmap value) {
|
|
||||||
if (super.put(key, value)) {
|
|
||||||
queue.add(value);
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Bitmap remove(String key) {
|
|
||||||
Bitmap value = super.get(key);
|
|
||||||
if (value != null) {
|
|
||||||
queue.remove(value);
|
|
||||||
}
|
|
||||||
return super.remove(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void clear() {
|
|
||||||
queue.clear();
|
|
||||||
super.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected int getSize(Bitmap value) {
|
|
||||||
return value.getRowBytes() * value.getHeight();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Bitmap removeNext() {
|
|
||||||
return queue.remove(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Reference<Bitmap> createReference(Bitmap value) {
|
|
||||||
return new WeakReference<Bitmap>(value);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,81 +0,0 @@
|
|||||||
/*******************************************************************************
|
|
||||||
* Copyright 2011-2014 Sergey Tarasevich
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*******************************************************************************/
|
|
||||||
package com.nostra13.universalimageloader.cache.memory.impl;
|
|
||||||
|
|
||||||
import android.graphics.Bitmap;
|
|
||||||
|
|
||||||
import com.nostra13.universalimageloader.cache.memory.MemoryCache;
|
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Comparator;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Decorator for {@link MemoryCache}. Provides special feature for cache: some different keys are considered as
|
|
||||||
* equals (using {@link Comparator comparator}). And when you try to put some value into cache by key so entries with
|
|
||||||
* "equals" keys will be removed from cache before.<br />
|
|
||||||
* <b>NOTE:</b> Used for internal needs. Normally you don't need to use this class.
|
|
||||||
*
|
|
||||||
* @author Sergey Tarasevich (nostra13[at]gmail[dot]com)
|
|
||||||
* @since 1.0.0
|
|
||||||
*/
|
|
||||||
public class FuzzyKeyMemoryCache implements MemoryCache {
|
|
||||||
|
|
||||||
private final MemoryCache cache;
|
|
||||||
private final Comparator<String> keyComparator;
|
|
||||||
|
|
||||||
public FuzzyKeyMemoryCache(MemoryCache cache, Comparator<String> keyComparator) {
|
|
||||||
this.cache = cache;
|
|
||||||
this.keyComparator = keyComparator;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean put(String key, Bitmap value) {
|
|
||||||
// Search equal key and remove this entry
|
|
||||||
synchronized (cache) {
|
|
||||||
String keyToRemove = null;
|
|
||||||
for (String cacheKey : cache.keys()) {
|
|
||||||
if (keyComparator.compare(key, cacheKey) == 0) {
|
|
||||||
keyToRemove = cacheKey;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (keyToRemove != null) {
|
|
||||||
cache.remove(keyToRemove);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return cache.put(key, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Bitmap get(String key) {
|
|
||||||
return cache.get(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Bitmap remove(String key) {
|
|
||||||
return cache.remove(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void clear() {
|
|
||||||
cache.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Collection<String> keys() {
|
|
||||||
return cache.keys();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,103 +0,0 @@
|
|||||||
/*******************************************************************************
|
|
||||||
* Copyright 2011-2014 Sergey Tarasevich
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*******************************************************************************/
|
|
||||||
package com.nostra13.universalimageloader.cache.memory.impl;
|
|
||||||
|
|
||||||
import android.graphics.Bitmap;
|
|
||||||
import com.nostra13.universalimageloader.cache.memory.LimitedMemoryCache;
|
|
||||||
|
|
||||||
import java.lang.ref.Reference;
|
|
||||||
import java.lang.ref.WeakReference;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.LinkedHashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Map.Entry;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Limited {@link Bitmap bitmap} cache. Provides {@link Bitmap bitmaps} storing. Size of all stored bitmaps will not to
|
|
||||||
* exceed size limit. When cache reaches limit size then the least recently used bitmap is deleted from cache.<br />
|
|
||||||
* <br />
|
|
||||||
* <b>NOTE:</b> This cache uses strong and weak references for stored Bitmaps. Strong references - for limited count of
|
|
||||||
* Bitmaps (depends on cache size), weak references - for all other cached Bitmaps.
|
|
||||||
*
|
|
||||||
* @author Sergey Tarasevich (nostra13[at]gmail[dot]com)
|
|
||||||
* @since 1.3.0
|
|
||||||
*/
|
|
||||||
public class LRULimitedMemoryCache extends LimitedMemoryCache {
|
|
||||||
|
|
||||||
private static final int INITIAL_CAPACITY = 10;
|
|
||||||
private static final float LOAD_FACTOR = 1.1f;
|
|
||||||
|
|
||||||
/** Cache providing Least-Recently-Used logic */
|
|
||||||
private final Map<String, Bitmap> lruCache = Collections.synchronizedMap(new LinkedHashMap<String, Bitmap>(INITIAL_CAPACITY, LOAD_FACTOR, true));
|
|
||||||
|
|
||||||
/** @param maxSize Maximum sum of the sizes of the Bitmaps in this cache */
|
|
||||||
public LRULimitedMemoryCache(int maxSize) {
|
|
||||||
super(maxSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean put(String key, Bitmap value) {
|
|
||||||
if (super.put(key, value)) {
|
|
||||||
lruCache.put(key, value);
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Bitmap get(String key) {
|
|
||||||
lruCache.get(key); // call "get" for LRU logic
|
|
||||||
return super.get(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Bitmap remove(String key) {
|
|
||||||
lruCache.remove(key);
|
|
||||||
return super.remove(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void clear() {
|
|
||||||
lruCache.clear();
|
|
||||||
super.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected int getSize(Bitmap value) {
|
|
||||||
return value.getRowBytes() * value.getHeight();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Bitmap removeNext() {
|
|
||||||
Bitmap mostLongUsedValue = null;
|
|
||||||
synchronized (lruCache) {
|
|
||||||
Iterator<Entry<String, Bitmap>> it = lruCache.entrySet().iterator();
|
|
||||||
if (it.hasNext()) {
|
|
||||||
Entry<String, Bitmap> entry = it.next();
|
|
||||||
mostLongUsedValue = entry.getValue();
|
|
||||||
it.remove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return mostLongUsedValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Reference<Bitmap> createReference(Bitmap value) {
|
|
||||||
return new WeakReference<Bitmap>(value);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,109 +0,0 @@
|
|||||||
/*******************************************************************************
|
|
||||||
* Copyright 2011-2014 Sergey Tarasevich
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*******************************************************************************/
|
|
||||||
package com.nostra13.universalimageloader.cache.memory.impl;
|
|
||||||
|
|
||||||
import android.graphics.Bitmap;
|
|
||||||
import com.nostra13.universalimageloader.cache.memory.LimitedMemoryCache;
|
|
||||||
|
|
||||||
import java.lang.ref.Reference;
|
|
||||||
import java.lang.ref.WeakReference;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Map.Entry;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Limited {@link Bitmap bitmap} cache. Provides {@link Bitmap bitmaps} storing. Size of all stored bitmaps will not to
|
|
||||||
* exceed size limit. When cache reaches limit size then the bitmap which has the largest size is deleted from
|
|
||||||
* cache.<br />
|
|
||||||
* <br />
|
|
||||||
* <b>NOTE:</b> This cache uses strong and weak references for stored Bitmaps. Strong references - for limited count of
|
|
||||||
* Bitmaps (depends on cache size), weak references - for all other cached Bitmaps.
|
|
||||||
*
|
|
||||||
* @author Sergey Tarasevich (nostra13[at]gmail[dot]com)
|
|
||||||
* @since 1.0.0
|
|
||||||
*/
|
|
||||||
public class LargestLimitedMemoryCache extends LimitedMemoryCache {
|
|
||||||
/**
|
|
||||||
* Contains strong references to stored objects (keys) and sizes of the objects. If hard cache
|
|
||||||
* size will exceed limit then object with the largest size is deleted (but it continue exist at
|
|
||||||
* {@link #softMap} and can be collected by GC at any time)
|
|
||||||
*/
|
|
||||||
private final Map<Bitmap, Integer> valueSizes = Collections.synchronizedMap(new HashMap<Bitmap, Integer>());
|
|
||||||
|
|
||||||
public LargestLimitedMemoryCache(int sizeLimit) {
|
|
||||||
super(sizeLimit);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean put(String key, Bitmap value) {
|
|
||||||
if (super.put(key, value)) {
|
|
||||||
valueSizes.put(value, getSize(value));
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Bitmap remove(String key) {
|
|
||||||
Bitmap value = super.get(key);
|
|
||||||
if (value != null) {
|
|
||||||
valueSizes.remove(value);
|
|
||||||
}
|
|
||||||
return super.remove(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void clear() {
|
|
||||||
valueSizes.clear();
|
|
||||||
super.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected int getSize(Bitmap value) {
|
|
||||||
return value.getRowBytes() * value.getHeight();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Bitmap removeNext() {
|
|
||||||
Integer maxSize = null;
|
|
||||||
Bitmap largestValue = null;
|
|
||||||
Set<Entry<Bitmap, Integer>> entries = valueSizes.entrySet();
|
|
||||||
synchronized (valueSizes) {
|
|
||||||
for (Entry<Bitmap, Integer> entry : entries) {
|
|
||||||
if (largestValue == null) {
|
|
||||||
largestValue = entry.getKey();
|
|
||||||
maxSize = entry.getValue();
|
|
||||||
} else {
|
|
||||||
Integer size = entry.getValue();
|
|
||||||
if (size > maxSize) {
|
|
||||||
maxSize = size;
|
|
||||||
largestValue = entry.getKey();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
valueSizes.remove(largestValue);
|
|
||||||
return largestValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Reference<Bitmap> createReference(Bitmap value) {
|
|
||||||
return new WeakReference<Bitmap>(value);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,88 +0,0 @@
|
|||||||
/*******************************************************************************
|
|
||||||
* Copyright 2011-2014 Sergey Tarasevich
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*******************************************************************************/
|
|
||||||
package com.nostra13.universalimageloader.cache.memory.impl;
|
|
||||||
|
|
||||||
import android.graphics.Bitmap;
|
|
||||||
|
|
||||||
import com.nostra13.universalimageloader.cache.memory.MemoryCache;
|
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Decorator for {@link MemoryCache}. Provides special feature for cache: if some cached object age exceeds defined
|
|
||||||
* value then this object will be removed from cache.
|
|
||||||
*
|
|
||||||
* @author Sergey Tarasevich (nostra13[at]gmail[dot]com)
|
|
||||||
* @see MemoryCache
|
|
||||||
* @since 1.3.1
|
|
||||||
*/
|
|
||||||
public class LimitedAgeMemoryCache implements MemoryCache {
|
|
||||||
|
|
||||||
private final MemoryCache cache;
|
|
||||||
|
|
||||||
private final long maxAge;
|
|
||||||
private final Map<String, Long> loadingDates = Collections.synchronizedMap(new HashMap<String, Long>());
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param cache Wrapped memory cache
|
|
||||||
* @param maxAge Max object age <b>(in seconds)</b>. If object age will exceed this value then it'll be removed from
|
|
||||||
* cache on next treatment (and therefore be reloaded).
|
|
||||||
*/
|
|
||||||
public LimitedAgeMemoryCache(MemoryCache cache, long maxAge) {
|
|
||||||
this.cache = cache;
|
|
||||||
this.maxAge = maxAge * 1000; // to milliseconds
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean put(String key, Bitmap value) {
|
|
||||||
boolean putSuccesfully = cache.put(key, value);
|
|
||||||
if (putSuccesfully) {
|
|
||||||
loadingDates.put(key, System.currentTimeMillis());
|
|
||||||
}
|
|
||||||
return putSuccesfully;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Bitmap get(String key) {
|
|
||||||
Long loadingDate = loadingDates.get(key);
|
|
||||||
if (loadingDate != null && System.currentTimeMillis() - loadingDate > maxAge) {
|
|
||||||
cache.remove(key);
|
|
||||||
loadingDates.remove(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
return cache.get(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Bitmap remove(String key) {
|
|
||||||
loadingDates.remove(key);
|
|
||||||
return cache.remove(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Collection<String> keys() {
|
|
||||||
return cache.keys();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void clear() {
|
|
||||||
cache.clear();
|
|
||||||
loadingDates.clear();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,144 +0,0 @@
|
|||||||
package com.nostra13.universalimageloader.cache.memory.impl;
|
|
||||||
|
|
||||||
import android.graphics.Bitmap;
|
|
||||||
|
|
||||||
import com.nostra13.universalimageloader.cache.memory.MemoryCache;
|
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.LinkedHashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A cache that holds strong references to a limited number of Bitmaps. Each time a Bitmap is accessed, it is moved to
|
|
||||||
* the head of a queue. When a Bitmap is added to a full cache, the Bitmap at the end of that queue is evicted and may
|
|
||||||
* become eligible for garbage collection.<br />
|
|
||||||
* <br />
|
|
||||||
* <b>NOTE:</b> This cache uses only strong references for stored Bitmaps.
|
|
||||||
*
|
|
||||||
* @author Sergey Tarasevich (nostra13[at]gmail[dot]com)
|
|
||||||
* @since 1.8.1
|
|
||||||
*/
|
|
||||||
public class LruMemoryCache implements MemoryCache {
|
|
||||||
|
|
||||||
private final LinkedHashMap<String, Bitmap> map;
|
|
||||||
|
|
||||||
private final int maxSize;
|
|
||||||
/** Size of this cache in bytes */
|
|
||||||
private int size;
|
|
||||||
|
|
||||||
/** @param maxSize Maximum sum of the sizes of the Bitmaps in this cache */
|
|
||||||
public LruMemoryCache(int maxSize) {
|
|
||||||
if (maxSize <= 0) {
|
|
||||||
throw new IllegalArgumentException("maxSize <= 0");
|
|
||||||
}
|
|
||||||
this.maxSize = maxSize;
|
|
||||||
this.map = new LinkedHashMap<String, Bitmap>(0, 0.75f, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the Bitmap for {@code key} if it exists in the cache. If a Bitmap was returned, it is moved to the head
|
|
||||||
* of the queue. This returns null if a Bitmap is not cached.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public final Bitmap get(String key) {
|
|
||||||
if (key == null) {
|
|
||||||
throw new NullPointerException("key == null");
|
|
||||||
}
|
|
||||||
|
|
||||||
synchronized (this) {
|
|
||||||
return map.get(key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Caches {@code Bitmap} for {@code key}. The Bitmap is moved to the head of the queue. */
|
|
||||||
@Override
|
|
||||||
public final boolean put(String key, Bitmap value) {
|
|
||||||
if (key == null || value == null) {
|
|
||||||
throw new NullPointerException("key == null || value == null");
|
|
||||||
}
|
|
||||||
|
|
||||||
synchronized (this) {
|
|
||||||
size += sizeOf(key, value);
|
|
||||||
Bitmap previous = map.put(key, value);
|
|
||||||
if (previous != null) {
|
|
||||||
size -= sizeOf(key, previous);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
trimToSize(maxSize);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove the eldest entries until the total of remaining entries is at or below the requested size.
|
|
||||||
*
|
|
||||||
* @param maxSize the maximum size of the cache before returning. May be -1 to evict even 0-sized elements.
|
|
||||||
*/
|
|
||||||
private void trimToSize(int maxSize) {
|
|
||||||
while (true) {
|
|
||||||
String key;
|
|
||||||
Bitmap value;
|
|
||||||
synchronized (this) {
|
|
||||||
if (size < 0 || (map.isEmpty() && size != 0)) {
|
|
||||||
throw new IllegalStateException(getClass().getName() + ".sizeOf() is reporting inconsistent results!");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (size <= maxSize || map.isEmpty()) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
Map.Entry<String, Bitmap> toEvict = map.entrySet().iterator().next();
|
|
||||||
if (toEvict == null) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
key = toEvict.getKey();
|
|
||||||
value = toEvict.getValue();
|
|
||||||
map.remove(key);
|
|
||||||
size -= sizeOf(key, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Removes the entry for {@code key} if it exists. */
|
|
||||||
@Override
|
|
||||||
public final Bitmap remove(String key) {
|
|
||||||
if (key == null) {
|
|
||||||
throw new NullPointerException("key == null");
|
|
||||||
}
|
|
||||||
|
|
||||||
synchronized (this) {
|
|
||||||
Bitmap previous = map.remove(key);
|
|
||||||
if (previous != null) {
|
|
||||||
size -= sizeOf(key, previous);
|
|
||||||
}
|
|
||||||
return previous;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Collection<String> keys() {
|
|
||||||
synchronized (this) {
|
|
||||||
return new HashSet<String>(map.keySet());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void clear() {
|
|
||||||
trimToSize(-1); // -1 will evict 0-sized elements
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the size {@code Bitmap} in bytes.
|
|
||||||
* <p/>
|
|
||||||
* An entry's size must not change while it is in the cache.
|
|
||||||
*/
|
|
||||||
private int sizeOf(String key, Bitmap value) {
|
|
||||||
return value.getRowBytes() * value.getHeight();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public synchronized final String toString() {
|
|
||||||
return String.format("LruCache[maxSize=%d]", maxSize);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,122 +0,0 @@
|
|||||||
/*******************************************************************************
|
|
||||||
* Copyright 2011-2014 Sergey Tarasevich
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*******************************************************************************/
|
|
||||||
package com.nostra13.universalimageloader.cache.memory.impl;
|
|
||||||
|
|
||||||
import android.graphics.Bitmap;
|
|
||||||
import com.nostra13.universalimageloader.cache.memory.LimitedMemoryCache;
|
|
||||||
|
|
||||||
import java.lang.ref.Reference;
|
|
||||||
import java.lang.ref.WeakReference;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Map.Entry;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Limited {@link Bitmap bitmap} cache. Provides {@link Bitmap bitmaps} storing. Size of all stored bitmaps will not to
|
|
||||||
* exceed size limit. When cache reaches limit size then the bitmap which used the least frequently is deleted from
|
|
||||||
* cache.<br />
|
|
||||||
* <br />
|
|
||||||
* <b>NOTE:</b> This cache uses strong and weak references for stored Bitmaps. Strong references - for limited count of
|
|
||||||
* Bitmaps (depends on cache size), weak references - for all other cached Bitmaps.
|
|
||||||
*
|
|
||||||
* @author Sergey Tarasevich (nostra13[at]gmail[dot]com)
|
|
||||||
* @since 1.0.0
|
|
||||||
*/
|
|
||||||
public class UsingFreqLimitedMemoryCache extends LimitedMemoryCache {
|
|
||||||
/**
|
|
||||||
* Contains strong references to stored objects (keys) and last object usage date (in milliseconds). If hard cache
|
|
||||||
* size will exceed limit then object with the least frequently usage is deleted (but it continue exist at
|
|
||||||
* {@link #softMap} and can be collected by GC at any time)
|
|
||||||
*/
|
|
||||||
private final Map<Bitmap, Integer> usingCounts = Collections.synchronizedMap(new HashMap<Bitmap, Integer>());
|
|
||||||
|
|
||||||
public UsingFreqLimitedMemoryCache(int sizeLimit) {
|
|
||||||
super(sizeLimit);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean put(String key, Bitmap value) {
|
|
||||||
if (super.put(key, value)) {
|
|
||||||
usingCounts.put(value, 0);
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Bitmap get(String key) {
|
|
||||||
Bitmap value = super.get(key);
|
|
||||||
// Increment usage count for value if value is contained in hardCahe
|
|
||||||
if (value != null) {
|
|
||||||
Integer usageCount = usingCounts.get(value);
|
|
||||||
if (usageCount != null) {
|
|
||||||
usingCounts.put(value, usageCount + 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Bitmap remove(String key) {
|
|
||||||
Bitmap value = super.get(key);
|
|
||||||
if (value != null) {
|
|
||||||
usingCounts.remove(value);
|
|
||||||
}
|
|
||||||
return super.remove(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void clear() {
|
|
||||||
usingCounts.clear();
|
|
||||||
super.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected int getSize(Bitmap value) {
|
|
||||||
return value.getRowBytes() * value.getHeight();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Bitmap removeNext() {
|
|
||||||
Integer minUsageCount = null;
|
|
||||||
Bitmap leastUsedValue = null;
|
|
||||||
Set<Entry<Bitmap, Integer>> entries = usingCounts.entrySet();
|
|
||||||
synchronized (usingCounts) {
|
|
||||||
for (Entry<Bitmap, Integer> entry : entries) {
|
|
||||||
if (leastUsedValue == null) {
|
|
||||||
leastUsedValue = entry.getKey();
|
|
||||||
minUsageCount = entry.getValue();
|
|
||||||
} else {
|
|
||||||
Integer lastValueUsage = entry.getValue();
|
|
||||||
if (lastValueUsage < minUsageCount) {
|
|
||||||
minUsageCount = lastValueUsage;
|
|
||||||
leastUsedValue = entry.getKey();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
usingCounts.remove(leastUsedValue);
|
|
||||||
return leastUsedValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Reference<Bitmap> createReference(Bitmap value) {
|
|
||||||
return new WeakReference<Bitmap>(value);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,37 +0,0 @@
|
|||||||
/*******************************************************************************
|
|
||||||
* Copyright 2011-2014 Sergey Tarasevich
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*******************************************************************************/
|
|
||||||
package com.nostra13.universalimageloader.cache.memory.impl;
|
|
||||||
|
|
||||||
import android.graphics.Bitmap;
|
|
||||||
import com.nostra13.universalimageloader.cache.memory.BaseMemoryCache;
|
|
||||||
|
|
||||||
import java.lang.ref.Reference;
|
|
||||||
import java.lang.ref.WeakReference;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Memory cache with {@linkplain WeakReference weak references} to {@linkplain android.graphics.Bitmap bitmaps}<br />
|
|
||||||
* <br />
|
|
||||||
* <b>NOTE:</b> This cache uses only weak references for stored Bitmaps.
|
|
||||||
*
|
|
||||||
* @author Sergey Tarasevich (nostra13[at]gmail[dot]com)
|
|
||||||
* @since 1.5.3
|
|
||||||
*/
|
|
||||||
public class WeakMemoryCache extends BaseMemoryCache {
|
|
||||||
@Override
|
|
||||||
protected Reference<Bitmap> createReference(Bitmap value) {
|
|
||||||
return new WeakReference<Bitmap>(value);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,183 +0,0 @@
|
|||||||
/*******************************************************************************
|
|
||||||
* Copyright 2011-2014 Sergey Tarasevich
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*******************************************************************************/
|
|
||||||
package com.nostra13.universalimageloader.core;
|
|
||||||
|
|
||||||
import android.annotation.TargetApi;
|
|
||||||
import android.app.ActivityManager;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.pm.ApplicationInfo;
|
|
||||||
import android.os.Build;
|
|
||||||
import com.nostra13.universalimageloader.cache.disc.DiskCache;
|
|
||||||
import com.nostra13.universalimageloader.cache.disc.impl.UnlimitedDiskCache;
|
|
||||||
import com.nostra13.universalimageloader.cache.disc.impl.ext.LruDiskCache;
|
|
||||||
import com.nostra13.universalimageloader.cache.disc.naming.FileNameGenerator;
|
|
||||||
import com.nostra13.universalimageloader.cache.disc.naming.HashCodeFileNameGenerator;
|
|
||||||
import com.nostra13.universalimageloader.cache.memory.MemoryCache;
|
|
||||||
import com.nostra13.universalimageloader.cache.memory.impl.LruMemoryCache;
|
|
||||||
import com.nostra13.universalimageloader.core.assist.QueueProcessingType;
|
|
||||||
import com.nostra13.universalimageloader.core.assist.deque.LIFOLinkedBlockingDeque;
|
|
||||||
import com.nostra13.universalimageloader.core.decode.BaseImageDecoder;
|
|
||||||
import com.nostra13.universalimageloader.core.decode.ImageDecoder;
|
|
||||||
import com.nostra13.universalimageloader.core.display.BitmapDisplayer;
|
|
||||||
import com.nostra13.universalimageloader.core.display.SimpleBitmapDisplayer;
|
|
||||||
import com.nostra13.universalimageloader.core.download.BaseImageDownloader;
|
|
||||||
import com.nostra13.universalimageloader.core.download.ImageDownloader;
|
|
||||||
import com.nostra13.universalimageloader.utils.L;
|
|
||||||
import com.nostra13.universalimageloader.utils.StorageUtils;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.concurrent.BlockingQueue;
|
|
||||||
import java.util.concurrent.Executor;
|
|
||||||
import java.util.concurrent.Executors;
|
|
||||||
import java.util.concurrent.LinkedBlockingQueue;
|
|
||||||
import java.util.concurrent.ThreadFactory;
|
|
||||||
import java.util.concurrent.ThreadPoolExecutor;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Factory for providing of default options for {@linkplain ImageLoaderConfiguration configuration}
|
|
||||||
*
|
|
||||||
* @author Sergey Tarasevich (nostra13[at]gmail[dot]com)
|
|
||||||
* @since 1.5.6
|
|
||||||
*/
|
|
||||||
public class DefaultConfigurationFactory {
|
|
||||||
|
|
||||||
/** Creates default implementation of task executor */
|
|
||||||
public static Executor createExecutor(int threadPoolSize, int threadPriority,
|
|
||||||
QueueProcessingType tasksProcessingType) {
|
|
||||||
boolean lifo = tasksProcessingType == QueueProcessingType.LIFO;
|
|
||||||
BlockingQueue<Runnable> taskQueue =
|
|
||||||
lifo ? new LIFOLinkedBlockingDeque<Runnable>() : new LinkedBlockingQueue<Runnable>();
|
|
||||||
return new ThreadPoolExecutor(threadPoolSize, threadPoolSize, 0L, TimeUnit.MILLISECONDS, taskQueue,
|
|
||||||
createThreadFactory(threadPriority, "uil-pool-"));
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Creates default implementation of task distributor */
|
|
||||||
public static Executor createTaskDistributor() {
|
|
||||||
return Executors.newCachedThreadPool(createThreadFactory(Thread.NORM_PRIORITY, "uil-pool-d-"));
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Creates {@linkplain HashCodeFileNameGenerator default implementation} of FileNameGenerator */
|
|
||||||
public static FileNameGenerator createFileNameGenerator() {
|
|
||||||
return new HashCodeFileNameGenerator();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates default implementation of {@link DiskCache} depends on incoming parameters
|
|
||||||
*/
|
|
||||||
public static DiskCache createDiskCache(Context context, FileNameGenerator diskCacheFileNameGenerator,
|
|
||||||
long diskCacheSize, int diskCacheFileCount) {
|
|
||||||
File reserveCacheDir = createReserveDiskCacheDir(context);
|
|
||||||
if (diskCacheSize > 0 || diskCacheFileCount > 0) {
|
|
||||||
File individualCacheDir = StorageUtils.getIndividualCacheDirectory(context);
|
|
||||||
try {
|
|
||||||
return new LruDiskCache(individualCacheDir, reserveCacheDir, diskCacheFileNameGenerator, diskCacheSize,
|
|
||||||
diskCacheFileCount);
|
|
||||||
} catch (IOException e) {
|
|
||||||
L.e(e);
|
|
||||||
// continue and create unlimited cache
|
|
||||||
}
|
|
||||||
}
|
|
||||||
File cacheDir = StorageUtils.getCacheDirectory(context);
|
|
||||||
return new UnlimitedDiskCache(cacheDir, reserveCacheDir, diskCacheFileNameGenerator);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Creates reserve disk cache folder which will be used if primary disk cache folder becomes unavailable */
|
|
||||||
private static File createReserveDiskCacheDir(Context context) {
|
|
||||||
File cacheDir = StorageUtils.getCacheDirectory(context, false);
|
|
||||||
File individualDir = new File(cacheDir, "uil-images");
|
|
||||||
if (individualDir.exists() || individualDir.mkdir()) {
|
|
||||||
cacheDir = individualDir;
|
|
||||||
}
|
|
||||||
return cacheDir;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates default implementation of {@link MemoryCache} - {@link LruMemoryCache}<br />
|
|
||||||
* Default cache size = 1/8 of available app memory.
|
|
||||||
*/
|
|
||||||
public static MemoryCache createMemoryCache(Context context, int memoryCacheSize) {
|
|
||||||
if (memoryCacheSize == 0) {
|
|
||||||
ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
|
|
||||||
int memoryClass = am.getMemoryClass();
|
|
||||||
if (hasHoneycomb() && isLargeHeap(context)) {
|
|
||||||
memoryClass = getLargeMemoryClass(am);
|
|
||||||
}
|
|
||||||
memoryCacheSize = 1024 * 1024 * memoryClass / 8;
|
|
||||||
}
|
|
||||||
return new LruMemoryCache(memoryCacheSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean hasHoneycomb() {
|
|
||||||
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB;
|
|
||||||
}
|
|
||||||
|
|
||||||
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
|
|
||||||
private static boolean isLargeHeap(Context context) {
|
|
||||||
return (context.getApplicationInfo().flags & ApplicationInfo.FLAG_LARGE_HEAP) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
|
|
||||||
private static int getLargeMemoryClass(ActivityManager am) {
|
|
||||||
return am.getLargeMemoryClass();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Creates default implementation of {@link ImageDownloader} - {@link BaseImageDownloader} */
|
|
||||||
public static ImageDownloader createImageDownloader(Context context) {
|
|
||||||
return new BaseImageDownloader(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Creates default implementation of {@link ImageDecoder} - {@link BaseImageDecoder} */
|
|
||||||
public static ImageDecoder createImageDecoder(boolean loggingEnabled) {
|
|
||||||
return new BaseImageDecoder(loggingEnabled);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Creates default implementation of {@link BitmapDisplayer} - {@link SimpleBitmapDisplayer} */
|
|
||||||
public static BitmapDisplayer createBitmapDisplayer() {
|
|
||||||
return new SimpleBitmapDisplayer();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Creates default implementation of {@linkplain ThreadFactory thread factory} for task executor */
|
|
||||||
private static ThreadFactory createThreadFactory(int threadPriority, String threadNamePrefix) {
|
|
||||||
return new DefaultThreadFactory(threadPriority, threadNamePrefix);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class DefaultThreadFactory implements ThreadFactory {
|
|
||||||
|
|
||||||
private static final AtomicInteger poolNumber = new AtomicInteger(1);
|
|
||||||
|
|
||||||
private final ThreadGroup group;
|
|
||||||
private final AtomicInteger threadNumber = new AtomicInteger(1);
|
|
||||||
private final String namePrefix;
|
|
||||||
private final int threadPriority;
|
|
||||||
|
|
||||||
DefaultThreadFactory(int threadPriority, String threadNamePrefix) {
|
|
||||||
this.threadPriority = threadPriority;
|
|
||||||
group = Thread.currentThread().getThreadGroup();
|
|
||||||
namePrefix = threadNamePrefix + poolNumber.getAndIncrement() + "-thread-";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Thread newThread(Runnable r) {
|
|
||||||
Thread t = new Thread(group, r, namePrefix + threadNumber.getAndIncrement(), 0);
|
|
||||||
if (t.isDaemon()) t.setDaemon(false);
|
|
||||||
t.setPriority(threadPriority);
|
|
||||||
return t;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,81 +0,0 @@
|
|||||||
/*******************************************************************************
|
|
||||||
* Copyright 2011-2014 Sergey Tarasevich
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*******************************************************************************/
|
|
||||||
package com.nostra13.universalimageloader.core;
|
|
||||||
|
|
||||||
import android.graphics.Bitmap;
|
|
||||||
import com.nostra13.universalimageloader.core.assist.LoadedFrom;
|
|
||||||
import com.nostra13.universalimageloader.core.display.BitmapDisplayer;
|
|
||||||
import com.nostra13.universalimageloader.core.imageaware.ImageAware;
|
|
||||||
import com.nostra13.universalimageloader.core.listener.ImageLoadingListener;
|
|
||||||
import com.nostra13.universalimageloader.utils.L;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Displays bitmap in {@link com.nostra13.universalimageloader.core.imageaware.ImageAware}. Must be called on UI thread.
|
|
||||||
*
|
|
||||||
* @author Sergey Tarasevich (nostra13[at]gmail[dot]com)
|
|
||||||
* @see ImageLoadingListener
|
|
||||||
* @see BitmapDisplayer
|
|
||||||
* @since 1.3.1
|
|
||||||
*/
|
|
||||||
final class DisplayBitmapTask implements Runnable {
|
|
||||||
|
|
||||||
private static final String LOG_DISPLAY_IMAGE_IN_IMAGEAWARE = "Display image in ImageAware (loaded from %1$s) [%2$s]";
|
|
||||||
private static final String LOG_TASK_CANCELLED_IMAGEAWARE_REUSED = "ImageAware is reused for another image. Task is cancelled. [%s]";
|
|
||||||
private static final String LOG_TASK_CANCELLED_IMAGEAWARE_COLLECTED = "ImageAware was collected by GC. Task is cancelled. [%s]";
|
|
||||||
|
|
||||||
private final Bitmap bitmap;
|
|
||||||
private final String imageUri;
|
|
||||||
private final ImageAware imageAware;
|
|
||||||
private final String memoryCacheKey;
|
|
||||||
private final BitmapDisplayer displayer;
|
|
||||||
private final ImageLoadingListener listener;
|
|
||||||
private final ImageLoaderEngine engine;
|
|
||||||
private final LoadedFrom loadedFrom;
|
|
||||||
|
|
||||||
public DisplayBitmapTask(Bitmap bitmap, ImageLoadingInfo imageLoadingInfo, ImageLoaderEngine engine,
|
|
||||||
LoadedFrom loadedFrom) {
|
|
||||||
this.bitmap = bitmap;
|
|
||||||
imageUri = imageLoadingInfo.uri;
|
|
||||||
imageAware = imageLoadingInfo.imageAware;
|
|
||||||
memoryCacheKey = imageLoadingInfo.memoryCacheKey;
|
|
||||||
displayer = imageLoadingInfo.options.getDisplayer();
|
|
||||||
listener = imageLoadingInfo.listener;
|
|
||||||
this.engine = engine;
|
|
||||||
this.loadedFrom = loadedFrom;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
if (imageAware.isCollected()) {
|
|
||||||
L.d(LOG_TASK_CANCELLED_IMAGEAWARE_COLLECTED, memoryCacheKey);
|
|
||||||
listener.onLoadingCancelled(imageUri, imageAware.getWrappedView());
|
|
||||||
} else if (isViewWasReused()) {
|
|
||||||
L.d(LOG_TASK_CANCELLED_IMAGEAWARE_REUSED, memoryCacheKey);
|
|
||||||
listener.onLoadingCancelled(imageUri, imageAware.getWrappedView());
|
|
||||||
} else {
|
|
||||||
L.d(LOG_DISPLAY_IMAGE_IN_IMAGEAWARE, loadedFrom, memoryCacheKey);
|
|
||||||
displayer.display(bitmap, imageAware, loadedFrom);
|
|
||||||
engine.cancelDisplayTaskFor(imageAware);
|
|
||||||
listener.onLoadingComplete(imageUri, imageAware.getWrappedView(), bitmap);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Checks whether memory cache key (image URI) for current ImageAware is actual */
|
|
||||||
private boolean isViewWasReused() {
|
|
||||||
String currentCacheKey = engine.getLoadingUriForView(imageAware);
|
|
||||||
return !memoryCacheKey.equals(currentCacheKey);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,509 +0,0 @@
|
|||||||
/*******************************************************************************
|
|
||||||
* Copyright 2011-2014 Sergey Tarasevich
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*******************************************************************************/
|
|
||||||
package com.nostra13.universalimageloader.core;
|
|
||||||
|
|
||||||
import android.content.res.Resources;
|
|
||||||
import android.graphics.Bitmap;
|
|
||||||
import android.graphics.BitmapFactory.Options;
|
|
||||||
import android.graphics.drawable.Drawable;
|
|
||||||
import android.os.Handler;
|
|
||||||
import com.nostra13.universalimageloader.core.listener.ImageLoadingListener;
|
|
||||||
import com.nostra13.universalimageloader.core.assist.ImageScaleType;
|
|
||||||
import com.nostra13.universalimageloader.core.display.BitmapDisplayer;
|
|
||||||
import com.nostra13.universalimageloader.core.display.SimpleBitmapDisplayer;
|
|
||||||
import com.nostra13.universalimageloader.core.download.ImageDownloader;
|
|
||||||
import com.nostra13.universalimageloader.core.process.BitmapProcessor;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Contains options for image display. Defines:
|
|
||||||
* <ul>
|
|
||||||
* <li>whether stub image will be displayed in {@link com.nostra13.universalimageloader.core.imageaware.ImageAware
|
|
||||||
* image aware view} during image loading</li>
|
|
||||||
* <li>whether stub image will be displayed in {@link com.nostra13.universalimageloader.core.imageaware.ImageAware
|
|
||||||
* image aware view} if empty URI is passed</li>
|
|
||||||
* <li>whether stub image will be displayed in {@link com.nostra13.universalimageloader.core.imageaware.ImageAware
|
|
||||||
* image aware view} if image loading fails</li>
|
|
||||||
* <li>whether {@link com.nostra13.universalimageloader.core.imageaware.ImageAware image aware view} should be reset
|
|
||||||
* before image loading start</li>
|
|
||||||
* <li>whether loaded image will be cached in memory</li>
|
|
||||||
* <li>whether loaded image will be cached on disk</li>
|
|
||||||
* <li>image scale type</li>
|
|
||||||
* <li>decoding options (including bitmap decoding configuration)</li>
|
|
||||||
* <li>delay before loading of image</li>
|
|
||||||
* <li>whether consider EXIF parameters of image</li>
|
|
||||||
* <li>auxiliary object which will be passed to {@link ImageDownloader#getStream(String, Object) ImageDownloader}</li>
|
|
||||||
* <li>pre-processor for image Bitmap (before caching in memory)</li>
|
|
||||||
* <li>post-processor for image Bitmap (after caching in memory, before displaying)</li>
|
|
||||||
* <li>how decoded {@link Bitmap} will be displayed</li>
|
|
||||||
* </ul>
|
|
||||||
* <p/>
|
|
||||||
* You can create instance:
|
|
||||||
* <ul>
|
|
||||||
* <li>with {@link Builder}:<br />
|
|
||||||
* <b>i.e.</b> :
|
|
||||||
* <code>new {@link DisplayImageOptions}.{@link Builder#Builder() Builder()}.{@link Builder#cacheInMemory() cacheInMemory()}.
|
|
||||||
* {@link Builder#showImageOnLoading(int) showImageOnLoading()}.{@link Builder#build() build()}</code><br />
|
|
||||||
* </li>
|
|
||||||
* <li>or by static method: {@link #createSimple()}</li> <br />
|
|
||||||
*
|
|
||||||
* @author Sergey Tarasevich (nostra13[at]gmail[dot]com)
|
|
||||||
* @since 1.0.0
|
|
||||||
*/
|
|
||||||
public final class DisplayImageOptions {
|
|
||||||
|
|
||||||
private final int imageResOnLoading;
|
|
||||||
private final int imageResForEmptyUri;
|
|
||||||
private final int imageResOnFail;
|
|
||||||
private final Drawable imageOnLoading;
|
|
||||||
private final Drawable imageForEmptyUri;
|
|
||||||
private final Drawable imageOnFail;
|
|
||||||
private final boolean resetViewBeforeLoading;
|
|
||||||
private final boolean cacheInMemory;
|
|
||||||
private final boolean cacheOnDisk;
|
|
||||||
private final ImageScaleType imageScaleType;
|
|
||||||
private final Options decodingOptions;
|
|
||||||
private final int delayBeforeLoading;
|
|
||||||
private final boolean considerExifParams;
|
|
||||||
private final Object extraForDownloader;
|
|
||||||
private final BitmapProcessor preProcessor;
|
|
||||||
private final BitmapProcessor postProcessor;
|
|
||||||
private final BitmapDisplayer displayer;
|
|
||||||
private final Handler handler;
|
|
||||||
private final boolean isSyncLoading;
|
|
||||||
|
|
||||||
private DisplayImageOptions(Builder builder) {
|
|
||||||
imageResOnLoading = builder.imageResOnLoading;
|
|
||||||
imageResForEmptyUri = builder.imageResForEmptyUri;
|
|
||||||
imageResOnFail = builder.imageResOnFail;
|
|
||||||
imageOnLoading = builder.imageOnLoading;
|
|
||||||
imageForEmptyUri = builder.imageForEmptyUri;
|
|
||||||
imageOnFail = builder.imageOnFail;
|
|
||||||
resetViewBeforeLoading = builder.resetViewBeforeLoading;
|
|
||||||
cacheInMemory = builder.cacheInMemory;
|
|
||||||
cacheOnDisk = builder.cacheOnDisk;
|
|
||||||
imageScaleType = builder.imageScaleType;
|
|
||||||
decodingOptions = builder.decodingOptions;
|
|
||||||
delayBeforeLoading = builder.delayBeforeLoading;
|
|
||||||
considerExifParams = builder.considerExifParams;
|
|
||||||
extraForDownloader = builder.extraForDownloader;
|
|
||||||
preProcessor = builder.preProcessor;
|
|
||||||
postProcessor = builder.postProcessor;
|
|
||||||
displayer = builder.displayer;
|
|
||||||
handler = builder.handler;
|
|
||||||
isSyncLoading = builder.isSyncLoading;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean shouldShowImageOnLoading() {
|
|
||||||
return imageOnLoading != null || imageResOnLoading != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean shouldShowImageForEmptyUri() {
|
|
||||||
return imageForEmptyUri != null || imageResForEmptyUri != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean shouldShowImageOnFail() {
|
|
||||||
return imageOnFail != null || imageResOnFail != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean shouldPreProcess() {
|
|
||||||
return preProcessor != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean shouldPostProcess() {
|
|
||||||
return postProcessor != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean shouldDelayBeforeLoading() {
|
|
||||||
return delayBeforeLoading > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Drawable getImageOnLoading(Resources res) {
|
|
||||||
return imageResOnLoading != 0 ? res.getDrawable(imageResOnLoading) : imageOnLoading;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Drawable getImageForEmptyUri(Resources res) {
|
|
||||||
return imageResForEmptyUri != 0 ? res.getDrawable(imageResForEmptyUri) : imageForEmptyUri;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Drawable getImageOnFail(Resources res) {
|
|
||||||
return imageResOnFail != 0 ? res.getDrawable(imageResOnFail) : imageOnFail;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isResetViewBeforeLoading() {
|
|
||||||
return resetViewBeforeLoading;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isCacheInMemory() {
|
|
||||||
return cacheInMemory;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isCacheOnDisk() {
|
|
||||||
return cacheOnDisk;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ImageScaleType getImageScaleType() {
|
|
||||||
return imageScaleType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Options getDecodingOptions() {
|
|
||||||
return decodingOptions;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getDelayBeforeLoading() {
|
|
||||||
return delayBeforeLoading;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isConsiderExifParams() {
|
|
||||||
return considerExifParams;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object getExtraForDownloader() {
|
|
||||||
return extraForDownloader;
|
|
||||||
}
|
|
||||||
|
|
||||||
public BitmapProcessor getPreProcessor() {
|
|
||||||
return preProcessor;
|
|
||||||
}
|
|
||||||
|
|
||||||
public BitmapProcessor getPostProcessor() {
|
|
||||||
return postProcessor;
|
|
||||||
}
|
|
||||||
|
|
||||||
public BitmapDisplayer getDisplayer() {
|
|
||||||
return displayer;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Handler getHandler() {
|
|
||||||
return handler;
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean isSyncLoading() {
|
|
||||||
return isSyncLoading;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Builder for {@link DisplayImageOptions}
|
|
||||||
*
|
|
||||||
* @author Sergey Tarasevich (nostra13[at]gmail[dot]com)
|
|
||||||
*/
|
|
||||||
public static class Builder {
|
|
||||||
private int imageResOnLoading = 0;
|
|
||||||
private int imageResForEmptyUri = 0;
|
|
||||||
private int imageResOnFail = 0;
|
|
||||||
private Drawable imageOnLoading = null;
|
|
||||||
private Drawable imageForEmptyUri = null;
|
|
||||||
private Drawable imageOnFail = null;
|
|
||||||
private boolean resetViewBeforeLoading = false;
|
|
||||||
private boolean cacheInMemory = false;
|
|
||||||
private boolean cacheOnDisk = false;
|
|
||||||
private ImageScaleType imageScaleType = ImageScaleType.IN_SAMPLE_POWER_OF_2;
|
|
||||||
private Options decodingOptions = new Options();
|
|
||||||
private int delayBeforeLoading = 0;
|
|
||||||
private boolean considerExifParams = false;
|
|
||||||
private Object extraForDownloader = null;
|
|
||||||
private BitmapProcessor preProcessor = null;
|
|
||||||
private BitmapProcessor postProcessor = null;
|
|
||||||
private BitmapDisplayer displayer = DefaultConfigurationFactory.createBitmapDisplayer();
|
|
||||||
private Handler handler = null;
|
|
||||||
private boolean isSyncLoading = false;
|
|
||||||
|
|
||||||
public Builder() {
|
|
||||||
decodingOptions.inPurgeable = true;
|
|
||||||
decodingOptions.inInputShareable = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stub image will be displayed in {@link com.nostra13.universalimageloader.core.imageaware.ImageAware
|
|
||||||
* image aware view} during image loading
|
|
||||||
*
|
|
||||||
* @param imageRes Stub image resource
|
|
||||||
* @deprecated Use {@link #showImageOnLoading(int)} instead
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public Builder showStubImage(int imageRes) {
|
|
||||||
imageResOnLoading = imageRes;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Incoming image will be displayed in {@link com.nostra13.universalimageloader.core.imageaware.ImageAware
|
|
||||||
* image aware view} during image loading
|
|
||||||
*
|
|
||||||
* @param imageRes Image resource
|
|
||||||
*/
|
|
||||||
public Builder showImageOnLoading(int imageRes) {
|
|
||||||
imageResOnLoading = imageRes;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Incoming drawable will be displayed in {@link com.nostra13.universalimageloader.core.imageaware.ImageAware
|
|
||||||
* image aware view} during image loading.
|
|
||||||
* This option will be ignored if {@link DisplayImageOptions.Builder#showImageOnLoading(int)} is set.
|
|
||||||
*/
|
|
||||||
public Builder showImageOnLoading(Drawable drawable) {
|
|
||||||
imageOnLoading = drawable;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Incoming image will be displayed in {@link com.nostra13.universalimageloader.core.imageaware.ImageAware
|
|
||||||
* image aware view} if empty URI (null or empty
|
|
||||||
* string) will be passed to <b>ImageLoader.displayImage(...)</b> method.
|
|
||||||
*
|
|
||||||
* @param imageRes Image resource
|
|
||||||
*/
|
|
||||||
public Builder showImageForEmptyUri(int imageRes) {
|
|
||||||
imageResForEmptyUri = imageRes;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Incoming drawable will be displayed in {@link com.nostra13.universalimageloader.core.imageaware.ImageAware
|
|
||||||
* image aware view} if empty URI (null or empty
|
|
||||||
* string) will be passed to <b>ImageLoader.displayImage(...)</b> method.
|
|
||||||
* This option will be ignored if {@link DisplayImageOptions.Builder#showImageForEmptyUri(int)} is set.
|
|
||||||
*/
|
|
||||||
public Builder showImageForEmptyUri(Drawable drawable) {
|
|
||||||
imageForEmptyUri = drawable;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Incoming image will be displayed in {@link com.nostra13.universalimageloader.core.imageaware.ImageAware
|
|
||||||
* image aware view} if some error occurs during
|
|
||||||
* requested image loading/decoding.
|
|
||||||
*
|
|
||||||
* @param imageRes Image resource
|
|
||||||
*/
|
|
||||||
public Builder showImageOnFail(int imageRes) {
|
|
||||||
imageResOnFail = imageRes;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Incoming drawable will be displayed in {@link com.nostra13.universalimageloader.core.imageaware.ImageAware
|
|
||||||
* image aware view} if some error occurs during
|
|
||||||
* requested image loading/decoding.
|
|
||||||
* This option will be ignored if {@link DisplayImageOptions.Builder#showImageOnFail(int)} is set.
|
|
||||||
*/
|
|
||||||
public Builder showImageOnFail(Drawable drawable) {
|
|
||||||
imageOnFail = drawable;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@link com.nostra13.universalimageloader.core.imageaware.ImageAware
|
|
||||||
* image aware view} will be reset (set <b>null</b>) before image loading start
|
|
||||||
*
|
|
||||||
* @deprecated Use {@link #resetViewBeforeLoading(boolean) resetViewBeforeLoading(true)} instead
|
|
||||||
*/
|
|
||||||
public Builder resetViewBeforeLoading() {
|
|
||||||
resetViewBeforeLoading = true;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets whether {@link com.nostra13.universalimageloader.core.imageaware.ImageAware
|
|
||||||
* image aware view} will be reset (set <b>null</b>) before image loading start
|
|
||||||
*/
|
|
||||||
public Builder resetViewBeforeLoading(boolean resetViewBeforeLoading) {
|
|
||||||
this.resetViewBeforeLoading = resetViewBeforeLoading;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Loaded image will be cached in memory
|
|
||||||
*
|
|
||||||
* @deprecated Use {@link #cacheInMemory(boolean) cacheInMemory(true)} instead
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public Builder cacheInMemory() {
|
|
||||||
cacheInMemory = true;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Sets whether loaded image will be cached in memory */
|
|
||||||
public Builder cacheInMemory(boolean cacheInMemory) {
|
|
||||||
this.cacheInMemory = cacheInMemory;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Loaded image will be cached on disk
|
|
||||||
*
|
|
||||||
* @deprecated Use {@link #cacheOnDisk(boolean) cacheOnDisk(true)} instead
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public Builder cacheOnDisc() {
|
|
||||||
return cacheOnDisk(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets whether loaded image will be cached on disk
|
|
||||||
*
|
|
||||||
* @deprecated Use {@link #cacheOnDisk(boolean)} instead
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public Builder cacheOnDisc(boolean cacheOnDisk) {
|
|
||||||
return cacheOnDisk(cacheOnDisk);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Sets whether loaded image will be cached on disk */
|
|
||||||
public Builder cacheOnDisk(boolean cacheOnDisk) {
|
|
||||||
this.cacheOnDisk = cacheOnDisk;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets {@linkplain ImageScaleType scale type} for decoding image. This parameter is used while define scale
|
|
||||||
* size for decoding image to Bitmap. Default value - {@link ImageScaleType#IN_SAMPLE_POWER_OF_2}
|
|
||||||
*/
|
|
||||||
public Builder imageScaleType(ImageScaleType imageScaleType) {
|
|
||||||
this.imageScaleType = imageScaleType;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Sets {@link Bitmap.Config bitmap config} for image decoding. Default value - {@link Bitmap.Config#ARGB_8888} */
|
|
||||||
public Builder bitmapConfig(Bitmap.Config bitmapConfig) {
|
|
||||||
if (bitmapConfig == null) throw new IllegalArgumentException("bitmapConfig can't be null");
|
|
||||||
decodingOptions.inPreferredConfig = bitmapConfig;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets options for image decoding.<br />
|
|
||||||
* <b>NOTE:</b> {@link Options#inSampleSize} of incoming options will <b>NOT</b> be considered. Library
|
|
||||||
* calculate the most appropriate sample size itself according yo {@link #imageScaleType(ImageScaleType)}
|
|
||||||
* options.<br />
|
|
||||||
* <b>NOTE:</b> This option overlaps {@link #bitmapConfig(android.graphics.Bitmap.Config) bitmapConfig()}
|
|
||||||
* option.
|
|
||||||
*/
|
|
||||||
public Builder decodingOptions(Options decodingOptions) {
|
|
||||||
if (decodingOptions == null) throw new IllegalArgumentException("decodingOptions can't be null");
|
|
||||||
this.decodingOptions = decodingOptions;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Sets delay time before starting loading task. Default - no delay. */
|
|
||||||
public Builder delayBeforeLoading(int delayInMillis) {
|
|
||||||
this.delayBeforeLoading = delayInMillis;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Sets auxiliary object which will be passed to {@link ImageDownloader#getStream(String, Object)} */
|
|
||||||
public Builder extraForDownloader(Object extra) {
|
|
||||||
this.extraForDownloader = extra;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Sets whether ImageLoader will consider EXIF parameters of JPEG image (rotate, flip) */
|
|
||||||
public Builder considerExifParams(boolean considerExifParams) {
|
|
||||||
this.considerExifParams = considerExifParams;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets bitmap processor which will be process bitmaps before they will be cached in memory. So memory cache
|
|
||||||
* will contain bitmap processed by incoming preProcessor.<br />
|
|
||||||
* Image will be pre-processed even if caching in memory is disabled.
|
|
||||||
*/
|
|
||||||
public Builder preProcessor(BitmapProcessor preProcessor) {
|
|
||||||
this.preProcessor = preProcessor;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets bitmap processor which will be process bitmaps before they will be displayed in
|
|
||||||
* {@link com.nostra13.universalimageloader.core.imageaware.ImageAware image aware view} but
|
|
||||||
* after they'll have been saved in memory cache.
|
|
||||||
*/
|
|
||||||
public Builder postProcessor(BitmapProcessor postProcessor) {
|
|
||||||
this.postProcessor = postProcessor;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets custom {@link BitmapDisplayer displayer} for image loading task. Default value -
|
|
||||||
* {@link DefaultConfigurationFactory#createBitmapDisplayer()}
|
|
||||||
*/
|
|
||||||
public Builder displayer(BitmapDisplayer displayer) {
|
|
||||||
if (displayer == null) throw new IllegalArgumentException("displayer can't be null");
|
|
||||||
this.displayer = displayer;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
Builder syncLoading(boolean isSyncLoading) {
|
|
||||||
this.isSyncLoading = isSyncLoading;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets custom {@linkplain Handler handler} for displaying images and firing {@linkplain ImageLoadingListener
|
|
||||||
* listener} events.
|
|
||||||
*/
|
|
||||||
public Builder handler(Handler handler) {
|
|
||||||
this.handler = handler;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Sets all options equal to incoming options */
|
|
||||||
public Builder cloneFrom(DisplayImageOptions options) {
|
|
||||||
imageResOnLoading = options.imageResOnLoading;
|
|
||||||
imageResForEmptyUri = options.imageResForEmptyUri;
|
|
||||||
imageResOnFail = options.imageResOnFail;
|
|
||||||
imageOnLoading = options.imageOnLoading;
|
|
||||||
imageForEmptyUri = options.imageForEmptyUri;
|
|
||||||
imageOnFail = options.imageOnFail;
|
|
||||||
resetViewBeforeLoading = options.resetViewBeforeLoading;
|
|
||||||
cacheInMemory = options.cacheInMemory;
|
|
||||||
cacheOnDisk = options.cacheOnDisk;
|
|
||||||
imageScaleType = options.imageScaleType;
|
|
||||||
decodingOptions = options.decodingOptions;
|
|
||||||
delayBeforeLoading = options.delayBeforeLoading;
|
|
||||||
considerExifParams = options.considerExifParams;
|
|
||||||
extraForDownloader = options.extraForDownloader;
|
|
||||||
preProcessor = options.preProcessor;
|
|
||||||
postProcessor = options.postProcessor;
|
|
||||||
displayer = options.displayer;
|
|
||||||
handler = options.handler;
|
|
||||||
isSyncLoading = options.isSyncLoading;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Builds configured {@link DisplayImageOptions} object */
|
|
||||||
public DisplayImageOptions build() {
|
|
||||||
return new DisplayImageOptions(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates options appropriate for single displaying:
|
|
||||||
* <ul>
|
|
||||||
* <li>View will <b>not</b> be reset before loading</li>
|
|
||||||
* <li>Loaded image will <b>not</b> be cached in memory</li>
|
|
||||||
* <li>Loaded image will <b>not</b> be cached on disk</li>
|
|
||||||
* <li>{@link ImageScaleType#IN_SAMPLE_POWER_OF_2} decoding type will be used</li>
|
|
||||||
* <li>{@link Bitmap.Config#ARGB_8888} bitmap config will be used for image decoding</li>
|
|
||||||
* <li>{@link SimpleBitmapDisplayer} will be used for image displaying</li>
|
|
||||||
* </ul>
|
|
||||||
* <p/>
|
|
||||||
* These option are appropriate for simple single-use image (from drawables or from Internet) displaying.
|
|
||||||
*/
|
|
||||||
public static DisplayImageOptions createSimple() {
|
|
||||||
return new Builder().build();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,768 +0,0 @@
|
|||||||
/*******************************************************************************
|
|
||||||
* Copyright 2011-2014 Sergey Tarasevich
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*******************************************************************************/
|
|
||||||
package com.nostra13.universalimageloader.core;
|
|
||||||
|
|
||||||
import android.graphics.Bitmap;
|
|
||||||
import android.os.Handler;
|
|
||||||
import android.os.Looper;
|
|
||||||
import android.text.TextUtils;
|
|
||||||
import android.view.View;
|
|
||||||
import android.widget.ImageView;
|
|
||||||
import com.nostra13.universalimageloader.cache.disc.DiskCache;
|
|
||||||
import com.nostra13.universalimageloader.cache.memory.MemoryCache;
|
|
||||||
import com.nostra13.universalimageloader.core.assist.FailReason;
|
|
||||||
import com.nostra13.universalimageloader.core.assist.FlushedInputStream;
|
|
||||||
import com.nostra13.universalimageloader.core.assist.ImageSize;
|
|
||||||
import com.nostra13.universalimageloader.core.assist.LoadedFrom;
|
|
||||||
import com.nostra13.universalimageloader.core.assist.ViewScaleType;
|
|
||||||
import com.nostra13.universalimageloader.core.imageaware.ImageAware;
|
|
||||||
import com.nostra13.universalimageloader.core.imageaware.ImageViewAware;
|
|
||||||
import com.nostra13.universalimageloader.core.imageaware.NonViewAware;
|
|
||||||
import com.nostra13.universalimageloader.core.listener.ImageLoadingListener;
|
|
||||||
import com.nostra13.universalimageloader.core.listener.ImageLoadingProgressListener;
|
|
||||||
import com.nostra13.universalimageloader.core.listener.SimpleImageLoadingListener;
|
|
||||||
import com.nostra13.universalimageloader.utils.ImageSizeUtils;
|
|
||||||
import com.nostra13.universalimageloader.utils.L;
|
|
||||||
import com.nostra13.universalimageloader.utils.MemoryCacheUtils;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Singletone for image loading and displaying at {@link ImageView ImageViews}<br />
|
|
||||||
* <b>NOTE:</b> {@link #init(ImageLoaderConfiguration)} method must be called before any other method.
|
|
||||||
*
|
|
||||||
* @author Sergey Tarasevich (nostra13[at]gmail[dot]com)
|
|
||||||
* @since 1.0.0
|
|
||||||
*/
|
|
||||||
public class ImageLoader {
|
|
||||||
|
|
||||||
public static final String TAG = ImageLoader.class.getSimpleName();
|
|
||||||
|
|
||||||
static final String LOG_INIT_CONFIG = "Initialize ImageLoader with configuration";
|
|
||||||
static final String LOG_DESTROY = "Destroy ImageLoader";
|
|
||||||
static final String LOG_LOAD_IMAGE_FROM_MEMORY_CACHE = "Load image from memory cache [%s]";
|
|
||||||
|
|
||||||
private static final String WARNING_RE_INIT_CONFIG = "Try to initialize ImageLoader which had already been initialized before. " + "To re-init ImageLoader with new configuration call ImageLoader.destroy() at first.";
|
|
||||||
private static final String ERROR_WRONG_ARGUMENTS = "Wrong arguments were passed to displayImage() method (ImageView reference must not be null)";
|
|
||||||
private static final String ERROR_NOT_INIT = "ImageLoader must be init with configuration before using";
|
|
||||||
private static final String ERROR_INIT_CONFIG_WITH_NULL = "ImageLoader configuration can not be initialized with null";
|
|
||||||
|
|
||||||
private ImageLoaderConfiguration configuration;
|
|
||||||
private ImageLoaderEngine engine;
|
|
||||||
|
|
||||||
private ImageLoadingListener defaultListener = new SimpleImageLoadingListener();
|
|
||||||
|
|
||||||
private volatile static ImageLoader instance;
|
|
||||||
|
|
||||||
/** Returns singleton class instance */
|
|
||||||
public static ImageLoader getInstance() {
|
|
||||||
if (instance == null) {
|
|
||||||
synchronized (ImageLoader.class) {
|
|
||||||
if (instance == null) {
|
|
||||||
instance = new ImageLoader();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected ImageLoader() {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initializes ImageLoader instance with configuration.<br />
|
|
||||||
* If configurations was set before ( {@link #isInited()} == true) then this method does nothing.<br />
|
|
||||||
* To force initialization with new configuration you should {@linkplain #destroy() destroy ImageLoader} at first.
|
|
||||||
*
|
|
||||||
* @param configuration {@linkplain ImageLoaderConfiguration ImageLoader configuration}
|
|
||||||
* @throws IllegalArgumentException if <b>configuration</b> parameter is null
|
|
||||||
*/
|
|
||||||
public synchronized void init(ImageLoaderConfiguration configuration) {
|
|
||||||
if (configuration == null) {
|
|
||||||
throw new IllegalArgumentException(ERROR_INIT_CONFIG_WITH_NULL);
|
|
||||||
}
|
|
||||||
if (this.configuration == null) {
|
|
||||||
L.d(LOG_INIT_CONFIG);
|
|
||||||
engine = new ImageLoaderEngine(configuration);
|
|
||||||
this.configuration = configuration;
|
|
||||||
} else {
|
|
||||||
L.w(WARNING_RE_INIT_CONFIG);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns <b>true</b> - if ImageLoader {@linkplain #init(ImageLoaderConfiguration) is initialized with
|
|
||||||
* configuration}; <b>false</b> - otherwise
|
|
||||||
*/
|
|
||||||
public boolean isInited() {
|
|
||||||
return configuration != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds display image task to execution pool. Image will be set to ImageAware when it's turn. <br/>
|
|
||||||
* Default {@linkplain DisplayImageOptions display image options} from {@linkplain ImageLoaderConfiguration
|
|
||||||
* configuration} will be used.<br />
|
|
||||||
* <b>NOTE:</b> {@link #init(ImageLoaderConfiguration)} method must be called before this method call
|
|
||||||
*
|
|
||||||
* @param uri Image URI (i.e. "http://site.com/image.png", "file:///mnt/sdcard/image.png")
|
|
||||||
* @param imageAware {@linkplain com.nostra13.universalimageloader.core.imageaware.ImageAware Image aware view}
|
|
||||||
* which should display image
|
|
||||||
* @throws IllegalStateException if {@link #init(ImageLoaderConfiguration)} method wasn't called before
|
|
||||||
* @throws IllegalArgumentException if passed <b>imageAware</b> is null
|
|
||||||
*/
|
|
||||||
public void displayImage(String uri, ImageAware imageAware) {
|
|
||||||
displayImage(uri, imageAware, null, null, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds display image task to execution pool. Image will be set to ImageAware when it's turn.<br />
|
|
||||||
* Default {@linkplain DisplayImageOptions display image options} from {@linkplain ImageLoaderConfiguration
|
|
||||||
* configuration} will be used.<br />
|
|
||||||
* <b>NOTE:</b> {@link #init(ImageLoaderConfiguration)} method must be called before this method call
|
|
||||||
*
|
|
||||||
* @param uri Image URI (i.e. "http://site.com/image.png", "file:///mnt/sdcard/image.png")
|
|
||||||
* @param imageAware {@linkplain com.nostra13.universalimageloader.core.imageaware.ImageAware Image aware view}
|
|
||||||
* which should display image
|
|
||||||
* @param listener {@linkplain ImageLoadingListener Listener} for image loading process. Listener fires events on
|
|
||||||
* UI thread if this method is called on UI thread.
|
|
||||||
* @throws IllegalStateException if {@link #init(ImageLoaderConfiguration)} method wasn't called before
|
|
||||||
* @throws IllegalArgumentException if passed <b>imageAware</b> is null
|
|
||||||
*/
|
|
||||||
public void displayImage(String uri, ImageAware imageAware, ImageLoadingListener listener) {
|
|
||||||
displayImage(uri, imageAware, null, listener, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds display image task to execution pool. Image will be set to ImageAware when it's turn.<br />
|
|
||||||
* <b>NOTE:</b> {@link #init(ImageLoaderConfiguration)} method must be called before this method call
|
|
||||||
*
|
|
||||||
* @param uri Image URI (i.e. "http://site.com/image.png", "file:///mnt/sdcard/image.png")
|
|
||||||
* @param imageAware {@linkplain com.nostra13.universalimageloader.core.imageaware.ImageAware Image aware view}
|
|
||||||
* which should display image
|
|
||||||
* @param options {@linkplain com.nostra13.universalimageloader.core.DisplayImageOptions Options} for image
|
|
||||||
* decoding and displaying. If <b>null</b> - default display image options
|
|
||||||
* {@linkplain ImageLoaderConfiguration.Builder#defaultDisplayImageOptions(DisplayImageOptions)
|
|
||||||
* from configuration} will be used.
|
|
||||||
* @throws IllegalStateException if {@link #init(ImageLoaderConfiguration)} method wasn't called before
|
|
||||||
* @throws IllegalArgumentException if passed <b>imageAware</b> is null
|
|
||||||
*/
|
|
||||||
public void displayImage(String uri, ImageAware imageAware, DisplayImageOptions options) {
|
|
||||||
displayImage(uri, imageAware, options, null, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds display image task to execution pool. Image will be set to ImageAware when it's turn.<br />
|
|
||||||
* <b>NOTE:</b> {@link #init(ImageLoaderConfiguration)} method must be called before this method call
|
|
||||||
*
|
|
||||||
* @param uri Image URI (i.e. "http://site.com/image.png", "file:///mnt/sdcard/image.png")
|
|
||||||
* @param imageAware {@linkplain com.nostra13.universalimageloader.core.imageaware.ImageAware Image aware view}
|
|
||||||
* which should display image
|
|
||||||
* @param options {@linkplain com.nostra13.universalimageloader.core.DisplayImageOptions Options} for image
|
|
||||||
* decoding and displaying. If <b>null</b> - default display image options
|
|
||||||
* {@linkplain ImageLoaderConfiguration.Builder#defaultDisplayImageOptions(DisplayImageOptions)
|
|
||||||
* from configuration} will be used.
|
|
||||||
* @param listener {@linkplain ImageLoadingListener Listener} for image loading process. Listener fires events on
|
|
||||||
* UI thread if this method is called on UI thread.
|
|
||||||
* @throws IllegalStateException if {@link #init(ImageLoaderConfiguration)} method wasn't called before
|
|
||||||
* @throws IllegalArgumentException if passed <b>imageAware</b> is null
|
|
||||||
*/
|
|
||||||
public void displayImage(String uri, ImageAware imageAware, DisplayImageOptions options,
|
|
||||||
ImageLoadingListener listener) {
|
|
||||||
displayImage(uri, imageAware, options, listener, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds display image task to execution pool. Image will be set to ImageAware when it's turn.<br />
|
|
||||||
* <b>NOTE:</b> {@link #init(ImageLoaderConfiguration)} method must be called before this method call
|
|
||||||
*
|
|
||||||
* @param uri Image URI (i.e. "http://site.com/image.png", "file:///mnt/sdcard/image.png")
|
|
||||||
* @param imageAware {@linkplain com.nostra13.universalimageloader.core.imageaware.ImageAware Image aware view}
|
|
||||||
* which should display image
|
|
||||||
* @param options {@linkplain com.nostra13.universalimageloader.core.DisplayImageOptions Options} for image
|
|
||||||
* decoding and displaying. If <b>null</b> - default display image options
|
|
||||||
* {@linkplain ImageLoaderConfiguration.Builder#defaultDisplayImageOptions(DisplayImageOptions)
|
|
||||||
* from configuration} will be used.
|
|
||||||
* @param listener {@linkplain ImageLoadingListener Listener} for image loading process. Listener fires
|
|
||||||
* events on UI thread if this method is called on UI thread.
|
|
||||||
* @param progressListener {@linkplain com.nostra13.universalimageloader.core.listener.ImageLoadingProgressListener
|
|
||||||
* Listener} for image loading progress. Listener fires events on UI thread if this method
|
|
||||||
* is called on UI thread. Caching on disk should be enabled in
|
|
||||||
* {@linkplain com.nostra13.universalimageloader.core.DisplayImageOptions options} to make
|
|
||||||
* this listener work.
|
|
||||||
* @throws IllegalStateException if {@link #init(ImageLoaderConfiguration)} method wasn't called before
|
|
||||||
* @throws IllegalArgumentException if passed <b>imageAware</b> is null
|
|
||||||
*/
|
|
||||||
public void displayImage(String uri, ImageAware imageAware, DisplayImageOptions options,
|
|
||||||
ImageLoadingListener listener, ImageLoadingProgressListener progressListener) {
|
|
||||||
checkConfiguration();
|
|
||||||
if (imageAware == null) {
|
|
||||||
throw new IllegalArgumentException(ERROR_WRONG_ARGUMENTS);
|
|
||||||
}
|
|
||||||
if (listener == null) {
|
|
||||||
listener = defaultListener;
|
|
||||||
}
|
|
||||||
if (options == null) {
|
|
||||||
options = configuration.defaultDisplayImageOptions;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (TextUtils.isEmpty(uri)) {
|
|
||||||
engine.cancelDisplayTaskFor(imageAware);
|
|
||||||
listener.onLoadingStarted(uri, imageAware.getWrappedView());
|
|
||||||
if (options.shouldShowImageForEmptyUri()) {
|
|
||||||
imageAware.setImageDrawable(options.getImageForEmptyUri(configuration.resources));
|
|
||||||
} else {
|
|
||||||
imageAware.setImageDrawable(null);
|
|
||||||
}
|
|
||||||
listener.onLoadingComplete(uri, imageAware.getWrappedView(), null);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ImageSize targetSize = ImageSizeUtils.defineTargetSizeForView(imageAware, configuration.getMaxImageSize());
|
|
||||||
String memoryCacheKey = MemoryCacheUtils.generateKey(uri, targetSize);
|
|
||||||
engine.prepareDisplayTaskFor(imageAware, memoryCacheKey);
|
|
||||||
|
|
||||||
listener.onLoadingStarted(uri, imageAware.getWrappedView());
|
|
||||||
|
|
||||||
Bitmap bmp = configuration.memoryCache.get(memoryCacheKey);
|
|
||||||
if (bmp != null && !bmp.isRecycled()) {
|
|
||||||
L.d(LOG_LOAD_IMAGE_FROM_MEMORY_CACHE, memoryCacheKey);
|
|
||||||
|
|
||||||
if (options.shouldPostProcess()) {
|
|
||||||
ImageLoadingInfo imageLoadingInfo = new ImageLoadingInfo(uri, imageAware, targetSize, memoryCacheKey,
|
|
||||||
options, listener, progressListener, engine.getLockForUri(uri));
|
|
||||||
ProcessAndDisplayImageTask displayTask = new ProcessAndDisplayImageTask(engine, bmp, imageLoadingInfo,
|
|
||||||
defineHandler(options));
|
|
||||||
if (options.isSyncLoading()) {
|
|
||||||
displayTask.run();
|
|
||||||
} else {
|
|
||||||
engine.submit(displayTask);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
options.getDisplayer().display(bmp, imageAware, LoadedFrom.MEMORY_CACHE);
|
|
||||||
listener.onLoadingComplete(uri, imageAware.getWrappedView(), bmp);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (options.shouldShowImageOnLoading()) {
|
|
||||||
imageAware.setImageDrawable(options.getImageOnLoading(configuration.resources));
|
|
||||||
} else if (options.isResetViewBeforeLoading()) {
|
|
||||||
imageAware.setImageDrawable(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
ImageLoadingInfo imageLoadingInfo = new ImageLoadingInfo(uri, imageAware, targetSize, memoryCacheKey,
|
|
||||||
options, listener, progressListener, engine.getLockForUri(uri));
|
|
||||||
LoadAndDisplayImageTask displayTask = new LoadAndDisplayImageTask(engine, imageLoadingInfo,
|
|
||||||
defineHandler(options));
|
|
||||||
if (options.isSyncLoading()) {
|
|
||||||
displayTask.run();
|
|
||||||
} else {
|
|
||||||
engine.submit(displayTask);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds display image task to execution pool. Image will be set to ImageView when it's turn. <br/>
|
|
||||||
* Default {@linkplain DisplayImageOptions display image options} from {@linkplain ImageLoaderConfiguration
|
|
||||||
* configuration} will be used.<br />
|
|
||||||
* <b>NOTE:</b> {@link #init(ImageLoaderConfiguration)} method must be called before this method call
|
|
||||||
*
|
|
||||||
* @param uri Image URI (i.e. "http://site.com/image.png", "file:///mnt/sdcard/image.png")
|
|
||||||
* @param imageView {@link ImageView} which should display image
|
|
||||||
* @throws IllegalStateException if {@link #init(ImageLoaderConfiguration)} method wasn't called before
|
|
||||||
* @throws IllegalArgumentException if passed <b>imageView</b> is null
|
|
||||||
*/
|
|
||||||
public void displayImage(String uri, ImageView imageView) {
|
|
||||||
displayImage(uri, new ImageViewAware(imageView), null, null, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds display image task to execution pool. Image will be set to ImageView when it's turn.<br />
|
|
||||||
* <b>NOTE:</b> {@link #init(ImageLoaderConfiguration)} method must be called before this method call
|
|
||||||
*
|
|
||||||
* @param uri Image URI (i.e. "http://site.com/image.png", "file:///mnt/sdcard/image.png")
|
|
||||||
* @param imageView {@link ImageView} which should display image
|
|
||||||
* @param options {@linkplain com.nostra13.universalimageloader.core.DisplayImageOptions Options} for image
|
|
||||||
* decoding and displaying. If <b>null</b> - default display image options
|
|
||||||
* {@linkplain ImageLoaderConfiguration.Builder#defaultDisplayImageOptions(DisplayImageOptions)
|
|
||||||
* from configuration} will be used.
|
|
||||||
* @throws IllegalStateException if {@link #init(ImageLoaderConfiguration)} method wasn't called before
|
|
||||||
* @throws IllegalArgumentException if passed <b>imageView</b> is null
|
|
||||||
*/
|
|
||||||
public void displayImage(String uri, ImageView imageView, DisplayImageOptions options) {
|
|
||||||
displayImage(uri, new ImageViewAware(imageView), options, null, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds display image task to execution pool. Image will be set to ImageView when it's turn.<br />
|
|
||||||
* Default {@linkplain DisplayImageOptions display image options} from {@linkplain ImageLoaderConfiguration
|
|
||||||
* configuration} will be used.<br />
|
|
||||||
* <b>NOTE:</b> {@link #init(ImageLoaderConfiguration)} method must be called before this method call
|
|
||||||
*
|
|
||||||
* @param uri Image URI (i.e. "http://site.com/image.png", "file:///mnt/sdcard/image.png")
|
|
||||||
* @param imageView {@link ImageView} which should display image
|
|
||||||
* @param listener {@linkplain ImageLoadingListener Listener} for image loading process. Listener fires events on
|
|
||||||
* UI thread if this method is called on UI thread.
|
|
||||||
* @throws IllegalStateException if {@link #init(ImageLoaderConfiguration)} method wasn't called before
|
|
||||||
* @throws IllegalArgumentException if passed <b>imageView</b> is null
|
|
||||||
*/
|
|
||||||
public void displayImage(String uri, ImageView imageView, ImageLoadingListener listener) {
|
|
||||||
displayImage(uri, new ImageViewAware(imageView), null, listener, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds display image task to execution pool. Image will be set to ImageView when it's turn.<br />
|
|
||||||
* <b>NOTE:</b> {@link #init(ImageLoaderConfiguration)} method must be called before this method call
|
|
||||||
*
|
|
||||||
* @param uri Image URI (i.e. "http://site.com/image.png", "file:///mnt/sdcard/image.png")
|
|
||||||
* @param imageView {@link ImageView} which should display image
|
|
||||||
* @param options {@linkplain com.nostra13.universalimageloader.core.DisplayImageOptions Options} for image
|
|
||||||
* decoding and displaying. If <b>null</b> - default display image options
|
|
||||||
* {@linkplain ImageLoaderConfiguration.Builder#defaultDisplayImageOptions(DisplayImageOptions)
|
|
||||||
* from configuration} will be used.
|
|
||||||
* @param listener {@linkplain ImageLoadingListener Listener} for image loading process. Listener fires events on
|
|
||||||
* UI thread if this method is called on UI thread.
|
|
||||||
* @throws IllegalStateException if {@link #init(ImageLoaderConfiguration)} method wasn't called before
|
|
||||||
* @throws IllegalArgumentException if passed <b>imageView</b> is null
|
|
||||||
*/
|
|
||||||
public void displayImage(String uri, ImageView imageView, DisplayImageOptions options,
|
|
||||||
ImageLoadingListener listener) {
|
|
||||||
displayImage(uri, imageView, options, listener, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds display image task to execution pool. Image will be set to ImageView when it's turn.<br />
|
|
||||||
* <b>NOTE:</b> {@link #init(ImageLoaderConfiguration)} method must be called before this method call
|
|
||||||
*
|
|
||||||
* @param uri Image URI (i.e. "http://site.com/image.png", "file:///mnt/sdcard/image.png")
|
|
||||||
* @param imageView {@link ImageView} which should display image
|
|
||||||
* @param options {@linkplain com.nostra13.universalimageloader.core.DisplayImageOptions Options} for image
|
|
||||||
* decoding and displaying. If <b>null</b> - default display image options
|
|
||||||
* {@linkplain ImageLoaderConfiguration.Builder#defaultDisplayImageOptions(DisplayImageOptions)
|
|
||||||
* from configuration} will be used.
|
|
||||||
* @param listener {@linkplain ImageLoadingListener Listener} for image loading process. Listener fires
|
|
||||||
* events on UI thread if this method is called on UI thread.
|
|
||||||
* @param progressListener {@linkplain com.nostra13.universalimageloader.core.listener.ImageLoadingProgressListener
|
|
||||||
* Listener} for image loading progress. Listener fires events on UI thread if this method
|
|
||||||
* is called on UI thread. Caching on disk should be enabled in
|
|
||||||
* {@linkplain com.nostra13.universalimageloader.core.DisplayImageOptions options} to make
|
|
||||||
* this listener work.
|
|
||||||
* @throws IllegalStateException if {@link #init(ImageLoaderConfiguration)} method wasn't called before
|
|
||||||
* @throws IllegalArgumentException if passed <b>imageView</b> is null
|
|
||||||
*/
|
|
||||||
public void displayImage(String uri, ImageView imageView, DisplayImageOptions options,
|
|
||||||
ImageLoadingListener listener, ImageLoadingProgressListener progressListener) {
|
|
||||||
displayImage(uri, new ImageViewAware(imageView), options, listener, progressListener);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds load image task to execution pool. Image will be returned with
|
|
||||||
* {@link ImageLoadingListener#onLoadingComplete(String, android.view.View, android.graphics.Bitmap)} callback}.
|
|
||||||
* <br />
|
|
||||||
* <b>NOTE:</b> {@link #init(ImageLoaderConfiguration)} method must be called before this method call
|
|
||||||
*
|
|
||||||
* @param uri Image URI (i.e. "http://site.com/image.png", "file:///mnt/sdcard/image.png")
|
|
||||||
* @param listener {@linkplain ImageLoadingListener Listener} for image loading process. Listener fires events on UI
|
|
||||||
* thread if this method is called on UI thread.
|
|
||||||
* @throws IllegalStateException if {@link #init(ImageLoaderConfiguration)} method wasn't called before
|
|
||||||
*/
|
|
||||||
public void loadImage(String uri, ImageLoadingListener listener) {
|
|
||||||
loadImage(uri, null, null, listener, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds load image task to execution pool. Image will be returned with
|
|
||||||
* {@link ImageLoadingListener#onLoadingComplete(String, android.view.View, android.graphics.Bitmap)} callback}.
|
|
||||||
* <br />
|
|
||||||
* <b>NOTE:</b> {@link #init(ImageLoaderConfiguration)} method must be called before this method call
|
|
||||||
*
|
|
||||||
* @param uri Image URI (i.e. "http://site.com/image.png", "file:///mnt/sdcard/image.png")
|
|
||||||
* @param targetImageSize Minimal size for {@link Bitmap} which will be returned in
|
|
||||||
* {@linkplain ImageLoadingListener#onLoadingComplete(String, android.view.View,
|
|
||||||
* android.graphics.Bitmap)} callback}. Downloaded image will be decoded
|
|
||||||
* and scaled to {@link Bitmap} of the size which is <b>equal or larger</b> (usually a bit
|
|
||||||
* larger) than incoming targetImageSize.
|
|
||||||
* @param listener {@linkplain ImageLoadingListener Listener} for image loading process. Listener fires
|
|
||||||
* events on UI thread if this method is called on UI thread.
|
|
||||||
* @throws IllegalStateException if {@link #init(ImageLoaderConfiguration)} method wasn't called before
|
|
||||||
*/
|
|
||||||
public void loadImage(String uri, ImageSize targetImageSize, ImageLoadingListener listener) {
|
|
||||||
loadImage(uri, targetImageSize, null, listener, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds load image task to execution pool. Image will be returned with
|
|
||||||
* {@link ImageLoadingListener#onLoadingComplete(String, android.view.View, android.graphics.Bitmap)} callback}.
|
|
||||||
* <br />
|
|
||||||
* <b>NOTE:</b> {@link #init(ImageLoaderConfiguration)} method must be called before this method call
|
|
||||||
*
|
|
||||||
* @param uri Image URI (i.e. "http://site.com/image.png", "file:///mnt/sdcard/image.png")
|
|
||||||
* @param options {@linkplain com.nostra13.universalimageloader.core.DisplayImageOptions Options} for image
|
|
||||||
* decoding and displaying. If <b>null</b> - default display image options
|
|
||||||
* {@linkplain ImageLoaderConfiguration.Builder#defaultDisplayImageOptions(DisplayImageOptions) from
|
|
||||||
* configuration} will be used.<br />
|
|
||||||
* @param listener {@linkplain ImageLoadingListener Listener} for image loading process. Listener fires events on UI
|
|
||||||
* thread if this method is called on UI thread.
|
|
||||||
* @throws IllegalStateException if {@link #init(ImageLoaderConfiguration)} method wasn't called before
|
|
||||||
*/
|
|
||||||
public void loadImage(String uri, DisplayImageOptions options, ImageLoadingListener listener) {
|
|
||||||
loadImage(uri, null, options, listener, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds load image task to execution pool. Image will be returned with
|
|
||||||
* {@link ImageLoadingListener#onLoadingComplete(String, android.view.View, android.graphics.Bitmap)} callback}.
|
|
||||||
* <br />
|
|
||||||
* <b>NOTE:</b> {@link #init(ImageLoaderConfiguration)} method must be called before this method call
|
|
||||||
*
|
|
||||||
* @param uri Image URI (i.e. "http://site.com/image.png", "file:///mnt/sdcard/image.png")
|
|
||||||
* @param targetImageSize Minimal size for {@link Bitmap} which will be returned in
|
|
||||||
* {@linkplain ImageLoadingListener#onLoadingComplete(String, android.view.View,
|
|
||||||
* android.graphics.Bitmap)} callback}. Downloaded image will be decoded
|
|
||||||
* and scaled to {@link Bitmap} of the size which is <b>equal or larger</b> (usually a bit
|
|
||||||
* larger) than incoming targetImageSize.
|
|
||||||
* @param options {@linkplain com.nostra13.universalimageloader.core.DisplayImageOptions Options} for image
|
|
||||||
* decoding and displaying. If <b>null</b> - default display image options
|
|
||||||
* {@linkplain ImageLoaderConfiguration.Builder#defaultDisplayImageOptions(DisplayImageOptions)
|
|
||||||
* from configuration} will be used.<br />
|
|
||||||
* @param listener {@linkplain ImageLoadingListener Listener} for image loading process. Listener fires
|
|
||||||
* events on UI thread if this method is called on UI thread.
|
|
||||||
* @throws IllegalStateException if {@link #init(ImageLoaderConfiguration)} method wasn't called before
|
|
||||||
*/
|
|
||||||
public void loadImage(String uri, ImageSize targetImageSize, DisplayImageOptions options,
|
|
||||||
ImageLoadingListener listener) {
|
|
||||||
loadImage(uri, targetImageSize, options, listener, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds load image task to execution pool. Image will be returned with
|
|
||||||
* {@link ImageLoadingListener#onLoadingComplete(String, android.view.View, android.graphics.Bitmap)} callback}.
|
|
||||||
* <br />
|
|
||||||
* <b>NOTE:</b> {@link #init(ImageLoaderConfiguration)} method must be called before this method call
|
|
||||||
*
|
|
||||||
* @param uri Image URI (i.e. "http://site.com/image.png", "file:///mnt/sdcard/image.png")
|
|
||||||
* @param targetImageSize Minimal size for {@link Bitmap} which will be returned in
|
|
||||||
* {@linkplain ImageLoadingListener#onLoadingComplete(String, android.view.View,
|
|
||||||
* android.graphics.Bitmap)} callback}. Downloaded image will be decoded
|
|
||||||
* and scaled to {@link Bitmap} of the size which is <b>equal or larger</b> (usually a bit
|
|
||||||
* larger) than incoming targetImageSize.
|
|
||||||
* @param options {@linkplain com.nostra13.universalimageloader.core.DisplayImageOptions Options} for image
|
|
||||||
* decoding and displaying. If <b>null</b> - default display image options
|
|
||||||
* {@linkplain ImageLoaderConfiguration.Builder#defaultDisplayImageOptions(DisplayImageOptions)
|
|
||||||
* from configuration} will be used.<br />
|
|
||||||
* @param listener {@linkplain ImageLoadingListener Listener} for image loading process. Listener fires
|
|
||||||
* events on UI thread if this method is called on UI thread.
|
|
||||||
* @param progressListener {@linkplain com.nostra13.universalimageloader.core.listener.ImageLoadingProgressListener
|
|
||||||
* Listener} for image loading progress. Listener fires events on UI thread if this method
|
|
||||||
* is called on UI thread. Caching on disk should be enabled in
|
|
||||||
* {@linkplain com.nostra13.universalimageloader.core.DisplayImageOptions options} to make
|
|
||||||
* this listener work.
|
|
||||||
* @throws IllegalStateException if {@link #init(ImageLoaderConfiguration)} method wasn't called before
|
|
||||||
*/
|
|
||||||
public void loadImage(String uri, ImageSize targetImageSize, DisplayImageOptions options,
|
|
||||||
ImageLoadingListener listener, ImageLoadingProgressListener progressListener) {
|
|
||||||
checkConfiguration();
|
|
||||||
if (targetImageSize == null) {
|
|
||||||
targetImageSize = configuration.getMaxImageSize();
|
|
||||||
}
|
|
||||||
if (options == null) {
|
|
||||||
options = configuration.defaultDisplayImageOptions;
|
|
||||||
}
|
|
||||||
|
|
||||||
NonViewAware imageAware = new NonViewAware(uri, targetImageSize, ViewScaleType.CROP);
|
|
||||||
displayImage(uri, imageAware, options, listener, progressListener);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Loads and decodes image synchronously.<br />
|
|
||||||
* Default display image options
|
|
||||||
* {@linkplain ImageLoaderConfiguration.Builder#defaultDisplayImageOptions(DisplayImageOptions) from
|
|
||||||
* configuration} will be used.<br />
|
|
||||||
* <b>NOTE:</b> {@link #init(ImageLoaderConfiguration)} method must be called before this method call
|
|
||||||
*
|
|
||||||
* @param uri Image URI (i.e. "http://site.com/image.png", "file:///mnt/sdcard/image.png")
|
|
||||||
* @return Result image Bitmap. Can be <b>null</b> if image loading/decoding was failed or cancelled.
|
|
||||||
* @throws IllegalStateException if {@link #init(ImageLoaderConfiguration)} method wasn't called before
|
|
||||||
*/
|
|
||||||
public Bitmap loadImageSync(String uri) {
|
|
||||||
return loadImageSync(uri, null, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Loads and decodes image synchronously.<br />
|
|
||||||
* <b>NOTE:</b> {@link #init(ImageLoaderConfiguration)} method must be called before this method call
|
|
||||||
*
|
|
||||||
* @param uri Image URI (i.e. "http://site.com/image.png", "file:///mnt/sdcard/image.png")
|
|
||||||
* @param options {@linkplain com.nostra13.universalimageloader.core.DisplayImageOptions Options} for image
|
|
||||||
* decoding and scaling. If <b>null</b> - default display image options
|
|
||||||
* {@linkplain ImageLoaderConfiguration.Builder#defaultDisplayImageOptions(DisplayImageOptions) from
|
|
||||||
* configuration} will be used.
|
|
||||||
* @return Result image Bitmap. Can be <b>null</b> if image loading/decoding was failed or cancelled.
|
|
||||||
* @throws IllegalStateException if {@link #init(ImageLoaderConfiguration)} method wasn't called before
|
|
||||||
*/
|
|
||||||
public Bitmap loadImageSync(String uri, DisplayImageOptions options) {
|
|
||||||
return loadImageSync(uri, null, options);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Loads and decodes image synchronously.<br />
|
|
||||||
* Default display image options
|
|
||||||
* {@linkplain ImageLoaderConfiguration.Builder#defaultDisplayImageOptions(DisplayImageOptions) from
|
|
||||||
* configuration} will be used.<br />
|
|
||||||
* <b>NOTE:</b> {@link #init(ImageLoaderConfiguration)} method must be called before this method call
|
|
||||||
*
|
|
||||||
* @param uri Image URI (i.e. "http://site.com/image.png", "file:///mnt/sdcard/image.png")
|
|
||||||
* @param targetImageSize Minimal size for {@link Bitmap} which will be returned. Downloaded image will be decoded
|
|
||||||
* and scaled to {@link Bitmap} of the size which is <b>equal or larger</b> (usually a bit
|
|
||||||
* larger) than incoming targetImageSize.
|
|
||||||
* @return Result image Bitmap. Can be <b>null</b> if image loading/decoding was failed or cancelled.
|
|
||||||
* @throws IllegalStateException if {@link #init(ImageLoaderConfiguration)} method wasn't called before
|
|
||||||
*/
|
|
||||||
public Bitmap loadImageSync(String uri, ImageSize targetImageSize) {
|
|
||||||
return loadImageSync(uri, targetImageSize, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Loads and decodes image synchronously.<br />
|
|
||||||
* <b>NOTE:</b> {@link #init(ImageLoaderConfiguration)} method must be called before this method call
|
|
||||||
*
|
|
||||||
* @param uri Image URI (i.e. "http://site.com/image.png", "file:///mnt/sdcard/image.png")
|
|
||||||
* @param targetImageSize Minimal size for {@link Bitmap} which will be returned. Downloaded image will be decoded
|
|
||||||
* and scaled to {@link Bitmap} of the size which is <b>equal or larger</b> (usually a bit
|
|
||||||
* larger) than incoming targetImageSize.
|
|
||||||
* @param options {@linkplain com.nostra13.universalimageloader.core.DisplayImageOptions Options} for image
|
|
||||||
* decoding and scaling. If <b>null</b> - default display image options
|
|
||||||
* {@linkplain ImageLoaderConfiguration.Builder#defaultDisplayImageOptions(DisplayImageOptions)
|
|
||||||
* from configuration} will be used.
|
|
||||||
* @return Result image Bitmap. Can be <b>null</b> if image loading/decoding was failed or cancelled.
|
|
||||||
* @throws IllegalStateException if {@link #init(ImageLoaderConfiguration)} method wasn't called before
|
|
||||||
*/
|
|
||||||
public Bitmap loadImageSync(String uri, ImageSize targetImageSize, DisplayImageOptions options) {
|
|
||||||
if (options == null) {
|
|
||||||
options = configuration.defaultDisplayImageOptions;
|
|
||||||
}
|
|
||||||
options = new DisplayImageOptions.Builder().cloneFrom(options).syncLoading(true).build();
|
|
||||||
|
|
||||||
SyncImageLoadingListener listener = new SyncImageLoadingListener();
|
|
||||||
loadImage(uri, targetImageSize, options, listener);
|
|
||||||
return listener.getLoadedBitmap();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if ImageLoader's configuration was initialized
|
|
||||||
*
|
|
||||||
* @throws IllegalStateException if configuration wasn't initialized
|
|
||||||
*/
|
|
||||||
private void checkConfiguration() {
|
|
||||||
if (configuration == null) {
|
|
||||||
throw new IllegalStateException(ERROR_NOT_INIT);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Sets a default loading listener for all display and loading tasks. */
|
|
||||||
public void setDefaultLoadingListener(ImageLoadingListener listener) {
|
|
||||||
defaultListener = listener == null ? new SimpleImageLoadingListener() : listener;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns memory cache
|
|
||||||
*
|
|
||||||
* @throws IllegalStateException if {@link #init(ImageLoaderConfiguration)} method wasn't called before
|
|
||||||
*/
|
|
||||||
public MemoryCache getMemoryCache() {
|
|
||||||
checkConfiguration();
|
|
||||||
return configuration.memoryCache;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Clears memory cache
|
|
||||||
*
|
|
||||||
* @throws IllegalStateException if {@link #init(ImageLoaderConfiguration)} method wasn't called before
|
|
||||||
*/
|
|
||||||
public void clearMemoryCache() {
|
|
||||||
checkConfiguration();
|
|
||||||
configuration.memoryCache.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns disk cache
|
|
||||||
*
|
|
||||||
* @throws IllegalStateException if {@link #init(ImageLoaderConfiguration)} method wasn't called before
|
|
||||||
* @deprecated Use {@link #getDiskCache()} instead
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public DiskCache getDiscCache() {
|
|
||||||
return getDiskCache();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns disk cache
|
|
||||||
*
|
|
||||||
* @throws IllegalStateException if {@link #init(ImageLoaderConfiguration)} method wasn't called before
|
|
||||||
*/
|
|
||||||
public DiskCache getDiskCache() {
|
|
||||||
checkConfiguration();
|
|
||||||
return configuration.diskCache;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Clears disk cache.
|
|
||||||
*
|
|
||||||
* @throws IllegalStateException if {@link #init(ImageLoaderConfiguration)} method wasn't called before
|
|
||||||
* @deprecated Use {@link #clearDiskCache()} instead
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public void clearDiscCache() {
|
|
||||||
clearDiskCache();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Clears disk cache.
|
|
||||||
*
|
|
||||||
* @throws IllegalStateException if {@link #init(ImageLoaderConfiguration)} method wasn't called before
|
|
||||||
*/
|
|
||||||
public void clearDiskCache() {
|
|
||||||
checkConfiguration();
|
|
||||||
configuration.diskCache.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns URI of image which is loading at this moment into passed
|
|
||||||
* {@link com.nostra13.universalimageloader.core.imageaware.ImageAware ImageAware}
|
|
||||||
*/
|
|
||||||
public String getLoadingUriForView(ImageAware imageAware) {
|
|
||||||
return engine.getLoadingUriForView(imageAware);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns URI of image which is loading at this moment into passed
|
|
||||||
* {@link android.widget.ImageView ImageView}
|
|
||||||
*/
|
|
||||||
public String getLoadingUriForView(ImageView imageView) {
|
|
||||||
return engine.getLoadingUriForView(new ImageViewAware(imageView));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Cancel the task of loading and displaying image for passed
|
|
||||||
* {@link com.nostra13.universalimageloader.core.imageaware.ImageAware ImageAware}.
|
|
||||||
*
|
|
||||||
* @param imageAware {@link com.nostra13.universalimageloader.core.imageaware.ImageAware ImageAware} for
|
|
||||||
* which display task will be cancelled
|
|
||||||
*/
|
|
||||||
public void cancelDisplayTask(ImageAware imageAware) {
|
|
||||||
engine.cancelDisplayTaskFor(imageAware);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Cancel the task of loading and displaying image for passed
|
|
||||||
* {@link android.widget.ImageView ImageView}.
|
|
||||||
*
|
|
||||||
* @param imageView {@link android.widget.ImageView ImageView} for which display task will be cancelled
|
|
||||||
*/
|
|
||||||
public void cancelDisplayTask(ImageView imageView) {
|
|
||||||
engine.cancelDisplayTaskFor(new ImageViewAware(imageView));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Denies or allows ImageLoader to download images from the network.<br />
|
|
||||||
* <br />
|
|
||||||
* If downloads are denied and if image isn't cached then
|
|
||||||
* {@link ImageLoadingListener#onLoadingFailed(String, View, FailReason)} callback will be fired with
|
|
||||||
* {@link FailReason.FailType#NETWORK_DENIED}
|
|
||||||
*
|
|
||||||
* @param denyNetworkDownloads pass <b>true</b> - to deny engine to download images from the network; <b>false</b> -
|
|
||||||
* to allow engine to download images from network.
|
|
||||||
*/
|
|
||||||
public void denyNetworkDownloads(boolean denyNetworkDownloads) {
|
|
||||||
engine.denyNetworkDownloads(denyNetworkDownloads);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets option whether ImageLoader will use {@link FlushedInputStream} for network downloads to handle <a
|
|
||||||
* href="http://code.google.com/p/android/issues/detail?id=6066">this known problem</a> or not.
|
|
||||||
*
|
|
||||||
* @param handleSlowNetwork pass <b>true</b> - to use {@link FlushedInputStream} for network downloads; <b>false</b>
|
|
||||||
* - otherwise.
|
|
||||||
*/
|
|
||||||
public void handleSlowNetwork(boolean handleSlowNetwork) {
|
|
||||||
engine.handleSlowNetwork(handleSlowNetwork);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Pause ImageLoader. All new "load&display" tasks won't be executed until ImageLoader is {@link #resume() resumed}.
|
|
||||||
* <br />
|
|
||||||
* Already running tasks are not paused.
|
|
||||||
*/
|
|
||||||
public void pause() {
|
|
||||||
engine.pause();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Resumes waiting "load&display" tasks */
|
|
||||||
public void resume() {
|
|
||||||
engine.resume();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Cancels all running and scheduled display image tasks.<br />
|
|
||||||
* <b>NOTE:</b> This method doesn't shutdown
|
|
||||||
* {@linkplain com.nostra13.universalimageloader.core.ImageLoaderConfiguration.Builder#taskExecutor(java.util.concurrent.Executor)
|
|
||||||
* custom task executors} if you set them.<br />
|
|
||||||
* ImageLoader still can be used after calling this method.
|
|
||||||
*/
|
|
||||||
public void stop() {
|
|
||||||
engine.stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@linkplain #stop() Stops ImageLoader} and clears current configuration. <br />
|
|
||||||
* You can {@linkplain #init(ImageLoaderConfiguration) init} ImageLoader with new configuration after calling this
|
|
||||||
* method.
|
|
||||||
*/
|
|
||||||
public void destroy() {
|
|
||||||
if (configuration != null) L.d(LOG_DESTROY);
|
|
||||||
stop();
|
|
||||||
configuration.diskCache.close();
|
|
||||||
engine = null;
|
|
||||||
configuration = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Handler defineHandler(DisplayImageOptions options) {
|
|
||||||
Handler handler = options.getHandler();
|
|
||||||
if (options.isSyncLoading()) {
|
|
||||||
handler = null;
|
|
||||||
} else if (handler == null && Looper.myLooper() == Looper.getMainLooper()) {
|
|
||||||
handler = new Handler();
|
|
||||||
}
|
|
||||||
return handler;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Listener which is designed for synchronous image loading.
|
|
||||||
*
|
|
||||||
* @author Sergey Tarasevich (nostra13[at]gmail[dot]com)
|
|
||||||
* @since 1.9.0
|
|
||||||
*/
|
|
||||||
private static class SyncImageLoadingListener extends SimpleImageLoadingListener {
|
|
||||||
|
|
||||||
private Bitmap loadedImage;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
|
|
||||||
this.loadedImage = loadedImage;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Bitmap getLoadedBitmap() {
|
|
||||||
return loadedImage;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,655 +0,0 @@
|
|||||||
/*******************************************************************************
|
|
||||||
* Copyright 2011-2014 Sergey Tarasevich
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*******************************************************************************/
|
|
||||||
package com.nostra13.universalimageloader.core;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.res.Resources;
|
|
||||||
import android.util.DisplayMetrics;
|
|
||||||
import com.nostra13.universalimageloader.cache.disc.DiskCache;
|
|
||||||
import com.nostra13.universalimageloader.cache.disc.naming.FileNameGenerator;
|
|
||||||
import com.nostra13.universalimageloader.cache.memory.MemoryCache;
|
|
||||||
import com.nostra13.universalimageloader.cache.memory.impl.FuzzyKeyMemoryCache;
|
|
||||||
import com.nostra13.universalimageloader.core.assist.FlushedInputStream;
|
|
||||||
import com.nostra13.universalimageloader.core.assist.ImageSize;
|
|
||||||
import com.nostra13.universalimageloader.core.assist.QueueProcessingType;
|
|
||||||
import com.nostra13.universalimageloader.core.decode.ImageDecoder;
|
|
||||||
import com.nostra13.universalimageloader.core.download.ImageDownloader;
|
|
||||||
import com.nostra13.universalimageloader.core.process.BitmapProcessor;
|
|
||||||
import com.nostra13.universalimageloader.utils.L;
|
|
||||||
import com.nostra13.universalimageloader.utils.MemoryCacheUtils;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.util.concurrent.Executor;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Presents configuration for {@link ImageLoader}
|
|
||||||
*
|
|
||||||
* @author Sergey Tarasevich (nostra13[at]gmail[dot]com)
|
|
||||||
* @see ImageLoader
|
|
||||||
* @see MemoryCache
|
|
||||||
* @see DiskCache
|
|
||||||
* @see DisplayImageOptions
|
|
||||||
* @see ImageDownloader
|
|
||||||
* @see FileNameGenerator
|
|
||||||
* @since 1.0.0
|
|
||||||
*/
|
|
||||||
public final class ImageLoaderConfiguration {
|
|
||||||
|
|
||||||
final Resources resources;
|
|
||||||
|
|
||||||
final int maxImageWidthForMemoryCache;
|
|
||||||
final int maxImageHeightForMemoryCache;
|
|
||||||
final int maxImageWidthForDiskCache;
|
|
||||||
final int maxImageHeightForDiskCache;
|
|
||||||
final BitmapProcessor processorForDiskCache;
|
|
||||||
|
|
||||||
final Executor taskExecutor;
|
|
||||||
final Executor taskExecutorForCachedImages;
|
|
||||||
final boolean customExecutor;
|
|
||||||
final boolean customExecutorForCachedImages;
|
|
||||||
|
|
||||||
final int threadPoolSize;
|
|
||||||
final int threadPriority;
|
|
||||||
final QueueProcessingType tasksProcessingType;
|
|
||||||
|
|
||||||
final MemoryCache memoryCache;
|
|
||||||
final DiskCache diskCache;
|
|
||||||
final ImageDownloader downloader;
|
|
||||||
final ImageDecoder decoder;
|
|
||||||
final DisplayImageOptions defaultDisplayImageOptions;
|
|
||||||
|
|
||||||
final ImageDownloader networkDeniedDownloader;
|
|
||||||
final ImageDownloader slowNetworkDownloader;
|
|
||||||
|
|
||||||
private ImageLoaderConfiguration(final Builder builder) {
|
|
||||||
resources = builder.context.getResources();
|
|
||||||
maxImageWidthForMemoryCache = builder.maxImageWidthForMemoryCache;
|
|
||||||
maxImageHeightForMemoryCache = builder.maxImageHeightForMemoryCache;
|
|
||||||
maxImageWidthForDiskCache = builder.maxImageWidthForDiskCache;
|
|
||||||
maxImageHeightForDiskCache = builder.maxImageHeightForDiskCache;
|
|
||||||
processorForDiskCache = builder.processorForDiskCache;
|
|
||||||
taskExecutor = builder.taskExecutor;
|
|
||||||
taskExecutorForCachedImages = builder.taskExecutorForCachedImages;
|
|
||||||
threadPoolSize = builder.threadPoolSize;
|
|
||||||
threadPriority = builder.threadPriority;
|
|
||||||
tasksProcessingType = builder.tasksProcessingType;
|
|
||||||
diskCache = builder.diskCache;
|
|
||||||
memoryCache = builder.memoryCache;
|
|
||||||
defaultDisplayImageOptions = builder.defaultDisplayImageOptions;
|
|
||||||
downloader = builder.downloader;
|
|
||||||
decoder = builder.decoder;
|
|
||||||
|
|
||||||
customExecutor = builder.customExecutor;
|
|
||||||
customExecutorForCachedImages = builder.customExecutorForCachedImages;
|
|
||||||
|
|
||||||
networkDeniedDownloader = new NetworkDeniedImageDownloader(downloader);
|
|
||||||
slowNetworkDownloader = new SlowNetworkImageDownloader(downloader);
|
|
||||||
|
|
||||||
L.writeDebugLogs(builder.writeLogs);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates default configuration for {@link ImageLoader} <br />
|
|
||||||
* <b>Default values:</b>
|
|
||||||
* <ul>
|
|
||||||
* <li>maxImageWidthForMemoryCache = device's screen width</li>
|
|
||||||
* <li>maxImageHeightForMemoryCache = device's screen height</li>
|
|
||||||
* <li>maxImageWidthForDikcCache = unlimited</li>
|
|
||||||
* <li>maxImageHeightForDiskCache = unlimited</li>
|
|
||||||
* <li>threadPoolSize = {@link Builder#DEFAULT_THREAD_POOL_SIZE this}</li>
|
|
||||||
* <li>threadPriority = {@link Builder#DEFAULT_THREAD_PRIORITY this}</li>
|
|
||||||
* <li>allow to cache different sizes of image in memory</li>
|
|
||||||
* <li>memoryCache = {@link DefaultConfigurationFactory#createMemoryCache(android.content.Context, int)}</li>
|
|
||||||
* <li>diskCache = {@link com.nostra13.universalimageloader.cache.disc.impl.UnlimitedDiskCache}</li>
|
|
||||||
* <li>imageDownloader = {@link DefaultConfigurationFactory#createImageDownloader(Context)}</li>
|
|
||||||
* <li>imageDecoder = {@link DefaultConfigurationFactory#createImageDecoder(boolean)}</li>
|
|
||||||
* <li>diskCacheFileNameGenerator = {@link DefaultConfigurationFactory#createFileNameGenerator()}</li>
|
|
||||||
* <li>defaultDisplayImageOptions = {@link DisplayImageOptions#createSimple() Simple options}</li>
|
|
||||||
* <li>tasksProcessingOrder = {@link QueueProcessingType#FIFO}</li>
|
|
||||||
* <li>detailed logging disabled</li>
|
|
||||||
* </ul>
|
|
||||||
*/
|
|
||||||
public static ImageLoaderConfiguration createDefault(Context context) {
|
|
||||||
return new Builder(context).build();
|
|
||||||
}
|
|
||||||
|
|
||||||
ImageSize getMaxImageSize() {
|
|
||||||
DisplayMetrics displayMetrics = resources.getDisplayMetrics();
|
|
||||||
|
|
||||||
int width = maxImageWidthForMemoryCache;
|
|
||||||
if (width <= 0) {
|
|
||||||
width = displayMetrics.widthPixels;
|
|
||||||
}
|
|
||||||
int height = maxImageHeightForMemoryCache;
|
|
||||||
if (height <= 0) {
|
|
||||||
height = displayMetrics.heightPixels;
|
|
||||||
}
|
|
||||||
return new ImageSize(width, height);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Builder for {@link ImageLoaderConfiguration}
|
|
||||||
*
|
|
||||||
* @author Sergey Tarasevich (nostra13[at]gmail[dot]com)
|
|
||||||
*/
|
|
||||||
public static class Builder {
|
|
||||||
|
|
||||||
private static final String WARNING_OVERLAP_DISK_CACHE_PARAMS = "diskCache(), diskCacheSize() and diskCacheFileCount calls overlap each other";
|
|
||||||
private static final String WARNING_OVERLAP_DISK_CACHE_NAME_GENERATOR = "diskCache() and diskCacheFileNameGenerator() calls overlap each other";
|
|
||||||
private static final String WARNING_OVERLAP_MEMORY_CACHE = "memoryCache() and memoryCacheSize() calls overlap each other";
|
|
||||||
private static final String WARNING_OVERLAP_EXECUTOR = "threadPoolSize(), threadPriority() and tasksProcessingOrder() calls "
|
|
||||||
+ "can overlap taskExecutor() and taskExecutorForCachedImages() calls.";
|
|
||||||
|
|
||||||
/** {@value} */
|
|
||||||
public static final int DEFAULT_THREAD_POOL_SIZE = 3;
|
|
||||||
/** {@value} */
|
|
||||||
public static final int DEFAULT_THREAD_PRIORITY = Thread.NORM_PRIORITY - 2;
|
|
||||||
/** {@value} */
|
|
||||||
public static final QueueProcessingType DEFAULT_TASK_PROCESSING_TYPE = QueueProcessingType.FIFO;
|
|
||||||
|
|
||||||
private Context context;
|
|
||||||
|
|
||||||
private int maxImageWidthForMemoryCache = 0;
|
|
||||||
private int maxImageHeightForMemoryCache = 0;
|
|
||||||
private int maxImageWidthForDiskCache = 0;
|
|
||||||
private int maxImageHeightForDiskCache = 0;
|
|
||||||
private BitmapProcessor processorForDiskCache = null;
|
|
||||||
|
|
||||||
private Executor taskExecutor = null;
|
|
||||||
private Executor taskExecutorForCachedImages = null;
|
|
||||||
private boolean customExecutor = false;
|
|
||||||
private boolean customExecutorForCachedImages = false;
|
|
||||||
|
|
||||||
private int threadPoolSize = DEFAULT_THREAD_POOL_SIZE;
|
|
||||||
private int threadPriority = DEFAULT_THREAD_PRIORITY;
|
|
||||||
private boolean denyCacheImageMultipleSizesInMemory = false;
|
|
||||||
private QueueProcessingType tasksProcessingType = DEFAULT_TASK_PROCESSING_TYPE;
|
|
||||||
|
|
||||||
private int memoryCacheSize = 0;
|
|
||||||
private long diskCacheSize = 0;
|
|
||||||
private int diskCacheFileCount = 0;
|
|
||||||
|
|
||||||
private MemoryCache memoryCache = null;
|
|
||||||
private DiskCache diskCache = null;
|
|
||||||
private FileNameGenerator diskCacheFileNameGenerator = null;
|
|
||||||
private ImageDownloader downloader = null;
|
|
||||||
private ImageDecoder decoder;
|
|
||||||
private DisplayImageOptions defaultDisplayImageOptions = null;
|
|
||||||
|
|
||||||
private boolean writeLogs = false;
|
|
||||||
|
|
||||||
public Builder(Context context) {
|
|
||||||
this.context = context.getApplicationContext();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets options for memory cache
|
|
||||||
*
|
|
||||||
* @param maxImageWidthForMemoryCache Maximum image width which will be used for memory saving during decoding
|
|
||||||
* an image to {@link android.graphics.Bitmap Bitmap}. <b>Default value - device's screen width</b>
|
|
||||||
* @param maxImageHeightForMemoryCache Maximum image height which will be used for memory saving during decoding
|
|
||||||
* an image to {@link android.graphics.Bitmap Bitmap}. <b>Default value</b> - device's screen height
|
|
||||||
*/
|
|
||||||
public Builder memoryCacheExtraOptions(int maxImageWidthForMemoryCache, int maxImageHeightForMemoryCache) {
|
|
||||||
this.maxImageWidthForMemoryCache = maxImageWidthForMemoryCache;
|
|
||||||
this.maxImageHeightForMemoryCache = maxImageHeightForMemoryCache;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated Use
|
|
||||||
* {@link #diskCacheExtraOptions(int, int, com.nostra13.universalimageloader.core.process.BitmapProcessor)}
|
|
||||||
* instead
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public Builder discCacheExtraOptions(int maxImageWidthForDiskCache, int maxImageHeightForDiskCache,
|
|
||||||
BitmapProcessor processorForDiskCache) {
|
|
||||||
return diskCacheExtraOptions(maxImageWidthForDiskCache, maxImageHeightForDiskCache, processorForDiskCache);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets options for resizing/compressing of downloaded images before saving to disk cache.<br />
|
|
||||||
* <b>NOTE: Use this option only when you have appropriate needs. It can make ImageLoader slower.</b>
|
|
||||||
*
|
|
||||||
* @param maxImageWidthForDiskCache Maximum width of downloaded images for saving at disk cache
|
|
||||||
* @param maxImageHeightForDiskCache Maximum height of downloaded images for saving at disk cache
|
|
||||||
* @param processorForDiskCache null-ok; {@linkplain BitmapProcessor Bitmap processor} which process images before saving them in disc cache
|
|
||||||
*/
|
|
||||||
public Builder diskCacheExtraOptions(int maxImageWidthForDiskCache, int maxImageHeightForDiskCache,
|
|
||||||
BitmapProcessor processorForDiskCache) {
|
|
||||||
this.maxImageWidthForDiskCache = maxImageWidthForDiskCache;
|
|
||||||
this.maxImageHeightForDiskCache = maxImageHeightForDiskCache;
|
|
||||||
this.processorForDiskCache = processorForDiskCache;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets custom {@linkplain Executor executor} for tasks of loading and displaying images.<br />
|
|
||||||
* <br />
|
|
||||||
* <b>NOTE:</b> If you set custom executor then following configuration options will not be considered for this
|
|
||||||
* executor:
|
|
||||||
* <ul>
|
|
||||||
* <li>{@link #threadPoolSize(int)}</li>
|
|
||||||
* <li>{@link #threadPriority(int)}</li>
|
|
||||||
* <li>{@link #tasksProcessingOrder(QueueProcessingType)}</li>
|
|
||||||
* </ul>
|
|
||||||
*
|
|
||||||
* @see #taskExecutorForCachedImages(Executor)
|
|
||||||
*/
|
|
||||||
public Builder taskExecutor(Executor executor) {
|
|
||||||
if (threadPoolSize != DEFAULT_THREAD_POOL_SIZE || threadPriority != DEFAULT_THREAD_PRIORITY || tasksProcessingType != DEFAULT_TASK_PROCESSING_TYPE) {
|
|
||||||
L.w(WARNING_OVERLAP_EXECUTOR);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.taskExecutor = executor;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets custom {@linkplain Executor executor} for tasks of displaying <b>cached on disk</b> images (these tasks
|
|
||||||
* are executed quickly so UIL prefer to use separate executor for them).<br />
|
|
||||||
* <br />
|
|
||||||
* If you set the same executor for {@linkplain #taskExecutor(Executor) general tasks} and
|
|
||||||
* tasks about cached images (this method) then these tasks will be in the
|
|
||||||
* same thread pool. So short-lived tasks can wait a long time for their turn.<br />
|
|
||||||
* <br />
|
|
||||||
* <b>NOTE:</b> If you set custom executor then following configuration options will not be considered for this
|
|
||||||
* executor:
|
|
||||||
* <ul>
|
|
||||||
* <li>{@link #threadPoolSize(int)}</li>
|
|
||||||
* <li>{@link #threadPriority(int)}</li>
|
|
||||||
* <li>{@link #tasksProcessingOrder(QueueProcessingType)}</li>
|
|
||||||
* </ul>
|
|
||||||
*
|
|
||||||
* @see #taskExecutor(Executor)
|
|
||||||
*/
|
|
||||||
public Builder taskExecutorForCachedImages(Executor executorForCachedImages) {
|
|
||||||
if (threadPoolSize != DEFAULT_THREAD_POOL_SIZE || threadPriority != DEFAULT_THREAD_PRIORITY || tasksProcessingType != DEFAULT_TASK_PROCESSING_TYPE) {
|
|
||||||
L.w(WARNING_OVERLAP_EXECUTOR);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.taskExecutorForCachedImages = executorForCachedImages;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets thread pool size for image display tasks.<br />
|
|
||||||
* Default value - {@link #DEFAULT_THREAD_POOL_SIZE this}
|
|
||||||
*/
|
|
||||||
public Builder threadPoolSize(int threadPoolSize) {
|
|
||||||
if (taskExecutor != null || taskExecutorForCachedImages != null) {
|
|
||||||
L.w(WARNING_OVERLAP_EXECUTOR);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.threadPoolSize = threadPoolSize;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the priority for image loading threads. Should be <b>NOT</b> greater than {@link Thread#MAX_PRIORITY} or
|
|
||||||
* less than {@link Thread#MIN_PRIORITY}<br />
|
|
||||||
* Default value - {@link #DEFAULT_THREAD_PRIORITY this}
|
|
||||||
*/
|
|
||||||
public Builder threadPriority(int threadPriority) {
|
|
||||||
if (taskExecutor != null || taskExecutorForCachedImages != null) {
|
|
||||||
L.w(WARNING_OVERLAP_EXECUTOR);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (threadPriority < Thread.MIN_PRIORITY) {
|
|
||||||
this.threadPriority = Thread.MIN_PRIORITY;
|
|
||||||
} else {
|
|
||||||
if (threadPriority > Thread.MAX_PRIORITY) {
|
|
||||||
this.threadPriority = Thread.MAX_PRIORITY;
|
|
||||||
} else {
|
|
||||||
this.threadPriority = threadPriority;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* When you display an image in a small {@link android.widget.ImageView ImageView} and later you try to display
|
|
||||||
* this image (from identical URI) in a larger {@link android.widget.ImageView ImageView} so decoded image of
|
|
||||||
* bigger size will be cached in memory as a previous decoded image of smaller size.<br />
|
|
||||||
* So <b>the default behavior is to allow to cache multiple sizes of one image in memory</b>. You can
|
|
||||||
* <b>deny</b> it by calling <b>this</b> method: so when some image will be cached in memory then previous
|
|
||||||
* cached size of this image (if it exists) will be removed from memory cache before.
|
|
||||||
*/
|
|
||||||
public Builder denyCacheImageMultipleSizesInMemory() {
|
|
||||||
this.denyCacheImageMultipleSizesInMemory = true;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets type of queue processing for tasks for loading and displaying images.<br />
|
|
||||||
* Default value - {@link QueueProcessingType#FIFO}
|
|
||||||
*/
|
|
||||||
public Builder tasksProcessingOrder(QueueProcessingType tasksProcessingType) {
|
|
||||||
if (taskExecutor != null || taskExecutorForCachedImages != null) {
|
|
||||||
L.w(WARNING_OVERLAP_EXECUTOR);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.tasksProcessingType = tasksProcessingType;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets maximum memory cache size for {@link android.graphics.Bitmap bitmaps} (in bytes).<br />
|
|
||||||
* Default value - 1/8 of available app memory.<br />
|
|
||||||
* <b>NOTE:</b> If you use this method then
|
|
||||||
* {@link com.nostra13.universalimageloader.cache.memory.impl.LruMemoryCache LruMemoryCache} will be used as
|
|
||||||
* memory cache. You can use {@link #memoryCache(MemoryCache)} method to set your own implementation of
|
|
||||||
* {@link MemoryCache}.
|
|
||||||
*/
|
|
||||||
public Builder memoryCacheSize(int memoryCacheSize) {
|
|
||||||
if (memoryCacheSize <= 0) throw new IllegalArgumentException("memoryCacheSize must be a positive number");
|
|
||||||
|
|
||||||
if (memoryCache != null) {
|
|
||||||
L.w(WARNING_OVERLAP_MEMORY_CACHE);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.memoryCacheSize = memoryCacheSize;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets maximum memory cache size (in percent of available app memory) for {@link android.graphics.Bitmap
|
|
||||||
* bitmaps}.<br />
|
|
||||||
* Default value - 1/8 of available app memory.<br />
|
|
||||||
* <b>NOTE:</b> If you use this method then
|
|
||||||
* {@link com.nostra13.universalimageloader.cache.memory.impl.LruMemoryCache LruMemoryCache} will be used as
|
|
||||||
* memory cache. You can use {@link #memoryCache(MemoryCache)} method to set your own implementation of
|
|
||||||
* {@link MemoryCache}.
|
|
||||||
*/
|
|
||||||
public Builder memoryCacheSizePercentage(int availableMemoryPercent) {
|
|
||||||
if (availableMemoryPercent <= 0 || availableMemoryPercent >= 100) {
|
|
||||||
throw new IllegalArgumentException("availableMemoryPercent must be in range (0 < % < 100)");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (memoryCache != null) {
|
|
||||||
L.w(WARNING_OVERLAP_MEMORY_CACHE);
|
|
||||||
}
|
|
||||||
|
|
||||||
long availableMemory = Runtime.getRuntime().maxMemory();
|
|
||||||
memoryCacheSize = (int) (availableMemory * (availableMemoryPercent / 100f));
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets memory cache for {@link android.graphics.Bitmap bitmaps}.<br />
|
|
||||||
* Default value - {@link com.nostra13.universalimageloader.cache.memory.impl.LruMemoryCache LruMemoryCache}
|
|
||||||
* with limited memory cache size (size = 1/8 of available app memory)<br />
|
|
||||||
* <br />
|
|
||||||
* <b>NOTE:</b> If you set custom memory cache then following configuration option will not be considered:
|
|
||||||
* <ul>
|
|
||||||
* <li>{@link #memoryCacheSize(int)}</li>
|
|
||||||
* </ul>
|
|
||||||
*/
|
|
||||||
public Builder memoryCache(MemoryCache memoryCache) {
|
|
||||||
if (memoryCacheSize != 0) {
|
|
||||||
L.w(WARNING_OVERLAP_MEMORY_CACHE);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.memoryCache = memoryCache;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @deprecated Use {@link #diskCacheSize(int)} instead */
|
|
||||||
@Deprecated
|
|
||||||
public Builder discCacheSize(int maxCacheSize) {
|
|
||||||
return diskCacheSize(maxCacheSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets maximum disk cache size for images (in bytes).<br />
|
|
||||||
* By default: disk cache is unlimited.<br />
|
|
||||||
* <b>NOTE:</b> If you use this method then
|
|
||||||
* {@link com.nostra13.universalimageloader.cache.disc.impl.ext.LruDiskCache LruDiskCache}
|
|
||||||
* will be used as disk cache. You can use {@link #diskCache(DiskCache)} method for introduction your own
|
|
||||||
* implementation of {@link DiskCache}
|
|
||||||
*/
|
|
||||||
public Builder diskCacheSize(int maxCacheSize) {
|
|
||||||
if (maxCacheSize <= 0) throw new IllegalArgumentException("maxCacheSize must be a positive number");
|
|
||||||
|
|
||||||
if (diskCache != null) {
|
|
||||||
L.w(WARNING_OVERLAP_DISK_CACHE_PARAMS);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.diskCacheSize = maxCacheSize;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @deprecated Use {@link #diskCacheFileCount(int)} instead */
|
|
||||||
@Deprecated
|
|
||||||
public Builder discCacheFileCount(int maxFileCount) {
|
|
||||||
return diskCacheFileCount(maxFileCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets maximum file count in disk cache directory.<br />
|
|
||||||
* By default: disk cache is unlimited.<br />
|
|
||||||
* <b>NOTE:</b> If you use this method then
|
|
||||||
* {@link com.nostra13.universalimageloader.cache.disc.impl.ext.LruDiskCache LruDiskCache}
|
|
||||||
* will be used as disk cache. You can use {@link #diskCache(DiskCache)} method for introduction your own
|
|
||||||
* implementation of {@link DiskCache}
|
|
||||||
*/
|
|
||||||
public Builder diskCacheFileCount(int maxFileCount) {
|
|
||||||
if (maxFileCount <= 0) throw new IllegalArgumentException("maxFileCount must be a positive number");
|
|
||||||
|
|
||||||
if (diskCache != null) {
|
|
||||||
L.w(WARNING_OVERLAP_DISK_CACHE_PARAMS);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.diskCacheFileCount = maxFileCount;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @deprecated Use {@link #diskCacheFileNameGenerator(com.nostra13.universalimageloader.cache.disc.naming.FileNameGenerator)} */
|
|
||||||
@Deprecated
|
|
||||||
public Builder discCacheFileNameGenerator(FileNameGenerator fileNameGenerator) {
|
|
||||||
return diskCacheFileNameGenerator(fileNameGenerator);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets name generator for files cached in disk cache.<br />
|
|
||||||
* Default value -
|
|
||||||
* {@link com.nostra13.universalimageloader.core.DefaultConfigurationFactory#createFileNameGenerator()
|
|
||||||
* DefaultConfigurationFactory.createFileNameGenerator()}
|
|
||||||
*/
|
|
||||||
public Builder diskCacheFileNameGenerator(FileNameGenerator fileNameGenerator) {
|
|
||||||
if (diskCache != null) {
|
|
||||||
L.w(WARNING_OVERLAP_DISK_CACHE_NAME_GENERATOR);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.diskCacheFileNameGenerator = fileNameGenerator;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @deprecated Use {@link #diskCache(com.nostra13.universalimageloader.cache.disc.DiskCache)} */
|
|
||||||
@Deprecated
|
|
||||||
public Builder discCache(DiskCache diskCache) {
|
|
||||||
return diskCache(diskCache);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets disk cache for images.<br />
|
|
||||||
* Default value - {@link com.nostra13.universalimageloader.cache.disc.impl.UnlimitedDiskCache
|
|
||||||
* UnlimitedDiskCache}. Cache directory is defined by
|
|
||||||
* {@link com.nostra13.universalimageloader.utils.StorageUtils#getCacheDirectory(Context)
|
|
||||||
* StorageUtils.getCacheDirectory(Context)}.<br />
|
|
||||||
* <br />
|
|
||||||
* <b>NOTE:</b> If you set custom disk cache then following configuration option will not be considered:
|
|
||||||
* <ul>
|
|
||||||
* <li>{@link #diskCacheSize(int)}</li>
|
|
||||||
* <li>{@link #diskCacheFileCount(int)}</li>
|
|
||||||
* <li>{@link #diskCacheFileNameGenerator(FileNameGenerator)}</li>
|
|
||||||
* </ul>
|
|
||||||
*/
|
|
||||||
public Builder diskCache(DiskCache diskCache) {
|
|
||||||
if (diskCacheSize > 0 || diskCacheFileCount > 0) {
|
|
||||||
L.w(WARNING_OVERLAP_DISK_CACHE_PARAMS);
|
|
||||||
}
|
|
||||||
if (diskCacheFileNameGenerator != null) {
|
|
||||||
L.w(WARNING_OVERLAP_DISK_CACHE_NAME_GENERATOR);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.diskCache = diskCache;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets utility which will be responsible for downloading of image.<br />
|
|
||||||
* Default value -
|
|
||||||
* {@link com.nostra13.universalimageloader.core.DefaultConfigurationFactory#createImageDownloader(Context)
|
|
||||||
* DefaultConfigurationFactory.createImageDownloader()}
|
|
||||||
*/
|
|
||||||
public Builder imageDownloader(ImageDownloader imageDownloader) {
|
|
||||||
this.downloader = imageDownloader;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets utility which will be responsible for decoding of image stream.<br />
|
|
||||||
* Default value -
|
|
||||||
* {@link com.nostra13.universalimageloader.core.DefaultConfigurationFactory#createImageDecoder(boolean)
|
|
||||||
* DefaultConfigurationFactory.createImageDecoder()}
|
|
||||||
*/
|
|
||||||
public Builder imageDecoder(ImageDecoder imageDecoder) {
|
|
||||||
this.decoder = imageDecoder;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets default {@linkplain DisplayImageOptions display image options} for image displaying. These options will
|
|
||||||
* be used for every {@linkplain ImageLoader#displayImage(String, android.widget.ImageView) image display call}
|
|
||||||
* without passing custom {@linkplain DisplayImageOptions options}<br />
|
|
||||||
* Default value - {@link DisplayImageOptions#createSimple() Simple options}
|
|
||||||
*/
|
|
||||||
public Builder defaultDisplayImageOptions(DisplayImageOptions defaultDisplayImageOptions) {
|
|
||||||
this.defaultDisplayImageOptions = defaultDisplayImageOptions;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Enables detail logging of {@link ImageLoader} work. To prevent detail logs don't call this method.
|
|
||||||
* Consider {@link com.nostra13.universalimageloader.utils.L#disableLogging()} to disable
|
|
||||||
* ImageLoader logging completely (even error logs)
|
|
||||||
*/
|
|
||||||
public Builder writeDebugLogs() {
|
|
||||||
this.writeLogs = true;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Builds configured {@link ImageLoaderConfiguration} object */
|
|
||||||
public ImageLoaderConfiguration build() {
|
|
||||||
initEmptyFieldsWithDefaultValues();
|
|
||||||
return new ImageLoaderConfiguration(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initEmptyFieldsWithDefaultValues() {
|
|
||||||
if (taskExecutor == null) {
|
|
||||||
taskExecutor = DefaultConfigurationFactory
|
|
||||||
.createExecutor(threadPoolSize, threadPriority, tasksProcessingType);
|
|
||||||
} else {
|
|
||||||
customExecutor = true;
|
|
||||||
}
|
|
||||||
if (taskExecutorForCachedImages == null) {
|
|
||||||
taskExecutorForCachedImages = DefaultConfigurationFactory
|
|
||||||
.createExecutor(threadPoolSize, threadPriority, tasksProcessingType);
|
|
||||||
} else {
|
|
||||||
customExecutorForCachedImages = true;
|
|
||||||
}
|
|
||||||
if (diskCache == null) {
|
|
||||||
if (diskCacheFileNameGenerator == null) {
|
|
||||||
diskCacheFileNameGenerator = DefaultConfigurationFactory.createFileNameGenerator();
|
|
||||||
}
|
|
||||||
diskCache = DefaultConfigurationFactory
|
|
||||||
.createDiskCache(context, diskCacheFileNameGenerator, diskCacheSize, diskCacheFileCount);
|
|
||||||
}
|
|
||||||
if (memoryCache == null) {
|
|
||||||
memoryCache = DefaultConfigurationFactory.createMemoryCache(context, memoryCacheSize);
|
|
||||||
}
|
|
||||||
if (denyCacheImageMultipleSizesInMemory) {
|
|
||||||
memoryCache = new FuzzyKeyMemoryCache(memoryCache, MemoryCacheUtils.createFuzzyKeyComparator());
|
|
||||||
}
|
|
||||||
if (downloader == null) {
|
|
||||||
downloader = DefaultConfigurationFactory.createImageDownloader(context);
|
|
||||||
}
|
|
||||||
if (decoder == null) {
|
|
||||||
decoder = DefaultConfigurationFactory.createImageDecoder(writeLogs);
|
|
||||||
}
|
|
||||||
if (defaultDisplayImageOptions == null) {
|
|
||||||
defaultDisplayImageOptions = DisplayImageOptions.createSimple();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Decorator. Prevents downloads from network (throws {@link IllegalStateException exception}).<br />
|
|
||||||
* In most cases this downloader shouldn't be used directly.
|
|
||||||
*
|
|
||||||
* @author Sergey Tarasevich (nostra13[at]gmail[dot]com)
|
|
||||||
* @since 1.8.0
|
|
||||||
*/
|
|
||||||
private static class NetworkDeniedImageDownloader implements ImageDownloader {
|
|
||||||
|
|
||||||
private final ImageDownloader wrappedDownloader;
|
|
||||||
|
|
||||||
public NetworkDeniedImageDownloader(ImageDownloader wrappedDownloader) {
|
|
||||||
this.wrappedDownloader = wrappedDownloader;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public InputStream getStream(String imageUri, Object extra) throws IOException {
|
|
||||||
switch (Scheme.ofUri(imageUri)) {
|
|
||||||
case HTTP:
|
|
||||||
case HTTPS:
|
|
||||||
throw new IllegalStateException();
|
|
||||||
default:
|
|
||||||
return wrappedDownloader.getStream(imageUri, extra);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Decorator. Handles <a href="http://code.google.com/p/android/issues/detail?id=6066">this problem</a> on slow networks
|
|
||||||
* using {@link com.nostra13.universalimageloader.core.assist.FlushedInputStream}.
|
|
||||||
*
|
|
||||||
* @author Sergey Tarasevich (nostra13[at]gmail[dot]com)
|
|
||||||
* @since 1.8.1
|
|
||||||
*/
|
|
||||||
private static class SlowNetworkImageDownloader implements ImageDownloader {
|
|
||||||
|
|
||||||
private final ImageDownloader wrappedDownloader;
|
|
||||||
|
|
||||||
public SlowNetworkImageDownloader(ImageDownloader wrappedDownloader) {
|
|
||||||
this.wrappedDownloader = wrappedDownloader;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public InputStream getStream(String imageUri, Object extra) throws IOException {
|
|
||||||
InputStream imageStream = wrappedDownloader.getStream(imageUri, extra);
|
|
||||||
switch (Scheme.ofUri(imageUri)) {
|
|
||||||
case HTTP:
|
|
||||||
case HTTPS:
|
|
||||||
return new FlushedInputStream(imageStream);
|
|
||||||
default:
|
|
||||||
return imageStream;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,217 +0,0 @@
|
|||||||
/*******************************************************************************
|
|
||||||
* Copyright 2011-2014 Sergey Tarasevich
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*******************************************************************************/
|
|
||||||
package com.nostra13.universalimageloader.core;
|
|
||||||
|
|
||||||
import android.view.View;
|
|
||||||
import com.nostra13.universalimageloader.core.assist.FailReason;
|
|
||||||
import com.nostra13.universalimageloader.core.assist.FlushedInputStream;
|
|
||||||
import com.nostra13.universalimageloader.core.imageaware.ImageAware;
|
|
||||||
import com.nostra13.universalimageloader.core.listener.ImageLoadingListener;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.WeakHashMap;
|
|
||||||
import java.util.concurrent.Executor;
|
|
||||||
import java.util.concurrent.ExecutorService;
|
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
|
||||||
import java.util.concurrent.locks.ReentrantLock;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@link ImageLoader} engine which responsible for {@linkplain LoadAndDisplayImageTask display task} execution.
|
|
||||||
*
|
|
||||||
* @author Sergey Tarasevich (nostra13[at]gmail[dot]com)
|
|
||||||
* @since 1.7.1
|
|
||||||
*/
|
|
||||||
class ImageLoaderEngine {
|
|
||||||
|
|
||||||
final ImageLoaderConfiguration configuration;
|
|
||||||
|
|
||||||
private Executor taskExecutor;
|
|
||||||
private Executor taskExecutorForCachedImages;
|
|
||||||
private Executor taskDistributor;
|
|
||||||
|
|
||||||
private final Map<Integer, String> cacheKeysForImageAwares = Collections
|
|
||||||
.synchronizedMap(new HashMap<Integer, String>());
|
|
||||||
private final Map<String, ReentrantLock> uriLocks = new WeakHashMap<String, ReentrantLock>();
|
|
||||||
|
|
||||||
private final AtomicBoolean paused = new AtomicBoolean(false);
|
|
||||||
private final AtomicBoolean networkDenied = new AtomicBoolean(false);
|
|
||||||
private final AtomicBoolean slowNetwork = new AtomicBoolean(false);
|
|
||||||
|
|
||||||
private final Object pauseLock = new Object();
|
|
||||||
|
|
||||||
ImageLoaderEngine(ImageLoaderConfiguration configuration) {
|
|
||||||
this.configuration = configuration;
|
|
||||||
|
|
||||||
taskExecutor = configuration.taskExecutor;
|
|
||||||
taskExecutorForCachedImages = configuration.taskExecutorForCachedImages;
|
|
||||||
|
|
||||||
taskDistributor = DefaultConfigurationFactory.createTaskDistributor();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Submits task to execution pool */
|
|
||||||
void submit(final LoadAndDisplayImageTask task) {
|
|
||||||
taskDistributor.execute(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
File image = configuration.diskCache.get(task.getLoadingUri());
|
|
||||||
boolean isImageCachedOnDisk = image != null && image.exists();
|
|
||||||
initExecutorsIfNeed();
|
|
||||||
if (isImageCachedOnDisk) {
|
|
||||||
taskExecutorForCachedImages.execute(task);
|
|
||||||
} else {
|
|
||||||
taskExecutor.execute(task);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Submits task to execution pool */
|
|
||||||
void submit(ProcessAndDisplayImageTask task) {
|
|
||||||
initExecutorsIfNeed();
|
|
||||||
taskExecutorForCachedImages.execute(task);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initExecutorsIfNeed() {
|
|
||||||
if (!configuration.customExecutor && ((ExecutorService) taskExecutor).isShutdown()) {
|
|
||||||
taskExecutor = createTaskExecutor();
|
|
||||||
}
|
|
||||||
if (!configuration.customExecutorForCachedImages && ((ExecutorService) taskExecutorForCachedImages)
|
|
||||||
.isShutdown()) {
|
|
||||||
taskExecutorForCachedImages = createTaskExecutor();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Executor createTaskExecutor() {
|
|
||||||
return DefaultConfigurationFactory
|
|
||||||
.createExecutor(configuration.threadPoolSize, configuration.threadPriority,
|
|
||||||
configuration.tasksProcessingType);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns URI of image which is loading at this moment into passed {@link com.nostra13.universalimageloader.core.imageaware.ImageAware}
|
|
||||||
*/
|
|
||||||
String getLoadingUriForView(ImageAware imageAware) {
|
|
||||||
return cacheKeysForImageAwares.get(imageAware.getId());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Associates <b>memoryCacheKey</b> with <b>imageAware</b>. Then it helps to define image URI is loaded into View at
|
|
||||||
* exact moment.
|
|
||||||
*/
|
|
||||||
void prepareDisplayTaskFor(ImageAware imageAware, String memoryCacheKey) {
|
|
||||||
cacheKeysForImageAwares.put(imageAware.getId(), memoryCacheKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Cancels the task of loading and displaying image for incoming <b>imageAware</b>.
|
|
||||||
*
|
|
||||||
* @param imageAware {@link com.nostra13.universalimageloader.core.imageaware.ImageAware} for which display task
|
|
||||||
* will be cancelled
|
|
||||||
*/
|
|
||||||
void cancelDisplayTaskFor(ImageAware imageAware) {
|
|
||||||
cacheKeysForImageAwares.remove(imageAware.getId());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Denies or allows engine to download images from the network.<br /> <br /> If downloads are denied and if image
|
|
||||||
* isn't cached then {@link ImageLoadingListener#onLoadingFailed(String, View, FailReason)} callback will be fired
|
|
||||||
* with {@link FailReason.FailType#NETWORK_DENIED}
|
|
||||||
*
|
|
||||||
* @param denyNetworkDownloads pass <b>true</b> - to deny engine to download images from the network; <b>false</b> -
|
|
||||||
* to allow engine to download images from network.
|
|
||||||
*/
|
|
||||||
void denyNetworkDownloads(boolean denyNetworkDownloads) {
|
|
||||||
networkDenied.set(denyNetworkDownloads);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets option whether ImageLoader will use {@link FlushedInputStream} for network downloads to handle <a
|
|
||||||
* href="http://code.google.com/p/android/issues/detail?id=6066">this known problem</a> or not.
|
|
||||||
*
|
|
||||||
* @param handleSlowNetwork pass <b>true</b> - to use {@link FlushedInputStream} for network downloads; <b>false</b>
|
|
||||||
* - otherwise.
|
|
||||||
*/
|
|
||||||
void handleSlowNetwork(boolean handleSlowNetwork) {
|
|
||||||
slowNetwork.set(handleSlowNetwork);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Pauses engine. All new "load&display" tasks won't be executed until ImageLoader is {@link #resume() resumed}.<br
|
|
||||||
* /> Already running tasks are not paused.
|
|
||||||
*/
|
|
||||||
void pause() {
|
|
||||||
paused.set(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Resumes engine work. Paused "load&display" tasks will continue its work. */
|
|
||||||
void resume() {
|
|
||||||
paused.set(false);
|
|
||||||
synchronized (pauseLock) {
|
|
||||||
pauseLock.notifyAll();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stops engine, cancels all running and scheduled display image tasks. Clears internal data.
|
|
||||||
* <br />
|
|
||||||
* <b>NOTE:</b> This method doesn't shutdown
|
|
||||||
* {@linkplain com.nostra13.universalimageloader.core.ImageLoaderConfiguration.Builder#taskExecutor(java.util.concurrent.Executor)
|
|
||||||
* custom task executors} if you set them.
|
|
||||||
*/
|
|
||||||
void stop() {
|
|
||||||
if (!configuration.customExecutor) {
|
|
||||||
((ExecutorService) taskExecutor).shutdownNow();
|
|
||||||
}
|
|
||||||
if (!configuration.customExecutorForCachedImages) {
|
|
||||||
((ExecutorService) taskExecutorForCachedImages).shutdownNow();
|
|
||||||
}
|
|
||||||
|
|
||||||
cacheKeysForImageAwares.clear();
|
|
||||||
uriLocks.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
void fireCallback(Runnable r) {
|
|
||||||
taskDistributor.execute(r);
|
|
||||||
}
|
|
||||||
|
|
||||||
ReentrantLock getLockForUri(String uri) {
|
|
||||||
ReentrantLock lock = uriLocks.get(uri);
|
|
||||||
if (lock == null) {
|
|
||||||
lock = new ReentrantLock();
|
|
||||||
uriLocks.put(uri, lock);
|
|
||||||
}
|
|
||||||
return lock;
|
|
||||||
}
|
|
||||||
|
|
||||||
AtomicBoolean getPause() {
|
|
||||||
return paused;
|
|
||||||
}
|
|
||||||
|
|
||||||
Object getPauseLock() {
|
|
||||||
return pauseLock;
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean isNetworkDenied() {
|
|
||||||
return networkDenied.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean isSlowNetwork() {
|
|
||||||
return slowNetwork.get();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,58 +0,0 @@
|
|||||||
/*******************************************************************************
|
|
||||||
* Copyright 2011-2013 Sergey Tarasevich
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*******************************************************************************/
|
|
||||||
package com.nostra13.universalimageloader.core;
|
|
||||||
|
|
||||||
import com.nostra13.universalimageloader.core.listener.ImageLoadingListener;
|
|
||||||
import com.nostra13.universalimageloader.core.listener.ImageLoadingProgressListener;
|
|
||||||
import com.nostra13.universalimageloader.core.assist.ImageSize;
|
|
||||||
import com.nostra13.universalimageloader.core.imageaware.ImageAware;
|
|
||||||
|
|
||||||
import java.util.concurrent.locks.ReentrantLock;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Information for load'n'display image task
|
|
||||||
*
|
|
||||||
* @author Sergey Tarasevich (nostra13[at]gmail[dot]com)
|
|
||||||
* @see com.nostra13.universalimageloader.utils.MemoryCacheUtils
|
|
||||||
* @see DisplayImageOptions
|
|
||||||
* @see ImageLoadingListener
|
|
||||||
* @see com.nostra13.universalimageloader.core.listener.ImageLoadingProgressListener
|
|
||||||
* @since 1.3.1
|
|
||||||
*/
|
|
||||||
final class ImageLoadingInfo {
|
|
||||||
|
|
||||||
final String uri;
|
|
||||||
final String memoryCacheKey;
|
|
||||||
final ImageAware imageAware;
|
|
||||||
final ImageSize targetSize;
|
|
||||||
final DisplayImageOptions options;
|
|
||||||
final ImageLoadingListener listener;
|
|
||||||
final ImageLoadingProgressListener progressListener;
|
|
||||||
final ReentrantLock loadFromUriLock;
|
|
||||||
|
|
||||||
public ImageLoadingInfo(String uri, ImageAware imageAware, ImageSize targetSize, String memoryCacheKey,
|
|
||||||
DisplayImageOptions options, ImageLoadingListener listener,
|
|
||||||
ImageLoadingProgressListener progressListener, ReentrantLock loadFromUriLock) {
|
|
||||||
this.uri = uri;
|
|
||||||
this.imageAware = imageAware;
|
|
||||||
this.targetSize = targetSize;
|
|
||||||
this.options = options;
|
|
||||||
this.listener = listener;
|
|
||||||
this.progressListener = progressListener;
|
|
||||||
this.loadFromUriLock = loadFromUriLock;
|
|
||||||
this.memoryCacheKey = memoryCacheKey;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,482 +0,0 @@
|
|||||||
/*******************************************************************************
|
|
||||||
* Copyright 2011-2014 Sergey Tarasevich
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*******************************************************************************/
|
|
||||||
package com.nostra13.universalimageloader.core;
|
|
||||||
|
|
||||||
import android.graphics.Bitmap;
|
|
||||||
import android.os.Handler;
|
|
||||||
import com.nostra13.universalimageloader.core.assist.FailReason;
|
|
||||||
import com.nostra13.universalimageloader.core.assist.FailReason.FailType;
|
|
||||||
import com.nostra13.universalimageloader.core.assist.ImageScaleType;
|
|
||||||
import com.nostra13.universalimageloader.core.assist.ImageSize;
|
|
||||||
import com.nostra13.universalimageloader.core.assist.LoadedFrom;
|
|
||||||
import com.nostra13.universalimageloader.core.assist.ViewScaleType;
|
|
||||||
import com.nostra13.universalimageloader.core.decode.ImageDecoder;
|
|
||||||
import com.nostra13.universalimageloader.core.decode.ImageDecodingInfo;
|
|
||||||
import com.nostra13.universalimageloader.core.download.ImageDownloader;
|
|
||||||
import com.nostra13.universalimageloader.core.download.ImageDownloader.Scheme;
|
|
||||||
import com.nostra13.universalimageloader.core.imageaware.ImageAware;
|
|
||||||
import com.nostra13.universalimageloader.core.listener.ImageLoadingListener;
|
|
||||||
import com.nostra13.universalimageloader.core.listener.ImageLoadingProgressListener;
|
|
||||||
import com.nostra13.universalimageloader.utils.IoUtils;
|
|
||||||
import com.nostra13.universalimageloader.utils.L;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
|
||||||
import java.util.concurrent.locks.ReentrantLock;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Presents load'n'display image task. Used to load image from Internet or file system, decode it to {@link Bitmap}, and
|
|
||||||
* display it in {@link com.nostra13.universalimageloader.core.imageaware.ImageAware} using {@link DisplayBitmapTask}.
|
|
||||||
*
|
|
||||||
* @author Sergey Tarasevich (nostra13[at]gmail[dot]com)
|
|
||||||
* @see ImageLoaderConfiguration
|
|
||||||
* @see ImageLoadingInfo
|
|
||||||
* @since 1.3.1
|
|
||||||
*/
|
|
||||||
final class LoadAndDisplayImageTask implements Runnable, IoUtils.CopyListener {
|
|
||||||
|
|
||||||
private static final String LOG_WAITING_FOR_RESUME = "ImageLoader is paused. Waiting... [%s]";
|
|
||||||
private static final String LOG_RESUME_AFTER_PAUSE = ".. Resume loading [%s]";
|
|
||||||
private static final String LOG_DELAY_BEFORE_LOADING = "Delay %d ms before loading... [%s]";
|
|
||||||
private static final String LOG_START_DISPLAY_IMAGE_TASK = "Start display image task [%s]";
|
|
||||||
private static final String LOG_WAITING_FOR_IMAGE_LOADED = "Image already is loading. Waiting... [%s]";
|
|
||||||
private static final String LOG_GET_IMAGE_FROM_MEMORY_CACHE_AFTER_WAITING = "...Get cached bitmap from memory after waiting. [%s]";
|
|
||||||
private static final String LOG_LOAD_IMAGE_FROM_NETWORK = "Load image from network [%s]";
|
|
||||||
private static final String LOG_LOAD_IMAGE_FROM_DISK_CACHE = "Load image from disk cache [%s]";
|
|
||||||
private static final String LOG_RESIZE_CACHED_IMAGE_FILE = "Resize image in disk cache [%s]";
|
|
||||||
private static final String LOG_PREPROCESS_IMAGE = "PreProcess image before caching in memory [%s]";
|
|
||||||
private static final String LOG_POSTPROCESS_IMAGE = "PostProcess image before displaying [%s]";
|
|
||||||
private static final String LOG_CACHE_IMAGE_IN_MEMORY = "Cache image in memory [%s]";
|
|
||||||
private static final String LOG_CACHE_IMAGE_ON_DISK = "Cache image on disk [%s]";
|
|
||||||
private static final String LOG_PROCESS_IMAGE_BEFORE_CACHE_ON_DISK = "Process image before cache on disk [%s]";
|
|
||||||
private static final String LOG_TASK_CANCELLED_IMAGEAWARE_REUSED = "ImageAware is reused for another image. Task is cancelled. [%s]";
|
|
||||||
private static final String LOG_TASK_CANCELLED_IMAGEAWARE_COLLECTED = "ImageAware was collected by GC. Task is cancelled. [%s]";
|
|
||||||
private static final String LOG_TASK_INTERRUPTED = "Task was interrupted [%s]";
|
|
||||||
|
|
||||||
private static final String ERROR_NO_IMAGE_STREAM = "No stream for image [%s]";
|
|
||||||
private static final String ERROR_PRE_PROCESSOR_NULL = "Pre-processor returned null [%s]";
|
|
||||||
private static final String ERROR_POST_PROCESSOR_NULL = "Post-processor returned null [%s]";
|
|
||||||
private static final String ERROR_PROCESSOR_FOR_DISK_CACHE_NULL = "Bitmap processor for disk cache returned null [%s]";
|
|
||||||
|
|
||||||
private final ImageLoaderEngine engine;
|
|
||||||
private final ImageLoadingInfo imageLoadingInfo;
|
|
||||||
private final Handler handler;
|
|
||||||
|
|
||||||
// Helper references
|
|
||||||
private final ImageLoaderConfiguration configuration;
|
|
||||||
private final ImageDownloader downloader;
|
|
||||||
private final ImageDownloader networkDeniedDownloader;
|
|
||||||
private final ImageDownloader slowNetworkDownloader;
|
|
||||||
private final ImageDecoder decoder;
|
|
||||||
final String uri;
|
|
||||||
private final String memoryCacheKey;
|
|
||||||
final ImageAware imageAware;
|
|
||||||
private final ImageSize targetSize;
|
|
||||||
final DisplayImageOptions options;
|
|
||||||
final ImageLoadingListener listener;
|
|
||||||
final ImageLoadingProgressListener progressListener;
|
|
||||||
private final boolean syncLoading;
|
|
||||||
|
|
||||||
// State vars
|
|
||||||
private LoadedFrom loadedFrom = LoadedFrom.NETWORK;
|
|
||||||
|
|
||||||
public LoadAndDisplayImageTask(ImageLoaderEngine engine, ImageLoadingInfo imageLoadingInfo, Handler handler) {
|
|
||||||
this.engine = engine;
|
|
||||||
this.imageLoadingInfo = imageLoadingInfo;
|
|
||||||
this.handler = handler;
|
|
||||||
|
|
||||||
configuration = engine.configuration;
|
|
||||||
downloader = configuration.downloader;
|
|
||||||
networkDeniedDownloader = configuration.networkDeniedDownloader;
|
|
||||||
slowNetworkDownloader = configuration.slowNetworkDownloader;
|
|
||||||
decoder = configuration.decoder;
|
|
||||||
uri = imageLoadingInfo.uri;
|
|
||||||
memoryCacheKey = imageLoadingInfo.memoryCacheKey;
|
|
||||||
imageAware = imageLoadingInfo.imageAware;
|
|
||||||
targetSize = imageLoadingInfo.targetSize;
|
|
||||||
options = imageLoadingInfo.options;
|
|
||||||
listener = imageLoadingInfo.listener;
|
|
||||||
progressListener = imageLoadingInfo.progressListener;
|
|
||||||
syncLoading = options.isSyncLoading();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
if (waitIfPaused()) return;
|
|
||||||
if (delayIfNeed()) return;
|
|
||||||
|
|
||||||
ReentrantLock loadFromUriLock = imageLoadingInfo.loadFromUriLock;
|
|
||||||
L.d(LOG_START_DISPLAY_IMAGE_TASK, memoryCacheKey);
|
|
||||||
if (loadFromUriLock.isLocked()) {
|
|
||||||
L.d(LOG_WAITING_FOR_IMAGE_LOADED, memoryCacheKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
loadFromUriLock.lock();
|
|
||||||
Bitmap bmp;
|
|
||||||
try {
|
|
||||||
checkTaskNotActual();
|
|
||||||
|
|
||||||
bmp = configuration.memoryCache.get(memoryCacheKey);
|
|
||||||
if (bmp == null || bmp.isRecycled()) {
|
|
||||||
bmp = tryLoadBitmap();
|
|
||||||
if (bmp == null) return; // listener callback already was fired
|
|
||||||
|
|
||||||
checkTaskNotActual();
|
|
||||||
checkTaskInterrupted();
|
|
||||||
|
|
||||||
if (options.shouldPreProcess()) {
|
|
||||||
L.d(LOG_PREPROCESS_IMAGE, memoryCacheKey);
|
|
||||||
bmp = options.getPreProcessor().process(bmp);
|
|
||||||
if (bmp == null) {
|
|
||||||
L.e(ERROR_PRE_PROCESSOR_NULL, memoryCacheKey);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bmp != null && options.isCacheInMemory()) {
|
|
||||||
L.d(LOG_CACHE_IMAGE_IN_MEMORY, memoryCacheKey);
|
|
||||||
configuration.memoryCache.put(memoryCacheKey, bmp);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
loadedFrom = LoadedFrom.MEMORY_CACHE;
|
|
||||||
L.d(LOG_GET_IMAGE_FROM_MEMORY_CACHE_AFTER_WAITING, memoryCacheKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bmp != null && options.shouldPostProcess()) {
|
|
||||||
L.d(LOG_POSTPROCESS_IMAGE, memoryCacheKey);
|
|
||||||
bmp = options.getPostProcessor().process(bmp);
|
|
||||||
if (bmp == null) {
|
|
||||||
L.e(ERROR_POST_PROCESSOR_NULL, memoryCacheKey);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
checkTaskNotActual();
|
|
||||||
checkTaskInterrupted();
|
|
||||||
} catch (TaskCancelledException e) {
|
|
||||||
fireCancelEvent();
|
|
||||||
return;
|
|
||||||
} finally {
|
|
||||||
loadFromUriLock.unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
DisplayBitmapTask displayBitmapTask = new DisplayBitmapTask(bmp, imageLoadingInfo, engine, loadedFrom);
|
|
||||||
runTask(displayBitmapTask, syncLoading, handler, engine);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @return <b>true</b> - if task should be interrupted; <b>false</b> - otherwise */
|
|
||||||
private boolean waitIfPaused() {
|
|
||||||
AtomicBoolean pause = engine.getPause();
|
|
||||||
if (pause.get()) {
|
|
||||||
synchronized (engine.getPauseLock()) {
|
|
||||||
if (pause.get()) {
|
|
||||||
L.d(LOG_WAITING_FOR_RESUME, memoryCacheKey);
|
|
||||||
try {
|
|
||||||
engine.getPauseLock().wait();
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
L.e(LOG_TASK_INTERRUPTED, memoryCacheKey);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
L.d(LOG_RESUME_AFTER_PAUSE, memoryCacheKey);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return isTaskNotActual();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @return <b>true</b> - if task should be interrupted; <b>false</b> - otherwise */
|
|
||||||
private boolean delayIfNeed() {
|
|
||||||
if (options.shouldDelayBeforeLoading()) {
|
|
||||||
L.d(LOG_DELAY_BEFORE_LOADING, options.getDelayBeforeLoading(), memoryCacheKey);
|
|
||||||
try {
|
|
||||||
Thread.sleep(options.getDelayBeforeLoading());
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
L.e(LOG_TASK_INTERRUPTED, memoryCacheKey);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return isTaskNotActual();
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Bitmap tryLoadBitmap() throws TaskCancelledException {
|
|
||||||
Bitmap bitmap = null;
|
|
||||||
try {
|
|
||||||
File imageFile = configuration.diskCache.get(uri);
|
|
||||||
if (imageFile != null && imageFile.exists() && imageFile.length() > 0) {
|
|
||||||
L.d(LOG_LOAD_IMAGE_FROM_DISK_CACHE, memoryCacheKey);
|
|
||||||
loadedFrom = LoadedFrom.DISC_CACHE;
|
|
||||||
|
|
||||||
checkTaskNotActual();
|
|
||||||
bitmap = decodeImage(Scheme.FILE.wrap(imageFile.getAbsolutePath()));
|
|
||||||
}
|
|
||||||
if (bitmap == null || bitmap.getWidth() <= 0 || bitmap.getHeight() <= 0) {
|
|
||||||
L.d(LOG_LOAD_IMAGE_FROM_NETWORK, memoryCacheKey);
|
|
||||||
loadedFrom = LoadedFrom.NETWORK;
|
|
||||||
|
|
||||||
String imageUriForDecoding = uri;
|
|
||||||
if (options.isCacheOnDisk() && tryCacheImageOnDisk()) {
|
|
||||||
imageFile = configuration.diskCache.get(uri);
|
|
||||||
if (imageFile != null) {
|
|
||||||
imageUriForDecoding = Scheme.FILE.wrap(imageFile.getAbsolutePath());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
checkTaskNotActual();
|
|
||||||
bitmap = decodeImage(imageUriForDecoding);
|
|
||||||
|
|
||||||
if (bitmap == null || bitmap.getWidth() <= 0 || bitmap.getHeight() <= 0) {
|
|
||||||
fireFailEvent(FailType.DECODING_ERROR, null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (IllegalStateException e) {
|
|
||||||
fireFailEvent(FailType.NETWORK_DENIED, null);
|
|
||||||
} catch (TaskCancelledException e) {
|
|
||||||
throw e;
|
|
||||||
} catch (IOException e) {
|
|
||||||
L.e(e);
|
|
||||||
fireFailEvent(FailType.IO_ERROR, e);
|
|
||||||
} catch (OutOfMemoryError e) {
|
|
||||||
L.e(e);
|
|
||||||
fireFailEvent(FailType.OUT_OF_MEMORY, e);
|
|
||||||
} catch (Throwable e) {
|
|
||||||
L.e(e);
|
|
||||||
fireFailEvent(FailType.UNKNOWN, e);
|
|
||||||
}
|
|
||||||
return bitmap;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Bitmap decodeImage(String imageUri) throws IOException {
|
|
||||||
ViewScaleType viewScaleType = imageAware.getScaleType();
|
|
||||||
ImageDecodingInfo decodingInfo = new ImageDecodingInfo(memoryCacheKey, imageUri, uri, targetSize, viewScaleType,
|
|
||||||
getDownloader(), options);
|
|
||||||
return decoder.decode(decodingInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @return <b>true</b> - if image was downloaded successfully; <b>false</b> - otherwise */
|
|
||||||
private boolean tryCacheImageOnDisk() throws TaskCancelledException {
|
|
||||||
L.d(LOG_CACHE_IMAGE_ON_DISK, memoryCacheKey);
|
|
||||||
|
|
||||||
boolean loaded;
|
|
||||||
try {
|
|
||||||
loaded = downloadImage();
|
|
||||||
if (loaded) {
|
|
||||||
int width = configuration.maxImageWidthForDiskCache;
|
|
||||||
int height = configuration.maxImageHeightForDiskCache;
|
|
||||||
if (width > 0 || height > 0) {
|
|
||||||
L.d(LOG_RESIZE_CACHED_IMAGE_FILE, memoryCacheKey);
|
|
||||||
resizeAndSaveImage(width, height); // TODO : process boolean result
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
L.e(e);
|
|
||||||
loaded = false;
|
|
||||||
}
|
|
||||||
return loaded;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean downloadImage() throws IOException {
|
|
||||||
InputStream is = getDownloader().getStream(uri, options.getExtraForDownloader());
|
|
||||||
if (is == null) {
|
|
||||||
L.e(ERROR_NO_IMAGE_STREAM, memoryCacheKey);
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
return configuration.diskCache.save(uri, is, this);
|
|
||||||
} finally {
|
|
||||||
IoUtils.closeSilently(is);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Decodes image file into Bitmap, resize it and save it back */
|
|
||||||
private boolean resizeAndSaveImage(int maxWidth, int maxHeight) throws IOException {
|
|
||||||
// Decode image file, compress and re-save it
|
|
||||||
boolean saved = false;
|
|
||||||
File targetFile = configuration.diskCache.get(uri);
|
|
||||||
if (targetFile != null && targetFile.exists()) {
|
|
||||||
ImageSize targetImageSize = new ImageSize(maxWidth, maxHeight);
|
|
||||||
DisplayImageOptions specialOptions = new DisplayImageOptions.Builder().cloneFrom(options)
|
|
||||||
.imageScaleType(ImageScaleType.IN_SAMPLE_INT).build();
|
|
||||||
ImageDecodingInfo decodingInfo = new ImageDecodingInfo(memoryCacheKey,
|
|
||||||
Scheme.FILE.wrap(targetFile.getAbsolutePath()), uri, targetImageSize, ViewScaleType.FIT_INSIDE,
|
|
||||||
getDownloader(), specialOptions);
|
|
||||||
Bitmap bmp = decoder.decode(decodingInfo);
|
|
||||||
if (bmp != null && configuration.processorForDiskCache != null) {
|
|
||||||
L.d(LOG_PROCESS_IMAGE_BEFORE_CACHE_ON_DISK, memoryCacheKey);
|
|
||||||
bmp = configuration.processorForDiskCache.process(bmp);
|
|
||||||
if (bmp == null) {
|
|
||||||
L.e(ERROR_PROCESSOR_FOR_DISK_CACHE_NULL, memoryCacheKey);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (bmp != null) {
|
|
||||||
saved = configuration.diskCache.save(uri, bmp);
|
|
||||||
bmp.recycle();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return saved;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onBytesCopied(int current, int total) {
|
|
||||||
return syncLoading || fireProgressEvent(current, total);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @return <b>true</b> - if loading should be continued; <b>false</b> - if loading should be interrupted */
|
|
||||||
private boolean fireProgressEvent(final int current, final int total) {
|
|
||||||
if (isTaskInterrupted() || isTaskNotActual()) return false;
|
|
||||||
if (progressListener != null) {
|
|
||||||
Runnable r = new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
progressListener.onProgressUpdate(uri, imageAware.getWrappedView(), current, total);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
runTask(r, false, handler, engine);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void fireFailEvent(final FailType failType, final Throwable failCause) {
|
|
||||||
if (syncLoading || isTaskInterrupted() || isTaskNotActual()) return;
|
|
||||||
Runnable r = new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
if (options.shouldShowImageOnFail()) {
|
|
||||||
imageAware.setImageDrawable(options.getImageOnFail(configuration.resources));
|
|
||||||
}
|
|
||||||
listener.onLoadingFailed(uri, imageAware.getWrappedView(), new FailReason(failType, failCause));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
runTask(r, false, handler, engine);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void fireCancelEvent() {
|
|
||||||
if (syncLoading || isTaskInterrupted()) return;
|
|
||||||
Runnable r = new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
listener.onLoadingCancelled(uri, imageAware.getWrappedView());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
runTask(r, false, handler, engine);
|
|
||||||
}
|
|
||||||
|
|
||||||
private ImageDownloader getDownloader() {
|
|
||||||
ImageDownloader d;
|
|
||||||
if (engine.isNetworkDenied()) {
|
|
||||||
d = networkDeniedDownloader;
|
|
||||||
} else if (engine.isSlowNetwork()) {
|
|
||||||
d = slowNetworkDownloader;
|
|
||||||
} else {
|
|
||||||
d = downloader;
|
|
||||||
}
|
|
||||||
return d;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws TaskCancelledException if task is not actual (target ImageAware is collected by GC or the image URI of
|
|
||||||
* this task doesn't match to image URI which is actual for current ImageAware at
|
|
||||||
* this moment)
|
|
||||||
*/
|
|
||||||
private void checkTaskNotActual() throws TaskCancelledException {
|
|
||||||
checkViewCollected();
|
|
||||||
checkViewReused();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return <b>true</b> - if task is not actual (target ImageAware is collected by GC or the image URI of this task
|
|
||||||
* doesn't match to image URI which is actual for current ImageAware at this moment)); <b>false</b> - otherwise
|
|
||||||
*/
|
|
||||||
private boolean isTaskNotActual() {
|
|
||||||
return isViewCollected() || isViewReused();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @throws TaskCancelledException if target ImageAware is collected */
|
|
||||||
private void checkViewCollected() throws TaskCancelledException {
|
|
||||||
if (isViewCollected()) {
|
|
||||||
throw new TaskCancelledException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @return <b>true</b> - if target ImageAware is collected by GC; <b>false</b> - otherwise */
|
|
||||||
private boolean isViewCollected() {
|
|
||||||
if (imageAware.isCollected()) {
|
|
||||||
L.d(LOG_TASK_CANCELLED_IMAGEAWARE_COLLECTED, memoryCacheKey);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @throws TaskCancelledException if target ImageAware is collected by GC */
|
|
||||||
private void checkViewReused() throws TaskCancelledException {
|
|
||||||
if (isViewReused()) {
|
|
||||||
throw new TaskCancelledException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @return <b>true</b> - if current ImageAware is reused for displaying another image; <b>false</b> - otherwise */
|
|
||||||
private boolean isViewReused() {
|
|
||||||
String currentCacheKey = engine.getLoadingUriForView(imageAware);
|
|
||||||
// Check whether memory cache key (image URI) for current ImageAware is actual.
|
|
||||||
// If ImageAware is reused for another task then current task should be cancelled.
|
|
||||||
boolean imageAwareWasReused = !memoryCacheKey.equals(currentCacheKey);
|
|
||||||
if (imageAwareWasReused) {
|
|
||||||
L.d(LOG_TASK_CANCELLED_IMAGEAWARE_REUSED, memoryCacheKey);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @throws TaskCancelledException if current task was interrupted */
|
|
||||||
private void checkTaskInterrupted() throws TaskCancelledException {
|
|
||||||
if (isTaskInterrupted()) {
|
|
||||||
throw new TaskCancelledException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @return <b>true</b> - if current task was interrupted; <b>false</b> - otherwise */
|
|
||||||
private boolean isTaskInterrupted() {
|
|
||||||
if (Thread.interrupted()) {
|
|
||||||
L.d(LOG_TASK_INTERRUPTED, memoryCacheKey);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
String getLoadingUri() {
|
|
||||||
return uri;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void runTask(Runnable r, boolean sync, Handler handler, ImageLoaderEngine engine) {
|
|
||||||
if (sync) {
|
|
||||||
r.run();
|
|
||||||
} else if (handler == null) {
|
|
||||||
engine.fireCallback(r);
|
|
||||||
} else {
|
|
||||||
handler.post(r);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Exceptions for case when task is cancelled (thread is interrupted, image view is reused for another task, view is
|
|
||||||
* collected by GC).
|
|
||||||
*
|
|
||||||
* @author Sergey Tarasevich (nostra13[at]gmail[dot]com)
|
|
||||||
* @since 1.9.1
|
|
||||||
*/
|
|
||||||
class TaskCancelledException extends Exception {
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,59 +0,0 @@
|
|||||||
/*******************************************************************************
|
|
||||||
* Copyright 2011-2014 Sergey Tarasevich
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*******************************************************************************/
|
|
||||||
package com.nostra13.universalimageloader.core;
|
|
||||||
|
|
||||||
import android.graphics.Bitmap;
|
|
||||||
import android.os.Handler;
|
|
||||||
import android.widget.ImageView;
|
|
||||||
import com.nostra13.universalimageloader.core.assist.LoadedFrom;
|
|
||||||
import com.nostra13.universalimageloader.core.process.BitmapProcessor;
|
|
||||||
import com.nostra13.universalimageloader.utils.L;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Presents process'n'display image task. Processes image {@linkplain Bitmap} and display it in {@link ImageView} using
|
|
||||||
* {@link DisplayBitmapTask}.
|
|
||||||
*
|
|
||||||
* @author Sergey Tarasevich (nostra13[at]gmail[dot]com)
|
|
||||||
* @since 1.8.0
|
|
||||||
*/
|
|
||||||
final class ProcessAndDisplayImageTask implements Runnable {
|
|
||||||
|
|
||||||
private static final String LOG_POSTPROCESS_IMAGE = "PostProcess image before displaying [%s]";
|
|
||||||
|
|
||||||
private final ImageLoaderEngine engine;
|
|
||||||
private final Bitmap bitmap;
|
|
||||||
private final ImageLoadingInfo imageLoadingInfo;
|
|
||||||
private final Handler handler;
|
|
||||||
|
|
||||||
public ProcessAndDisplayImageTask(ImageLoaderEngine engine, Bitmap bitmap, ImageLoadingInfo imageLoadingInfo,
|
|
||||||
Handler handler) {
|
|
||||||
this.engine = engine;
|
|
||||||
this.bitmap = bitmap;
|
|
||||||
this.imageLoadingInfo = imageLoadingInfo;
|
|
||||||
this.handler = handler;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
L.d(LOG_POSTPROCESS_IMAGE, imageLoadingInfo.memoryCacheKey);
|
|
||||||
|
|
||||||
BitmapProcessor processor = imageLoadingInfo.options.getPostProcessor();
|
|
||||||
Bitmap processedBitmap = processor.process(bitmap);
|
|
||||||
DisplayBitmapTask displayBitmapTask = new DisplayBitmapTask(processedBitmap, imageLoadingInfo, engine,
|
|
||||||
LoadedFrom.MEMORY_CACHE);
|
|
||||||
LoadAndDisplayImageTask.runTask(displayBitmapTask, imageLoadingInfo.options.isSyncLoading(), handler, engine);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,82 +0,0 @@
|
|||||||
/*******************************************************************************
|
|
||||||
* Copyright 2013-2014 Sergey Tarasevich
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*******************************************************************************/
|
|
||||||
package com.nostra13.universalimageloader.core.assist;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Decorator for {@link java.io.InputStream InputStream}. Provides possibility to return defined stream length by
|
|
||||||
* {@link #available()} method.
|
|
||||||
*
|
|
||||||
* @author Sergey Tarasevich (nostra13[at]gmail[dot]com), Mariotaku
|
|
||||||
* @since 1.9.1
|
|
||||||
*/
|
|
||||||
public class ContentLengthInputStream extends InputStream {
|
|
||||||
|
|
||||||
private final InputStream stream;
|
|
||||||
private final int length;
|
|
||||||
|
|
||||||
public ContentLengthInputStream(InputStream stream, int length) {
|
|
||||||
this.stream = stream;
|
|
||||||
this.length = length;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int available() {
|
|
||||||
return length;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void close() throws IOException {
|
|
||||||
stream.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void mark(int readLimit) {
|
|
||||||
stream.mark(readLimit);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int read() throws IOException {
|
|
||||||
return stream.read();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int read(byte[] buffer) throws IOException {
|
|
||||||
return stream.read(buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int read(byte[] buffer, int byteOffset, int byteCount) throws IOException {
|
|
||||||
return stream.read(buffer, byteOffset, byteCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void reset() throws IOException {
|
|
||||||
stream.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long skip(long byteCount) throws IOException {
|
|
||||||
return stream.skip(byteCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean markSupported() {
|
|
||||||
return stream.markSupported();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,65 +0,0 @@
|
|||||||
/*******************************************************************************
|
|
||||||
* Copyright 2011-2014 Sergey Tarasevich
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*******************************************************************************/
|
|
||||||
package com.nostra13.universalimageloader.core.assist;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Presents the reason why image loading and displaying was failed
|
|
||||||
*
|
|
||||||
* @author Sergey Tarasevich (nostra13[at]gmail[dot]com)
|
|
||||||
* @since 1.0.0
|
|
||||||
*/
|
|
||||||
public class FailReason {
|
|
||||||
|
|
||||||
private final FailType type;
|
|
||||||
|
|
||||||
private final Throwable cause;
|
|
||||||
|
|
||||||
public FailReason(FailType type, Throwable cause) {
|
|
||||||
this.type = type;
|
|
||||||
this.cause = cause;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @return {@linkplain FailType Fail type} */
|
|
||||||
public FailType getType() {
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @return Thrown exception/error, can be <b>null</b> */
|
|
||||||
public Throwable getCause() {
|
|
||||||
return cause;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Presents type of fail while image loading */
|
|
||||||
public static enum FailType {
|
|
||||||
/** Input/output error. Can be caused by network communication fail or error while caching image on file system. */
|
|
||||||
IO_ERROR,
|
|
||||||
/**
|
|
||||||
* Error while
|
|
||||||
* {@linkplain android.graphics.BitmapFactory#decodeStream(java.io.InputStream, android.graphics.Rect, android.graphics.BitmapFactory.Options)
|
|
||||||
* decode image to Bitmap}
|
|
||||||
*/
|
|
||||||
DECODING_ERROR,
|
|
||||||
/**
|
|
||||||
* {@linkplain com.nostra13.universalimageloader.core.ImageLoader#denyNetworkDownloads(boolean) Network
|
|
||||||
* downloads are denied} and requested image wasn't cached in disk cache before.
|
|
||||||
*/
|
|
||||||
NETWORK_DENIED,
|
|
||||||
/** Not enough memory to create needed Bitmap for image */
|
|
||||||
OUT_OF_MEMORY,
|
|
||||||
/** Unknown error was occurred while loading image */
|
|
||||||
UNKNOWN
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,34 +0,0 @@
|
|||||||
package com.nostra13.universalimageloader.core.assist;
|
|
||||||
|
|
||||||
import java.io.FilterInputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Many streams obtained over slow connection show <a href="http://code.google.com/p/android/issues/detail?id=6066">this
|
|
||||||
* problem</a>.
|
|
||||||
*/
|
|
||||||
public class FlushedInputStream extends FilterInputStream {
|
|
||||||
|
|
||||||
public FlushedInputStream(InputStream inputStream) {
|
|
||||||
super(inputStream);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long skip(long n) throws IOException {
|
|
||||||
long totalBytesSkipped = 0L;
|
|
||||||
while (totalBytesSkipped < n) {
|
|
||||||
long bytesSkipped = in.skip(n - totalBytesSkipped);
|
|
||||||
if (bytesSkipped == 0L) {
|
|
||||||
int by_te = read();
|
|
||||||
if (by_te < 0) {
|
|
||||||
break; // we reached EOF
|
|
||||||
} else {
|
|
||||||
bytesSkipped = 1; // we read one byte
|
|
||||||
}
|
|
||||||
}
|
|
||||||
totalBytesSkipped += bytesSkipped;
|
|
||||||
}
|
|
||||||
return totalBytesSkipped;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,78 +0,0 @@
|
|||||||
/*******************************************************************************
|
|
||||||
* Copyright 2011-2014 Sergey Tarasevich
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*******************************************************************************/
|
|
||||||
package com.nostra13.universalimageloader.core.assist;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Type of image scaling during decoding.
|
|
||||||
*
|
|
||||||
* @author Sergey Tarasevich (nostra13[at]gmail[dot]com)
|
|
||||||
* @since 1.5.0
|
|
||||||
*/
|
|
||||||
public enum ImageScaleType {
|
|
||||||
/** Image won't be scaled */
|
|
||||||
NONE,
|
|
||||||
/**
|
|
||||||
* Image will be scaled down only if image size is greater than
|
|
||||||
* {@linkplain javax.microedition.khronos.opengles.GL10#GL_MAX_TEXTURE_SIZE maximum acceptable texture size}.
|
|
||||||
* Usually it's 2048x2048.<br />
|
|
||||||
* If Bitmap is expected to display than it must not exceed this size (otherwise you'll get the exception
|
|
||||||
* "OpenGLRenderer: Bitmap too large to be uploaded into a texture".<br />
|
|
||||||
* Image will be subsampled in an integer number of times (1, 2, 3, ...) to maximum texture size of device.
|
|
||||||
*/
|
|
||||||
NONE_SAFE,
|
|
||||||
/**
|
|
||||||
* Image will be reduces 2-fold until next reduce step make image smaller target size.<br />
|
|
||||||
* It's <b>fast</b> type and it's preferable for usage in lists/grids/galleries (and other
|
|
||||||
* {@linkplain android.widget.AdapterView adapter-views}) .<br />
|
|
||||||
* Relates to {@link android.graphics.BitmapFactory.Options#inSampleSize}<br />
|
|
||||||
* Note: If original image size is smaller than target size then original image <b>won't</b> be scaled.
|
|
||||||
*/
|
|
||||||
IN_SAMPLE_POWER_OF_2,
|
|
||||||
/**
|
|
||||||
* Image will be subsampled in an integer number of times (1, 2, 3, ...). Use it if memory economy is quite
|
|
||||||
* important.<br />
|
|
||||||
* Relates to {@link android.graphics.BitmapFactory.Options#inSampleSize}<br />
|
|
||||||
* Note: If original image size is smaller than target size then original image <b>won't</b> be scaled.
|
|
||||||
*/
|
|
||||||
IN_SAMPLE_INT,
|
|
||||||
/**
|
|
||||||
* Image will scaled-down exactly to target size (scaled width or height or both will be equal to target size;
|
|
||||||
* depends on {@linkplain android.widget.ImageView.ScaleType ImageView's scale type}). Use it if memory economy is
|
|
||||||
* critically important.<br />
|
|
||||||
* <b>Note:</b> If original image size is smaller than target size then original image <b>won't</b> be scaled.<br />
|
|
||||||
* <br />
|
|
||||||
* <b>NOTE:</b> For creating result Bitmap (of exact size) additional Bitmap will be created with
|
|
||||||
* {@link android.graphics.Bitmap#createBitmap(android.graphics.Bitmap, int, int, int, int, android.graphics.Matrix, boolean)
|
|
||||||
* Bitmap.createBitmap(...)}.<br />
|
|
||||||
* <b>Cons:</b> Saves memory by keeping smaller Bitmap in memory cache (comparing with IN_SAMPLE... scale types)<br />
|
|
||||||
* <b>Pros:</b> Requires more memory in one time for creation of result Bitmap.
|
|
||||||
*/
|
|
||||||
EXACTLY,
|
|
||||||
/**
|
|
||||||
* Image will scaled exactly to target size (scaled width or height or both will be equal to target size; depends on
|
|
||||||
* {@linkplain android.widget.ImageView.ScaleType ImageView's scale type}). Use it if memory economy is critically
|
|
||||||
* important.<br />
|
|
||||||
* <b>Note:</b> If original image size is smaller than target size then original image <b>will be stretched</b> to
|
|
||||||
* target size.<br />
|
|
||||||
* <br />
|
|
||||||
* <b>NOTE:</b> For creating result Bitmap (of exact size) additional Bitmap will be created with
|
|
||||||
* {@link android.graphics.Bitmap#createBitmap(android.graphics.Bitmap, int, int, int, int, android.graphics.Matrix, boolean)
|
|
||||||
* Bitmap.createBitmap(...)}.<br />
|
|
||||||
* <b>Cons:</b> Saves memory by keeping smaller Bitmap in memory cache (comparing with IN_SAMPLE... scale types)<br />
|
|
||||||
* <b>Pros:</b> Requires more memory in one time for creation of result Bitmap.
|
|
||||||
*/
|
|
||||||
EXACTLY_STRETCHED
|
|
||||||
}
|
|
@ -1,69 +0,0 @@
|
|||||||
/*******************************************************************************
|
|
||||||
* Copyright 2011-2013 Sergey Tarasevich
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*******************************************************************************/
|
|
||||||
package com.nostra13.universalimageloader.core.assist;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Present width and height values
|
|
||||||
*
|
|
||||||
* @author Sergey Tarasevich (nostra13[at]gmail[dot]com)
|
|
||||||
* @since 1.0.0
|
|
||||||
*/
|
|
||||||
public class ImageSize {
|
|
||||||
|
|
||||||
private static final int TO_STRING_MAX_LENGHT = 9; // "9999x9999".length()
|
|
||||||
private static final String SEPARATOR = "x";
|
|
||||||
|
|
||||||
private final int width;
|
|
||||||
private final int height;
|
|
||||||
|
|
||||||
public ImageSize(int width, int height) {
|
|
||||||
this.width = width;
|
|
||||||
this.height = height;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ImageSize(int width, int height, int rotation) {
|
|
||||||
if (rotation % 180 == 0) {
|
|
||||||
this.width = width;
|
|
||||||
this.height = height;
|
|
||||||
} else {
|
|
||||||
this.width = height;
|
|
||||||
this.height = width;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getWidth() {
|
|
||||||
return width;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getHeight() {
|
|
||||||
return height;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Scales down dimensions in <b>sampleSize</b> times. Returns new object. */
|
|
||||||
public ImageSize scaleDown(int sampleSize) {
|
|
||||||
return new ImageSize(width / sampleSize, height / sampleSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Scales dimensions according to incoming scale. Returns new object. */
|
|
||||||
public ImageSize scale(float scale) {
|
|
||||||
return new ImageSize((int) (width * scale), (int) (height * scale));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return new StringBuilder(TO_STRING_MAX_LENGHT).append(width).append(SEPARATOR).append(height).toString();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,10 +0,0 @@
|
|||||||
package com.nostra13.universalimageloader.core.assist;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Source image loaded from.
|
|
||||||
*
|
|
||||||
* @author Sergey Tarasevich (nostra13[at]gmail[dot]com)
|
|
||||||
*/
|
|
||||||
public enum LoadedFrom {
|
|
||||||
NETWORK, DISC_CACHE, MEMORY_CACHE
|
|
||||||
}
|
|
@ -1,26 +0,0 @@
|
|||||||
/*******************************************************************************
|
|
||||||
* Copyright 2011-2013 Sergey Tarasevich
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*******************************************************************************/
|
|
||||||
package com.nostra13.universalimageloader.core.assist;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Queue processing type which will be used for display task processing
|
|
||||||
*
|
|
||||||
* @author Sergey Tarasevich (nostra13[at]gmail[dot]com)
|
|
||||||
* @since 1.6.3
|
|
||||||
*/
|
|
||||||
public enum QueueProcessingType {
|
|
||||||
FIFO, LIFO
|
|
||||||
}
|
|
@ -1,73 +0,0 @@
|
|||||||
/*******************************************************************************
|
|
||||||
* Copyright 2011-2013 Sergey Tarasevich
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*******************************************************************************/
|
|
||||||
package com.nostra13.universalimageloader.core.assist;
|
|
||||||
|
|
||||||
import android.widget.ImageView;
|
|
||||||
import android.widget.ImageView.ScaleType;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Simplify {@linkplain ScaleType ImageView's scale type} to 2 types: {@link #FIT_INSIDE} and {@link #CROP}
|
|
||||||
*
|
|
||||||
* @author Sergey Tarasevich (nostra13[at]gmail[dot]com)
|
|
||||||
* @since 1.6.1
|
|
||||||
*/
|
|
||||||
public enum ViewScaleType {
|
|
||||||
/**
|
|
||||||
* Scale the image uniformly (maintain the image's aspect ratio) so that at least one dimension (width or height) of
|
|
||||||
* the image will be equal to or less the corresponding dimension of the view.
|
|
||||||
*/
|
|
||||||
FIT_INSIDE,
|
|
||||||
/**
|
|
||||||
* Scale the image uniformly (maintain the image's aspect ratio) so that both dimensions (width and height) of the
|
|
||||||
* image will be equal to or larger than the corresponding dimension of the view.
|
|
||||||
*/
|
|
||||||
CROP;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Defines scale type of ImageView.
|
|
||||||
*
|
|
||||||
* @param imageView {@link ImageView}
|
|
||||||
* @return {@link #FIT_INSIDE} for
|
|
||||||
* <ul>
|
|
||||||
* <li>{@link ScaleType#FIT_CENTER}</li>
|
|
||||||
* <li>{@link ScaleType#FIT_XY}</li>
|
|
||||||
* <li>{@link ScaleType#FIT_START}</li>
|
|
||||||
* <li>{@link ScaleType#FIT_END}</li>
|
|
||||||
* <li>{@link ScaleType#CENTER_INSIDE}</li>
|
|
||||||
* </ul>
|
|
||||||
* {@link #CROP} for
|
|
||||||
* <ul>
|
|
||||||
* <li>{@link ScaleType#CENTER}</li>
|
|
||||||
* <li>{@link ScaleType#CENTER_CROP}</li>
|
|
||||||
* <li>{@link ScaleType#MATRIX}</li>
|
|
||||||
* </ul>
|
|
||||||
*/
|
|
||||||
public static ViewScaleType fromImageView(ImageView imageView) {
|
|
||||||
switch (imageView.getScaleType()) {
|
|
||||||
case FIT_CENTER:
|
|
||||||
case FIT_XY:
|
|
||||||
case FIT_START:
|
|
||||||
case FIT_END:
|
|
||||||
case CENTER_INSIDE:
|
|
||||||
return FIT_INSIDE;
|
|
||||||
case MATRIX:
|
|
||||||
case CENTER:
|
|
||||||
case CENTER_CROP:
|
|
||||||
default:
|
|
||||||
return CROP;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,616 +0,0 @@
|
|||||||
/*
|
|
||||||
* Written by Doug Lea with assistance from members of JCP JSR-166
|
|
||||||
* Expert Group and released to the public domain, as explained at
|
|
||||||
* http://creativecommons.org/licenses/publicdomain
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.nostra13.universalimageloader.core.assist.deque;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.NoSuchElementException;
|
|
||||||
import java.util.concurrent.BlockingQueue;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A {@link Deque} that additionally supports blocking operations that wait
|
|
||||||
* for the deque to become non-empty when retrieving an element, and wait for
|
|
||||||
* space to become available in the deque when storing an element.
|
|
||||||
*
|
|
||||||
* <p><tt>BlockingDeque</tt> methods come in four forms, with different ways
|
|
||||||
* of handling operations that cannot be satisfied immediately, but may be
|
|
||||||
* satisfied at some point in the future:
|
|
||||||
* one throws an exception, the second returns a special value (either
|
|
||||||
* <tt>null</tt> or <tt>false</tt>, depending on the operation), the third
|
|
||||||
* blocks the current thread indefinitely until the operation can succeed,
|
|
||||||
* and the fourth blocks for only a given maximum time limit before giving
|
|
||||||
* up. These methods are summarized in the following table:
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* <table BORDER CELLPADDING=3 CELLSPACING=1>
|
|
||||||
* <tr>
|
|
||||||
* <td ALIGN=CENTER COLSPAN = 5> <b>First Element (Head)</b></td>
|
|
||||||
* </tr>
|
|
||||||
* <tr>
|
|
||||||
* <td></td>
|
|
||||||
* <td ALIGN=CENTER><em>Throws exception</em></td>
|
|
||||||
* <td ALIGN=CENTER><em>Special value</em></td>
|
|
||||||
* <td ALIGN=CENTER><em>Blocks</em></td>
|
|
||||||
* <td ALIGN=CENTER><em>Times out</em></td>
|
|
||||||
* </tr>
|
|
||||||
* <tr>
|
|
||||||
* <td><b>Insert</b></td>
|
|
||||||
* <td>{@link #addFirst addFirst(e)}</td>
|
|
||||||
* <td>{@link #offerFirst offerFirst(e)}</td>
|
|
||||||
* <td>{@link #putFirst putFirst(e)}</td>
|
|
||||||
* <td>{@link #offerFirst offerFirst(e, time, unit)}</td>
|
|
||||||
* </tr>
|
|
||||||
* <tr>
|
|
||||||
* <td><b>Remove</b></td>
|
|
||||||
* <td>{@link #removeFirst removeFirst()}</td>
|
|
||||||
* <td>{@link #pollFirst pollFirst()}</td>
|
|
||||||
* <td>{@link #takeFirst takeFirst()}</td>
|
|
||||||
* <td>{@link #pollFirst(long, TimeUnit) pollFirst(time, unit)}</td>
|
|
||||||
* </tr>
|
|
||||||
* <tr>
|
|
||||||
* <td><b>Examine</b></td>
|
|
||||||
* <td>{@link #getFirst getFirst()}</td>
|
|
||||||
* <td>{@link #peekFirst peekFirst()}</td>
|
|
||||||
* <td><em>not applicable</em></td>
|
|
||||||
* <td><em>not applicable</em></td>
|
|
||||||
* </tr>
|
|
||||||
* <tr>
|
|
||||||
* <td ALIGN=CENTER COLSPAN = 5> <b>Last Element (Tail)</b></td>
|
|
||||||
* </tr>
|
|
||||||
* <tr>
|
|
||||||
* <td></td>
|
|
||||||
* <td ALIGN=CENTER><em>Throws exception</em></td>
|
|
||||||
* <td ALIGN=CENTER><em>Special value</em></td>
|
|
||||||
* <td ALIGN=CENTER><em>Blocks</em></td>
|
|
||||||
* <td ALIGN=CENTER><em>Times out</em></td>
|
|
||||||
* </tr>
|
|
||||||
* <tr>
|
|
||||||
* <td><b>Insert</b></td>
|
|
||||||
* <td>{@link #addLast addLast(e)}</td>
|
|
||||||
* <td>{@link #offerLast offerLast(e)}</td>
|
|
||||||
* <td>{@link #putLast putLast(e)}</td>
|
|
||||||
* <td>{@link #offerLast offerLast(e, time, unit)}</td>
|
|
||||||
* </tr>
|
|
||||||
* <tr>
|
|
||||||
* <td><b>Remove</b></td>
|
|
||||||
* <td>{@link #removeLast() removeLast()}</td>
|
|
||||||
* <td>{@link #pollLast() pollLast()}</td>
|
|
||||||
* <td>{@link #takeLast takeLast()}</td>
|
|
||||||
* <td>{@link #pollLast(long, TimeUnit) pollLast(time, unit)}</td>
|
|
||||||
* </tr>
|
|
||||||
* <tr>
|
|
||||||
* <td><b>Examine</b></td>
|
|
||||||
* <td>{@link #getLast getLast()}</td>
|
|
||||||
* <td>{@link #peekLast peekLast()}</td>
|
|
||||||
* <td><em>not applicable</em></td>
|
|
||||||
* <td><em>not applicable</em></td>
|
|
||||||
* </tr>
|
|
||||||
* </table>
|
|
||||||
*
|
|
||||||
* <p>Like any {@link BlockingQueue}, a <tt>BlockingDeque</tt> is thread safe,
|
|
||||||
* does not permit null elements, and may (or may not) be
|
|
||||||
* capacity-constrained.
|
|
||||||
*
|
|
||||||
* <p>A <tt>BlockingDeque</tt> implementation may be used directly as a FIFO
|
|
||||||
* <tt>BlockingQueue</tt>. The methods inherited from the
|
|
||||||
* <tt>BlockingQueue</tt> interface are precisely equivalent to
|
|
||||||
* <tt>BlockingDeque</tt> methods as indicated in the following table:
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* <table BORDER CELLPADDING=3 CELLSPACING=1>
|
|
||||||
* <tr>
|
|
||||||
* <td ALIGN=CENTER> <b><tt>BlockingQueue</tt> Method</b></td>
|
|
||||||
* <td ALIGN=CENTER> <b>Equivalent <tt>BlockingDeque</tt> Method</b></td>
|
|
||||||
* </tr>
|
|
||||||
* <tr>
|
|
||||||
* <td ALIGN=CENTER COLSPAN = 2> <b>Insert</b></td>
|
|
||||||
* </tr>
|
|
||||||
* <tr>
|
|
||||||
* <td>{@link #add add(e)}</td>
|
|
||||||
* <td>{@link #addLast addLast(e)}</td>
|
|
||||||
* </tr>
|
|
||||||
* <tr>
|
|
||||||
* <td>{@link #offer offer(e)}</td>
|
|
||||||
* <td>{@link #offerLast offerLast(e)}</td>
|
|
||||||
* </tr>
|
|
||||||
* <tr>
|
|
||||||
* <td>{@link #put put(e)}</td>
|
|
||||||
* <td>{@link #putLast putLast(e)}</td>
|
|
||||||
* </tr>
|
|
||||||
* <tr>
|
|
||||||
* <td>{@link #offer offer(e, time, unit)}</td>
|
|
||||||
* <td>{@link #offerLast offerLast(e, time, unit)}</td>
|
|
||||||
* </tr>
|
|
||||||
* <tr>
|
|
||||||
* <td ALIGN=CENTER COLSPAN = 2> <b>Remove</b></td>
|
|
||||||
* </tr>
|
|
||||||
* <tr>
|
|
||||||
* <td>{@link #remove() remove()}</td>
|
|
||||||
* <td>{@link #removeFirst() removeFirst()}</td>
|
|
||||||
* </tr>
|
|
||||||
* <tr>
|
|
||||||
* <td>{@link #poll() poll()}</td>
|
|
||||||
* <td>{@link #pollFirst() pollFirst()}</td>
|
|
||||||
* </tr>
|
|
||||||
* <tr>
|
|
||||||
* <td>{@link #take() take()}</td>
|
|
||||||
* <td>{@link #takeFirst() takeFirst()}</td>
|
|
||||||
* </tr>
|
|
||||||
* <tr>
|
|
||||||
* <td>{@link #poll(long, TimeUnit) poll(time, unit)}</td>
|
|
||||||
* <td>{@link #pollFirst(long, TimeUnit) pollFirst(time, unit)}</td>
|
|
||||||
* </tr>
|
|
||||||
* <tr>
|
|
||||||
* <td ALIGN=CENTER COLSPAN = 2> <b>Examine</b></td>
|
|
||||||
* </tr>
|
|
||||||
* <tr>
|
|
||||||
* <td>{@link #element() element()}</td>
|
|
||||||
* <td>{@link #getFirst() getFirst()}</td>
|
|
||||||
* </tr>
|
|
||||||
* <tr>
|
|
||||||
* <td>{@link #peek() peek()}</td>
|
|
||||||
* <td>{@link #peekFirst() peekFirst()}</td>
|
|
||||||
* </tr>
|
|
||||||
* </table>
|
|
||||||
*
|
|
||||||
* <p>Memory consistency effects: As with other concurrent
|
|
||||||
* collections, actions in a thread prior to placing an object into a
|
|
||||||
* {@code BlockingDeque}
|
|
||||||
* <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a>
|
|
||||||
* actions subsequent to the access or removal of that element from
|
|
||||||
* the {@code BlockingDeque} in another thread.
|
|
||||||
*
|
|
||||||
* <p>This interface is a member of the
|
|
||||||
* <a href="{@docRoot}/../technotes/guides/collections/index.html">
|
|
||||||
* Java Collections Framework</a>.
|
|
||||||
*
|
|
||||||
* @since 1.6
|
|
||||||
* @author Doug Lea
|
|
||||||
* @param <E> the type of elements held in this collection
|
|
||||||
*/
|
|
||||||
public interface BlockingDeque<E> extends BlockingQueue<E>, Deque<E> {
|
|
||||||
/*
|
|
||||||
* We have "diamond" multiple interface inheritance here, and that
|
|
||||||
* introduces ambiguities. Methods might end up with different
|
|
||||||
* specs depending on the branch chosen by javadoc. Thus a lot of
|
|
||||||
* methods specs here are copied from superinterfaces.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Inserts the specified element at the front of this deque if it is
|
|
||||||
* possible to do so immediately without violating capacity restrictions,
|
|
||||||
* throwing an <tt>IllegalStateException</tt> if no space is currently
|
|
||||||
* available. When using a capacity-restricted deque, it is generally
|
|
||||||
* preferable to use {@link #offerFirst offerFirst}.
|
|
||||||
*
|
|
||||||
* @param e the element to add
|
|
||||||
* @throws IllegalStateException {@inheritDoc}
|
|
||||||
* @throws ClassCastException {@inheritDoc}
|
|
||||||
* @throws NullPointerException if the specified element is null
|
|
||||||
* @throws IllegalArgumentException {@inheritDoc}
|
|
||||||
*/
|
|
||||||
void addFirst(E e);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Inserts the specified element at the end of this deque if it is
|
|
||||||
* possible to do so immediately without violating capacity restrictions,
|
|
||||||
* throwing an <tt>IllegalStateException</tt> if no space is currently
|
|
||||||
* available. When using a capacity-restricted deque, it is generally
|
|
||||||
* preferable to use {@link #offerLast offerLast}.
|
|
||||||
*
|
|
||||||
* @param e the element to add
|
|
||||||
* @throws IllegalStateException {@inheritDoc}
|
|
||||||
* @throws ClassCastException {@inheritDoc}
|
|
||||||
* @throws NullPointerException if the specified element is null
|
|
||||||
* @throws IllegalArgumentException {@inheritDoc}
|
|
||||||
*/
|
|
||||||
void addLast(E e);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Inserts the specified element at the front of this deque if it is
|
|
||||||
* possible to do so immediately without violating capacity restrictions,
|
|
||||||
* returning <tt>true</tt> upon success and <tt>false</tt> if no space is
|
|
||||||
* currently available.
|
|
||||||
* When using a capacity-restricted deque, this method is generally
|
|
||||||
* preferable to the {@link #addFirst addFirst} method, which can
|
|
||||||
* fail to insert an element only by throwing an exception.
|
|
||||||
*
|
|
||||||
* @param e the element to add
|
|
||||||
* @throws ClassCastException {@inheritDoc}
|
|
||||||
* @throws NullPointerException if the specified element is null
|
|
||||||
* @throws IllegalArgumentException {@inheritDoc}
|
|
||||||
*/
|
|
||||||
boolean offerFirst(E e);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Inserts the specified element at the end of this deque if it is
|
|
||||||
* possible to do so immediately without violating capacity restrictions,
|
|
||||||
* returning <tt>true</tt> upon success and <tt>false</tt> if no space is
|
|
||||||
* currently available.
|
|
||||||
* When using a capacity-restricted deque, this method is generally
|
|
||||||
* preferable to the {@link #addLast addLast} method, which can
|
|
||||||
* fail to insert an element only by throwing an exception.
|
|
||||||
*
|
|
||||||
* @param e the element to add
|
|
||||||
* @throws ClassCastException {@inheritDoc}
|
|
||||||
* @throws NullPointerException if the specified element is null
|
|
||||||
* @throws IllegalArgumentException {@inheritDoc}
|
|
||||||
*/
|
|
||||||
boolean offerLast(E e);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Inserts the specified element at the front of this deque,
|
|
||||||
* waiting if necessary for space to become available.
|
|
||||||
*
|
|
||||||
* @param e the element to add
|
|
||||||
* @throws InterruptedException if interrupted while waiting
|
|
||||||
* @throws ClassCastException if the class of the specified element
|
|
||||||
* prevents it from being added to this deque
|
|
||||||
* @throws NullPointerException if the specified element is null
|
|
||||||
* @throws IllegalArgumentException if some property of the specified
|
|
||||||
* element prevents it from being added to this deque
|
|
||||||
*/
|
|
||||||
void putFirst(E e) throws InterruptedException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Inserts the specified element at the end of this deque,
|
|
||||||
* waiting if necessary for space to become available.
|
|
||||||
*
|
|
||||||
* @param e the element to add
|
|
||||||
* @throws InterruptedException if interrupted while waiting
|
|
||||||
* @throws ClassCastException if the class of the specified element
|
|
||||||
* prevents it from being added to this deque
|
|
||||||
* @throws NullPointerException if the specified element is null
|
|
||||||
* @throws IllegalArgumentException if some property of the specified
|
|
||||||
* element prevents it from being added to this deque
|
|
||||||
*/
|
|
||||||
void putLast(E e) throws InterruptedException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Inserts the specified element at the front of this deque,
|
|
||||||
* waiting up to the specified wait time if necessary for space to
|
|
||||||
* become available.
|
|
||||||
*
|
|
||||||
* @param e the element to add
|
|
||||||
* @param timeout how long to wait before giving up, in units of
|
|
||||||
* <tt>unit</tt>
|
|
||||||
* @param unit a <tt>TimeUnit</tt> determining how to interpret the
|
|
||||||
* <tt>timeout</tt> parameter
|
|
||||||
* @return <tt>true</tt> if successful, or <tt>false</tt> if
|
|
||||||
* the specified waiting time elapses before space is available
|
|
||||||
* @throws InterruptedException if interrupted while waiting
|
|
||||||
* @throws ClassCastException if the class of the specified element
|
|
||||||
* prevents it from being added to this deque
|
|
||||||
* @throws NullPointerException if the specified element is null
|
|
||||||
* @throws IllegalArgumentException if some property of the specified
|
|
||||||
* element prevents it from being added to this deque
|
|
||||||
*/
|
|
||||||
boolean offerFirst(E e, long timeout, TimeUnit unit)
|
|
||||||
throws InterruptedException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Inserts the specified element at the end of this deque,
|
|
||||||
* waiting up to the specified wait time if necessary for space to
|
|
||||||
* become available.
|
|
||||||
*
|
|
||||||
* @param e the element to add
|
|
||||||
* @param timeout how long to wait before giving up, in units of
|
|
||||||
* <tt>unit</tt>
|
|
||||||
* @param unit a <tt>TimeUnit</tt> determining how to interpret the
|
|
||||||
* <tt>timeout</tt> parameter
|
|
||||||
* @return <tt>true</tt> if successful, or <tt>false</tt> if
|
|
||||||
* the specified waiting time elapses before space is available
|
|
||||||
* @throws InterruptedException if interrupted while waiting
|
|
||||||
* @throws ClassCastException if the class of the specified element
|
|
||||||
* prevents it from being added to this deque
|
|
||||||
* @throws NullPointerException if the specified element is null
|
|
||||||
* @throws IllegalArgumentException if some property of the specified
|
|
||||||
* element prevents it from being added to this deque
|
|
||||||
*/
|
|
||||||
boolean offerLast(E e, long timeout, TimeUnit unit)
|
|
||||||
throws InterruptedException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves and removes the first element of this deque, waiting
|
|
||||||
* if necessary until an element becomes available.
|
|
||||||
*
|
|
||||||
* @return the head of this deque
|
|
||||||
* @throws InterruptedException if interrupted while waiting
|
|
||||||
*/
|
|
||||||
E takeFirst() throws InterruptedException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves and removes the last element of this deque, waiting
|
|
||||||
* if necessary until an element becomes available.
|
|
||||||
*
|
|
||||||
* @return the tail of this deque
|
|
||||||
* @throws InterruptedException if interrupted while waiting
|
|
||||||
*/
|
|
||||||
E takeLast() throws InterruptedException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves and removes the first element of this deque, waiting
|
|
||||||
* up to the specified wait time if necessary for an element to
|
|
||||||
* become available.
|
|
||||||
*
|
|
||||||
* @param timeout how long to wait before giving up, in units of
|
|
||||||
* <tt>unit</tt>
|
|
||||||
* @param unit a <tt>TimeUnit</tt> determining how to interpret the
|
|
||||||
* <tt>timeout</tt> parameter
|
|
||||||
* @return the head of this deque, or <tt>null</tt> if the specified
|
|
||||||
* waiting time elapses before an element is available
|
|
||||||
* @throws InterruptedException if interrupted while waiting
|
|
||||||
*/
|
|
||||||
E pollFirst(long timeout, TimeUnit unit)
|
|
||||||
throws InterruptedException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves and removes the last element of this deque, waiting
|
|
||||||
* up to the specified wait time if necessary for an element to
|
|
||||||
* become available.
|
|
||||||
*
|
|
||||||
* @param timeout how long to wait before giving up, in units of
|
|
||||||
* <tt>unit</tt>
|
|
||||||
* @param unit a <tt>TimeUnit</tt> determining how to interpret the
|
|
||||||
* <tt>timeout</tt> parameter
|
|
||||||
* @return the tail of this deque, or <tt>null</tt> if the specified
|
|
||||||
* waiting time elapses before an element is available
|
|
||||||
* @throws InterruptedException if interrupted while waiting
|
|
||||||
*/
|
|
||||||
E pollLast(long timeout, TimeUnit unit)
|
|
||||||
throws InterruptedException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes the first occurrence of the specified element from this deque.
|
|
||||||
* If the deque does not contain the element, it is unchanged.
|
|
||||||
* More formally, removes the first element <tt>e</tt> such that
|
|
||||||
* <tt>o.equals(e)</tt> (if such an element exists).
|
|
||||||
* Returns <tt>true</tt> if this deque contained the specified element
|
|
||||||
* (or equivalently, if this deque changed as a result of the call).
|
|
||||||
*
|
|
||||||
* @param o element to be removed from this deque, if present
|
|
||||||
* @return <tt>true</tt> if an element was removed as a result of this call
|
|
||||||
* @throws ClassCastException if the class of the specified element
|
|
||||||
* is incompatible with this deque (optional)
|
|
||||||
* @throws NullPointerException if the specified element is null (optional)
|
|
||||||
*/
|
|
||||||
boolean removeFirstOccurrence(Object o);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes the last occurrence of the specified element from this deque.
|
|
||||||
* If the deque does not contain the element, it is unchanged.
|
|
||||||
* More formally, removes the last element <tt>e</tt> such that
|
|
||||||
* <tt>o.equals(e)</tt> (if such an element exists).
|
|
||||||
* Returns <tt>true</tt> if this deque contained the specified element
|
|
||||||
* (or equivalently, if this deque changed as a result of the call).
|
|
||||||
*
|
|
||||||
* @param o element to be removed from this deque, if present
|
|
||||||
* @return <tt>true</tt> if an element was removed as a result of this call
|
|
||||||
* @throws ClassCastException if the class of the specified element
|
|
||||||
* is incompatible with this deque (optional)
|
|
||||||
* @throws NullPointerException if the specified element is null (optional)
|
|
||||||
*/
|
|
||||||
boolean removeLastOccurrence(Object o);
|
|
||||||
|
|
||||||
// *** BlockingQueue methods ***
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Inserts the specified element into the queue represented by this deque
|
|
||||||
* (in other words, at the tail of this deque) if it is possible to do so
|
|
||||||
* immediately without violating capacity restrictions, returning
|
|
||||||
* <tt>true</tt> upon success and throwing an
|
|
||||||
* <tt>IllegalStateException</tt> if no space is currently available.
|
|
||||||
* When using a capacity-restricted deque, it is generally preferable to
|
|
||||||
* use {@link #offer offer}.
|
|
||||||
*
|
|
||||||
* <p>This method is equivalent to {@link #addLast addLast}.
|
|
||||||
*
|
|
||||||
* @param e the element to add
|
|
||||||
* @throws IllegalStateException {@inheritDoc}
|
|
||||||
* @throws ClassCastException if the class of the specified element
|
|
||||||
* prevents it from being added to this deque
|
|
||||||
* @throws NullPointerException if the specified element is null
|
|
||||||
* @throws IllegalArgumentException if some property of the specified
|
|
||||||
* element prevents it from being added to this deque
|
|
||||||
*/
|
|
||||||
boolean add(E e);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Inserts the specified element into the queue represented by this deque
|
|
||||||
* (in other words, at the tail of this deque) if it is possible to do so
|
|
||||||
* immediately without violating capacity restrictions, returning
|
|
||||||
* <tt>true</tt> upon success and <tt>false</tt> if no space is currently
|
|
||||||
* available. When using a capacity-restricted deque, this method is
|
|
||||||
* generally preferable to the {@link #add} method, which can fail to
|
|
||||||
* insert an element only by throwing an exception.
|
|
||||||
*
|
|
||||||
* <p>This method is equivalent to {@link #offerLast offerLast}.
|
|
||||||
*
|
|
||||||
* @param e the element to add
|
|
||||||
* @throws ClassCastException if the class of the specified element
|
|
||||||
* prevents it from being added to this deque
|
|
||||||
* @throws NullPointerException if the specified element is null
|
|
||||||
* @throws IllegalArgumentException if some property of the specified
|
|
||||||
* element prevents it from being added to this deque
|
|
||||||
*/
|
|
||||||
boolean offer(E e);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Inserts the specified element into the queue represented by this deque
|
|
||||||
* (in other words, at the tail of this deque), waiting if necessary for
|
|
||||||
* space to become available.
|
|
||||||
*
|
|
||||||
* <p>This method is equivalent to {@link #putLast putLast}.
|
|
||||||
*
|
|
||||||
* @param e the element to add
|
|
||||||
* @throws InterruptedException {@inheritDoc}
|
|
||||||
* @throws ClassCastException if the class of the specified element
|
|
||||||
* prevents it from being added to this deque
|
|
||||||
* @throws NullPointerException if the specified element is null
|
|
||||||
* @throws IllegalArgumentException if some property of the specified
|
|
||||||
* element prevents it from being added to this deque
|
|
||||||
*/
|
|
||||||
void put(E e) throws InterruptedException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Inserts the specified element into the queue represented by this deque
|
|
||||||
* (in other words, at the tail of this deque), waiting up to the
|
|
||||||
* specified wait time if necessary for space to become available.
|
|
||||||
*
|
|
||||||
* <p>This method is equivalent to
|
|
||||||
* {@link #offerLast offerLast}.
|
|
||||||
*
|
|
||||||
* @param e the element to add
|
|
||||||
* @return <tt>true</tt> if the element was added to this deque, else
|
|
||||||
* <tt>false</tt>
|
|
||||||
* @throws InterruptedException {@inheritDoc}
|
|
||||||
* @throws ClassCastException if the class of the specified element
|
|
||||||
* prevents it from being added to this deque
|
|
||||||
* @throws NullPointerException if the specified element is null
|
|
||||||
* @throws IllegalArgumentException if some property of the specified
|
|
||||||
* element prevents it from being added to this deque
|
|
||||||
*/
|
|
||||||
boolean offer(E e, long timeout, TimeUnit unit)
|
|
||||||
throws InterruptedException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves and removes the head of the queue represented by this deque
|
|
||||||
* (in other words, the first element of this deque).
|
|
||||||
* This method differs from {@link #poll poll} only in that it
|
|
||||||
* throws an exception if this deque is empty.
|
|
||||||
*
|
|
||||||
* <p>This method is equivalent to {@link #removeFirst() removeFirst}.
|
|
||||||
*
|
|
||||||
* @return the head of the queue represented by this deque
|
|
||||||
* @throws NoSuchElementException if this deque is empty
|
|
||||||
*/
|
|
||||||
E remove();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves and removes the head of the queue represented by this deque
|
|
||||||
* (in other words, the first element of this deque), or returns
|
|
||||||
* <tt>null</tt> if this deque is empty.
|
|
||||||
*
|
|
||||||
* <p>This method is equivalent to {@link #pollFirst()}.
|
|
||||||
*
|
|
||||||
* @return the head of this deque, or <tt>null</tt> if this deque is empty
|
|
||||||
*/
|
|
||||||
E poll();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves and removes the head of the queue represented by this deque
|
|
||||||
* (in other words, the first element of this deque), waiting if
|
|
||||||
* necessary until an element becomes available.
|
|
||||||
*
|
|
||||||
* <p>This method is equivalent to {@link #takeFirst() takeFirst}.
|
|
||||||
*
|
|
||||||
* @return the head of this deque
|
|
||||||
* @throws InterruptedException if interrupted while waiting
|
|
||||||
*/
|
|
||||||
E take() throws InterruptedException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves and removes the head of the queue represented by this deque
|
|
||||||
* (in other words, the first element of this deque), waiting up to the
|
|
||||||
* specified wait time if necessary for an element to become available.
|
|
||||||
*
|
|
||||||
* <p>This method is equivalent to
|
|
||||||
* {@link #pollFirst(long,TimeUnit) pollFirst}.
|
|
||||||
*
|
|
||||||
* @return the head of this deque, or <tt>null</tt> if the
|
|
||||||
* specified waiting time elapses before an element is available
|
|
||||||
* @throws InterruptedException if interrupted while waiting
|
|
||||||
*/
|
|
||||||
E poll(long timeout, TimeUnit unit)
|
|
||||||
throws InterruptedException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves, but does not remove, the head of the queue represented by
|
|
||||||
* this deque (in other words, the first element of this deque).
|
|
||||||
* This method differs from {@link #peek peek} only in that it throws an
|
|
||||||
* exception if this deque is empty.
|
|
||||||
*
|
|
||||||
* <p>This method is equivalent to {@link #getFirst() getFirst}.
|
|
||||||
*
|
|
||||||
* @return the head of this deque
|
|
||||||
* @throws NoSuchElementException if this deque is empty
|
|
||||||
*/
|
|
||||||
E element();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves, but does not remove, the head of the queue represented by
|
|
||||||
* this deque (in other words, the first element of this deque), or
|
|
||||||
* returns <tt>null</tt> if this deque is empty.
|
|
||||||
*
|
|
||||||
* <p>This method is equivalent to {@link #peekFirst() peekFirst}.
|
|
||||||
*
|
|
||||||
* @return the head of this deque, or <tt>null</tt> if this deque is empty
|
|
||||||
*/
|
|
||||||
E peek();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes the first occurrence of the specified element from this deque.
|
|
||||||
* If the deque does not contain the element, it is unchanged.
|
|
||||||
* More formally, removes the first element <tt>e</tt> such that
|
|
||||||
* <tt>o.equals(e)</tt> (if such an element exists).
|
|
||||||
* Returns <tt>true</tt> if this deque contained the specified element
|
|
||||||
* (or equivalently, if this deque changed as a result of the call).
|
|
||||||
*
|
|
||||||
* <p>This method is equivalent to
|
|
||||||
* {@link #removeFirstOccurrence removeFirstOccurrence}.
|
|
||||||
*
|
|
||||||
* @param o element to be removed from this deque, if present
|
|
||||||
* @return <tt>true</tt> if this deque changed as a result of the call
|
|
||||||
* @throws ClassCastException if the class of the specified element
|
|
||||||
* is incompatible with this deque (optional)
|
|
||||||
* @throws NullPointerException if the specified element is null (optional)
|
|
||||||
*/
|
|
||||||
boolean remove(Object o);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns <tt>true</tt> if this deque contains the specified element.
|
|
||||||
* More formally, returns <tt>true</tt> if and only if this deque contains
|
|
||||||
* at least one element <tt>e</tt> such that <tt>o.equals(e)</tt>.
|
|
||||||
*
|
|
||||||
* @param o object to be checked for containment in this deque
|
|
||||||
* @return <tt>true</tt> if this deque contains the specified element
|
|
||||||
* @throws ClassCastException if the class of the specified element
|
|
||||||
* is incompatible with this deque (optional)
|
|
||||||
* @throws NullPointerException if the specified element is null (optional)
|
|
||||||
*/
|
|
||||||
public boolean contains(Object o);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the number of elements in this deque.
|
|
||||||
*
|
|
||||||
* @return the number of elements in this deque
|
|
||||||
*/
|
|
||||||
public int size();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an iterator over the elements in this deque in proper sequence.
|
|
||||||
* The elements will be returned in order from first (head) to last (tail).
|
|
||||||
*
|
|
||||||
* @return an iterator over the elements in this deque in proper sequence
|
|
||||||
*/
|
|
||||||
Iterator<E> iterator();
|
|
||||||
|
|
||||||
// *** Stack methods ***
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Pushes an element onto the stack represented by this deque. In other
|
|
||||||
* words, inserts the element at the front of this deque unless it would
|
|
||||||
* violate capacity restrictions.
|
|
||||||
*
|
|
||||||
* <p>This method is equivalent to {@link #addFirst addFirst}.
|
|
||||||
*
|
|
||||||
* @throws IllegalStateException {@inheritDoc}
|
|
||||||
* @throws ClassCastException {@inheritDoc}
|
|
||||||
* @throws NullPointerException if the specified element is null
|
|
||||||
* @throws IllegalArgumentException {@inheritDoc}
|
|
||||||
*/
|
|
||||||
void push(E e);
|
|
||||||
}
|
|
@ -1,550 +0,0 @@
|
|||||||
/*
|
|
||||||
* Written by Doug Lea and Josh Bloch with assistance from members of
|
|
||||||
* JCP JSR-166 Expert Group and released to the public domain, as explained
|
|
||||||
* at http://creativecommons.org/licenses/publicdomain
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.nostra13.universalimageloader.core.assist.deque;
|
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.NoSuchElementException;
|
|
||||||
import java.util.Queue;
|
|
||||||
import java.util.Stack;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A linear collection that supports element insertion and removal at
|
|
||||||
* both ends. The name <i>deque</i> is short for "double ended queue"
|
|
||||||
* and is usually pronounced "deck". Most <tt>Deque</tt>
|
|
||||||
* implementations place no fixed limits on the number of elements
|
|
||||||
* they may contain, but this interface supports capacity-restricted
|
|
||||||
* deques as well as those with no fixed size limit.
|
|
||||||
*
|
|
||||||
* <p>This interface defines methods to access the elements at both
|
|
||||||
* ends of the deque. Methods are provided to insert, remove, and
|
|
||||||
* examine the element. Each of these methods exists in two forms:
|
|
||||||
* one throws an exception if the operation fails, the other returns a
|
|
||||||
* special value (either <tt>null</tt> or <tt>false</tt>, depending on
|
|
||||||
* the operation). The latter form of the insert operation is
|
|
||||||
* designed specifically for use with capacity-restricted
|
|
||||||
* <tt>Deque</tt> implementations; in most implementations, insert
|
|
||||||
* operations cannot fail.
|
|
||||||
*
|
|
||||||
* <p>The twelve methods described above are summarized in the
|
|
||||||
* following table:
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* <table BORDER CELLPADDING=3 CELLSPACING=1>
|
|
||||||
* <tr>
|
|
||||||
* <td></td>
|
|
||||||
* <td ALIGN=CENTER COLSPAN = 2> <b>First Element (Head)</b></td>
|
|
||||||
* <td ALIGN=CENTER COLSPAN = 2> <b>Last Element (Tail)</b></td>
|
|
||||||
* </tr>
|
|
||||||
* <tr>
|
|
||||||
* <td></td>
|
|
||||||
* <td ALIGN=CENTER><em>Throws exception</em></td>
|
|
||||||
* <td ALIGN=CENTER><em>Special value</em></td>
|
|
||||||
* <td ALIGN=CENTER><em>Throws exception</em></td>
|
|
||||||
* <td ALIGN=CENTER><em>Special value</em></td>
|
|
||||||
* </tr>
|
|
||||||
* <tr>
|
|
||||||
* <td><b>Insert</b></td>
|
|
||||||
* <td>{@link #addFirst addFirst(e)}</td>
|
|
||||||
* <td>{@link #offerFirst offerFirst(e)}</td>
|
|
||||||
* <td>{@link #addLast addLast(e)}</td>
|
|
||||||
* <td>{@link #offerLast offerLast(e)}</td>
|
|
||||||
* </tr>
|
|
||||||
* <tr>
|
|
||||||
* <td><b>Remove</b></td>
|
|
||||||
* <td>{@link #removeFirst removeFirst()}</td>
|
|
||||||
* <td>{@link #pollFirst pollFirst()}</td>
|
|
||||||
* <td>{@link #removeLast removeLast()}</td>
|
|
||||||
* <td>{@link #pollLast pollLast()}</td>
|
|
||||||
* </tr>
|
|
||||||
* <tr>
|
|
||||||
* <td><b>Examine</b></td>
|
|
||||||
* <td>{@link #getFirst getFirst()}</td>
|
|
||||||
* <td>{@link #peekFirst peekFirst()}</td>
|
|
||||||
* <td>{@link #getLast getLast()}</td>
|
|
||||||
* <td>{@link #peekLast peekLast()}</td>
|
|
||||||
* </tr>
|
|
||||||
* </table>
|
|
||||||
*
|
|
||||||
* <p>This interface extends the {@link Queue} interface. When a deque is
|
|
||||||
* used as a queue, FIFO (First-In-First-Out) behavior results. Elements are
|
|
||||||
* added at the end of the deque and removed from the beginning. The methods
|
|
||||||
* inherited from the <tt>Queue</tt> interface are precisely equivalent to
|
|
||||||
* <tt>Deque</tt> methods as indicated in the following table:
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* <table BORDER CELLPADDING=3 CELLSPACING=1>
|
|
||||||
* <tr>
|
|
||||||
* <td ALIGN=CENTER> <b><tt>Queue</tt> Method</b></td>
|
|
||||||
* <td ALIGN=CENTER> <b>Equivalent <tt>Deque</tt> Method</b></td>
|
|
||||||
* </tr>
|
|
||||||
* <tr>
|
|
||||||
* <td>{@link java.util.Queue#add add(e)}</td>
|
|
||||||
* <td>{@link #addLast addLast(e)}</td>
|
|
||||||
* </tr>
|
|
||||||
* <tr>
|
|
||||||
* <td>{@link java.util.Queue#offer offer(e)}</td>
|
|
||||||
* <td>{@link #offerLast offerLast(e)}</td>
|
|
||||||
* </tr>
|
|
||||||
* <tr>
|
|
||||||
* <td>{@link java.util.Queue#remove remove()}</td>
|
|
||||||
* <td>{@link #removeFirst removeFirst()}</td>
|
|
||||||
* </tr>
|
|
||||||
* <tr>
|
|
||||||
* <td>{@link java.util.Queue#poll poll()}</td>
|
|
||||||
* <td>{@link #pollFirst pollFirst()}</td>
|
|
||||||
* </tr>
|
|
||||||
* <tr>
|
|
||||||
* <td>{@link java.util.Queue#element element()}</td>
|
|
||||||
* <td>{@link #getFirst getFirst()}</td>
|
|
||||||
* </tr>
|
|
||||||
* <tr>
|
|
||||||
* <td>{@link java.util.Queue#peek peek()}</td>
|
|
||||||
* <td>{@link #peek peekFirst()}</td>
|
|
||||||
* </tr>
|
|
||||||
* </table>
|
|
||||||
*
|
|
||||||
* <p>Deques can also be used as LIFO (Last-In-First-Out) stacks. This
|
|
||||||
* interface should be used in preference to the legacy {@link Stack} class.
|
|
||||||
* When a deque is used as a stack, elements are pushed and popped from the
|
|
||||||
* beginning of the deque. Stack methods are precisely equivalent to
|
|
||||||
* <tt>Deque</tt> methods as indicated in the table below:
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* <table BORDER CELLPADDING=3 CELLSPACING=1>
|
|
||||||
* <tr>
|
|
||||||
* <td ALIGN=CENTER> <b>Stack Method</b></td>
|
|
||||||
* <td ALIGN=CENTER> <b>Equivalent <tt>Deque</tt> Method</b></td>
|
|
||||||
* </tr>
|
|
||||||
* <tr>
|
|
||||||
* <td>{@link #push push(e)}</td>
|
|
||||||
* <td>{@link #addFirst addFirst(e)}</td>
|
|
||||||
* </tr>
|
|
||||||
* <tr>
|
|
||||||
* <td>{@link #pop pop()}</td>
|
|
||||||
* <td>{@link #removeFirst removeFirst()}</td>
|
|
||||||
* </tr>
|
|
||||||
* <tr>
|
|
||||||
* <td>{@link #peek peek()}</td>
|
|
||||||
* <td>{@link #peekFirst peekFirst()}</td>
|
|
||||||
* </tr>
|
|
||||||
* </table>
|
|
||||||
*
|
|
||||||
* <p>Note that the {@link #peek peek} method works equally well when
|
|
||||||
* a deque is used as a queue or a stack; in either case, elements are
|
|
||||||
* drawn from the beginning of the deque.
|
|
||||||
*
|
|
||||||
* <p>This interface provides two methods to remove interior
|
|
||||||
* elements, {@link #removeFirstOccurrence removeFirstOccurrence} and
|
|
||||||
* {@link #removeLastOccurrence removeLastOccurrence}.
|
|
||||||
*
|
|
||||||
* <p>Unlike the {@link List} interface, this interface does not
|
|
||||||
* provide support for indexed access to elements.
|
|
||||||
*
|
|
||||||
* <p>While <tt>Deque</tt> implementations are not strictly required
|
|
||||||
* to prohibit the insertion of null elements, they are strongly
|
|
||||||
* encouraged to do so. Users of any <tt>Deque</tt> implementations
|
|
||||||
* that do allow null elements are strongly encouraged <i>not</i> to
|
|
||||||
* take advantage of the ability to insert nulls. This is so because
|
|
||||||
* <tt>null</tt> is used as a special return value by various methods
|
|
||||||
* to indicated that the deque is empty.
|
|
||||||
*
|
|
||||||
* <p><tt>Deque</tt> implementations generally do not define
|
|
||||||
* element-based versions of the <tt>equals</tt> and <tt>hashCode</tt>
|
|
||||||
* methods, but instead inherit the identity-based versions from class
|
|
||||||
* <tt>Object</tt>.
|
|
||||||
*
|
|
||||||
* @author Doug Lea
|
|
||||||
* @author Josh Bloch
|
|
||||||
* @since 1.6
|
|
||||||
* @param <E> the type of elements held in this collection
|
|
||||||
*/
|
|
||||||
|
|
||||||
public interface Deque<E> extends Queue<E> {
|
|
||||||
/**
|
|
||||||
* Inserts the specified element at the front of this deque if it is
|
|
||||||
* possible to do so immediately without violating capacity restrictions.
|
|
||||||
* When using a capacity-restricted deque, it is generally preferable to
|
|
||||||
* use method {@link #offerFirst}.
|
|
||||||
*
|
|
||||||
* @param e the element to add
|
|
||||||
* @throws IllegalStateException if the element cannot be added at this
|
|
||||||
* time due to capacity restrictions
|
|
||||||
* @throws ClassCastException if the class of the specified element
|
|
||||||
* prevents it from being added to this deque
|
|
||||||
* @throws NullPointerException if the specified element is null and this
|
|
||||||
* deque does not permit null elements
|
|
||||||
* @throws IllegalArgumentException if some property of the specified
|
|
||||||
* element prevents it from being added to this deque
|
|
||||||
*/
|
|
||||||
void addFirst(E e);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Inserts the specified element at the end of this deque if it is
|
|
||||||
* possible to do so immediately without violating capacity restrictions.
|
|
||||||
* When using a capacity-restricted deque, it is generally preferable to
|
|
||||||
* use method {@link #offerLast}.
|
|
||||||
*
|
|
||||||
* <p>This method is equivalent to {@link #add}.
|
|
||||||
*
|
|
||||||
* @param e the element to add
|
|
||||||
* @throws IllegalStateException if the element cannot be added at this
|
|
||||||
* time due to capacity restrictions
|
|
||||||
* @throws ClassCastException if the class of the specified element
|
|
||||||
* prevents it from being added to this deque
|
|
||||||
* @throws NullPointerException if the specified element is null and this
|
|
||||||
* deque does not permit null elements
|
|
||||||
* @throws IllegalArgumentException if some property of the specified
|
|
||||||
* element prevents it from being added to this deque
|
|
||||||
*/
|
|
||||||
void addLast(E e);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Inserts the specified element at the front of this deque unless it would
|
|
||||||
* violate capacity restrictions. When using a capacity-restricted deque,
|
|
||||||
* this method is generally preferable to the {@link #addFirst} method,
|
|
||||||
* which can fail to insert an element only by throwing an exception.
|
|
||||||
*
|
|
||||||
* @param e the element to add
|
|
||||||
* @return <tt>true</tt> if the element was added to this deque, else
|
|
||||||
* <tt>false</tt>
|
|
||||||
* @throws ClassCastException if the class of the specified element
|
|
||||||
* prevents it from being added to this deque
|
|
||||||
* @throws NullPointerException if the specified element is null and this
|
|
||||||
* deque does not permit null elements
|
|
||||||
* @throws IllegalArgumentException if some property of the specified
|
|
||||||
* element prevents it from being added to this deque
|
|
||||||
*/
|
|
||||||
boolean offerFirst(E e);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Inserts the specified element at the end of this deque unless it would
|
|
||||||
* violate capacity restrictions. When using a capacity-restricted deque,
|
|
||||||
* this method is generally preferable to the {@link #addLast} method,
|
|
||||||
* which can fail to insert an element only by throwing an exception.
|
|
||||||
*
|
|
||||||
* @param e the element to add
|
|
||||||
* @return <tt>true</tt> if the element was added to this deque, else
|
|
||||||
* <tt>false</tt>
|
|
||||||
* @throws ClassCastException if the class of the specified element
|
|
||||||
* prevents it from being added to this deque
|
|
||||||
* @throws NullPointerException if the specified element is null and this
|
|
||||||
* deque does not permit null elements
|
|
||||||
* @throws IllegalArgumentException if some property of the specified
|
|
||||||
* element prevents it from being added to this deque
|
|
||||||
*/
|
|
||||||
boolean offerLast(E e);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves and removes the first element of this deque. This method
|
|
||||||
* differs from {@link #pollFirst pollFirst} only in that it throws an
|
|
||||||
* exception if this deque is empty.
|
|
||||||
*
|
|
||||||
* @return the head of this deque
|
|
||||||
* @throws NoSuchElementException if this deque is empty
|
|
||||||
*/
|
|
||||||
E removeFirst();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves and removes the last element of this deque. This method
|
|
||||||
* differs from {@link #pollLast pollLast} only in that it throws an
|
|
||||||
* exception if this deque is empty.
|
|
||||||
*
|
|
||||||
* @return the tail of this deque
|
|
||||||
* @throws NoSuchElementException if this deque is empty
|
|
||||||
*/
|
|
||||||
E removeLast();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves and removes the first element of this deque,
|
|
||||||
* or returns <tt>null</tt> if this deque is empty.
|
|
||||||
*
|
|
||||||
* @return the head of this deque, or <tt>null</tt> if this deque is empty
|
|
||||||
*/
|
|
||||||
E pollFirst();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves and removes the last element of this deque,
|
|
||||||
* or returns <tt>null</tt> if this deque is empty.
|
|
||||||
*
|
|
||||||
* @return the tail of this deque, or <tt>null</tt> if this deque is empty
|
|
||||||
*/
|
|
||||||
E pollLast();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves, but does not remove, the first element of this deque.
|
|
||||||
*
|
|
||||||
* This method differs from {@link #peekFirst peekFirst} only in that it
|
|
||||||
* throws an exception if this deque is empty.
|
|
||||||
*
|
|
||||||
* @return the head of this deque
|
|
||||||
* @throws NoSuchElementException if this deque is empty
|
|
||||||
*/
|
|
||||||
E getFirst();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves, but does not remove, the last element of this deque.
|
|
||||||
* This method differs from {@link #peekLast peekLast} only in that it
|
|
||||||
* throws an exception if this deque is empty.
|
|
||||||
*
|
|
||||||
* @return the tail of this deque
|
|
||||||
* @throws NoSuchElementException if this deque is empty
|
|
||||||
*/
|
|
||||||
E getLast();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves, but does not remove, the first element of this deque,
|
|
||||||
* or returns <tt>null</tt> if this deque is empty.
|
|
||||||
*
|
|
||||||
* @return the head of this deque, or <tt>null</tt> if this deque is empty
|
|
||||||
*/
|
|
||||||
E peekFirst();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves, but does not remove, the last element of this deque,
|
|
||||||
* or returns <tt>null</tt> if this deque is empty.
|
|
||||||
*
|
|
||||||
* @return the tail of this deque, or <tt>null</tt> if this deque is empty
|
|
||||||
*/
|
|
||||||
E peekLast();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes the first occurrence of the specified element from this deque.
|
|
||||||
* If the deque does not contain the element, it is unchanged.
|
|
||||||
* More formally, removes the first element <tt>e</tt> such that
|
|
||||||
* <tt>(o==null ? e==null : o.equals(e))</tt>
|
|
||||||
* (if such an element exists).
|
|
||||||
* Returns <tt>true</tt> if this deque contained the specified element
|
|
||||||
* (or equivalently, if this deque changed as a result of the call).
|
|
||||||
*
|
|
||||||
* @param o element to be removed from this deque, if present
|
|
||||||
* @return <tt>true</tt> if an element was removed as a result of this call
|
|
||||||
* @throws ClassCastException if the class of the specified element
|
|
||||||
* is incompatible with this deque (optional)
|
|
||||||
* @throws NullPointerException if the specified element is null and this
|
|
||||||
* deque does not permit null elements (optional)
|
|
||||||
*/
|
|
||||||
boolean removeFirstOccurrence(Object o);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes the last occurrence of the specified element from this deque.
|
|
||||||
* If the deque does not contain the element, it is unchanged.
|
|
||||||
* More formally, removes the last element <tt>e</tt> such that
|
|
||||||
* <tt>(o==null ? e==null : o.equals(e))</tt>
|
|
||||||
* (if such an element exists).
|
|
||||||
* Returns <tt>true</tt> if this deque contained the specified element
|
|
||||||
* (or equivalently, if this deque changed as a result of the call).
|
|
||||||
*
|
|
||||||
* @param o element to be removed from this deque, if present
|
|
||||||
* @return <tt>true</tt> if an element was removed as a result of this call
|
|
||||||
* @throws ClassCastException if the class of the specified element
|
|
||||||
* is incompatible with this deque (optional)
|
|
||||||
* @throws NullPointerException if the specified element is null and this
|
|
||||||
* deque does not permit null elements (optional)
|
|
||||||
*/
|
|
||||||
boolean removeLastOccurrence(Object o);
|
|
||||||
|
|
||||||
// *** Queue methods ***
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Inserts the specified element into the queue represented by this deque
|
|
||||||
* (in other words, at the tail of this deque) if it is possible to do so
|
|
||||||
* immediately without violating capacity restrictions, returning
|
|
||||||
* <tt>true</tt> upon success and throwing an
|
|
||||||
* <tt>IllegalStateException</tt> if no space is currently available.
|
|
||||||
* When using a capacity-restricted deque, it is generally preferable to
|
|
||||||
* use {@link #offer offer}.
|
|
||||||
*
|
|
||||||
* <p>This method is equivalent to {@link #addLast}.
|
|
||||||
*
|
|
||||||
* @param e the element to add
|
|
||||||
* @return <tt>true</tt> (as specified by {@link Collection#add})
|
|
||||||
* @throws IllegalStateException if the element cannot be added at this
|
|
||||||
* time due to capacity restrictions
|
|
||||||
* @throws ClassCastException if the class of the specified element
|
|
||||||
* prevents it from being added to this deque
|
|
||||||
* @throws NullPointerException if the specified element is null and this
|
|
||||||
* deque does not permit null elements
|
|
||||||
* @throws IllegalArgumentException if some property of the specified
|
|
||||||
* element prevents it from being added to this deque
|
|
||||||
*/
|
|
||||||
boolean add(E e);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Inserts the specified element into the queue represented by this deque
|
|
||||||
* (in other words, at the tail of this deque) if it is possible to do so
|
|
||||||
* immediately without violating capacity restrictions, returning
|
|
||||||
* <tt>true</tt> upon success and <tt>false</tt> if no space is currently
|
|
||||||
* available. When using a capacity-restricted deque, this method is
|
|
||||||
* generally preferable to the {@link #add} method, which can fail to
|
|
||||||
* insert an element only by throwing an exception.
|
|
||||||
*
|
|
||||||
* <p>This method is equivalent to {@link #offerLast}.
|
|
||||||
*
|
|
||||||
* @param e the element to add
|
|
||||||
* @return <tt>true</tt> if the element was added to this deque, else
|
|
||||||
* <tt>false</tt>
|
|
||||||
* @throws ClassCastException if the class of the specified element
|
|
||||||
* prevents it from being added to this deque
|
|
||||||
* @throws NullPointerException if the specified element is null and this
|
|
||||||
* deque does not permit null elements
|
|
||||||
* @throws IllegalArgumentException if some property of the specified
|
|
||||||
* element prevents it from being added to this deque
|
|
||||||
*/
|
|
||||||
boolean offer(E e);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves and removes the head of the queue represented by this deque
|
|
||||||
* (in other words, the first element of this deque).
|
|
||||||
* This method differs from {@link #poll poll} only in that it throws an
|
|
||||||
* exception if this deque is empty.
|
|
||||||
*
|
|
||||||
* <p>This method is equivalent to {@link #removeFirst()}.
|
|
||||||
*
|
|
||||||
* @return the head of the queue represented by this deque
|
|
||||||
* @throws NoSuchElementException if this deque is empty
|
|
||||||
*/
|
|
||||||
E remove();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves and removes the head of the queue represented by this deque
|
|
||||||
* (in other words, the first element of this deque), or returns
|
|
||||||
* <tt>null</tt> if this deque is empty.
|
|
||||||
*
|
|
||||||
* <p>This method is equivalent to {@link #pollFirst()}.
|
|
||||||
*
|
|
||||||
* @return the first element of this deque, or <tt>null</tt> if
|
|
||||||
* this deque is empty
|
|
||||||
*/
|
|
||||||
E poll();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves, but does not remove, the head of the queue represented by
|
|
||||||
* this deque (in other words, the first element of this deque).
|
|
||||||
* This method differs from {@link #peek peek} only in that it throws an
|
|
||||||
* exception if this deque is empty.
|
|
||||||
*
|
|
||||||
* <p>This method is equivalent to {@link #getFirst()}.
|
|
||||||
*
|
|
||||||
* @return the head of the queue represented by this deque
|
|
||||||
* @throws NoSuchElementException if this deque is empty
|
|
||||||
*/
|
|
||||||
E element();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves, but does not remove, the head of the queue represented by
|
|
||||||
* this deque (in other words, the first element of this deque), or
|
|
||||||
* returns <tt>null</tt> if this deque is empty.
|
|
||||||
*
|
|
||||||
* <p>This method is equivalent to {@link #peekFirst()}.
|
|
||||||
*
|
|
||||||
* @return the head of the queue represented by this deque, or
|
|
||||||
* <tt>null</tt> if this deque is empty
|
|
||||||
*/
|
|
||||||
E peek();
|
|
||||||
|
|
||||||
|
|
||||||
// *** Stack methods ***
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Pushes an element onto the stack represented by this deque (in other
|
|
||||||
* words, at the head of this deque) if it is possible to do so
|
|
||||||
* immediately without violating capacity restrictions, returning
|
|
||||||
* <tt>true</tt> upon success and throwing an
|
|
||||||
* <tt>IllegalStateException</tt> if no space is currently available.
|
|
||||||
*
|
|
||||||
* <p>This method is equivalent to {@link #addFirst}.
|
|
||||||
*
|
|
||||||
* @param e the element to push
|
|
||||||
* @throws IllegalStateException if the element cannot be added at this
|
|
||||||
* time due to capacity restrictions
|
|
||||||
* @throws ClassCastException if the class of the specified element
|
|
||||||
* prevents it from being added to this deque
|
|
||||||
* @throws NullPointerException if the specified element is null and this
|
|
||||||
* deque does not permit null elements
|
|
||||||
* @throws IllegalArgumentException if some property of the specified
|
|
||||||
* element prevents it from being added to this deque
|
|
||||||
*/
|
|
||||||
void push(E e);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Pops an element from the stack represented by this deque. In other
|
|
||||||
* words, removes and returns the first element of this deque.
|
|
||||||
*
|
|
||||||
* <p>This method is equivalent to {@link #removeFirst()}.
|
|
||||||
*
|
|
||||||
* @return the element at the front of this deque (which is the top
|
|
||||||
* of the stack represented by this deque)
|
|
||||||
* @throws NoSuchElementException if this deque is empty
|
|
||||||
*/
|
|
||||||
E pop();
|
|
||||||
|
|
||||||
|
|
||||||
// *** Collection methods ***
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes the first occurrence of the specified element from this deque.
|
|
||||||
* If the deque does not contain the element, it is unchanged.
|
|
||||||
* More formally, removes the first element <tt>e</tt> such that
|
|
||||||
* <tt>(o==null ? e==null : o.equals(e))</tt>
|
|
||||||
* (if such an element exists).
|
|
||||||
* Returns <tt>true</tt> if this deque contained the specified element
|
|
||||||
* (or equivalently, if this deque changed as a result of the call).
|
|
||||||
*
|
|
||||||
* <p>This method is equivalent to {@link #removeFirstOccurrence}.
|
|
||||||
*
|
|
||||||
* @param o element to be removed from this deque, if present
|
|
||||||
* @return <tt>true</tt> if an element was removed as a result of this call
|
|
||||||
* @throws ClassCastException if the class of the specified element
|
|
||||||
* is incompatible with this deque (optional)
|
|
||||||
* @throws NullPointerException if the specified element is null and this
|
|
||||||
* deque does not permit null elements (optional)
|
|
||||||
*/
|
|
||||||
boolean remove(Object o);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns <tt>true</tt> if this deque contains the specified element.
|
|
||||||
* More formally, returns <tt>true</tt> if and only if this deque contains
|
|
||||||
* at least one element <tt>e</tt> such that
|
|
||||||
* <tt>(o==null ? e==null : o.equals(e))</tt>.
|
|
||||||
*
|
|
||||||
* @param o element whose presence in this deque is to be tested
|
|
||||||
* @return <tt>true</tt> if this deque contains the specified element
|
|
||||||
* @throws ClassCastException if the type of the specified element
|
|
||||||
* is incompatible with this deque (optional)
|
|
||||||
* @throws NullPointerException if the specified element is null and this
|
|
||||||
* deque does not permit null elements (optional)
|
|
||||||
*/
|
|
||||||
boolean contains(Object o);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the number of elements in this deque.
|
|
||||||
*
|
|
||||||
* @return the number of elements in this deque
|
|
||||||
*/
|
|
||||||
public int size();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an iterator over the elements in this deque in proper sequence.
|
|
||||||
* The elements will be returned in order from first (head) to last (tail).
|
|
||||||
*
|
|
||||||
* @return an iterator over the elements in this deque in proper sequence
|
|
||||||
*/
|
|
||||||
Iterator<E> iterator();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an iterator over the elements in this deque in reverse
|
|
||||||
* sequential order. The elements will be returned in order from
|
|
||||||
* last (tail) to first (head).
|
|
||||||
*
|
|
||||||
* @return an iterator over the elements in this deque in reverse
|
|
||||||
* sequence
|
|
||||||
*/
|
|
||||||
Iterator<E> descendingIterator();
|
|
||||||
|
|
||||||
}
|
|
@ -1,47 +0,0 @@
|
|||||||
package com.nostra13.universalimageloader.core.assist.deque;
|
|
||||||
|
|
||||||
import java.util.NoSuchElementException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@link LinkedBlockingDeque} using LIFO algorithm
|
|
||||||
*
|
|
||||||
* @author Sergey Tarasevich (nostra13[at]gmail[dot]com)
|
|
||||||
* @since 1.6.3
|
|
||||||
*/
|
|
||||||
public class LIFOLinkedBlockingDeque<T> extends LinkedBlockingDeque<T> {
|
|
||||||
|
|
||||||
private static final long serialVersionUID = -4114786347960826192L;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Inserts the specified element at the front of this deque if it is possible to do so immediately without violating
|
|
||||||
* capacity restrictions, returning <tt>true</tt> upon success and <tt>false</tt> if no space is currently
|
|
||||||
* available. When using a capacity-restricted deque, this method is generally preferable to the {@link #addFirst
|
|
||||||
* addFirst} method, which can fail to insert an element only by throwing an exception.
|
|
||||||
*
|
|
||||||
* @param e
|
|
||||||
* the element to add
|
|
||||||
* @throws ClassCastException
|
|
||||||
* {@inheritDoc}
|
|
||||||
* @throws NullPointerException
|
|
||||||
* if the specified element is null
|
|
||||||
* @throws IllegalArgumentException
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public boolean offer(T e) {
|
|
||||||
return super.offerFirst(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves and removes the first element of this deque. This method differs from {@link #pollFirst pollFirst} only
|
|
||||||
* in that it throws an exception if this deque is empty.
|
|
||||||
*
|
|
||||||
* @return the head of this deque
|
|
||||||
* @throws NoSuchElementException
|
|
||||||
* if this deque is empty
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public T remove() {
|
|
||||||
return super.removeFirst();
|
|
||||||
}
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
@ -1,250 +0,0 @@
|
|||||||
/*******************************************************************************
|
|
||||||
* Copyright 2011-2014 Sergey Tarasevich
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*******************************************************************************/
|
|
||||||
package com.nostra13.universalimageloader.core.decode;
|
|
||||||
|
|
||||||
import android.graphics.Bitmap;
|
|
||||||
import android.graphics.BitmapFactory;
|
|
||||||
import android.graphics.BitmapFactory.Options;
|
|
||||||
import android.graphics.Matrix;
|
|
||||||
import android.media.ExifInterface;
|
|
||||||
import com.nostra13.universalimageloader.core.assist.ImageScaleType;
|
|
||||||
import com.nostra13.universalimageloader.core.assist.ImageSize;
|
|
||||||
import com.nostra13.universalimageloader.core.download.ImageDownloader.Scheme;
|
|
||||||
import com.nostra13.universalimageloader.utils.ImageSizeUtils;
|
|
||||||
import com.nostra13.universalimageloader.utils.IoUtils;
|
|
||||||
import com.nostra13.universalimageloader.utils.L;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Decodes images to {@link Bitmap}, scales them to needed size
|
|
||||||
*
|
|
||||||
* @author Sergey Tarasevich (nostra13[at]gmail[dot]com)
|
|
||||||
* @see ImageDecodingInfo
|
|
||||||
* @since 1.8.3
|
|
||||||
*/
|
|
||||||
public class BaseImageDecoder implements ImageDecoder {
|
|
||||||
|
|
||||||
protected static final String LOG_SUBSAMPLE_IMAGE = "Subsample original image (%1$s) to %2$s (scale = %3$d) [%4$s]";
|
|
||||||
protected static final String LOG_SCALE_IMAGE = "Scale subsampled image (%1$s) to %2$s (scale = %3$.5f) [%4$s]";
|
|
||||||
protected static final String LOG_ROTATE_IMAGE = "Rotate image on %1$d\u00B0 [%2$s]";
|
|
||||||
protected static final String LOG_FLIP_IMAGE = "Flip image horizontally [%s]";
|
|
||||||
protected static final String ERROR_NO_IMAGE_STREAM = "No stream for image [%s]";
|
|
||||||
protected static final String ERROR_CANT_DECODE_IMAGE = "Image can't be decoded [%s]";
|
|
||||||
|
|
||||||
protected final boolean loggingEnabled;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param loggingEnabled Whether debug logs will be written to LogCat. Usually should match {@link
|
|
||||||
* com.nostra13.universalimageloader.core.ImageLoaderConfiguration.Builder#writeDebugLogs()
|
|
||||||
* ImageLoaderConfiguration.writeDebugLogs()}
|
|
||||||
*/
|
|
||||||
public BaseImageDecoder(boolean loggingEnabled) {
|
|
||||||
this.loggingEnabled = loggingEnabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Decodes image from URI into {@link Bitmap}. Image is scaled close to incoming {@linkplain ImageSize target size}
|
|
||||||
* during decoding (depend on incoming parameters).
|
|
||||||
*
|
|
||||||
* @param decodingInfo Needed data for decoding image
|
|
||||||
* @return Decoded bitmap
|
|
||||||
* @throws IOException if some I/O exception occurs during image reading
|
|
||||||
* @throws UnsupportedOperationException if image URI has unsupported scheme(protocol)
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public Bitmap decode(ImageDecodingInfo decodingInfo) throws IOException {
|
|
||||||
Bitmap decodedBitmap;
|
|
||||||
ImageFileInfo imageInfo;
|
|
||||||
|
|
||||||
InputStream imageStream = getImageStream(decodingInfo);
|
|
||||||
if (imageStream == null) {
|
|
||||||
L.e(ERROR_NO_IMAGE_STREAM, decodingInfo.getImageKey());
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
imageInfo = defineImageSizeAndRotation(imageStream, decodingInfo);
|
|
||||||
imageStream = resetStream(imageStream, decodingInfo);
|
|
||||||
Options decodingOptions = prepareDecodingOptions(imageInfo.imageSize, decodingInfo);
|
|
||||||
decodedBitmap = BitmapFactory.decodeStream(imageStream, null, decodingOptions);
|
|
||||||
} finally {
|
|
||||||
IoUtils.closeSilently(imageStream);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (decodedBitmap == null) {
|
|
||||||
L.e(ERROR_CANT_DECODE_IMAGE, decodingInfo.getImageKey());
|
|
||||||
} else {
|
|
||||||
decodedBitmap = considerExactScaleAndOrientatiton(decodedBitmap, decodingInfo, imageInfo.exif.rotation,
|
|
||||||
imageInfo.exif.flipHorizontal);
|
|
||||||
}
|
|
||||||
return decodedBitmap;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected InputStream getImageStream(ImageDecodingInfo decodingInfo) throws IOException {
|
|
||||||
return decodingInfo.getDownloader().getStream(decodingInfo.getImageUri(), decodingInfo.getExtraForDownloader());
|
|
||||||
}
|
|
||||||
|
|
||||||
protected ImageFileInfo defineImageSizeAndRotation(InputStream imageStream, ImageDecodingInfo decodingInfo)
|
|
||||||
throws IOException {
|
|
||||||
Options options = new Options();
|
|
||||||
options.inJustDecodeBounds = true;
|
|
||||||
BitmapFactory.decodeStream(imageStream, null, options);
|
|
||||||
|
|
||||||
ExifInfo exif;
|
|
||||||
String imageUri = decodingInfo.getImageUri();
|
|
||||||
if (decodingInfo.shouldConsiderExifParams() && canDefineExifParams(imageUri, options.outMimeType)) {
|
|
||||||
exif = defineExifOrientation(imageUri);
|
|
||||||
} else {
|
|
||||||
exif = new ExifInfo();
|
|
||||||
}
|
|
||||||
return new ImageFileInfo(new ImageSize(options.outWidth, options.outHeight, exif.rotation), exif);
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean canDefineExifParams(String imageUri, String mimeType) {
|
|
||||||
return "image/jpeg".equalsIgnoreCase(mimeType) && (Scheme.ofUri(imageUri) == Scheme.FILE);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected ExifInfo defineExifOrientation(String imageUri) {
|
|
||||||
int rotation = 0;
|
|
||||||
boolean flip = false;
|
|
||||||
try {
|
|
||||||
ExifInterface exif = new ExifInterface(Scheme.FILE.crop(imageUri));
|
|
||||||
int exifOrientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
|
|
||||||
switch (exifOrientation) {
|
|
||||||
case ExifInterface.ORIENTATION_FLIP_HORIZONTAL:
|
|
||||||
flip = true;
|
|
||||||
case ExifInterface.ORIENTATION_NORMAL:
|
|
||||||
rotation = 0;
|
|
||||||
break;
|
|
||||||
case ExifInterface.ORIENTATION_TRANSVERSE:
|
|
||||||
flip = true;
|
|
||||||
case ExifInterface.ORIENTATION_ROTATE_90:
|
|
||||||
rotation = 90;
|
|
||||||
break;
|
|
||||||
case ExifInterface.ORIENTATION_FLIP_VERTICAL:
|
|
||||||
flip = true;
|
|
||||||
case ExifInterface.ORIENTATION_ROTATE_180:
|
|
||||||
rotation = 180;
|
|
||||||
break;
|
|
||||||
case ExifInterface.ORIENTATION_TRANSPOSE:
|
|
||||||
flip = true;
|
|
||||||
case ExifInterface.ORIENTATION_ROTATE_270:
|
|
||||||
rotation = 270;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
L.w("Can't read EXIF tags from file [%s]", imageUri);
|
|
||||||
}
|
|
||||||
return new ExifInfo(rotation, flip);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Options prepareDecodingOptions(ImageSize imageSize, ImageDecodingInfo decodingInfo) {
|
|
||||||
ImageScaleType scaleType = decodingInfo.getImageScaleType();
|
|
||||||
int scale;
|
|
||||||
if (scaleType == ImageScaleType.NONE) {
|
|
||||||
scale = 1;
|
|
||||||
} else if (scaleType == ImageScaleType.NONE_SAFE) {
|
|
||||||
scale = ImageSizeUtils.computeMinImageSampleSize(imageSize);
|
|
||||||
} else {
|
|
||||||
ImageSize targetSize = decodingInfo.getTargetSize();
|
|
||||||
boolean powerOf2 = scaleType == ImageScaleType.IN_SAMPLE_POWER_OF_2;
|
|
||||||
scale = ImageSizeUtils.computeImageSampleSize(imageSize, targetSize, decodingInfo.getViewScaleType(), powerOf2);
|
|
||||||
}
|
|
||||||
if (scale > 1 && loggingEnabled) {
|
|
||||||
L.d(LOG_SUBSAMPLE_IMAGE, imageSize, imageSize.scaleDown(scale), scale, decodingInfo.getImageKey());
|
|
||||||
}
|
|
||||||
|
|
||||||
Options decodingOptions = decodingInfo.getDecodingOptions();
|
|
||||||
decodingOptions.inSampleSize = scale;
|
|
||||||
return decodingOptions;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected InputStream resetStream(InputStream imageStream, ImageDecodingInfo decodingInfo) throws IOException {
|
|
||||||
try {
|
|
||||||
imageStream.reset();
|
|
||||||
} catch (IOException e) {
|
|
||||||
IoUtils.closeSilently(imageStream);
|
|
||||||
imageStream = getImageStream(decodingInfo);
|
|
||||||
}
|
|
||||||
return imageStream;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Bitmap considerExactScaleAndOrientatiton(Bitmap subsampledBitmap, ImageDecodingInfo decodingInfo,
|
|
||||||
int rotation, boolean flipHorizontal) {
|
|
||||||
Matrix m = new Matrix();
|
|
||||||
// Scale to exact size if need
|
|
||||||
ImageScaleType scaleType = decodingInfo.getImageScaleType();
|
|
||||||
if (scaleType == ImageScaleType.EXACTLY || scaleType == ImageScaleType.EXACTLY_STRETCHED) {
|
|
||||||
ImageSize srcSize = new ImageSize(subsampledBitmap.getWidth(), subsampledBitmap.getHeight(), rotation);
|
|
||||||
float scale = ImageSizeUtils.computeImageScale(srcSize, decodingInfo.getTargetSize(), decodingInfo
|
|
||||||
.getViewScaleType(), scaleType == ImageScaleType.EXACTLY_STRETCHED);
|
|
||||||
if (Float.compare(scale, 1f) != 0) {
|
|
||||||
m.setScale(scale, scale);
|
|
||||||
|
|
||||||
if (loggingEnabled) {
|
|
||||||
L.d(LOG_SCALE_IMAGE, srcSize, srcSize.scale(scale), scale, decodingInfo.getImageKey());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Flip bitmap if need
|
|
||||||
if (flipHorizontal) {
|
|
||||||
m.postScale(-1, 1);
|
|
||||||
|
|
||||||
if (loggingEnabled) L.d(LOG_FLIP_IMAGE, decodingInfo.getImageKey());
|
|
||||||
}
|
|
||||||
// Rotate bitmap if need
|
|
||||||
if (rotation != 0) {
|
|
||||||
m.postRotate(rotation);
|
|
||||||
|
|
||||||
if (loggingEnabled) L.d(LOG_ROTATE_IMAGE, rotation, decodingInfo.getImageKey());
|
|
||||||
}
|
|
||||||
|
|
||||||
Bitmap finalBitmap = Bitmap.createBitmap(subsampledBitmap, 0, 0, subsampledBitmap.getWidth(), subsampledBitmap
|
|
||||||
.getHeight(), m, true);
|
|
||||||
if (finalBitmap != subsampledBitmap) {
|
|
||||||
subsampledBitmap.recycle();
|
|
||||||
}
|
|
||||||
return finalBitmap;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static class ExifInfo {
|
|
||||||
|
|
||||||
public final int rotation;
|
|
||||||
public final boolean flipHorizontal;
|
|
||||||
|
|
||||||
protected ExifInfo() {
|
|
||||||
this.rotation = 0;
|
|
||||||
this.flipHorizontal = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected ExifInfo(int rotation, boolean flipHorizontal) {
|
|
||||||
this.rotation = rotation;
|
|
||||||
this.flipHorizontal = flipHorizontal;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static class ImageFileInfo {
|
|
||||||
|
|
||||||
public final ImageSize imageSize;
|
|
||||||
public final ExifInfo exif;
|
|
||||||
|
|
||||||
protected ImageFileInfo(ImageSize imageSize, ExifInfo exif) {
|
|
||||||
this.imageSize = imageSize;
|
|
||||||
this.exif = exif;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,39 +0,0 @@
|
|||||||
/*******************************************************************************
|
|
||||||
* Copyright 2013 Sergey Tarasevich
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*******************************************************************************/
|
|
||||||
package com.nostra13.universalimageloader.core.decode;
|
|
||||||
|
|
||||||
import android.graphics.Bitmap;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Provide decoding image to result {@link Bitmap}.
|
|
||||||
*
|
|
||||||
* @author Sergey Tarasevich (nostra13[at]gmail[dot]com)
|
|
||||||
* @see ImageDecodingInfo
|
|
||||||
* @since 1.8.3
|
|
||||||
*/
|
|
||||||
public interface ImageDecoder {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Decodes image to {@link Bitmap} according target size and other parameters.
|
|
||||||
*
|
|
||||||
* @param imageDecodingInfo
|
|
||||||
* @return
|
|
||||||
* @throws IOException
|
|
||||||
*/
|
|
||||||
Bitmap decode(ImageDecodingInfo imageDecodingInfo) throws IOException;
|
|
||||||
}
|
|
@ -1,150 +0,0 @@
|
|||||||
/*******************************************************************************
|
|
||||||
* Copyright 2013-2014 Sergey Tarasevich
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*******************************************************************************/
|
|
||||||
package com.nostra13.universalimageloader.core.decode;
|
|
||||||
|
|
||||||
import android.annotation.TargetApi;
|
|
||||||
import android.graphics.BitmapFactory.Options;
|
|
||||||
import android.os.Build;
|
|
||||||
|
|
||||||
import com.nostra13.universalimageloader.core.DisplayImageOptions;
|
|
||||||
import com.nostra13.universalimageloader.core.assist.ImageScaleType;
|
|
||||||
import com.nostra13.universalimageloader.core.assist.ImageSize;
|
|
||||||
import com.nostra13.universalimageloader.core.assist.ViewScaleType;
|
|
||||||
import com.nostra13.universalimageloader.core.download.ImageDownloader;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Contains needed information for decoding image to Bitmap
|
|
||||||
*
|
|
||||||
* @author Sergey Tarasevich (nostra13[at]gmail[dot]com)
|
|
||||||
* @since 1.8.3
|
|
||||||
*/
|
|
||||||
public class ImageDecodingInfo {
|
|
||||||
|
|
||||||
private final String imageKey;
|
|
||||||
private final String imageUri;
|
|
||||||
private final String originalImageUri;
|
|
||||||
private final ImageSize targetSize;
|
|
||||||
|
|
||||||
private final ImageScaleType imageScaleType;
|
|
||||||
private final ViewScaleType viewScaleType;
|
|
||||||
|
|
||||||
private final ImageDownloader downloader;
|
|
||||||
private final Object extraForDownloader;
|
|
||||||
|
|
||||||
private final boolean considerExifParams;
|
|
||||||
private final Options decodingOptions;
|
|
||||||
|
|
||||||
public ImageDecodingInfo(String imageKey, String imageUri, String originalImageUri, ImageSize targetSize, ViewScaleType viewScaleType,
|
|
||||||
ImageDownloader downloader, DisplayImageOptions displayOptions) {
|
|
||||||
this.imageKey = imageKey;
|
|
||||||
this.imageUri = imageUri;
|
|
||||||
this.originalImageUri = originalImageUri;
|
|
||||||
this.targetSize = targetSize;
|
|
||||||
|
|
||||||
this.imageScaleType = displayOptions.getImageScaleType();
|
|
||||||
this.viewScaleType = viewScaleType;
|
|
||||||
|
|
||||||
this.downloader = downloader;
|
|
||||||
this.extraForDownloader = displayOptions.getExtraForDownloader();
|
|
||||||
|
|
||||||
considerExifParams = displayOptions.isConsiderExifParams();
|
|
||||||
decodingOptions = new Options();
|
|
||||||
copyOptions(displayOptions.getDecodingOptions(), decodingOptions);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void copyOptions(Options srcOptions, Options destOptions) {
|
|
||||||
destOptions.inDensity = srcOptions.inDensity;
|
|
||||||
destOptions.inDither = srcOptions.inDither;
|
|
||||||
destOptions.inInputShareable = srcOptions.inInputShareable;
|
|
||||||
destOptions.inJustDecodeBounds = srcOptions.inJustDecodeBounds;
|
|
||||||
destOptions.inPreferredConfig = srcOptions.inPreferredConfig;
|
|
||||||
destOptions.inPurgeable = srcOptions.inPurgeable;
|
|
||||||
destOptions.inSampleSize = srcOptions.inSampleSize;
|
|
||||||
destOptions.inScaled = srcOptions.inScaled;
|
|
||||||
destOptions.inScreenDensity = srcOptions.inScreenDensity;
|
|
||||||
destOptions.inTargetDensity = srcOptions.inTargetDensity;
|
|
||||||
destOptions.inTempStorage = srcOptions.inTempStorage;
|
|
||||||
if (Build.VERSION.SDK_INT >= 10) copyOptions10(srcOptions, destOptions);
|
|
||||||
if (Build.VERSION.SDK_INT >= 11) copyOptions11(srcOptions, destOptions);
|
|
||||||
}
|
|
||||||
|
|
||||||
@TargetApi(10)
|
|
||||||
private void copyOptions10(Options srcOptions, Options destOptions) {
|
|
||||||
destOptions.inPreferQualityOverSpeed = srcOptions.inPreferQualityOverSpeed;
|
|
||||||
}
|
|
||||||
|
|
||||||
@TargetApi(11)
|
|
||||||
private void copyOptions11(Options srcOptions, Options destOptions) {
|
|
||||||
destOptions.inBitmap = srcOptions.inBitmap;
|
|
||||||
destOptions.inMutable = srcOptions.inMutable;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @return Original {@linkplain com.nostra13.universalimageloader.utils.MemoryCacheUtils#generateKey(String, ImageSize) image key} (used in memory cache). */
|
|
||||||
public String getImageKey() {
|
|
||||||
return imageKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @return Image URI for decoding (usually image from disk cache) */
|
|
||||||
public String getImageUri() {
|
|
||||||
return imageUri;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @return The original image URI which was passed to ImageLoader */
|
|
||||||
public String getOriginalImageUri() {
|
|
||||||
return originalImageUri;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return Target size for image. Decoded bitmap should close to this size according to {@linkplain ImageScaleType
|
|
||||||
* image scale type} and {@linkplain ViewScaleType view scale type}.
|
|
||||||
*/
|
|
||||||
public ImageSize getTargetSize() {
|
|
||||||
return targetSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return {@linkplain ImageScaleType Scale type for image sampling and scaling}. This parameter affects result size
|
|
||||||
* of decoded bitmap.
|
|
||||||
*/
|
|
||||||
public ImageScaleType getImageScaleType() {
|
|
||||||
return imageScaleType;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @return {@linkplain ViewScaleType View scale type}. This parameter affects result size of decoded bitmap. */
|
|
||||||
public ViewScaleType getViewScaleType() {
|
|
||||||
return viewScaleType;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @return Downloader for image loading */
|
|
||||||
public ImageDownloader getDownloader() {
|
|
||||||
return downloader;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @return Auxiliary object for downloader */
|
|
||||||
public Object getExtraForDownloader() {
|
|
||||||
return extraForDownloader;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @return <b>true</b> - if EXIF params of image should be considered; <b>false</b> - otherwise */
|
|
||||||
public boolean shouldConsiderExifParams() {
|
|
||||||
return considerExifParams;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @return Decoding options */
|
|
||||||
public Options getDecodingOptions() {
|
|
||||||
return decodingOptions;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,43 +0,0 @@
|
|||||||
/*******************************************************************************
|
|
||||||
* Copyright 2011-2014 Sergey Tarasevich
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*******************************************************************************/
|
|
||||||
package com.nostra13.universalimageloader.core.display;
|
|
||||||
|
|
||||||
import android.graphics.Bitmap;
|
|
||||||
import com.nostra13.universalimageloader.core.assist.LoadedFrom;
|
|
||||||
import com.nostra13.universalimageloader.core.imageaware.ImageAware;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Displays {@link Bitmap} in {@link com.nostra13.universalimageloader.core.imageaware.ImageAware}. Implementations can
|
|
||||||
* apply some changes to Bitmap or any animation for displaying Bitmap.<br />
|
|
||||||
* Implementations have to be thread-safe.
|
|
||||||
*
|
|
||||||
* @author Sergey Tarasevich (nostra13[at]gmail[dot]com)
|
|
||||||
* @see com.nostra13.universalimageloader.core.imageaware.ImageAware
|
|
||||||
* @see com.nostra13.universalimageloader.core.assist.LoadedFrom
|
|
||||||
* @since 1.5.6
|
|
||||||
*/
|
|
||||||
public interface BitmapDisplayer {
|
|
||||||
/**
|
|
||||||
* Displays bitmap in {@link com.nostra13.universalimageloader.core.imageaware.ImageAware}.
|
|
||||||
* <b>NOTE:</b> This method is called on UI thread so it's strongly recommended not to do any heavy work in it.
|
|
||||||
*
|
|
||||||
* @param bitmap Source bitmap
|
|
||||||
* @param imageAware {@linkplain com.nostra13.universalimageloader.core.imageaware.ImageAware Image aware view} to
|
|
||||||
* display Bitmap
|
|
||||||
* @param loadedFrom Source of loaded image
|
|
||||||
*/
|
|
||||||
void display(Bitmap bitmap, ImageAware imageAware, LoadedFrom loadedFrom);
|
|
||||||
}
|
|
@ -1,86 +0,0 @@
|
|||||||
/*******************************************************************************
|
|
||||||
* Copyright 2011-2014 Sergey Tarasevich, Daniel Martí
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*******************************************************************************/
|
|
||||||
package com.nostra13.universalimageloader.core.display;
|
|
||||||
|
|
||||||
import android.graphics.Bitmap;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.animation.AlphaAnimation;
|
|
||||||
import android.view.animation.DecelerateInterpolator;
|
|
||||||
import android.widget.ImageView;
|
|
||||||
import com.nostra13.universalimageloader.core.assist.LoadedFrom;
|
|
||||||
import com.nostra13.universalimageloader.core.imageaware.ImageAware;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Displays image with "fade in" animation
|
|
||||||
*
|
|
||||||
* @author Sergey Tarasevich (nostra13[at]gmail[dot]com), Daniel Martí
|
|
||||||
* @since 1.6.4
|
|
||||||
*/
|
|
||||||
public class FadeInBitmapDisplayer implements BitmapDisplayer {
|
|
||||||
|
|
||||||
private final int durationMillis;
|
|
||||||
|
|
||||||
private final boolean animateFromNetwork;
|
|
||||||
private final boolean animateFromDisk;
|
|
||||||
private final boolean animateFromMemory;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param durationMillis Duration of "fade-in" animation (in milliseconds)
|
|
||||||
*/
|
|
||||||
public FadeInBitmapDisplayer(int durationMillis) {
|
|
||||||
this(durationMillis, true, true, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param durationMillis Duration of "fade-in" animation (in milliseconds)
|
|
||||||
* @param animateFromNetwork Whether animation should be played if image is loaded from network
|
|
||||||
* @param animateFromDisk Whether animation should be played if image is loaded from disk cache
|
|
||||||
* @param animateFromMemory Whether animation should be played if image is loaded from memory cache
|
|
||||||
*/
|
|
||||||
public FadeInBitmapDisplayer(int durationMillis, boolean animateFromNetwork, boolean animateFromDisk,
|
|
||||||
boolean animateFromMemory) {
|
|
||||||
this.durationMillis = durationMillis;
|
|
||||||
this.animateFromNetwork = animateFromNetwork;
|
|
||||||
this.animateFromDisk = animateFromDisk;
|
|
||||||
this.animateFromMemory = animateFromMemory;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void display(Bitmap bitmap, ImageAware imageAware, LoadedFrom loadedFrom) {
|
|
||||||
imageAware.setImageBitmap(bitmap);
|
|
||||||
|
|
||||||
if ((animateFromNetwork && loadedFrom == LoadedFrom.NETWORK) ||
|
|
||||||
(animateFromDisk && loadedFrom == LoadedFrom.DISC_CACHE) ||
|
|
||||||
(animateFromMemory && loadedFrom == LoadedFrom.MEMORY_CACHE)) {
|
|
||||||
animate(imageAware.getWrappedView(), durationMillis);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Animates {@link ImageView} with "fade-in" effect
|
|
||||||
*
|
|
||||||
* @param imageView {@link ImageView} which display image in
|
|
||||||
* @param durationMillis The length of the animation in milliseconds
|
|
||||||
*/
|
|
||||||
public static void animate(View imageView, int durationMillis) {
|
|
||||||
if (imageView != null) {
|
|
||||||
AlphaAnimation fadeImage = new AlphaAnimation(0, 1);
|
|
||||||
fadeImage.setDuration(durationMillis);
|
|
||||||
fadeImage.setInterpolator(new DecelerateInterpolator());
|
|
||||||
imageView.startAnimation(fadeImage);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,118 +0,0 @@
|
|||||||
/*******************************************************************************
|
|
||||||
* Copyright 2011-2014 Sergey Tarasevich
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*******************************************************************************/
|
|
||||||
package com.nostra13.universalimageloader.core.display;
|
|
||||||
|
|
||||||
import android.graphics.*;
|
|
||||||
import android.graphics.drawable.Drawable;
|
|
||||||
|
|
||||||
import com.nostra13.universalimageloader.core.assist.LoadedFrom;
|
|
||||||
import com.nostra13.universalimageloader.core.imageaware.ImageAware;
|
|
||||||
import com.nostra13.universalimageloader.core.imageaware.ImageViewAware;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Can display bitmap with rounded corners. This implementation works only with ImageViews wrapped
|
|
||||||
* in ImageViewAware.
|
|
||||||
* <br />
|
|
||||||
* This implementation is inspired by
|
|
||||||
* <a href="http://www.curious-creature.org/2012/12/11/android-recipe-1-image-with-rounded-corners/">
|
|
||||||
* Romain Guy's article</a>. It rounds images using custom drawable drawing. Original bitmap isn't changed.
|
|
||||||
* <br />
|
|
||||||
* <br />
|
|
||||||
* If this implementation doesn't meet your needs then consider
|
|
||||||
* <a href="https://github.com/vinc3m1/RoundedImageView">RoundedImageView</a> or
|
|
||||||
* <a href="https://github.com/Pkmmte/CircularImageView">CircularImageView</a> projects for usage.
|
|
||||||
*
|
|
||||||
* @author Sergey Tarasevich (nostra13[at]gmail[dot]com)
|
|
||||||
* @since 1.5.6
|
|
||||||
*/
|
|
||||||
public class RoundedBitmapDisplayer implements BitmapDisplayer {
|
|
||||||
|
|
||||||
protected final int cornerRadius;
|
|
||||||
protected final int margin;
|
|
||||||
|
|
||||||
public RoundedBitmapDisplayer(int cornerRadiusPixels) {
|
|
||||||
this(cornerRadiusPixels, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public RoundedBitmapDisplayer(int cornerRadiusPixels, int marginPixels) {
|
|
||||||
this.cornerRadius = cornerRadiusPixels;
|
|
||||||
this.margin = marginPixels;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void display(Bitmap bitmap, ImageAware imageAware, LoadedFrom loadedFrom) {
|
|
||||||
if (!(imageAware instanceof ImageViewAware)) {
|
|
||||||
throw new IllegalArgumentException("ImageAware should wrap ImageView. ImageViewAware is expected.");
|
|
||||||
}
|
|
||||||
|
|
||||||
imageAware.setImageDrawable(new RoundedDrawable(bitmap, cornerRadius, margin));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class RoundedDrawable extends Drawable {
|
|
||||||
|
|
||||||
protected final float cornerRadius;
|
|
||||||
protected final int margin;
|
|
||||||
|
|
||||||
protected final RectF mRect = new RectF(),
|
|
||||||
mBitmapRect;
|
|
||||||
protected final BitmapShader bitmapShader;
|
|
||||||
protected final Paint paint;
|
|
||||||
|
|
||||||
public RoundedDrawable(Bitmap bitmap, int cornerRadius, int margin) {
|
|
||||||
this.cornerRadius = cornerRadius;
|
|
||||||
this.margin = margin;
|
|
||||||
|
|
||||||
bitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
|
|
||||||
mBitmapRect = new RectF (margin, margin, bitmap.getWidth() - margin, bitmap.getHeight() - margin);
|
|
||||||
|
|
||||||
paint = new Paint();
|
|
||||||
paint.setAntiAlias(true);
|
|
||||||
paint.setShader(bitmapShader);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onBoundsChange(Rect bounds) {
|
|
||||||
super.onBoundsChange(bounds);
|
|
||||||
mRect.set(margin, margin, bounds.width() - margin, bounds.height() - margin);
|
|
||||||
|
|
||||||
// Resize the original bitmap to fit the new bound
|
|
||||||
Matrix shaderMatrix = new Matrix();
|
|
||||||
shaderMatrix.setRectToRect(mBitmapRect, mRect, Matrix.ScaleToFit.FILL);
|
|
||||||
bitmapShader.setLocalMatrix(shaderMatrix);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void draw(Canvas canvas) {
|
|
||||||
canvas.drawRoundRect(mRect, cornerRadius, cornerRadius, paint);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getOpacity() {
|
|
||||||
return PixelFormat.TRANSLUCENT;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setAlpha(int alpha) {
|
|
||||||
paint.setAlpha(alpha);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setColorFilter(ColorFilter cf) {
|
|
||||||
paint.setColorFilter(cf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,74 +0,0 @@
|
|||||||
/*******************************************************************************
|
|
||||||
* Copyright 2013 Sergey Tarasevich
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*******************************************************************************/
|
|
||||||
package com.nostra13.universalimageloader.core.display;
|
|
||||||
|
|
||||||
import android.graphics.*;
|
|
||||||
import com.nostra13.universalimageloader.core.assist.LoadedFrom;
|
|
||||||
import com.nostra13.universalimageloader.core.imageaware.ImageAware;
|
|
||||||
import com.nostra13.universalimageloader.core.imageaware.ImageViewAware;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Can display bitmap with rounded corners and vignette effect. This implementation works only with ImageViews wrapped
|
|
||||||
* in ImageViewAware.
|
|
||||||
* <br />
|
|
||||||
* This implementation is inspired by
|
|
||||||
* <a href="http://www.curious-creature.org/2012/12/11/android-recipe-1-image-with-rounded-corners/">
|
|
||||||
* Romain Guy's article</a>. It rounds images using custom drawable drawing. Original bitmap isn't changed.
|
|
||||||
* <br />
|
|
||||||
* <br />
|
|
||||||
* If this implementation doesn't meet your needs then consider
|
|
||||||
* <a href="https://github.com/vinc3m1/RoundedImageView">this project</a> for usage.
|
|
||||||
*
|
|
||||||
* @author Sergey Tarasevich (nostra13[at]gmail[dot]com)
|
|
||||||
* @since 1.9.1
|
|
||||||
*/
|
|
||||||
public class RoundedVignetteBitmapDisplayer extends RoundedBitmapDisplayer {
|
|
||||||
|
|
||||||
public RoundedVignetteBitmapDisplayer(int cornerRadiusPixels, int marginPixels) {
|
|
||||||
super(cornerRadiusPixels, marginPixels);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void display(Bitmap bitmap, ImageAware imageAware, LoadedFrom loadedFrom) {
|
|
||||||
if (!(imageAware instanceof ImageViewAware)) {
|
|
||||||
throw new IllegalArgumentException("ImageAware should wrap ImageView. ImageViewAware is expected.");
|
|
||||||
}
|
|
||||||
|
|
||||||
imageAware.setImageDrawable(new RoundedVignetteDrawable(bitmap, cornerRadius, margin));
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static class RoundedVignetteDrawable extends RoundedDrawable {
|
|
||||||
|
|
||||||
RoundedVignetteDrawable(Bitmap bitmap, int cornerRadius, int margin) {
|
|
||||||
super(bitmap, cornerRadius, margin);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onBoundsChange(Rect bounds) {
|
|
||||||
super.onBoundsChange(bounds);
|
|
||||||
RadialGradient vignette = new RadialGradient(
|
|
||||||
mRect.centerX(), mRect.centerY() * 1.0f / 0.7f, mRect.centerX() * 1.3f,
|
|
||||||
new int[]{0, 0, 0x7f000000}, new float[]{0.0f, 0.7f, 1.0f},
|
|
||||||
Shader.TileMode.CLAMP);
|
|
||||||
|
|
||||||
Matrix oval = new Matrix();
|
|
||||||
oval.setScale(1.0f, 0.7f);
|
|
||||||
vignette.setLocalMatrix(oval);
|
|
||||||
|
|
||||||
paint.setShader(new ComposeShader(bitmapShader, vignette, PorterDuff.Mode.SRC_OVER));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,33 +0,0 @@
|
|||||||
/*******************************************************************************
|
|
||||||
* Copyright 2011-2013 Sergey Tarasevich
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*******************************************************************************/
|
|
||||||
package com.nostra13.universalimageloader.core.display;
|
|
||||||
|
|
||||||
import android.graphics.Bitmap;
|
|
||||||
import com.nostra13.universalimageloader.core.assist.LoadedFrom;
|
|
||||||
import com.nostra13.universalimageloader.core.imageaware.ImageAware;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Just displays {@link Bitmap} in {@link com.nostra13.universalimageloader.core.imageaware.ImageAware}
|
|
||||||
*
|
|
||||||
* @author Sergey Tarasevich (nostra13[at]gmail[dot]com)
|
|
||||||
* @since 1.5.6
|
|
||||||
*/
|
|
||||||
public final class SimpleBitmapDisplayer implements BitmapDisplayer {
|
|
||||||
@Override
|
|
||||||
public void display(Bitmap bitmap, ImageAware imageAware, LoadedFrom loadedFrom) {
|
|
||||||
imageAware.setImageBitmap(bitmap);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,293 +0,0 @@
|
|||||||
/*******************************************************************************
|
|
||||||
* Copyright 2011-2014 Sergey Tarasevich
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*******************************************************************************/
|
|
||||||
package com.nostra13.universalimageloader.core.download;
|
|
||||||
|
|
||||||
import android.annotation.TargetApi;
|
|
||||||
import android.content.ContentResolver;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.graphics.Bitmap;
|
|
||||||
import android.graphics.Bitmap.CompressFormat;
|
|
||||||
import android.media.ThumbnailUtils;
|
|
||||||
import android.net.Uri;
|
|
||||||
import android.os.Build;
|
|
||||||
import android.provider.ContactsContract;
|
|
||||||
import android.provider.MediaStore;
|
|
||||||
import android.webkit.MimeTypeMap;
|
|
||||||
import com.nostra13.universalimageloader.core.DisplayImageOptions;
|
|
||||||
import com.nostra13.universalimageloader.core.assist.ContentLengthInputStream;
|
|
||||||
import com.nostra13.universalimageloader.utils.IoUtils;
|
|
||||||
|
|
||||||
import java.io.BufferedInputStream;
|
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.net.HttpURLConnection;
|
|
||||||
import java.net.URL;
|
|
||||||
import java.net.URLConnection;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Provides retrieving of {@link InputStream} of image by URI from network or file system or app resources.<br />
|
|
||||||
* {@link URLConnection} is used to retrieve image stream from network.
|
|
||||||
*
|
|
||||||
* @author Sergey Tarasevich (nostra13[at]gmail[dot]com)
|
|
||||||
* @since 1.8.0
|
|
||||||
*/
|
|
||||||
public class BaseImageDownloader implements ImageDownloader {
|
|
||||||
/** {@value} */
|
|
||||||
public static final int DEFAULT_HTTP_CONNECT_TIMEOUT = 5 * 1000; // milliseconds
|
|
||||||
/** {@value} */
|
|
||||||
public static final int DEFAULT_HTTP_READ_TIMEOUT = 20 * 1000; // milliseconds
|
|
||||||
|
|
||||||
/** {@value} */
|
|
||||||
protected static final int BUFFER_SIZE = 32 * 1024; // 32 Kb
|
|
||||||
/** {@value} */
|
|
||||||
protected static final String ALLOWED_URI_CHARS = "@#&=*+-_.,:!?()/~'%";
|
|
||||||
|
|
||||||
protected static final int MAX_REDIRECT_COUNT = 5;
|
|
||||||
|
|
||||||
protected static final String CONTENT_CONTACTS_URI_PREFIX = "content://com.android.contacts/";
|
|
||||||
|
|
||||||
private static final String ERROR_UNSUPPORTED_SCHEME = "UIL doesn't support scheme(protocol) by default [%s]. " + "You should implement this support yourself (BaseImageDownloader.getStreamFromOtherSource(...))";
|
|
||||||
|
|
||||||
protected final Context context;
|
|
||||||
protected final int connectTimeout;
|
|
||||||
protected final int readTimeout;
|
|
||||||
|
|
||||||
public BaseImageDownloader(Context context) {
|
|
||||||
this(context, DEFAULT_HTTP_CONNECT_TIMEOUT, DEFAULT_HTTP_READ_TIMEOUT);
|
|
||||||
}
|
|
||||||
|
|
||||||
public BaseImageDownloader(Context context, int connectTimeout, int readTimeout) {
|
|
||||||
this.context = context.getApplicationContext();
|
|
||||||
this.connectTimeout = connectTimeout;
|
|
||||||
this.readTimeout = readTimeout;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public InputStream getStream(String imageUri, Object extra) throws IOException {
|
|
||||||
switch (Scheme.ofUri(imageUri)) {
|
|
||||||
case HTTP:
|
|
||||||
case HTTPS:
|
|
||||||
return getStreamFromNetwork(imageUri, extra);
|
|
||||||
case FILE:
|
|
||||||
return getStreamFromFile(imageUri, extra);
|
|
||||||
case CONTENT:
|
|
||||||
return getStreamFromContent(imageUri, extra);
|
|
||||||
case ASSETS:
|
|
||||||
return getStreamFromAssets(imageUri, extra);
|
|
||||||
case DRAWABLE:
|
|
||||||
return getStreamFromDrawable(imageUri, extra);
|
|
||||||
case UNKNOWN:
|
|
||||||
default:
|
|
||||||
return getStreamFromOtherSource(imageUri, extra);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves {@link InputStream} of image by URI (image is located in the network).
|
|
||||||
*
|
|
||||||
* @param imageUri Image URI
|
|
||||||
* @param extra Auxiliary object which was passed to {@link DisplayImageOptions.Builder#extraForDownloader(Object)
|
|
||||||
* DisplayImageOptions.extraForDownloader(Object)}; can be null
|
|
||||||
* @return {@link InputStream} of image
|
|
||||||
* @throws IOException if some I/O error occurs during network request or if no InputStream could be created for
|
|
||||||
* URL.
|
|
||||||
*/
|
|
||||||
protected InputStream getStreamFromNetwork(String imageUri, Object extra) throws IOException {
|
|
||||||
HttpURLConnection conn = createConnection(imageUri, extra);
|
|
||||||
|
|
||||||
int redirectCount = 0;
|
|
||||||
while (conn.getResponseCode() / 100 == 3 && redirectCount < MAX_REDIRECT_COUNT) {
|
|
||||||
conn = createConnection(conn.getHeaderField("Location"), extra);
|
|
||||||
redirectCount++;
|
|
||||||
}
|
|
||||||
|
|
||||||
InputStream imageStream;
|
|
||||||
try {
|
|
||||||
imageStream = conn.getInputStream();
|
|
||||||
} catch (IOException e) {
|
|
||||||
// Read all data to allow reuse connection (http://bit.ly/1ad35PY)
|
|
||||||
IoUtils.readAndCloseStream(conn.getErrorStream());
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
if (!shouldBeProcessed(conn)) {
|
|
||||||
IoUtils.closeSilently(imageStream);
|
|
||||||
throw new IOException("Image request failed with response code " + conn.getResponseCode());
|
|
||||||
}
|
|
||||||
|
|
||||||
return new ContentLengthInputStream(new BufferedInputStream(imageStream, BUFFER_SIZE), conn.getContentLength());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param conn Opened request connection (response code is available)
|
|
||||||
* @return <b>true</b> - if data from connection is correct and should be read and processed;
|
|
||||||
* <b>false</b> - if response contains irrelevant data and shouldn't be processed
|
|
||||||
* @throws IOException
|
|
||||||
*/
|
|
||||||
protected boolean shouldBeProcessed(HttpURLConnection conn) throws IOException {
|
|
||||||
return conn.getResponseCode() == 200;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create {@linkplain HttpURLConnection HTTP connection} for incoming URL
|
|
||||||
*
|
|
||||||
* @param url URL to connect to
|
|
||||||
* @param extra Auxiliary object which was passed to {@link DisplayImageOptions.Builder#extraForDownloader(Object)
|
|
||||||
* DisplayImageOptions.extraForDownloader(Object)}; can be null
|
|
||||||
* @return {@linkplain HttpURLConnection Connection} for incoming URL. Connection isn't established so it still configurable.
|
|
||||||
* @throws IOException if some I/O error occurs during network request or if no InputStream could be created for
|
|
||||||
* URL.
|
|
||||||
*/
|
|
||||||
protected HttpURLConnection createConnection(String url, Object extra) throws IOException {
|
|
||||||
String encodedUrl = Uri.encode(url, ALLOWED_URI_CHARS);
|
|
||||||
HttpURLConnection conn = (HttpURLConnection) new URL(encodedUrl).openConnection();
|
|
||||||
conn.setConnectTimeout(connectTimeout);
|
|
||||||
conn.setReadTimeout(readTimeout);
|
|
||||||
return conn;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves {@link InputStream} of image by URI (image is located on the local file system or SD card).
|
|
||||||
*
|
|
||||||
* @param imageUri Image URI
|
|
||||||
* @param extra Auxiliary object which was passed to {@link DisplayImageOptions.Builder#extraForDownloader(Object)
|
|
||||||
* DisplayImageOptions.extraForDownloader(Object)}; can be null
|
|
||||||
* @return {@link InputStream} of image
|
|
||||||
* @throws IOException if some I/O error occurs reading from file system
|
|
||||||
*/
|
|
||||||
protected InputStream getStreamFromFile(String imageUri, Object extra) throws IOException {
|
|
||||||
String filePath = Scheme.FILE.crop(imageUri);
|
|
||||||
if (isVideoFileUri(imageUri)) {
|
|
||||||
return getVideoThumbnailStream(filePath);
|
|
||||||
} else {
|
|
||||||
BufferedInputStream imageStream = new BufferedInputStream(new FileInputStream(filePath), BUFFER_SIZE);
|
|
||||||
return new ContentLengthInputStream(imageStream, (int) new File(filePath).length());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@TargetApi(Build.VERSION_CODES.FROYO)
|
|
||||||
private InputStream getVideoThumbnailStream(String filePath) {
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO) {
|
|
||||||
Bitmap bitmap = ThumbnailUtils
|
|
||||||
.createVideoThumbnail(filePath, MediaStore.Images.Thumbnails.FULL_SCREEN_KIND);
|
|
||||||
if (bitmap != null) {
|
|
||||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
|
||||||
bitmap.compress(CompressFormat.PNG, 0, bos);
|
|
||||||
return new ByteArrayInputStream(bos.toByteArray());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves {@link InputStream} of image by URI (image is accessed using {@link ContentResolver}).
|
|
||||||
*
|
|
||||||
* @param imageUri Image URI
|
|
||||||
* @param extra Auxiliary object which was passed to {@link DisplayImageOptions.Builder#extraForDownloader(Object)
|
|
||||||
* DisplayImageOptions.extraForDownloader(Object)}; can be null
|
|
||||||
* @return {@link InputStream} of image
|
|
||||||
* @throws FileNotFoundException if the provided URI could not be opened
|
|
||||||
*/
|
|
||||||
protected InputStream getStreamFromContent(String imageUri, Object extra) throws FileNotFoundException {
|
|
||||||
ContentResolver res = context.getContentResolver();
|
|
||||||
|
|
||||||
Uri uri = Uri.parse(imageUri);
|
|
||||||
if (isVideoContentUri(uri)) { // video thumbnail
|
|
||||||
Long origId = Long.valueOf(uri.getLastPathSegment());
|
|
||||||
Bitmap bitmap = MediaStore.Video.Thumbnails
|
|
||||||
.getThumbnail(res, origId, MediaStore.Images.Thumbnails.MINI_KIND, null);
|
|
||||||
if (bitmap != null) {
|
|
||||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
|
||||||
bitmap.compress(CompressFormat.PNG, 0, bos);
|
|
||||||
return new ByteArrayInputStream(bos.toByteArray());
|
|
||||||
}
|
|
||||||
} else if (imageUri.startsWith(CONTENT_CONTACTS_URI_PREFIX)) { // contacts photo
|
|
||||||
return getContactPhotoStream(uri);
|
|
||||||
}
|
|
||||||
|
|
||||||
return res.openInputStream(uri);
|
|
||||||
}
|
|
||||||
|
|
||||||
@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
|
|
||||||
protected InputStream getContactPhotoStream(Uri uri) {
|
|
||||||
ContentResolver res = context.getContentResolver();
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
|
|
||||||
return ContactsContract.Contacts.openContactPhotoInputStream(res, uri, true);
|
|
||||||
} else {
|
|
||||||
return ContactsContract.Contacts.openContactPhotoInputStream(res, uri);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves {@link InputStream} of image by URI (image is located in assets of application).
|
|
||||||
*
|
|
||||||
* @param imageUri Image URI
|
|
||||||
* @param extra Auxiliary object which was passed to {@link DisplayImageOptions.Builder#extraForDownloader(Object)
|
|
||||||
* DisplayImageOptions.extraForDownloader(Object)}; can be null
|
|
||||||
* @return {@link InputStream} of image
|
|
||||||
* @throws IOException if some I/O error occurs file reading
|
|
||||||
*/
|
|
||||||
protected InputStream getStreamFromAssets(String imageUri, Object extra) throws IOException {
|
|
||||||
String filePath = Scheme.ASSETS.crop(imageUri);
|
|
||||||
return context.getAssets().open(filePath);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves {@link InputStream} of image by URI (image is located in drawable resources of application).
|
|
||||||
*
|
|
||||||
* @param imageUri Image URI
|
|
||||||
* @param extra Auxiliary object which was passed to {@link DisplayImageOptions.Builder#extraForDownloader(Object)
|
|
||||||
* DisplayImageOptions.extraForDownloader(Object)}; can be null
|
|
||||||
* @return {@link InputStream} of image
|
|
||||||
*/
|
|
||||||
protected InputStream getStreamFromDrawable(String imageUri, Object extra) {
|
|
||||||
String drawableIdString = Scheme.DRAWABLE.crop(imageUri);
|
|
||||||
int drawableId = Integer.parseInt(drawableIdString);
|
|
||||||
return context.getResources().openRawResource(drawableId);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves {@link InputStream} of image by URI from other source with unsupported scheme. Should be overriden by
|
|
||||||
* successors to implement image downloading from special sources.<br />
|
|
||||||
* This method is called only if image URI has unsupported scheme. Throws {@link UnsupportedOperationException} by
|
|
||||||
* default.
|
|
||||||
*
|
|
||||||
* @param imageUri Image URI
|
|
||||||
* @param extra Auxiliary object which was passed to {@link DisplayImageOptions.Builder#extraForDownloader(Object)
|
|
||||||
* DisplayImageOptions.extraForDownloader(Object)}; can be null
|
|
||||||
* @return {@link InputStream} of image
|
|
||||||
* @throws IOException if some I/O error occurs
|
|
||||||
* @throws UnsupportedOperationException if image URI has unsupported scheme(protocol)
|
|
||||||
*/
|
|
||||||
protected InputStream getStreamFromOtherSource(String imageUri, Object extra) throws IOException {
|
|
||||||
throw new UnsupportedOperationException(String.format(ERROR_UNSUPPORTED_SCHEME, imageUri));
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isVideoContentUri(Uri uri) {
|
|
||||||
String mimeType = context.getContentResolver().getType(uri);
|
|
||||||
return mimeType != null && mimeType.startsWith("video/");
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isVideoFileUri(String uri) {
|
|
||||||
String extension = MimeTypeMap.getFileExtensionFromUrl(uri);
|
|
||||||
String mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
|
|
||||||
return mimeType != null && mimeType.startsWith("video/");
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,90 +0,0 @@
|
|||||||
/*******************************************************************************
|
|
||||||
* Copyright 2011-2013 Sergey Tarasevich
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*******************************************************************************/
|
|
||||||
package com.nostra13.universalimageloader.core.download;
|
|
||||||
|
|
||||||
import com.nostra13.universalimageloader.core.DisplayImageOptions;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.util.Locale;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Provides retrieving of {@link InputStream} of image by URI.<br />
|
|
||||||
* Implementations have to be thread-safe.
|
|
||||||
*
|
|
||||||
* @author Sergey Tarasevich (nostra13[at]gmail[dot]com)
|
|
||||||
* @since 1.4.0
|
|
||||||
*/
|
|
||||||
public interface ImageDownloader {
|
|
||||||
/**
|
|
||||||
* Retrieves {@link InputStream} of image by URI.
|
|
||||||
*
|
|
||||||
* @param imageUri Image URI
|
|
||||||
* @param extra Auxiliary object which was passed to {@link DisplayImageOptions.Builder#extraForDownloader(Object)
|
|
||||||
* DisplayImageOptions.extraForDownloader(Object)}; can be null
|
|
||||||
* @return {@link InputStream} of image
|
|
||||||
* @throws IOException if some I/O error occurs during getting image stream
|
|
||||||
* @throws UnsupportedOperationException if image URI has unsupported scheme(protocol)
|
|
||||||
*/
|
|
||||||
InputStream getStream(String imageUri, Object extra) throws IOException;
|
|
||||||
|
|
||||||
/** Represents supported schemes(protocols) of URI. Provides convenient methods for work with schemes and URIs. */
|
|
||||||
public enum Scheme {
|
|
||||||
HTTP("http"), HTTPS("https"), FILE("file"), CONTENT("content"), ASSETS("assets"), DRAWABLE("drawable"), UNKNOWN("");
|
|
||||||
|
|
||||||
private String scheme;
|
|
||||||
private String uriPrefix;
|
|
||||||
|
|
||||||
Scheme(String scheme) {
|
|
||||||
this.scheme = scheme;
|
|
||||||
uriPrefix = scheme + "://";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Defines scheme of incoming URI
|
|
||||||
*
|
|
||||||
* @param uri URI for scheme detection
|
|
||||||
* @return Scheme of incoming URI
|
|
||||||
*/
|
|
||||||
public static Scheme ofUri(String uri) {
|
|
||||||
if (uri != null) {
|
|
||||||
for (Scheme s : values()) {
|
|
||||||
if (s.belongsTo(uri)) {
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return UNKNOWN;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean belongsTo(String uri) {
|
|
||||||
return uri.toLowerCase(Locale.US).startsWith(uriPrefix);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Appends scheme to incoming path */
|
|
||||||
public String wrap(String path) {
|
|
||||||
return uriPrefix + path;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Removed scheme part ("scheme://") from incoming URI */
|
|
||||||
public String crop(String uri) {
|
|
||||||
if (!belongsTo(uri)) {
|
|
||||||
throw new IllegalArgumentException(String.format("URI [%1$s] doesn't have expected scheme [%2$s]", uri, scheme));
|
|
||||||
}
|
|
||||||
return uri.substring(uriPrefix.length());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,114 +0,0 @@
|
|||||||
/*******************************************************************************
|
|
||||||
* Copyright 2013-2014 Sergey Tarasevich
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*******************************************************************************/
|
|
||||||
package com.nostra13.universalimageloader.core.imageaware;
|
|
||||||
|
|
||||||
import android.graphics.Bitmap;
|
|
||||||
import android.graphics.drawable.Drawable;
|
|
||||||
import android.view.View;
|
|
||||||
import com.nostra13.universalimageloader.core.assist.ViewScaleType;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents image aware view which provides all needed properties and behavior for image processing and displaying
|
|
||||||
* through {@link com.nostra13.universalimageloader.core.ImageLoader ImageLoader}.
|
|
||||||
* It can wrap any Android {@link android.view.View View} which can be accessed by {@link #getWrappedView()}. Wrapped
|
|
||||||
* view is returned in {@link com.nostra13.universalimageloader.core.listener.ImageLoadingListener ImageLoadingListener}'s
|
|
||||||
* callbacks.
|
|
||||||
*
|
|
||||||
* @author Sergey Tarasevich (nostra13[at]gmail[dot]com)
|
|
||||||
* @see ViewAware
|
|
||||||
* @see ImageViewAware
|
|
||||||
* @see NonViewAware
|
|
||||||
* @since 1.9.0
|
|
||||||
*/
|
|
||||||
public interface ImageAware {
|
|
||||||
/**
|
|
||||||
* Returns width of image aware view. This value is used to define scale size for original image.
|
|
||||||
* Can return 0 if width is undefined.<br />
|
|
||||||
* Is called on UI thread if ImageLoader was called on UI thread. Otherwise - on background thread.
|
|
||||||
*/
|
|
||||||
int getWidth();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns height of image aware view. This value is used to define scale size for original image.
|
|
||||||
* Can return 0 if height is undefined.<br />
|
|
||||||
* Is called on UI thread if ImageLoader was called on UI thread. Otherwise - on background thread.
|
|
||||||
*/
|
|
||||||
int getHeight();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns {@linkplain com.nostra13.universalimageloader.core.assist.ViewScaleType scale type} which is used for
|
|
||||||
* scaling image for this image aware view. Must <b>NOT</b> return <b>null</b>.
|
|
||||||
*/
|
|
||||||
ViewScaleType getScaleType();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns wrapped Android {@link android.view.View View}. Can return <b>null</b> if no view is wrapped or view was
|
|
||||||
* collected by GC.<br />
|
|
||||||
* Is called on UI thread if ImageLoader was called on UI thread. Otherwise - on background thread.
|
|
||||||
*/
|
|
||||||
View getWrappedView();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a flag whether image aware view is collected by GC or whatsoever. If so then ImageLoader stop processing
|
|
||||||
* of task for this image aware view and fires
|
|
||||||
* {@link com.nostra13.universalimageloader.core.listener.ImageLoadingListener#onLoadingCancelled(String,
|
|
||||||
* android.view.View) ImageLoadingListener#onLoadingCancelled(String, View)} callback.<br />
|
|
||||||
* Mey be called on UI thread if ImageLoader was called on UI thread. Otherwise - on background thread.
|
|
||||||
*
|
|
||||||
* @return <b>true</b> - if view is collected by GC and ImageLoader should stop processing this image aware view;
|
|
||||||
* <b>false</b> - otherwise
|
|
||||||
*/
|
|
||||||
boolean isCollected();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns ID of image aware view. Point of ID is similar to Object's hashCode. This ID should be unique for every
|
|
||||||
* image view instance and should be the same for same instances. This ID identifies processing task in ImageLoader
|
|
||||||
* so ImageLoader won't process two image aware views with the same ID in one time. When ImageLoader get new task
|
|
||||||
* it cancels old task with this ID (if any) and starts new task.
|
|
||||||
* <p/>
|
|
||||||
* It's reasonable to return hash code of wrapped view (if any) to prevent displaying non-actual images in view
|
|
||||||
* because of view re-using.
|
|
||||||
*/
|
|
||||||
int getId();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets image drawable into this image aware view.<br />
|
|
||||||
* Displays drawable in this image aware view
|
|
||||||
* {@linkplain com.nostra13.universalimageloader.core.DisplayImageOptions.Builder#showImageForEmptyUri(
|
|
||||||
*android.graphics.drawable.Drawable) for empty Uri},
|
|
||||||
* {@linkplain com.nostra13.universalimageloader.core.DisplayImageOptions.Builder#showImageOnLoading(
|
|
||||||
*android.graphics.drawable.Drawable) on loading} or
|
|
||||||
* {@linkplain com.nostra13.universalimageloader.core.DisplayImageOptions.Builder#showImageOnFail(
|
|
||||||
*android.graphics.drawable.Drawable) on loading fail}. These drawables can be specified in
|
|
||||||
* {@linkplain com.nostra13.universalimageloader.core.DisplayImageOptions display options}.<br />
|
|
||||||
* Also can be called in {@link com.nostra13.universalimageloader.core.display.BitmapDisplayer BitmapDisplayer}.< br />
|
|
||||||
* Is called on UI thread if ImageLoader was called on UI thread. Otherwise - on background thread.
|
|
||||||
*
|
|
||||||
* @return <b>true</b> if drawable was set successfully; <b>false</b> - otherwise
|
|
||||||
*/
|
|
||||||
boolean setImageDrawable(Drawable drawable);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets image bitmap into this image aware view.<br />
|
|
||||||
* Displays loaded and decoded image {@link android.graphics.Bitmap} in this image view aware.
|
|
||||||
* Actually it's used only in
|
|
||||||
* {@link com.nostra13.universalimageloader.core.display.BitmapDisplayer BitmapDisplayer}.< br />
|
|
||||||
* Is called on UI thread if ImageLoader was called on UI thread. Otherwise - on background thread.
|
|
||||||
*
|
|
||||||
* @return <b>true</b> if bitmap was set successfully; <b>false</b> - otherwise
|
|
||||||
*/
|
|
||||||
boolean setImageBitmap(Bitmap bitmap);
|
|
||||||
}
|
|
@ -1,143 +0,0 @@
|
|||||||
/*******************************************************************************
|
|
||||||
* Copyright 2013-2014 Sergey Tarasevich
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*******************************************************************************/
|
|
||||||
package com.nostra13.universalimageloader.core.imageaware;
|
|
||||||
|
|
||||||
import android.graphics.Bitmap;
|
|
||||||
import android.graphics.drawable.AnimationDrawable;
|
|
||||||
import android.graphics.drawable.Drawable;
|
|
||||||
import android.view.View;
|
|
||||||
import android.widget.ImageView;
|
|
||||||
import com.nostra13.universalimageloader.core.assist.ViewScaleType;
|
|
||||||
import com.nostra13.universalimageloader.utils.L;
|
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Wrapper for Android {@link android.widget.ImageView ImageView}. Keeps weak reference of ImageView to prevent memory
|
|
||||||
* leaks.
|
|
||||||
*
|
|
||||||
* @author Sergey Tarasevich (nostra13[at]gmail[dot]com)
|
|
||||||
* @since 1.9.0
|
|
||||||
*/
|
|
||||||
public class ImageViewAware extends ViewAware {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor. <br />
|
|
||||||
* References {@link #ImageViewAware(android.widget.ImageView, boolean) ImageViewAware(imageView, true)}.
|
|
||||||
*
|
|
||||||
* @param imageView {@link android.widget.ImageView ImageView} to work with
|
|
||||||
*/
|
|
||||||
public ImageViewAware(ImageView imageView) {
|
|
||||||
super(imageView);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
*
|
|
||||||
* @param imageView {@link android.widget.ImageView ImageView} to work with
|
|
||||||
* @param checkActualViewSize <b>true</b> - then {@link #getWidth()} and {@link #getHeight()} will check actual
|
|
||||||
* size of ImageView. It can cause known issues like
|
|
||||||
* <a href="https://github.com/nostra13/Android-Universal-Image-Loader/issues/376">this</a>.
|
|
||||||
* But it helps to save memory because memory cache keeps bitmaps of actual (less in
|
|
||||||
* general) size.
|
|
||||||
* <p/>
|
|
||||||
* <b>false</b> - then {@link #getWidth()} and {@link #getHeight()} will <b>NOT</b>
|
|
||||||
* consider actual size of ImageView, just layout parameters. <br /> If you set 'false'
|
|
||||||
* it's recommended 'android:layout_width' and 'android:layout_height' (or
|
|
||||||
* 'android:maxWidth' and 'android:maxHeight') are set with concrete values. It helps to
|
|
||||||
* save memory.
|
|
||||||
* <p/>
|
|
||||||
*/
|
|
||||||
public ImageViewAware(ImageView imageView, boolean checkActualViewSize) {
|
|
||||||
super(imageView, checkActualViewSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
* <br />
|
|
||||||
* 3) Get <b>maxWidth</b>.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public int getWidth() {
|
|
||||||
int width = super.getWidth();
|
|
||||||
if (width <= 0) {
|
|
||||||
ImageView imageView = (ImageView) viewRef.get();
|
|
||||||
if (imageView != null) {
|
|
||||||
width = getImageViewFieldValue(imageView, "mMaxWidth"); // Check maxWidth parameter
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return width;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
* <br />
|
|
||||||
* 3) Get <b>maxHeight</b>
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public int getHeight() {
|
|
||||||
int height = super.getHeight();
|
|
||||||
if (height <= 0) {
|
|
||||||
ImageView imageView = (ImageView) viewRef.get();
|
|
||||||
if (imageView != null) {
|
|
||||||
height = getImageViewFieldValue(imageView, "mMaxHeight"); // Check maxHeight parameter
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return height;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ViewScaleType getScaleType() {
|
|
||||||
ImageView imageView = (ImageView) viewRef.get();
|
|
||||||
if (imageView != null) {
|
|
||||||
return ViewScaleType.fromImageView(imageView);
|
|
||||||
}
|
|
||||||
return super.getScaleType();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ImageView getWrappedView() {
|
|
||||||
return (ImageView) super.getWrappedView();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void setImageDrawableInto(Drawable drawable, View view) {
|
|
||||||
((ImageView) view).setImageDrawable(drawable);
|
|
||||||
if (drawable instanceof AnimationDrawable) {
|
|
||||||
((AnimationDrawable)drawable).start();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void setImageBitmapInto(Bitmap bitmap, View view) {
|
|
||||||
((ImageView) view).setImageBitmap(bitmap);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int getImageViewFieldValue(Object object, String fieldName) {
|
|
||||||
int value = 0;
|
|
||||||
try {
|
|
||||||
Field field = ImageView.class.getDeclaredField(fieldName);
|
|
||||||
field.setAccessible(true);
|
|
||||||
int fieldValue = (Integer) field.get(object);
|
|
||||||
if (fieldValue > 0 && fieldValue < Integer.MAX_VALUE) {
|
|
||||||
value = fieldValue;
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
L.e(e);
|
|
||||||
}
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,92 +0,0 @@
|
|||||||
/*******************************************************************************
|
|
||||||
* Copyright 2013-2014 Sergey Tarasevich
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*******************************************************************************/
|
|
||||||
package com.nostra13.universalimageloader.core.imageaware;
|
|
||||||
|
|
||||||
import android.graphics.Bitmap;
|
|
||||||
import android.graphics.drawable.Drawable;
|
|
||||||
import android.text.TextUtils;
|
|
||||||
import android.view.View;
|
|
||||||
import com.nostra13.universalimageloader.core.assist.ImageSize;
|
|
||||||
import com.nostra13.universalimageloader.core.assist.ViewScaleType;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ImageAware which provides needed info for processing of original image but do nothing for displaying image. It's
|
|
||||||
* used when user need just load and decode image and get it in {@linkplain
|
|
||||||
* com.nostra13.universalimageloader.core.listener.ImageLoadingListener#onLoadingComplete(String, android.view.View,
|
|
||||||
* android.graphics.Bitmap) callback}.
|
|
||||||
*
|
|
||||||
* @author Sergey Tarasevich (nostra13[at]gmail[dot]com)
|
|
||||||
* @since 1.9.0
|
|
||||||
*/
|
|
||||||
public class NonViewAware implements ImageAware {
|
|
||||||
|
|
||||||
protected final String imageUri;
|
|
||||||
protected final ImageSize imageSize;
|
|
||||||
protected final ViewScaleType scaleType;
|
|
||||||
|
|
||||||
public NonViewAware(ImageSize imageSize, ViewScaleType scaleType) {
|
|
||||||
this(null, imageSize, scaleType);
|
|
||||||
}
|
|
||||||
|
|
||||||
public NonViewAware(String imageUri, ImageSize imageSize, ViewScaleType scaleType) {
|
|
||||||
if (imageSize == null) throw new IllegalArgumentException("imageSize must not be null");
|
|
||||||
if (scaleType == null) throw new IllegalArgumentException("scaleType must not be null");
|
|
||||||
|
|
||||||
this.imageUri = imageUri;
|
|
||||||
this.imageSize = imageSize;
|
|
||||||
this.scaleType = scaleType;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getWidth() {
|
|
||||||
return imageSize.getWidth();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getHeight() {
|
|
||||||
return imageSize.getHeight();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ViewScaleType getScaleType() {
|
|
||||||
return scaleType;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public View getWrappedView() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isCollected() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getId() {
|
|
||||||
return TextUtils.isEmpty(imageUri) ? super.hashCode() : imageUri.hashCode();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean setImageDrawable(Drawable drawable) { // Do nothing
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean setImageBitmap(Bitmap bitmap) { // Do nothing
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,184 +0,0 @@
|
|||||||
/*******************************************************************************
|
|
||||||
* Copyright 2014 Sergey Tarasevich
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*******************************************************************************/
|
|
||||||
package com.nostra13.universalimageloader.core.imageaware;
|
|
||||||
|
|
||||||
import android.graphics.Bitmap;
|
|
||||||
import android.graphics.drawable.Drawable;
|
|
||||||
import android.os.Looper;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import com.nostra13.universalimageloader.core.assist.ViewScaleType;
|
|
||||||
import com.nostra13.universalimageloader.utils.L;
|
|
||||||
|
|
||||||
import java.lang.ref.Reference;
|
|
||||||
import java.lang.ref.WeakReference;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Wrapper for Android {@link android.view.View View}. Keeps weak reference of View to prevent memory leaks.
|
|
||||||
*
|
|
||||||
* @author Sergey Tarasevich (nostra13[at]gmail[dot]com)
|
|
||||||
* @since 1.9.2
|
|
||||||
*/
|
|
||||||
public abstract class ViewAware implements ImageAware {
|
|
||||||
|
|
||||||
public static final String WARN_CANT_SET_DRAWABLE = "Can't set a drawable into view. You should call ImageLoader on UI thread for it.";
|
|
||||||
public static final String WARN_CANT_SET_BITMAP = "Can't set a bitmap into view. You should call ImageLoader on UI thread for it.";
|
|
||||||
|
|
||||||
protected Reference<View> viewRef;
|
|
||||||
protected boolean checkActualViewSize;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor. <br />
|
|
||||||
* References {@link #ViewAware(android.view.View, boolean) ImageViewAware(imageView, true)}.
|
|
||||||
*
|
|
||||||
* @param view {@link android.view.View View} to work with
|
|
||||||
*/
|
|
||||||
public ViewAware(View view) {
|
|
||||||
this(view, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
*
|
|
||||||
* @param view {@link android.view.View View} to work with
|
|
||||||
* @param checkActualViewSize <b>true</b> - then {@link #getWidth()} and {@link #getHeight()} will check actual
|
|
||||||
* size of View. It can cause known issues like
|
|
||||||
* <a href="https://github.com/nostra13/Android-Universal-Image-Loader/issues/376">this</a>.
|
|
||||||
* But it helps to save memory because memory cache keeps bitmaps of actual (less in
|
|
||||||
* general) size.
|
|
||||||
* <p/>
|
|
||||||
* <b>false</b> - then {@link #getWidth()} and {@link #getHeight()} will <b>NOT</b>
|
|
||||||
* consider actual size of View, just layout parameters. <br /> If you set 'false'
|
|
||||||
* it's recommended 'android:layout_width' and 'android:layout_height' (or
|
|
||||||
* 'android:maxWidth' and 'android:maxHeight') are set with concrete values. It helps to
|
|
||||||
* save memory.
|
|
||||||
*/
|
|
||||||
public ViewAware(View view, boolean checkActualViewSize) {
|
|
||||||
if (view == null) throw new IllegalArgumentException("view must not be null");
|
|
||||||
|
|
||||||
this.viewRef = new WeakReference<View>(view);
|
|
||||||
this.checkActualViewSize = checkActualViewSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
* <p/>
|
|
||||||
* Width is defined by target {@link android.view.View view} parameters, configuration
|
|
||||||
* parameters or device display dimensions.<br />
|
|
||||||
* Size computing algorithm (go by steps until get non-zero value):<br />
|
|
||||||
* 1) Get the actual drawn <b>getWidth()</b> of the View<br />
|
|
||||||
* 2) Get <b>layout_width</b>
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public int getWidth() {
|
|
||||||
View view = viewRef.get();
|
|
||||||
if (view != null) {
|
|
||||||
final ViewGroup.LayoutParams params = view.getLayoutParams();
|
|
||||||
int width = 0;
|
|
||||||
if (checkActualViewSize && params != null && params.width != ViewGroup.LayoutParams.WRAP_CONTENT) {
|
|
||||||
width = view.getWidth(); // Get actual image width
|
|
||||||
}
|
|
||||||
if (width <= 0 && params != null) width = params.width; // Get layout width parameter
|
|
||||||
return width;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
* <p/>
|
|
||||||
* Height is defined by target {@link android.view.View view} parameters, configuration
|
|
||||||
* parameters or device display dimensions.<br />
|
|
||||||
* Size computing algorithm (go by steps until get non-zero value):<br />
|
|
||||||
* 1) Get the actual drawn <b>getHeight()</b> of the View<br />
|
|
||||||
* 2) Get <b>layout_height</b>
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public int getHeight() {
|
|
||||||
View view = viewRef.get();
|
|
||||||
if (view != null) {
|
|
||||||
final ViewGroup.LayoutParams params = view.getLayoutParams();
|
|
||||||
int height = 0;
|
|
||||||
if (checkActualViewSize && params != null && params.height != ViewGroup.LayoutParams.WRAP_CONTENT) {
|
|
||||||
height = view.getHeight(); // Get actual image height
|
|
||||||
}
|
|
||||||
if (height <= 0 && params != null) height = params.height; // Get layout height parameter
|
|
||||||
return height;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ViewScaleType getScaleType() {
|
|
||||||
return ViewScaleType.CROP;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public View getWrappedView() {
|
|
||||||
return viewRef.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isCollected() {
|
|
||||||
return viewRef.get() == null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getId() {
|
|
||||||
View view = viewRef.get();
|
|
||||||
return view == null ? super.hashCode() : view.hashCode();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean setImageDrawable(Drawable drawable) {
|
|
||||||
if (Looper.myLooper() == Looper.getMainLooper()) {
|
|
||||||
View view = viewRef.get();
|
|
||||||
if (view != null) {
|
|
||||||
setImageDrawableInto(drawable, view);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
L.w(WARN_CANT_SET_DRAWABLE);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean setImageBitmap(Bitmap bitmap) {
|
|
||||||
if (Looper.myLooper() == Looper.getMainLooper()) {
|
|
||||||
View view = viewRef.get();
|
|
||||||
if (view != null) {
|
|
||||||
setImageBitmapInto(bitmap, view);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
L.w(WARN_CANT_SET_BITMAP);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Should set drawable into incoming view. Incoming view is guaranteed not null.<br />
|
|
||||||
* This method is called on UI thread.
|
|
||||||
*/
|
|
||||||
protected abstract void setImageDrawableInto(Drawable drawable, View view);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Should set Bitmap into incoming view. Incoming view is guaranteed not null.< br />
|
|
||||||
* This method is called on UI thread.
|
|
||||||
*/
|
|
||||||
protected abstract void setImageBitmapInto(Bitmap bitmap, View view);
|
|
||||||
}
|
|
@ -1,67 +0,0 @@
|
|||||||
/*******************************************************************************
|
|
||||||
* Copyright 2011-2013 Sergey Tarasevich
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*******************************************************************************/
|
|
||||||
package com.nostra13.universalimageloader.core.listener;
|
|
||||||
|
|
||||||
import android.graphics.Bitmap;
|
|
||||||
import android.view.View;
|
|
||||||
import com.nostra13.universalimageloader.core.assist.FailReason;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Listener for image loading process.<br />
|
|
||||||
* You can use {@link SimpleImageLoadingListener} for implementing only needed methods.
|
|
||||||
*
|
|
||||||
* @author Sergey Tarasevich (nostra13[at]gmail[dot]com)
|
|
||||||
* @see SimpleImageLoadingListener
|
|
||||||
* @see com.nostra13.universalimageloader.core.assist.FailReason
|
|
||||||
* @since 1.0.0
|
|
||||||
*/
|
|
||||||
public interface ImageLoadingListener {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Is called when image loading task was started
|
|
||||||
*
|
|
||||||
* @param imageUri Loading image URI
|
|
||||||
* @param view View for image
|
|
||||||
*/
|
|
||||||
void onLoadingStarted(String imageUri, View view);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Is called when an error was occurred during image loading
|
|
||||||
*
|
|
||||||
* @param imageUri Loading image URI
|
|
||||||
* @param view View for image. Can be <b>null</b>.
|
|
||||||
* @param failReason {@linkplain com.nostra13.universalimageloader.core.assist.FailReason The reason} why image
|
|
||||||
* loading was failed
|
|
||||||
*/
|
|
||||||
void onLoadingFailed(String imageUri, View view, FailReason failReason);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Is called when image is loaded successfully (and displayed in View if one was specified)
|
|
||||||
*
|
|
||||||
* @param imageUri Loaded image URI
|
|
||||||
* @param view View for image. Can be <b>null</b>.
|
|
||||||
* @param loadedImage Bitmap of loaded and decoded image
|
|
||||||
*/
|
|
||||||
void onLoadingComplete(String imageUri, View view, Bitmap loadedImage);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Is called when image loading task was cancelled because View for image was reused in newer task
|
|
||||||
*
|
|
||||||
* @param imageUri Loading image URI
|
|
||||||
* @param view View for image. Can be <b>null</b>.
|
|
||||||
*/
|
|
||||||
void onLoadingCancelled(String imageUri, View view);
|
|
||||||
}
|
|
@ -1,37 +0,0 @@
|
|||||||
/*******************************************************************************
|
|
||||||
* Copyright 2013 Sergey Tarasevich
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*******************************************************************************/
|
|
||||||
package com.nostra13.universalimageloader.core.listener;
|
|
||||||
|
|
||||||
import android.view.View;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Listener for image loading progress.
|
|
||||||
*
|
|
||||||
* @author Sergey Tarasevich (nostra13[at]gmail[dot]com)
|
|
||||||
* @since 1.9.1
|
|
||||||
*/
|
|
||||||
public interface ImageLoadingProgressListener {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Is called when image loading progress changed.
|
|
||||||
*
|
|
||||||
* @param imageUri Image URI
|
|
||||||
* @param view View for image. Can be <b>null</b>.
|
|
||||||
* @param current Downloaded size in bytes
|
|
||||||
* @param total Total size in bytes
|
|
||||||
*/
|
|
||||||
void onProgressUpdate(String imageUri, View view, int current, int total);
|
|
||||||
}
|
|
@ -1,98 +0,0 @@
|
|||||||
/*******************************************************************************
|
|
||||||
* Copyright 2011-2013 Sergey Tarasevich
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*******************************************************************************/
|
|
||||||
package com.nostra13.universalimageloader.core.listener;
|
|
||||||
|
|
||||||
import android.widget.AbsListView;
|
|
||||||
import android.widget.AbsListView.OnScrollListener;
|
|
||||||
import android.widget.GridView;
|
|
||||||
import android.widget.ListView;
|
|
||||||
import com.nostra13.universalimageloader.core.ImageLoader;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Listener-helper for {@linkplain AbsListView list views} ({@link ListView}, {@link GridView}) which can
|
|
||||||
* {@linkplain ImageLoader#pause() pause ImageLoader's tasks} while list view is scrolling (touch scrolling and/or
|
|
||||||
* fling). It prevents redundant loadings.<br />
|
|
||||||
* Set it to your list view's {@link AbsListView#setOnScrollListener(OnScrollListener) setOnScrollListener(...)}.<br />
|
|
||||||
* This listener can wrap your custom {@linkplain OnScrollListener listener}.
|
|
||||||
*
|
|
||||||
* @author Sergey Tarasevich (nostra13[at]gmail[dot]com)
|
|
||||||
* @since 1.7.0
|
|
||||||
*/
|
|
||||||
public class PauseOnScrollListener implements OnScrollListener {
|
|
||||||
|
|
||||||
private ImageLoader imageLoader;
|
|
||||||
|
|
||||||
private final boolean pauseOnScroll;
|
|
||||||
private final boolean pauseOnFling;
|
|
||||||
private final OnScrollListener externalListener;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
*
|
|
||||||
* @param imageLoader {@linkplain ImageLoader} instance for controlling
|
|
||||||
* @param pauseOnScroll Whether {@linkplain ImageLoader#pause() pause ImageLoader} during touch scrolling
|
|
||||||
* @param pauseOnFling Whether {@linkplain ImageLoader#pause() pause ImageLoader} during fling
|
|
||||||
*/
|
|
||||||
public PauseOnScrollListener(ImageLoader imageLoader, boolean pauseOnScroll, boolean pauseOnFling) {
|
|
||||||
this(imageLoader, pauseOnScroll, pauseOnFling, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
*
|
|
||||||
* @param imageLoader {@linkplain ImageLoader} instance for controlling
|
|
||||||
* @param pauseOnScroll Whether {@linkplain ImageLoader#pause() pause ImageLoader} during touch scrolling
|
|
||||||
* @param pauseOnFling Whether {@linkplain ImageLoader#pause() pause ImageLoader} during fling
|
|
||||||
* @param customListener Your custom {@link OnScrollListener} for {@linkplain AbsListView list view} which also
|
|
||||||
* will be get scroll events
|
|
||||||
*/
|
|
||||||
public PauseOnScrollListener(ImageLoader imageLoader, boolean pauseOnScroll, boolean pauseOnFling,
|
|
||||||
OnScrollListener customListener) {
|
|
||||||
this.imageLoader = imageLoader;
|
|
||||||
this.pauseOnScroll = pauseOnScroll;
|
|
||||||
this.pauseOnFling = pauseOnFling;
|
|
||||||
externalListener = customListener;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onScrollStateChanged(AbsListView view, int scrollState) {
|
|
||||||
switch (scrollState) {
|
|
||||||
case OnScrollListener.SCROLL_STATE_IDLE:
|
|
||||||
imageLoader.resume();
|
|
||||||
break;
|
|
||||||
case OnScrollListener.SCROLL_STATE_TOUCH_SCROLL:
|
|
||||||
if (pauseOnScroll) {
|
|
||||||
imageLoader.pause();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case OnScrollListener.SCROLL_STATE_FLING:
|
|
||||||
if (pauseOnFling) {
|
|
||||||
imageLoader.pause();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (externalListener != null) {
|
|
||||||
externalListener.onScrollStateChanged(view, scrollState);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
|
|
||||||
if (externalListener != null) {
|
|
||||||
externalListener.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,50 +0,0 @@
|
|||||||
/*******************************************************************************
|
|
||||||
* Copyright 2011-2013 Sergey Tarasevich
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*******************************************************************************/
|
|
||||||
package com.nostra13.universalimageloader.core.listener;
|
|
||||||
|
|
||||||
import android.graphics.Bitmap;
|
|
||||||
import android.view.View;
|
|
||||||
import com.nostra13.universalimageloader.core.assist.FailReason;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A convenient class to extend when you only want to listen for a subset of all the image loading events. This
|
|
||||||
* implements all methods in the {@link com.nostra13.universalimageloader.core.listener.ImageLoadingListener} but does
|
|
||||||
* nothing.
|
|
||||||
*
|
|
||||||
* @author Sergey Tarasevich (nostra13[at]gmail[dot]com)
|
|
||||||
* @since 1.4.0
|
|
||||||
*/
|
|
||||||
public class SimpleImageLoadingListener implements ImageLoadingListener {
|
|
||||||
@Override
|
|
||||||
public void onLoadingStarted(String imageUri, View view) {
|
|
||||||
// Empty implementation
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onLoadingFailed(String imageUri, View view, FailReason failReason) {
|
|
||||||
// Empty implementation
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
|
|
||||||
// Empty implementation
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onLoadingCancelled(String imageUri, View view) {
|
|
||||||
// Empty implementation
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,40 +0,0 @@
|
|||||||
/*******************************************************************************
|
|
||||||
* Copyright 2011-2013 Sergey Tarasevich
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*******************************************************************************/
|
|
||||||
package com.nostra13.universalimageloader.core.process;
|
|
||||||
|
|
||||||
import android.graphics.Bitmap;
|
|
||||||
import com.nostra13.universalimageloader.core.DisplayImageOptions;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Makes some processing on {@link Bitmap}. Implementations can apply any changes to original {@link Bitmap}.<br />
|
|
||||||
* Implementations have to be thread-safe.
|
|
||||||
*
|
|
||||||
* @author Sergey Tarasevich (nostra13[at]gmail[dot]com)
|
|
||||||
* @since 1.8.0
|
|
||||||
*/
|
|
||||||
public interface BitmapProcessor {
|
|
||||||
/**
|
|
||||||
* Makes some processing of incoming bitmap.<br />
|
|
||||||
* This method is executing on additional thread (not on UI thread).<br />
|
|
||||||
* <b>Note:</b> If this processor is used as {@linkplain DisplayImageOptions.Builder#preProcessor(BitmapProcessor)
|
|
||||||
* pre-processor} then don't forget {@linkplain Bitmap#recycle() to recycle} incoming bitmap if you return a new
|
|
||||||
* created one.
|
|
||||||
*
|
|
||||||
* @param bitmap Original {@linkplain Bitmap bitmap}
|
|
||||||
* @return Processed {@linkplain Bitmap bitmap}
|
|
||||||
*/
|
|
||||||
Bitmap process(Bitmap bitmap);
|
|
||||||
}
|
|
@ -1,49 +0,0 @@
|
|||||||
/*******************************************************************************
|
|
||||||
* Copyright 2011-2014 Sergey Tarasevich
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*******************************************************************************/
|
|
||||||
package com.nostra13.universalimageloader.utils;
|
|
||||||
|
|
||||||
import com.nostra13.universalimageloader.cache.disc.DiskCache;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Utility for convenient work with disk cache.<br />
|
|
||||||
* <b>NOTE:</b> This utility works with file system so avoid using it on application main thread.
|
|
||||||
*
|
|
||||||
* @author Sergey Tarasevich (nostra13[at]gmail[dot]com)
|
|
||||||
* @since 1.8.0
|
|
||||||
*/
|
|
||||||
public final class DiskCacheUtils {
|
|
||||||
|
|
||||||
private DiskCacheUtils() {
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Returns {@link File} of cached image or <b>null</b> if image was not cached in disk cache */
|
|
||||||
public static File findInCache(String imageUri, DiskCache diskCache) {
|
|
||||||
File image = diskCache.get(imageUri);
|
|
||||||
return image != null && image.exists() ? image : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removed cached image file from disk cache (if image was cached in disk cache before)
|
|
||||||
*
|
|
||||||
* @return <b>true</b> - if cached image file existed and was deleted; <b>false</b> - otherwise.
|
|
||||||
*/
|
|
||||||
public static boolean removeFromCache(String imageUri, DiskCache diskCache) {
|
|
||||||
File image = diskCache.get(imageUri);
|
|
||||||
return image != null && image.exists() && image.delete();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,215 +0,0 @@
|
|||||||
/*******************************************************************************
|
|
||||||
* Copyright 2013-2014 Sergey Tarasevich
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*******************************************************************************/
|
|
||||||
package com.nostra13.universalimageloader.utils;
|
|
||||||
|
|
||||||
import android.graphics.BitmapFactory;
|
|
||||||
import android.opengl.GLES10;
|
|
||||||
import com.nostra13.universalimageloader.core.assist.ImageSize;
|
|
||||||
import com.nostra13.universalimageloader.core.assist.ViewScaleType;
|
|
||||||
import com.nostra13.universalimageloader.core.imageaware.ImageAware;
|
|
||||||
|
|
||||||
import javax.microedition.khronos.opengles.GL10;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Provides calculations with image sizes, scales
|
|
||||||
*
|
|
||||||
* @author Sergey Tarasevich (nostra13[at]gmail[dot]com)
|
|
||||||
* @since 1.8.3
|
|
||||||
*/
|
|
||||||
public final class ImageSizeUtils {
|
|
||||||
|
|
||||||
private static final int DEFAULT_MAX_BITMAP_DIMENSION = 2048;
|
|
||||||
|
|
||||||
private static ImageSize maxBitmapSize;
|
|
||||||
|
|
||||||
static {
|
|
||||||
int[] maxTextureSize = new int[1];
|
|
||||||
GLES10.glGetIntegerv(GL10.GL_MAX_TEXTURE_SIZE, maxTextureSize, 0);
|
|
||||||
int maxBitmapDimension = Math.max(maxTextureSize[0], DEFAULT_MAX_BITMAP_DIMENSION);
|
|
||||||
maxBitmapSize = new ImageSize(maxBitmapDimension, maxBitmapDimension);
|
|
||||||
}
|
|
||||||
|
|
||||||
private ImageSizeUtils() {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Defines target size for image aware view. Size is defined by target
|
|
||||||
* {@link com.nostra13.universalimageloader.core.imageaware.ImageAware view} parameters, configuration
|
|
||||||
* parameters or device display dimensions.<br />
|
|
||||||
*/
|
|
||||||
public static ImageSize defineTargetSizeForView(ImageAware imageAware, ImageSize maxImageSize) {
|
|
||||||
int width = imageAware.getWidth();
|
|
||||||
if (width <= 0) width = maxImageSize.getWidth();
|
|
||||||
|
|
||||||
int height = imageAware.getHeight();
|
|
||||||
if (height <= 0) height = maxImageSize.getHeight();
|
|
||||||
|
|
||||||
return new ImageSize(width, height);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Computes sample size for downscaling image size (<b>srcSize</b>) to view size (<b>targetSize</b>). This sample
|
|
||||||
* size is used during
|
|
||||||
* {@linkplain BitmapFactory#decodeStream(java.io.InputStream, android.graphics.Rect, android.graphics.BitmapFactory.Options)
|
|
||||||
* decoding image} to bitmap.<br />
|
|
||||||
* <br />
|
|
||||||
* <b>Examples:</b><br />
|
|
||||||
* <p/>
|
|
||||||
* <pre>
|
|
||||||
* srcSize(100x100), targetSize(10x10), powerOf2Scale = true -> sampleSize = 8
|
|
||||||
* srcSize(100x100), targetSize(10x10), powerOf2Scale = false -> sampleSize = 10
|
|
||||||
*
|
|
||||||
* srcSize(100x100), targetSize(20x40), viewScaleType = FIT_INSIDE -> sampleSize = 5
|
|
||||||
* srcSize(100x100), targetSize(20x40), viewScaleType = CROP -> sampleSize = 2
|
|
||||||
* </pre>
|
|
||||||
* <p/>
|
|
||||||
* <br />
|
|
||||||
* The sample size is the number of pixels in either dimension that correspond to a single pixel in the decoded
|
|
||||||
* bitmap. For example, inSampleSize == 4 returns an image that is 1/4 the width/height of the original, and 1/16
|
|
||||||
* the number of pixels. Any value <= 1 is treated the same as 1.
|
|
||||||
*
|
|
||||||
* @param srcSize Original (image) size
|
|
||||||
* @param targetSize Target (view) size
|
|
||||||
* @param viewScaleType {@linkplain ViewScaleType Scale type} for placing image in view
|
|
||||||
* @param powerOf2Scale <i>true</i> - if sample size be a power of 2 (1, 2, 4, 8, ...)
|
|
||||||
* @return Computed sample size
|
|
||||||
*/
|
|
||||||
public static int computeImageSampleSize(ImageSize srcSize, ImageSize targetSize, ViewScaleType viewScaleType,
|
|
||||||
boolean powerOf2Scale) {
|
|
||||||
final int srcWidth = srcSize.getWidth();
|
|
||||||
final int srcHeight = srcSize.getHeight();
|
|
||||||
final int targetWidth = targetSize.getWidth();
|
|
||||||
final int targetHeight = targetSize.getHeight();
|
|
||||||
|
|
||||||
int scale = 1;
|
|
||||||
|
|
||||||
switch (viewScaleType) {
|
|
||||||
case FIT_INSIDE:
|
|
||||||
if (powerOf2Scale) {
|
|
||||||
final int halfWidth = srcWidth / 2;
|
|
||||||
final int halfHeight = srcHeight / 2;
|
|
||||||
while ((halfWidth / scale) > targetWidth || (halfHeight / scale) > targetHeight) { // ||
|
|
||||||
scale *= 2;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
scale = Math.max(srcWidth / targetWidth, srcHeight / targetHeight); // max
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case CROP:
|
|
||||||
if (powerOf2Scale) {
|
|
||||||
final int halfWidth = srcWidth / 2;
|
|
||||||
final int halfHeight = srcHeight / 2;
|
|
||||||
while ((halfWidth / scale) > targetWidth && (halfHeight / scale) > targetHeight) { // &&
|
|
||||||
scale *= 2;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
scale = Math.min(srcWidth / targetWidth, srcHeight / targetHeight); // min
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (scale < 1) {
|
|
||||||
scale = 1;
|
|
||||||
}
|
|
||||||
scale = considerMaxTextureSize(srcWidth, srcHeight, scale, powerOf2Scale);
|
|
||||||
|
|
||||||
return scale;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int considerMaxTextureSize(int srcWidth, int srcHeight, int scale, boolean powerOf2) {
|
|
||||||
final int maxWidth = maxBitmapSize.getWidth();
|
|
||||||
final int maxHeight = maxBitmapSize.getHeight();
|
|
||||||
while ((srcWidth / scale) > maxWidth || (srcHeight / scale) > maxHeight) {
|
|
||||||
if (powerOf2) {
|
|
||||||
scale *= 2;
|
|
||||||
} else {
|
|
||||||
scale++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return scale;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Computes minimal sample size for downscaling image so result image size won't exceed max acceptable OpenGL
|
|
||||||
* texture size.<br />
|
|
||||||
* We can't create Bitmap in memory with size exceed max texture size (usually this is 2048x2048) so this method
|
|
||||||
* calculate minimal sample size which should be applied to image to fit into these limits.
|
|
||||||
*
|
|
||||||
* @param srcSize Original image size
|
|
||||||
* @return Minimal sample size
|
|
||||||
*/
|
|
||||||
public static int computeMinImageSampleSize(ImageSize srcSize) {
|
|
||||||
final int srcWidth = srcSize.getWidth();
|
|
||||||
final int srcHeight = srcSize.getHeight();
|
|
||||||
final int targetWidth = maxBitmapSize.getWidth();
|
|
||||||
final int targetHeight = maxBitmapSize.getHeight();
|
|
||||||
|
|
||||||
final int widthScale = (int) Math.ceil((float) srcWidth / targetWidth);
|
|
||||||
final int heightScale = (int) Math.ceil((float) srcHeight / targetHeight);
|
|
||||||
|
|
||||||
return Math.max(widthScale, heightScale); // max
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Computes scale of target size (<b>targetSize</b>) to source size (<b>srcSize</b>).<br />
|
|
||||||
* <br />
|
|
||||||
* <b>Examples:</b><br />
|
|
||||||
* <p/>
|
|
||||||
* <pre>
|
|
||||||
* srcSize(40x40), targetSize(10x10) -> scale = 0.25
|
|
||||||
*
|
|
||||||
* srcSize(10x10), targetSize(20x20), stretch = false -> scale = 1
|
|
||||||
* srcSize(10x10), targetSize(20x20), stretch = true -> scale = 2
|
|
||||||
*
|
|
||||||
* srcSize(100x100), targetSize(20x40), viewScaleType = FIT_INSIDE -> scale = 0.2
|
|
||||||
* srcSize(100x100), targetSize(20x40), viewScaleType = CROP -> scale = 0.4
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* @param srcSize Source (image) size
|
|
||||||
* @param targetSize Target (view) size
|
|
||||||
* @param viewScaleType {@linkplain ViewScaleType Scale type} for placing image in view
|
|
||||||
* @param stretch Whether source size should be stretched if target size is larger than source size. If <b>false</b>
|
|
||||||
* then result scale value can't be greater than 1.
|
|
||||||
* @return Computed scale
|
|
||||||
*/
|
|
||||||
public static float computeImageScale(ImageSize srcSize, ImageSize targetSize, ViewScaleType viewScaleType,
|
|
||||||
boolean stretch) {
|
|
||||||
final int srcWidth = srcSize.getWidth();
|
|
||||||
final int srcHeight = srcSize.getHeight();
|
|
||||||
final int targetWidth = targetSize.getWidth();
|
|
||||||
final int targetHeight = targetSize.getHeight();
|
|
||||||
|
|
||||||
final float widthScale = (float) srcWidth / targetWidth;
|
|
||||||
final float heightScale = (float) srcHeight / targetHeight;
|
|
||||||
|
|
||||||
final int destWidth;
|
|
||||||
final int destHeight;
|
|
||||||
if ((viewScaleType == ViewScaleType.FIT_INSIDE && widthScale >= heightScale) || (viewScaleType == ViewScaleType.CROP && widthScale < heightScale)) {
|
|
||||||
destWidth = targetWidth;
|
|
||||||
destHeight = (int) (srcHeight / widthScale);
|
|
||||||
} else {
|
|
||||||
destWidth = (int) (srcWidth / heightScale);
|
|
||||||
destHeight = targetHeight;
|
|
||||||
}
|
|
||||||
|
|
||||||
float scale = 1;
|
|
||||||
if ((!stretch && destWidth < srcWidth && destHeight < srcHeight) || (stretch && destWidth != srcWidth && destHeight != srcHeight)) {
|
|
||||||
scale = (float) destWidth / srcWidth;
|
|
||||||
}
|
|
||||||
|
|
||||||
return scale;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,131 +0,0 @@
|
|||||||
/*******************************************************************************
|
|
||||||
* Copyright 2011-2014 Sergey Tarasevich
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*******************************************************************************/
|
|
||||||
package com.nostra13.universalimageloader.utils;
|
|
||||||
|
|
||||||
import java.io.Closeable;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Provides I/O operations
|
|
||||||
*
|
|
||||||
* @author Sergey Tarasevich (nostra13[at]gmail[dot]com)
|
|
||||||
* @since 1.0.0
|
|
||||||
*/
|
|
||||||
public final class IoUtils {
|
|
||||||
|
|
||||||
/** {@value} */
|
|
||||||
public static final int DEFAULT_BUFFER_SIZE = 32 * 1024; // 32 KB
|
|
||||||
/** {@value} */
|
|
||||||
public static final int DEFAULT_IMAGE_TOTAL_SIZE = 500 * 1024; // 500 Kb
|
|
||||||
/** {@value} */
|
|
||||||
public static final int CONTINUE_LOADING_PERCENTAGE = 75;
|
|
||||||
|
|
||||||
private IoUtils() {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Copies stream, fires progress events by listener, can be interrupted by listener. Uses buffer size =
|
|
||||||
* {@value #DEFAULT_BUFFER_SIZE} bytes.
|
|
||||||
*
|
|
||||||
* @param is Input stream
|
|
||||||
* @param os Output stream
|
|
||||||
* @param listener null-ok; Listener of copying progress and controller of copying interrupting
|
|
||||||
* @return <b>true</b> - if stream copied successfully; <b>false</b> - if copying was interrupted by listener
|
|
||||||
* @throws IOException
|
|
||||||
*/
|
|
||||||
public static boolean copyStream(InputStream is, OutputStream os, CopyListener listener) throws IOException {
|
|
||||||
return copyStream(is, os, listener, DEFAULT_BUFFER_SIZE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Copies stream, fires progress events by listener, can be interrupted by listener.
|
|
||||||
*
|
|
||||||
* @param is Input stream
|
|
||||||
* @param os Output stream
|
|
||||||
* @param listener null-ok; Listener of copying progress and controller of copying interrupting
|
|
||||||
* @param bufferSize Buffer size for copying, also represents a step for firing progress listener callback, i.e.
|
|
||||||
* progress event will be fired after every copied <b>bufferSize</b> bytes
|
|
||||||
* @return <b>true</b> - if stream copied successfully; <b>false</b> - if copying was interrupted by listener
|
|
||||||
* @throws IOException
|
|
||||||
*/
|
|
||||||
public static boolean copyStream(InputStream is, OutputStream os, CopyListener listener, int bufferSize)
|
|
||||||
throws IOException {
|
|
||||||
int current = 0;
|
|
||||||
int total = is.available();
|
|
||||||
if (total <= 0) {
|
|
||||||
total = DEFAULT_IMAGE_TOTAL_SIZE;
|
|
||||||
}
|
|
||||||
|
|
||||||
final byte[] bytes = new byte[bufferSize];
|
|
||||||
int count;
|
|
||||||
if (shouldStopLoading(listener, current, total)) return false;
|
|
||||||
while ((count = is.read(bytes, 0, bufferSize)) != -1) {
|
|
||||||
os.write(bytes, 0, count);
|
|
||||||
current += count;
|
|
||||||
if (shouldStopLoading(listener, current, total)) return false;
|
|
||||||
}
|
|
||||||
os.flush();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean shouldStopLoading(CopyListener listener, int current, int total) {
|
|
||||||
if (listener != null) {
|
|
||||||
boolean shouldContinue = listener.onBytesCopied(current, total);
|
|
||||||
if (!shouldContinue) {
|
|
||||||
if (100 * current / total < CONTINUE_LOADING_PERCENTAGE) {
|
|
||||||
return true; // if loaded more than 75% then continue loading anyway
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reads all data from stream and close it silently
|
|
||||||
*
|
|
||||||
* @param is Input stream
|
|
||||||
*/
|
|
||||||
public static void readAndCloseStream(InputStream is) {
|
|
||||||
final byte[] bytes = new byte[DEFAULT_BUFFER_SIZE];
|
|
||||||
try {
|
|
||||||
while (is.read(bytes, 0, DEFAULT_BUFFER_SIZE) != -1);
|
|
||||||
} catch (IOException ignored) {
|
|
||||||
} finally {
|
|
||||||
closeSilently(is);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void closeSilently(Closeable closeable) {
|
|
||||||
if (closeable != null) {
|
|
||||||
try {
|
|
||||||
closeable.close();
|
|
||||||
} catch (Exception ignored) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Listener and controller for copy process */
|
|
||||||
public static interface CopyListener {
|
|
||||||
/**
|
|
||||||
* @param current Loaded bytes
|
|
||||||
* @param total Total bytes for loading
|
|
||||||
* @return <b>true</b> - if copying should be continued; <b>false</b> - if copying should be interrupted
|
|
||||||
*/
|
|
||||||
boolean onBytesCopied(int current, int total);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,113 +0,0 @@
|
|||||||
/*******************************************************************************
|
|
||||||
* Copyright 2011-2014 Sergey Tarasevich
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*******************************************************************************/
|
|
||||||
package com.nostra13.universalimageloader.utils;
|
|
||||||
|
|
||||||
import android.util.Log;
|
|
||||||
import com.nostra13.universalimageloader.core.ImageLoader;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* "Less-word" analog of Android {@link android.util.Log logger}
|
|
||||||
*
|
|
||||||
* @author Sergey Tarasevich (nostra13[at]gmail[dot]com)
|
|
||||||
* @since 1.6.4
|
|
||||||
*/
|
|
||||||
public final class L {
|
|
||||||
|
|
||||||
private static final String LOG_FORMAT = "%1$s\n%2$s";
|
|
||||||
private static volatile boolean writeDebugLogs = false;
|
|
||||||
private static volatile boolean writeLogs = true;
|
|
||||||
|
|
||||||
private L() {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Enables logger (if {@link #disableLogging()} was called before)
|
|
||||||
*
|
|
||||||
* @deprecated Use {@link #writeLogs(boolean) writeLogs(true)} instead
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public static void enableLogging() {
|
|
||||||
writeLogs(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Disables logger, no logs will be passed to LogCat, all log methods will do nothing
|
|
||||||
*
|
|
||||||
* @deprecated Use {@link #writeLogs(boolean) writeLogs(false)} instead
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public static void disableLogging() {
|
|
||||||
writeLogs(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Enables/disables detail logging of {@link ImageLoader} work.
|
|
||||||
* Consider {@link com.nostra13.universalimageloader.utils.L#disableLogging()} to disable
|
|
||||||
* ImageLoader logging completely (even error logs)<br />
|
|
||||||
* Debug logs are disabled by default.
|
|
||||||
*/
|
|
||||||
public static void writeDebugLogs(boolean writeDebugLogs) {
|
|
||||||
L.writeDebugLogs = writeDebugLogs;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Enables/disables logging of {@link ImageLoader} completely (even error logs). */
|
|
||||||
public static void writeLogs(boolean writeLogs) {
|
|
||||||
L.writeLogs = writeLogs;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void d(String message, Object... args) {
|
|
||||||
if (writeDebugLogs) {
|
|
||||||
log(Log.DEBUG, null, message, args);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void i(String message, Object... args) {
|
|
||||||
log(Log.INFO, null, message, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void w(String message, Object... args) {
|
|
||||||
log(Log.WARN, null, message, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void e(Throwable ex) {
|
|
||||||
log(Log.ERROR, ex, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void e(String message, Object... args) {
|
|
||||||
log(Log.ERROR, null, message, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void e(Throwable ex, String message, Object... args) {
|
|
||||||
log(Log.ERROR, ex, message, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void log(int priority, Throwable ex, String message, Object... args) {
|
|
||||||
if (!writeLogs) return;
|
|
||||||
if (args.length > 0) {
|
|
||||||
message = String.format(message, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
String log;
|
|
||||||
if (ex == null) {
|
|
||||||
log = message;
|
|
||||||
} else {
|
|
||||||
String logMessage = message == null ? ex.getMessage() : message;
|
|
||||||
String logBody = Log.getStackTraceString(ex);
|
|
||||||
log = String.format(LOG_FORMAT, logMessage, logBody);
|
|
||||||
}
|
|
||||||
Log.println(priority, ImageLoader.TAG, log);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,110 +0,0 @@
|
|||||||
/*******************************************************************************
|
|
||||||
* Copyright 2011-2014 Sergey Tarasevich
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*******************************************************************************/
|
|
||||||
package com.nostra13.universalimageloader.utils;
|
|
||||||
|
|
||||||
import android.graphics.Bitmap;
|
|
||||||
|
|
||||||
import com.nostra13.universalimageloader.cache.memory.MemoryCache;
|
|
||||||
import com.nostra13.universalimageloader.core.ImageLoaderConfiguration;
|
|
||||||
import com.nostra13.universalimageloader.core.assist.ImageSize;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Comparator;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Utility for generating of keys for memory cache, key comparing and other work with memory cache
|
|
||||||
*
|
|
||||||
* @author Sergey Tarasevich (nostra13[at]gmail[dot]com)
|
|
||||||
* @since 1.6.3
|
|
||||||
*/
|
|
||||||
public final class MemoryCacheUtils {
|
|
||||||
|
|
||||||
private static final String URI_AND_SIZE_SEPARATOR = "_";
|
|
||||||
private static final String WIDTH_AND_HEIGHT_SEPARATOR = "x";
|
|
||||||
|
|
||||||
private MemoryCacheUtils() {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generates key for memory cache for incoming image (URI + size).<br />
|
|
||||||
* Pattern for cache key - <b>[imageUri]_[width]x[height]</b>.
|
|
||||||
*/
|
|
||||||
public static String generateKey(String imageUri, ImageSize targetSize) {
|
|
||||||
return new StringBuilder(imageUri).append(URI_AND_SIZE_SEPARATOR).append(targetSize.getWidth()).append(WIDTH_AND_HEIGHT_SEPARATOR).append(targetSize.getHeight()).toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Comparator<String> createFuzzyKeyComparator() {
|
|
||||||
return new Comparator<String>() {
|
|
||||||
@Override
|
|
||||||
public int compare(String key1, String key2) {
|
|
||||||
String imageUri1 = key1.substring(0, key1.lastIndexOf(URI_AND_SIZE_SEPARATOR));
|
|
||||||
String imageUri2 = key2.substring(0, key2.lastIndexOf(URI_AND_SIZE_SEPARATOR));
|
|
||||||
return imageUri1.compareTo(imageUri2);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Searches all bitmaps in memory cache which are corresponded to incoming URI.<br />
|
|
||||||
* <b>Note:</b> Memory cache can contain multiple sizes of the same image if only you didn't set
|
|
||||||
* {@link ImageLoaderConfiguration.Builder#denyCacheImageMultipleSizesInMemory()
|
|
||||||
* denyCacheImageMultipleSizesInMemory()} option in {@linkplain ImageLoaderConfiguration configuration}
|
|
||||||
*/
|
|
||||||
public static List<Bitmap> findCachedBitmapsForImageUri(String imageUri, MemoryCache memoryCache) {
|
|
||||||
List<Bitmap> values = new ArrayList<Bitmap>();
|
|
||||||
for (String key : memoryCache.keys()) {
|
|
||||||
if (key.startsWith(imageUri)) {
|
|
||||||
values.add(memoryCache.get(key));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return values;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Searches all keys in memory cache which are corresponded to incoming URI.<br />
|
|
||||||
* <b>Note:</b> Memory cache can contain multiple sizes of the same image if only you didn't set
|
|
||||||
* {@link ImageLoaderConfiguration.Builder#denyCacheImageMultipleSizesInMemory()
|
|
||||||
* denyCacheImageMultipleSizesInMemory()} option in {@linkplain ImageLoaderConfiguration configuration}
|
|
||||||
*/
|
|
||||||
public static List<String> findCacheKeysForImageUri(String imageUri, MemoryCache memoryCache) {
|
|
||||||
List<String> values = new ArrayList<String>();
|
|
||||||
for (String key : memoryCache.keys()) {
|
|
||||||
if (key.startsWith(imageUri)) {
|
|
||||||
values.add(key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return values;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes from memory cache all images for incoming URI.<br />
|
|
||||||
* <b>Note:</b> Memory cache can contain multiple sizes of the same image if only you didn't set
|
|
||||||
* {@link ImageLoaderConfiguration.Builder#denyCacheImageMultipleSizesInMemory()
|
|
||||||
* denyCacheImageMultipleSizesInMemory()} option in {@linkplain ImageLoaderConfiguration configuration}
|
|
||||||
*/
|
|
||||||
public static void removeFromCache(String imageUri, MemoryCache memoryCache) {
|
|
||||||
List<String> keysToRemove = new ArrayList<String>();
|
|
||||||
for (String key : memoryCache.keys()) {
|
|
||||||
if (key.startsWith(imageUri)) {
|
|
||||||
keysToRemove.add(key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (String keyToRemove : keysToRemove) {
|
|
||||||
memoryCache.remove(keyToRemove);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,181 +0,0 @@
|
|||||||
/*******************************************************************************
|
|
||||||
* Copyright 2011-2014 Sergey Tarasevich
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*******************************************************************************/
|
|
||||||
package com.nostra13.universalimageloader.utils;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.pm.PackageManager;
|
|
||||||
import android.os.Environment;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import static android.os.Environment.MEDIA_MOUNTED;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Provides application storage paths
|
|
||||||
*
|
|
||||||
* @author Sergey Tarasevich (nostra13[at]gmail[dot]com)
|
|
||||||
* @since 1.0.0
|
|
||||||
*/
|
|
||||||
public final class StorageUtils {
|
|
||||||
|
|
||||||
private static final String EXTERNAL_STORAGE_PERMISSION = "android.permission.WRITE_EXTERNAL_STORAGE";
|
|
||||||
private static final String INDIVIDUAL_DIR_NAME = "uil-images";
|
|
||||||
|
|
||||||
private StorageUtils() {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns application cache directory. Cache directory will be created on SD card
|
|
||||||
* <i>("/Android/data/[app_package_name]/cache")</i> if card is mounted and app has appropriate permission. Else -
|
|
||||||
* Android defines cache directory on device's file system.
|
|
||||||
*
|
|
||||||
* @param context Application context
|
|
||||||
* @return Cache {@link File directory}.<br />
|
|
||||||
* <b>NOTE:</b> Can be null in some unpredictable cases (if SD card is unmounted and
|
|
||||||
* {@link android.content.Context#getCacheDir() Context.getCacheDir()} returns null).
|
|
||||||
*/
|
|
||||||
public static File getCacheDirectory(Context context) {
|
|
||||||
return getCacheDirectory(context, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns application cache directory. Cache directory will be created on SD card
|
|
||||||
* <i>("/Android/data/[app_package_name]/cache")</i> (if card is mounted and app has appropriate permission) or
|
|
||||||
* on device's file system depending incoming parameters.
|
|
||||||
*
|
|
||||||
* @param context Application context
|
|
||||||
* @param preferExternal Whether prefer external location for cache
|
|
||||||
* @return Cache {@link File directory}.<br />
|
|
||||||
* <b>NOTE:</b> Can be null in some unpredictable cases (if SD card is unmounted and
|
|
||||||
* {@link android.content.Context#getCacheDir() Context.getCacheDir()} returns null).
|
|
||||||
*/
|
|
||||||
public static File getCacheDirectory(Context context, boolean preferExternal) {
|
|
||||||
File appCacheDir = null;
|
|
||||||
String externalStorageState;
|
|
||||||
try {
|
|
||||||
externalStorageState = Environment.getExternalStorageState();
|
|
||||||
} catch (NullPointerException e) { // (sh)it happens (Issue #660)
|
|
||||||
externalStorageState = "";
|
|
||||||
} catch (IncompatibleClassChangeError e) { // (sh)it happens too (Issue #989)
|
|
||||||
externalStorageState = "";
|
|
||||||
}
|
|
||||||
if (preferExternal && MEDIA_MOUNTED.equals(externalStorageState) && hasExternalStoragePermission(context)) {
|
|
||||||
appCacheDir = getExternalCacheDir(context);
|
|
||||||
}
|
|
||||||
if (appCacheDir == null) {
|
|
||||||
appCacheDir = context.getCacheDir();
|
|
||||||
}
|
|
||||||
if (appCacheDir == null) {
|
|
||||||
String cacheDirPath = "/data/data/" + context.getPackageName() + "/cache/";
|
|
||||||
L.w("Can't define system cache directory! '%s' will be used.", cacheDirPath);
|
|
||||||
appCacheDir = new File(cacheDirPath);
|
|
||||||
}
|
|
||||||
return appCacheDir;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns individual application cache directory (for only image caching from ImageLoader). Cache directory will be
|
|
||||||
* created on SD card <i>("/Android/data/[app_package_name]/cache/uil-images")</i> if card is mounted and app has
|
|
||||||
* appropriate permission. Else - Android defines cache directory on device's file system.
|
|
||||||
*
|
|
||||||
* @param context Application context
|
|
||||||
* @return Cache {@link File directory}
|
|
||||||
*/
|
|
||||||
public static File getIndividualCacheDirectory(Context context) {
|
|
||||||
return getIndividualCacheDirectory(context, INDIVIDUAL_DIR_NAME);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns individual application cache directory (for only image caching from ImageLoader). Cache directory will be
|
|
||||||
* created on SD card <i>("/Android/data/[app_package_name]/cache/uil-images")</i> if card is mounted and app has
|
|
||||||
* appropriate permission. Else - Android defines cache directory on device's file system.
|
|
||||||
*
|
|
||||||
* @param context Application context
|
|
||||||
* @param cacheDir Cache directory path (e.g.: "AppCacheDir", "AppDir/cache/images")
|
|
||||||
* @return Cache {@link File directory}
|
|
||||||
*/
|
|
||||||
public static File getIndividualCacheDirectory(Context context, String cacheDir) {
|
|
||||||
File appCacheDir = getCacheDirectory(context);
|
|
||||||
File individualCacheDir = new File(appCacheDir, cacheDir);
|
|
||||||
if (!individualCacheDir.exists()) {
|
|
||||||
if (!individualCacheDir.mkdir()) {
|
|
||||||
individualCacheDir = appCacheDir;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return individualCacheDir;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns specified application cache directory. Cache directory will be created on SD card by defined path if card
|
|
||||||
* is mounted and app has appropriate permission. Else - Android defines cache directory on device's file system.
|
|
||||||
*
|
|
||||||
* @param context Application context
|
|
||||||
* @param cacheDir Cache directory path (e.g.: "AppCacheDir", "AppDir/cache/images")
|
|
||||||
* @return Cache {@link File directory}
|
|
||||||
*/
|
|
||||||
public static File getOwnCacheDirectory(Context context, String cacheDir) {
|
|
||||||
File appCacheDir = null;
|
|
||||||
if (MEDIA_MOUNTED.equals(Environment.getExternalStorageState()) && hasExternalStoragePermission(context)) {
|
|
||||||
appCacheDir = new File(Environment.getExternalStorageDirectory(), cacheDir);
|
|
||||||
}
|
|
||||||
if (appCacheDir == null || (!appCacheDir.exists() && !appCacheDir.mkdirs())) {
|
|
||||||
appCacheDir = context.getCacheDir();
|
|
||||||
}
|
|
||||||
return appCacheDir;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns specified application cache directory. Cache directory will be created on SD card by defined path if card
|
|
||||||
* is mounted and app has appropriate permission. Else - Android defines cache directory on device's file system.
|
|
||||||
*
|
|
||||||
* @param context Application context
|
|
||||||
* @param cacheDir Cache directory path (e.g.: "AppCacheDir", "AppDir/cache/images")
|
|
||||||
* @return Cache {@link File directory}
|
|
||||||
*/
|
|
||||||
public static File getOwnCacheDirectory(Context context, String cacheDir, boolean preferExternal) {
|
|
||||||
File appCacheDir = null;
|
|
||||||
if (preferExternal && MEDIA_MOUNTED.equals(Environment.getExternalStorageState()) && hasExternalStoragePermission(context)) {
|
|
||||||
appCacheDir = new File(Environment.getExternalStorageDirectory(), cacheDir);
|
|
||||||
}
|
|
||||||
if (appCacheDir == null || (!appCacheDir.exists() && !appCacheDir.mkdirs())) {
|
|
||||||
appCacheDir = context.getCacheDir();
|
|
||||||
}
|
|
||||||
return appCacheDir;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static File getExternalCacheDir(Context context) {
|
|
||||||
File dataDir = new File(new File(Environment.getExternalStorageDirectory(), "Android"), "data");
|
|
||||||
File appCacheDir = new File(new File(dataDir, context.getPackageName()), "cache");
|
|
||||||
if (!appCacheDir.exists()) {
|
|
||||||
if (!appCacheDir.mkdirs()) {
|
|
||||||
L.w("Unable to create external cache directory");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
new File(appCacheDir, ".nomedia").createNewFile();
|
|
||||||
} catch (IOException e) {
|
|
||||||
L.i("Can't create \".nomedia\" file in application external cache directory");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return appCacheDir;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean hasExternalStoragePermission(Context context) {
|
|
||||||
int perm = context.checkCallingOrSelfPermission(EXTERNAL_STORAGE_PERMISSION);
|
|
||||||
return perm == PackageManager.PERMISSION_GRANTED;
|
|
||||||
}
|
|
||||||
}
|
|
1
extern/UniversalImageLoader/settings.gradle
vendored
1
extern/UniversalImageLoader/settings.gradle
vendored
@ -1 +0,0 @@
|
|||||||
include ':library'
|
|
177
extern/libsuperuser/LICENSE
vendored
177
extern/libsuperuser/LICENSE
vendored
@ -1,177 +0,0 @@
|
|||||||
|
|
||||||
Apache License
|
|
||||||
Version 2.0, January 2004
|
|
||||||
http://www.apache.org/licenses/
|
|
||||||
|
|
||||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
||||||
|
|
||||||
1. Definitions.
|
|
||||||
|
|
||||||
"License" shall mean the terms and conditions for use, reproduction,
|
|
||||||
and distribution as defined by Sections 1 through 9 of this document.
|
|
||||||
|
|
||||||
"Licensor" shall mean the copyright owner or entity authorized by
|
|
||||||
the copyright owner that is granting the License.
|
|
||||||
|
|
||||||
"Legal Entity" shall mean the union of the acting entity and all
|
|
||||||
other entities that control, are controlled by, or are under common
|
|
||||||
control with that entity. For the purposes of this definition,
|
|
||||||
"control" means (i) the power, direct or indirect, to cause the
|
|
||||||
direction or management of such entity, whether by contract or
|
|
||||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
||||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
||||||
|
|
||||||
"You" (or "Your") shall mean an individual or Legal Entity
|
|
||||||
exercising permissions granted by this License.
|
|
||||||
|
|
||||||
"Source" form shall mean the preferred form for making modifications,
|
|
||||||
including but not limited to software source code, documentation
|
|
||||||
source, and configuration files.
|
|
||||||
|
|
||||||
"Object" form shall mean any form resulting from mechanical
|
|
||||||
transformation or translation of a Source form, including but
|
|
||||||
not limited to compiled object code, generated documentation,
|
|
||||||
and conversions to other media types.
|
|
||||||
|
|
||||||
"Work" shall mean the work of authorship, whether in Source or
|
|
||||||
Object form, made available under the License, as indicated by a
|
|
||||||
copyright notice that is included in or attached to the work
|
|
||||||
(an example is provided in the Appendix below).
|
|
||||||
|
|
||||||
"Derivative Works" shall mean any work, whether in Source or Object
|
|
||||||
form, that is based on (or derived from) the Work and for which the
|
|
||||||
editorial revisions, annotations, elaborations, or other modifications
|
|
||||||
represent, as a whole, an original work of authorship. For the purposes
|
|
||||||
of this License, Derivative Works shall not include works that remain
|
|
||||||
separable from, or merely link (or bind by name) to the interfaces of,
|
|
||||||
the Work and Derivative Works thereof.
|
|
||||||
|
|
||||||
"Contribution" shall mean any work of authorship, including
|
|
||||||
the original version of the Work and any modifications or additions
|
|
||||||
to that Work or Derivative Works thereof, that is intentionally
|
|
||||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
||||||
or by an individual or Legal Entity authorized to submit on behalf of
|
|
||||||
the copyright owner. For the purposes of this definition, "submitted"
|
|
||||||
means any form of electronic, verbal, or written communication sent
|
|
||||||
to the Licensor or its representatives, including but not limited to
|
|
||||||
communication on electronic mailing lists, source code control systems,
|
|
||||||
and issue tracking systems that are managed by, or on behalf of, the
|
|
||||||
Licensor for the purpose of discussing and improving the Work, but
|
|
||||||
excluding communication that is conspicuously marked or otherwise
|
|
||||||
designated in writing by the copyright owner as "Not a Contribution."
|
|
||||||
|
|
||||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
||||||
on behalf of whom a Contribution has been received by Licensor and
|
|
||||||
subsequently incorporated within the Work.
|
|
||||||
|
|
||||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
||||||
copyright license to reproduce, prepare Derivative Works of,
|
|
||||||
publicly display, publicly perform, sublicense, and distribute the
|
|
||||||
Work and such Derivative Works in Source or Object form.
|
|
||||||
|
|
||||||
3. Grant of Patent License. Subject to the terms and conditions of
|
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
||||||
(except as stated in this section) patent license to make, have made,
|
|
||||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
||||||
where such license applies only to those patent claims licensable
|
|
||||||
by such Contributor that are necessarily infringed by their
|
|
||||||
Contribution(s) alone or by combination of their Contribution(s)
|
|
||||||
with the Work to which such Contribution(s) was submitted. If You
|
|
||||||
institute patent litigation against any entity (including a
|
|
||||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
||||||
or a Contribution incorporated within the Work constitutes direct
|
|
||||||
or contributory patent infringement, then any patent licenses
|
|
||||||
granted to You under this License for that Work shall terminate
|
|
||||||
as of the date such litigation is filed.
|
|
||||||
|
|
||||||
4. Redistribution. You may reproduce and distribute copies of the
|
|
||||||
Work or Derivative Works thereof in any medium, with or without
|
|
||||||
modifications, and in Source or Object form, provided that You
|
|
||||||
meet the following conditions:
|
|
||||||
|
|
||||||
(a) You must give any other recipients of the Work or
|
|
||||||
Derivative Works a copy of this License; and
|
|
||||||
|
|
||||||
(b) You must cause any modified files to carry prominent notices
|
|
||||||
stating that You changed the files; and
|
|
||||||
|
|
||||||
(c) You must retain, in the Source form of any Derivative Works
|
|
||||||
that You distribute, all copyright, patent, trademark, and
|
|
||||||
attribution notices from the Source form of the Work,
|
|
||||||
excluding those notices that do not pertain to any part of
|
|
||||||
the Derivative Works; and
|
|
||||||
|
|
||||||
(d) If the Work includes a "NOTICE" text file as part of its
|
|
||||||
distribution, then any Derivative Works that You distribute must
|
|
||||||
include a readable copy of the attribution notices contained
|
|
||||||
within such NOTICE file, excluding those notices that do not
|
|
||||||
pertain to any part of the Derivative Works, in at least one
|
|
||||||
of the following places: within a NOTICE text file distributed
|
|
||||||
as part of the Derivative Works; within the Source form or
|
|
||||||
documentation, if provided along with the Derivative Works; or,
|
|
||||||
within a display generated by the Derivative Works, if and
|
|
||||||
wherever such third-party notices normally appear. The contents
|
|
||||||
of the NOTICE file are for informational purposes only and
|
|
||||||
do not modify the License. You may add Your own attribution
|
|
||||||
notices within Derivative Works that You distribute, alongside
|
|
||||||
or as an addendum to the NOTICE text from the Work, provided
|
|
||||||
that such additional attribution notices cannot be construed
|
|
||||||
as modifying the License.
|
|
||||||
|
|
||||||
You may add Your own copyright statement to Your modifications and
|
|
||||||
may provide additional or different license terms and conditions
|
|
||||||
for use, reproduction, or distribution of Your modifications, or
|
|
||||||
for any such Derivative Works as a whole, provided Your use,
|
|
||||||
reproduction, and distribution of the Work otherwise complies with
|
|
||||||
the conditions stated in this License.
|
|
||||||
|
|
||||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
||||||
any Contribution intentionally submitted for inclusion in the Work
|
|
||||||
by You to the Licensor shall be under the terms and conditions of
|
|
||||||
this License, without any additional terms or conditions.
|
|
||||||
Notwithstanding the above, nothing herein shall supersede or modify
|
|
||||||
the terms of any separate license agreement you may have executed
|
|
||||||
with Licensor regarding such Contributions.
|
|
||||||
|
|
||||||
6. Trademarks. This License does not grant permission to use the trade
|
|
||||||
names, trademarks, service marks, or product names of the Licensor,
|
|
||||||
except as required for reasonable and customary use in describing the
|
|
||||||
origin of the Work and reproducing the content of the NOTICE file.
|
|
||||||
|
|
||||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
||||||
agreed to in writing, Licensor provides the Work (and each
|
|
||||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
||||||
implied, including, without limitation, any warranties or conditions
|
|
||||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
||||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
||||||
appropriateness of using or redistributing the Work and assume any
|
|
||||||
risks associated with Your exercise of permissions under this License.
|
|
||||||
|
|
||||||
8. Limitation of Liability. In no event and under no legal theory,
|
|
||||||
whether in tort (including negligence), contract, or otherwise,
|
|
||||||
unless required by applicable law (such as deliberate and grossly
|
|
||||||
negligent acts) or agreed to in writing, shall any Contributor be
|
|
||||||
liable to You for damages, including any direct, indirect, special,
|
|
||||||
incidental, or consequential damages of any character arising as a
|
|
||||||
result of this License or out of the use or inability to use the
|
|
||||||
Work (including but not limited to damages for loss of goodwill,
|
|
||||||
work stoppage, computer failure or malfunction, or any and all
|
|
||||||
other commercial damages or losses), even if such Contributor
|
|
||||||
has been advised of the possibility of such damages.
|
|
||||||
|
|
||||||
9. Accepting Warranty or Additional Liability. While redistributing
|
|
||||||
the Work or Derivative Works thereof, You may choose to offer,
|
|
||||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
||||||
or other liability obligations and/or rights consistent with this
|
|
||||||
License. However, in accepting such obligations, You may act only
|
|
||||||
on Your own behalf and on Your sole responsibility, not on behalf
|
|
||||||
of any other Contributor, and only if You agree to indemnify,
|
|
||||||
defend, and hold each Contributor harmless for any liability
|
|
||||||
incurred by, or claims asserted against, such Contributor by reason
|
|
||||||
of your accepting any such warranty or additional liability.
|
|
||||||
|
|
||||||
END OF TERMS AND CONDITIONS
|
|
15
extern/libsuperuser/build.gradle
vendored
15
extern/libsuperuser/build.gradle
vendored
@ -1,15 +0,0 @@
|
|||||||
buildscript {
|
|
||||||
repositories {
|
|
||||||
jcenter()
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
classpath 'com.android.tools.build:gradle:1.0.0'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
allprojects {
|
|
||||||
repositories {
|
|
||||||
jcenter()
|
|
||||||
}
|
|
||||||
}
|
|
9
extern/libsuperuser/libsuperuser/.classpath
vendored
9
extern/libsuperuser/libsuperuser/.classpath
vendored
@ -1,9 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<classpath>
|
|
||||||
<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
|
|
||||||
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
|
|
||||||
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.DEPENDENCIES"/>
|
|
||||||
<classpathentry kind="src" path="src"/>
|
|
||||||
<classpathentry kind="src" path="gen"/>
|
|
||||||
<classpathentry kind="output" path="bin/classes"/>
|
|
||||||
</classpath>
|
|
38
extern/libsuperuser/libsuperuser/.project
vendored
38
extern/libsuperuser/libsuperuser/.project
vendored
@ -1,38 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<projectDescription>
|
|
||||||
<name>libsuperuser</name>
|
|
||||||
<comment></comment>
|
|
||||||
<projects>
|
|
||||||
</projects>
|
|
||||||
<buildSpec>
|
|
||||||
<buildCommand>
|
|
||||||
<name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name>
|
|
||||||
<arguments>
|
|
||||||
</arguments>
|
|
||||||
</buildCommand>
|
|
||||||
<buildCommand>
|
|
||||||
<name>com.android.ide.eclipse.adt.PreCompilerBuilder</name>
|
|
||||||
<arguments>
|
|
||||||
</arguments>
|
|
||||||
</buildCommand>
|
|
||||||
<buildCommand>
|
|
||||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
|
||||||
<arguments>
|
|
||||||
</arguments>
|
|
||||||
</buildCommand>
|
|
||||||
<buildCommand>
|
|
||||||
<name>com.saikoa.dexguard.eclipse.adt.ApkBuilder</name>
|
|
||||||
<arguments>
|
|
||||||
</arguments>
|
|
||||||
</buildCommand>
|
|
||||||
<buildCommand>
|
|
||||||
<name>com.android.ide.eclipse.adt.ApkBuilder</name>
|
|
||||||
<arguments>
|
|
||||||
</arguments>
|
|
||||||
</buildCommand>
|
|
||||||
</buildSpec>
|
|
||||||
<natures>
|
|
||||||
<nature>com.android.ide.eclipse.adt.AndroidNature</nature>
|
|
||||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
|
||||||
</natures>
|
|
||||||
</projectDescription>
|
|
@ -1,8 +0,0 @@
|
|||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
package="eu.chainfire.libsuperuser"
|
|
||||||
android:versionCode="1"
|
|
||||||
android:versionName="1.0">
|
|
||||||
|
|
||||||
<uses-sdk android:minSdkVersion="4" android:targetSdkVersion="21" />
|
|
||||||
</manifest>
|
|
||||||
|
|
56
extern/libsuperuser/libsuperuser/build.gradle
vendored
56
extern/libsuperuser/libsuperuser/build.gradle
vendored
@ -1,56 +0,0 @@
|
|||||||
apply plugin: 'com.android.library'
|
|
||||||
|
|
||||||
android {
|
|
||||||
compileSdkVersion 21
|
|
||||||
buildToolsVersion "23.0.1"
|
|
||||||
|
|
||||||
defaultConfig {
|
|
||||||
minSdkVersion 4
|
|
||||||
targetSdkVersion 21
|
|
||||||
}
|
|
||||||
|
|
||||||
sourceSets {
|
|
||||||
main {
|
|
||||||
manifest.srcFile 'AndroidManifest.xml'
|
|
||||||
java.srcDirs = ['src']
|
|
||||||
resources.srcDirs = ['src']
|
|
||||||
aidl.srcDirs = ['src']
|
|
||||||
renderscript.srcDirs = ['src']
|
|
||||||
res.srcDirs = ['res']
|
|
||||||
assets.srcDirs = ['assets']
|
|
||||||
}
|
|
||||||
}
|
|
||||||
compileOptions {
|
|
||||||
sourceCompatibility JavaVersion.VERSION_1_6
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
version = "1.0.0." + (new Date()).format('yyyyMMddHHmm')
|
|
||||||
group = "eu.chainfire"
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
}
|
|
||||||
|
|
||||||
task sourcesJar(type: Jar) {
|
|
||||||
from android.sourceSets.main.java.srcDirs
|
|
||||||
classifier = 'sources'
|
|
||||||
}
|
|
||||||
|
|
||||||
task javadoc(type: Javadoc) {
|
|
||||||
source = android.sourceSets.main.java.srcDirs
|
|
||||||
classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
|
|
||||||
}
|
|
||||||
|
|
||||||
task javadocJar(type: Jar, dependsOn: javadoc) {
|
|
||||||
classifier = 'javadoc'
|
|
||||||
from javadoc.destinationDir
|
|
||||||
}
|
|
||||||
|
|
||||||
artifacts {
|
|
||||||
archives javadocJar
|
|
||||||
archives sourcesJar
|
|
||||||
}
|
|
||||||
|
|
||||||
task findConventions << {
|
|
||||||
println project.getConvention()
|
|
||||||
}
|
|
@ -1,15 +0,0 @@
|
|||||||
# This file is automatically generated by Android Tools.
|
|
||||||
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
|
|
||||||
#
|
|
||||||
# This file must be checked in Version Control Systems.
|
|
||||||
#
|
|
||||||
# To customize properties used by the Ant build system edit
|
|
||||||
# "ant.properties", and override values to adapt the script to your
|
|
||||||
# project structure.
|
|
||||||
#
|
|
||||||
# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
|
|
||||||
#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
|
|
||||||
|
|
||||||
# Project target.
|
|
||||||
target=android-21
|
|
||||||
android.library=true
|
|
@ -1,80 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2012-2014 Jorrit "Chainfire" Jongma
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package eu.chainfire.libsuperuser;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.os.Handler;
|
|
||||||
import android.widget.Toast;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Base application class to extend from, solving some issues with
|
|
||||||
* toasts and AsyncTasks you are likely to run into
|
|
||||||
*/
|
|
||||||
public class Application extends android.app.Application {
|
|
||||||
/**
|
|
||||||
* Shows a toast message
|
|
||||||
*
|
|
||||||
* @param context Any context belonging to this application
|
|
||||||
* @param message The message to show
|
|
||||||
*/
|
|
||||||
public static void toast(Context context, String message) {
|
|
||||||
// this is a static method so it is easier to call,
|
|
||||||
// as the context checking and casting is done for you
|
|
||||||
|
|
||||||
if (context == null) return;
|
|
||||||
|
|
||||||
if (!(context instanceof Application)) {
|
|
||||||
context = context.getApplicationContext();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (context instanceof Application) {
|
|
||||||
final Context c = context;
|
|
||||||
final String m = message;
|
|
||||||
|
|
||||||
((Application)context).runInApplicationThread(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
Toast.makeText(c, m, Toast.LENGTH_LONG).show();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Handler mApplicationHandler = new Handler();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Run a runnable in the main application thread
|
|
||||||
*
|
|
||||||
* @param r Runnable to run
|
|
||||||
*/
|
|
||||||
public void runInApplicationThread(Runnable r) {
|
|
||||||
mApplicationHandler.post(r);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCreate() {
|
|
||||||
super.onCreate();
|
|
||||||
|
|
||||||
try {
|
|
||||||
// workaround bug in AsyncTask, can show up (for example) when you toast from a service
|
|
||||||
// this makes sure AsyncTask's internal handler is created from the right (main) thread
|
|
||||||
Class.forName("android.os.AsyncTask");
|
|
||||||
} catch (ClassNotFoundException e) {
|
|
||||||
// will never happen
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,240 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2012-2014 Jorrit "Chainfire" Jongma
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package eu.chainfire.libsuperuser;
|
|
||||||
|
|
||||||
import android.os.Looper;
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Utility class for logging and debug features that (by default) does nothing when not in debug mode
|
|
||||||
*/
|
|
||||||
public class Debug {
|
|
||||||
|
|
||||||
// ----- DEBUGGING -----
|
|
||||||
|
|
||||||
private static boolean debug = BuildConfig.DEBUG;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Enable or disable debug mode</p>
|
|
||||||
*
|
|
||||||
* <p>By default, debug mode is enabled for development
|
|
||||||
* builds and disabled for exported APKs - see
|
|
||||||
* BuildConfig.DEBUG</p>
|
|
||||||
*
|
|
||||||
* @param enable Enable debug mode ?
|
|
||||||
*/
|
|
||||||
public static void setDebug(boolean enable) {
|
|
||||||
debug = enable;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Is debug mode enabled ?</p>
|
|
||||||
*
|
|
||||||
* @return Debug mode enabled
|
|
||||||
*/
|
|
||||||
public static boolean getDebug() {
|
|
||||||
return debug;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ----- LOGGING -----
|
|
||||||
|
|
||||||
public interface OnLogListener {
|
|
||||||
void onLog(int type, String typeIndicator, String message);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final String TAG = "libsuperuser";
|
|
||||||
|
|
||||||
public static final int LOG_GENERAL = 0x0001;
|
|
||||||
public static final int LOG_COMMAND = 0x0002;
|
|
||||||
public static final int LOG_OUTPUT = 0x0004;
|
|
||||||
|
|
||||||
public static final int LOG_NONE = 0x0000;
|
|
||||||
public static final int LOG_ALL = 0xFFFF;
|
|
||||||
|
|
||||||
private static int logTypes = LOG_ALL;
|
|
||||||
|
|
||||||
private static OnLogListener logListener = null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Log a message (internal)</p>
|
|
||||||
*
|
|
||||||
* <p>Current debug and enabled logtypes decide what gets logged -
|
|
||||||
* even if a custom callback is registered</p>
|
|
||||||
*
|
|
||||||
* @param type Type of message to log
|
|
||||||
* @param typeIndicator String indicator for message type
|
|
||||||
* @param message The message to log
|
|
||||||
*/
|
|
||||||
private static void logCommon(int type, String typeIndicator, String message) {
|
|
||||||
if (debug && ((logTypes & type) == type)) {
|
|
||||||
if (logListener != null) {
|
|
||||||
logListener.onLog(type, typeIndicator, message);
|
|
||||||
} else {
|
|
||||||
Log.d(TAG, "[" + TAG + "][" + typeIndicator + "]" + (!message.startsWith("[") && !message.startsWith(" ") ? " " : "") + message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Log a "general" message</p>
|
|
||||||
*
|
|
||||||
* <p>These messages are infrequent and mostly occur at startup/shutdown or on error</p>
|
|
||||||
*
|
|
||||||
* @param message The message to log
|
|
||||||
*/
|
|
||||||
public static void log(String message) {
|
|
||||||
logCommon(LOG_GENERAL, "G", message);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Log a "per-command" message</p>
|
|
||||||
*
|
|
||||||
* <p>This could produce a lot of output if the client runs many commands in the session</p>
|
|
||||||
*
|
|
||||||
* @param message The message to log
|
|
||||||
*/
|
|
||||||
public static void logCommand(String message) {
|
|
||||||
logCommon(LOG_COMMAND, "C", message);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Log a line of stdout/stderr output</p>
|
|
||||||
*
|
|
||||||
* <p>This could produce a lot of output if the shell commands are noisy</p>
|
|
||||||
*
|
|
||||||
* @param message The message to log
|
|
||||||
*/
|
|
||||||
public static void logOutput(String message) {
|
|
||||||
logCommon(LOG_OUTPUT, "O", message);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Enable or disable logging specific types of message</p>
|
|
||||||
*
|
|
||||||
* <p>You may | (or) LOG_* constants together. Note that
|
|
||||||
* debug mode must also be enabled for actual logging to
|
|
||||||
* occur.</p>
|
|
||||||
*
|
|
||||||
* @param type LOG_* constants
|
|
||||||
* @param enable Enable or disable
|
|
||||||
*/
|
|
||||||
public static void setLogTypeEnabled(int type, boolean enable) {
|
|
||||||
if (enable) {
|
|
||||||
logTypes |= type;
|
|
||||||
} else {
|
|
||||||
logTypes &= ~type;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Is logging for specific types of messages enabled ?</p>
|
|
||||||
*
|
|
||||||
* <p>You may | (or) LOG_* constants together, to learn if
|
|
||||||
* <b>all</b> passed message types are enabled for logging. Note
|
|
||||||
* that debug mode must also be enabled for actual logging
|
|
||||||
* to occur.</p>
|
|
||||||
*
|
|
||||||
* @param type LOG_* constants
|
|
||||||
*/
|
|
||||||
public static boolean getLogTypeEnabled(int type) {
|
|
||||||
return ((logTypes & type) == type);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Is logging for specific types of messages enabled ?</p>
|
|
||||||
*
|
|
||||||
* <p>You may | (or) LOG_* constants together, to learn if
|
|
||||||
* <b>all</b> message types are enabled for logging. Takes
|
|
||||||
* debug mode into account for the result.</p>
|
|
||||||
*
|
|
||||||
* @param type LOG_* constants
|
|
||||||
*/
|
|
||||||
public static boolean getLogTypeEnabledEffective(int type) {
|
|
||||||
return getDebug() && getLogTypeEnabled(type);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Register a custom log handler</p>
|
|
||||||
*
|
|
||||||
* <p>Replaces the log method (write to logcat) with your own
|
|
||||||
* handler. Whether your handler gets called is still dependent
|
|
||||||
* on debug mode and message types being enabled for logging.</p>
|
|
||||||
*
|
|
||||||
* @param onLogListener Custom log listener or NULL to revert to default
|
|
||||||
*/
|
|
||||||
public static void setOnLogListener(OnLogListener onLogListener) {
|
|
||||||
logListener = onLogListener;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Get the currently registered custom log handler</p>
|
|
||||||
*
|
|
||||||
* @return Current custom log handler or NULL if none is present
|
|
||||||
*/
|
|
||||||
public static OnLogListener getOnLogListener() {
|
|
||||||
return logListener;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ----- SANITY CHECKS -----
|
|
||||||
|
|
||||||
private static boolean sanityChecks = true;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Enable or disable sanity checks</p>
|
|
||||||
*
|
|
||||||
* <p>Enables or disables the library crashing when su is called
|
|
||||||
* from the main thread.</p>
|
|
||||||
*
|
|
||||||
* @param enable Enable or disable
|
|
||||||
*/
|
|
||||||
public static void setSanityChecksEnabled(boolean enable) {
|
|
||||||
sanityChecks = enable;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Are sanity checks enabled ?</p>
|
|
||||||
*
|
|
||||||
* <p>Note that debug mode must also be enabled for actual
|
|
||||||
* sanity checks to occur.</p>
|
|
||||||
*
|
|
||||||
* @return True if enabled
|
|
||||||
*/
|
|
||||||
public static boolean getSanityChecksEnabled() {
|
|
||||||
return sanityChecks;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Are sanity checks enabled ?</p>
|
|
||||||
*
|
|
||||||
* <p>Takes debug mode into account for the result.</p>
|
|
||||||
*
|
|
||||||
* @return True if enabled
|
|
||||||
*/
|
|
||||||
public static boolean getSanityChecksEnabledEffective() {
|
|
||||||
return getDebug() && getSanityChecksEnabled();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Are we running on the main thread ?</p>
|
|
||||||
*
|
|
||||||
* @return Running on main thread ?
|
|
||||||
*/
|
|
||||||
public static boolean onMainThread() {
|
|
||||||
return ((Looper.myLooper() != null) && (Looper.myLooper() == Looper.getMainLooper()));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,59 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2012-2014 Jorrit "Chainfire" Jongma
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package eu.chainfire.libsuperuser;
|
|
||||||
|
|
||||||
import android.content.BroadcastReceiver;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>
|
|
||||||
* Base receiver to extend to catch notifications when overlays should be
|
|
||||||
* hidden.
|
|
||||||
* </p>
|
|
||||||
* <p>
|
|
||||||
* Tapjacking protection in SuperSU prevents some dialogs from receiving user
|
|
||||||
* input when overlays are present. For security reasons this notification is
|
|
||||||
* only sent to apps that have previously been granted root access, so even if
|
|
||||||
* your app does not <em>require</em> root, you still need to <em>request</em>
|
|
||||||
* it, and the user must grant it.
|
|
||||||
* </p>
|
|
||||||
* <p>
|
|
||||||
* Note that the word overlay as used here should be interpreted as "any view or
|
|
||||||
* window possibly obscuring SuperSU dialogs".
|
|
||||||
* </p>
|
|
||||||
*/
|
|
||||||
public abstract class HideOverlaysReceiver extends BroadcastReceiver {
|
|
||||||
public static final String ACTION_HIDE_OVERLAYS = "eu.chainfire.supersu.action.HIDE_OVERLAYS";
|
|
||||||
public static final String CATEGORY_HIDE_OVERLAYS = Intent.CATEGORY_INFO;
|
|
||||||
public static final String EXTRA_HIDE_OVERLAYS = "eu.chainfire.supersu.extra.HIDE";
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final void onReceive(Context context, Intent intent) {
|
|
||||||
if (intent.hasExtra(EXTRA_HIDE_OVERLAYS)) {
|
|
||||||
onHideOverlays(intent.getBooleanExtra(EXTRA_HIDE_OVERLAYS, false));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when overlays <em>should</em> be hidden or <em>may</em> be shown
|
|
||||||
* again.
|
|
||||||
*
|
|
||||||
* @param hide Should overlays be hidden?
|
|
||||||
*/
|
|
||||||
public abstract void onHideOverlays(boolean hide);
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
@ -1,29 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2012-2014 Jorrit "Chainfire" Jongma
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package eu.chainfire.libsuperuser;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Exception class used to notify developer that a shell was not close()d
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("serial")
|
|
||||||
public class ShellNotClosedException extends RuntimeException {
|
|
||||||
public static final String EXCEPTION_NOT_CLOSED = "Application did not close() interactive shell";
|
|
||||||
|
|
||||||
public ShellNotClosedException() {
|
|
||||||
super(EXCEPTION_NOT_CLOSED);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,32 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2012-2014 Jorrit "Chainfire" Jongma
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package eu.chainfire.libsuperuser;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Exception class used to crash application when shell commands are executed
|
|
||||||
* from the main thread, and we are in debug mode.
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("serial")
|
|
||||||
public class ShellOnMainThreadException extends RuntimeException {
|
|
||||||
public static final String EXCEPTION_COMMAND = "Application attempted to run a shell command from the main thread";
|
|
||||||
public static final String EXCEPTION_NOT_IDLE = "Application attempted to wait for a non-idle shell to close on the main thread";
|
|
||||||
public static final String EXCEPTION_WAIT_IDLE = "Application attempted to wait for a shell to become idle on the main thread";
|
|
||||||
|
|
||||||
public ShellOnMainThreadException(String message) {
|
|
||||||
super(message);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,105 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2012-2014 Jorrit "Chainfire" Jongma
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package eu.chainfire.libsuperuser;
|
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Thread utility class continuously reading from an InputStream
|
|
||||||
*/
|
|
||||||
public class StreamGobbler extends Thread {
|
|
||||||
/**
|
|
||||||
* Line callback interface
|
|
||||||
*/
|
|
||||||
public interface OnLineListener {
|
|
||||||
/**
|
|
||||||
* <p>Line callback</p>
|
|
||||||
*
|
|
||||||
* <p>This callback should process the line as quickly as possible.
|
|
||||||
* Delays in this callback may pause the native process or even
|
|
||||||
* result in a deadlock</p>
|
|
||||||
*
|
|
||||||
* @param line String that was gobbled
|
|
||||||
*/
|
|
||||||
void onLine(String line);
|
|
||||||
}
|
|
||||||
|
|
||||||
private String shell = null;
|
|
||||||
private BufferedReader reader = null;
|
|
||||||
private List<String> writer = null;
|
|
||||||
private OnLineListener listener = null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>StreamGobbler constructor</p>
|
|
||||||
*
|
|
||||||
* <p>We use this class because shell STDOUT and STDERR should be read as quickly as
|
|
||||||
* possible to prevent a deadlock from occurring, or Process.waitFor() never
|
|
||||||
* returning (as the buffer is full, pausing the native process)</p>
|
|
||||||
*
|
|
||||||
* @param shell Name of the shell
|
|
||||||
* @param inputStream InputStream to read from
|
|
||||||
* @param outputList List<String> to write to, or null
|
|
||||||
*/
|
|
||||||
public StreamGobbler(String shell, InputStream inputStream, List<String> outputList) {
|
|
||||||
this.shell = shell;
|
|
||||||
reader = new BufferedReader(new InputStreamReader(inputStream));
|
|
||||||
writer = outputList;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>StreamGobbler constructor</p>
|
|
||||||
*
|
|
||||||
* <p>We use this class because shell STDOUT and STDERR should be read as quickly as
|
|
||||||
* possible to prevent a deadlock from occurring, or Process.waitFor() never
|
|
||||||
* returning (as the buffer is full, pausing the native process)</p>
|
|
||||||
*
|
|
||||||
* @param shell Name of the shell
|
|
||||||
* @param inputStream InputStream to read from
|
|
||||||
* @param onLineListener OnLineListener callback
|
|
||||||
*/
|
|
||||||
public StreamGobbler(String shell, InputStream inputStream, OnLineListener onLineListener) {
|
|
||||||
this.shell = shell;
|
|
||||||
reader = new BufferedReader(new InputStreamReader(inputStream));
|
|
||||||
listener = onLineListener;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
// keep reading the InputStream until it ends (or an error occurs)
|
|
||||||
try {
|
|
||||||
String line;
|
|
||||||
while ((line = reader.readLine()) != null) {
|
|
||||||
Debug.logOutput(String.format("[%s] %s", shell, line));
|
|
||||||
if (writer != null) writer.add(line);
|
|
||||||
if (listener != null) listener.onLine(line);
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
// reader probably closed, expected exit condition
|
|
||||||
}
|
|
||||||
|
|
||||||
// make sure our stream is closed and resources will be freed
|
|
||||||
try {
|
|
||||||
reader.close();
|
|
||||||
} catch (IOException e) {
|
|
||||||
// read already closed
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
1
extern/libsuperuser/settings.gradle
vendored
1
extern/libsuperuser/settings.gradle
vendored
@ -1 +0,0 @@
|
|||||||
include ':libsuperuser', ':libsuperuser_example'
|
|
3
extern/zxing-core/build.gradle
vendored
3
extern/zxing-core/build.gradle
vendored
@ -1,3 +0,0 @@
|
|||||||
apply plugin: 'java'
|
|
||||||
|
|
||||||
sourceCompatibility = 1.7
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user