diff --git a/.gitignore b/.gitignore
index 3c8e6349e..37dc7d784 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,9 +1,4 @@
*/bin/*
*/gen/*
*.DS_Store
-*.pyc
-
-# Prevent Git from versioning the GreenDroid library in the samples project.
-
-GDCatalog/src/greendroid/*
-GDCatalog/res/*/gd_*
\ No newline at end of file
+*.pyc
\ No newline at end of file
diff --git a/CHANGES.mdown b/CHANGES.mdown
new file mode 100644
index 000000000..92b47f14a
--- /dev/null
+++ b/CHANGES.mdown
@@ -0,0 +1,40 @@
+#GreenDroid Changes History
+
+##Changes from March 22, 2011 (version 0.11)
+
+- [CHANGE] Refactor on some GreenDroid style. Styles related to `ItemView`s are now named `@style/GreenDroid.Widget.ItemView.`
+ * This change may impact your code if you are extending GreenDroid's styles. There is no impact otherwise
+- [CHANGE] The `SegmentedBar` style has been refactored to be in accordance with other widget styles. It is now in `@style/GreenDroid.Widget`
+- [CHANGE] All XML files have been re-indented with tabs instead of spaces (used in Java files)
+- [FIXED] `ActionBar` title background has previously inherited from the `ActionBar`. As a result, using translucent backgrounds was quite hazardous.
+ * Starting for now, the `ActionBar` title has no background. The background is only given by the `ActionBar` itself.
+- [FIXED] The `ImageLoaderCallback.onImageLoadingFailed(ImageLoader loader, Throwable exception)` was sometimes called with a null `Throwable`.
+- [NEW] New `setBitmapFactoryOptions(BitmapFactory.Options)` and `setInDensity(int)` / `greendroid:inDensity` methods to `AsyncImageView`
+ * May be used to bypass the default image loading behavior. By default images loaded from the network are all considered
+ as mdpi images. Using a `BitmapFactory.Options` object with a inDensity to `DisplayMetrics.DENSITY_HIGH` will load images as hdpi images.
+- [NEW] Add of new Javadoc on some GreenDroid's classes (`AsyncImageView`, `Time`, `ImageProcessor`, etc.)
+- [NEW] Add of new `ActionBarItem.Type`. Almost 10 new icons are now available. Icons are extracted from the [Android Assets Studio][android_assets_studio] project by Roman Nurik
+- [NEW] GreenDroid now has a version number! This makes GreenDroid's versions and history tracking way easier.
+
+##Changes from March 1, 2011 (version 0.10)
+
+- [NEW] Add of a complete image loader system: `AsyncImageView` widget, `ImageLoader`, `ImageCache`, etc.
+- [FIXED] Class check issue in `GDTabActivity`
+- [NEW] `GDListActivity` does not force normal `ActionBar` mode anymore
+- [NEW] Add of a new `ActionBar.Type`: `ÀctionBar.Type.Empty`
+ * In this mode, the `ActionBar` has no "Home" button
+- [NEW] `addActionBarItem()` methods now return the newly added `ActionBarItem`
+- [NEW] `ActionBarItem` can be "tagged". This makes `ActionBarItem` click handling way easier
+- [NEW] Add of a `removeItem(ActionBarItem)` in the `ActionBar` widget
+- [NEW] Add of a new `ActionBarDrawable` class that helps the developer easily creating `Drawable`s for `ActionBar`s
+ * The `ActionBarDrawable` takes a `Drawable` and automatically fill the shape with the white or black color
+ depending on its current state. It allows you to decrease the size of your project. (GreenDroid's size
+ has also decreased thanks to this optimization)
+- [NEW] Add of a `GDMapActivity`
+ * In order to use it you have to replace GreenDroid by the new GreenDroid-GoogleAPI library.
+ GreenDroid-GoogleAPIs already integrates the GreenDroid library.
+- [NEW] Add of a new `ActionBarActivity` extra parameter: `ÀctionBarActivity.GD_ACTION_BAR_VISIBILITY`
+ * Enable `ActionBar` visibility changes from parameters passed via an `Intent`. This may be useful when using
+ a reusable `GDActivity` inside a `GDTabActivity`.
+
+[android_assets_studio]: http://j.mp/androidassetstudio
\ No newline at end of file
diff --git a/GDCatalog/AndroidManifest.xml b/GDCatalog/AndroidManifest.xml
index 2e0161ed2..3fcfeda7e 100644
--- a/GDCatalog/AndroidManifest.xml
+++ b/GDCatalog/AndroidManifest.xml
@@ -23,15 +23,16 @@
android:versionCode="1"
android:versionName="1.0">
+
+
+
+ android:name=".CatalogApplication">
-
+
@@ -39,35 +40,28 @@
-
-
+ android:name=".InfoTabActivity"
+ android:label="@string/general_info_label"/>
+
+
+
+
+
+
+ android:theme="@style/Theme.GDCatalog.TweakedItems" />
-
-
-
-
-
+
+
+
+
-
+
+
+
-
-
\ No newline at end of file
diff --git a/GDCatalog/assets/LICENSE.txt b/GDCatalog/assets/LICENSE.txt
new file mode 100644
index 000000000..b7dafce6b
--- /dev/null
+++ b/GDCatalog/assets/LICENSE.txt
@@ -0,0 +1,56 @@
+
+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:
+
+ 1. You must give any other recipients of the Work or Derivative Works a copy of this License; and
+
+ 2. You must cause any modified files to carry prominent notices stating that You changed the files; and
+
+ 3. 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
+
+ 4. 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
diff --git a/GDCatalog/default.properties b/GDCatalog/default.properties
index 1bb292689..3c8031c8f 100644
--- a/GDCatalog/default.properties
+++ b/GDCatalog/default.properties
@@ -11,4 +11,4 @@
split.density=false
# Project target.
target=android-4
-android.library.reference.1=../GreenDroid/
+android.library.reference.1=../GreenDroid
diff --git a/GDCatalog/res/color/link.xml b/GDCatalog/res/color/link.xml
new file mode 100644
index 000000000..d4f7ea0cf
--- /dev/null
+++ b/GDCatalog/res/color/link.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/GDCatalog/res/drawable-hdpi/greendroid_application_logo.png b/GDCatalog/res/drawable-hdpi/greendroid_application_logo.png
deleted file mode 100644
index 944bb5fd1..000000000
Binary files a/GDCatalog/res/drawable-hdpi/greendroid_application_logo.png and /dev/null differ
diff --git a/GDCatalog/res/drawable-hdpi/greendroid_application_logo_alt.png b/GDCatalog/res/drawable-hdpi/greendroid_application_logo_alt.png
new file mode 100644
index 000000000..de9d22867
Binary files /dev/null and b/GDCatalog/res/drawable-hdpi/greendroid_application_logo_alt.png differ
diff --git a/GDCatalog/res/drawable-hdpi/greendroid_application_logo_normal.png b/GDCatalog/res/drawable-hdpi/greendroid_application_logo_normal.png
new file mode 100644
index 000000000..39f240813
Binary files /dev/null and b/GDCatalog/res/drawable-hdpi/greendroid_application_logo_normal.png differ
diff --git a/GDCatalog/res/drawable-hdpi/greendroid_logo.png b/GDCatalog/res/drawable-hdpi/greendroid_logo.png
new file mode 100644
index 000000000..fc5cb0de1
Binary files /dev/null and b/GDCatalog/res/drawable-hdpi/greendroid_logo.png differ
diff --git a/GDCatalog/res/drawable-hdpi/ic_action_bar_info.png b/GDCatalog/res/drawable-hdpi/ic_action_bar_info.png
new file mode 100644
index 000000000..59ec7e078
Binary files /dev/null and b/GDCatalog/res/drawable-hdpi/ic_action_bar_info.png differ
diff --git a/GDCatalog/res/drawable-hdpi/greendroid_icon.png b/GDCatalog/res/drawable-hdpi/ic_gdcatalog.png
similarity index 100%
rename from GDCatalog/res/drawable-hdpi/greendroid_icon.png
rename to GDCatalog/res/drawable-hdpi/ic_gdcatalog.png
diff --git a/GDCatalog/res/drawable-hdpi/header_bg.9.png b/GDCatalog/res/drawable-hdpi/separator_bg.9.png
similarity index 100%
rename from GDCatalog/res/drawable-hdpi/header_bg.9.png
rename to GDCatalog/res/drawable-hdpi/separator_bg.9.png
diff --git a/GDCatalog/res/drawable-mdpi/greendroid_application_logo.png b/GDCatalog/res/drawable-mdpi/greendroid_application_logo.png
deleted file mode 100755
index f4ce26e7b..000000000
Binary files a/GDCatalog/res/drawable-mdpi/greendroid_application_logo.png and /dev/null differ
diff --git a/GDCatalog/res/drawable-mdpi/greendroid_application_logo_alt.png b/GDCatalog/res/drawable-mdpi/greendroid_application_logo_alt.png
new file mode 100644
index 000000000..046e350f5
Binary files /dev/null and b/GDCatalog/res/drawable-mdpi/greendroid_application_logo_alt.png differ
diff --git a/GDCatalog/res/drawable-mdpi/greendroid_application_logo_normal.png b/GDCatalog/res/drawable-mdpi/greendroid_application_logo_normal.png
new file mode 100644
index 000000000..c17623673
Binary files /dev/null and b/GDCatalog/res/drawable-mdpi/greendroid_application_logo_normal.png differ
diff --git a/GDCatalog/res/drawable-mdpi/greendroid_logo.png b/GDCatalog/res/drawable-mdpi/greendroid_logo.png
new file mode 100644
index 000000000..62bf17a87
Binary files /dev/null and b/GDCatalog/res/drawable-mdpi/greendroid_logo.png differ
diff --git a/GDCatalog/res/drawable-mdpi/ic_action_bar_info.png b/GDCatalog/res/drawable-mdpi/ic_action_bar_info.png
new file mode 100644
index 000000000..8318a3dc7
Binary files /dev/null and b/GDCatalog/res/drawable-mdpi/ic_action_bar_info.png differ
diff --git a/GDCatalog/res/drawable-mdpi/greendroid_icon.png b/GDCatalog/res/drawable-mdpi/ic_gdcatalog.png
similarity index 100%
rename from GDCatalog/res/drawable-mdpi/greendroid_icon.png
rename to GDCatalog/res/drawable-mdpi/ic_gdcatalog.png
diff --git a/GDCatalog/res/drawable-mdpi/header_bg.9.png b/GDCatalog/res/drawable-mdpi/separator_bg.9.png
similarity index 100%
rename from GDCatalog/res/drawable-mdpi/header_bg.9.png
rename to GDCatalog/res/drawable-mdpi/separator_bg.9.png
diff --git a/GreenDroid/res/drawable/gd_action_bar_home.xml b/GDCatalog/res/drawable/greendroid_application_logo.xml
similarity index 67%
rename from GreenDroid/res/drawable/gd_action_bar_home.xml
rename to GDCatalog/res/drawable/greendroid_application_logo.xml
index e744dd9bb..ac8c0a9f1 100644
--- a/GreenDroid/res/drawable/gd_action_bar_home.xml
+++ b/GDCatalog/res/drawable/greendroid_application_logo.xml
@@ -19,23 +19,16 @@
-
+
-
-
-
+ android:drawable="@drawable/greendroid_application_logo_alt" />
+
-
+ android:drawable="@drawable/greendroid_application_logo_alt" />
+
+ android:drawable="@drawable/greendroid_application_logo_normal" />
+
diff --git a/GDCatalog/res/drawable/ic_title_export.xml b/GDCatalog/res/drawable/ic_title_export.xml
index c979f55eb..ed09bb102 100644
--- a/GDCatalog/res/drawable/ic_title_export.xml
+++ b/GDCatalog/res/drawable/ic_title_export.xml
@@ -19,6 +19,7 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/GDCatalog/res/layout/image.xml b/GDCatalog/res/layout/image.xml
new file mode 100644
index 000000000..53c60b197
--- /dev/null
+++ b/GDCatalog/res/layout/image.xml
@@ -0,0 +1,71 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/GDCatalog/res/layout/image_item_view.xml b/GDCatalog/res/layout/image_item_view.xml
new file mode 100644
index 000000000..3380d7871
--- /dev/null
+++ b/GDCatalog/res/layout/image_item_view.xml
@@ -0,0 +1,42 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/GDCatalog/res/layout/info.xml b/GDCatalog/res/layout/info.xml
new file mode 100644
index 000000000..8feed95b9
--- /dev/null
+++ b/GDCatalog/res/layout/info.xml
@@ -0,0 +1,102 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/GDCatalog/res/layout/quick_action.xml b/GDCatalog/res/layout/quick_action.xml
index 10d13c4c5..8f4fc9498 100644
--- a/GDCatalog/res/layout/quick_action.xml
+++ b/GDCatalog/res/layout/quick_action.xml
@@ -24,7 +24,6 @@
android:padding="5dp">
*
* @see {@link GDApplication#getHomeActivityClass()}
- * @see {@link GDActivity#GD_ACTION_BAR_TITLE}
+ * @see {@link ActionBarActivity#GD_ACTION_BAR_TITLE}
* @see {@link GDActivity#setActionBarContentView(int)}
* @see {@link GDActivity#setActionBarContentView(View)}
* @see {@link GDActivity#setActionBarContentView(View, LayoutParams)}
@@ -141,6 +141,8 @@ public class GDActivity extends Activity implements ActionBarActivity {
switch (mActionBarType) {
case Dashboard:
return R.layout.gd_content_dashboard;
+ case Empty:
+ return R.layout.gd_content_empty;
case Normal:
default:
return R.layout.gd_content_normal;
@@ -203,6 +205,9 @@ public class GDActivity extends Activity implements ActionBarActivity {
// Do nothing
}
}
+
+ final int visibility = intent.getIntExtra(ActionBarActivity.GD_ACTION_BAR_VISIBILITY, View.VISIBLE);
+ getActionBar().setVisibility(visibility);
}
@Override
@@ -220,12 +225,20 @@ public class GDActivity extends Activity implements ActionBarActivity {
return mActionBarHost.getActionBar();
}
- public void addActionBarItem(ActionBarItem item) {
- getActionBar().addItem(item);
+ public ActionBarItem addActionBarItem(ActionBarItem item) {
+ return getActionBar().addItem(item);
+ }
+
+ public ActionBarItem addActionBarItem(ActionBarItem item, int itemId) {
+ return getActionBar().addItem(item, itemId);
+ }
+
+ public ActionBarItem addActionBarItem(ActionBarItem.Type actionBarItemType) {
+ return getActionBar().addItem(actionBarItemType);
}
- public void addActionBarItem(ActionBarItem.Type actionBarItemType) {
- getActionBar().addItem(actionBarItemType);
+ public ActionBarItem addActionBarItem(ActionBarItem.Type actionBarItemType, int itemId) {
+ return getActionBar().addItem(actionBarItemType, itemId);
}
public FrameLayout getContentView() {
diff --git a/GreenDroid/src/greendroid/app/GDApplication.java b/GreenDroid/src/greendroid/app/GDApplication.java
index 96d9b8b40..72e2aa174 100644
--- a/GreenDroid/src/greendroid/app/GDApplication.java
+++ b/GreenDroid/src/greendroid/app/GDApplication.java
@@ -15,6 +15,15 @@
*/
package greendroid.app;
+import greendroid.image.ImageCache;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.atomic.AtomicInteger;
+
import android.app.Activity;
import android.app.Application;
import android.content.Intent;
@@ -26,6 +35,51 @@ import android.content.Intent;
* @author Cyril Mottier
*/
public class GDApplication extends Application {
+
+ /**
+ * Used for receiving low memory system notification. You should definitely
+ * use it in order to clear caches and not important data everytime the
+ * system need memory.
+ *
+ * @author Cyril Mottier
+ * @see GDApplication#registerOnLowMemoryListener(OnLowMemoryListener)
+ * @see GDApplication#unregisterOnLowMemoryListener(OnLowMemoryListener)
+ */
+ public static interface OnLowMemoryListener {
+ public void onLowMemoryReceived();
+ }
+
+ private static final int CORE_POOL_SIZE = 5;
+
+ private static final ThreadFactory sThreadFactory = new ThreadFactory() {
+ private final AtomicInteger mCount = new AtomicInteger(1);
+
+ public Thread newThread(Runnable r) {
+ return new Thread(r, "GreenDroid thread #" + mCount.getAndIncrement());
+ }
+ };
+
+ private ExecutorService mExecutorService;
+ private ImageCache mImageCache;
+ private ArrayList> mLowMemoryListeners;
+
+ public GDApplication() {
+ mLowMemoryListeners = new ArrayList>();
+ }
+
+ public ExecutorService getExecutor() {
+ if (mExecutorService == null) {
+ mExecutorService = Executors.newFixedThreadPool(CORE_POOL_SIZE, sThreadFactory);
+ }
+ return mExecutorService;
+ }
+
+ public ImageCache getImageCache() {
+ if (mImageCache == null) {
+ mImageCache = new ImageCache(this);
+ }
+ return mImageCache;
+ }
/**
* Returns the class of the home {@link Activity}. The home {@link Activity}
@@ -48,4 +102,51 @@ public class GDApplication extends Application {
public Intent getMainApplicationIntent() {
return null;
}
+
+ /**
+ * Adds a new listener to the list
+ *
+ * @param listener The listener to unregister
+ * @see {@link OnLowMemoryListener}
+ */
+ public void registerOnLowMemoryListener(OnLowMemoryListener listener) {
+ if (listener != null) {
+ mLowMemoryListeners.add(new WeakReference(listener));
+ }
+ }
+
+ /**
+ * Removes a previously registered listener
+ *
+ * @param listener The listener to unregister
+ * @see {@link OnLowMemoryListener}
+ */
+ public void unregisterOnLowMemoryListener(OnLowMemoryListener listener) {
+ if (listener != null) {
+ int i = 0;
+ while (i < mLowMemoryListeners.size()) {
+ final OnLowMemoryListener l = mLowMemoryListeners.get(i).get();
+ if (l == null || l == listener) {
+ mLowMemoryListeners.remove(i);
+ } else {
+ i++;
+ }
+ }
+ }
+ }
+
+ @Override
+ public void onLowMemory() {
+ super.onLowMemory();
+ int i = 0;
+ while (i < mLowMemoryListeners.size()) {
+ final OnLowMemoryListener listener = mLowMemoryListeners.get(i).get();
+ if (listener == null) {
+ mLowMemoryListeners.remove(i);
+ } else {
+ listener.onLowMemoryReceived();
+ i++;
+ }
+ }
+ }
}
diff --git a/GreenDroid/src/greendroid/app/GDListActivity.java b/GreenDroid/src/greendroid/app/GDListActivity.java
index 59de729c1..5665a1a7d 100644
--- a/GreenDroid/src/greendroid/app/GDListActivity.java
+++ b/GreenDroid/src/greendroid/app/GDListActivity.java
@@ -16,6 +16,7 @@
package greendroid.app;
import greendroid.util.Config;
+import greendroid.widget.ActionBar;
import android.app.ListActivity;
import android.os.Handler;
import android.util.Log;
@@ -26,7 +27,6 @@ import android.widget.ListView;
import com.cyrilmottier.android.greendroid.R;
-
/**
* An equivalent to {@link ListActivity} that manages a ListView.
*
@@ -49,6 +49,14 @@ public class GDListActivity extends GDActivity {
mList.focusableViewAvailable(mList);
}
};
+
+ public GDListActivity() {
+ super();
+ }
+
+ public GDListActivity(ActionBar.Type actionBarType) {
+ super(actionBarType);
+ }
/**
* This method will be called when an item in the list is selected.
@@ -119,7 +127,16 @@ public class GDListActivity extends GDActivity {
if (Config.GD_INFO_LOGS_ENABLED) {
Log.d(LOG_TAG, "No layout specified : creating the default layout");
}
- return R.layout.gd_list_content;
+
+ switch (getActionBarType()) {
+ case Dashboard:
+ return R.layout.gd_list_content_dashboard;
+ case Empty:
+ return R.layout.gd_list_content_empty;
+ case Normal:
+ default:
+ return R.layout.gd_list_content_normal;
+ }
}
@Override
diff --git a/GreenDroid/src/greendroid/app/GDTabActivity.java b/GreenDroid/src/greendroid/app/GDTabActivity.java
index 87723aaab..52ffe8908 100644
--- a/GreenDroid/src/greendroid/app/GDTabActivity.java
+++ b/GreenDroid/src/greendroid/app/GDTabActivity.java
@@ -100,6 +100,9 @@ public class GDTabActivity extends TabActivity implements ActionBarActivity {
// Do nothing
}
}
+
+ final int visibility = intent.getIntExtra(ActionBarActivity.GD_ACTION_BAR_VISIBILITY, View.VISIBLE);
+ getActionBar().setVisibility(visibility);
}
// @Override
@@ -121,12 +124,20 @@ public class GDTabActivity extends TabActivity implements ActionBarActivity {
return mActionBarHost.getActionBar();
}
- public void addActionBarItem(ActionBarItem item) {
- getActionBar().addItem(item);
+ public ActionBarItem addActionBarItem(ActionBarItem item) {
+ return getActionBar().addItem(item);
+ }
+
+ public ActionBarItem addActionBarItem(ActionBarItem item, int itemId) {
+ return getActionBar().addItem(item, itemId);
}
- public void addActionBarItem(ActionBarItem.Type actionBarItemType) {
- getActionBar().addItem(actionBarItemType);
+ public ActionBarItem addActionBarItem(ActionBarItem.Type actionBarItemType) {
+ return getActionBar().addItem(actionBarItemType);
+ }
+
+ public ActionBarItem addActionBarItem(ActionBarItem.Type actionBarItemType, int itemId) {
+ return getActionBar().addItem(actionBarItemType, itemId);
}
public FrameLayout getContentView() {
@@ -142,7 +153,7 @@ public class GDTabActivity extends TabActivity implements ActionBarActivity {
if (position == OnActionBarListener.HOME_ITEM) {
final Class> klass = getGDApplication().getHomeActivityClass();
- if (klass != null && !klass.equals(getClass())) {
+ if (klass != null && !klass.equals(GDTabActivity.class.getClass())) {
if (Config.GD_INFO_LOGS_ENABLED) {
Log.i(LOG_TAG, "Going back to the home activity");
}
diff --git a/GreenDroid/src/greendroid/graphics/drawable/ActionBarDrawable.java b/GreenDroid/src/greendroid/graphics/drawable/ActionBarDrawable.java
new file mode 100644
index 000000000..014525dc9
--- /dev/null
+++ b/GreenDroid/src/greendroid/graphics/drawable/ActionBarDrawable.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2011 Cyril Mottier (http://www.cyrilmottier.com)
+ *
+ * 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 greendroid.graphics.drawable;
+
+import greendroid.widget.ActionBar;
+import android.content.res.Resources;
+import android.graphics.Color;
+import android.graphics.ColorFilter;
+import android.graphics.LightingColorFilter;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.StateListDrawable;
+import android.util.StateSet;
+
+/**
+ * A specialized {@link Drawable} that is dedicated to {@link ActionBarItem}s.
+ * It automatically adapts its color depending on its current state (black when
+ * pressed or focused and white otherwise). As a result, the
+ * {@link AutoColorDrawable} is a replacement {@link StateListDrawable} that
+ * should be used in {@link ActionBar}s.
+ *
+ * @author Cyril Mottier
+ */
+public class ActionBarDrawable extends BitmapDrawable {
+
+ private ColorFilter mNormalCf;
+ private ColorFilter mAltCf;
+
+ public ActionBarDrawable(Resources res, int resId) {
+ this(res, res.getDrawable(resId), Color.WHITE, Color.BLACK);
+ }
+
+ public ActionBarDrawable(Resources res, Drawable d) {
+ this(res, d, Color.WHITE, Color.BLACK);
+ }
+
+ public ActionBarDrawable(Resources res, int resId, int normalColor, int altColor) {
+ this(res, res.getDrawable(resId), normalColor, altColor);
+ }
+
+ public ActionBarDrawable(Resources res, Drawable d, int normalColor, int altColor) {
+ super(res, (d instanceof BitmapDrawable) ? ((BitmapDrawable) d).getBitmap() : null);
+ mNormalCf = new LightingColorFilter(Color.BLACK, normalColor);
+ mAltCf = new LightingColorFilter(Color.BLACK, altColor);
+ }
+
+ @Override
+ public boolean isStateful() {
+ return true;
+ }
+
+ @Override
+ protected boolean onStateChange(int[] stateSet) {
+ final boolean useAlt = StateSet.stateSetMatches(DrawableStateSet.ENABLED_PRESSED_STATE_SET, stateSet)
+ || StateSet.stateSetMatches(DrawableStateSet.ENABLED_FOCUSED_STATE_SET, stateSet);
+ setColorFilter(useAlt ? mAltCf : mNormalCf);
+ return true;
+ }
+}
diff --git a/GreenDroid/src/greendroid/graphics/drawable/DrawableStateSet.java b/GreenDroid/src/greendroid/graphics/drawable/DrawableStateSet.java
new file mode 100644
index 000000000..10ccb877e
--- /dev/null
+++ b/GreenDroid/src/greendroid/graphics/drawable/DrawableStateSet.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2011 Cyril Mottier (http://www.cyrilmottier.com)
+ *
+ * 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 greendroid.graphics.drawable;
+
+public class DrawableStateSet {
+
+ public static final int[] EMPTY_STATE_SET = {};
+
+ public static final int[] ENABLED_PRESSED_STATE_SET = {
+ android.R.attr.state_enabled, android.R.attr.state_pressed
+ };
+
+ public static final int[] ENABLED_FOCUSED_STATE_SET = {
+ android.R.attr.state_enabled, android.R.attr.state_focused
+ };
+
+}
diff --git a/GreenDroid/src/greendroid/image/ImageCache.java b/GreenDroid/src/greendroid/image/ImageCache.java
new file mode 100644
index 000000000..603172729
--- /dev/null
+++ b/GreenDroid/src/greendroid/image/ImageCache.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2010 Cyril Mottier (http://www.cyrilmottier.com)
+ *
+ * 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 greendroid.image;
+
+import greendroid.app.GDApplication.OnLowMemoryListener;
+import greendroid.util.GDUtils;
+
+import java.lang.ref.SoftReference;
+import java.util.HashMap;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+
+public class ImageCache implements OnLowMemoryListener {
+
+ private final HashMap> mSoftCache;
+
+ public ImageCache(Context context) {
+ mSoftCache = new HashMap>();
+ GDUtils.getGDApplication(context).registerOnLowMemoryListener(this);
+ }
+
+ public static ImageCache from(Context context) {
+ return GDUtils.getImageCache(context);
+ }
+
+ public Bitmap get(String url) {
+ final SoftReference ref = mSoftCache.get(url);
+ if (ref == null) {
+ return null;
+ }
+
+ final Bitmap bitmap = ref.get();
+ if (bitmap == null) {
+ mSoftCache.remove(url);
+ }
+
+ return bitmap;
+ }
+
+ public void put(String url, Bitmap bitmap) {
+ mSoftCache.put(url, new SoftReference(bitmap));
+ }
+
+ public void flush() {
+ mSoftCache.clear();
+ }
+
+ public void onLowMemoryReceived() {
+ flush();
+ }
+}
diff --git a/GreenDroid/src/greendroid/image/ImageLoader.java b/GreenDroid/src/greendroid/image/ImageLoader.java
new file mode 100644
index 000000000..6216e80f1
--- /dev/null
+++ b/GreenDroid/src/greendroid/image/ImageLoader.java
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2010 Cyril Mottier (http://www.cyrilmottier.com)
+ *
+ * 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 greendroid.image;
+
+import greendroid.util.Config;
+import greendroid.util.GDUtils;
+
+import java.net.URL;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.os.Handler;
+import android.os.Message;
+import android.os.Process;
+import android.text.TextUtils;
+import android.util.DisplayMetrics;
+import android.util.Log;
+
+/**
+ * An ImageLoader asynchronously loads image from a given url. Client may be
+ * notified from the current image loading state using the
+ * {@link ImageLoaderCallback}.
+ *
+ * Note: You normally don't need to use the {@link ImageLoader}
+ * class directly in your application. You'll generally prefer using an
+ * {@link ImageRequest} that takes care of the entire loading process.
+ *
+ *
+ * @author Cyril Mottier
+ */
+public class ImageLoader {
+
+ private static final String LOG_TAG = ImageLoader.class.getSimpleName();
+
+ public static interface ImageLoaderCallback {
+
+ void onImageLoadingStarted(ImageLoader loader);
+
+ void onImageLoadingEnded(ImageLoader loader, Bitmap bitmap);
+
+ void onImageLoadingFailed(ImageLoader loader, Throwable exception);
+ }
+
+ private static final int ON_START = 0x100;
+ private static final int ON_FAIL = 0x101;
+ private static final int ON_END = 0x102;
+
+ private static ImageCache sImageCache;
+ private static ExecutorService sExecutor;
+ private static BitmapFactory.Options sDefaultOptions;
+
+ public ImageLoader(Context context) {
+ if (sImageCache == null) {
+ sImageCache = GDUtils.getImageCache(context);
+ }
+ if (sExecutor == null) {
+ sExecutor = GDUtils.getExecutor(context);
+ }
+ if (sDefaultOptions == null) {
+ sDefaultOptions = new BitmapFactory.Options();
+ sDefaultOptions.inDither = true;
+ sDefaultOptions.inScaled = true;
+ sDefaultOptions.inDensity = DisplayMetrics.DENSITY_MEDIUM;
+ sDefaultOptions.inTargetDensity = context.getResources().getDisplayMetrics().densityDpi;
+ }
+ }
+
+ public Future> loadImage(String url, ImageLoaderCallback callback) {
+ return loadImage(url, callback, null);
+ }
+
+ public Future> loadImage(String url, ImageLoaderCallback callback, ImageProcessor bitmapProcessor) {
+ return loadImage(url, callback, bitmapProcessor, null);
+ }
+
+ public Future> loadImage(String url, ImageLoaderCallback callback, ImageProcessor bitmapProcessor, BitmapFactory.Options options) {
+ return sExecutor.submit(new ImageFetcher(url, callback, bitmapProcessor, options));
+ }
+
+ private class ImageFetcher implements Runnable {
+
+ private String mUrl;
+ private ImageHandler mHandler;
+ private ImageProcessor mBitmapProcessor;
+ private BitmapFactory.Options mOptions;
+
+ public ImageFetcher(String url, ImageLoaderCallback callback, ImageProcessor bitmapProcessor, BitmapFactory.Options options) {
+ mUrl = url;
+ mHandler = new ImageHandler(url, callback);
+ mBitmapProcessor = bitmapProcessor;
+ mOptions = options;
+ }
+
+ public void run() {
+
+ Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
+
+ final Handler h = mHandler;
+ Bitmap bitmap = null;
+ Throwable throwable = null;
+
+ h.sendMessage(Message.obtain(h, ON_START));
+
+ try {
+
+ if (TextUtils.isEmpty(mUrl)) {
+ throw new Exception("The given URL cannot be null or empty");
+ }
+
+ // TODO Cyril: Use a AndroidHttpClient?
+ bitmap = BitmapFactory.decodeStream(new URL(mUrl).openStream(), null, (mOptions == null) ? sDefaultOptions : mOptions);
+
+ if (mBitmapProcessor != null && bitmap != null) {
+ final Bitmap processedBitmap = mBitmapProcessor.processImage(bitmap);
+ if (processedBitmap != null) {
+ bitmap = processedBitmap;
+ }
+ }
+
+ } catch (Exception e) {
+ // An error occured while retrieving the image
+ if (Config.GD_ERROR_LOGS_ENABLED) {
+ Log.e(LOG_TAG, "Error while fetching image", e);
+ }
+ throwable = e;
+ }
+
+ if (bitmap == null) {
+ if (throwable == null) {
+ // Skia returned a null bitmap ... that's usually because
+ // the given url wasn't pointing to a valid image
+ throwable = new Exception("Skia image decoding failed");
+ }
+ h.sendMessage(Message.obtain(h, ON_FAIL, throwable));
+ } else {
+ h.sendMessage(Message.obtain(h, ON_END, bitmap));
+ }
+ }
+ }
+
+ private class ImageHandler extends Handler {
+
+ private String mUrl;
+ private ImageLoaderCallback mCallback;
+
+ private ImageHandler(String url, ImageLoaderCallback callback) {
+ mUrl = url;
+ mCallback = callback;
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+
+ switch (msg.what) {
+
+ case ON_START:
+ if (mCallback != null) {
+ mCallback.onImageLoadingStarted(ImageLoader.this);
+ }
+ break;
+
+ case ON_FAIL:
+ if (mCallback != null) {
+ mCallback.onImageLoadingFailed(ImageLoader.this, (Throwable) msg.obj);
+ }
+ break;
+
+ case ON_END:
+
+ final Bitmap bitmap = (Bitmap) msg.obj;
+ sImageCache.put(mUrl, bitmap);
+
+ if (mCallback != null) {
+ mCallback.onImageLoadingEnded(ImageLoader.this, bitmap);
+ }
+ break;
+
+ default:
+ super.handleMessage(msg);
+ break;
+ }
+ };
+ }
+
+}
diff --git a/GreenDroid/src/greendroid/image/ImageProcessor.java b/GreenDroid/src/greendroid/image/ImageProcessor.java
new file mode 100644
index 000000000..6534fd454
--- /dev/null
+++ b/GreenDroid/src/greendroid/image/ImageProcessor.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2010 Cyril Mottier (http://www.cyrilmottier.com)
+ *
+ * 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 greendroid.image;
+
+import android.graphics.Bitmap;
+
+/**
+ * An interface specifying a way to process an image prior storing it in the
+ * application-wide cache. A great way to use this interface is to prepare a
+ * Bitmap (resizing, adding rounded corners, changing the tint color, etc.) for
+ * faster drawing.
+ *
+ * @author Cyril Mottier
+ */
+public interface ImageProcessor {
+
+ /**
+ * Called whenever the bitmap need to be processed. The returned may have
+ * been modified or completely different.
+ *
+ * @param bitmap
+ * The Bitmap to process
+ * @return A Bitmap that has been modified
+ */
+ Bitmap processImage(Bitmap bitmap);
+
+}
diff --git a/GreenDroid/src/greendroid/image/ImageRequest.java b/GreenDroid/src/greendroid/image/ImageRequest.java
new file mode 100644
index 000000000..1ffdf777c
--- /dev/null
+++ b/GreenDroid/src/greendroid/image/ImageRequest.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2010 Cyril Mottier (http://www.cyrilmottier.com)
+ *
+ * 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 greendroid.image;
+
+import greendroid.image.ImageLoader.ImageLoaderCallback;
+
+import java.util.concurrent.Future;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+
+/**
+ * An {@link ImageRequest} may be used to request an image from the network. The
+ * process of requesting for an image is done in three steps:
+ *
+ *
Instantiate a new {@link ImageRequest}
+ *
Call {@link #load(Context)} to start loading the image
+ *
Listen to loading state changes using a {@link ImageRequestCallback}
+ *
+ *
+ * @author Cyril Mottier
+ */
+public class ImageRequest {
+
+ /**
+ * @author Cyril Mottier
+ */
+ public static interface ImageRequestCallback {
+ void onImageRequestStarted(ImageRequest request);
+
+ void onImageRequestFailed(ImageRequest request, Throwable throwable);
+
+ void onImageRequestEnded(ImageRequest request, Bitmap image);
+
+ void onImageRequestCancelled(ImageRequest request);
+ }
+
+ private static ImageLoader sImageLoader;
+
+ private Future> mFuture;
+ private String mUrl;
+ private ImageRequestCallback mCallback;
+ private ImageProcessor mBitmapProcessor;
+ private BitmapFactory.Options mOptions;
+
+ public ImageRequest(String url, ImageRequestCallback callback) {
+ this(url, callback, null);
+ }
+
+ public ImageRequest(String url, ImageRequestCallback callback, ImageProcessor bitmapProcessor) {
+ this(url, callback, bitmapProcessor, null);
+ }
+
+ public ImageRequest(String url, ImageRequestCallback callback, ImageProcessor bitmapProcessor, BitmapFactory.Options options) {
+ mUrl = url;
+ mCallback = callback;
+ mBitmapProcessor = bitmapProcessor;
+ mOptions = options;
+ }
+
+ public void setImageRequestCallback(ImageRequestCallback callback) {
+ mCallback = callback;
+ }
+
+ public String getUrl() {
+ return mUrl;
+ }
+
+ public void load(Context context) {
+ if (mFuture == null) {
+ if (sImageLoader == null) {
+ sImageLoader = new ImageLoader(context);
+ }
+ mFuture = sImageLoader.loadImage(mUrl, new InnerCallback(), mBitmapProcessor, mOptions);
+ }
+ }
+
+ public void cancel() {
+ if (!isCancelled()) {
+ // Here we do not want to force the task to be interrupted. Indeed,
+ // it may be useful to keep the result in a cache for a further use
+ mFuture.cancel(false);
+ if (mCallback != null) {
+ mCallback.onImageRequestCancelled(this);
+ }
+ }
+ }
+
+ public final boolean isCancelled() {
+ return mFuture.isCancelled();
+ }
+
+ private class InnerCallback implements ImageLoaderCallback {
+
+ public void onImageLoadingStarted(ImageLoader loader) {
+ if (mCallback != null) {
+ mCallback.onImageRequestStarted(ImageRequest.this);
+ }
+ }
+
+ public void onImageLoadingEnded(ImageLoader loader, Bitmap bitmap) {
+ if (mCallback != null && !isCancelled()) {
+ mCallback.onImageRequestEnded(ImageRequest.this, bitmap);
+ }
+ mFuture = null;
+ }
+
+ public void onImageLoadingFailed(ImageLoader loader, Throwable exception) {
+ if (mCallback != null && !isCancelled()) {
+ mCallback.onImageRequestFailed(ImageRequest.this, exception);
+ }
+ mFuture = null;
+ }
+ }
+
+}
diff --git a/GreenDroid/src/greendroid/util/Config.java b/GreenDroid/src/greendroid/util/Config.java
index a1169e6ef..9e301cb2c 100644
--- a/GreenDroid/src/greendroid/util/Config.java
+++ b/GreenDroid/src/greendroid/util/Config.java
@@ -35,6 +35,6 @@ public class Config {
public static final boolean GD_INFO_LOGS_ENABLED = (GD_LOG_LEVEL == GD_LOG_LEVEL_INFO);
public static final boolean GD_WARNING_LOGS_ENABLED = GD_INFO_LOGS_ENABLED
|| (GD_LOG_LEVEL == GD_LOG_LEVEL_WARNING);
- public static final boolean GD_ERROR_LOGS_ENABLED = (GD_LOG_LEVEL == GD_LOG_LEVEL_ERROR) || GD_WARNING_LOGS_ENABLED;
+ public static final boolean GD_ERROR_LOGS_ENABLED = GD_WARNING_LOGS_ENABLED || (GD_LOG_LEVEL == GD_LOG_LEVEL_ERROR);
}
diff --git a/GreenDroid/src/greendroid/util/GDUtils.java b/GreenDroid/src/greendroid/util/GDUtils.java
new file mode 100644
index 000000000..313c45ab7
--- /dev/null
+++ b/GreenDroid/src/greendroid/util/GDUtils.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2010 Cyril Mottier (http://www.cyrilmottier.com)
+ *
+ * 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 greendroid.util;
+
+import greendroid.app.GDApplication;
+import greendroid.image.ImageCache;
+
+import java.util.concurrent.ExecutorService;
+
+import android.content.Context;
+
+/**
+ * Class that provides several utility methods related to GreenDroid.
+ *
+ * @author Cyril Mottier
+ */
+public class GDUtils {
+
+ private GDUtils() {
+ }
+
+ /**
+ * Return the current {@link GDApplication}
+ *
+ * @param context The calling context
+ * @return The {@link GDApplication} the given context is linked to.
+ */
+ public static GDApplication getGDApplication(Context context) {
+ return (GDApplication) context.getApplicationContext();
+ }
+
+ /**
+ * Return the {@link GDApplication} image cache
+ *
+ * @param context The calling context
+ * @return The image cache of the current {@link GDApplication}
+ */
+ public static ImageCache getImageCache(Context context) {
+ return getGDApplication(context).getImageCache();
+ }
+
+ /**
+ * Return the {@link GDApplication} executors pool.
+ *
+ * @param context The calling context
+ * @return The executors pool of the current {@link GDApplication}
+ */
+ public static ExecutorService getExecutor(Context context) {
+ return getGDApplication(context).getExecutor();
+ }
+
+}
diff --git a/GreenDroid/src/greendroid/util/Md5Util.java b/GreenDroid/src/greendroid/util/Md5Util.java
new file mode 100644
index 000000000..d63f30051
--- /dev/null
+++ b/GreenDroid/src/greendroid/util/Md5Util.java
@@ -0,0 +1,38 @@
+package greendroid.util;
+
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+
+public class Md5Util {
+
+ private static MessageDigest sMd5MessageDigest;
+ private static StringBuilder sStringBuilder;
+
+ static {
+ try {
+ sMd5MessageDigest = MessageDigest.getInstance("MD5");
+ } catch (NoSuchAlgorithmException e) {
+ // TODO cyril: I'm quite sure about my "MD5" algorithm
+ // but this is not a correct way to handle an exception ...
+ }
+ sStringBuilder = new StringBuilder();
+ }
+
+ private Md5Util() {
+ }
+
+ public static String md5(String s) {
+
+ sMd5MessageDigest.reset();
+ sMd5MessageDigest.update(s.getBytes());
+
+ byte digest[] = sMd5MessageDigest.digest();
+
+ sStringBuilder.setLength(0);
+ for (int i=0; i mItems;
@@ -93,10 +91,17 @@ public class ActionBar extends LinearLayout {
mDividerDrawable = a.getDrawable(R.styleable.ActionBar_dividerDrawable);
mDividerWidth = a.getDimensionPixelSize(R.styleable.ActionBar_dividerWidth, -1);
mHomeDrawable = a.getDrawable(R.styleable.ActionBar_homeDrawable);
+ if (mHomeDrawable == null) {
+ mHomeDrawable = new ActionBarDrawable(getResources(), R.drawable.gd_action_bar_home);
+ }
int layoutID;
int type = a.getInteger(R.styleable.ActionBar_type, -1);
switch (type) {
+ case 2:
+ mType = Type.Empty;
+ layoutID = R.layout.gd_action_bar_empty;
+ break;
case 1:
mType = Type.Dashboard;
layoutID = R.layout.gd_action_bar_dashboard;
@@ -108,7 +113,7 @@ public class ActionBar extends LinearLayout {
break;
}
- // HACK cyril: Without this, the onFinishInflate is called twice !?!
+ // HACK Cyril: Without this, the onFinishInflate is called twice !?!
// This issue is due to a bug when Android inflates a layout with a
// parent - which is compulsory with a tag. I've reported this
// bug to Romain Guy who fixed it (patch will probably be available in
@@ -130,29 +135,29 @@ public class ActionBar extends LinearLayout {
if (!mMerging) {
- if (Config.GD_INFO_LOGS_ENABLED) {
- Log.i(LOG_TAG, "onFinishInflate() - not merging");
- }
+ switch (mType) {
+ case Dashboard:
+ mHomeButton = (ImageButton) findViewById(R.id.gd_action_bar_home_item);
+ mHomeButton.setOnClickListener(mClickHandler);
+ break;
- // Work done for both Dashboard and Normal type
- mHomeButton = (ImageButton) findViewById(R.id.gd_action_bar_home_item);
- mHomeButton.setOnClickListener(mClickHandler);
+ case Empty:
+ mTitleView = (TextView) findViewById(R.id.gd_action_bar_title);
+ setTitle(mTitle);
+ break;
- switch (mType) {
case Normal:
+ default:
+ mHomeButton = (ImageButton) findViewById(R.id.gd_action_bar_home_item);
+ mHomeButton.setOnClickListener(mClickHandler);
mHomeButton.setImageDrawable(mHomeDrawable);
mHomeButton.setContentDescription(getContext().getString(R.string.gd_go_home));
mTitleView = (TextView) findViewById(R.id.gd_action_bar_title);
- if (mTitle != null) {
- setTitle(mTitle);
- }
-
- default:
- //Do nothing
+ setTitle(mTitle);
break;
+
}
}
-
}
public void setOnActionBarListener(OnActionBarListener listener) {
@@ -160,41 +165,57 @@ public class ActionBar extends LinearLayout {
}
public void setTitle(CharSequence title) {
+ mTitle = title;
if (mTitleView != null) {
mTitleView.setText(title);
}
}
- public void addItem(ActionBarItem.Type actionBarItemType) {
- addItem(ActionBarItem.createWithType(this, actionBarItemType));
+ public ActionBarItem addItem(ActionBarItem.Type actionBarItemType) {
+ return addItem(ActionBarItem.createWithType(this, actionBarItemType), NONE);
+ }
+
+ public ActionBarItem addItem(ActionBarItem.Type actionBarItemType, int itemId) {
+ return addItem(ActionBarItem.createWithType(this, actionBarItemType), itemId);
+ }
+
+ public ActionBarItem addItem(ActionBarItem item) {
+ return addItem(item, NONE);
}
- public void addItem(ActionBarItem item) {
+ public ActionBarItem addItem(ActionBarItem item, int itemId) {
if (mItems.size() >= MAX_ITEMS_COUNT) {
/*
* An ActionBar must contain as few items as possible. So let's keep
* a limit :)
*/
- return;
+ return null;
}
- if (mDividerDrawable != null) {
- ImageView divider = new ImageView(getContext());
- int dividerWidth = (mDividerWidth > 0) ? mDividerWidth : mDividerDrawable.getIntrinsicWidth();
- final LinearLayout.LayoutParams lp = new LayoutParams(dividerWidth, LayoutParams.FILL_PARENT);
- divider.setLayoutParams(lp);
- divider.setBackgroundDrawable(mDividerDrawable);
- addView(divider);
- }
+ if (item != null) {
+
+ item.setItemId(itemId);
+
+ if (mDividerDrawable != null) {
+ ImageView divider = new ImageView(getContext());
+ int dividerWidth = (mDividerWidth > 0) ? mDividerWidth : mDividerDrawable.getIntrinsicWidth();
+ final LinearLayout.LayoutParams lp = new LayoutParams(dividerWidth, LayoutParams.FILL_PARENT);
+ divider.setLayoutParams(lp);
+ divider.setBackgroundDrawable(mDividerDrawable);
+ addView(divider);
+ }
- final View itemView = item.getItemView();
- itemView.findViewById(R.id.gd_action_bar_item).setOnClickListener(mClickHandler);
+ final View itemView = item.getItemView();
+ itemView.findViewById(R.id.gd_action_bar_item).setOnClickListener(mClickHandler);
- final int size = (int) getResources().getDimension(R.dimen.gd_action_bar_height);
- addView(itemView, new LayoutParams(size, LayoutParams.FILL_PARENT));
+ final int size = (int) getResources().getDimension(R.dimen.gd_action_bar_height);
+ addView(itemView, new LayoutParams(size, LayoutParams.FILL_PARENT));
- mItems.add(item);
+ mItems.add(item);
+ }
+
+ return item;
}
public ActionBarItem getItem(int position) {
@@ -204,6 +225,10 @@ public class ActionBar extends LinearLayout {
return mItems.get(position);
}
+ public void removeItem(ActionBarItem item) {
+ removeItem(mItems.indexOf(item));
+ }
+
public void removeItem(int position) {
if (position < 0 || position >= mItems.size()) {
@@ -216,16 +241,16 @@ public class ActionBar extends LinearLayout {
mItems.remove(position);
}
- /**
- * @hide TODO cyril: To be tested.
- */
public void setType(Type type) {
if (type != mType) {
-
+
removeAllViews();
int layoutId = 0;
switch (type) {
+ case Empty:
+ layoutId = R.layout.gd_action_bar_empty;
+ break;
case Dashboard:
layoutId = R.layout.gd_action_bar_dashboard;
break;
@@ -233,10 +258,9 @@ public class ActionBar extends LinearLayout {
layoutId = R.layout.gd_action_bar_normal;
break;
}
-
- mMerging = true;
+
+ mType = type;
LayoutInflater.from(getContext()).inflate(layoutId, this);
- mMerging = false;
// Reset all items
LinkedList itemsCopy = new LinkedList(mItems);
@@ -256,7 +280,7 @@ public class ActionBar extends LinearLayout {
throw new IllegalArgumentException("The given klass must have a default constructor");
}
}
-
+
private OnClickListener mClickHandler = new OnClickListener() {
public void onClick(View v) {
diff --git a/GreenDroid/src/greendroid/widget/ActionBarHost.java b/GreenDroid/src/greendroid/widget/ActionBarHost.java
index 14b533fbb..e65b074bd 100644
--- a/GreenDroid/src/greendroid/widget/ActionBarHost.java
+++ b/GreenDroid/src/greendroid/widget/ActionBarHost.java
@@ -47,7 +47,7 @@ public class ActionBarHost extends LinearLayout {
mContentView = (FrameLayout) findViewById(R.id.gd_action_bar_content_view);
if (mContentView == null || !(mContentView instanceof FrameLayout)) {
- throw new IllegalArgumentException("No content view with the id R.id.gd_content_view found in the layout.");
+ throw new IllegalArgumentException("No FrameLayout with the id R.id.gd_action_bar_content_view found in the layout.");
}
}
diff --git a/GreenDroid/src/greendroid/widget/ActionBarItem.java b/GreenDroid/src/greendroid/widget/ActionBarItem.java
index 4d5e9ff1b..dc49bedc5 100644
--- a/GreenDroid/src/greendroid/widget/ActionBarItem.java
+++ b/GreenDroid/src/greendroid/widget/ActionBarItem.java
@@ -15,17 +15,17 @@
*/
package greendroid.widget;
+import greendroid.graphics.drawable.ActionBarDrawable;
import android.content.Context;
import android.graphics.drawable.Drawable;
-import android.graphics.drawable.StateListDrawable;
import android.view.View;
import com.cyrilmottier.android.greendroid.R;
/**
* Base class representing an {@link ActionBarItem} used in {@link ActionBar}s.
- * The base implementation exposes a single Drawable as well as a
- * content description.
+ * The base implementation exposes a single Drawable as well as a content
+ * description.
*
* @author Cyril Mottier
*/
@@ -46,27 +46,22 @@ public abstract class ActionBarItem {
Add, // A plus sign
Star, // A star
SortBySize, // Some bars
- LocateMyself
- // A surrounded dot
+ LocateMyself, // A surrounded dot
+ Compass,
+ Help,
+ Info,
+ Settings,
+ List,
+ Trashcan,
+ Eye,
+ AllFriends,
+ Group,
+ Gallery,
+ Slideshow,
+ Mail
}
- // Why, the hell, are those value protected to View ??? The simplest way to
- // get those sets here is to copy them. Another way would be to subclass
- // View just to access those protected fields ... yuck !!!
- private static final int[] ENABLE_STATE_SET = {
- android.R.attr.state_enabled
- };
-
- private static final int[] ENABLED_PRESSED_STATE_SET = {
- android.R.attr.state_enabled, android.R.attr.state_pressed
- };
-
- private static final int[] ENABLED_FOCUSED_STATE_SET = {
- android.R.attr.state_enabled, android.R.attr.state_focused
- };
-
protected Drawable mDrawable;
- protected int mDrawableId;
protected CharSequence mContentDescription;
protected View mItemView;
@@ -74,6 +69,8 @@ public abstract class ActionBarItem {
protected Context mContext;
protected ActionBar mActionBar;
+ private int mItemId;
+
void setActionBar(ActionBar actionBar) {
mContext = actionBar.getContext();
mActionBar = actionBar;
@@ -137,126 +134,164 @@ public abstract class ActionBarItem {
protected void onItemClicked() {
}
+ void setItemId(int itemId) {
+ mItemId = itemId;
+ }
+
+ public int getItemId() {
+ return mItemId;
+ }
+
static ActionBarItem createWithType(ActionBar actionBar, ActionBarItem.Type type) {
- int normalDrawableId;
- int altDrawableId;
- int descriptionId;
+ int drawableId = 0;
+ int descriptionId = 0;
switch (type) {
case GoHome:
- normalDrawableId = R.drawable.gd_action_bar_home_normal;
- altDrawableId = R.drawable.gd_action_bar_home_alt;
+ drawableId = R.drawable.gd_action_bar_home;
descriptionId = R.string.gd_go_home;
break;
case Search:
- normalDrawableId = R.drawable.gd_action_bar_search_normal;
- altDrawableId = R.drawable.gd_action_bar_search_alt;
+ drawableId = R.drawable.gd_action_bar_search;
descriptionId = R.string.gd_search;
break;
case Talk:
- normalDrawableId = R.drawable.gd_action_bar_talk_normal;
- altDrawableId = R.drawable.gd_action_bar_talk_alt;
+ drawableId = R.drawable.gd_action_bar_talk;
descriptionId = R.string.gd_talk;
break;
case Compose:
- normalDrawableId = R.drawable.gd_action_bar_compose_normal;
- altDrawableId = R.drawable.gd_action_bar_compose_alt;
+ drawableId = R.drawable.gd_action_bar_compose;
descriptionId = R.string.gd_compose;
break;
case Export:
- normalDrawableId = R.drawable.gd_action_bar_export_normal;
- altDrawableId = R.drawable.gd_action_bar_export_alt;
+ drawableId = R.drawable.gd_action_bar_export;
descriptionId = R.string.gd_export;
break;
case Share:
- normalDrawableId = R.drawable.gd_action_bar_share_normal;
- altDrawableId = R.drawable.gd_action_bar_share_alt;
+ drawableId = R.drawable.gd_action_bar_share;
descriptionId = R.string.gd_share;
break;
case Refresh:
- return actionBar
- .newActionBarItem(LoaderActionBarItem.class)
- .setDrawable(
- createStateListDrawable(actionBar.getContext(),
- R.drawable.gd_action_bar_refresh_normal, R.drawable.gd_action_bar_refresh_alt))
+ return actionBar.newActionBarItem(LoaderActionBarItem.class)
+ .setDrawable(new ActionBarDrawable(actionBar.getResources(), R.drawable.gd_action_bar_refresh))
.setContentDescription(R.string.gd_refresh);
case TakePhoto:
- normalDrawableId = R.drawable.gd_action_bar_take_photo_normal;
- altDrawableId = R.drawable.gd_action_bar_take_photo_alt;
+ drawableId = R.drawable.gd_action_bar_take_photo;
descriptionId = R.string.gd_take_photo;
break;
//
// case PickPhoto:
- // normalDrawableId = R.drawable.gd_action_bar_pick_photo_normal;
- // altDrawableId = R.drawable.gd_action_bar_pick_photo_alt;
+ // drawableId = R.drawable.gd_action_bar_pick_photo;
// descriptionId = R.string.gd_pick_photo;
// break;
case Locate:
- normalDrawableId = R.drawable.gd_action_bar_locate_normal;
- altDrawableId = R.drawable.gd_action_bar_locate_alt;
+ drawableId = R.drawable.gd_action_bar_locate;
descriptionId = R.string.gd_locate;
break;
case Edit:
- normalDrawableId = R.drawable.gd_action_bar_edit_normal;
- altDrawableId = R.drawable.gd_action_bar_edit_alt;
+ drawableId = R.drawable.gd_action_bar_edit;
descriptionId = R.string.gd_edit;
break;
case Add:
- normalDrawableId = R.drawable.gd_action_bar_add_normal;
- altDrawableId = R.drawable.gd_action_bar_add_alt;
+ drawableId = R.drawable.gd_action_bar_add;
descriptionId = R.string.gd_add;
break;
case Star:
- normalDrawableId = R.drawable.gd_action_bar_star_normal;
- altDrawableId = R.drawable.gd_action_bar_star_alt;
+ drawableId = R.drawable.gd_action_bar_star;
descriptionId = R.string.gd_star;
break;
case SortBySize:
- normalDrawableId = R.drawable.gd_action_bar_sort_by_size_normal;
- altDrawableId = R.drawable.gd_action_bar_sort_by_size_alt;
+ drawableId = R.drawable.gd_action_bar_sort_by_size;
descriptionId = R.string.gd_sort_by_size;
break;
case LocateMyself:
- normalDrawableId = R.drawable.gd_action_bar_locate_myself_normal;
- altDrawableId = R.drawable.gd_action_bar_locate_myself_alt;
+ drawableId = R.drawable.gd_action_bar_locate_myself;
descriptionId = R.string.gd_locate_myself;
break;
+
+ case Compass:
+ drawableId = R.drawable.gd_action_bar_compass;
+ descriptionId = R.string.gd_compass;
+ break;
+
+ case Help:
+ drawableId = R.drawable.gd_action_bar_help;
+ descriptionId = R.string.gd_help;
+ break;
+
+ case Info:
+ drawableId = R.drawable.gd_action_bar_info;
+ descriptionId = R.string.gd_info;
+ break;
+
+ case Settings:
+ drawableId = R.drawable.gd_action_bar_settings;
+ descriptionId = R.string.gd_settings;
+ break;
+
+ case List:
+ drawableId = R.drawable.gd_action_bar_list;
+ descriptionId = R.string.gd_list;
+ break;
+
+ case Trashcan:
+ drawableId = R.drawable.gd_action_bar_trashcan;
+ descriptionId = R.string.gd_trashcan;
+ break;
+
+ case Eye:
+ drawableId = R.drawable.gd_action_bar_eye;
+ descriptionId = R.string.gd_eye;
+ break;
+
+ case AllFriends:
+ drawableId = R.drawable.gd_action_bar_all_friends;
+ descriptionId = R.string.gd_all_friends;
+ break;
+
+ case Group:
+ drawableId = R.drawable.gd_action_bar_group;
+ descriptionId = R.string.gd_group;
+ break;
+
+ case Gallery:
+ drawableId = R.drawable.gd_action_bar_gallery;
+ descriptionId = R.string.gd_gallery;
+ break;
+
+ case Slideshow:
+ drawableId = R.drawable.gd_action_bar_slideshow;
+ descriptionId = R.string.gd_slideshow;
+ break;
+
+ case Mail:
+ drawableId = R.drawable.gd_action_bar_mail;
+ descriptionId = R.string.gd_mail;
+ break;
default:
// Do nothing but return null
return null;
}
- final Drawable d = createStateListDrawable(actionBar.getContext(), normalDrawableId, altDrawableId);
+ final Drawable d = new ActionBarDrawable(actionBar.getResources(), drawableId);
return actionBar.newActionBarItem(NormalActionBarItem.class).setDrawable(d)
.setContentDescription(descriptionId);
}
- private static Drawable createStateListDrawable(Context context, int normalDrawableId, int altDrawableId) {
-
- StateListDrawable stateListDrawable = new StateListDrawable();
- Drawable normalDrawable = context.getResources().getDrawable(normalDrawableId);
- Drawable altDrawable = context.getResources().getDrawable(altDrawableId);
-
- stateListDrawable.addState(ENABLED_FOCUSED_STATE_SET, altDrawable);
- stateListDrawable.addState(ENABLED_PRESSED_STATE_SET, altDrawable);
- stateListDrawable.addState(ENABLE_STATE_SET, normalDrawable);
-
- return stateListDrawable;
- }
}
diff --git a/GreenDroid/src/greendroid/widget/AsyncImageView.java b/GreenDroid/src/greendroid/widget/AsyncImageView.java
new file mode 100644
index 000000000..2f1d03b04
--- /dev/null
+++ b/GreenDroid/src/greendroid/widget/AsyncImageView.java
@@ -0,0 +1,466 @@
+/*
+ * Copyright (C) 2010 Cyril Mottier (http://www.cyrilmottier.com)
+ *
+ * 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 greendroid.widget;
+
+import greendroid.image.ImageProcessor;
+import greendroid.image.ImageRequest;
+import greendroid.image.ImageRequest.ImageRequestCallback;
+import greendroid.util.Config;
+import greendroid.util.GDUtils;
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.BitmapFactory.Options;
+import android.graphics.drawable.Drawable;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.widget.ImageView;
+import android.widget.ListView;
+
+import com.cyrilmottier.android.greendroid.R;
+
+/**
+ *
+ * A {@link AsyncImageView} is a network-aware {@link ImageView}. It may display
+ * images from the web according to a URL. {@link AsyncImageView} takes care of
+ * loading asynchronously images on the Internet. It also caches images in an
+ * application-wide cache to prevent loading images several times.
+ *
+ *
+ * Clients may listen the {@link OnImageViewLoadListener} to be notified of the
+ * current image loading state.
+ *
+ *
+ * {@link AsyncImageView} may be extremely useful in {@link ListView}'s row. To
+ * prevent your {@link AsyncImageView} from downloading while scrolling or
+ * flinging it is a good idea to pause it using {@link #setPaused(boolean)}
+ * method. Once the scrolling/flinging is over, un-pause your
+ * {@link AsyncImageView}s using setPaused(false)
+ *