diff --git a/.classpath b/.classpath index 6aed2eb..08be9d6 100644 --- a/.classpath +++ b/.classpath @@ -1,8 +1,10 @@ - - - - - + + + + + diff --git a/.gitignore b/.gitignore index bae96b2..ccbc0bc 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,8 @@ gen/ authors.txt keystore +/.apt_generated +.settings/ +build.xml +local.properties +proguard-project.txt \ No newline at end of file diff --git a/.project b/.project index 5aadd53..58fcd0a 100644 --- a/.project +++ b/.project @@ -1,6 +1,6 @@ - Sparse RSS + test diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 2bd62ee..4c5647e 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -1,100 +1,192 @@ - + package="cn.eric.rss" + android:installLocation="auto" + android:versionCode="6" + android:versionName="1.05" > + + + + + + + - - - - - - + + + + + + + + + android:protectionLevel="normal" /> - - - + android:protectionLevel="normal" /> + + + + + - - + android:name="cn.eric.rss.provider.FeedDataContentProvider" + android:authorities="cn.eric.rss.provider.FeedData" + android:readPermission="cn.eric.rss.READFEEDS" + android:writePermission="cn.eric.rss.WRITEFEEDS" /> + + + + - - - + + + - + + + - + - + + + - - + + - + - - - + + + + + - - + + + + - + + - + - + + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + - + + \ No newline at end of file diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 19838d9..0000000 --- a/LICENSE +++ /dev/null @@ -1,31 +0,0 @@ -Sparse rss - -Copyright (c) 2010-2012 Stefan Handschuh - -Translators - - Dutch: Eelko Berkenpies - - Spanish: Sergio Martín - - French: - - Turkish: - - Russian: Igor Nedoboy - -Code-Contributors - - Joel Low - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/Makefile b/Makefile deleted file mode 100644 index 69501d6..0000000 --- a/Makefile +++ /dev/null @@ -1,71 +0,0 @@ -# Adjust to your local settings -SDK_DIR = /home/android/android-sdks -API_LEVEL = 15 -KEYALIAS = rss - - -# From here on, the file should be left unchanged -AAPT = $(SDK_DIR)/platform-tools/aapt -ANDROID_JAR = $(SDK_DIR)/platforms/android-$(API_LEVEL)/android.jar -DX_JAR = $(SDK_DIR)/platform-tools/lib/dx.jar -SDKLIB_JAR = $(SDK_DIR)/tools/lib/sdklib.jar -ZIPALIGN = $(SDK_DIR)/tools/zipalign - - -all: zipalign - -icons: res/drawable/icon.png res/drawable/feed.png res/drawable/feed_grey.png res/drawable/ic_statusbar_rss.png res/drawable-v9/ic_statusbar_rss.png res/drawable-v11/ic_statusbar_rss.png - -res/drawable/icon.png: launcher.svg - mkdir -p res/drawable - convert launcher.svg -resize 60x60 -background Transparent -bordercolor Transparent -border 4x6 \( +clone -background Transparent -shadow 40x1+0+3 \) +swap -layers merge +repage res/drawable/icon.png - convert -extract 72x72+0+0 +repage res/drawable/icon.png res/drawable/icon.png - -res/drawable/feed.png: launcher.svg - mkdir -p res/drawable - convert launcher.svg -resize 19x19 -background Transparent -bordercolor Transparent -border 23x23 res/drawable/feed.png - convert -extract 44x44+0+21 +repage res/drawable/feed.png res/drawable/feed.png - -res/drawable/feed_grey.png: launcher.svg - mkdir -p res/drawable - convert launcher.svg -resize 19x19 -background Transparent -type Grayscale -bordercolor Transparent -border 23x23 res/drawable/feed_grey.png - convert -extract 44x44+0+21 +repage res/drawable/feed_grey.png res/drawable/feed_grey.png - -res/drawable/ic_statusbar_rss.png: status_icon.svg - mkdir -p res/drawable - convert status_icon.svg -background Transparent -resize 21x21 -bordercolor Transparent -border 2 res/drawable/ic_statusbar_rss.png - -res/drawable-v9/ic_statusbar_rss.png: status_icon_23.svg - mkdir -p res/drawable-v9 - convert status_icon_23.svg -background Transparent -resize 21x21 -bordercolor Transparent -border 2 res/drawable-v9/ic_statusbar_rss.png - -res/drawable-v11/ic_statusbar_rss.png: status_icon_30.svg - mkdir -p res/drawable-v11 - convert status_icon_30.svg -background Transparent -resize 21x21 -bordercolor Transparent -border 2 res/drawable-v11/ic_statusbar_rss.png - -aapt: icons AndroidManifest.xml res - mkdir -p gen/de/shandschuh/sparserss/ - mkdir -p bin - $(AAPT) p -f -M AndroidManifest.xml -F bin/resources.ap_ -I $(ANDROID_JAR) -S res -m -J gen - -javac: aapt - mkdir -p bin/classes - javac -d bin/classes -sourcepath gen gen/de/shandschuh/sparserss/*.java - javac -cp bin/classes:$(ANDROID_JAR) -d bin/classes -sourcepath src `find src -name *.java -print` - -bin/classes.dex: javac - java -jar $(DX_JAR) --dex --output=bin/classes.dex bin/classes - -bin/SparseRSS_unsigned.apk: bin/classes.dex - java -cp $(SDKLIB_JAR) com.android.sdklib.build.ApkBuilderMain bin/SparseRSS_unsigned.apk -u -z bin/resources.ap_ -f bin/classes.dex - -bin/SparseRSS_signed.apk: bin/SparseRSS_unsigned.apk - jarsigner -keystore keystore -signedjar bin/SparseRSS_signed.apk bin/SparseRSS_unsigned.apk $(KEYALIAS) - -zipalign: bin/SparseRSS_signed.apk - $(ZIPALIGN) 4 bin/SparseRSS_signed.apk bin/SparseRSS_signed_aligned.apk - -clean: - rm -fr res/drawable* - rm -fr gen - rm -fr bin diff --git a/README b/README deleted file mode 100644 index a5a4c97..0000000 --- a/README +++ /dev/null @@ -1,24 +0,0 @@ -Sparse rss android program - -Copyright (c) 2010-2012 Stefan Handschuh - -Translators - - Dutch: Eelko Berkenpies - - Spanish: Sergio Martín - - French: - - Turkish: - - Russian: Igor Nedoboy - -Code-Contributors - - Joel Low - -The file "LICENSE" contains the license information for the program. - -Icons and artwork are distributed under the CC-BY 3.0 license. - -### - -This fork contains additional settings for feeds: - -- Choose different notification tones for different feeds -- Disable notification of updates for selected feeds diff --git a/README.md b/README.md new file mode 100644 index 0000000..ac90453 --- /dev/null +++ b/README.md @@ -0,0 +1,4 @@ +Quick RSS Reader +========== + +Sparse rss is a very simple and basic RSS reader for Android. Fork with some additional feed settings. diff --git a/launcher.svg b/launcher.svg index 2bd224d..cc32591 100644 --- a/launcher.svg +++ b/launcher.svg @@ -29,25 +29,15 @@ offset="1" id="stop3894" /> - - - - + @@ -189,16 +179,7 @@ inkscape:groupmode="layer" id="layer1" transform="translate(-292.69593,-415.05811)"> - + ; +} + +-keepclasseswithmembers class * { + public (android.content.Context, android.util.AttributeSet); +} + +-keepclasseswithmembers class * { + public (android.content.Context, android.util.AttributeSet, int); +} + +-keepclassmembers class * extends android.app.Activity { + public void *(android.view.View); +} + +-keepclassmembers enum * { + public static **[] values(); + public static ** valueOf(java.lang.String); +} + +-keep class * implements android.os.Parcelable { + public static final android.os.Parcelable$Creator *; +} + +-dontwarn android.support.** + +-dontwarn com.markupartist.** + +-keep public class com.umeng.example.R$*{ + public static final int *; +} + +-keepclassmembers class * { + public (org.json.JSONObject); +} + +-keep public class com.umeng.fb.ui.ThreadView { +} diff --git a/project.properties b/project.properties index fd44ee5..0fa7c6a 100644 --- a/project.properties +++ b/project.properties @@ -10,4 +10,5 @@ # Indicates whether an apk should be generated for each density. split.density=false # Project target. -target=android-17 +target=android-14 +android.library.reference.1=../ActionBarSherlock/library diff --git a/res/anim/umeng_xp_fade_in.xml b/res/anim/umeng_xp_fade_in.xml new file mode 100644 index 0000000..6ef335d --- /dev/null +++ b/res/anim/umeng_xp_fade_in.xml @@ -0,0 +1,10 @@ + + + + + + \ No newline at end of file diff --git a/res/anim/umeng_xp_fade_out.xml b/res/anim/umeng_xp_fade_out.xml new file mode 100644 index 0000000..d05bb1a --- /dev/null +++ b/res/anim/umeng_xp_fade_out.xml @@ -0,0 +1,10 @@ + + + + + + \ No newline at end of file diff --git a/res/anim/umeng_xp_large_gallery_in.xml b/res/anim/umeng_xp_large_gallery_in.xml new file mode 100644 index 0000000..96078e9 --- /dev/null +++ b/res/anim/umeng_xp_large_gallery_in.xml @@ -0,0 +1,10 @@ + + + + + + \ No newline at end of file diff --git a/res/anim/umeng_xp_progressbar.xml b/res/anim/umeng_xp_progressbar.xml new file mode 100644 index 0000000..e20c04c --- /dev/null +++ b/res/anim/umeng_xp_progressbar.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/res/anim/umeng_xp_push_down_out.xml b/res/anim/umeng_xp_push_down_out.xml new file mode 100644 index 0000000..ae7f464 --- /dev/null +++ b/res/anim/umeng_xp_push_down_out.xml @@ -0,0 +1,25 @@ + + + + + + + + + \ No newline at end of file diff --git a/res/anim/umeng_xp_push_up_in.xml b/res/anim/umeng_xp_push_up_in.xml new file mode 100644 index 0000000..84d8cb0 --- /dev/null +++ b/res/anim/umeng_xp_push_up_in.xml @@ -0,0 +1,9 @@ + + + + + + \ No newline at end of file diff --git a/res/anim/umeng_xp_push_up_out.xml b/res/anim/umeng_xp_push_up_out.xml new file mode 100644 index 0000000..f05194a --- /dev/null +++ b/res/anim/umeng_xp_push_up_out.xml @@ -0,0 +1,9 @@ + + + + + + \ No newline at end of file diff --git a/res/anim/umeng_xp_slide_in_from_bottom.xml b/res/anim/umeng_xp_slide_in_from_bottom.xml new file mode 100644 index 0000000..8537c4b --- /dev/null +++ b/res/anim/umeng_xp_slide_in_from_bottom.xml @@ -0,0 +1,6 @@ + + diff --git a/res/anim/umeng_xp_slide_in_from_left.xml b/res/anim/umeng_xp_slide_in_from_left.xml new file mode 100644 index 0000000..7402226 --- /dev/null +++ b/res/anim/umeng_xp_slide_in_from_left.xml @@ -0,0 +1,6 @@ + + diff --git a/res/anim/umeng_xp_slide_in_from_right.xml b/res/anim/umeng_xp_slide_in_from_right.xml new file mode 100644 index 0000000..334ae20 --- /dev/null +++ b/res/anim/umeng_xp_slide_in_from_right.xml @@ -0,0 +1,6 @@ + + diff --git a/res/anim/umeng_xp_slide_in_from_top.xml b/res/anim/umeng_xp_slide_in_from_top.xml new file mode 100644 index 0000000..8e3dcb8 --- /dev/null +++ b/res/anim/umeng_xp_slide_in_from_top.xml @@ -0,0 +1,6 @@ + + diff --git a/res/anim/umeng_xp_slide_out_from_bottom.xml b/res/anim/umeng_xp_slide_out_from_bottom.xml new file mode 100644 index 0000000..61b84a6 --- /dev/null +++ b/res/anim/umeng_xp_slide_out_from_bottom.xml @@ -0,0 +1,6 @@ + + diff --git a/res/anim/umeng_xp_slide_out_from_left.xml b/res/anim/umeng_xp_slide_out_from_left.xml new file mode 100644 index 0000000..e9ab077 --- /dev/null +++ b/res/anim/umeng_xp_slide_out_from_left.xml @@ -0,0 +1,6 @@ + + diff --git a/res/anim/umeng_xp_slide_out_from_right.xml b/res/anim/umeng_xp_slide_out_from_right.xml new file mode 100644 index 0000000..9c31fb3 --- /dev/null +++ b/res/anim/umeng_xp_slide_out_from_right.xml @@ -0,0 +1,6 @@ + + diff --git a/res/anim/umeng_xp_slide_out_from_top.xml b/res/anim/umeng_xp_slide_out_from_top.xml new file mode 100644 index 0000000..aec327f --- /dev/null +++ b/res/anim/umeng_xp_slide_out_from_top.xml @@ -0,0 +1,6 @@ + + diff --git a/res/anim/umeng_xp_zoom_in.xml b/res/anim/umeng_xp_zoom_in.xml new file mode 100644 index 0000000..7718be3 --- /dev/null +++ b/res/anim/umeng_xp_zoom_in.xml @@ -0,0 +1,34 @@ + + + + + + + + \ No newline at end of file diff --git a/res/anim/umeng_xp_zoom_out.xml b/res/anim/umeng_xp_zoom_out.xml new file mode 100644 index 0000000..a509d98 --- /dev/null +++ b/res/anim/umeng_xp_zoom_out.xml @@ -0,0 +1,41 @@ + + + + + + + + + + \ No newline at end of file diff --git a/res/drawable-hdpi/favorite.png b/res/drawable-hdpi/favorite.png new file mode 100644 index 0000000..7c25f35 Binary files /dev/null and b/res/drawable-hdpi/favorite.png differ diff --git a/res/drawable-hdpi/ic_more.png b/res/drawable-hdpi/ic_more.png new file mode 100644 index 0000000..6637993 Binary files /dev/null and b/res/drawable-hdpi/ic_more.png differ diff --git a/res/drawable-hdpi/list_divider.png b/res/drawable-hdpi/list_divider.png new file mode 100644 index 0000000..5541845 Binary files /dev/null and b/res/drawable-hdpi/list_divider.png differ diff --git a/res/drawable-hdpi/not_favorite.png b/res/drawable-hdpi/not_favorite.png new file mode 100644 index 0000000..c10325f Binary files /dev/null and b/res/drawable-hdpi/not_favorite.png differ diff --git a/res/drawable-hdpi/umeng_xp_ad_action_bg.9.png b/res/drawable-hdpi/umeng_xp_ad_action_bg.9.png new file mode 100644 index 0000000..1287e35 Binary files /dev/null and b/res/drawable-hdpi/umeng_xp_ad_action_bg.9.png differ diff --git a/res/drawable-hdpi/umeng_xp_ad_action_bg_clicked.9.png b/res/drawable-hdpi/umeng_xp_ad_action_bg_clicked.9.png new file mode 100644 index 0000000..6d4afce Binary files /dev/null and b/res/drawable-hdpi/umeng_xp_ad_action_bg_clicked.9.png differ diff --git a/res/drawable-hdpi/umeng_xp_ad_action_bg_selector.xml b/res/drawable-hdpi/umeng_xp_ad_action_bg_selector.xml new file mode 100644 index 0000000..7bd7d72 --- /dev/null +++ b/res/drawable-hdpi/umeng_xp_ad_action_bg_selector.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/res/drawable-hdpi/umeng_xp_ad_action_browse.png b/res/drawable-hdpi/umeng_xp_ad_action_browse.png new file mode 100644 index 0000000..17c2378 Binary files /dev/null and b/res/drawable-hdpi/umeng_xp_ad_action_browse.png differ diff --git a/res/drawable-hdpi/umeng_xp_ad_action_browse_clicked.png b/res/drawable-hdpi/umeng_xp_ad_action_browse_clicked.png new file mode 100644 index 0000000..e6b91e8 Binary files /dev/null and b/res/drawable-hdpi/umeng_xp_ad_action_browse_clicked.png differ diff --git a/res/drawable-hdpi/umeng_xp_ad_action_browse_selector.xml b/res/drawable-hdpi/umeng_xp_ad_action_browse_selector.xml new file mode 100644 index 0000000..e3d7b56 --- /dev/null +++ b/res/drawable-hdpi/umeng_xp_ad_action_browse_selector.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable-hdpi/umeng_xp_ad_action_download.png b/res/drawable-hdpi/umeng_xp_ad_action_download.png new file mode 100644 index 0000000..bdd0c79 Binary files /dev/null and b/res/drawable-hdpi/umeng_xp_ad_action_download.png differ diff --git a/res/drawable-hdpi/umeng_xp_ad_action_download_clicked.png b/res/drawable-hdpi/umeng_xp_ad_action_download_clicked.png new file mode 100644 index 0000000..6cd1942 Binary files /dev/null and b/res/drawable-hdpi/umeng_xp_ad_action_download_clicked.png differ diff --git a/res/drawable-hdpi/umeng_xp_ad_action_download_selector.xml b/res/drawable-hdpi/umeng_xp_ad_action_download_selector.xml new file mode 100644 index 0000000..1154800 --- /dev/null +++ b/res/drawable-hdpi/umeng_xp_ad_action_download_selector.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable-hdpi/umeng_xp_ad_action_open.png b/res/drawable-hdpi/umeng_xp_ad_action_open.png new file mode 100644 index 0000000..9979372 Binary files /dev/null and b/res/drawable-hdpi/umeng_xp_ad_action_open.png differ diff --git a/res/drawable-hdpi/umeng_xp_ad_action_open_clicked.png b/res/drawable-hdpi/umeng_xp_ad_action_open_clicked.png new file mode 100644 index 0000000..7286e49 Binary files /dev/null and b/res/drawable-hdpi/umeng_xp_ad_action_open_clicked.png differ diff --git a/res/drawable-hdpi/umeng_xp_ad_action_open_selector.xml b/res/drawable-hdpi/umeng_xp_ad_action_open_selector.xml new file mode 100644 index 0000000..9c661f8 --- /dev/null +++ b/res/drawable-hdpi/umeng_xp_ad_action_open_selector.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable-hdpi/umeng_xp_ad_action_phone.png b/res/drawable-hdpi/umeng_xp_ad_action_phone.png new file mode 100644 index 0000000..c539ffa Binary files /dev/null and b/res/drawable-hdpi/umeng_xp_ad_action_phone.png differ diff --git a/res/drawable-hdpi/umeng_xp_ad_action_phone_clicked.png b/res/drawable-hdpi/umeng_xp_ad_action_phone_clicked.png new file mode 100644 index 0000000..4bd27be Binary files /dev/null and b/res/drawable-hdpi/umeng_xp_ad_action_phone_clicked.png differ diff --git a/res/drawable-hdpi/umeng_xp_ad_action_phone_selector.xml b/res/drawable-hdpi/umeng_xp_ad_action_phone_selector.xml new file mode 100644 index 0000000..0ace1a1 --- /dev/null +++ b/res/drawable-hdpi/umeng_xp_ad_action_phone_selector.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/res/drawable-hdpi/umeng_xp_back.png b/res/drawable-hdpi/umeng_xp_back.png new file mode 100644 index 0000000..3c5499d Binary files /dev/null and b/res/drawable-hdpi/umeng_xp_back.png differ diff --git a/res/drawable-hdpi/umeng_xp_back_button.xml b/res/drawable-hdpi/umeng_xp_back_button.xml new file mode 100644 index 0000000..9a9dd90 --- /dev/null +++ b/res/drawable-hdpi/umeng_xp_back_button.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/res/drawable-hdpi/umeng_xp_back_button_normal.png b/res/drawable-hdpi/umeng_xp_back_button_normal.png new file mode 100644 index 0000000..5faa236 Binary files /dev/null and b/res/drawable-hdpi/umeng_xp_back_button_normal.png differ diff --git a/res/drawable-hdpi/umeng_xp_back_button_selected.png b/res/drawable-hdpi/umeng_xp_back_button_selected.png new file mode 100644 index 0000000..eda6d35 Binary files /dev/null and b/res/drawable-hdpi/umeng_xp_back_button_selected.png differ diff --git a/res/drawable-hdpi/umeng_xp_back_click.png b/res/drawable-hdpi/umeng_xp_back_click.png new file mode 100644 index 0000000..23ed17d Binary files /dev/null and b/res/drawable-hdpi/umeng_xp_back_click.png differ diff --git a/res/drawable-hdpi/umeng_xp_banner_grey.xml b/res/drawable-hdpi/umeng_xp_banner_grey.xml new file mode 100644 index 0000000..65b2d84 --- /dev/null +++ b/res/drawable-hdpi/umeng_xp_banner_grey.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/res/drawable-hdpi/umeng_xp_btn_gradient_dark_grey.xml b/res/drawable-hdpi/umeng_xp_btn_gradient_dark_grey.xml new file mode 100644 index 0000000..1799f8e --- /dev/null +++ b/res/drawable-hdpi/umeng_xp_btn_gradient_dark_grey.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/res/drawable-hdpi/umeng_xp_btn_gradient_grey.xml b/res/drawable-hdpi/umeng_xp_btn_gradient_grey.xml new file mode 100644 index 0000000..ebd531f --- /dev/null +++ b/res/drawable-hdpi/umeng_xp_btn_gradient_grey.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/res/drawable-hdpi/umeng_xp_button_cancel.9.png b/res/drawable-hdpi/umeng_xp_button_cancel.9.png new file mode 100644 index 0000000..df0b715 Binary files /dev/null and b/res/drawable-hdpi/umeng_xp_button_cancel.9.png differ diff --git a/res/drawable-hdpi/umeng_xp_button_cancel_click.9.png b/res/drawable-hdpi/umeng_xp_button_cancel_click.9.png new file mode 100644 index 0000000..52fc7c9 Binary files /dev/null and b/res/drawable-hdpi/umeng_xp_button_cancel_click.9.png differ diff --git a/res/drawable-hdpi/umeng_xp_button_cancel_selector.xml b/res/drawable-hdpi/umeng_xp_button_cancel_selector.xml new file mode 100644 index 0000000..22c3a7d --- /dev/null +++ b/res/drawable-hdpi/umeng_xp_button_cancel_selector.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/res/drawable-hdpi/umeng_xp_button_download.9.png b/res/drawable-hdpi/umeng_xp_button_download.9.png new file mode 100644 index 0000000..a050813 Binary files /dev/null and b/res/drawable-hdpi/umeng_xp_button_download.9.png differ diff --git a/res/drawable-hdpi/umeng_xp_button_download_click.9.png b/res/drawable-hdpi/umeng_xp_button_download_click.9.png new file mode 100644 index 0000000..e1ca04d Binary files /dev/null and b/res/drawable-hdpi/umeng_xp_button_download_click.9.png differ diff --git a/res/drawable-hdpi/umeng_xp_button_download_selector.xml b/res/drawable-hdpi/umeng_xp_button_download_selector.xml new file mode 100644 index 0000000..49e6e7e --- /dev/null +++ b/res/drawable-hdpi/umeng_xp_button_download_selector.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/res/drawable-hdpi/umeng_xp_container_banner_background_selector.xml b/res/drawable-hdpi/umeng_xp_container_banner_background_selector.xml new file mode 100644 index 0000000..0882ec7 --- /dev/null +++ b/res/drawable-hdpi/umeng_xp_container_banner_background_selector.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/res/drawable-hdpi/umeng_xp_darkbg.png b/res/drawable-hdpi/umeng_xp_darkbg.png new file mode 100644 index 0000000..9a2e188 Binary files /dev/null and b/res/drawable-hdpi/umeng_xp_darkbg.png differ diff --git a/res/drawable-hdpi/umeng_xp_detail.png b/res/drawable-hdpi/umeng_xp_detail.png new file mode 100644 index 0000000..5bed77b Binary files /dev/null and b/res/drawable-hdpi/umeng_xp_detail.png differ diff --git a/res/drawable-hdpi/umeng_xp_detail365.png b/res/drawable-hdpi/umeng_xp_detail365.png new file mode 100644 index 0000000..5cf720e Binary files /dev/null and b/res/drawable-hdpi/umeng_xp_detail365.png differ diff --git a/res/drawable-hdpi/umeng_xp_detail_bg.png b/res/drawable-hdpi/umeng_xp_detail_bg.png new file mode 100644 index 0000000..2af10fc Binary files /dev/null and b/res/drawable-hdpi/umeng_xp_detail_bg.png differ diff --git a/res/drawable-hdpi/umeng_xp_download_dialog_bg.png b/res/drawable-hdpi/umeng_xp_download_dialog_bg.png new file mode 100644 index 0000000..9773150 Binary files /dev/null and b/res/drawable-hdpi/umeng_xp_download_dialog_bg.png differ diff --git a/res/drawable-hdpi/umeng_xp_download_dialog_close.png b/res/drawable-hdpi/umeng_xp_download_dialog_close.png new file mode 100644 index 0000000..a83ee18 Binary files /dev/null and b/res/drawable-hdpi/umeng_xp_download_dialog_close.png differ diff --git a/res/drawable-hdpi/umeng_xp_download_dialog_close_clicked.png b/res/drawable-hdpi/umeng_xp_download_dialog_close_clicked.png new file mode 100644 index 0000000..5639027 Binary files /dev/null and b/res/drawable-hdpi/umeng_xp_download_dialog_close_clicked.png differ diff --git a/res/drawable-hdpi/umeng_xp_download_dialog_close_selector.xml b/res/drawable-hdpi/umeng_xp_download_dialog_close_selector.xml new file mode 100644 index 0000000..1be5ac9 --- /dev/null +++ b/res/drawable-hdpi/umeng_xp_download_dialog_close_selector.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable-hdpi/umeng_xp_download_gradient_grey.xml b/res/drawable-hdpi/umeng_xp_download_gradient_grey.xml new file mode 100644 index 0000000..b9a427c --- /dev/null +++ b/res/drawable-hdpi/umeng_xp_download_gradient_grey.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/res/drawable-hdpi/umeng_xp_gradient_grey.xml b/res/drawable-hdpi/umeng_xp_gradient_grey.xml new file mode 100644 index 0000000..ff6c705 --- /dev/null +++ b/res/drawable-hdpi/umeng_xp_gradient_grey.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/res/drawable-hdpi/umeng_xp_gradient_grey1.xml b/res/drawable-hdpi/umeng_xp_gradient_grey1.xml new file mode 100644 index 0000000..4da43f3 --- /dev/null +++ b/res/drawable-hdpi/umeng_xp_gradient_grey1.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/res/drawable-hdpi/umeng_xp_gradient_grey2.xml b/res/drawable-hdpi/umeng_xp_gradient_grey2.xml new file mode 100644 index 0000000..72fdd85 --- /dev/null +++ b/res/drawable-hdpi/umeng_xp_gradient_grey2.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/res/drawable-hdpi/umeng_xp_greenbg_selector.xml b/res/drawable-hdpi/umeng_xp_greenbg_selector.xml new file mode 100644 index 0000000..f86d900 --- /dev/null +++ b/res/drawable-hdpi/umeng_xp_greenbg_selector.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/res/drawable-hdpi/umeng_xp_handler_rc.png b/res/drawable-hdpi/umeng_xp_handler_rc.png new file mode 100644 index 0000000..0a5b1d5 Binary files /dev/null and b/res/drawable-hdpi/umeng_xp_handler_rc.png differ diff --git a/res/drawable-hdpi/umeng_xp_highlight_banner_background_selector.xml b/res/drawable-hdpi/umeng_xp_highlight_banner_background_selector.xml new file mode 100644 index 0000000..18138a3 --- /dev/null +++ b/res/drawable-hdpi/umeng_xp_highlight_banner_background_selector.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable-hdpi/umeng_xp_highlight_banner_bg.9.png b/res/drawable-hdpi/umeng_xp_highlight_banner_bg.9.png new file mode 100644 index 0000000..9d2e545 Binary files /dev/null and b/res/drawable-hdpi/umeng_xp_highlight_banner_bg.9.png differ diff --git a/res/drawable-hdpi/umeng_xp_highlight_footview_dashed_line.xml b/res/drawable-hdpi/umeng_xp_highlight_footview_dashed_line.xml new file mode 100644 index 0000000..e7e1591 --- /dev/null +++ b/res/drawable-hdpi/umeng_xp_highlight_footview_dashed_line.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/res/drawable-hdpi/umeng_xp_highlight_footview_loading.png b/res/drawable-hdpi/umeng_xp_highlight_footview_loading.png new file mode 100644 index 0000000..911230c Binary files /dev/null and b/res/drawable-hdpi/umeng_xp_highlight_footview_loading.png differ diff --git a/res/drawable-hdpi/umeng_xp_highlight_item_bg.9.png b/res/drawable-hdpi/umeng_xp_highlight_item_bg.9.png new file mode 100644 index 0000000..77b5eab Binary files /dev/null and b/res/drawable-hdpi/umeng_xp_highlight_item_bg.9.png differ diff --git a/res/drawable-hdpi/umeng_xp_highlight_item_bg_clicked.9.png b/res/drawable-hdpi/umeng_xp_highlight_item_bg_clicked.9.png new file mode 100644 index 0000000..63155d8 Binary files /dev/null and b/res/drawable-hdpi/umeng_xp_highlight_item_bg_clicked.9.png differ diff --git a/res/drawable-hdpi/umeng_xp_highlight_item_bg_selector.xml b/res/drawable-hdpi/umeng_xp_highlight_item_bg_selector.xml new file mode 100644 index 0000000..ad46ff2 --- /dev/null +++ b/res/drawable-hdpi/umeng_xp_highlight_item_bg_selector.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable-hdpi/umeng_xp_horizontal_divider.xml b/res/drawable-hdpi/umeng_xp_horizontal_divider.xml new file mode 100644 index 0000000..319d73b --- /dev/null +++ b/res/drawable-hdpi/umeng_xp_horizontal_divider.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/res/drawable-hdpi/umeng_xp_icon_background.png b/res/drawable-hdpi/umeng_xp_icon_background.png new file mode 100644 index 0000000..4d5f7ce Binary files /dev/null and b/res/drawable-hdpi/umeng_xp_icon_background.png differ diff --git a/res/drawable-hdpi/umeng_xp_icon_background_clicked.png b/res/drawable-hdpi/umeng_xp_icon_background_clicked.png new file mode 100644 index 0000000..337721b Binary files /dev/null and b/res/drawable-hdpi/umeng_xp_icon_background_clicked.png differ diff --git a/res/drawable-hdpi/umeng_xp_icon_background_selector.xml b/res/drawable-hdpi/umeng_xp_icon_background_selector.xml new file mode 100644 index 0000000..a485797 --- /dev/null +++ b/res/drawable-hdpi/umeng_xp_icon_background_selector.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable-hdpi/umeng_xp_kaijuan_bg.xml b/res/drawable-hdpi/umeng_xp_kaijuan_bg.xml new file mode 100644 index 0000000..54d366f --- /dev/null +++ b/res/drawable-hdpi/umeng_xp_kaijuan_bg.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/res/drawable-hdpi/umeng_xp_large_gallery_failed.jpg b/res/drawable-hdpi/umeng_xp_large_gallery_failed.jpg new file mode 100644 index 0000000..443f4d5 Binary files /dev/null and b/res/drawable-hdpi/umeng_xp_large_gallery_failed.jpg differ diff --git a/res/drawable-hdpi/umeng_xp_large_gallery_item_bg.xml b/res/drawable-hdpi/umeng_xp_large_gallery_item_bg.xml new file mode 100644 index 0000000..4af0c3a --- /dev/null +++ b/res/drawable-hdpi/umeng_xp_large_gallery_item_bg.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/res/drawable-hdpi/umeng_xp_link_radius_shape.xml b/res/drawable-hdpi/umeng_xp_link_radius_shape.xml new file mode 100644 index 0000000..fcddc6a --- /dev/null +++ b/res/drawable-hdpi/umeng_xp_link_radius_shape.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable-hdpi/umeng_xp_list_item_text_selector.xml b/res/drawable-hdpi/umeng_xp_list_item_text_selector.xml new file mode 100644 index 0000000..e5f3318 --- /dev/null +++ b/res/drawable-hdpi/umeng_xp_list_item_text_selector.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable-hdpi/umeng_xp_loading.png b/res/drawable-hdpi/umeng_xp_loading.png new file mode 100644 index 0000000..fb7e024 Binary files /dev/null and b/res/drawable-hdpi/umeng_xp_loading.png differ diff --git a/res/drawable-hdpi/umeng_xp_loading_seek.xml b/res/drawable-hdpi/umeng_xp_loading_seek.xml new file mode 100644 index 0000000..171a6b7 --- /dev/null +++ b/res/drawable-hdpi/umeng_xp_loading_seek.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/res/drawable-hdpi/umeng_xp_more_bottom.9.png b/res/drawable-hdpi/umeng_xp_more_bottom.9.png new file mode 100644 index 0000000..21af98b Binary files /dev/null and b/res/drawable-hdpi/umeng_xp_more_bottom.9.png differ diff --git a/res/drawable-hdpi/umeng_xp_more_top.9.png b/res/drawable-hdpi/umeng_xp_more_top.9.png new file mode 100644 index 0000000..3b1ed0b Binary files /dev/null and b/res/drawable-hdpi/umeng_xp_more_top.9.png differ diff --git a/res/drawable-hdpi/umeng_xp_new_tip.png b/res/drawable-hdpi/umeng_xp_new_tip.png new file mode 100644 index 0000000..d039017 Binary files /dev/null and b/res/drawable-hdpi/umeng_xp_new_tip.png differ diff --git a/res/drawable-hdpi/umeng_xp_new_tip_bg.png b/res/drawable-hdpi/umeng_xp_new_tip_bg.png new file mode 100644 index 0000000..30ddc1a Binary files /dev/null and b/res/drawable-hdpi/umeng_xp_new_tip_bg.png differ diff --git a/res/drawable-hdpi/umeng_xp_new_tip_button.png b/res/drawable-hdpi/umeng_xp_new_tip_button.png new file mode 100644 index 0000000..d039017 Binary files /dev/null and b/res/drawable-hdpi/umeng_xp_new_tip_button.png differ diff --git a/res/drawable-hdpi/umeng_xp_normal_banner_background_selector.xml b/res/drawable-hdpi/umeng_xp_normal_banner_background_selector.xml new file mode 100644 index 0000000..abb551b --- /dev/null +++ b/res/drawable-hdpi/umeng_xp_normal_banner_background_selector.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable-hdpi/umeng_xp_point_normal.png b/res/drawable-hdpi/umeng_xp_point_normal.png new file mode 100644 index 0000000..6a924c5 Binary files /dev/null and b/res/drawable-hdpi/umeng_xp_point_normal.png differ diff --git a/res/drawable-hdpi/umeng_xp_point_selected.png b/res/drawable-hdpi/umeng_xp_point_selected.png new file mode 100644 index 0000000..faad26a Binary files /dev/null and b/res/drawable-hdpi/umeng_xp_point_selected.png differ diff --git a/res/drawable-hdpi/umeng_xp_progressbar.xml b/res/drawable-hdpi/umeng_xp_progressbar.xml new file mode 100644 index 0000000..197cc6a --- /dev/null +++ b/res/drawable-hdpi/umeng_xp_progressbar.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/res/drawable-hdpi/umeng_xp_radius_shape.xml b/res/drawable-hdpi/umeng_xp_radius_shape.xml new file mode 100644 index 0000000..969d3c3 --- /dev/null +++ b/res/drawable-hdpi/umeng_xp_radius_shape.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable-hdpi/umeng_xp_recommend_titile_bg.png b/res/drawable-hdpi/umeng_xp_recommend_titile_bg.png new file mode 100644 index 0000000..c7cd33f Binary files /dev/null and b/res/drawable-hdpi/umeng_xp_recommend_titile_bg.png differ diff --git a/res/drawable-hdpi/umeng_xp_recoright.png b/res/drawable-hdpi/umeng_xp_recoright.png new file mode 100644 index 0000000..31f7b2c Binary files /dev/null and b/res/drawable-hdpi/umeng_xp_recoright.png differ diff --git a/res/drawable-hdpi/umeng_xp_seek.png b/res/drawable-hdpi/umeng_xp_seek.png new file mode 100644 index 0000000..ea92e88 Binary files /dev/null and b/res/drawable-hdpi/umeng_xp_seek.png differ diff --git a/res/drawable-hdpi/umeng_xp_seek_bg.png b/res/drawable-hdpi/umeng_xp_seek_bg.png new file mode 100644 index 0000000..e4c71a1 Binary files /dev/null and b/res/drawable-hdpi/umeng_xp_seek_bg.png differ diff --git a/res/drawable-hdpi/umeng_xp_selector_back.xml b/res/drawable-hdpi/umeng_xp_selector_back.xml new file mode 100644 index 0000000..0d84962 --- /dev/null +++ b/res/drawable-hdpi/umeng_xp_selector_back.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/res/drawable-hdpi/umeng_xp_selector_cancel.xml b/res/drawable-hdpi/umeng_xp_selector_cancel.xml new file mode 100644 index 0000000..22c3a7d --- /dev/null +++ b/res/drawable-hdpi/umeng_xp_selector_cancel.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/res/drawable-hdpi/umeng_xp_selector_download.xml b/res/drawable-hdpi/umeng_xp_selector_download.xml new file mode 100644 index 0000000..49e6e7e --- /dev/null +++ b/res/drawable-hdpi/umeng_xp_selector_download.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/res/drawable-hdpi/umeng_xp_shadow_bg.9.png b/res/drawable-hdpi/umeng_xp_shadow_bg.9.png new file mode 100644 index 0000000..e18ad5c Binary files /dev/null and b/res/drawable-hdpi/umeng_xp_shadow_bg.9.png differ diff --git a/res/drawable-hdpi/umeng_xp_shape_conner_blackish_green.xml b/res/drawable-hdpi/umeng_xp_shape_conner_blackish_green.xml new file mode 100644 index 0000000..0abc7e7 --- /dev/null +++ b/res/drawable-hdpi/umeng_xp_shape_conner_blackish_green.xml @@ -0,0 +1,14 @@ + + + + + + + + \ No newline at end of file diff --git a/res/drawable-hdpi/umeng_xp_shape_conner_green.xml b/res/drawable-hdpi/umeng_xp_shape_conner_green.xml new file mode 100644 index 0000000..4653218 --- /dev/null +++ b/res/drawable-hdpi/umeng_xp_shape_conner_green.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/res/drawable-hdpi/umeng_xp_shape_gradient_blue.xml b/res/drawable-hdpi/umeng_xp_shape_gradient_blue.xml new file mode 100644 index 0000000..ef249ca --- /dev/null +++ b/res/drawable-hdpi/umeng_xp_shape_gradient_blue.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable-hdpi/umeng_xp_shape_gradient_blue_container.xml b/res/drawable-hdpi/umeng_xp_shape_gradient_blue_container.xml new file mode 100644 index 0000000..7e9a2c1 --- /dev/null +++ b/res/drawable-hdpi/umeng_xp_shape_gradient_blue_container.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable-hdpi/umeng_xp_shape_gradient_blue_v2.xml b/res/drawable-hdpi/umeng_xp_shape_gradient_blue_v2.xml new file mode 100644 index 0000000..6a9980f --- /dev/null +++ b/res/drawable-hdpi/umeng_xp_shape_gradient_blue_v2.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/res/drawable-hdpi/umeng_xp_shape_gradient_gray_stroke.xml b/res/drawable-hdpi/umeng_xp_shape_gradient_gray_stroke.xml new file mode 100644 index 0000000..3ba838d --- /dev/null +++ b/res/drawable-hdpi/umeng_xp_shape_gradient_gray_stroke.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/res/drawable-hdpi/umeng_xp_shape_gradient_grey_0.xml b/res/drawable-hdpi/umeng_xp_shape_gradient_grey_0.xml new file mode 100644 index 0000000..f6610b0 --- /dev/null +++ b/res/drawable-hdpi/umeng_xp_shape_gradient_grey_0.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/res/drawable-hdpi/umeng_xp_shape_gradient_grey_1.xml b/res/drawable-hdpi/umeng_xp_shape_gradient_grey_1.xml new file mode 100644 index 0000000..03f7f5a --- /dev/null +++ b/res/drawable-hdpi/umeng_xp_shape_gradient_grey_1.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/res/drawable-hdpi/umeng_xp_shape_gradient_grey_2.xml b/res/drawable-hdpi/umeng_xp_shape_gradient_grey_2.xml new file mode 100644 index 0000000..8073d46 --- /dev/null +++ b/res/drawable-hdpi/umeng_xp_shape_gradient_grey_2.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable-hdpi/umeng_xp_shape_gradient_grey_3.xml b/res/drawable-hdpi/umeng_xp_shape_gradient_grey_3.xml new file mode 100644 index 0000000..ce82e2b --- /dev/null +++ b/res/drawable-hdpi/umeng_xp_shape_gradient_grey_3.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable-hdpi/umeng_xp_shape_gradient_grey_4.xml b/res/drawable-hdpi/umeng_xp_shape_gradient_grey_4.xml new file mode 100644 index 0000000..ef249ca --- /dev/null +++ b/res/drawable-hdpi/umeng_xp_shape_gradient_grey_4.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable-hdpi/umeng_xp_shape_gradient_grey_5.xml b/res/drawable-hdpi/umeng_xp_shape_gradient_grey_5.xml new file mode 100644 index 0000000..c459a37 --- /dev/null +++ b/res/drawable-hdpi/umeng_xp_shape_gradient_grey_5.xml @@ -0,0 +1,12 @@ + + + + + + + + \ No newline at end of file diff --git a/res/drawable-hdpi/umeng_xp_shape_gradient_grey_7.xml b/res/drawable-hdpi/umeng_xp_shape_gradient_grey_7.xml new file mode 100644 index 0000000..f0b0ada --- /dev/null +++ b/res/drawable-hdpi/umeng_xp_shape_gradient_grey_7.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/res/drawable-hdpi/umeng_xp_shape_gradient_grey_list.xml b/res/drawable-hdpi/umeng_xp_shape_gradient_grey_list.xml new file mode 100644 index 0000000..e8b5b91 --- /dev/null +++ b/res/drawable-hdpi/umeng_xp_shape_gradient_grey_list.xml @@ -0,0 +1,16 @@ + + + + + + + + + + \ No newline at end of file diff --git a/res/drawable-hdpi/umeng_xp_shape_grey.xml b/res/drawable-hdpi/umeng_xp_shape_grey.xml new file mode 100644 index 0000000..832b5fb --- /dev/null +++ b/res/drawable-hdpi/umeng_xp_shape_grey.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable-hdpi/umeng_xp_standalone_bg.9.png b/res/drawable-hdpi/umeng_xp_standalone_bg.9.png new file mode 100644 index 0000000..f466ccf Binary files /dev/null and b/res/drawable-hdpi/umeng_xp_standalone_bg.9.png differ diff --git a/res/drawable-hdpi/umeng_xp_strock_bg_1.xml b/res/drawable-hdpi/umeng_xp_strock_bg_1.xml new file mode 100644 index 0000000..62adcb5 --- /dev/null +++ b/res/drawable-hdpi/umeng_xp_strock_bg_1.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/res/drawable-hdpi/umeng_xp_vertical_divider.xml b/res/drawable-hdpi/umeng_xp_vertical_divider.xml new file mode 100644 index 0000000..92470b4 --- /dev/null +++ b/res/drawable-hdpi/umeng_xp_vertical_divider.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/res/drawable-hdpi/umeng_xp_x_button.png b/res/drawable-hdpi/umeng_xp_x_button.png new file mode 100644 index 0000000..62535e2 Binary files /dev/null and b/res/drawable-hdpi/umeng_xp_x_button.png differ diff --git a/res/drawable-hdpi/umeng_xp_x_button_clicked.png b/res/drawable-hdpi/umeng_xp_x_button_clicked.png new file mode 100644 index 0000000..cb5180f Binary files /dev/null and b/res/drawable-hdpi/umeng_xp_x_button_clicked.png differ diff --git a/res/drawable-hdpi/umeng_xp_x_button_selector.xml b/res/drawable-hdpi/umeng_xp_x_button_selector.xml new file mode 100644 index 0000000..eb7c8ac --- /dev/null +++ b/res/drawable-hdpi/umeng_xp_x_button_selector.xml @@ -0,0 +1,8 @@ + + + + + + \ No newline at end of file diff --git a/res/drawable-hdpi/umeng_xp_zhanwei.png b/res/drawable-hdpi/umeng_xp_zhanwei.png new file mode 100644 index 0000000..df869fd Binary files /dev/null and b/res/drawable-hdpi/umeng_xp_zhanwei.png differ diff --git a/res/drawable-hdpi/upbar_back.png b/res/drawable-hdpi/upbar_back.png new file mode 100644 index 0000000..4c5dab8 Binary files /dev/null and b/res/drawable-hdpi/upbar_back.png differ diff --git a/res/drawable/btn_bg_normal_color.xml b/res/drawable/btn_bg_normal_color.xml new file mode 100644 index 0000000..cce47dc --- /dev/null +++ b/res/drawable/btn_bg_normal_color.xml @@ -0,0 +1,5 @@ + + + + diff --git a/res/drawable/btn_bg_pressed_color.xml b/res/drawable/btn_bg_pressed_color.xml new file mode 100644 index 0000000..30264ae --- /dev/null +++ b/res/drawable/btn_bg_pressed_color.xml @@ -0,0 +1,5 @@ + + + + diff --git a/res/drawable/button_bg_selector.xml b/res/drawable/button_bg_selector.xml new file mode 100644 index 0000000..c76c19c --- /dev/null +++ b/res/drawable/button_bg_selector.xml @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/res/drawable/ic_logo.png b/res/drawable/ic_logo.png new file mode 100644 index 0000000..bdb919e Binary files /dev/null and b/res/drawable/ic_logo.png differ diff --git a/res/drawable/icon.png b/res/drawable/icon.png deleted file mode 100644 index c866b66..0000000 Binary files a/res/drawable/icon.png and /dev/null differ diff --git a/res/drawable/umeng_common_gradient_green.xml b/res/drawable/umeng_common_gradient_green.xml new file mode 100644 index 0000000..3290fc4 --- /dev/null +++ b/res/drawable/umeng_common_gradient_green.xml @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/res/drawable/umeng_common_gradient_orange.xml b/res/drawable/umeng_common_gradient_orange.xml new file mode 100644 index 0000000..bd62c66 --- /dev/null +++ b/res/drawable/umeng_common_gradient_orange.xml @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/res/drawable/umeng_common_gradient_red.xml b/res/drawable/umeng_common_gradient_red.xml new file mode 100644 index 0000000..3b010c4 --- /dev/null +++ b/res/drawable/umeng_common_gradient_red.xml @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/res/drawable/umeng_fb_bar_bg.9.png b/res/drawable/umeng_fb_bar_bg.9.png new file mode 100644 index 0000000..52e66b4 Binary files /dev/null and b/res/drawable/umeng_fb_bar_bg.9.png differ diff --git a/res/drawable/umeng_fb_blank_selector.xml b/res/drawable/umeng_fb_blank_selector.xml new file mode 100644 index 0000000..c8888da --- /dev/null +++ b/res/drawable/umeng_fb_blank_selector.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/res/drawable/umeng_fb_bottom_banner.xml b/res/drawable/umeng_fb_bottom_banner.xml new file mode 100644 index 0000000..0716893 --- /dev/null +++ b/res/drawable/umeng_fb_bottom_banner.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/res/drawable/umeng_fb_dev_bubble.9.png b/res/drawable/umeng_fb_dev_bubble.9.png new file mode 100644 index 0000000..9f66244 Binary files /dev/null and b/res/drawable/umeng_fb_dev_bubble.9.png differ diff --git a/res/drawable/umeng_fb_gradient_green.xml b/res/drawable/umeng_fb_gradient_green.xml new file mode 100644 index 0000000..3290fc4 --- /dev/null +++ b/res/drawable/umeng_fb_gradient_green.xml @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/res/drawable/umeng_fb_gradient_orange.xml b/res/drawable/umeng_fb_gradient_orange.xml new file mode 100644 index 0000000..bd62c66 --- /dev/null +++ b/res/drawable/umeng_fb_gradient_orange.xml @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/res/drawable/umeng_fb_gray_frame.xml b/res/drawable/umeng_fb_gray_frame.xml new file mode 100644 index 0000000..daf2745 --- /dev/null +++ b/res/drawable/umeng_fb_gray_frame.xml @@ -0,0 +1,9 @@ + + + + + + + \ No newline at end of file diff --git a/res/drawable/umeng_fb_list_item.9.png b/res/drawable/umeng_fb_list_item.9.png new file mode 100644 index 0000000..963896a Binary files /dev/null and b/res/drawable/umeng_fb_list_item.9.png differ diff --git a/res/drawable/umeng_fb_list_item_pressed.9.png b/res/drawable/umeng_fb_list_item_pressed.9.png new file mode 100644 index 0000000..fe6731e Binary files /dev/null and b/res/drawable/umeng_fb_list_item_pressed.9.png differ diff --git a/res/drawable/umeng_fb_list_item_selector.xml b/res/drawable/umeng_fb_list_item_selector.xml new file mode 100644 index 0000000..c5e904c --- /dev/null +++ b/res/drawable/umeng_fb_list_item_selector.xml @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/res/drawable/umeng_fb_point_new.xml b/res/drawable/umeng_fb_point_new.xml new file mode 100644 index 0000000..c9cb154 --- /dev/null +++ b/res/drawable/umeng_fb_point_new.xml @@ -0,0 +1,8 @@ + + + + + + \ No newline at end of file diff --git a/res/drawable/umeng_fb_point_normal.xml b/res/drawable/umeng_fb_point_normal.xml new file mode 100644 index 0000000..903c900 --- /dev/null +++ b/res/drawable/umeng_fb_point_normal.xml @@ -0,0 +1,8 @@ + + + + + + \ No newline at end of file diff --git a/res/drawable/umeng_fb_see_list_normal.png b/res/drawable/umeng_fb_see_list_normal.png new file mode 100644 index 0000000..d5f6607 Binary files /dev/null and b/res/drawable/umeng_fb_see_list_normal.png differ diff --git a/res/drawable/umeng_fb_see_list_pressed.png b/res/drawable/umeng_fb_see_list_pressed.png new file mode 100644 index 0000000..d2bc4cb Binary files /dev/null and b/res/drawable/umeng_fb_see_list_pressed.png differ diff --git a/res/drawable/umeng_fb_see_list_selector.xml b/res/drawable/umeng_fb_see_list_selector.xml new file mode 100644 index 0000000..ff7bf9c --- /dev/null +++ b/res/drawable/umeng_fb_see_list_selector.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/res/drawable/umeng_fb_statusbar_icon.png b/res/drawable/umeng_fb_statusbar_icon.png new file mode 100644 index 0000000..4f2b82c Binary files /dev/null and b/res/drawable/umeng_fb_statusbar_icon.png differ diff --git a/res/drawable/umeng_fb_submit_selector.xml b/res/drawable/umeng_fb_submit_selector.xml new file mode 100644 index 0000000..0d75bf4 --- /dev/null +++ b/res/drawable/umeng_fb_submit_selector.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/res/drawable/umeng_fb_top_banner.xml b/res/drawable/umeng_fb_top_banner.xml new file mode 100644 index 0000000..529f0c3 --- /dev/null +++ b/res/drawable/umeng_fb_top_banner.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/res/drawable/umeng_fb_user_bubble.9.png b/res/drawable/umeng_fb_user_bubble.9.png new file mode 100644 index 0000000..13b75ad Binary files /dev/null and b/res/drawable/umeng_fb_user_bubble.9.png differ diff --git a/res/drawable/umeng_fb_write_normal.png b/res/drawable/umeng_fb_write_normal.png new file mode 100644 index 0000000..b62be96 Binary files /dev/null and b/res/drawable/umeng_fb_write_normal.png differ diff --git a/res/drawable/umeng_fb_write_pressed.png b/res/drawable/umeng_fb_write_pressed.png new file mode 100644 index 0000000..e30fd23 Binary files /dev/null and b/res/drawable/umeng_fb_write_pressed.png differ diff --git a/res/drawable/umeng_fb_write_selector.xml b/res/drawable/umeng_fb_write_selector.xml new file mode 100644 index 0000000..e6d75ec --- /dev/null +++ b/res/drawable/umeng_fb_write_selector.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/layout-hdpi/listitem_content.xml b/res/layout-hdpi/listitem_content.xml index 1943ae9..befb4e7 100644 --- a/res/layout-hdpi/listitem_content.xml +++ b/res/layout-hdpi/listitem_content.xml @@ -1,24 +1,31 @@ - + + + android:layout_marginLeft="6dip" + android:layout_marginRight="2dip" + android:layout_toLeftOf="@android:id/icon" + android:gravity="top" + android:textAppearance="?android:attr/textAppearanceSmall" + android:textColor="@color/content_black" /> + + android:singleLine="true" + android:textColor="@color/content_black" /> + + android:id="@android:id/icon" + android:layout_width="30dip" + android:layout_height="30dip" + android:layout_alignTop="@android:id/text1" + android:layout_alignParentRight="true" /> + \ No newline at end of file diff --git a/res/layout-v11/feedsettings.xml b/res/layout-v11/feedsettings.xml deleted file mode 100644 index 5213007..0000000 --- a/res/layout-v11/feedsettings.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/res/layout/umeng_xp_container_banner.xml b/res/layout/umeng_xp_container_banner.xml new file mode 100644 index 0000000..a54d957 --- /dev/null +++ b/res/layout/umeng_xp_container_banner.xml @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/res/layout/umeng_xp_download_dialog_landscape.xml b/res/layout/umeng_xp_download_dialog_landscape.xml new file mode 100644 index 0000000..133a7e1 --- /dev/null +++ b/res/layout/umeng_xp_download_dialog_landscape.xml @@ -0,0 +1,151 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/res/layout/umeng_xp_full_screen_list_layout.xml b/res/layout/umeng_xp_full_screen_list_layout.xml new file mode 100644 index 0000000..d039882 --- /dev/null +++ b/res/layout/umeng_xp_full_screen_list_layout.xml @@ -0,0 +1,20 @@ + + + + + \ No newline at end of file diff --git a/res/layout/umeng_xp_handler_gallery.xml b/res/layout/umeng_xp_handler_gallery.xml new file mode 100644 index 0000000..855e963 --- /dev/null +++ b/res/layout/umeng_xp_handler_gallery.xml @@ -0,0 +1,20 @@ + + + + + + + + \ No newline at end of file diff --git a/res/layout/umeng_xp_handler_grid_item.xml b/res/layout/umeng_xp_handler_grid_item.xml new file mode 100644 index 0000000..729acc2 --- /dev/null +++ b/res/layout/umeng_xp_handler_grid_item.xml @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + diff --git a/res/layout/umeng_xp_handler_template.xml b/res/layout/umeng_xp_handler_template.xml new file mode 100644 index 0000000..dd905ab --- /dev/null +++ b/res/layout/umeng_xp_handler_template.xml @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/res/layout/umeng_xp_highlight_banner.xml b/res/layout/umeng_xp_highlight_banner.xml new file mode 100644 index 0000000..59ea85b --- /dev/null +++ b/res/layout/umeng_xp_highlight_banner.xml @@ -0,0 +1,152 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/res/layout/widgetconfig.xml b/res/layout/widgetconfig.xml index a905460..713805d 100644 --- a/res/layout/widgetconfig.xml +++ b/res/layout/widgetconfig.xml @@ -9,7 +9,10 @@ android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_gravity="fill" - android:layout_weight="1"/> + android:layout_weight="1" + android:background="@color/common_bg_gray" + android:cacheColorHint="@color/common_bg_gray" + android:divider="@drawable/list_divider"/> - - - - - + + + + + + diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml index 1f7318d..5deeb16 100644 --- a/res/values-de/strings.xml +++ b/res/values-de/strings.xml @@ -8,7 +8,7 @@ Löschen Favoriten - Diese Software ist unter der MIT Open source Lizenz veröffentlicht und der Quellcode befindet sich unter http://code.google.com/p/sparserss + Diese Software ist unter der MIT Open source Lizenz veröffentlicht und der Quellcode befindet sich unter http://code.google.com/p/MiniRSS Feed bearbeiten Neuer Feed @@ -79,9 +79,7 @@ Anzahl an Einträgen die im Widget gezeigt werden Hintergrund Farbe und Transparenz des Widgethintergrundes - Zeige Tabs - Zusätzliche Tabs für Favoriten und alle Einträge - + Netzwerk Standard user-agent Benutze den Standard-user-agent Namen diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml index 89f74de..0148584 100644 --- a/res/values-es/strings.xml +++ b/res/values-es/strings.xml @@ -23,7 +23,7 @@ Ordenar activar Ordenar off - Este software se distribuye bajo licencia de código abierto MIT y el código fuente está disponible en http://code.google.com/p/sparserss + Este software se distribuye bajo licencia de código abierto MIT y el código fuente está disponible en http://code.google.com/p/MiniRSS Ajustes de actualizaciones Habilitar @@ -57,8 +57,6 @@ Ocultar entradas desde el widget si han sido leídas Ajuste de entrada Ver canales - Visualizar pestañas - Añadir pestañas para favoritos y todos los canales Red Solo Wi-Fi Utilizar proxy solo para Wi-Fi diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml index 9645b9e..7c29814 100644 --- a/res/values-fr/strings.xml +++ b/res/values-fr/strings.xml @@ -26,7 +26,7 @@ Désactiver le tri des flux Partager - Ce logiciel est distribué sous licence libre MIT et son code source est disponible sur http://code.google.com/p/sparserss + Ce logiciel est distribué sous licence libre MIT et son code source est disponible sur http://code.google.com/p/MiniRSS Actualisation automatique Activée @@ -72,10 +72,7 @@ Nombre d\'entrées à afficher dans le widget Arrière-plan Couleur et transparence de l\'arrière-plan du widget - Montrer les onglets - Onglets additionnels pour les favoris et l\'ensemble des flux - - Réseau + Réseau Suivre les redirections http <-> https Suivre automatiquement les redirections http vers https et vice versa Analyse de flux efficace diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml index 76f6e8c..102b36f 100644 --- a/res/values-ja/strings.xml +++ b/res/values-ja/strings.xml @@ -8,7 +8,7 @@ 消去 お気に入り - このソフトウェアのライセンスは、MIT Licenseで公示されており、ソースコードは、http://code.google.com/p/sparserssにある + このソフトウェアのライセンスは、MIT Licenseで公示されており、ソースコードは、http://code.google.com/p/MiniRSSにある フィード編集 編集 @@ -76,9 +76,6 @@ ウィジェットに表示する記事数 背景 ウィジェットの背景の色と透明度 - タブを表示する - お気に入りと全ての記事のためのタブを追加 - ネットワーク 一般的なuser-agent 一般的なuser-agentの名前を使う diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml index 5e80599..9c9dcfc 100644 --- a/res/values-nl/strings.xml +++ b/res/values-nl/strings.xml @@ -23,7 +23,7 @@ Sorteer activeren Sort off - De software wordt verspreid onder de MIT open source licentie en de broncode is beschikbaar via http://code.google.com/p/sparserss + De software wordt verspreid onder de MIT open source licentie en de broncode is beschikbaar via http://code.google.com/p/MiniRSS Automatisch vernieuwen Aan @@ -53,9 +53,6 @@ Verberg items in de widget als ze gelezen zijn Artikel instellingen Zichtbare feeds - Bekijk Tabs - Additionele tabs voor favorieten en alle feed artikelen - nooit Bijwerken ongelezen diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml index 56bda7e..ceeb046 100644 --- a/res/values-ru/strings.xml +++ b/res/values-ru/strings.xml @@ -28,7 +28,7 @@ Завершить Отправить - This software is distributed under the MIT open source license and its source code is available under http://code.google.com/p/sparserss + This software is distributed under the MIT open source license and its source code is available under http://code.google.com/p/MiniRSS Также участвовали >> << Лицензия @@ -80,8 +80,6 @@ Количество новостей, отображаемых на виджете Фон Цвет и прозрачность фона виджета - Вкладки - Использовать интерфейс с вкладками Сеть Сменить user-agent diff --git a/res/values-se/strings.xml b/res/values-se/strings.xml index 31adf7f..fb63568 100644 --- a/res/values-se/strings.xml +++ b/res/values-se/strings.xml @@ -76,9 +76,6 @@ Antal poster som visas i widgeten Bakgrund Färg och transparens för widgetens bakgrund - Visa tabbar - Extra tabbar för favorit och alla feedposter - Nätverk Standard användaragent Använd namnet på standard användaragenten @@ -141,7 +138,7 @@ License Tips - + 1 minut 5 minuter 15 minuter diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml index 51ba5f2..6aace62 100644 --- a/res/values-tr/strings.xml +++ b/res/values-tr/strings.xml @@ -25,7 +25,7 @@ Besleme sıralamasını etkinleştir Besleme sıralamasını devre dışı bırak - Bu yazılım MIT özgür yazılım lisansı kapsamında yayınlanmıştır ve kaynak kodu şu adreste mevcuttur: http://code.google.com/p/sparserss + Bu yazılım MIT özgür yazılım lisansı kapsamında yayınlanmıştır ve kaynak kodu şu adreste mevcuttur: http://code.google.com/p/MiniRSS Otomatik tazeleme Etkin @@ -71,9 +71,6 @@ Widget üzerinde gösterilecek unsur sayısı Arka plan Widget arka planının rengi ve şeffaflığı - Sekmeleri göster - Favori ve tüm beslemeler için ek sekmeler - http <-> https yönlendirmelerini izle http\'den https\'e ve tersi yönlendirmeleri otomatik olarak izle diff --git a/res/values-v11/styles.xml b/res/values-v11/styles.xml deleted file mode 100644 index 26964e2..0000000 --- a/res/values-v11/styles.xml +++ /dev/null @@ -1,6 +0,0 @@ - - + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/res/values/umeng_common_strings.xml b/res/values/umeng_common_strings.xml new file mode 100644 index 0000000..6f1810a --- /dev/null +++ b/res/values/umeng_common_strings.xml @@ -0,0 +1,12 @@ + + + + The app is already in downloading list. + dowload interrupted. + Pause + Continue + Cancel + Downloading: + Please make sure you are connected to internet, download failed + Download Failed! + \ No newline at end of file diff --git a/res/values/umeng_fb_strings.xml b/res/values/umeng_fb_strings.xml new file mode 100644 index 0000000..19c59b7 --- /dev/null +++ b/res/values/umeng_fb_strings.xml @@ -0,0 +1,51 @@ + + + Please input your feedback. + Your content was over 140 characters. You\'ll have + to be more clever. + Fail,Press to resend + Sending… + Resending + Fail + Fail + Sending… + 发送失败,轻触以重发 + Fail,press to resend + Feedback + My Feedback + My Feedback + Every word you write will benefit us. + Input your suggestions here + Submit + Return + + Got it + See Detail + + + Age + <18 + 18~24 + 25~30 + 31~35 + 36~40 + 41~50 + 51~59 + >=60 + + + Gender + Male + Female + + View Thread + You\'ve got reply + Delete Thread + View Feedback + Delete Feedback + Resend Feedback + Delete message + Got new reply + Got new reply + Click to view + diff --git a/res/values/umeng_update_string.xml b/res/values/umeng_update_string.xml new file mode 100644 index 0000000..959833e --- /dev/null +++ b/res/values/umeng_update_string.xml @@ -0,0 +1,14 @@ + + + + Please make sure you are connected to internet,update failed + New version found + Latest version: + (Warning: Not WIFI Condition) + Update now + App updating + Not now + Updating... + The lastest version has been downloaded, install now ? + + \ No newline at end of file diff --git a/res/values/umeng_xp_strings.xml b/res/values/umeng_xp_strings.xml new file mode 100644 index 0000000..72c324a --- /dev/null +++ b/res/values/umeng_xp_strings.xml @@ -0,0 +1,22 @@ + + + + Size + open + browse + download + + Please make sure you are connected to internet, download failed + Top + more + Back + Featured + Download + Call + Download the app? + Failed loading... + 请先安装浏览器.. + Start download + Banner style is not supported for current version of SDK, please contact us for support. + + \ No newline at end of file diff --git a/res/values/umeng_xp_style.xml b/res/values/umeng_xp_style.xml new file mode 100644 index 0000000..02073d1 --- /dev/null +++ b/res/values/umeng_xp_style.xml @@ -0,0 +1,97 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/res/xml/widgetinfo.xml b/res/xml/widgetinfo.xml index 82536ff..247e7f0 100644 --- a/res/xml/widgetinfo.xml +++ b/res/xml/widgetinfo.xml @@ -1,7 +1,7 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/src/de/shandschuh/sparserss/ApplicationPreferencesActivity.java b/src/cn/eric/rss/ApplicationPreferencesActivity.java similarity index 69% rename from src/de/shandschuh/sparserss/ApplicationPreferencesActivity.java rename to src/cn/eric/rss/ApplicationPreferencesActivity.java index 1226a66..0626daa 100644 --- a/src/de/shandschuh/sparserss/ApplicationPreferencesActivity.java +++ b/src/cn/eric/rss/ApplicationPreferencesActivity.java @@ -23,7 +23,9 @@ * */ -package de.shandschuh.sparserss; +package cn.eric.rss; + +import com.umeng.analytics.MobclickAgent; import android.app.AlertDialog; import android.content.DialogInterface; @@ -37,18 +39,17 @@ import android.preference.Preference.OnPreferenceChangeListener; import android.preference.PreferenceActivity; import android.preference.PreferenceManager; -import de.shandschuh.sparserss.service.RefreshService; +import cn.eric.rss.R; +import cn.eric.rss.service.RefreshService; +import cn.eric.rss.utility.MyStrings; public class ApplicationPreferencesActivity extends PreferenceActivity { @Override protected void onCreate(Bundle savedInstanceState) { - if (MainTabActivity.isLightTheme(this)) { - setTheme(R.style.Theme_Light); - } super.onCreate(savedInstanceState); addPreferencesFromResource(R.layout.preferences); - Preference preference = (Preference) findPreference(Strings.SETTINGS_REFRESHENABLED); + Preference preference = (Preference) findPreference(MyStrings.SETTINGS_REFRESHENABLED); preference.setOnPreferenceChangeListener(new OnPreferenceChangeListener() { public boolean onPreferenceChange(Preference preference, Object newValue) { @@ -59,38 +60,15 @@ public void run() { } }.start(); } else { - getPreferences(MODE_PRIVATE).edit().putLong(Strings.PREFERENCE_LASTSCHEDULEDREFRESH, 0).commit(); + getPreferences(MODE_PRIVATE).edit().putLong(MyStrings.PREFERENCE_LASTSCHEDULEDREFRESH, 0).commit(); stopService(new Intent(ApplicationPreferencesActivity.this, RefreshService.class)); } return true; } }); - preference = (Preference) findPreference(Strings.SETTINGS_SHOWTABS); - preference.setOnPreferenceChangeListener(new OnPreferenceChangeListener() { - public boolean onPreferenceChange(Preference preference, Object newValue) { - if (MainTabActivity.INSTANCE != null ) { - MainTabActivity.INSTANCE.setTabWidgetVisible(Boolean.TRUE.equals(newValue)); - } - return true; - } - }); - - preference = (Preference) findPreference(Strings.SETTINGS_LIGHTTHEME); - preference.setOnPreferenceChangeListener(new OnPreferenceChangeListener() { - public boolean onPreferenceChange(Preference preference, Object newValue) { - Editor editor = PreferenceManager.getDefaultSharedPreferences(ApplicationPreferencesActivity.this).edit(); - - editor.putBoolean(Strings.SETTINGS_LIGHTTHEME, Boolean.TRUE.equals(newValue)); - editor.commit(); - android.os.Process.killProcess(android.os.Process.myPid()); - - // this return statement will never be reached - return true; - } - }); - - preference = (Preference) findPreference(Strings.SETTINGS_EFFICIENTFEEDPARSING); + + preference = (Preference) findPreference(MyStrings.SETTINGS_EFFICIENTFEEDPARSING); preference.setOnPreferenceChangeListener(new OnPreferenceChangeListener() { public boolean onPreferenceChange(final Preference preference, Object newValue) { if (newValue.equals(Boolean.FALSE)) { @@ -102,7 +80,7 @@ public boolean onPreferenceChange(final Preference preference, Object newValue) public void onClick(DialogInterface dialog, int which) { Editor editor = PreferenceManager.getDefaultSharedPreferences(ApplicationPreferencesActivity.this).edit(); - editor.putBoolean(Strings.SETTINGS_EFFICIENTFEEDPARSING, Boolean.FALSE); + editor.putBoolean(MyStrings.SETTINGS_EFFICIENTFEEDPARSING, Boolean.FALSE); editor.commit(); ((CheckBoxPreference) preference).setChecked(false); dialog.dismiss(); @@ -123,4 +101,16 @@ public void onClick(DialogInterface dialog, int which) { }); } + @Override + public void onResume() { + super.onResume(); + MobclickAgent.onResume(this); + } + + @Override + public void onPause() { + super.onPause(); + MobclickAgent.onPause(this); + } + } diff --git a/src/de/shandschuh/sparserss/BootCompletedBroadcastReceiver.java b/src/cn/eric/rss/BootCompletedBroadcastReceiver.java similarity index 81% rename from src/de/shandschuh/sparserss/BootCompletedBroadcastReceiver.java rename to src/cn/eric/rss/BootCompletedBroadcastReceiver.java index a7cfc6e..86b88ed 100644 --- a/src/de/shandschuh/sparserss/BootCompletedBroadcastReceiver.java +++ b/src/cn/eric/rss/BootCompletedBroadcastReceiver.java @@ -23,7 +23,7 @@ * */ -package de.shandschuh.sparserss; +package cn.eric.rss; import android.content.BroadcastReceiver; import android.content.Context; @@ -31,19 +31,20 @@ import android.content.SharedPreferences; import android.content.pm.PackageManager.NameNotFoundException; import android.preference.PreferenceManager; -import de.shandschuh.sparserss.service.RefreshService; +import cn.eric.rss.service.RefreshService; +import cn.eric.rss.utility.MyStrings; public class BootCompletedBroadcastReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { try { - SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context.createPackageContext(Strings.PACKAGE, 0)); + SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context.createPackageContext(MyStrings.PACKAGE, 0)); - preferences.edit().putLong(Strings.PREFERENCE_LASTSCHEDULEDREFRESH, 0).commit(); - if (preferences.getBoolean(Strings.SETTINGS_REFRESHENABLED, false)) { + preferences.edit().putLong(MyStrings.PREFERENCE_LASTSCHEDULEDREFRESH, 0).commit(); + if (preferences.getBoolean(MyStrings.SETTINGS_REFRESHENABLED, false)) { context.startService(new Intent(context, RefreshService.class)); } - context.sendBroadcast(new Intent(Strings.ACTION_UPDATEWIDGET)); + context.sendBroadcast(new Intent(MyStrings.ACTION_UPDATEWIDGET)); } catch (NameNotFoundException e) { } } diff --git a/src/de/shandschuh/sparserss/CompatibilityHelper.java b/src/cn/eric/rss/CompatibilityHelper.java similarity index 95% rename from src/de/shandschuh/sparserss/CompatibilityHelper.java rename to src/cn/eric/rss/CompatibilityHelper.java index f1df90e..dfd492a 100644 --- a/src/de/shandschuh/sparserss/CompatibilityHelper.java +++ b/src/cn/eric/rss/CompatibilityHelper.java @@ -1,71 +1,72 @@ -/** - * Sparse rss - * - * Copyright (c) 2012 Stefan Handschuh - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * - * ============================================================================== - * This helper class is needed for older Android versions that verify all - * existing references on startup. - */ - -package de.shandschuh.sparserss; - -import android.app.Activity; -import android.graphics.drawable.Drawable; -import android.webkit.WebView; - -public class CompatibilityHelper { - private static final String METHOD_GETACTIONBAR = "getActionBar"; - - private static final String METHOD_SETICON = "setIcon"; - - private static final String METHOD_ONRESUME = "onResume"; - - private static final String METHOD_ONPAUSE = "onPause"; - - public static void setActionBarDrawable(Activity activity, Drawable drawable) { - try { - Object actionBar = Activity.class.getMethod(METHOD_GETACTIONBAR).invoke(activity); - - actionBar.getClass().getMethod(METHOD_SETICON, Drawable.class).invoke(actionBar, drawable); - } catch (Exception e) { - - } - - } - - public static void onResume(WebView webView) { - try { - WebView.class.getMethod(METHOD_ONRESUME).invoke(webView); - } catch (Exception e) { - - } - } - - public static void onPause(WebView webView) { - try { - WebView.class.getMethod(METHOD_ONPAUSE).invoke(webView); - } catch (Exception e) { - - } - } -} +/** + * Sparse rss + * + * Copyright (c) 2012 Stefan Handschuh + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * + * ============================================================================== + * This helper class is needed for older Android versions that verify all + * existing references on startup. + */ + +package cn.eric.rss; + +import android.app.Activity; +import android.graphics.drawable.Drawable; +import android.webkit.WebView; +import cn.eric.rss.R; + +public class CompatibilityHelper { + private static final String METHOD_GETACTIONBAR = "getActionBar"; + + private static final String METHOD_SETICON = "setIcon"; + + private static final String METHOD_ONRESUME = "onResume"; + + private static final String METHOD_ONPAUSE = "onPause"; + + public static void setActionBarDrawable(Activity activity, Drawable drawable) { + try { + Object actionBar = Activity.class.getMethod(METHOD_GETACTIONBAR).invoke(activity); + + actionBar.getClass().getMethod(METHOD_SETICON, Drawable.class).invoke(actionBar, drawable); + } catch (Exception e) { + + } + + } + + public static void onResume(WebView webView) { + try { + WebView.class.getMethod(METHOD_ONRESUME).invoke(webView); + } catch (Exception e) { + + } + } + + public static void onPause(WebView webView) { + try { + WebView.class.getMethod(METHOD_ONPAUSE).invoke(webView); + } catch (Exception e) { + + } + } +} diff --git a/src/de/shandschuh/sparserss/EmptyActivity.java b/src/cn/eric/rss/EmptyActivity.java similarity index 94% rename from src/de/shandschuh/sparserss/EmptyActivity.java rename to src/cn/eric/rss/EmptyActivity.java index d6625e8..a60f615 100644 --- a/src/de/shandschuh/sparserss/EmptyActivity.java +++ b/src/cn/eric/rss/EmptyActivity.java @@ -1,32 +1,33 @@ -/** - * Sparse rss - * - * Copyright (c) 2012 Stefan Handschuh - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - */ - -package de.shandschuh.sparserss; - -import android.app.Activity; - -public class EmptyActivity extends Activity { - -} +/** + * Sparse rss + * + * Copyright (c) 2012 Stefan Handschuh + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +package cn.eric.rss; + +import android.app.Activity; +import cn.eric.rss.R; + +public class EmptyActivity extends Activity { + +} diff --git a/src/cn/eric/rss/EntriesListActivity.java b/src/cn/eric/rss/EntriesListActivity.java new file mode 100644 index 0000000..c12b6d0 --- /dev/null +++ b/src/cn/eric/rss/EntriesListActivity.java @@ -0,0 +1,377 @@ +/** + * Sparse rss + * + * Copyright (c) 2010-2012 Stefan Handschuh + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +package cn.eric.rss; + +import com.actionbarsherlock.app.ActionBar; +import com.actionbarsherlock.view.SubMenu; + +import android.app.AlertDialog; +import android.app.AlertDialog.Builder; +import android.content.ContentUris; +import android.content.DialogInterface; +import android.content.Intent; +import android.database.Cursor; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Typeface; +import android.graphics.drawable.BitmapDrawable; +import android.net.Uri; +import android.os.Bundle; +import android.text.ClipboardManager; +import android.util.TypedValue; +import android.view.ContextMenu; +import android.view.ContextMenu.ContextMenuInfo; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.view.View.OnCreateContextMenuListener; +import android.view.Window; +import android.widget.AdapterView; +import android.widget.AdapterView.OnItemClickListener; +import android.widget.ListView; +import android.widget.TextView; +import cn.eric.rss.provider.FeedData; +import cn.eric.rss.ui.MenuData; +import cn.eric.rss.utility.MyStrings; + +public class EntriesListActivity extends SherlockActivityBase implements + OnItemClickListener { + private static final int CONTEXTMENU_MARKASREAD_ID = 6; + + private static final int CONTEXTMENU_MARKASUNREAD_ID = 7; + + private static final int CONTEXTMENU_DELETE_ID = 8; + + private static final int CONTEXTMENU_COPYURL = 9; + + public static final String EXTRA_SHOWREAD = "show_read"; + + public static final String EXTRA_SHOWFEEDINFO = "show_feedinfo"; + + public static final String EXTRA_AUTORELOAD = "autoreload"; + + private static final String[] FEED_PROJECTION = { + FeedData.FeedColumns.NAME, FeedData.FeedColumns.URL, + FeedData.FeedColumns.ICON }; + + private Uri uri; + + private EntriesListAdapter entriesListAdapter; + + // private byte[] iconBytes; + + private ListView listView; + + @Override + protected void onCreate(Bundle savedInstanceState) { + + super.onCreate(savedInstanceState); + + // iconBytes = null; + + Intent intent = getIntent(); + + // if (!MainActivity.POSTGINGERBREAD && iconBytes != null + // && iconBytes.length > 0) { // we cannot insert the icon here + // // because it would be overwritten, + // // but we have to reserve the icon + // // here + // if (!requestWindowFeature(Window.FEATURE_LEFT_ICON)) { + // iconBytes = null; + // } + // } + + listView = (ListView) this.findViewById(android.R.id.list); + listView.setOnItemClickListener(this); + + uri = intent.getData(); + + entriesListAdapter = new EntriesListAdapter(this, uri, + intent.getBooleanExtra(EXTRA_SHOWFEEDINFO, false), + intent.getBooleanExtra(EXTRA_AUTORELOAD, false)); + listView.setAdapter(entriesListAdapter); + + // if (iconBytes != null && iconBytes.length > 0) { + // int bitmapSizeInDip = (int) TypedValue.applyDimension( + // TypedValue.COMPLEX_UNIT_DIP, 24f, getResources() + // .getDisplayMetrics()); + // Bitmap bitmap = BitmapFactory.decodeByteArray(iconBytes, 0, + // iconBytes.length); + // if (bitmap != null) { + // if (bitmap.getHeight() != bitmapSizeInDip) { + // bitmap = Bitmap.createScaledBitmap(bitmap, bitmapSizeInDip, + // bitmapSizeInDip, false); + // } + // + // if (MainActivity.POSTGINGERBREAD) { + // CompatibilityHelper.setActionBarDrawable(this, + // new BitmapDrawable(bitmap)); + // } else { + // setFeatureDrawable(Window.FEATURE_LEFT_ICON, + // new BitmapDrawable(bitmap)); + // } + // } + // } + if (MainActivity.notificationManager != null) { + MainActivity.notificationManager.cancel(0); + } + + listView.setOnCreateContextMenuListener(new OnCreateContextMenuListener() { + public void onCreateContextMenu(ContextMenu menu, View view, + ContextMenuInfo menuInfo) { + menu.setHeaderTitle(((TextView) ((AdapterView.AdapterContextMenuInfo) menuInfo).targetView + .findViewById(android.R.id.text1)).getText()); + menu.add(0, CONTEXTMENU_MARKASREAD_ID, Menu.NONE, + R.string.contextmenu_markasread).setIcon( + android.R.drawable.ic_menu_manage); + menu.add(0, CONTEXTMENU_MARKASUNREAD_ID, Menu.NONE, + R.string.contextmenu_markasunread).setIcon( + android.R.drawable.ic_menu_manage); + menu.add(0, CONTEXTMENU_DELETE_ID, Menu.NONE, + R.string.contextmenu_delete).setIcon( + android.R.drawable.ic_menu_delete); + menu.add(0, CONTEXTMENU_COPYURL, Menu.NONE, + R.string.contextmenu_copyurl).setIcon( + android.R.drawable.ic_menu_share); + } + }); + } + + @Override + protected void onInitUpbar(ActionBar actionBar) { + super.onInitUpbar(actionBar); + actionBar.setDisplayShowTitleEnabled(true); + actionBar.setTitle(getTitleStr()); + } + + private String getTitleStr() { + + long feedId = getIntent().getLongExtra(FeedData.FeedColumns._ID, 0); + if (feedId > 0) { + + String title = null; + Cursor cursor = getContentResolver().query( + FeedData.FeedColumns.CONTENT_URI(feedId), FEED_PROJECTION, + null, null, null); + + if (cursor.moveToFirst()) { + title = cursor.isNull(0) ? cursor.getString(1) : cursor + .getString(0); + // iconBytes = cursor.getBlob(2); + } + cursor.close(); + if (title != null && title.length()>0) { + return title; + } + } + return ""; + } + + @Override + public void onItemClick(AdapterView listView, View view, int position, + long id) { + TextView textView = (TextView) view.findViewById(android.R.id.text1); + + textView.setTypeface(Typeface.DEFAULT); + textView.setEnabled(false); + view.findViewById(android.R.id.text2).setEnabled(false); + entriesListAdapter.neutralizeReadState(); + startActivity(new Intent(Intent.ACTION_VIEW, + ContentUris.withAppendedId(uri, id)).putExtra(EXTRA_SHOWREAD, + entriesListAdapter.isShowRead())); + } + + @Override + public boolean onContextItemSelected(final android.view.MenuItem item) { + + switch (item.getItemId()) { + + case R.id.menu_hideread: { + if (item.isChecked()) { + item.setChecked(false).setTitle(R.string.contextmenu_hideread) + .setIcon(android.R.drawable.ic_menu_close_clear_cancel); + entriesListAdapter.showRead(true); + } else { + item.setChecked(true).setTitle(R.string.contextmenu_showread) + .setIcon(android.R.drawable.ic_menu_view); + entriesListAdapter.showRead(false); + } + break; + } + + case CONTEXTMENU_MARKASREAD_ID: { + long id = ((AdapterView.AdapterContextMenuInfo) item.getMenuInfo()).id; + + getContentResolver().update(ContentUris.withAppendedId(uri, id), + MainActivity.getReadContentValues(), null, null); + entriesListAdapter.markAsRead(id); + break; + } + case CONTEXTMENU_MARKASUNREAD_ID: { + long id = ((AdapterView.AdapterContextMenuInfo) item.getMenuInfo()).id; + + getContentResolver().update(ContentUris.withAppendedId(uri, id), + MainActivity.getUnreadContentValues(), null, null); + entriesListAdapter.markAsUnread(id); + break; + } + case CONTEXTMENU_DELETE_ID: { + long id = ((AdapterView.AdapterContextMenuInfo) item.getMenuInfo()).id; + + getContentResolver().delete(ContentUris.withAppendedId(uri, id), + null, null); + FeedData.deletePicturesOfEntry(Long.toString(id)); + entriesListAdapter.getCursor().requery(); // he have no other choice + break; + } + case CONTEXTMENU_COPYURL: { + ((ClipboardManager) getSystemService(CLIPBOARD_SERVICE)) + .setText(((AdapterView.AdapterContextMenuInfo) item + .getMenuInfo()).targetView.getTag().toString()); + break; + } + + } + return true; + } + + @Override + protected int getLayoutRes() { + return R.layout.entries; + } + + @Override + public boolean onCreateOptionsMenu(com.actionbarsherlock.view.Menu menu) { + + com.actionbarsherlock.view.Menu subMenu=getSubMenu(menu); + + subMenu.add(0, MenuData.MENUITEM_MARK_AS_READ, 0, + R.string.contextmenu_markasread); + subMenu.add(0, MenuData.MENUITEM_MARK_AS_UNREAD, 0, + R.string.contextmenu_markasunread); + + subMenu.add(0, MenuData.MENUITEM_DELETE_READ_ENTRIES, 0, + R.string.contextmenu_deleteread); + subMenu.add(0, MenuData.MENUITEM_DELETE_ALL_ENTRIES, 0, + R.string.contextmenu_deleteallentries); + + return true; + } + + + // @Override + // public boolean onCreateOptionsMenu(Menu menu) { + // getMenuInflater().inflate(R.menu.entrylist, menu); + // return true; + // } + // + @Override + public boolean onPrepareOptionsMenu(com.actionbarsherlock.view.Menu menu) { + // menu.setGroupVisible(R.id.menu_group_0, entriesListAdapter.getCount() + // > + // 0); + return true; + } + + @Override + public boolean onOptionsItemSelected( + final com.actionbarsherlock.view.MenuItem menuItem) { + + switch (menuItem.getItemId()) { + case MenuData.MENUITEM_MARK_AS_READ: { + new Thread() { // the update process takes some time + public void run() { + getContentResolver().update(uri, + MainActivity.getReadContentValues(), null, null); + } + }.start(); + entriesListAdapter.markAsRead(); + break; + } + case MenuData.MENUITEM_MARK_AS_UNREAD: { + new Thread() { // the update process takes some time + public void run() { + getContentResolver().update(uri, + MainActivity.getUnreadContentValues(), null, null); + } + }.start(); + entriesListAdapter.markAsUnread(); + break; + } + + case MenuData.MENUITEM_DELETE_READ_ENTRIES: { + new Thread() { // the delete process takes some time + public void run() { + String selection = MyStrings.READDATE_GREATERZERO + + MyStrings.DB_AND + " (" + MyStrings.DB_EXCUDEFAVORITE + + ")"; + + getContentResolver().delete(uri, selection, null); + FeedData.deletePicturesOfFeed(EntriesListActivity.this, + uri, selection); + runOnUiThread(new Runnable() { + public void run() { + entriesListAdapter.getCursor().requery(); + } + }); + } + }.start(); + + break; + } + case MenuData.MENUITEM_DELETE_ALL_ENTRIES: { + Builder builder = new AlertDialog.Builder(this); + + builder.setIcon(android.R.drawable.ic_dialog_alert); + builder.setTitle(R.string.contextmenu_deleteallentries); + builder.setMessage(R.string.question_areyousure); + builder.setPositiveButton(android.R.string.yes, + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + new Thread() { + public void run() { + getContentResolver().delete(uri, + MyStrings.DB_EXCUDEFAVORITE, null); + runOnUiThread(new Runnable() { + public void run() { + entriesListAdapter.getCursor() + .requery(); + } + }); + } + }.start(); + } + }); + builder.setNegativeButton(android.R.string.no, null); + builder.show(); + break; + } + + } + return super.onOptionsItemSelected(menuItem); + } + +} diff --git a/src/de/shandschuh/sparserss/EntriesListAdapter.java b/src/cn/eric/rss/EntriesListAdapter.java similarity index 65% rename from src/de/shandschuh/sparserss/EntriesListAdapter.java rename to src/cn/eric/rss/EntriesListAdapter.java index af3da71..b154dbd 100644 --- a/src/de/shandschuh/sparserss/EntriesListAdapter.java +++ b/src/cn/eric/rss/EntriesListAdapter.java @@ -23,7 +23,7 @@ * */ -package de.shandschuh.sparserss; +package cn.eric.rss; import java.text.DateFormat; import java.util.Date; @@ -45,66 +45,71 @@ import android.widget.ImageView; import android.widget.ResourceCursorAdapter; import android.widget.TextView; -import de.shandschuh.sparserss.provider.FeedData; +import cn.eric.rss.R; +import cn.eric.rss.provider.FeedData; +import cn.eric.rss.utility.MyStrings; public class EntriesListAdapter extends ResourceCursorAdapter { private static final int STATE_NEUTRAL = 0; - + private static final int STATE_ALLREAD = 1; - + private static final int STATE_ALLUNREAD = 2; - + private int titleColumnPosition; - + private int dateColumn; - + private int readDateColumn; - + private int favoriteColumn; - + private int idColumn; - + private int feedIconColumn; - + private int feedNameColumn; - + private int linkColumn; - + private static final String SQLREAD = "length(readdate) ASC, "; - + public static final String READDATEISNULL = "readdate is null"; private boolean showRead; - + private Activity context; - + private Uri uri; - + private boolean showFeedInfo; - + private int forcedState; - + private Vector markedAsRead; - + private Vector markedAsUnread; - + private Vector favorited; - + private Vector unfavorited; - + private DateFormat dateFormat; - + private DateFormat timeFormat; - - public EntriesListAdapter(Activity context, Uri uri, boolean showFeedInfo, boolean autoreload) { - super(context, R.layout.entrylistitem, createManagedCursor(context, uri, true), autoreload); + + public EntriesListAdapter(Activity context, Uri uri, boolean showFeedInfo, + boolean autoreload) { + super(context, R.layout.entrylistitem, createManagedCursor(context, + uri, true), autoreload); showRead = true; this.context = context; this.uri = uri; - + Cursor cursor = getCursor(); - - titleColumnPosition = cursor.getColumnIndex(FeedData.EntryColumns.TITLE); + + titleColumnPosition = cursor + .getColumnIndex(FeedData.EntryColumns.TITLE); dateColumn = cursor.getColumnIndex(FeedData.EntryColumns.DATE); readDateColumn = cursor.getColumnIndex(FeedData.EntryColumns.READDATE); favoriteColumn = cursor.getColumnIndex(FeedData.EntryColumns.FAVORITE); @@ -127,75 +132,110 @@ public EntriesListAdapter(Activity context, Uri uri, boolean showFeedInfo, boole @Override public void bindView(View view, final Context context, Cursor cursor) { TextView textView = (TextView) view.findViewById(android.R.id.text1); - + textView.setText(cursor.getString(titleColumnPosition)); - - TextView dateTextView = (TextView) view.findViewById(android.R.id.text2); - - final ImageView imageView = (ImageView) view.findViewById(android.R.id.icon); - + + TextView dateTextView = (TextView) view + .findViewById(android.R.id.text2); + + final ImageView imageView = (ImageView) view + .findViewById(android.R.id.icon); + final long id = cursor.getLong(idColumn); - + view.setTag(cursor.getString(linkColumn)); - - final boolean favorite = !unfavorited.contains(id) && (cursor.getInt(favoriteColumn) == 1 || favorited.contains(id)); - - imageView.setImageResource(favorite ? android.R.drawable.star_on : android.R.drawable.star_off); - imageView.setTag(favorite ? Strings.TRUE : Strings.FALSE); + + final boolean favorite = !unfavorited.contains(id) + && (cursor.getInt(favoriteColumn) == 1 || favorited + .contains(id)); + + imageView.setBackgroundResource(favorite ? R.drawable.favorite + : R.drawable.not_favorite); + imageView.setTag(favorite ? MyStrings.TRUE : MyStrings.FALSE); imageView.setOnClickListener(new OnClickListener() { public void onClick(View view) { - boolean newFavorite = !Strings.TRUE.equals(view.getTag()); - + boolean newFavorite = !MyStrings.TRUE.equals(view.getTag()); + if (newFavorite) { - view.setTag(Strings.TRUE); - imageView.setImageResource(android.R.drawable.star_on); + view.setTag(MyStrings.TRUE); + imageView.setBackgroundResource(R.drawable.favorite); favorited.add(id); unfavorited.remove(id); } else { - view.setTag(Strings.FALSE); - imageView.setImageResource(android.R.drawable.star_off); + view.setTag(MyStrings.FALSE); + imageView.setBackgroundResource(R.drawable.not_favorite); unfavorited.add(id); favorited.remove(id); } - + ContentValues values = new ContentValues(); - + values.put(FeedData.EntryColumns.FAVORITE, newFavorite ? 1 : 0); - view.getContext().getContentResolver().update(uri, values, new StringBuilder(FeedData.EntryColumns._ID).append(Strings.DB_ARG).toString(), new String[] {Long.toString(id)}); - context.getContentResolver().notifyChange(FeedData.EntryColumns.FAVORITES_CONTENT_URI, null); - + view.getContext() + .getContentResolver() + .update(uri, + values, + new StringBuilder(FeedData.EntryColumns._ID) + .append(MyStrings.DB_ARG).toString(), + new String[] { Long.toString(id) }); + context.getContentResolver().notifyChange( + FeedData.EntryColumns.FAVORITES_CONTENT_URI, null); + } }); - + Date date = new Date(cursor.getLong(dateColumn)); - + if (showFeedInfo && feedIconColumn > -1 && feedNameColumn > -1) { byte[] iconBytes = cursor.getBlob(feedIconColumn); - + if (iconBytes != null && iconBytes.length > 0) { - Bitmap bitmap = BitmapFactory.decodeByteArray(iconBytes, 0, iconBytes.length); - + Bitmap bitmap = BitmapFactory.decodeByteArray(iconBytes, 0, + iconBytes.length); + if (bitmap != null) { - int bitmapSizeInDip = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 18f, context.getResources().getDisplayMetrics()); + int bitmapSizeInDip = (int) TypedValue.applyDimension( + TypedValue.COMPLEX_UNIT_DIP, 18f, context + .getResources().getDisplayMetrics()); if (bitmap.getHeight() != bitmapSizeInDip) { - bitmap = Bitmap.createScaledBitmap(bitmap, bitmapSizeInDip, bitmapSizeInDip, false); + bitmap = Bitmap.createScaledBitmap(bitmap, + bitmapSizeInDip, bitmapSizeInDip, false); } - dateTextView.setText(new StringBuilder().append(' ').append(dateFormat.format(date)).append(' ').append(timeFormat.format(date)).append(Strings.COMMASPACE).append(cursor.getString(feedNameColumn))); // bad style + dateTextView.setText(new StringBuilder().append(' ') + .append(dateFormat.format(date)).append(' ') + .append(timeFormat.format(date)) + .append(MyStrings.COMMASPACE) + .append(cursor.getString(feedNameColumn))); // bad + // style } else { - dateTextView.setText(new StringBuilder(dateFormat.format(date)).append(' ').append(timeFormat.format(date)).append(Strings.COMMASPACE).append(cursor.getString(feedNameColumn))); + dateTextView.setText(new StringBuilder(dateFormat + .format(date)).append(' ') + .append(timeFormat.format(date)) + .append(MyStrings.COMMASPACE) + .append(cursor.getString(feedNameColumn))); } - dateTextView.setCompoundDrawablesWithIntrinsicBounds(new BitmapDrawable(bitmap), null, null, null); + dateTextView.setCompoundDrawablesWithIntrinsicBounds( + new BitmapDrawable(bitmap), null, null, null); } else { - dateTextView.setCompoundDrawablesWithIntrinsicBounds(null, null, null, null); - dateTextView.setText(new StringBuilder(dateFormat.format(date)).append(' ').append(timeFormat.format(date)).append(Strings.COMMASPACE).append(cursor.getString(feedNameColumn))); + dateTextView.setCompoundDrawablesWithIntrinsicBounds(null, + null, null, null); + dateTextView.setText(new StringBuilder(dateFormat.format(date)) + .append(' ').append(timeFormat.format(date)) + .append(MyStrings.COMMASPACE) + .append(cursor.getString(feedNameColumn))); } - + } else { textView.setText(cursor.getString(titleColumnPosition)); - dateTextView.setText(new StringBuilder(dateFormat.format(date)).append(' ').append(timeFormat.format(date))); + dateTextView.setText(new StringBuilder(dateFormat.format(date)) + .append(' ').append(timeFormat.format(date))); } - - if (forcedState == STATE_ALLUNREAD && !markedAsRead.contains(id) || (forcedState != STATE_ALLREAD && cursor.isNull(readDateColumn) && !markedAsRead.contains(id)) || markedAsUnread.contains(id)) { + + if (forcedState == STATE_ALLUNREAD + && !markedAsRead.contains(id) + || (forcedState != STATE_ALLREAD + && cursor.isNull(readDateColumn) && !markedAsRead + .contains(id)) || markedAsUnread.contains(id)) { textView.setTypeface(Typeface.DEFAULT_BOLD); textView.setEnabled(true); dateTextView.setEnabled(true); @@ -213,29 +253,39 @@ public void showRead(boolean showRead) { this.showRead = showRead; } } - + public boolean isShowRead() { return showRead; } - - private static Cursor createManagedCursor(Activity context, Uri uri, boolean showRead) { - return context.managedQuery(uri, null, showRead ? null : READDATEISNULL, null, new StringBuilder(PreferenceManager.getDefaultSharedPreferences(context).getBoolean(Strings.SETTINGS_PRIORITIZE, false) ? SQLREAD : Strings.EMPTY).append(FeedData.EntryColumns.DATE).append(Strings.DB_DESC).toString()); + + private static Cursor createManagedCursor(Activity context, Uri uri, + boolean showRead) { + return context.managedQuery( + uri, + null, + showRead ? null : READDATEISNULL, + null, + new StringBuilder(PreferenceManager + .getDefaultSharedPreferences(context).getBoolean( + MyStrings.SETTINGS_PRIORITIZE, false) ? SQLREAD + : MyStrings.EMPTY).append(FeedData.EntryColumns.DATE) + .append(MyStrings.DB_DESC).toString()); } - + public void markAsRead() { forcedState = STATE_ALLREAD; markedAsRead.clear(); markedAsUnread.clear(); notifyDataSetInvalidated(); } - + public void markAsUnread() { forcedState = STATE_ALLUNREAD; markedAsRead.clear(); markedAsUnread.clear(); notifyDataSetInvalidated(); } - + public void neutralizeReadState() { forcedState = STATE_NEUTRAL; } @@ -251,5 +301,5 @@ public void markAsUnread(long id) { markedAsRead.remove(id); notifyDataSetInvalidated(); } - + } diff --git a/src/cn/eric/rss/EntryDetailActivity.java b/src/cn/eric/rss/EntryDetailActivity.java new file mode 100644 index 0000000..5180420 --- /dev/null +++ b/src/cn/eric/rss/EntryDetailActivity.java @@ -0,0 +1,884 @@ +/** + * Sparse rss + * + * Copyright (c) 2010-2012 Stefan Handschuh + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +package cn.eric.rss; + +import java.util.Date; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import android.app.AlertDialog; +import android.app.AlertDialog.Builder; +import android.app.NotificationManager; +import android.content.BroadcastReceiver; +import android.content.ContentValues; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.SharedPreferences; +import android.database.Cursor; +import android.graphics.Color; +import android.net.Uri; +import android.os.Bundle; +import android.preference.PreferenceManager; +import android.text.ClipboardManager; +import android.text.TextUtils; +import android.text.format.DateFormat; +import android.view.GestureDetector; +import android.view.GestureDetector.OnGestureListener; +import android.view.KeyEvent; +import android.view.Menu; +import android.view.MotionEvent; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.View.OnCreateContextMenuListener; +import android.view.View.OnKeyListener; +import android.view.View.OnTouchListener; +import android.view.ViewGroup.LayoutParams; +import android.view.animation.Animation; +import android.webkit.WebView; +import android.widget.AdapterView; +import android.widget.ImageButton; +import android.widget.ImageView; +import android.widget.TextView; +import android.widget.Toast; +import android.widget.ViewFlipper; +import android.widget.AdapterView.OnItemClickListener; +import cn.eric.rss.provider.FeedData; +import cn.eric.rss.ui.MyAnimations; +import cn.eric.rss.ui.MenuData; +import cn.eric.rss.utility.MyStrings; + +import com.actionbarsherlock.app.ActionBar; +import com.actionbarsherlock.view.MenuItem; +import com.actionbarsherlock.view.SubMenu; +import com.adsmogo.adview.AdsMogoLayout; +import com.umeng.analytics.MobclickAgent; + +public class EntryDetailActivity extends SherlockActivityBase { + + private static final String TEXT_HTML = "text/html"; + + private static final String UTF8 = "utf-8"; + + private static final String OR_DATE = " or date "; + + private static final String DATE = "(date="; + + private static final String AND_ID = " and _id"; + + private static final String ASC = "date asc, _id desc limit 1"; + + private static final String DESC = "date desc, _id asc limit 1"; + + private static final String CSS = ""; + + private static final String FONT_START = CSS + + ""; + + private static final String FONT_FONTSIZE_START = CSS + + ""; + + private static final String FONTSIZE_END = ""; + + private static final String FONT_END = "



"; + + private static final String BODY_START = ""; + + private static final String BODY_END = "



"; + + private static final int BUTTON_ALPHA = 180; + + private static final String IMAGE_ENCLOSURE = "[@]image/"; + + private static final String TEXTPLAIN = "text/plain"; + + private static final String BRACKET = " ("; + + private int titlePosition, datePosition, abstractPosition, linkPosition, + feedIdPosition, favoritePosition, readDatePosition, + enclosurePosition, authorPosition; + + private String _id, _nextId, _previousId; + + private Uri uri, parentUri; + + private int feedId; + + boolean favorite; + + private boolean showRead, canShowIcon; + + private byte[] iconBytes; + + private WebView webView, webView0; // only needed for the animation + + private ViewFlipper viewFlipper; + + private ImageButton nextButton, urlButton, previousButton, playButton; + + int scrollX, scrollY; + + private String link; + + private LayoutParams layoutParams; + + private View content; + + private SharedPreferences preferences; + + private boolean localPictures; + + private TextView titleTextView; + + private int backgroundColor; + + public void onCreate(Bundle savedInstanceState) { + + super.onCreate(savedInstanceState); + + uri = getIntent().getData(); + parentUri = FeedData.EntryColumns.PARENT_URI(uri.getPath()); + showRead = getIntent().getBooleanExtra( + EntriesListActivity.EXTRA_SHOWREAD, true); + iconBytes = getIntent().getByteArrayExtra(FeedData.FeedColumns.ICON); + feedId = 0; + + Cursor entryCursor = getContentResolver().query(uri, null, null, null, + null); + + titlePosition = entryCursor.getColumnIndex(FeedData.EntryColumns.TITLE); + datePosition = entryCursor.getColumnIndex(FeedData.EntryColumns.DATE); + abstractPosition = entryCursor + .getColumnIndex(FeedData.EntryColumns.ABSTRACT); + linkPosition = entryCursor.getColumnIndex(FeedData.EntryColumns.LINK); + feedIdPosition = entryCursor + .getColumnIndex(FeedData.EntryColumns.FEED_ID); + favoritePosition = entryCursor + .getColumnIndex(FeedData.EntryColumns.FAVORITE); + readDatePosition = entryCursor + .getColumnIndex(FeedData.EntryColumns.READDATE); + enclosurePosition = entryCursor + .getColumnIndex(FeedData.EntryColumns.ENCLOSURE); + authorPosition = entryCursor + .getColumnIndex(FeedData.EntryColumns.AUTHOR); + + entryCursor.close(); + if (MainActivity.notificationManager == null) { + MainActivity.notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); + } + + nextButton = (ImageButton) findViewById(R.id.next_button); + urlButton = (ImageButton) findViewById(R.id.url_button); + urlButton.setAlpha(BUTTON_ALPHA + 30); + previousButton = (ImageButton) findViewById(R.id.prev_button); + playButton = (ImageButton) findViewById(R.id.play_button); + playButton.setAlpha(BUTTON_ALPHA); + + viewFlipper = (ViewFlipper) findViewById(R.id.content_flipper); + + layoutParams = new LayoutParams(LayoutParams.FILL_PARENT, + LayoutParams.FILL_PARENT); + + webView = new WebView(this); + backgroundColor = this.getResources().getColor(R.color.common_bg_gray); + viewFlipper.addView(webView, layoutParams); + + OnKeyListener onKeyEventListener = new OnKeyListener() { + public boolean onKey(View v, int keyCode, KeyEvent event) { + if (event.getAction() == KeyEvent.ACTION_DOWN) { + if (keyCode == 92 || keyCode == 94) { + scrollUp(); + return true; + } else if (keyCode == 93 || keyCode == 95) { + scrollDown(); + return true; + } + } + return false; + } + }; + webView.setOnKeyListener(onKeyEventListener); + + content = findViewById(R.id.entry_content); + + webView0 = new WebView(this); + webView0.setOnKeyListener(onKeyEventListener); + + preferences = PreferenceManager.getDefaultSharedPreferences(this); + + final boolean gestures = preferences.getBoolean( + MyStrings.SETTINGS_GESTURESENABLED, true); + + final GestureDetector gestureDetector = new GestureDetector(this, + new OnGestureListener() { + public boolean onDown(MotionEvent e) { + return false; + } + + public boolean onFling(MotionEvent e1, MotionEvent e2, + float velocityX, float velocityY) { + if (gestures) { + if (Math.abs(velocityY) < Math.abs(velocityX)) { + if (velocityX > 800) { + if (previousButton.isEnabled()) { + previousEntry(true); + } + } else if (velocityX < -800) { + if (nextButton.isEnabled()) { + nextEntry(true); + } + } + } + } + return false; + } + + public void onLongPress(MotionEvent e) { + + } + + public boolean onScroll(MotionEvent e1, MotionEvent e2, + float distanceX, float distanceY) { + return false; + } + + public void onShowPress(MotionEvent e) { + + } + + public boolean onSingleTapUp(MotionEvent e) { + return false; + } + }); + + OnTouchListener onTouchListener = new OnTouchListener() { + public boolean onTouch(View v, MotionEvent event) { + return gestureDetector.onTouchEvent(event); + } + }; + + webView.setOnTouchListener(onTouchListener); + + content.setOnTouchListener(new OnTouchListener() { + public boolean onTouch(View v, MotionEvent event) { + gestureDetector.onTouchEvent(event); + return true; // different to the above one! + } + }); + + webView0.setOnTouchListener(onTouchListener); + + scrollX = 0; + scrollY = 0; + } + + @Override + protected void onRestoreInstanceState(Bundle savedInstanceState) { + super.onRestoreInstanceState(savedInstanceState); + webView.restoreState(savedInstanceState); + } + + @Override + protected void onResume() { + super.onResume(); + MobclickAgent.onResume(this); + if (MainActivity.notificationManager != null) { + MainActivity.notificationManager.cancel(0); + } + uri = getIntent().getData(); + parentUri = FeedData.EntryColumns.PARENT_URI(uri.getPath()); + if (MainActivity.POSTGINGERBREAD) { + CompatibilityHelper.onResume(webView); + } + reload(); + } + + @Override + protected void onNewIntent(Intent intent) { + super.onNewIntent(intent); + setIntent(intent); + } + + private void reload() { + if (_id != null && _id.equals(uri.getLastPathSegment())) { + return; + } + + _id = uri.getLastPathSegment(); + + ContentValues values = new ContentValues(); + + values.put(FeedData.EntryColumns.READDATE, System.currentTimeMillis()); + + Cursor entryCursor = getContentResolver().query(uri, null, null, null, + null); + + if (entryCursor.moveToFirst()) { + String abstractText = entryCursor.getString(abstractPosition); + + if (entryCursor.isNull(readDatePosition)) { + getContentResolver().update( + uri, + values, + new StringBuilder(FeedData.EntryColumns.READDATE) + .append(MyStrings.DB_ISNULL).toString(), null); + } + if (abstractText == null) { + String link = entryCursor.getString(linkPosition); + + entryCursor.close(); + finish(); + startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(link))); + } else { + updateUpbarTitle(entryCursor.getString(titlePosition)); + if (titleTextView != null) { + titleTextView.requestFocus(); // restart ellipsize + } + + int _feedId = entryCursor.getInt(feedIdPosition); + + if (feedId != _feedId) { + if (feedId != 0) { + iconBytes = null; // triggers re-fetch of the icon + } + feedId = _feedId; + } + + if (canShowIcon) { + if (iconBytes == null || iconBytes.length == 0) { + Cursor iconCursor = getContentResolver().query( + FeedData.FeedColumns.CONTENT_URI(Integer + .toString(feedId)), + new String[] { FeedData.FeedColumns._ID, + FeedData.FeedColumns.ICON }, null, + null, null); + + if (iconCursor.moveToFirst()) { + iconBytes = iconCursor.getBlob(1); + } + iconCursor.close(); + } + + // if (iconBytes != null && iconBytes.length > 0) { + // int bitmapSizeInDip = (int) TypedValue.applyDimension( + // TypedValue.COMPLEX_UNIT_DIP, 24f, + // getResources().getDisplayMetrics()); + // Bitmap bitmap = BitmapFactory.decodeByteArray( + // iconBytes, 0, iconBytes.length); + // if (bitmap != null) { + // if (bitmap.getHeight() != bitmapSizeInDip) { + // bitmap = Bitmap + // .createScaledBitmap(bitmap, + // bitmapSizeInDip, + // bitmapSizeInDip, false); + // } + // + // if (MainActivity.POSTGINGERBREAD) { + // CompatibilityHelper.setActionBarDrawable(this, + // new BitmapDrawable(bitmap)); + // } else { + // setFeatureDrawable(Window.FEATURE_LEFT_ICON, + // new BitmapDrawable(bitmap)); + // } + // } + // } + } + + long timestamp = entryCursor.getLong(datePosition); + + Date date = new Date(timestamp); + + StringBuilder dateStringBuilder = new StringBuilder(DateFormat + .getDateFormat(this).format(date)).append(' ').append( + DateFormat.getTimeFormat(this).format(date)); + + String author = entryCursor.getString(authorPosition); + + if (author != null) { + dateStringBuilder.append(BRACKET).append(author) + .append(')'); + } + + ((TextView) findViewById(R.id.entry_date)) + .setText(dateStringBuilder); + + final ImageView imageView = (ImageView) findViewById(android.R.id.icon); + + favorite = entryCursor.getInt(favoritePosition) == 1; + + imageView.setBackgroundResource(favorite ? R.drawable.favorite + : R.drawable.not_favorite); + imageView.setOnClickListener(new OnClickListener() { + public void onClick(View view) { + favorite = !favorite; + imageView + .setBackgroundResource(favorite ? R.drawable.favorite + : R.drawable.not_favorite); + ContentValues values = new ContentValues(); + + values.put(FeedData.EntryColumns.FAVORITE, favorite ? 1 + : 0); + getContentResolver().update(uri, values, null, null); + } + }); + // loadData does not recognize the encoding without correct + // html-header + localPictures = abstractText + .indexOf(MyStrings.IMAGEID_REPLACEMENT) > -1; + + abstractText = abstractText.replace( + MyStrings.IMAGEID_REPLACEMENT, uri.getLastPathSegment() + + MyStrings.IMAGEFILE_IDSEPARATOR); + + Pattern linkP = Pattern.compile("]*href=[^>]*>"); + Matcher linkM = linkP.matcher(abstractText); + if (!linkM.find()) { + abstractText = abstractText.replaceAll( + "(?i)(https?://[^ \n\r\t\\[\\]]+)", + "$1"); + } + + Pattern brP = Pattern.compile("]*>"); + Matcher brM = brP.matcher(abstractText); + if (!brM.find()) { + abstractText = abstractText.replaceAll("\n", "
"); + } + + abstractText = abstractText.replaceAll("(?i)\\[(/?(b|u))\\]", + "<$1>"); + abstractText = abstractText.replaceAll( + "(?i)\\[img\\](https?://[^ \n\r\t\\[\\]]+)\\[/img\\]", + ""); + abstractText = abstractText.replaceAll( + "(?i)\\[/?(center|color|size|img|url|pre)[^\\]]*\\]", + ""); + + final SharedPreferences preferences = PreferenceManager + .getDefaultSharedPreferences(this); + + if (localPictures) { + abstractText = abstractText.replace( + MyStrings.IMAGEID_REPLACEMENT, _id + + MyStrings.IMAGEFILE_IDSEPARATOR); + } + + if (preferences.getBoolean(MyStrings.SETTINGS_DISABLEPICTURES, + false)) { + abstractText = abstractText.replaceAll( + MyStrings.HTML_IMG_REGEX, MyStrings.EMPTY); + webView.getSettings().setBlockNetworkImage(true); + } else { + if (webView.getSettings().getBlockNetworkImage()) { + /* + * setBlockNetwortImage(false) calls postSync, which + * takes time, so we clean up the html first and change + * the value afterwards + */ + webView.loadData(MyStrings.EMPTY, TEXT_HTML, UTF8); + webView.getSettings().setBlockNetworkImage(false); + } + } + + int fontsize = Integer.parseInt(preferences.getString( + MyStrings.SETTINGS_FONTSIZE, MyStrings.ONE)); + + if (fontsize > 0) { + webView.loadDataWithBaseURL(null, + new StringBuilder(CSS).append(FONTSIZE_START) + .append(fontsize).append(FONTSIZE_MIDDLE) + .append(abstractText).append(FONTSIZE_END) + .toString(), TEXT_HTML, UTF8, null); + } else { + webView.loadDataWithBaseURL( + null, + new StringBuilder(CSS).append(BODY_START) + .append(abstractText).append(BODY_END) + .toString(), TEXT_HTML, UTF8, null); + } + webView.setBackgroundColor(backgroundColor); + content.setBackgroundColor(Color.WHITE); + link = entryCursor.getString(linkPosition); + + if (link != null && link.length() > 0) { + urlButton.setEnabled(true); + urlButton.setAlpha(BUTTON_ALPHA + 20); + urlButton.setOnClickListener(new OnClickListener() { + public void onClick(View view) { + startActivityForResult(new Intent( + Intent.ACTION_VIEW, Uri.parse(link)), 0); + } + }); + } else { + urlButton.setEnabled(false); + urlButton.setAlpha(80); + } + + final String enclosure = entryCursor + .getString(enclosurePosition); + + if (enclosure != null && enclosure.length() > 6 + && enclosure.indexOf(IMAGE_ENCLOSURE) == -1) { + playButton.setVisibility(View.VISIBLE); + playButton.setOnClickListener(new OnClickListener() { + public void onClick(View v) { + final int position1 = enclosure + .indexOf(MyStrings.ENCLOSURE_SEPARATOR); + + final int position2 = enclosure.indexOf( + MyStrings.ENCLOSURE_SEPARATOR, position1 + 3); + + final Uri uri = Uri.parse(enclosure.substring(0, + position1)); + + if (preferences.getBoolean( + MyStrings.SETTINGS_ENCLOSUREWARNINGSENABLED, + true)) { + Builder builder = new AlertDialog.Builder( + EntryDetailActivity.this); + + builder.setTitle(R.string.question_areyousure); + builder.setIcon(android.R.drawable.ic_dialog_alert); + if (position2 + 4 > enclosure.length()) { + builder.setMessage(getString( + R.string.question_playenclosure, + uri, + position2 + 4 > enclosure.length() ? MyStrings.QUESTIONMARKS + : enclosure + .substring(position2 + 3))); + } else { + try { + builder.setMessage(getString( + R.string.question_playenclosure, + uri, + (Integer.parseInt(enclosure + .substring(position2 + 3)) / 1024f) + + getString(R.string.kb))); + } catch (Exception e) { + builder.setMessage(getString( + R.string.question_playenclosure, + uri, + enclosure + .substring(position2 + 3))); + } + } + builder.setCancelable(true); + builder.setPositiveButton(android.R.string.ok, + new DialogInterface.OnClickListener() { + public void onClick( + DialogInterface dialog, + int which) { + showEnclosure(uri, enclosure, + position1, position2); + } + }); + builder.setNeutralButton( + R.string.button_alwaysokforall, + new DialogInterface.OnClickListener() { + public void onClick( + DialogInterface dialog, + int which) { + preferences + .edit() + .putBoolean( + MyStrings.SETTINGS_ENCLOSUREWARNINGSENABLED, + false).commit(); + showEnclosure(uri, enclosure, + position1, position2); + } + }); + builder.setNegativeButton( + android.R.string.cancel, + new DialogInterface.OnClickListener() { + public void onClick( + DialogInterface dialog, + int which) { + dialog.dismiss(); + } + }); + builder.show(); + } else { + showEnclosure(uri, enclosure, position1, + position2); + } + } + }); + } else { + playButton.setVisibility(View.GONE); + } + entryCursor.close(); + setupButton(previousButton, false, timestamp); + setupButton(nextButton, true, timestamp); + webView.scrollTo(scrollX, scrollY); // resets the scrolling + } + } else { + entryCursor.close(); + } + + } + + private void showEnclosure(Uri uri, String enclosure, int position1, + int position2) { + try { + startActivityForResult( + new Intent(Intent.ACTION_VIEW).setDataAndType(uri, + enclosure.substring(position1 + 3, position2)), 0); + } catch (Exception e) { + try { + startActivityForResult(new Intent(Intent.ACTION_VIEW, uri), 0); // fallbackmode + // - + // let + // the + // browser + // handle + // this + } catch (Throwable t) { + Toast.makeText(EntryDetailActivity.this, t.getMessage(), + Toast.LENGTH_LONG).show(); + } + } + } + + private void setupButton(ImageButton button, final boolean successor, + long date) { + StringBuilder queryString = new StringBuilder(DATE).append(date) + .append(AND_ID).append(successor ? '>' : '<').append(_id) + .append(')').append(OR_DATE).append(successor ? '<' : '>') + .append(date); + + if (!showRead) { + queryString.append(MyStrings.DB_AND).append( + EntriesListAdapter.READDATEISNULL); + } + + Cursor cursor = getContentResolver().query(parentUri, + new String[] { FeedData.EntryColumns._ID }, + queryString.toString(), null, successor ? DESC : ASC); + + if (cursor.moveToFirst()) { + button.setEnabled(true); + button.setAlpha(BUTTON_ALPHA); + + final String id = cursor.getString(0); + + if (successor) { + _nextId = id; + } else { + _previousId = id; + } + button.setOnClickListener(new OnClickListener() { + public void onClick(View view) { + if (successor) { + nextEntry(false); + } else { + previousEntry(false); + } + } + }); + } else { + button.setEnabled(false); + button.setAlpha(60); + } + cursor.close(); + } + + private void switchEntry(String id, boolean animate, Animation inAnimation, + Animation outAnimation) { + uri = parentUri.buildUpon().appendPath(id).build(); + getIntent().setData(uri); + scrollX = 0; + scrollY = 0; + + if (animate) { + WebView dummy = webView; // switch reference + + webView = webView0; + webView0 = dummy; + } + + reload(); + + if (animate) { + viewFlipper.setInAnimation(inAnimation); + viewFlipper.setOutAnimation(outAnimation); + viewFlipper.addView(webView, layoutParams); + viewFlipper.showNext(); + viewFlipper.removeViewAt(0); + } + } + + private void nextEntry(boolean animate) { + switchEntry(_nextId, animate, MyAnimations.SLIDE_IN_RIGHT, + MyAnimations.SLIDE_OUT_LEFT); + } + + private void previousEntry(boolean animate) { + switchEntry(_previousId, animate, MyAnimations.SLIDE_IN_LEFT, + MyAnimations.SLIDE_OUT_RIGHT); + } + + @Override + protected void onPause() { + super.onPause(); + MobclickAgent.onPause(this); + if (MainActivity.POSTGINGERBREAD) { + CompatibilityHelper.onPause(webView); + } + scrollX = webView.getScrollX(); + scrollY = webView.getScrollY(); + } + + @Override + protected void onSaveInstanceState(Bundle outState) { + webView.saveState(outState); + super.onSaveInstanceState(outState); + } + + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + if (event.getAction() == KeyEvent.ACTION_DOWN) { + if (keyCode == 92 || keyCode == 94) { + scrollUp(); + return true; + } else if (keyCode == 93 || keyCode == 95) { + scrollDown(); + return true; + } + } + return super.onKeyDown(keyCode, event); + } + + private void scrollUp() { + if (webView != null) { + webView.pageUp(false); + } + } + + private void scrollDown() { + if (webView != null) { + webView.pageDown(false); + } + } + + /** + * Works around android issue 6191 + */ + @Override + public void unregisterReceiver(BroadcastReceiver receiver) { + try { + super.unregisterReceiver(receiver); + } catch (Exception e) { + // do nothing + } + } + + @Override + protected void onDestroy() { + AdsMogoLayout.clear(); + // 清除adsMogoLayout 实例所产生用于多线程缓冲机制的线程池 + // 此方法请不要轻易调用,如果调用时间不当,会造成无法统计计数 + // adsMogoLayoutCode.clearThread(); + super.onDestroy(); + } + + @Override + protected int getLayoutRes() { + return R.layout.entry; + } + + @Override + protected void onInitUpbar(ActionBar actionBar) { + super.onInitUpbar(actionBar); + actionBar.setDisplayShowTitleEnabled(true); + actionBar.setTitle(""); + } + + @Override + public boolean onCreateOptionsMenu(com.actionbarsherlock.view.Menu menu) { + + com.actionbarsherlock.view.Menu subMenu=getSubMenu(menu); + + subMenu.add(0, MenuData.MENUITEM_COPY_LINK_INTO_CLIPBOARD, 0, + R.string.contextmenu_copyurl); + subMenu.add(0, MenuData.MENUITEM_SHARE, 0, R.string.menu_share); + + subMenu.add(0, MenuData.MENUITEM_DELETE, 0, R.string.contextmenu_delete); + + return true; + } + + @Override + public boolean onPrepareOptionsMenu(com.actionbarsherlock.view.Menu menu) { + + return true; + } + + @Override + public boolean onOptionsItemSelected( + com.actionbarsherlock.view.MenuItem menuItem) { + switch (menuItem.getItemId()) { + case MenuData.MENUITEM_COPY_LINK_INTO_CLIPBOARD: { + if (link != null) { + ((ClipboardManager) getSystemService(CLIPBOARD_SERVICE)) + .setText(link); + } + break; + } + + case MenuData.MENUITEM_SHARE: { + if (link != null) { + startActivity(Intent.createChooser(new Intent( + Intent.ACTION_SEND).putExtra(Intent.EXTRA_TEXT, link) + .setType(TEXTPLAIN), getString(R.string.menu_share))); + } + break; + } + + case MenuData.MENUITEM_DELETE: { + getContentResolver().delete(uri, null, null); + if (localPictures) { + FeedData.deletePicturesOfEntry(_id); + } + + if (nextButton.isEnabled()) { + nextButton.performClick(); + } else { + if (previousButton.isEnabled()) { + previousButton.performClick(); + } else { + finish(); + } + } + break; + } + } + return super.onOptionsItemSelected(menuItem); + } + +} diff --git a/src/cn/eric/rss/FeedConfigActivity.java b/src/cn/eric/rss/FeedConfigActivity.java new file mode 100644 index 0000000..c1bfb88 --- /dev/null +++ b/src/cn/eric/rss/FeedConfigActivity.java @@ -0,0 +1,294 @@ +/** + * Sparse rss + * + * Copyright (c) 2012 Stefan Handschuh + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +package cn.eric.rss; + +import android.app.Activity; +import android.content.ContentValues; +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.database.Cursor; +import android.os.Bundle; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.Window; +import android.widget.Button; +import android.widget.CheckBox; +import android.widget.EditText; +import android.widget.Toast; +import cn.eric.rss.provider.FeedData; +import cn.eric.rss.utility.ApplicationHelper; +import cn.eric.rss.utility.MyStrings; + +public class FeedConfigActivity extends Activity { + private static final String WASACTIVE = "wasactive"; + + private static final String[] PROJECTION = new String[] { + FeedData.FeedColumns.NAME, FeedData.FeedColumns.URL, + FeedData.FeedColumns.WIFIONLY }; + + private EditText nameEditText; + + private EditText urlEditText; + + private CheckBox refreshOnlyWifiCheckBox; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + this.requestWindowFeature(Window.FEATURE_NO_TITLE); + + this.setContentView(R.layout.feedsettings); + setResult(RESULT_CANCELED); + + Intent intent = getIntent(); + + nameEditText = (EditText) findViewById(R.id.feed_title); + urlEditText = (EditText) findViewById(R.id.feed_url); + refreshOnlyWifiCheckBox = (CheckBox) findViewById(R.id.wifionlycheckbox); + + // add feed dialog + if (intent.getAction().equals(Intent.ACTION_INSERT)) { + + restoreInstanceState(savedInstanceState); + ((Button) findViewById(R.id.button_ok)) + .setOnClickListener(new OnClickListener() { + public void onClick(View v) { + String url = urlEditText.getText().toString(); + + if (url == null || url.length() <= 0) { + Toast.makeText(FeedConfigActivity.this, + R.string.error_feederror, + Toast.LENGTH_LONG).show(); + return; + } + + if (!url.startsWith(MyStrings.HTTP) + && !url.startsWith(MyStrings.HTTPS)) { + url = MyStrings.HTTP + url; + } + + Cursor cursor = getContentResolver().query( + FeedData.FeedColumns.CONTENT_URI, + null, + new StringBuilder(FeedData.FeedColumns.URL) + .append(MyStrings.DB_ARG).toString(), + new String[] { url }, null); + + if (cursor.moveToFirst()) { + cursor.close(); + Toast.makeText(FeedConfigActivity.this, + R.string.error_feedurlexists, + Toast.LENGTH_LONG).show(); + } else { + cursor.close(); + ContentValues values = new ContentValues(); + + values.put(FeedData.FeedColumns.WIFIONLY, + refreshOnlyWifiCheckBox.isChecked() ? 1 + : 0); + values.put(FeedData.FeedColumns.URL, url); + values.put(FeedData.FeedColumns.ERROR, + (String) null); + + String name = nameEditText.getText().toString(); + + if (name.trim().length() > 0) { + values.put(FeedData.FeedColumns.NAME, name); + } + getContentResolver().insert( + FeedData.FeedColumns.CONTENT_URI, + values); + setResult(RESULT_OK); + finish(); + } + } + }); + } else { + // edit feed dialog + if (!restoreInstanceState(savedInstanceState)) { + Cursor cursor = getContentResolver().query(intent.getData(), + PROJECTION, null, null, null); + + if (cursor.moveToNext()) { + nameEditText.setText(cursor.getString(0)); + urlEditText.setText(cursor.getString(1)); + refreshOnlyWifiCheckBox.setChecked(cursor.getInt(2) == 1); + cursor.close(); + } else { + cursor.close(); + Toast.makeText(FeedConfigActivity.this, R.string.error, + Toast.LENGTH_LONG).show(); + finish(); + } + } + ((Button) findViewById(R.id.button_ok)) + .setOnClickListener(new OnClickListener() { + public void onClick(View v) { + String url = urlEditText.getText().toString(); + + Cursor cursor = getContentResolver().query( + FeedData.FeedColumns.CONTENT_URI, + new String[] { FeedData.FeedColumns._ID }, + new StringBuilder(FeedData.FeedColumns.URL) + .append(MyStrings.DB_ARG).toString(), + new String[] { url }, null); + + if (cursor.moveToFirst() + && !getIntent().getData() + .getLastPathSegment() + .equals(cursor.getString(0))) { + cursor.close(); + Toast.makeText(FeedConfigActivity.this, + R.string.error_feedurlexists, + Toast.LENGTH_LONG).show(); + } else { + cursor.close(); + ContentValues values = new ContentValues(); + + if (!url.startsWith(MyStrings.HTTP) + && !url.startsWith(MyStrings.HTTPS)) { + url = MyStrings.HTTP + url; + } + values.put(FeedData.FeedColumns.URL, url); + + String name = nameEditText.getText().toString(); + + values.put(FeedData.FeedColumns.NAME, name + .trim().length() > 0 ? name : null); + values.put(FeedData.FeedColumns.FETCHMODE, 0); + values.put(FeedData.FeedColumns.WIFIONLY, + refreshOnlyWifiCheckBox.isChecked() ? 1 + : 0); + values.put(FeedData.FeedColumns.ERROR, + (String) null); + getContentResolver().update( + getIntent().getData(), values, null, + null); + + setResult(RESULT_OK); + finish(); + } + } + + }); + + } + + ((Button) findViewById(R.id.button_cancel)) + .setOnClickListener(new OnClickListener() { + public void onClick(View v) { + finish(); + } + }); + } + + private boolean restoreInstanceState(Bundle savedInstanceState) { + if (savedInstanceState != null + && savedInstanceState.getBoolean(WASACTIVE, false)) { + nameEditText.setText(savedInstanceState + .getCharSequence(FeedData.FeedColumns.NAME)); + urlEditText.setText(savedInstanceState + .getCharSequence(FeedData.FeedColumns.URL)); + refreshOnlyWifiCheckBox.setChecked(savedInstanceState + .getBoolean(FeedData.FeedColumns.WIFIONLY)); + return true; + } else { + return false; + } + } + + @Override + protected void onSaveInstanceState(Bundle outState) { + outState.putBoolean(WASACTIVE, true); + outState.putCharSequence(FeedData.FeedColumns.NAME, + nameEditText.getText()); + outState.putCharSequence(FeedData.FeedColumns.URL, + urlEditText.getText()); + outState.putBoolean(FeedData.FeedColumns.WIFIONLY, + refreshOnlyWifiCheckBox.isChecked()); + } + + /** + * fill in some common feed urls for users + * + * @param activity + * @return + */ + public static void insertInitialFeeds(Activity activity) { + Cursor cursor = activity.getContentResolver().query( + FeedData.FeedColumns.CONTENT_URI, null, null, null, null); + + if (cursor.moveToFirst()) { + // the feed list isn't empty, do nothing + return; + } + String url, name; + url = "http://news.163.com/special/00011K6L/rss_newstop.xml"; + name = "网易新闻(头条)"; + insertFeed(activity, url, name); + url = "http://news.163.com/special/00011K6L/rss_hotnews.xml"; + name = "网易新闻(深度)"; + insertFeed(activity, url, name); + url = "https://news.google.com.hk/news/feeds?pz=1&cf=all&ned=cn&hl=en&output=rss"; + name = "谷歌新闻"; + insertFeed(activity, url, name); + url = "http://news.qq.com/newssh/rss_newssh.xml"; + name = "腾讯社会新闻"; + insertFeed(activity, url, name); + url = "http://comic.qq.com/news/rss_news.xml"; + name = "腾讯动漫频道"; + insertFeed(activity, url, name); + url = "http://feed.mtime.com/movienews.rss"; + name = "时光电影新闻"; + insertFeed(activity, url, name); + url = "http://feed.williamlong.info/"; + name = "月光博客"; + insertFeed(activity, url, name); + url = "http://online.wsj.com/xml/rss/3_7085.xml"; + name = "华尔街日报(世界新闻,英文)"; + insertFeed(activity, url, name); + } + + private static boolean insertFeed(Activity activity, String url, String name) { + ContentValues values = new ContentValues(); + + values.put(FeedData.FeedColumns.URL, url); + values.put(FeedData.FeedColumns.NAME, name); + values.put(FeedData.FeedColumns.FETCHMODE, 0); + values.put(FeedData.FeedColumns.WIFIONLY, 0); + values.put(FeedData.FeedColumns.ERROR, (String) null); + try { + activity.getContentResolver().insert( + FeedData.FeedColumns.CONTENT_URI, values); + return true; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + + } +} diff --git a/src/de/shandschuh/sparserss/FeedPrefsActivity.java b/src/cn/eric/rss/FeedPrefsActivity.java similarity index 74% rename from src/de/shandschuh/sparserss/FeedPrefsActivity.java rename to src/cn/eric/rss/FeedPrefsActivity.java index 4b820cb..243da0f 100644 --- a/src/de/shandschuh/sparserss/FeedPrefsActivity.java +++ b/src/cn/eric/rss/FeedPrefsActivity.java @@ -1,6 +1,10 @@ -package de.shandschuh.sparserss; +package cn.eric.rss; -import de.shandschuh.sparserss.provider.FeedData; +import com.umeng.analytics.MobclickAgent; + +import cn.eric.rss.R; +import cn.eric.rss.provider.FeedData; +import cn.eric.rss.utility.MyStrings; import android.content.ContentValues; import android.database.Cursor; import android.os.Bundle; @@ -21,16 +25,16 @@ public void onCreate(Bundle savedInstanceState) { public boolean onPreferenceChange(Preference pref, Object change) { ContentValues values = new ContentValues(); - if( pref.getKey().equals(Strings.FEED_SETTINGS_ALERT_RINGTONE)) { + if( pref.getKey().equals(MyStrings.FEED_SETTINGS_ALERT_RINGTONE)) { values.put(FeedData.FeedColumns.ALERT_RINGTONE, change.toString()); getContentResolver().update(FeedData.FeedColumns.CONTENT_URI(feedId), values, null, null); return true; - } else if(pref.getKey().equals(Strings.FEED_SETTINGS_OTHER_ALERT_RINGTONE)) { + } else if(pref.getKey().equals(MyStrings.FEED_SETTINGS_OTHER_ALERT_RINGTONE)) { int val = change.equals(Boolean.TRUE) ? 1 : 0; values.put(FeedData.FeedColumns.OTHER_ALERT_RINGTONE, val); getContentResolver().update(FeedData.FeedColumns.CONTENT_URI(feedId), values, null, null); return true; - } else if(pref.getKey().equals(Strings.FEED_SETTINGS_SKIP_ALERT)) { + } else if(pref.getKey().equals(MyStrings.FEED_SETTINGS_SKIP_ALERT)) { int val = change.equals(Boolean.TRUE) ? 1 : 0; values.put(FeedData.FeedColumns.SKIP_ALERT, val); getContentResolver().update(FeedData.FeedColumns.CONTENT_URI(feedId), values, null, null); @@ -40,9 +44,9 @@ public boolean onPreferenceChange(Preference pref, Object change) { } }; - CheckBoxPreference skipAlert = (CheckBoxPreference)findPreference(Strings.FEED_SETTINGS_SKIP_ALERT); - CheckBoxPreference other_ringtone = (CheckBoxPreference)findPreference(Strings.FEED_SETTINGS_OTHER_ALERT_RINGTONE); - Preference ringtone = findPreference(Strings.FEED_SETTINGS_ALERT_RINGTONE); + CheckBoxPreference skipAlert = (CheckBoxPreference)findPreference(MyStrings.FEED_SETTINGS_SKIP_ALERT); + CheckBoxPreference other_ringtone = (CheckBoxPreference)findPreference(MyStrings.FEED_SETTINGS_OTHER_ALERT_RINGTONE); + Preference ringtone = findPreference(MyStrings.FEED_SETTINGS_ALERT_RINGTONE); skipAlert.setOnPreferenceChangeListener(listener); ringtone.setOnPreferenceChangeListener(listener); @@ -62,4 +66,16 @@ public boolean onPreferenceChange(Preference pref, Object change) { } + + @Override + public void onResume() { + super.onResume(); + MobclickAgent.onResume(this); + } + + @Override + public void onPause() { + super.onPause(); + MobclickAgent.onPause(this); + } } diff --git a/src/cn/eric/rss/MainActivity.java b/src/cn/eric/rss/MainActivity.java new file mode 100644 index 0000000..bec4b9f --- /dev/null +++ b/src/cn/eric/rss/MainActivity.java @@ -0,0 +1,859 @@ +package cn.eric.rss; + +import java.io.File; +import java.io.FilenameFilter; + +import android.app.AlertDialog; +import android.app.AlertDialog.Builder; +import android.app.Activity; +import android.app.Dialog; +import android.app.NotificationManager; +import android.content.ContentValues; +import android.content.Context; +import android.content.DialogInterface; +import android.content.SharedPreferences; +import android.content.DialogInterface.OnKeyListener; +import android.content.Intent; +import android.content.SharedPreferences.Editor; +import android.database.Cursor; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; +import android.net.Uri; +import android.os.Build; +import android.os.Bundle; +import android.os.Environment; +import android.os.Looper; +import android.preference.PreferenceManager; +import android.view.ContextMenu; +import android.view.ContextMenu.ContextMenuInfo; +import android.view.KeyEvent; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.View.OnCreateContextMenuListener; +import android.widget.AdapterView; +import android.widget.AdapterView.OnItemClickListener; +import android.widget.ListView; +import android.widget.TextView; +import android.widget.Toast; +import cn.eric.rss.provider.FeedData; +import cn.eric.rss.provider.OPML; +import cn.eric.rss.service.RefreshService; +import cn.eric.rss.ui.MenuData; +import cn.eric.rss.utility.ApplicationHelper; +import cn.eric.rss.utility.MyStrings; + +import com.actionbarsherlock.app.ActionBar; +import com.actionbarsherlock.view.Menu; +import com.actionbarsherlock.view.MenuItem; +import com.actionbarsherlock.view.SubMenu; +import com.umeng.analytics.MobclickAgent; +import com.umeng.update.UmengUpdateAgent; + +/** + * the launcher and overview activity + * + * @author Ruobin Wang + * + */ +public class MainActivity extends SherlockActivityBase implements + OnItemClickListener, OnCreateContextMenuListener { + + public static MainActivity INSTANCE; + + public static final boolean POSTGINGERBREAD = !Build.VERSION.RELEASE + .startsWith("1") && !Build.VERSION.RELEASE.startsWith("2"); + + private static final int DIALOG_LICENSEAGREEMENT = 0; // save + + private static final int DIALOG_ERROR_FEEDIMPORT = 3; + + private static final int DIALOG_ERROR_FEEDEXPORT = 4; + + private static final int DIALOG_ERROR_INVALIDIMPORTFILE = 5; + + private static final int DIALOG_ERROR_EXTERNALSTORAGENOTAVAILABLE = 6; + + private static final int DIALOG_ABOUT = 7; + + private static final int CONTEXTMENU_EDIT_ID = 3; + + private static final int CONTEXTMENU_REFRESH_ID = 4; + + private static final int CONTEXTMENU_DELETE_ID = 5; + + private static final int CONTEXTMENU_MARKASREAD_ID = 6; + + private static final int CONTEXTMENU_MARKASUNREAD_ID = 7; + + private static final int CONTEXTMENU_DELETEREAD_ID = 8; + + private static final int CONTEXTMENU_DELETEALLENTRIES_ID = 9; + + private static final int CONTEXTMENU_RESETUPDATEDATE_ID = 10; + + private static final int ACTIVITY_APPLICATIONPREFERENCES_ID = 1; + + private static final Uri CANGELOG_URI = Uri + .parse("http://code.google.com/p/MiniRSS/wiki/Changelog"); + + private static final int CONTEXTMENU_SETTINGS_ID = 99; + + static NotificationManager notificationManager; + + private RSSOverviewListAdapter listAdapter; + private ListView listView; + + private View emptyView; + + public void onCreate(Bundle savedInstanceState) { + + super.onCreate(savedInstanceState); + + MobclickAgent.updateOnlineConfig(this); + UmengUpdateAgent.update(this); + UmengUpdateAgent.setUpdateOnlyWifi(false); + INSTANCE = this; + if (getPreferences(MODE_PRIVATE).getBoolean( + MyStrings.PREFERENCE_LICENSEACCEPTED, false)) { + } else { + showDialog(DIALOG_LICENSEAGREEMENT); + } + + if (notificationManager == null) { + notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); + } + + initializeForFirstUse(); + + listView = (ListView) this.findViewById(R.id.list); + listAdapter = new RSSOverviewListAdapter(this); + + emptyView = this.findViewById(android.R.id.empty); + showEmptyView(); + listView.setAdapter(listAdapter); + listView.setOnItemClickListener(this); + + listView.setOnCreateContextMenuListener(this); + + if (PreferenceManager.getDefaultSharedPreferences(this).getBoolean( + MyStrings.SETTINGS_REFRESHENABLED, true)) { + startService(new Intent(this, RefreshService.class)); + } else { + stopService(new Intent(this, RefreshService.class)); + } + + if (PreferenceManager.getDefaultSharedPreferences(this).getBoolean( + MyStrings.SETTINGS_REFRESHONPENENABLED, true)) { + new Thread() { + public void run() { + sendBroadcast(new Intent(MyStrings.ACTION_REFRESHFEEDS)); + } + }.start(); + } + } + + private void initializeForFirstUse() { + + if (!ApplicationHelper.isMaidenVoyage(this)) { + return; + } + + FeedConfigActivity.insertInitialFeeds(this); + + ApplicationHelper.createShortcutOnHomeScreen(this); + + ApplicationHelper.claimMaidenVoyage(this); + + } + + /** + * decide whether to show the empty view + */ + private void showEmptyView() { + if (Looper.getMainLooper() == Looper.myLooper()) { + if ((listAdapter == null) || listAdapter.isEmpty()) { + emptyView.setVisibility(View.VISIBLE); + } else { + emptyView.setVisibility(View.GONE); + } + } else { + runOnUiThread(new Runnable() { + @Override + public void run() { + if ((listAdapter == null) || listAdapter.isEmpty()) { + emptyView.setVisibility(View.VISIBLE); + } else { + emptyView.setVisibility(View.GONE); + } + } + }); + } + } + + @Override + protected void onResume() { + super.onResume(); + if (MainActivity.notificationManager != null) { + notificationManager.cancel(0); + } + } + + @Override + protected void onInitUpbar(ActionBar actionBar) { + super.onInitUpbar(actionBar); + actionBar.setDisplayShowTitleEnabled(true); + actionBar.setDisplayHomeAsUpEnabled(false); + actionBar.setTitle(R.string.rss_feeds); + } + + void setupLicenseText(AlertDialog.Builder builder) { + View view = getLayoutInflater().inflate(R.layout.license, null); + + final TextView textView = (TextView) view + .findViewById(R.id.license_text); + + textView.setTextColor(textView.getTextColors().getDefaultColor()); // disables + // color + // change + // on + // selection + textView.setText(new StringBuilder(getString(R.string.license_intro)) + .append(MyStrings.THREENEWLINES).append( + getString(R.string.license))); + + final TextView contributorsTextView = (TextView) view + .findViewById(R.id.contributors_togglebutton); + + contributorsTextView.setOnClickListener(new OnClickListener() { + boolean showingLicense = true; + + @Override + public void onClick(View view) { + if (showingLicense) { + textView.setText(R.string.contributors_list); + contributorsTextView.setText(R.string.license_word); + } else { + textView.setText(new StringBuilder( + getString(R.string.license_intro)).append( + MyStrings.THREENEWLINES).append( + getString(R.string.license))); + contributorsTextView.setText(R.string.contributors); + } + showingLicense = !showingLicense; + } + + }); + builder.setView(view); + } + + @Override + public boolean onCreateOptionsMenu(com.actionbarsherlock.view.Menu menu) { + + com.actionbarsherlock.view.Menu subMenu = getSubMenu(menu); + + subMenu.add(0, MenuData.MENUITEM_ADD_FEED, 0, R.string.menu_addfeed); + subMenu.add(0, MenuData.MENUITEM_REFRESH, 0, R.string.menu_refresh); + subMenu.add(0, MenuData.MENUITEM_SETTINGS, 0, R.string.menu_settings); + subMenu.add(0, MenuData.MENUITEM_MARK_ALL_AS_READ, 0, + R.string.menu_allread); + subMenu.add(0, MenuData.MENUITEM_ABOUT, 0, R.string.menu_about); + subMenu.add(0, MenuData.MENUITEM_IMPORT_FROM_OPML, 0, + R.string.menu_import); + subMenu.add(0, MenuData.MENUITEM_EXPORT_TO_OPML, 0, + R.string.menu_export); + + return true; + } + + @Override + public boolean onPrepareOptionsMenu(Menu menu) { + // menu.setGroupVisible(R.id.menu_group_0, !feedSort); + // menu.setGroupVisible(R.id.menu_group_1, feedSort); + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem menuItem) { + switch (menuItem.getItemId()) { + case MenuData.MENUITEM_ADD_FEED: + + startActivity(new Intent(Intent.ACTION_INSERT) + .setData(FeedData.FeedColumns.CONTENT_URI)); + return true; + + case MenuData.MENUITEM_REFRESH: + new Thread() { + public void run() { + sendBroadcast(new Intent(MyStrings.ACTION_REFRESHFEEDS) + .putExtra( + MyStrings.SETTINGS_OVERRIDEWIFIONLY, + PreferenceManager + .getDefaultSharedPreferences( + MainActivity.this) + .getBoolean( + MyStrings.SETTINGS_OVERRIDEWIFIONLY, + false))); + } + }.start(); + return true; + + case MenuData.MENUITEM_SETTINGS: { + startActivityForResult(new Intent(this, + ApplicationPreferencesActivity.class), + ACTIVITY_APPLICATIONPREFERENCES_ID); + break; + } + case MenuData.MENUITEM_MARK_ALL_AS_READ: { + new Thread() { + public void run() { + if (getContentResolver() + .update(FeedData.EntryColumns.CONTENT_URI, + getReadContentValues(), + new StringBuilder( + FeedData.EntryColumns.READDATE) + .append(MyStrings.DB_ISNULL) + .toString(), null) > 0) { + getContentResolver().notifyChange( + FeedData.FeedColumns.CONTENT_URI, null); + } + } + }.start(); + break; + } + case MenuData.MENUITEM_ABOUT: { + showDialog(DIALOG_ABOUT); + break; + } + case MenuData.MENUITEM_IMPORT_FROM_OPML: { + if (Environment.getExternalStorageState().equals( + Environment.MEDIA_MOUNTED) + || Environment.getExternalStorageState().equals( + Environment.MEDIA_MOUNTED_READ_ONLY)) { + final AlertDialog.Builder builder = new AlertDialog.Builder( + this); + + builder.setTitle(R.string.select_file); + + try { + final String[] fileNames = Environment + .getExternalStorageDirectory().list( + new FilenameFilter() { + public boolean accept(File dir, + String filename) { + return new File(dir, filename) + .isFile(); + } + }); + builder.setItems(fileNames, + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, + int which) { + try { + OPML.importFromFile( + new StringBuilder( + Environment + .getExternalStorageDirectory() + .toString()) + .append(File.separator) + .append(fileNames[which]) + .toString(), + MainActivity.this); + } catch (Exception e) { + showDialog(DIALOG_ERROR_FEEDIMPORT); + } + } + }); + builder.show(); + } catch (Exception e) { + showDialog(DIALOG_ERROR_FEEDIMPORT); + } + } else { + showDialog(DIALOG_ERROR_EXTERNALSTORAGENOTAVAILABLE); + } + + break; + } + case MenuData.MENUITEM_EXPORT_TO_OPML: { + if (Environment.getExternalStorageState().equals( + Environment.MEDIA_MOUNTED) + || Environment.getExternalStorageState().equals( + Environment.MEDIA_MOUNTED_READ_ONLY)) { + try { + String filename = new StringBuilder(Environment + .getExternalStorageDirectory().toString()) + .append("/sparse_rss_") + .append(System.currentTimeMillis()).append(".opml") + .toString(); + + OPML.exportToFile(filename, this); + Toast.makeText( + this, + String.format( + getString(R.string.message_exportedto), + filename), Toast.LENGTH_LONG).show(); + } catch (Exception e) { + showDialog(DIALOG_ERROR_FEEDEXPORT); + } + } else { + showDialog(DIALOG_ERROR_EXTERNALSTORAGENOTAVAILABLE); + } + break; + } + + } + + return true; + + } + + public static final ContentValues getReadContentValues() { + ContentValues values = new ContentValues(); + + values.put(FeedData.EntryColumns.READDATE, System.currentTimeMillis()); + return values; + } + + public static final ContentValues getUnreadContentValues() { + ContentValues values = new ContentValues(); + + values.putNull(FeedData.EntryColumns.READDATE); + return values; + } + + @Override + protected Dialog onCreateDialog(int id) { + Dialog dialog; + + switch (id) { + case DIALOG_ERROR_FEEDIMPORT: { + dialog = createErrorDialog(R.string.error_feedimport); + break; + } + case DIALOG_ERROR_FEEDEXPORT: { + dialog = createErrorDialog(R.string.error_feedexport); + break; + } + case DIALOG_ERROR_INVALIDIMPORTFILE: { + dialog = createErrorDialog(R.string.error_invalidimportfile); + break; + } + case DIALOG_ERROR_EXTERNALSTORAGENOTAVAILABLE: { + dialog = createErrorDialog(R.string.error_externalstoragenotavailable); + break; + } + case DIALOG_ABOUT: { + AlertDialog.Builder builder = new AlertDialog.Builder(this); + + builder.setIcon(android.R.drawable.ic_dialog_info); + builder.setTitle(R.string.menu_about); + MainActivity.INSTANCE.setupLicenseText(builder); + builder.setPositiveButton(android.R.string.ok, + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + dialog.cancel(); + } + }); + builder.setNeutralButton(R.string.changelog, + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + startActivity(new Intent(Intent.ACTION_VIEW, + CANGELOG_URI)); + } + }); + return builder.create(); + } + case DIALOG_LICENSEAGREEMENT: { + AlertDialog.Builder builder = new AlertDialog.Builder(this); + + builder.setIcon(android.R.drawable.ic_dialog_alert); + builder.setTitle(R.string.dialog_licenseagreement); + builder.setNegativeButton(R.string.button_decline, + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + dialog.cancel(); + finish(); + } + }); + builder.setPositiveButton(R.string.button_accept, + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + dialog.dismiss(); + + Editor editor = getPreferences(MODE_PRIVATE).edit(); + + editor.putBoolean( + MyStrings.PREFERENCE_LICENSEACCEPTED, true); + editor.commit(); + + // setContent(); + } + }); + setupLicenseText(builder); + builder.setOnKeyListener(new OnKeyListener() { + public boolean onKey(DialogInterface dialog, int keyCode, + KeyEvent event) { + if (keyCode == KeyEvent.KEYCODE_BACK) { + dialog.cancel(); + finish(); + } + return true; + } + }); + return builder.create(); + } + default: + dialog = null; + } + return dialog; + } + + private Dialog createErrorDialog(int messageId) { + AlertDialog.Builder builder = new AlertDialog.Builder(this); + + builder.setMessage(messageId); + builder.setTitle(R.string.error); + builder.setIcon(android.R.drawable.ic_dialog_alert); + builder.setPositiveButton(android.R.string.ok, null); + return builder.create(); + } + + static void showDeleteAllEntriesQuestion(final Context context, + final Uri uri) { + Builder builder = new AlertDialog.Builder(context); + + builder.setIcon(android.R.drawable.ic_dialog_alert); + builder.setTitle(R.string.contextmenu_deleteallentries); + builder.setMessage(R.string.question_areyousure); + builder.setPositiveButton(android.R.string.yes, + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + new Thread() { + public void run() { + FeedData.deletePicturesOfFeed(context, uri, + MyStrings.DB_EXCUDEFAVORITE); + if (context.getContentResolver().delete(uri, + MyStrings.DB_EXCUDEFAVORITE, null) > 0) { + context.getContentResolver().notifyChange( + FeedData.FeedColumns.CONTENT_URI, + null); + } + } + }.start(); + } + }); + builder.setNegativeButton(android.R.string.no, null); + builder.show(); + } + + @Override + public void onItemClick(AdapterView arg0, View view, int position, + long id) { + + Intent intent = new Intent(Intent.ACTION_VIEW, + FeedData.EntryColumns.CONTENT_URI(Long.toString(id))); + + intent.putExtra(FeedData.FeedColumns._ID, id); + startActivity(intent); + + } + + @Override + public void onCreateContextMenu(ContextMenu menu, View view, + ContextMenuInfo menuInfo) { + menu.setHeaderTitle(((TextView) ((AdapterView.AdapterContextMenuInfo) menuInfo).targetView + .findViewById(android.R.id.text1)).getText()); + menu.add(0, CONTEXTMENU_REFRESH_ID, Menu.NONE, + R.string.contextmenu_refresh); + menu.add(0, CONTEXTMENU_MARKASREAD_ID, Menu.NONE, + R.string.contextmenu_markasread); + menu.add(0, CONTEXTMENU_MARKASUNREAD_ID, Menu.NONE, + R.string.contextmenu_markasunread); + menu.add(0, CONTEXTMENU_DELETEREAD_ID, Menu.NONE, + R.string.contextmenu_deleteread); + menu.add(0, CONTEXTMENU_DELETEALLENTRIES_ID, Menu.NONE, + R.string.contextmenu_deleteallentries); + menu.add(0, CONTEXTMENU_EDIT_ID, Menu.NONE, R.string.contextmenu_edit); + menu.add(0, CONTEXTMENU_RESETUPDATEDATE_ID, Menu.NONE, + R.string.contextmenu_resetupdatedate); + menu.add(0, CONTEXTMENU_DELETE_ID, Menu.NONE, + R.string.contextmenu_delete); + menu.add(0, CONTEXTMENU_SETTINGS_ID, Menu.NONE, + R.string.contextmenu_settings); + } + + @Override + public boolean onContextItemSelected(final android.view.MenuItem item) { + switch (item.getItemId()) { + case R.id.menu_addfeed: { + startActivity(new Intent(Intent.ACTION_INSERT) + .setData(FeedData.FeedColumns.CONTENT_URI)); + break; + } + case R.id.menu_refresh: { + new Thread() { + public void run() { + sendBroadcast(new Intent(MyStrings.ACTION_REFRESHFEEDS) + .putExtra( + MyStrings.SETTINGS_OVERRIDEWIFIONLY, + PreferenceManager + .getDefaultSharedPreferences( + MainActivity.this) + .getBoolean( + MyStrings.SETTINGS_OVERRIDEWIFIONLY, + false))); + } + }.start(); + break; + } + case CONTEXTMENU_EDIT_ID: { + startActivity(new Intent(Intent.ACTION_EDIT) + .setData(FeedData.FeedColumns + .CONTENT_URI(((AdapterView.AdapterContextMenuInfo) item + .getMenuInfo()).id))); + break; + } + case CONTEXTMENU_REFRESH_ID: { + final String id = Long + .toString(((AdapterView.AdapterContextMenuInfo) item + .getMenuInfo()).id); + + ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); + + final NetworkInfo networkInfo = connectivityManager + .getActiveNetworkInfo(); + + if (networkInfo != null + && networkInfo.getState() == NetworkInfo.State.CONNECTED) { // since + // we + // have + // acquired + // the + // networkInfo, + // we + // use + // it + // for + // basic + // checks + final Intent intent = new Intent(MyStrings.ACTION_REFRESHFEEDS) + .putExtra(MyStrings.FEEDID, id); + + final Thread thread = new Thread() { + public void run() { + sendBroadcast(intent); + } + }; + + if (networkInfo.getType() == ConnectivityManager.TYPE_WIFI + || PreferenceManager.getDefaultSharedPreferences( + MainActivity.this).getBoolean( + MyStrings.SETTINGS_OVERRIDEWIFIONLY, false)) { + intent.putExtra(MyStrings.SETTINGS_OVERRIDEWIFIONLY, true); + thread.start(); + } else { + Cursor cursor = getContentResolver().query( + FeedData.FeedColumns.CONTENT_URI(id), + new String[] { FeedData.FeedColumns.WIFIONLY }, + null, null, null); + + cursor.moveToFirst(); + + if (cursor.isNull(0) || cursor.getInt(0) == 0) { + thread.start(); + } else { + Builder builder = new AlertDialog.Builder(this); + + builder.setIcon(android.R.drawable.ic_dialog_alert); + builder.setTitle(R.string.dialog_hint); + builder.setMessage(R.string.question_refreshwowifi); + builder.setPositiveButton(android.R.string.yes, + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, + int which) { + intent.putExtra( + MyStrings.SETTINGS_OVERRIDEWIFIONLY, + true); + thread.start(); + } + }); + builder.setNeutralButton( + R.string.button_alwaysokforall, + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, + int which) { + PreferenceManager + .getDefaultSharedPreferences( + MainActivity.this) + .edit() + .putBoolean( + MyStrings.SETTINGS_OVERRIDEWIFIONLY, + true).commit(); + intent.putExtra( + MyStrings.SETTINGS_OVERRIDEWIFIONLY, + true); + thread.start(); + } + }); + builder.setNegativeButton(android.R.string.no, null); + builder.show(); + } + cursor.close(); + } + + } + break; + } + case CONTEXTMENU_DELETE_ID: { + String id = Long + .toString(((AdapterView.AdapterContextMenuInfo) item + .getMenuInfo()).id); + + Cursor cursor = getContentResolver().query( + FeedData.FeedColumns.CONTENT_URI(id), + new String[] { FeedData.FeedColumns.NAME }, null, null, + null); + + cursor.moveToFirst(); + + Builder builder = new AlertDialog.Builder(this); + + builder.setIcon(android.R.drawable.ic_dialog_alert); + builder.setTitle(cursor.getString(0)); + builder.setMessage(R.string.question_deletefeed); + builder.setPositiveButton(android.R.string.yes, + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + new Thread() { + public void run() { + getContentResolver() + .delete(FeedData.FeedColumns + .CONTENT_URI(Long + .toString(((AdapterView.AdapterContextMenuInfo) item + .getMenuInfo()).id)), + null, null); + sendBroadcast(new Intent( + MyStrings.ACTION_UPDATEWIDGET)); + + showEmptyView(); + } + }.start(); + } + }); + builder.setNegativeButton(android.R.string.no, null); + cursor.close(); + builder.show(); + break; + } + case CONTEXTMENU_MARKASREAD_ID: { + new Thread() { + public void run() { + String id = Long + .toString(((AdapterView.AdapterContextMenuInfo) item + .getMenuInfo()).id); + + if (getContentResolver() + .update(FeedData.EntryColumns.CONTENT_URI(id), + getReadContentValues(), + new StringBuilder( + FeedData.EntryColumns.READDATE) + .append(MyStrings.DB_ISNULL) + .toString(), null) > 0) { + getContentResolver().notifyChange( + FeedData.FeedColumns.CONTENT_URI(id), null); + } + } + }.start(); + break; + } + case CONTEXTMENU_MARKASUNREAD_ID: { + new Thread() { + public void run() { + String id = Long + .toString(((AdapterView.AdapterContextMenuInfo) item + .getMenuInfo()).id); + + if (getContentResolver().update( + FeedData.EntryColumns.CONTENT_URI(id), + getUnreadContentValues(), null, null) > 0) { + getContentResolver().notifyChange( + FeedData.FeedColumns.CONTENT_URI(id), null); + ; + } + } + }.start(); + break; + } + case CONTEXTMENU_SETTINGS_ID: { + startActivity(new Intent(this, FeedPrefsActivity.class).putExtra( + FeedData.FeedColumns._ID, + Long.toString(((AdapterView.AdapterContextMenuInfo) item + .getMenuInfo()).id))); + break; + } + case CONTEXTMENU_DELETEREAD_ID: { + new Thread() { + public void run() { + String id = Long + .toString(((AdapterView.AdapterContextMenuInfo) item + .getMenuInfo()).id); + + Uri uri = FeedData.EntryColumns.CONTENT_URI(id); + + String selection = MyStrings.READDATE_GREATERZERO + + MyStrings.DB_AND + " (" + MyStrings.DB_EXCUDEFAVORITE + + ")"; + + FeedData.deletePicturesOfFeed(MainActivity.this, uri, + selection); + if (getContentResolver().delete(uri, selection, null) > 0) { + getContentResolver().notifyChange( + FeedData.FeedColumns.CONTENT_URI(id), null); + } + } + }.start(); + break; + } + case CONTEXTMENU_DELETEALLENTRIES_ID: { + showDeleteAllEntriesQuestion( + this, + FeedData.EntryColumns.CONTENT_URI(Long + .toString(((AdapterView.AdapterContextMenuInfo) item + .getMenuInfo()).id))); + break; + } + case CONTEXTMENU_RESETUPDATEDATE_ID: { + ContentValues values = new ContentValues(); + + values.put(FeedData.FeedColumns.LASTUPDATE, 0); + values.put(FeedData.FeedColumns.REALLASTUPDATE, 0); + getContentResolver() + .update(FeedData.FeedColumns.CONTENT_URI(Long + .toString(((AdapterView.AdapterContextMenuInfo) item + .getMenuInfo()).id)), values, null, null); + break; + } + + case R.id.menu_deleteread: { + FeedData.deletePicturesOfFeedAsync(this, + FeedData.EntryColumns.CONTENT_URI, + MyStrings.READDATE_GREATERZERO); + getContentResolver().delete(FeedData.EntryColumns.CONTENT_URI, + MyStrings.READDATE_GREATERZERO, null); + listAdapter.notifyDataSetChanged(); + + break; + } + case R.id.menu_deleteallentries: { + showDeleteAllEntriesQuestion(this, + FeedData.EntryColumns.CONTENT_URI); + break; + } + } + return true; + } + + @Override + protected int getLayoutRes() { + return R.layout.main; + } +} diff --git a/src/de/shandschuh/sparserss/RSSOverviewListAdapter.java b/src/cn/eric/rss/RSSOverviewListAdapter.java similarity index 94% rename from src/de/shandschuh/sparserss/RSSOverviewListAdapter.java rename to src/cn/eric/rss/RSSOverviewListAdapter.java index 48bf773..e2546cf 100644 --- a/src/de/shandschuh/sparserss/RSSOverviewListAdapter.java +++ b/src/cn/eric/rss/RSSOverviewListAdapter.java @@ -23,7 +23,7 @@ * */ -package de.shandschuh.sparserss; +package cn.eric.rss; import java.text.DateFormat; import java.util.Date; @@ -41,7 +41,10 @@ import android.view.View; import android.widget.ResourceCursorAdapter; import android.widget.TextView; -import de.shandschuh.sparserss.provider.FeedData; +import cn.eric.rss.R; +import cn.eric.rss.provider.FeedData; +import cn.eric.rss.utility.SimpleTask; +import cn.eric.rss.utility.MyStrings; public class RSSOverviewListAdapter extends ResourceCursorAdapter { private static final String COUNT_UNREAD = "COUNT(*) - COUNT(readdate)"; @@ -76,6 +79,7 @@ public class RSSOverviewListAdapter extends ResourceCursorAdapter { public RSSOverviewListAdapter(Activity activity) { super(activity, R.layout.feedlistitem, activity.managedQuery(FeedData.FeedColumns.CONTENT_URI, null, null, null, null)); + Cursor cursor=activity.managedQuery(FeedData.FeedColumns.CONTENT_URI, null, null, null, null); nameColumnPosition = getCursor().getColumnIndex(FeedData.FeedColumns.NAME); lastUpdateColumn = getCursor().getColumnIndex(FeedData.FeedColumns.LASTUPDATE); idPosition = getCursor().getColumnIndex(FeedData.FeedColumns._ID); @@ -126,7 +130,7 @@ public void bindView(View view, Context context, Cursor cursor) { if (cursor.isNull(errorPosition)) { Date date = new Date(timestamp); - updateTextView.setText(new StringBuilder(context.getString(R.string.update)).append(COLON).append(timestamp == 0 ? context.getString(R.string.never) : new StringBuilder(dateFormat.format(date)).append(' ').append(timeFormat.format(date)).append(Strings.COMMASPACE).append(unreadCount).append('/').append(count).append(' ').append(context.getString(R.string.unread)))); + updateTextView.setText(new StringBuilder(context.getString(R.string.update)).append(COLON).append(timestamp == 0 ? context.getString(R.string.never) : new StringBuilder(dateFormat.format(date)).append(' ').append(timeFormat.format(date)).append(MyStrings.COMMASPACE).append(unreadCount).append('/').append(count).append(' ').append(context.getString(R.string.unread)))); } else { updateTextView.setText(new StringBuilder(context.getString(R.string.error)).append(COLON).append(cursor.getString(errorPosition))); } diff --git a/src/de/shandschuh/sparserss/RefreshBroadcastReceiver.java b/src/cn/eric/rss/RefreshBroadcastReceiver.java similarity index 89% rename from src/de/shandschuh/sparserss/RefreshBroadcastReceiver.java rename to src/cn/eric/rss/RefreshBroadcastReceiver.java index 4eafe7c..d9ac5c7 100644 --- a/src/de/shandschuh/sparserss/RefreshBroadcastReceiver.java +++ b/src/cn/eric/rss/RefreshBroadcastReceiver.java @@ -1,39 +1,44 @@ -/** - * Sparse rss - * - * Copyright (c) 2010 Stefan Handschuh - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - */ - -package de.shandschuh.sparserss; - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import de.shandschuh.sparserss.service.FetcherService; - -public class RefreshBroadcastReceiver extends BroadcastReceiver { - @Override - public void onReceive(Context context, Intent intent) { - context.startService(new Intent(context, FetcherService.class).putExtras(intent)); // a thread would mark the process as inactive - } - -} +/** + * Sparse rss + * + * Copyright (c) 2010 Stefan Handschuh + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +package cn.eric.rss; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import cn.eric.rss.service.FetcherService; + +/** + * call the fetch(refresh) service here + * @author Ruobin Wang + * + */ +public class RefreshBroadcastReceiver extends BroadcastReceiver { + @Override + public void onReceive(Context context, Intent intent) { + context.startService(new Intent(context, FetcherService.class).putExtras(intent)); // a thread would mark the process as inactive + } + +} diff --git a/src/cn/eric/rss/SherlockActivityBase.java b/src/cn/eric/rss/SherlockActivityBase.java new file mode 100644 index 0000000..09f6523 --- /dev/null +++ b/src/cn/eric/rss/SherlockActivityBase.java @@ -0,0 +1,112 @@ +/** + * + */ +package cn.eric.rss; + +import android.os.Bundle; +import android.os.Looper; + +import com.actionbarsherlock.app.ActionBar; +import com.actionbarsherlock.app.SherlockActivity; +import com.actionbarsherlock.view.MenuItem; +import com.actionbarsherlock.view.SubMenu; +import com.umeng.analytics.MobclickAgent; + +/** + * @author Ruobin Wang + * + */ +public abstract class SherlockActivityBase extends SherlockActivity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + this.setTheme(R.style.Theme_Eric); + setContentView(getLayoutRes()); + + ActionBar actionBar = getSupportActionBar(); + onInitConfiguration(); + onInitUpbar(actionBar); + } + + /** + * 获取并设置当前的layout + * + * @return + */ + protected abstract int getLayoutRes(); + + /** + * 初始化用户配置 + */ + protected void onInitConfiguration() { + // UserConfigurationUtils + // .loadUserConfig(getApplicationContext(), + // TravelUserConfigurationImpl.class); + } + + /** + * 初始化upBar + */ + protected void onInitUpbar(ActionBar actionBar) { + actionBar.setLogo(R.drawable.ic_logo); + actionBar.setDisplayShowTitleEnabled(false); + actionBar.setDisplayHomeAsUpEnabled(true); + } + + /** + * if you can't get title as soon as the activity is created, you can update + * it later + * + * @param title + */ + protected void updateUpbarTitle(final String title) { + final ActionBar actionBar = getSupportActionBar(); + if (actionBar != null) { + if (Looper.getMainLooper() == Looper.myLooper()) { + actionBar.setDisplayShowTitleEnabled(true); + actionBar.setTitle(title); + } else { + runOnUiThread(new Runnable() { + @Override + public void run() { + actionBar.setDisplayShowTitleEnabled(true); + actionBar.setTitle(title); + } + }); + } + } + } + + + protected SubMenu getSubMenu(com.actionbarsherlock.view.Menu menu){ + SubMenu subMenu = menu.addSubMenu("").setIcon(R.drawable.ic_more); + + subMenu.getItem().setShowAsAction( + MenuItem.SHOW_AS_ACTION_ALWAYS + | MenuItem.SHOW_AS_ACTION_WITH_TEXT); + return subMenu; + } + + @Override + public boolean onOptionsItemSelected( + com.actionbarsherlock.view.MenuItem menuItem) { + if (menuItem.getItemId() == android.R.id.home) { + finish(); + return true; + } + return super.onOptionsItemSelected(menuItem); + } + + @Override + protected void onPause() { + super.onPause(); + MobclickAgent.onPause(this); + } + + @Override + protected void onResume() { + super.onResume(); + MobclickAgent.onResume(this); + } +} diff --git a/src/de/shandschuh/sparserss/handler/PictureFilenameFilter.java b/src/cn/eric/rss/handler/PictureFilenameFilter.java similarity index 92% rename from src/de/shandschuh/sparserss/handler/PictureFilenameFilter.java rename to src/cn/eric/rss/handler/PictureFilenameFilter.java index 7314a64..7762641 100644 --- a/src/de/shandschuh/sparserss/handler/PictureFilenameFilter.java +++ b/src/cn/eric/rss/handler/PictureFilenameFilter.java @@ -1,59 +1,59 @@ -/** - * Sparse rss - * - * Copyright (c) 2012 Stefan Handschuh - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - */ - -package de.shandschuh.sparserss.handler; - -import java.io.File; -import java.io.FilenameFilter; -import java.util.regex.Pattern; - -import de.shandschuh.sparserss.provider.FeedDataContentProvider; - -public class PictureFilenameFilter implements FilenameFilter { - private static final String REGEX = "__[^\\.]*\\.[A-Za-z]*"; - - private Pattern pattern; - - public PictureFilenameFilter(String entryId) { - setEntryId(entryId); - } - - public PictureFilenameFilter() { - - } - - public void setEntryId(String entryId) { - pattern = Pattern.compile(entryId+REGEX); - } - - public boolean accept(File dir, String filename) { - if (dir != null && dir.equals(FeedDataContentProvider.IMAGEFOLDER_FILE)) { // this should be always true but lets check it anyway - return pattern.matcher(filename).find(); - } else { - return false; - } - } - -} +/** + * Sparse rss + * + * Copyright (c) 2012 Stefan Handschuh + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +package cn.eric.rss.handler; + +import java.io.File; +import java.io.FilenameFilter; +import java.util.regex.Pattern; + +import cn.eric.rss.provider.FeedDataContentProvider; + +public class PictureFilenameFilter implements FilenameFilter { + private static final String REGEX = "__[^\\.]*\\.[A-Za-z]*"; + + private Pattern pattern; + + public PictureFilenameFilter(String entryId) { + setEntryId(entryId); + } + + public PictureFilenameFilter() { + + } + + public void setEntryId(String entryId) { + pattern = Pattern.compile(entryId+REGEX); + } + + public boolean accept(File dir, String filename) { + if (dir != null && dir.equals(FeedDataContentProvider.IMAGEFOLDER_FILE)) { // this should be always true but lets check it anyway + return pattern.matcher(filename).find(); + } else { + return false; + } + } + +} diff --git a/src/de/shandschuh/sparserss/handler/RSSHandler.java b/src/cn/eric/rss/handler/RSSHandler.java similarity index 89% rename from src/de/shandschuh/sparserss/handler/RSSHandler.java rename to src/cn/eric/rss/handler/RSSHandler.java index f78a0dc..df2acb8 100644 --- a/src/de/shandschuh/sparserss/handler/RSSHandler.java +++ b/src/cn/eric/rss/handler/RSSHandler.java @@ -23,7 +23,7 @@ * */ -package de.shandschuh.sparserss.handler; +package cn.eric.rss.handler; import java.io.FileOutputStream; import java.io.IOException; @@ -48,10 +48,10 @@ import android.net.Uri; import android.preference.PreferenceManager; import android.text.Html; -import de.shandschuh.sparserss.Strings; -import de.shandschuh.sparserss.provider.FeedData; -import de.shandschuh.sparserss.provider.FeedDataContentProvider; -import de.shandschuh.sparserss.service.FetcherService; +import cn.eric.rss.utility.MyStrings; +import cn.eric.rss.provider.FeedData; +import cn.eric.rss.provider.FeedDataContentProvider; +import cn.eric.rss.service.FetcherService; public class RSSHandler extends DefaultHandler { private static final String ANDRHOMBUS = "&#"; @@ -139,7 +139,7 @@ public class RSSHandler extends DefaultHandler { private static final String GMT = "GMT"; - private static final StringBuilder DB_FAVORITE = new StringBuilder(" AND (").append(Strings.DB_EXCUDEFAVORITE).append(')'); + private static final StringBuilder DB_FAVORITE = new StringBuilder(" AND (").append(MyStrings.DB_EXCUDEFAVORITE).append(')'); private static Pattern imgPattern = Pattern.compile("]*>"); // middle () is group 1; s* is important for non-whitespaces; ' also usable @@ -216,7 +216,7 @@ public class RSSHandler extends DefaultHandler { private boolean nameTagEntered; public RSSHandler(Context context) { - KEEP_TIME = Long.parseLong(PreferenceManager.getDefaultSharedPreferences(context).getString(Strings.SETTINGS_KEEPTIME, "4"))*86400000l; + KEEP_TIME = Long.parseLong(PreferenceManager.getDefaultSharedPreferences(context).getString(MyStrings.SETTINGS_KEEPTIME, "4"))*86400000l; this.context = context; this.efficientFeedParsing = true; } @@ -308,8 +308,8 @@ public void startElement(String uri, String localName, String qName, Attributes if (authorTagEntered) { return; } - if (TAG_ENCLOSURE.equals(attributes.getValue(Strings.EMPTY, ATTRIBUTE_REL))) { - startEnclosure(attributes, attributes.getValue(Strings.EMPTY, ATTRIBUTE_HREF)); + if (TAG_ENCLOSURE.equals(attributes.getValue(MyStrings.EMPTY, ATTRIBUTE_REL))) { + startEnclosure(attributes, attributes.getValue(MyStrings.EMPTY, ATTRIBUTE_HREF)); } else { entryLink = new StringBuilder(); @@ -352,7 +352,7 @@ public void startElement(String uri, String localName, String qName, Attributes descriptionTagEntered = true; description = new StringBuilder(); } else if (TAG_ENCLOSURE.equals(localName)) { - startEnclosure(attributes, attributes.getValue(Strings.EMPTY, ATTRIBUTE_URL)); + startEnclosure(attributes, attributes.getValue(MyStrings.EMPTY, ATTRIBUTE_URL)); } else if (TAG_GUID.equals(localName)) { guidTagEntered = true; guid = new StringBuilder(); @@ -362,7 +362,7 @@ public void startElement(String uri, String localName, String qName, Attributes author = new StringBuilder(); } else { // this indicates multiple authors - author.append(Strings.COMMASPACE); + author.append(MyStrings.COMMASPACE); } } else if (TAG_NAME.equals(localName)) { nameTagEntered = true; @@ -372,15 +372,15 @@ public void startElement(String uri, String localName, String qName, Attributes private void startEnclosure(Attributes attributes, String url) { if (enclosure == null) { // fetch the first enclosure only enclosure = new StringBuilder(url); - enclosure.append(Strings.ENCLOSURE_SEPARATOR); + enclosure.append(MyStrings.ENCLOSURE_SEPARATOR); - String value = attributes.getValue(Strings.EMPTY, ATTRIBUTE_TYPE); + String value = attributes.getValue(MyStrings.EMPTY, ATTRIBUTE_TYPE); if (value != null) { enclosure.append(value); } - enclosure.append(Strings.ENCLOSURE_SEPARATOR); - value = attributes.getValue(Strings.EMPTY, ATTRIBUTE_LENGTH); + enclosure.append(MyStrings.ENCLOSURE_SEPARATOR); + value = attributes.getValue(MyStrings.EMPTY, ATTRIBUTE_LENGTH); if (value != null) { enclosure.append(value); } @@ -422,10 +422,10 @@ public void endElement(String uri, String localName, String qName) throws SAXExc entryDate = parseUpdateDate(dateStringBuilder.toString()); updatedTagEntered = false; } else if (TAG_PUBDATE.equals(localName)) { - entryDate = parsePubdateDate(dateStringBuilder.toString().replace(Strings.TWOSPACE, Strings.SPACE)); + entryDate = parsePubdateDate(dateStringBuilder.toString().replace(MyStrings.TWOSPACE, MyStrings.SPACE)); pubDateTagEntered = false; } else if (TAG_LASTBUILDDATE.equals(localName)) { - lastBuildDate = parsePubdateDate(dateStringBuilder.toString().replace(Strings.TWOSPACE, Strings.SPACE)); + lastBuildDate = parsePubdateDate(dateStringBuilder.toString().replace(MyStrings.TWOSPACE, MyStrings.SPACE)); lastUpdateDateTagEntered = false; } else if (TAG_DATE.equals(localName)) { entryDate = parseUpdateDate(dateStringBuilder.toString()); @@ -455,7 +455,7 @@ public void endElement(String uri, String localName, String qName) throws SAXExc Vector images = null; if (description != null) { - String descriptionString = description.toString().trim().replaceAll(Strings.HTML_SPAN_REGEX, Strings.EMPTY); + String descriptionString = description.toString().trim().replaceAll(MyStrings.HTML_SPAN_REGEX, MyStrings.EMPTY); if (descriptionString.length() > 0) { if (fetchImages) { @@ -464,10 +464,10 @@ public void endElement(String uri, String localName, String qName) throws SAXExc Matcher matcher = imgPattern.matcher(description); while (matcher.find()) { - String match = matcher.group(1).replace(Strings.SPACE, Strings.URL_SPACE); + String match = matcher.group(1).replace(MyStrings.SPACE, MyStrings.URL_SPACE); images.add(match); - descriptionString = descriptionString.replace(match, new StringBuilder(Strings.FILEURL).append(FeedDataContentProvider.IMAGEFOLDER).append(Strings.IMAGEID_REPLACEMENT).append(match.substring(match.lastIndexOf('/')+1)).toString()); + descriptionString = descriptionString.replace(match, new StringBuilder(MyStrings.FILEURL).append(FeedDataContentProvider.IMAGEFOLDER).append(MyStrings.IMAGEID_REPLACEMENT).append(match.substring(match.lastIndexOf('/')+1)).toString()); } } values.put(FeedData.EntryColumns.ABSTRACT, descriptionString); @@ -476,12 +476,12 @@ public void endElement(String uri, String localName, String qName) throws SAXExc String enclosureString = null; - StringBuilder existanceStringBuilder = new StringBuilder(FeedData.EntryColumns.LINK).append(Strings.DB_ARG); + StringBuilder existanceStringBuilder = new StringBuilder(FeedData.EntryColumns.LINK).append(MyStrings.DB_ARG); if (enclosure != null && enclosure.length() > 0) { enclosureString = enclosure.toString(); values.put(FeedData.EntryColumns.ENCLOSURE, enclosureString); - existanceStringBuilder.append(Strings.DB_AND).append(FeedData.EntryColumns.ENCLOSURE).append(Strings.DB_ARG); + existanceStringBuilder.append(MyStrings.DB_AND).append(FeedData.EntryColumns.ENCLOSURE).append(MyStrings.DB_ARG); } String guidString = null; @@ -489,15 +489,15 @@ public void endElement(String uri, String localName, String qName) throws SAXExc if (guid != null && guid.length() > 0) { guidString = guid.toString(); values.put(FeedData.EntryColumns.GUID, guidString); - existanceStringBuilder.append(Strings.DB_AND).append(FeedData.EntryColumns.GUID).append(Strings.DB_ARG); + existanceStringBuilder.append(MyStrings.DB_AND).append(FeedData.EntryColumns.GUID).append(MyStrings.DB_ARG); } - String entryLinkString = Strings.EMPTY; // don't set this to null as we need *some* value + String entryLinkString = MyStrings.EMPTY; // don't set this to null as we need *some* value if (entryLink != null && entryLink.length() > 0) { entryLinkString = entryLink.toString().trim(); - if (feedBaseUrl != null && !entryLinkString.startsWith(Strings.HTTP) && !entryLinkString.startsWith(Strings.HTTPS)) { - entryLinkString = feedBaseUrl + (entryLinkString.startsWith(Strings.SLASH) ? entryLinkString : Strings.SLASH + entryLinkString); + if (feedBaseUrl != null && !entryLinkString.startsWith(MyStrings.HTTP) && !entryLinkString.startsWith(MyStrings.HTTPS)) { + entryLinkString = feedBaseUrl + (entryLinkString.startsWith(MyStrings.SLASH) ? entryLinkString : MyStrings.SLASH + entryLinkString); } } @@ -531,7 +531,7 @@ public void endElement(String uri, String localName, String qName) throws SAXExc byte[] data = FetcherService.getBytes(new URL(images.get(n)).openStream()); - FileOutputStream fos = new FileOutputStream(new StringBuilder(FeedDataContentProvider.IMAGEFOLDER).append(entryId).append(Strings.IMAGEFILE_IDSEPARATOR).append(match.substring(match.lastIndexOf('/')+1)).toString()); + FileOutputStream fos = new FileOutputStream(new StringBuilder(FeedDataContentProvider.IMAGEFOLDER).append(entryId).append(MyStrings.IMAGEFILE_IDSEPARATOR).append(match.substring(match.lastIndexOf('/')+1)).toString()); fos.write(data); fos.close(); @@ -637,7 +637,7 @@ private static Date parsePubdateDate(String string) { } private static String unescapeTitle(String title) { - String result = title.replace(Strings.AMP_SG, Strings.AMP).replaceAll(Strings.HTML_TAG_REGEX, Strings.EMPTY).replace(Strings.HTML_LT, Strings.LT).replace(Strings.HTML_GT, Strings.GT).replace(Strings.HTML_QUOT, Strings.QUOT).replace(Strings.HTML_APOSTROPHE, Strings.APOSTROPHE); + String result = title.replace(MyStrings.AMP_SG, MyStrings.AMP).replaceAll(MyStrings.HTML_TAG_REGEX, MyStrings.EMPTY).replace(MyStrings.HTML_LT, MyStrings.LT).replace(MyStrings.HTML_GT, MyStrings.GT).replace(MyStrings.HTML_QUOT, MyStrings.QUOT).replace(MyStrings.HTML_APOSTROPHE, MyStrings.APOSTROPHE); if (result.indexOf(ANDRHOMBUS) > -1) { return Html.fromHtml(result, null, null).toString(); diff --git a/src/de/shandschuh/sparserss/provider/FeedData.java b/src/cn/eric/rss/provider/FeedData.java similarity index 69% rename from src/de/shandschuh/sparserss/provider/FeedData.java rename to src/cn/eric/rss/provider/FeedData.java index 54066d7..192b19f 100644 --- a/src/de/shandschuh/sparserss/provider/FeedData.java +++ b/src/cn/eric/rss/provider/FeedData.java @@ -1,181 +1,206 @@ -/** - * Sparse rss - * - * Copyright (c) 2010-2012 Stefan Handschuh - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - */ - -package de.shandschuh.sparserss.provider; - -import java.io.File; - -import de.shandschuh.sparserss.handler.PictureFilenameFilter; - -import android.content.Context; -import android.database.Cursor; -import android.net.Uri; -import android.provider.BaseColumns; - -public class FeedData { - public static final String CONTENT = "content://"; - - public static final String AUTHORITY = "de.shandschuh.sparserss.provider.FeedData"; - - private static final String TYPE_PRIMARY_KEY = "INTEGER PRIMARY KEY AUTOINCREMENT"; - - protected static final String TYPE_TEXT = "TEXT"; - - protected static final String TYPE_DATETIME = "DATETIME"; - - protected static final String TYPE_INT = "INT"; - - protected static final String TYPE_BOOLEAN = "INTEGER(1)"; - - public static final String FEED_DEFAULTSORTORDER = FeedColumns.PRIORITY; - - public static class FeedColumns implements BaseColumns { - public static final Uri CONTENT_URI = Uri.parse(new StringBuilder(CONTENT).append(AUTHORITY).append("/feeds").toString()); - - public static final String URL = "url"; - - public static final String NAME = "name"; - - public static final String OTHER_ALERT_RINGTONE = "other_alertringtone"; - - public static final String ALERT_RINGTONE = "alertringtone"; - - public static final String SKIP_ALERT = "skipalert"; - - public static final String LASTUPDATE = "lastupdate"; - - public static final String ICON = "icon"; - - public static final String ERROR = "error"; - - public static final String PRIORITY = "priority"; - - public static final String FETCHMODE = "fetchmode"; - - public static final String REALLASTUPDATE = "reallastupdate"; - - public static final String WIFIONLY = "wifionly"; - - public static final String[] COLUMNS = new String[] {_ID, URL, NAME, LASTUPDATE, ICON, ERROR, PRIORITY, FETCHMODE, REALLASTUPDATE, ALERT_RINGTONE, OTHER_ALERT_RINGTONE, SKIP_ALERT, WIFIONLY}; - - public static final String[] TYPES = new String[] {TYPE_PRIMARY_KEY, "TEXT UNIQUE", TYPE_TEXT, TYPE_DATETIME, "BLOB", TYPE_TEXT, TYPE_INT, TYPE_INT, TYPE_DATETIME, TYPE_TEXT, TYPE_INT, TYPE_INT, TYPE_BOOLEAN}; - - public static final Uri CONTENT_URI(String feedId) { - return Uri.parse(new StringBuilder(CONTENT).append(AUTHORITY).append("/feeds/").append(feedId).toString()); - } - - public static final Uri CONTENT_URI(long feedId) { - return Uri.parse(new StringBuilder(CONTENT).append(AUTHORITY).append("/feeds/").append(feedId).toString()); - } - } - - public static class EntryColumns implements BaseColumns { - public static final String FEED_ID = "feedid"; - - public static final String TITLE = "title"; - - public static final String ABSTRACT = "abstract"; - - public static final String DATE = "date"; - - public static final String READDATE = "readdate"; - - public static final String LINK = "link"; - - public static final String FAVORITE = "favorite"; - - public static final String ENCLOSURE = "enclosure"; - - public static final String GUID = "guid"; - - public static final String AUTHOR = "author"; - - public static final String[] COLUMNS = new String[] {_ID, FEED_ID, TITLE, ABSTRACT, DATE, READDATE, LINK, FAVORITE, ENCLOSURE, GUID, AUTHOR}; - - public static final String[] TYPES = new String[] {TYPE_PRIMARY_KEY, "INTEGER(7)", TYPE_TEXT, TYPE_TEXT, TYPE_DATETIME, TYPE_DATETIME, TYPE_TEXT, TYPE_BOOLEAN, TYPE_TEXT, TYPE_TEXT, TYPE_TEXT}; - - public static Uri CONTENT_URI = Uri.parse(new StringBuilder(CONTENT).append(AUTHORITY).append("/entries").toString()); - - public static Uri FAVORITES_CONTENT_URI = Uri.parse(new StringBuilder(CONTENT).append(AUTHORITY).append("/favorites").toString()); - - public static Uri CONTENT_URI(String feedId) { - return Uri.parse(new StringBuilder(CONTENT).append(AUTHORITY).append("/feeds/").append(feedId).append("/entries").toString()); - } - - public static Uri ENTRY_CONTENT_URI(String entryId) { - return Uri.parse(new StringBuilder(CONTENT).append(AUTHORITY).append("/entries/").append(entryId).toString()); - } - - public static Uri PARENT_URI(String path) { - return Uri.parse(new StringBuilder(CONTENT).append(AUTHORITY).append(path.substring(0, path.lastIndexOf('/'))).toString()); - } - - } - - private static String[] IDPROJECTION = new String[] {FeedData.EntryColumns._ID}; - - public static void deletePicturesOfFeedAsync(final Context context, final Uri entriesUri, final String selection) { - if (FeedDataContentProvider.IMAGEFOLDER_FILE.exists()) { - new Thread() { - public void run() { - deletePicturesOfFeed(context, entriesUri, selection); - } - }.start(); - } - } - - public static synchronized void deletePicturesOfFeed(Context context, Uri entriesUri, String selection) { - if (FeedDataContentProvider.IMAGEFOLDER_FILE.exists()) { - PictureFilenameFilter filenameFilter = new PictureFilenameFilter(); - - Cursor cursor = context.getContentResolver().query(entriesUri, IDPROJECTION, selection, null, null); - - while (cursor.moveToNext()) { - filenameFilter.setEntryId(cursor.getString(0)); - - File[] files = FeedDataContentProvider.IMAGEFOLDER_FILE.listFiles(filenameFilter); - - for (int n = 0, i = files != null ? files.length : 0; n < i; n++) { - files[n].delete(); - } - } - cursor.close(); - } - } - - public static synchronized void deletePicturesOfEntry(String entryId) { - if (FeedDataContentProvider.IMAGEFOLDER_FILE.exists()) { - PictureFilenameFilter filenameFilter = new PictureFilenameFilter(entryId); - - File[] files = FeedDataContentProvider.IMAGEFOLDER_FILE.listFiles(filenameFilter); - - for (int n = 0, i = files != null ? files.length : 0; n < i; n++) { - files[n].delete(); - } - } - } - - -} +/** + * Sparse rss + * + * Copyright (c) 2010-2012 Stefan Handschuh + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +package cn.eric.rss.provider; + +import java.io.File; + +import cn.eric.rss.handler.PictureFilenameFilter; + +import android.content.Context; +import android.database.Cursor; +import android.net.Uri; +import android.provider.BaseColumns; + +public class FeedData { + public static final String CONTENT = "content://"; + + public static final String AUTHORITY = "cn.eric.rss.provider.FeedData"; + + private static final String TYPE_PRIMARY_KEY = "INTEGER PRIMARY KEY AUTOINCREMENT"; + + protected static final String TYPE_TEXT = "TEXT"; + + protected static final String TYPE_DATETIME = "DATETIME"; + + protected static final String TYPE_INT = "INT"; + + protected static final String TYPE_BOOLEAN = "INTEGER(1)"; + + public static final String FEED_DEFAULTSORTORDER = FeedColumns.PRIORITY; + + public static class FeedColumns implements BaseColumns { + public static final Uri CONTENT_URI = Uri.parse(new StringBuilder( + CONTENT).append(AUTHORITY).append("/feeds").toString()); + + public static final String URL = "url"; + + public static final String NAME = "name"; + + public static final String OTHER_ALERT_RINGTONE = "other_alertringtone"; + + public static final String ALERT_RINGTONE = "alertringtone"; + + public static final String SKIP_ALERT = "skipalert"; + + public static final String LASTUPDATE = "lastupdate"; + + public static final String ICON = "icon"; + + public static final String ERROR = "error"; + + public static final String PRIORITY = "priority"; + + public static final String FETCHMODE = "fetchmode"; + + public static final String REALLASTUPDATE = "reallastupdate"; + + public static final String WIFIONLY = "wifionly"; + + public static final String[] COLUMNS = new String[] { _ID, URL, NAME, + LASTUPDATE, ICON, ERROR, PRIORITY, FETCHMODE, REALLASTUPDATE, + ALERT_RINGTONE, OTHER_ALERT_RINGTONE, SKIP_ALERT, WIFIONLY }; + + public static final String[] TYPES = new String[] { TYPE_PRIMARY_KEY, + "TEXT UNIQUE", TYPE_TEXT, TYPE_DATETIME, "BLOB", TYPE_TEXT, + TYPE_INT, TYPE_INT, TYPE_DATETIME, TYPE_TEXT, TYPE_INT, + TYPE_INT, TYPE_BOOLEAN }; + + public static final Uri CONTENT_URI(String feedId) { + return Uri.parse(new StringBuilder(CONTENT).append(AUTHORITY) + .append("/feeds/").append(feedId).toString()); + } + + public static final Uri CONTENT_URI(long feedId) { + return Uri.parse(new StringBuilder(CONTENT).append(AUTHORITY) + .append("/feeds/").append(feedId).toString()); + } + } + + public static class EntryColumns implements BaseColumns { + public static final String FEED_ID = "feedid"; + + public static final String TITLE = "title"; + + public static final String ABSTRACT = "abstract"; + + public static final String DATE = "date"; + + public static final String READDATE = "readdate"; + + public static final String LINK = "link"; + + public static final String FAVORITE = "favorite"; + + public static final String ENCLOSURE = "enclosure"; + + public static final String GUID = "guid"; + + public static final String AUTHOR = "author"; + + public static final String[] COLUMNS = new String[] { _ID, FEED_ID, + TITLE, ABSTRACT, DATE, READDATE, LINK, FAVORITE, ENCLOSURE, + GUID, AUTHOR }; + + public static final String[] TYPES = new String[] { TYPE_PRIMARY_KEY, + "INTEGER(7)", TYPE_TEXT, TYPE_TEXT, TYPE_DATETIME, + TYPE_DATETIME, TYPE_TEXT, TYPE_BOOLEAN, TYPE_TEXT, TYPE_TEXT, + TYPE_TEXT }; + + public static Uri CONTENT_URI = Uri.parse(new StringBuilder(CONTENT) + .append(AUTHORITY).append("/entries").toString()); + + public static Uri FAVORITES_CONTENT_URI = Uri.parse(new StringBuilder( + CONTENT).append(AUTHORITY).append("/favorites").toString()); + + public static Uri CONTENT_URI(String feedId) { + return Uri.parse(new StringBuilder(CONTENT).append(AUTHORITY) + .append("/feeds/").append(feedId).append("/entries") + .toString()); + } + + public static Uri ENTRY_CONTENT_URI(String entryId) { + return Uri.parse(new StringBuilder(CONTENT).append(AUTHORITY) + .append("/entries/").append(entryId).toString()); + } + + public static Uri PARENT_URI(String path) { + return Uri.parse(new StringBuilder(CONTENT).append(AUTHORITY) + .append(path.substring(0, path.lastIndexOf('/'))) + .toString()); + } + + } + + private static String[] IDPROJECTION = new String[] { FeedData.EntryColumns._ID }; + + public static void deletePicturesOfFeedAsync(final Context context, + final Uri entriesUri, final String selection) { + if (FeedDataContentProvider.IMAGEFOLDER_FILE.exists()) { + new Thread() { + public void run() { + deletePicturesOfFeed(context, entriesUri, selection); + } + }.start(); + } + } + + public static synchronized void deletePicturesOfFeed(Context context, + Uri entriesUri, String selection) { + if (FeedDataContentProvider.IMAGEFOLDER_FILE.exists()) { + PictureFilenameFilter filenameFilter = new PictureFilenameFilter(); + + Cursor cursor = context.getContentResolver().query(entriesUri, + IDPROJECTION, selection, null, null); + + while (cursor.moveToNext()) { + filenameFilter.setEntryId(cursor.getString(0)); + + File[] files = FeedDataContentProvider.IMAGEFOLDER_FILE + .listFiles(filenameFilter); + + for (int n = 0, i = files != null ? files.length : 0; n < i; n++) { + files[n].delete(); + } + } + cursor.close(); + } + } + + public static synchronized void deletePicturesOfEntry(String entryId) { + if (FeedDataContentProvider.IMAGEFOLDER_FILE.exists()) { + PictureFilenameFilter filenameFilter = new PictureFilenameFilter( + entryId); + + File[] files = FeedDataContentProvider.IMAGEFOLDER_FILE + .listFiles(filenameFilter); + + for (int n = 0, i = files != null ? files.length : 0; n < i; n++) { + files[n].delete(); + } + } + } + +} diff --git a/src/de/shandschuh/sparserss/provider/FeedDataContentProvider.java b/src/cn/eric/rss/provider/FeedDataContentProvider.java similarity index 96% rename from src/de/shandschuh/sparserss/provider/FeedDataContentProvider.java rename to src/cn/eric/rss/provider/FeedDataContentProvider.java index 0b525c2..50d6f1d 100644 --- a/src/de/shandschuh/sparserss/provider/FeedDataContentProvider.java +++ b/src/cn/eric/rss/provider/FeedDataContentProvider.java @@ -23,7 +23,7 @@ * */ -package de.shandschuh.sparserss.provider; +package cn.eric.rss.provider; import java.io.File; @@ -41,12 +41,12 @@ import android.net.Uri; import android.os.Environment; import android.text.TextUtils; -import de.shandschuh.sparserss.Strings; +import cn.eric.rss.utility.MyStrings; public class FeedDataContentProvider extends ContentProvider { - private static final String FOLDER = Environment.getExternalStorageDirectory()+"/sparserss/"; + private static final String FOLDER = Environment.getExternalStorageDirectory()+"/MiniRSS/"; - private static final String DATABASE_NAME = "sparserss.db"; + private static final String DATABASE_NAME = "MiniRSS.db"; private static final int DATABASE_VERSION = 15; @@ -76,11 +76,11 @@ public class FeedDataContentProvider extends ContentProvider { private static final String EQUALS_ONE = "=1"; - public static final String IMAGEFOLDER = Environment.getExternalStorageDirectory()+"/sparserss/images/"; // faster than FOLDER+"images/" + public static final String IMAGEFOLDER = Environment.getExternalStorageDirectory()+"/MiniRSS/images/"; // faster than FOLDER+"images/" public static final File IMAGEFOLDER_FILE = new File(IMAGEFOLDER); - private static final String BACKUPOPML = Environment.getExternalStorageDirectory()+"/sparserss/backup.opml"; + private static final String BACKUPOPML = Environment.getExternalStorageDirectory()+"/MiniRSS/backup.opml"; private static UriMatcher URI_MATCHER; @@ -101,7 +101,7 @@ public class FeedDataContentProvider extends ContentProvider { private static class DatabaseHelper extends SQLiteOpenHelper { public DatabaseHelper(Context context, String name, int version) { super(context, name, null, version); - context.sendBroadcast(new Intent(Strings.ACTION_UPDATEWIDGET)); + context.sendBroadcast(new Intent(MyStrings.ACTION_UPDATEWIDGET)); } @Override @@ -192,13 +192,13 @@ private void executeCatchedSQL(SQLiteDatabase database, String query) { @Override public synchronized SQLiteDatabase getWritableDatabase() { - File oldDatabaseFile = new File(Environment.getExternalStorageDirectory()+"/sparserss/sparserss.db"); + File oldDatabaseFile = new File(Environment.getExternalStorageDirectory()+"/MiniRSS/MiniRSS.db"); if (oldDatabaseFile.exists()) { // get rid of the old structure SQLiteDatabase newDatabase = super.getWritableDatabase(); try { - SQLiteDatabase oldDatabase = SQLiteDatabase.openDatabase(Environment.getExternalStorageDirectory()+"/sparserss/sparserss.db", null, SQLiteDatabase.OPEN_READWRITE + SQLiteDatabase.CREATE_IF_NECESSARY); + SQLiteDatabase oldDatabase = SQLiteDatabase.openDatabase(Environment.getExternalStorageDirectory()+"/MiniRSS/MiniRSS.db", null, SQLiteDatabase.OPEN_READWRITE + SQLiteDatabase.CREATE_IF_NECESSARY); Cursor cursor = oldDatabase.query(TABLE_ENTRIES, null, null, null, null, null, null); @@ -342,7 +342,7 @@ public void run() { if (!TextUtils.isEmpty(selection)) { if (where.length() > 0) { - where.append(Strings.DB_AND); + where.append(MyStrings.DB_AND); } where.append(selection); } @@ -555,7 +555,7 @@ public int update(Uri uri, ContentValues values, String selection, String[] sele if (!TextUtils.isEmpty(selection)) { if (where.length() > 0) { - where.append(Strings.DB_AND).append(selection); + where.append(MyStrings.DB_AND).append(selection); } else { where.append(selection); } diff --git a/src/de/shandschuh/sparserss/provider/OPML.java b/src/cn/eric/rss/provider/OPML.java similarity index 93% rename from src/de/shandschuh/sparserss/provider/OPML.java rename to src/cn/eric/rss/provider/OPML.java index c40decb..b80a02b 100644 --- a/src/de/shandschuh/sparserss/provider/OPML.java +++ b/src/cn/eric/rss/provider/OPML.java @@ -23,7 +23,7 @@ * */ -package de.shandschuh.sparserss.provider; +package cn.eric.rss.provider; import java.io.BufferedWriter; import java.io.File; @@ -44,7 +44,7 @@ import android.database.sqlite.SQLiteDatabase; import android.text.TextUtils; import android.util.Xml; -import de.shandschuh.sparserss.Strings; +import cn.eric.rss.utility.MyStrings; public class OPML { private static final String START = "Sparse RSS export"; @@ -125,7 +125,7 @@ private static void writeData(String filename, Cursor cursor) throws IOException while(cursor.moveToNext()) { builder.append(OUTLINE_TITLE); - builder.append(cursor.isNull(1) ? Strings.EMPTY : TextUtils.htmlEncode(cursor.getString(1))); + builder.append(cursor.isNull(1) ? MyStrings.EMPTY : TextUtils.htmlEncode(cursor.getString(1))); builder.append(OUTLINE_XMLURL); builder.append(TextUtils.htmlEncode(cursor.getString(2))); if (cursor.getInt(3) == 1) { @@ -169,19 +169,19 @@ public void startElement(String uri, String localName, String qName, Attributes probablyValidElement = true; } } else if (TAG_OUTLINE.equals(localName)) { - String url = attributes.getValue(Strings.EMPTY, ATTRIBUTE_XMLURL); + String url = attributes.getValue(MyStrings.EMPTY, ATTRIBUTE_XMLURL); if (url != null) { - String title = attributes.getValue(Strings.EMPTY, ATTRIBUTE_TITLE); + String title = attributes.getValue(MyStrings.EMPTY, ATTRIBUTE_TITLE); ContentValues values = new ContentValues(); values.put(FeedData.FeedColumns.URL, url); values.put(FeedData.FeedColumns.NAME, title != null && title.length() > 0 ? title : null); - values.put(FeedData.FeedColumns.WIFIONLY, ATTRIBUTE_CATEGORY_VALUE.equals(attributes.getValue(Strings.EMPTY, ATTRIBUTE_CATEGORY)) ? 1 : 0); + values.put(FeedData.FeedColumns.WIFIONLY, ATTRIBUTE_CATEGORY_VALUE.equals(attributes.getValue(MyStrings.EMPTY, ATTRIBUTE_CATEGORY)) ? 1 : 0); if (context != null) { - Cursor cursor = context.getContentResolver().query(FeedData.FeedColumns.CONTENT_URI, null, new StringBuilder(FeedData.FeedColumns.URL).append(Strings.DB_ARG).toString(), new String[] {url}, null); + Cursor cursor = context.getContentResolver().query(FeedData.FeedColumns.CONTENT_URI, null, new StringBuilder(FeedData.FeedColumns.URL).append(MyStrings.DB_ARG).toString(), new String[] {url}, null); if (!cursor.moveToFirst()) { context.getContentResolver().insert(FeedData.FeedColumns.CONTENT_URI, values); diff --git a/src/de/shandschuh/sparserss/service/FetcherService.java b/src/cn/eric/rss/service/FetcherService.java similarity index 87% rename from src/de/shandschuh/sparserss/service/FetcherService.java rename to src/cn/eric/rss/service/FetcherService.java index 096fd6f..e9d4fc1 100644 --- a/src/de/shandschuh/sparserss/service/FetcherService.java +++ b/src/cn/eric/rss/service/FetcherService.java @@ -23,7 +23,7 @@ * */ -package de.shandschuh.sparserss.service; +package cn.eric.rss.service; import java.io.BufferedReader; import java.io.ByteArrayOutputStream; import java.io.FileNotFoundException; @@ -59,12 +59,12 @@ import android.os.SystemClock; import android.preference.PreferenceManager; import android.util.Xml; -import de.shandschuh.sparserss.BASE64; -import de.shandschuh.sparserss.MainTabActivity; -import de.shandschuh.sparserss.R; -import de.shandschuh.sparserss.Strings; -import de.shandschuh.sparserss.handler.RSSHandler; -import de.shandschuh.sparserss.provider.FeedData; +import cn.eric.rss.utility.BASE64; +import cn.eric.rss.MainActivity; +import cn.eric.rss.R; +import cn.eric.rss.utility.MyStrings; +import cn.eric.rss.handler.RSSHandler; +import cn.eric.rss.provider.FeedData; public class FetcherService extends IntentService { private static final int FETCHMODE_DIRECT = 1; @@ -121,15 +121,15 @@ public FetcherService() { public void onHandleIntent(Intent intent) { if (preferences == null) { try { - preferences = PreferenceManager.getDefaultSharedPreferences(createPackageContext(Strings.PACKAGE, 0)); + preferences = PreferenceManager.getDefaultSharedPreferences(createPackageContext(MyStrings.PACKAGE, 0)); } catch (NameNotFoundException e) { preferences = PreferenceManager.getDefaultSharedPreferences(FetcherService.this); } } - if (intent.getBooleanExtra(Strings.SCHEDULED, false)) { + if (intent.getBooleanExtra(MyStrings.SCHEDULED, false)) { SharedPreferences.Editor editor = preferences.edit(); - editor.putLong(Strings.PREFERENCE_LASTSCHEDULEDREFRESH, SystemClock.elapsedRealtime()); + editor.putLong(MyStrings.PREFERENCE_LASTSCHEDULEDREFRESH, SystemClock.elapsedRealtime()); editor.commit(); } @@ -138,9 +138,9 @@ public void onHandleIntent(Intent intent) { final NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo(); if (networkInfo != null && networkInfo.getState() == NetworkInfo.State.CONNECTED && intent != null) { - if (preferences.getBoolean(Strings.SETTINGS_PROXYENABLED, false) && (networkInfo.getType() == ConnectivityManager.TYPE_WIFI || !preferences.getBoolean(Strings.SETTINGS_PROXYWIFIONLY, false))) { + if (preferences.getBoolean(MyStrings.SETTINGS_PROXYENABLED, false) && (networkInfo.getType() == ConnectivityManager.TYPE_WIFI || !preferences.getBoolean(MyStrings.SETTINGS_PROXYWIFIONLY, false))) { try { - proxy = new Proxy(ZERO.equals(preferences.getString(Strings.SETTINGS_PROXYTYPE, ZERO)) ? Proxy.Type.HTTP : Proxy.Type.SOCKS, new InetSocketAddress(preferences.getString(Strings.SETTINGS_PROXYHOST, Strings.EMPTY), Integer.parseInt(preferences.getString(Strings.SETTINGS_PROXYPORT, Strings.DEFAULTPROXYPORT)))); + proxy = new Proxy(ZERO.equals(preferences.getString(MyStrings.SETTINGS_PROXYTYPE, ZERO)) ? Proxy.Type.HTTP : Proxy.Type.SOCKS, new InetSocketAddress(preferences.getString(MyStrings.SETTINGS_PROXYHOST, MyStrings.EMPTY), Integer.parseInt(preferences.getString(MyStrings.SETTINGS_PROXYPORT, MyStrings.DEFAULTPROXYPORT)))); } catch (Exception e) { proxy = null; } @@ -148,11 +148,11 @@ public void onHandleIntent(Intent intent) { proxy = null; } - FetchResult updates = FetcherService.refreshFeedsStatic(FetcherService.this, intent.getStringExtra(Strings.FEEDID), networkInfo, intent.getBooleanExtra(Strings.SETTINGS_OVERRIDEWIFIONLY, false) || preferences.getBoolean(Strings.SETTINGS_OVERRIDEWIFIONLY, false)); + FetchResult updates = FetcherService.refreshFeedsStatic(FetcherService.this, intent.getStringExtra(MyStrings.FEEDID), networkInfo, intent.getBooleanExtra(MyStrings.SETTINGS_OVERRIDEWIFIONLY, false) || preferences.getBoolean(MyStrings.SETTINGS_OVERRIDEWIFIONLY, false)); if (updates.count > 0) { - if (preferences.getBoolean(Strings.SETTINGS_NOTIFICATIONSENABLED, false)) { - Cursor cursor = getContentResolver().query(FeedData.EntryColumns.CONTENT_URI, new String[] {COUNT}, new StringBuilder(FeedData.EntryColumns.READDATE).append(Strings.DB_ISNULL).toString(), null, null); + if (preferences.getBoolean(MyStrings.SETTINGS_NOTIFICATIONSENABLED, false)) { + Cursor cursor = getContentResolver().query(FeedData.EntryColumns.CONTENT_URI, new String[] {COUNT}, new StringBuilder(FeedData.EntryColumns.READDATE).append(MyStrings.DB_ISNULL).toString(), null, null); cursor.moveToFirst(); int newCount = cursor.getInt(0); @@ -162,11 +162,11 @@ public void onHandleIntent(Intent intent) { Notification notification = new Notification(R.drawable.ic_statusbar_rss, text, System.currentTimeMillis()); - Intent notificationIntent = new Intent(FetcherService.this, MainTabActivity.class); + Intent notificationIntent = new Intent(FetcherService.this, MainActivity.class); PendingIntent contentIntent = PendingIntent.getActivity(FetcherService.this, 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT); - if (preferences.getBoolean(Strings.SETTINGS_NOTIFICATIONSVIBRATE, false)) { + if (preferences.getBoolean(MyStrings.SETTINGS_NOTIFICATIONSVIBRATE, false)) { notification.defaults = Notification.DEFAULT_VIBRATE; } notification.flags = Notification.FLAG_AUTO_CANCEL | Notification.FLAG_SHOW_LIGHTS; @@ -194,7 +194,7 @@ public void onHandleIntent(Intent intent) { } if( (ringtone == null || ringtone.length() == 0) && updates.feedIds.size() != ringCursor.getCount()) { // at least one not overridden but the others were all silence - ringtone = preferences.getString(Strings.SETTINGS_NOTIFICATIONSRINGTONE, null); + ringtone = preferences.getString(MyStrings.SETTINGS_NOTIFICATIONSRINGTONE, null); } ringCursor.close(); @@ -223,8 +223,8 @@ public void onCreate() { @Override public void onDestroy() { - if (MainTabActivity.INSTANCE != null) - MainTabActivity.INSTANCE.setProgressBarIndeterminateVisibility(false); + if (MainActivity.INSTANCE != null) + MainActivity.INSTANCE.setProgressBarIndeterminateVisibility(false); super.onDestroy(); } @@ -249,11 +249,11 @@ private static FetchResult refreshFeedsStatic(Context context, String feedId, Ne int iconPosition = cursor.getColumnIndex(FeedData.FeedColumns.ICON); - boolean imposeUserAgent = !preferences.getBoolean(Strings.SETTINGS_STANDARDUSERAGENT, false); + boolean imposeUserAgent = !preferences.getBoolean(MyStrings.SETTINGS_STANDARDUSERAGENT, false); int skipAlertPosition = cursor.getColumnIndex(FeedData.FeedColumns.SKIP_ALERT); - boolean followHttpHttpsRedirects = preferences.getBoolean(Strings.SETTINGS_HTTPHTTPSREDIRECTS, false); + boolean followHttpHttpsRedirects = preferences.getBoolean(MyStrings.SETTINGS_HTTPHTTPSREDIRECTS, false); int result = 0; ArrayList ids = new ArrayList(); @@ -261,8 +261,8 @@ private static FetchResult refreshFeedsStatic(Context context, String feedId, Ne RSSHandler handler = new RSSHandler(context); - handler.setEfficientFeedParsing(preferences.getBoolean(Strings.SETTINGS_EFFICIENTFEEDPARSING, true)); - handler.setFetchImages(preferences.getBoolean(Strings.SETTINGS_FETCHPICTURES, false)); + handler.setEfficientFeedParsing(preferences.getBoolean(MyStrings.SETTINGS_EFFICIENTFEEDPARSING, true)); + handler.setFetchImages(preferences.getBoolean(MyStrings.SETTINGS_FETCHPICTURES, false)); while(cursor.moveToNext()) { String id = cursor.getString(idPosition); @@ -300,11 +300,11 @@ private static FetchResult refreshFeedsStatic(Context context, String feedId, Ne posStart = line.indexOf(HREF, pos); if (posStart > -1) { - String url = line.substring(posStart+6, line.indexOf('"', posStart+10)).replace(Strings.AMP_SG, Strings.AMP); + String url = line.substring(posStart+6, line.indexOf('"', posStart+10)).replace(MyStrings.AMP_SG, MyStrings.AMP); ContentValues values = new ContentValues(); - if (url.startsWith(Strings.SLASH)) { + if (url.startsWith(MyStrings.SLASH)) { int index = feedUrl.indexOf('/', 8); if (index > -1) { @@ -312,7 +312,7 @@ private static FetchResult refreshFeedsStatic(Context context, String feedId, Ne } else { url = feedUrl+url; } - } else if (!url.startsWith(Strings.HTTP) && !url.startsWith(Strings.HTTPS)) { + } else if (!url.startsWith(MyStrings.HTTP) && !url.startsWith(MyStrings.HTTPS)) { url = new StringBuilder(feedUrl).append('/').append(url).toString(); } values.put(FeedData.FeedColumns.URL, url); @@ -385,7 +385,7 @@ private static FetchResult refreshFeedsStatic(Context context, String feedId, Ne byte[] iconBytes = cursor.getBlob(iconPosition); if (iconBytes == null) { - HttpURLConnection iconURLConnection = setupConnection(new URL(new StringBuilder(connection.getURL().getProtocol()).append(Strings.PROTOCOL_SEPARATOR).append(connection.getURL().getHost()).append(Strings.FILE_FAVICON).toString()), imposeUserAgent, followHttpHttpsRedirects); + HttpURLConnection iconURLConnection = setupConnection(new URL(new StringBuilder(connection.getURL().getProtocol()).append(MyStrings.PROTOCOL_SEPARATOR).append(connection.getURL().getHost()).append(MyStrings.FILE_FAVICON).toString()), imposeUserAgent, followHttpHttpsRedirects); try { iconBytes = getBytes(getConnectionInputStream(iconURLConnection)); @@ -505,7 +505,7 @@ private static FetchResult refreshFeedsStatic(Context context, String feedId, Ne cursor.close(); if (updateWidget) { - context.sendBroadcast(new Intent(Strings.ACTION_UPDATEWIDGET)); + context.sendBroadcast(new Intent(MyStrings.ACTION_UPDATEWIDGET)); } return new FetchResult(result, ids); } @@ -539,7 +539,7 @@ private static final HttpURLConnection setupConnection(URL url, boolean imposeUs String location = connection.getHeaderField("Location"); - if (location != null && (url.getProtocol().equals(Strings._HTTP) && location.startsWith(Strings.HTTPS) || url.getProtocol().equals(Strings._HTTPS) && location.startsWith(Strings.HTTP))) { + if (location != null && (url.getProtocol().equals(MyStrings._HTTP) && location.startsWith(MyStrings.HTTPS) || url.getProtocol().equals(MyStrings._HTTPS) && location.startsWith(MyStrings.HTTP))) { // if location != null, the system-automatic redirect has failed which indicates a protocol change if (followHttpHttpsRedirects) { connection.disconnect(); diff --git a/src/de/shandschuh/sparserss/service/RefreshService.java b/src/cn/eric/rss/service/RefreshService.java similarity index 89% rename from src/de/shandschuh/sparserss/service/RefreshService.java rename to src/cn/eric/rss/service/RefreshService.java index 2cca32e..e2bb487 100644 --- a/src/de/shandschuh/sparserss/service/RefreshService.java +++ b/src/cn/eric/rss/service/RefreshService.java @@ -23,7 +23,7 @@ * */ -package de.shandschuh.sparserss.service; +package cn.eric.rss.service; import android.app.AlarmManager; import android.app.PendingIntent; @@ -35,14 +35,14 @@ import android.os.IBinder; import android.os.SystemClock; import android.preference.PreferenceManager; -import de.shandschuh.sparserss.Strings; +import cn.eric.rss.utility.MyStrings; public class RefreshService extends Service { private static final String SIXTYMINUTES = "3600000"; private OnSharedPreferenceChangeListener listener = new OnSharedPreferenceChangeListener() { public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { - if (Strings.SETTINGS_REFRESHINTERVAL.equals(key)) { + if (MyStrings.SETTINGS_REFRESHINTERVAL.equals(key)) { restartTimer(false); } } @@ -78,12 +78,12 @@ public boolean onUnbind(Intent intent) { public void onCreate() { super.onCreate(); try { - preferences = PreferenceManager.getDefaultSharedPreferences(createPackageContext(Strings.PACKAGE, 0)); + preferences = PreferenceManager.getDefaultSharedPreferences(createPackageContext(MyStrings.PACKAGE, 0)); } catch (NameNotFoundException e) { preferences = PreferenceManager.getDefaultSharedPreferences(this); } - refreshBroadcastIntent = new Intent(Strings.ACTION_REFRESHFEEDS).putExtra(Strings.SCHEDULED, true); + refreshBroadcastIntent = new Intent(MyStrings.ACTION_REFRESHFEEDS).putExtra(MyStrings.SCHEDULED, true); alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE); preferences.registerOnSharedPreferenceChangeListener(listener); restartTimer(true); @@ -99,7 +99,7 @@ private void restartTimer(boolean created) { int time = 3600000; try { - time = Math.max(60000, Integer.parseInt(preferences.getString(Strings.SETTINGS_REFRESHINTERVAL, SIXTYMINUTES))); + time = Math.max(60000, Integer.parseInt(preferences.getString(MyStrings.SETTINGS_REFRESHINTERVAL, SIXTYMINUTES))); } catch (Exception exception) { } @@ -107,7 +107,7 @@ private void restartTimer(boolean created) { long initialRefreshTime = SystemClock.elapsedRealtime() + 10000; if (created) { - long lastRefresh = preferences.getLong(Strings.PREFERENCE_LASTSCHEDULEDREFRESH, 0); + long lastRefresh = preferences.getLong(MyStrings.PREFERENCE_LASTSCHEDULEDREFRESH, 0); if (lastRefresh > 0) { // this indicates a service restart by the system diff --git a/src/cn/eric/rss/ui/MenuData.java b/src/cn/eric/rss/ui/MenuData.java new file mode 100644 index 0000000..79f2285 --- /dev/null +++ b/src/cn/eric/rss/ui/MenuData.java @@ -0,0 +1,32 @@ +package cn.eric.rss.ui; + +/** + * + * @author Ruobin Wang + * + */ +public class MenuData { + public static final int MENUITEM_ADD_FEED=1; + public static final int MENUITEM_REFRESH=2; + public static final int MENUITEM_SETTINGS=3; + public static final int MENUITEM_MARK_ALL_AS_READ=4; + public static final int MENUITEM_ABOUT=5; + public static final int MENUITEM_MORE=6; + public static final int MENUITEM_IMPORT_FROM_OPML=7; + public static final int MENUITEM_EXPORT_TO_OPML=8; + public static final int MENUITEM_ENABLE_FEED_SORT=9; + + public static final int MENUITEM_DELETE_READ_ENTRIES=10; + public static final int MENUITEM_DELETE_ALL_ENTRIES=11; + + public static final int MENUITEM_MARK_AS_READ=12; + public static final int MENUITEM_MARK_AS_UNREAD=13; + public static final int MENUITEM_HIDE_READ_ENTRIES=14; + + public static final int MENUITEM_COPY_LINK_INTO_CLIPBOARD=15; + public static final int MENUITEM_SHARE=16; + public static final int MENUITEM_DELETE=17; + + + +} diff --git a/src/cn/eric/rss/ui/MyAnimations.java b/src/cn/eric/rss/ui/MyAnimations.java new file mode 100644 index 0000000..2574cd8 --- /dev/null +++ b/src/cn/eric/rss/ui/MyAnimations.java @@ -0,0 +1,35 @@ +package cn.eric.rss.ui; + +import android.view.animation.Animation; +import android.view.animation.TranslateAnimation; + +public class MyAnimations { + /** Slide in from right */ + public static final TranslateAnimation SLIDE_IN_RIGHT = generateAnimation( + 1, 0); + + /** Slide in from left */ + public static final TranslateAnimation SLIDE_IN_LEFT = generateAnimation( + -1, 0); + + /** Slide out to right */ + public static final TranslateAnimation SLIDE_OUT_RIGHT = generateAnimation( + 0, 1); + + /** Slide out to left */ + public static final TranslateAnimation SLIDE_OUT_LEFT = generateAnimation( + 0, -1); + + /** Duration of one animation */ + private static final long DURATION = 180; + + private static TranslateAnimation generateAnimation(float fromX, float toX) { + TranslateAnimation transformAnimation = new TranslateAnimation( + Animation.RELATIVE_TO_SELF, fromX, Animation.RELATIVE_TO_SELF, + toX, 0, 0, 0, 0); + + transformAnimation.setDuration(DURATION); + return transformAnimation; + } + +} diff --git a/src/cn/eric/rss/utility/ApplicationHelper.java b/src/cn/eric/rss/utility/ApplicationHelper.java new file mode 100644 index 0000000..badba07 --- /dev/null +++ b/src/cn/eric/rss/utility/ApplicationHelper.java @@ -0,0 +1,62 @@ +package cn.eric.rss.utility; + +import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import cn.eric.rss.MainActivity; +import cn.eric.rss.R; + +/** + * used for global operations + * + * @author Ruobin Wang + * + */ +public class ApplicationHelper { + + public static void claimMaidenVoyage(Activity activity) { + SharedPreferences sharedPref = activity + .getPreferences(Context.MODE_PRIVATE); + SharedPreferences.Editor editor = sharedPref.edit(); + editor.putBoolean( + activity.getResources().getString(R.string.pref_maiden_voyage), + false); + editor.commit(); + } + + /** + * check if this is the first use + * + * @param activity + * @return + */ + public static boolean isMaidenVoyage(Activity activity) { + SharedPreferences sharedPref = activity + .getPreferences(Context.MODE_PRIVATE); + boolean isMaidenVoyage = sharedPref.getBoolean(activity.getResources() + .getString(R.string.pref_maiden_voyage), true); + return isMaidenVoyage; + } + + public static void createShortcutOnHomeScreen(Activity activity) { + + Intent shortcutIntent = new Intent(activity.getApplicationContext(), + MainActivity.class); + + shortcutIntent.setAction(Intent.ACTION_MAIN); + + Intent addIntent = new Intent(); + addIntent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent); + addIntent.putExtra(Intent.EXTRA_SHORTCUT_NAME, activity.getResources() + .getString(R.string.app_name)); + addIntent.putExtra( + Intent.EXTRA_SHORTCUT_ICON_RESOURCE, + Intent.ShortcutIconResource.fromContext( + activity.getApplicationContext(), R.drawable.ic_logo)); + + addIntent.setAction("com.android.launcher.action.INSTALL_SHORTCUT"); + activity.getApplicationContext().sendBroadcast(addIntent); + } + +} diff --git a/src/cn/eric/rss/utility/BASE64.java b/src/cn/eric/rss/utility/BASE64.java new file mode 100644 index 0000000..117067f --- /dev/null +++ b/src/cn/eric/rss/utility/BASE64.java @@ -0,0 +1,67 @@ +package cn.eric.rss.utility; + +public class BASE64 { + private static char[] TOCHAR = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', + 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', + 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', + 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', + 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', '+', '/' }; + + public static String encode(byte[] bytes) { + StringBuilder builder = new StringBuilder(); + + int i = bytes.length; + + int k = i / 3; + + for (int n = 0; n < k; n++) { + if (n > 0 && n % 19 == 0) { + builder.append('\n'); + } + builder.append(convertToString(bytes[3 * n], bytes[3 * n + 1], + bytes[3 * n + 2])); + } + + k = i % 3; + if (k == 2) { + char[] chars = convertToString(bytes[i - 2], bytes[i - 1], 0); + + chars[3] = '='; + builder.append(chars); + } else if (k == 1) { + char[] chars = convertToString(bytes[i - 1], 0, 0); + + chars[2] = '='; + chars[3] = '='; + builder.append(chars); + } + return builder.toString(); + } + + private static char[] convertToString(int b, int c, int d) { + char[] result = new char[4]; + if (b < 0) { + b += 256; + } + if (c < 0) { + c += 256; + } + if (d < 0) { + d += 256; + } + + int f = d + (c + b * 256) * 256; + + result[3] = TOCHAR[f % 64]; + f /= 64; + result[2] = TOCHAR[f % 64]; + f /= 64; + result[1] = TOCHAR[f % 64]; + f /= 64; + result[0] = TOCHAR[f % 64]; + + return result; + } + +} diff --git a/src/de/shandschuh/sparserss/Strings.java b/src/cn/eric/rss/utility/MyStrings.java similarity index 65% rename from src/de/shandschuh/sparserss/Strings.java rename to src/cn/eric/rss/utility/MyStrings.java index c06d254..133078f 100644 --- a/src/de/shandschuh/sparserss/Strings.java +++ b/src/cn/eric/rss/utility/MyStrings.java @@ -1,134 +1,108 @@ -/** - * Sparse rss - * - * Copyright (c) 2010-2012 Stefan Handschuh - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - */ - -package de.shandschuh.sparserss; - -import de.shandschuh.sparserss.provider.FeedData; - -public final class Strings { +package cn.eric.rss.utility; + +import cn.eric.rss.provider.FeedData; + +public final class MyStrings { public static final String FEED_SETTINGS_OTHER_ALERT_RINGTONE = "other_alertringtone"; - + public static final String FEED_SETTINGS_ALERT_RINGTONE = "alertringtone"; - + public static final String FEED_SETTINGS_SKIP_ALERT = "skipalert"; - public static final String PACKAGE = "de.shandschuh.sparserss"; - + public static final String PACKAGE = "cn.eric.rss"; + public static final String SETTINGS_REFRESHINTERVAL = "refresh.interval"; - + public static final String SETTINGS_NOTIFICATIONSENABLED = "notifications.enabled"; - + public static final String SETTINGS_REFRESHENABLED = "refresh.enabled"; - + public static final String SETTINGS_REFRESHONPENENABLED = "refreshonopen.enabled"; - + public static final String SETTINGS_NOTIFICATIONSRINGTONE = "notifications.ringtone"; - + public static final String SETTINGS_NOTIFICATIONSVIBRATE = "notifications.vibrate"; - + public static final String SETTINGS_PRIORITIZE = "contentpresentation.prioritize"; - - public static final String SETTINGS_SHOWTABS = "tabs.show"; - + public static final String SETTINGS_FETCHPICTURES = "pictures.fetch"; - + public static final String SETTINGS_PROXYENABLED = "proxy.enabled"; - + public static final String SETTINGS_PROXYPORT = "proxy.port"; - + public static final String SETTINGS_PROXYHOST = "proxy.host"; - + public static final String SETTINGS_PROXYWIFIONLY = "proxy.wifionly"; - + public static final String SETTINGS_PROXYTYPE = "proxy.type"; - + public static final String SETTINGS_KEEPTIME = "keeptime"; - + public static final String SETTINGS_BLACKTEXTONWHITE = "blacktextonwhite"; - - public static final String SETTINGS_LIGHTTHEME = "lighttheme"; - + public static final String SETTINGS_FONTSIZE = "fontsize"; - + public static final String SETTINGS_STANDARDUSERAGENT = "standarduseragent"; - + public static final String SETTINGS_DISABLEPICTURES = "pictures.disable"; - + public static final String SETTINGS_HTTPHTTPSREDIRECTS = "httphttpsredirects"; - + public static final String SETTINGS_OVERRIDEWIFIONLY = "overridewifionly"; - + public static final String SETTINGS_GESTURESENABLED = "gestures.enabled"; - + public static final String SETTINGS_ENCLOSUREWARNINGSENABLED = "enclosurewarnings.enabled"; - + public static final String SETTINGS_EFFICIENTFEEDPARSING = "efficientfeedparsing"; - - public static final String ACTION_REFRESHFEEDS = "de.shandschuh.sparserss.REFRESH"; - - public static final String ACTION_UPDATEWIDGET = "de.shandschuh.sparserss.FEEDUPDATED"; - - public static final String ACTION_RESTART = "de.shandschuh.sparserss.RESTART"; - + + public static final String ACTION_REFRESHFEEDS = "cn.eric.rss.REFRESH"; + + public static final String ACTION_UPDATEWIDGET = "cn.eric.rss.FEEDUPDATED"; + + public static final String ACTION_RESTART = "cn.eric.rss.RESTART"; + public static final String FEEDID = "feedid"; - + public static final String DB_ISNULL = " IS NULL"; - + public static final String DB_DESC = " DESC"; - + public static final String DB_ARG = "=?"; - + public static final String DB_AND = " AND "; - - public static final String DB_EXCUDEFAVORITE = new StringBuilder(FeedData.EntryColumns.FAVORITE).append(Strings.DB_ISNULL).append(" OR ").append(FeedData.EntryColumns.FAVORITE).append("=0").toString(); - + + public static final String DB_EXCUDEFAVORITE = new StringBuilder( + FeedData.EntryColumns.FAVORITE).append(MyStrings.DB_ISNULL) + .append(" OR ").append(FeedData.EntryColumns.FAVORITE).append("=0") + .toString(); + public static final String EMPTY = ""; public static final String HTTP = "http://"; - + public static final String HTTPS = "https://"; - + public static final String _HTTP = "http"; - + public static final String _HTTPS = "https"; public static final String PROTOCOL_SEPARATOR = "://"; public static final String FILE_FAVICON = "/favicon.ico"; - + public static final String SPACE = " "; - + public static final String TWOSPACE = " "; - + public static final String HTML_TAG_REGEX = "<(.|\n)*?>"; - + public static final String FILEURL = "file://"; - + public static final String IMAGEFILE_IDSEPARATOR = "__"; - + public static final String IMAGEID_REPLACEMENT = "##ID##"; public static final String DEFAULTPROXYPORT = "8080"; @@ -136,53 +110,55 @@ public final class Strings { public static final String URL_SPACE = "%20"; public static final String HTML_SPAN_REGEX = "<[/]?[ ]?span(.|\n)*?>"; - + public static final String HTML_IMG_REGEX = "<[/]?[ ]?img(.|\n)*?>"; - + public static final String ONE = "1"; public static final Object THREENEWLINES = "\n\n\n"; public static final String PREFERENCE_LICENSEACCEPTED = "license.accepted"; - + public static final String PREFERENCE_LASTSCHEDULEDREFRESH = "lastscheduledrefresh"; - + public static final String HTML_LT = "<"; - + public static final String HTML_GT = ">"; - + public static final String LT = "<"; - + public static final String GT = ">"; - protected static final String TRUE = "true"; - - protected static final String FALSE = "false"; - - public static final String READDATE_GREATERZERO = FeedData.EntryColumns.READDATE+">0"; + public static final String TRUE = "true"; + + public static final String FALSE = "false"; + + public static final String READDATE_GREATERZERO = FeedData.EntryColumns.READDATE + + ">0"; public static final String COUNT = "count"; - - public static final String ENCLOSURE_SEPARATOR = "[@]"; // exactly three characters! - + + public static final String ENCLOSURE_SEPARATOR = "[@]"; // exactly three + // characters! + public static final String QUESTIONMARKS = "'??'"; public static final String HTML_QUOT = """; - + public static final String QUOT = "\""; - + public static final String HTML_APOSTROPHE = "'"; - + public static final String APOSTROPHE = "'"; - + public static final String AMP = "&"; - + public static final String AMP_SG = "&"; - + public static final String SLASH = "/"; - + public static final String COMMASPACE = ", "; - + public static final String SCHEDULED = "scheduled"; } diff --git a/src/cn/eric/rss/utility/SimpleTask.java b/src/cn/eric/rss/utility/SimpleTask.java new file mode 100644 index 0000000..6d23429 --- /dev/null +++ b/src/cn/eric/rss/utility/SimpleTask.java @@ -0,0 +1,54 @@ +package cn.eric.rss.utility; + +public abstract class SimpleTask implements Runnable { + private boolean canceled = false; + + private int postCount = 0; + + public abstract void runControlled(); + + public void cancel() { + canceled = true; + } + + public boolean isCanceled() { + return canceled; + } + + public void post() { + post(1); + } + + public synchronized void post(int count) { + postCount += count; + canceled = false; + } + + public boolean isPosted() { + return postCount > 0; + } + + public int getPostCount() { + return postCount; + } + + public final synchronized void run() { + if (!canceled) { + runControlled(); + } + postRun(); + postCount--; + } + + /** + * Override to use + */ + public void postRun() { + + } + + public void enable() { + canceled = false; + } + +} diff --git a/src/de/shandschuh/sparserss/widget/ColorPickerDialogPreference.java b/src/cn/eric/rss/widget/ColorPickerDialogPreference.java similarity index 94% rename from src/de/shandschuh/sparserss/widget/ColorPickerDialogPreference.java rename to src/cn/eric/rss/widget/ColorPickerDialogPreference.java index 4b899e8..d323fc4 100644 --- a/src/de/shandschuh/sparserss/widget/ColorPickerDialogPreference.java +++ b/src/cn/eric/rss/widget/ColorPickerDialogPreference.java @@ -1,112 +1,112 @@ -/** - * Sparse rss - * - * Copyright (c) 2012 Stefan Handschuh - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - */ - -package de.shandschuh.sparserss.widget; - -import android.content.Context; -import android.preference.DialogPreference; -import android.util.AttributeSet; -import android.view.View; -import android.widget.SeekBar; -import android.widget.SeekBar.OnSeekBarChangeListener; -import de.shandschuh.sparserss.R; - -public class ColorPickerDialogPreference extends DialogPreference { - private SeekBar redSeekBar; - - private SeekBar greenSeekBar; - - private SeekBar blueSeekBar; - - private SeekBar transparencySeekBar; - - int color; - - public ColorPickerDialogPreference(Context context, AttributeSet attrs) { - super(context, attrs); - color = SparseRSSAppWidgetProvider.STANDARD_BACKGROUND; - } - - @Override - protected View onCreateDialogView() { - final View view = super.onCreateDialogView(); - - view.setBackgroundColor(color); - - redSeekBar = (SeekBar) view.findViewById(R.id.seekbar_red); - greenSeekBar = (SeekBar) view.findViewById(R.id.seekbar_green); - blueSeekBar = (SeekBar) view.findViewById(R.id.seekbar_blue); - transparencySeekBar = (SeekBar) view.findViewById(R.id.seekbar_transparency); - - int _color = color; - - transparencySeekBar.setProgress(((_color / 0x01000000)*100)/255); - _color %= 0x01000000; - redSeekBar.setProgress(((_color / 0x00010000)*100)/255); - _color %= 0x00010000; - greenSeekBar.setProgress(((_color / 0x00000100)*100)/255); - _color %= 0x00000100; - blueSeekBar.setProgress((_color*100)/255); - - OnSeekBarChangeListener onSeekBarChangeListener = new OnSeekBarChangeListener() { - - public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { - int red = (redSeekBar.getProgress()*255) / 100; - - int green = (greenSeekBar.getProgress()*255) / 100; - - int blue = (blueSeekBar.getProgress()*255) / 100; - - int transparency = (transparencySeekBar.getProgress()*255) / 100; - - color = transparency*0x01000000 + red*0x00010000 + green*0x00000100 + blue; - view.setBackgroundColor(color); - } - - public void onStartTrackingTouch(SeekBar seekBar) { - - } - - public void onStopTrackingTouch(SeekBar seekBar) { - - } - }; - - redSeekBar.setOnSeekBarChangeListener(onSeekBarChangeListener); - greenSeekBar.setOnSeekBarChangeListener(onSeekBarChangeListener); - blueSeekBar.setOnSeekBarChangeListener(onSeekBarChangeListener); - transparencySeekBar.setOnSeekBarChangeListener(onSeekBarChangeListener); - return view; - } - - @Override - protected void onDialogClosed(boolean positiveResult) { - if (positiveResult) { - persistInt(color); - } - super.onDialogClosed(positiveResult); - } - -} +/** + * Sparse rss + * + * Copyright (c) 2012 Stefan Handschuh + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +package cn.eric.rss.widget; + +import android.content.Context; +import android.preference.DialogPreference; +import android.util.AttributeSet; +import android.view.View; +import android.widget.SeekBar; +import android.widget.SeekBar.OnSeekBarChangeListener; +import cn.eric.rss.R; + +public class ColorPickerDialogPreference extends DialogPreference { + private SeekBar redSeekBar; + + private SeekBar greenSeekBar; + + private SeekBar blueSeekBar; + + private SeekBar transparencySeekBar; + + int color; + + public ColorPickerDialogPreference(Context context, AttributeSet attrs) { + super(context, attrs); + color = MiniRSSAppWidgetProvider.STANDARD_BACKGROUND; + } + + @Override + protected View onCreateDialogView() { + final View view = super.onCreateDialogView(); + + view.setBackgroundColor(color); + + redSeekBar = (SeekBar) view.findViewById(R.id.seekbar_red); + greenSeekBar = (SeekBar) view.findViewById(R.id.seekbar_green); + blueSeekBar = (SeekBar) view.findViewById(R.id.seekbar_blue); + transparencySeekBar = (SeekBar) view.findViewById(R.id.seekbar_transparency); + + int _color = color; + + transparencySeekBar.setProgress(((_color / 0x01000000)*100)/255); + _color %= 0x01000000; + redSeekBar.setProgress(((_color / 0x00010000)*100)/255); + _color %= 0x00010000; + greenSeekBar.setProgress(((_color / 0x00000100)*100)/255); + _color %= 0x00000100; + blueSeekBar.setProgress((_color*100)/255); + + OnSeekBarChangeListener onSeekBarChangeListener = new OnSeekBarChangeListener() { + + public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { + int red = (redSeekBar.getProgress()*255) / 100; + + int green = (greenSeekBar.getProgress()*255) / 100; + + int blue = (blueSeekBar.getProgress()*255) / 100; + + int transparency = (transparencySeekBar.getProgress()*255) / 100; + + color = transparency*0x01000000 + red*0x00010000 + green*0x00000100 + blue; + view.setBackgroundColor(color); + } + + public void onStartTrackingTouch(SeekBar seekBar) { + + } + + public void onStopTrackingTouch(SeekBar seekBar) { + + } + }; + + redSeekBar.setOnSeekBarChangeListener(onSeekBarChangeListener); + greenSeekBar.setOnSeekBarChangeListener(onSeekBarChangeListener); + blueSeekBar.setOnSeekBarChangeListener(onSeekBarChangeListener); + transparencySeekBar.setOnSeekBarChangeListener(onSeekBarChangeListener); + return view; + } + + @Override + protected void onDialogClosed(boolean positiveResult) { + if (positiveResult) { + persistInt(color); + } + super.onDialogClosed(positiveResult); + } + +} diff --git a/src/de/shandschuh/sparserss/widget/SparseRSSAppWidgetProvider.java b/src/cn/eric/rss/widget/MiniRSSAppWidgetProvider.java similarity index 85% rename from src/de/shandschuh/sparserss/widget/SparseRSSAppWidgetProvider.java rename to src/cn/eric/rss/widget/MiniRSSAppWidgetProvider.java index 9c43379..6ec95aa 100644 --- a/src/de/shandschuh/sparserss/widget/SparseRSSAppWidgetProvider.java +++ b/src/cn/eric/rss/widget/MiniRSSAppWidgetProvider.java @@ -23,7 +23,7 @@ * */ -package de.shandschuh.sparserss.widget; +package cn.eric.rss.widget; import android.app.PendingIntent; import android.appwidget.AppWidgetManager; @@ -37,12 +37,12 @@ import android.graphics.BitmapFactory; import android.view.View; import android.widget.RemoteViews; -import de.shandschuh.sparserss.MainTabActivity; -import de.shandschuh.sparserss.R; -import de.shandschuh.sparserss.Strings; -import de.shandschuh.sparserss.provider.FeedData; +import cn.eric.rss.MainActivity; +import cn.eric.rss.R; +import cn.eric.rss.utility.MyStrings; +import cn.eric.rss.provider.FeedData; -public class SparseRSSAppWidgetProvider extends AppWidgetProvider { +public class MiniRSSAppWidgetProvider extends AppWidgetProvider { private static final String LIMIT = " limit "; private static final int[] IDS = {R.id.news_1, R.id.news_2, R.id.news_3, R.id.news_4, R.id.news_5, R.id.news_6, R.id.news_7, R.id.news_8, R.id.news_9, R.id.news_10}; @@ -55,14 +55,14 @@ public class SparseRSSAppWidgetProvider extends AppWidgetProvider { public void onReceive(Context context, Intent intent) { AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context); - onUpdate(context, appWidgetManager, appWidgetManager.getAppWidgetIds(new ComponentName(context, SparseRSSAppWidgetProvider.class))); + onUpdate(context, appWidgetManager, appWidgetManager.getAppWidgetIds(new ComponentName(context, MiniRSSAppWidgetProvider.class))); } public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { - SharedPreferences preferences = context.getSharedPreferences(SparseRSSAppWidgetProvider.class.getName(), 0); + SharedPreferences preferences = context.getSharedPreferences(MiniRSSAppWidgetProvider.class.getName(), 0); for (int n = 0, i = appWidgetIds.length; n < i; n++) { - updateAppWidget(context, appWidgetManager, appWidgetIds[n], preferences.getBoolean(appWidgetIds[n]+".hideread", false), preferences.getString(appWidgetIds[n]+".entrycount", "10"), preferences.getString(appWidgetIds[n]+".feeds", Strings.EMPTY), preferences.getInt(appWidgetIds[n]+".background", STANDARD_BACKGROUND)); + updateAppWidget(context, appWidgetManager, appWidgetIds[n], preferences.getBoolean(appWidgetIds[n]+".hideread", false), preferences.getString(appWidgetIds[n]+".entrycount", "10"), preferences.getString(appWidgetIds[n]+".feeds", MyStrings.EMPTY), preferences.getInt(appWidgetIds[n]+".background", STANDARD_BACKGROUND)); } } @@ -74,21 +74,21 @@ private static void updateAppWidget(Context context, AppWidgetManager appWidgetM StringBuilder selection = new StringBuilder(); if (hideRead) { - selection.append(FeedData.EntryColumns.READDATE).append(Strings.DB_ISNULL); + selection.append(FeedData.EntryColumns.READDATE).append(MyStrings.DB_ISNULL); } if (feedIds.length() > 0) { if (selection.length() > 0) { - selection.append(Strings.DB_AND); + selection.append(MyStrings.DB_AND); } selection.append(FeedData.EntryColumns.FEED_ID).append(" IN ("+feedIds).append(')'); } - Cursor cursor = context.getContentResolver().query(FeedData.EntryColumns.CONTENT_URI, new String[] {FeedData.EntryColumns.TITLE, FeedData.EntryColumns._ID, FeedData.FeedColumns.ICON}, selection.toString(), null, new StringBuilder(FeedData.EntryColumns.DATE).append(Strings.DB_DESC).append(LIMIT).append(entryCount).toString()); + Cursor cursor = context.getContentResolver().query(FeedData.EntryColumns.CONTENT_URI, new String[] {FeedData.EntryColumns.TITLE, FeedData.EntryColumns._ID, FeedData.FeedColumns.ICON}, selection.toString(), null, new StringBuilder(FeedData.EntryColumns.DATE).append(MyStrings.DB_DESC).append(LIMIT).append(entryCount).toString()); RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.homescreenwidget); - views.setOnClickPendingIntent(R.id.feed_icon, PendingIntent.getActivity(context, 0, new Intent(context, MainTabActivity.class), 0)); + views.setOnClickPendingIntent(R.id.feed_icon, PendingIntent.getActivity(context, 0, new Intent(context, MainActivity.class), 0)); int k = 0; @@ -127,7 +127,7 @@ private static void updateAppWidget(Context context, AppWidgetManager appWidgetM for (; k < IDS.length; k++) { views.setViewVisibility(ICON_IDS[k], View.GONE); views.setViewVisibility(IDS[k], View.GONE); - views.setTextViewText(IDS[k], Strings.EMPTY); + views.setTextViewText(IDS[k], MyStrings.EMPTY); } views.setInt(R.id.widgetlayout, "setBackgroundColor", backgroundColor); appWidgetManager.updateAppWidget(appWidgetId, views); diff --git a/src/de/shandschuh/sparserss/widget/WidgetConfigActivity.java b/src/cn/eric/rss/widget/WidgetConfigActivity.java similarity index 89% rename from src/de/shandschuh/sparserss/widget/WidgetConfigActivity.java rename to src/cn/eric/rss/widget/WidgetConfigActivity.java index 2c405de..905e902 100644 --- a/src/de/shandschuh/sparserss/widget/WidgetConfigActivity.java +++ b/src/cn/eric/rss/widget/WidgetConfigActivity.java @@ -23,7 +23,9 @@ * */ -package de.shandschuh.sparserss.widget; +package cn.eric.rss.widget; + +import com.umeng.analytics.MobclickAgent; import android.appwidget.AppWidgetManager; import android.content.Intent; @@ -36,8 +38,8 @@ import android.preference.PreferenceCategory; import android.view.View; import android.view.View.OnClickListener; -import de.shandschuh.sparserss.R; -import de.shandschuh.sparserss.provider.FeedData; +import cn.eric.rss.R; +import cn.eric.rss.provider.FeedData; public class WidgetConfigActivity extends PreferenceActivity { private int widgetId; @@ -91,7 +93,7 @@ protected void onCreate(Bundle bundle) { findViewById(R.id.save_button).setOnClickListener(new OnClickListener() { public void onClick(View view) { - SharedPreferences.Editor preferences = getSharedPreferences(SparseRSSAppWidgetProvider.class.getName(), 0).edit(); + SharedPreferences.Editor preferences = getSharedPreferences(MiniRSSAppWidgetProvider.class.getName(), 0).edit(); boolean hideRead = false;//((CheckBoxPreference) getPreferenceManager().findPreference("widget.hideread")).isChecked(); @@ -121,12 +123,12 @@ public void onClick(View view) { preferences.putString(widgetId+".feeds", feedIds); preferences.putString(widgetId+".entrycount", entryCount); - int color = getPreferenceManager().getSharedPreferences().getInt("widget.background", SparseRSSAppWidgetProvider.STANDARD_BACKGROUND); + int color = getPreferenceManager().getSharedPreferences().getInt("widget.background", MiniRSSAppWidgetProvider.STANDARD_BACKGROUND); preferences.putInt(widgetId+".background", color); preferences.commit(); - SparseRSSAppWidgetProvider.updateAppWidget(WidgetConfigActivity.this, widgetId, hideRead, entryCount, feedIds, color); + MiniRSSAppWidgetProvider.updateAppWidget(WidgetConfigActivity.this, widgetId, hideRead, entryCount, feedIds, color); setResult(RESULT_OK, new Intent().putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, widgetId)); finish(); } @@ -138,5 +140,16 @@ public void onClick(View view) { } } + + @Override + public void onResume() { + super.onResume(); + MobclickAgent.onResume(this); + } + @Override + public void onPause() { + super.onPause(); + MobclickAgent.onPause(this); + } } diff --git a/src/de/shandschuh/sparserss/Animations.java b/src/de/shandschuh/sparserss/Animations.java deleted file mode 100644 index d91c7f6..0000000 --- a/src/de/shandschuh/sparserss/Animations.java +++ /dev/null @@ -1,54 +0,0 @@ -/** - * Sparse rss - * - * Copyright (c) 2012 Stefan Handschuh - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - */ - -package de.shandschuh.sparserss; - -import android.view.animation.Animation; -import android.view.animation.TranslateAnimation; - -public class Animations { - /** Slide in from right */ - public static final TranslateAnimation SLIDE_IN_RIGHT = generateAnimation(1, 0); - - /** Slide in from left */ - public static final TranslateAnimation SLIDE_IN_LEFT = generateAnimation(-1, 0); - - /** Slide out to right */ - public static final TranslateAnimation SLIDE_OUT_RIGHT = generateAnimation(0, 1); - - /** Slide out to left */ - public static final TranslateAnimation SLIDE_OUT_LEFT = generateAnimation(0, -1); - - /** Duration of one animation */ - private static final long DURATION = 180; - - private static TranslateAnimation generateAnimation(float fromX, float toX) { - TranslateAnimation transformAnimation = new TranslateAnimation(Animation.RELATIVE_TO_SELF, fromX, Animation.RELATIVE_TO_SELF, toX, 0, 0, 0, 0); - - transformAnimation.setDuration(DURATION); - return transformAnimation; - } - -} diff --git a/src/de/shandschuh/sparserss/BASE64.java b/src/de/shandschuh/sparserss/BASE64.java deleted file mode 100644 index 7190d46..0000000 --- a/src/de/shandschuh/sparserss/BASE64.java +++ /dev/null @@ -1,90 +0,0 @@ -/** - * Sparse rss - * - * Copyright (c) 2010, 2011 Stefan Handschuh - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * (this is an excerpt from BASE64 class of jaolt, except for the license) - */ - -package de.shandschuh.sparserss; - - -public class BASE64 { - private static char[] TOCHAR = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', - 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'}; - - public static String encode(byte[] bytes) { - StringBuilder builder = new StringBuilder(); - - int i = bytes.length; - - int k = i/3; - - for (int n = 0; n < k; n++) { - if (n > 0 && n % 19 == 0) { - builder.append('\n'); - } - builder.append(convertToString(bytes[3*n], bytes[3*n+1], bytes[3*n+2])); - } - - k = i % 3; - if (k == 2) { - char[] chars = convertToString(bytes[i-2], bytes[i-1], 0); - - chars[3] = '='; - builder.append(chars); - } else if (k == 1) { - char[] chars = convertToString(bytes[i-1], 0, 0); - - chars[2] = '='; - chars[3] = '='; - builder.append(chars); - } - return builder.toString(); - } - - private static char[] convertToString(int b, int c, int d) { - char[] result = new char[4]; - if (b < 0) { - b += 256; - } - if (c < 0) { - c += 256; - } - if (d < 0) { - d += 256; - } - - int f = d+(c+b*256)*256; - - result[3] = TOCHAR[f % 64]; - f /= 64; - result[2] = TOCHAR[f % 64]; - f /= 64; - result[1] = TOCHAR[f % 64]; - f /= 64; - result[0] = TOCHAR[f % 64]; - - return result; - } - -} diff --git a/src/de/shandschuh/sparserss/EntriesListActivity.java b/src/de/shandschuh/sparserss/EntriesListActivity.java deleted file mode 100644 index 9b7f31a..0000000 --- a/src/de/shandschuh/sparserss/EntriesListActivity.java +++ /dev/null @@ -1,277 +0,0 @@ -/** - * Sparse rss - * - * Copyright (c) 2010-2012 Stefan Handschuh - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - */ - -package de.shandschuh.sparserss; - -import android.app.AlertDialog; -import android.app.AlertDialog.Builder; -import android.app.ListActivity; -import android.content.ContentUris; -import android.content.DialogInterface; -import android.content.Intent; -import android.database.Cursor; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.graphics.Typeface; -import android.graphics.drawable.BitmapDrawable; -import android.net.Uri; -import android.os.Bundle; -import android.text.ClipboardManager; -import android.util.TypedValue; -import android.view.ContextMenu; -import android.view.ContextMenu.ContextMenuInfo; -import android.view.Menu; -import android.view.MenuItem; -import android.view.View; -import android.view.View.OnCreateContextMenuListener; -import android.view.Window; -import android.widget.AdapterView; -import android.widget.ListView; -import android.widget.TextView; -import de.shandschuh.sparserss.provider.FeedData; - -public class EntriesListActivity extends ListActivity { - private static final int CONTEXTMENU_MARKASREAD_ID = 6; - - private static final int CONTEXTMENU_MARKASUNREAD_ID = 7; - - private static final int CONTEXTMENU_DELETE_ID = 8; - - private static final int CONTEXTMENU_COPYURL = 9; - - public static final String EXTRA_SHOWREAD = "show_read"; - - public static final String EXTRA_SHOWFEEDINFO = "show_feedinfo"; - - public static final String EXTRA_AUTORELOAD = "autoreload"; - - private static final String[] FEED_PROJECTION = {FeedData.FeedColumns.NAME, - FeedData.FeedColumns.URL, - FeedData.FeedColumns.ICON - }; - - private Uri uri; - - private EntriesListAdapter entriesListAdapter; - - private byte[] iconBytes; - - @Override - protected void onCreate(Bundle savedInstanceState) { - if (MainTabActivity.isLightTheme(this)) { - setTheme(R.style.Theme_Light); - } - - super.onCreate(savedInstanceState); - - String title = null; - - iconBytes = null; - - Intent intent = getIntent(); - - long feedId = intent.getLongExtra(FeedData.FeedColumns._ID, 0); - - if (feedId > 0) { - Cursor cursor = getContentResolver().query(FeedData.FeedColumns.CONTENT_URI(feedId), FEED_PROJECTION, null, null, null); - - if (cursor.moveToFirst()) { - title = cursor.isNull(0) ? cursor.getString(1) : cursor.getString(0); - iconBytes = cursor.getBlob(2); - } - cursor.close(); - } - - if (!MainTabActivity.POSTGINGERBREAD && iconBytes != null && iconBytes.length > 0) { // we cannot insert the icon here because it would be overwritten, but we have to reserve the icon here - if (!requestWindowFeature(Window.FEATURE_LEFT_ICON)) { - iconBytes = null; - } - } - - setContentView(R.layout.entries); - - uri = intent.getData(); - - entriesListAdapter = new EntriesListAdapter(this, uri, intent.getBooleanExtra(EXTRA_SHOWFEEDINFO, false), intent.getBooleanExtra(EXTRA_AUTORELOAD, false)); - setListAdapter(entriesListAdapter); - - if (title != null) { - setTitle(title); - } - if (iconBytes != null && iconBytes.length > 0) { - int bitmapSizeInDip = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 24f, getResources().getDisplayMetrics()); - Bitmap bitmap = BitmapFactory.decodeByteArray(iconBytes, 0, iconBytes.length); - if (bitmap != null) { - if (bitmap.getHeight() != bitmapSizeInDip) { - bitmap = Bitmap.createScaledBitmap(bitmap, bitmapSizeInDip, bitmapSizeInDip, false); - } - - if (MainTabActivity.POSTGINGERBREAD) { - CompatibilityHelper.setActionBarDrawable(this, new BitmapDrawable(bitmap)); - } else { - setFeatureDrawable(Window.FEATURE_LEFT_ICON, new BitmapDrawable(bitmap)); - } - } - } - if (RSSOverview.notificationManager != null) { - RSSOverview.notificationManager.cancel(0); - } - - getListView().setOnCreateContextMenuListener(new OnCreateContextMenuListener() { - public void onCreateContextMenu(ContextMenu menu, View view, ContextMenuInfo menuInfo) { - menu.setHeaderTitle(((TextView) ((AdapterView.AdapterContextMenuInfo) menuInfo).targetView.findViewById(android.R.id.text1)).getText()); - menu.add(0, CONTEXTMENU_MARKASREAD_ID, Menu.NONE, R.string.contextmenu_markasread).setIcon(android.R.drawable.ic_menu_manage); - menu.add(0, CONTEXTMENU_MARKASUNREAD_ID, Menu.NONE, R.string.contextmenu_markasunread).setIcon(android.R.drawable.ic_menu_manage); - menu.add(0, CONTEXTMENU_DELETE_ID, Menu.NONE, R.string.contextmenu_delete).setIcon(android.R.drawable.ic_menu_delete); - menu.add(0, CONTEXTMENU_COPYURL, Menu.NONE, R.string.contextmenu_copyurl).setIcon(android.R.drawable.ic_menu_share); - } - }); - } - - @Override - protected void onListItemClick(ListView listView, View view, int position, long id) { - TextView textView = (TextView) view.findViewById(android.R.id.text1); - - textView.setTypeface(Typeface.DEFAULT); - textView.setEnabled(false); - view.findViewById(android.R.id.text2).setEnabled(false); - entriesListAdapter.neutralizeReadState(); - startActivity(new Intent(Intent.ACTION_VIEW, ContentUris.withAppendedId(uri, id)).putExtra(EXTRA_SHOWREAD, entriesListAdapter.isShowRead()).putExtra(FeedData.FeedColumns.ICON, iconBytes)); - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - getMenuInflater().inflate(R.menu.entrylist, menu); - return true; - } - - @Override - public boolean onPrepareOptionsMenu(Menu menu) { - menu.setGroupVisible(R.id.menu_group_0, entriesListAdapter.getCount() > 0); - return true; - } - - public boolean onMenuItemSelected(int featureId, MenuItem item) { - switch (item.getItemId()) { - case R.id.menu_markasread: { - new Thread() { // the update process takes some time - public void run() { - getContentResolver().update(uri, RSSOverview.getReadContentValues(), null, null); - } - }.start(); - entriesListAdapter.markAsRead(); - break; - } - case R.id.menu_markasunread: { - new Thread() { // the update process takes some time - public void run() { - getContentResolver().update(uri, RSSOverview.getUnreadContentValues(), null, null); - } - }.start(); - entriesListAdapter.markAsUnread(); - break; - } - case R.id.menu_hideread: { - if (item.isChecked()) { - item.setChecked(false).setTitle(R.string.contextmenu_hideread).setIcon(android.R.drawable.ic_menu_close_clear_cancel); - entriesListAdapter.showRead(true); - } else { - item.setChecked(true).setTitle(R.string.contextmenu_showread).setIcon(android.R.drawable.ic_menu_view); - entriesListAdapter.showRead(false); - } - break; - } - case R.id.menu_deleteread: { - new Thread() { // the delete process takes some time - public void run() { - String selection = Strings.READDATE_GREATERZERO+Strings.DB_AND+" ("+Strings.DB_EXCUDEFAVORITE+")"; - - getContentResolver().delete(uri, selection, null); - FeedData.deletePicturesOfFeed(EntriesListActivity.this, uri, selection); - runOnUiThread(new Runnable() { - public void run() { - entriesListAdapter.getCursor().requery(); - } - }); - } - }.start(); - break; - } - case R.id.menu_deleteallentries: { - Builder builder = new AlertDialog.Builder(this); - - builder.setIcon(android.R.drawable.ic_dialog_alert); - builder.setTitle(R.string.contextmenu_deleteallentries); - builder.setMessage(R.string.question_areyousure); - builder.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - new Thread() { - public void run() { - getContentResolver().delete(uri, Strings.DB_EXCUDEFAVORITE, null); - runOnUiThread(new Runnable() { - public void run() { - entriesListAdapter.getCursor().requery(); - } - }); - } - }.start(); - } - }); - builder.setNegativeButton(android.R.string.no, null); - builder.show(); - break; - } - case CONTEXTMENU_MARKASREAD_ID: { - long id = ((AdapterView.AdapterContextMenuInfo) item.getMenuInfo()).id; - - getContentResolver().update(ContentUris.withAppendedId(uri, id), RSSOverview.getReadContentValues(), null, null); - entriesListAdapter.markAsRead(id); - break; - } - case CONTEXTMENU_MARKASUNREAD_ID: { - long id = ((AdapterView.AdapterContextMenuInfo) item.getMenuInfo()).id; - - getContentResolver().update(ContentUris.withAppendedId(uri, id), RSSOverview.getUnreadContentValues(), null, null); - entriesListAdapter.markAsUnread(id); - break; - } - case CONTEXTMENU_DELETE_ID: { - long id = ((AdapterView.AdapterContextMenuInfo) item.getMenuInfo()).id; - - getContentResolver().delete(ContentUris.withAppendedId(uri, id), null, null); - FeedData.deletePicturesOfEntry(Long.toString(id)); - entriesListAdapter.getCursor().requery(); // he have no other choice - break; - } - case CONTEXTMENU_COPYURL: { - ((ClipboardManager) getSystemService(CLIPBOARD_SERVICE)).setText(((AdapterView.AdapterContextMenuInfo) item.getMenuInfo()).targetView.getTag().toString()); - break; - } - - } - return true; - } - -} diff --git a/src/de/shandschuh/sparserss/EntryActivity.java b/src/de/shandschuh/sparserss/EntryActivity.java deleted file mode 100644 index 16615e9..0000000 --- a/src/de/shandschuh/sparserss/EntryActivity.java +++ /dev/null @@ -1,806 +0,0 @@ -/** - * Sparse rss - * - * Copyright (c) 2010-2012 Stefan Handschuh - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - */ - -package de.shandschuh.sparserss; - -import java.util.Date; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import android.app.Activity; -import android.app.AlertDialog; -import android.app.AlertDialog.Builder; -import android.app.NotificationManager; -import android.content.BroadcastReceiver; -import android.content.ContentValues; -import android.content.Context; -import android.content.DialogInterface; -import android.content.Intent; -import android.content.SharedPreferences; -import android.database.Cursor; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.graphics.Color; -import android.graphics.drawable.BitmapDrawable; -import android.net.Uri; -import android.os.Bundle; -import android.preference.PreferenceManager; -import android.text.ClipboardManager; -import android.text.TextUtils; -import android.text.format.DateFormat; -import android.util.TypedValue; -import android.view.GestureDetector; -import android.view.GestureDetector.OnGestureListener; -import android.view.KeyEvent; -import android.view.Menu; -import android.view.MenuItem; -import android.view.MotionEvent; -import android.view.View; -import android.view.View.OnClickListener; -import android.view.View.OnKeyListener; -import android.view.View.OnTouchListener; -import android.view.ViewGroup.LayoutParams; -import android.view.Window; -import android.view.animation.Animation; -import android.webkit.WebView; -import android.widget.ImageButton; -import android.widget.ImageView; -import android.widget.TextView; -import android.widget.Toast; -import android.widget.ViewFlipper; -import de.shandschuh.sparserss.provider.FeedData; - -public class EntryActivity extends Activity { - /* - private static final String NEWLINE = "\n"; - - private static final String BR = "
"; - */ - - private static final String TEXT_HTML = "text/html"; - - private static final String UTF8 = "utf-8"; - - private static final String OR_DATE = " or date "; - - private static final String DATE = "(date="; - - private static final String AND_ID = " and _id"; - - private static final String ASC = "date asc, _id desc limit 1"; - - private static final String DESC = "date desc, _id asc limit 1"; - - private static final String CSS = ""; - - private static final String FONT_START = CSS+""; - - private static final String FONT_FONTSIZE_START = CSS+""; - - private static final String FONTSIZE_END = ""; - - private static final String FONT_END = "



"; - - private static final String BODY_START = ""; - - private static final String BODY_END = "



"; - - private static final int BUTTON_ALPHA = 180; - - private static final String IMAGE_ENCLOSURE = "[@]image/"; - - private static final String TEXTPLAIN = "text/plain"; - - private static final String BRACKET = " ("; - - private int titlePosition; - - private int datePosition; - - private int abstractPosition; - - private int linkPosition; - - private int feedIdPosition; - - private int favoritePosition; - - private int readDatePosition; - - private int enclosurePosition; - - private int authorPosition; - - private String _id; - - private String _nextId; - - private String _previousId; - - private Uri uri; - - private Uri parentUri; - - private int feedId; - - boolean favorite; - - private boolean showRead; - - private boolean canShowIcon; - - private byte[] iconBytes; - - private WebView webView; - - private WebView webView0; // only needed for the animation - - private ViewFlipper viewFlipper; - - private ImageButton nextButton; - - private ImageButton urlButton; - - private ImageButton previousButton; - - private ImageButton playButton; - - int scrollX; - - int scrollY; - - private String link; - - private LayoutParams layoutParams; - - private View content; - - private SharedPreferences preferences; - - private boolean localPictures; - - private TextView titleTextView; - - @Override - protected void onCreate(Bundle savedInstanceState) { - if (MainTabActivity.isLightTheme(this)) { - setTheme(R.style.Theme_Light); - } - - super.onCreate(savedInstanceState); - - int titleId = -1; - - if (MainTabActivity.POSTGINGERBREAD) { - canShowIcon = true; - setContentView(R.layout.entry); - try { - /* This is a trick as com.android.internal.R.id.action_bar_title is not directly accessible */ - titleId = (Integer) Class.forName("com.android.internal.R$id").getField("action_bar_title").get(null); - } catch (Exception exception) { - - } - } else { - canShowIcon = requestWindowFeature(Window.FEATURE_LEFT_ICON); - setContentView(R.layout.entry); - titleId = android.R.id.title; - } - - try { - titleTextView = (TextView) findViewById(titleId); - titleTextView.setSingleLine(true); - titleTextView.setHorizontallyScrolling(true); - titleTextView.setMarqueeRepeatLimit(1); - titleTextView.setEllipsize(TextUtils.TruncateAt.MARQUEE); - titleTextView.setFocusable(true); - titleTextView.setFocusableInTouchMode(true); - } catch (Exception e) { - // just in case for non standard android, nullpointer etc - } - - uri = getIntent().getData(); - parentUri = FeedData.EntryColumns.PARENT_URI(uri.getPath()); - showRead = getIntent().getBooleanExtra(EntriesListActivity.EXTRA_SHOWREAD, true); - iconBytes = getIntent().getByteArrayExtra(FeedData.FeedColumns.ICON); - feedId = 0; - - Cursor entryCursor = getContentResolver().query(uri, null, null, null, null); - - titlePosition = entryCursor.getColumnIndex(FeedData.EntryColumns.TITLE); - datePosition = entryCursor.getColumnIndex(FeedData.EntryColumns.DATE); - abstractPosition = entryCursor.getColumnIndex(FeedData.EntryColumns.ABSTRACT); - linkPosition = entryCursor.getColumnIndex(FeedData.EntryColumns.LINK); - feedIdPosition = entryCursor.getColumnIndex(FeedData.EntryColumns.FEED_ID); - favoritePosition = entryCursor.getColumnIndex(FeedData.EntryColumns.FAVORITE); - readDatePosition = entryCursor.getColumnIndex(FeedData.EntryColumns.READDATE); - enclosurePosition = entryCursor.getColumnIndex(FeedData.EntryColumns.ENCLOSURE); - authorPosition = entryCursor.getColumnIndex(FeedData.EntryColumns.AUTHOR); - - entryCursor.close(); - if (RSSOverview.notificationManager == null) { - RSSOverview.notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); - } - - nextButton = (ImageButton) findViewById(R.id.next_button); - urlButton = (ImageButton) findViewById(R.id.url_button); - urlButton.setAlpha(BUTTON_ALPHA+30); - previousButton = (ImageButton) findViewById(R.id.prev_button); - playButton = (ImageButton) findViewById(R.id.play_button); - playButton.setAlpha(BUTTON_ALPHA); - - viewFlipper = (ViewFlipper) findViewById(R.id.content_flipper); - - - - layoutParams = new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT); - - webView = new WebView(this); - - viewFlipper.addView(webView, layoutParams); - - OnKeyListener onKeyEventListener = new OnKeyListener() { - public boolean onKey(View v, int keyCode, KeyEvent event) { - if (event.getAction() == KeyEvent.ACTION_DOWN) { - if (keyCode == 92 || keyCode == 94) { - scrollUp(); - return true; - } else if (keyCode == 93 || keyCode == 95) { - scrollDown(); - return true; - } - } - return false; - } - }; - webView.setOnKeyListener(onKeyEventListener); - - content = findViewById(R.id.entry_content); - - webView0 = new WebView(this); - webView0.setOnKeyListener(onKeyEventListener); - - preferences = PreferenceManager.getDefaultSharedPreferences(this); - - final boolean gestures = preferences.getBoolean(Strings.SETTINGS_GESTURESENABLED, true); - - final GestureDetector gestureDetector = new GestureDetector(this, new OnGestureListener() { - public boolean onDown(MotionEvent e) { - return false; - } - - public boolean onFling(MotionEvent e1, MotionEvent e2, - float velocityX, float velocityY) { - if (gestures) { - if (Math.abs(velocityY) < Math.abs(velocityX)) { - if (velocityX > 800) { - if (previousButton.isEnabled()) { - previousEntry(true); - } - } else if (velocityX < -800) { - if (nextButton.isEnabled()) { - nextEntry(true); - } - } - } - } - return false; - } - - public void onLongPress(MotionEvent e) { - - } - - public boolean onScroll(MotionEvent e1, MotionEvent e2, - float distanceX, float distanceY) { - return false; - } - - public void onShowPress(MotionEvent e) { - - } - - public boolean onSingleTapUp(MotionEvent e) { - return false; - } - }); - - OnTouchListener onTouchListener = new OnTouchListener() { - public boolean onTouch(View v, MotionEvent event) { - return gestureDetector.onTouchEvent(event); - } - }; - - webView.setOnTouchListener(onTouchListener); - - content.setOnTouchListener(new OnTouchListener() { - public boolean onTouch(View v, MotionEvent event) { - gestureDetector.onTouchEvent(event); - return true; // different to the above one! - } - }); - - webView0.setOnTouchListener(onTouchListener); - - scrollX = 0; - scrollY = 0; - } - - @Override - protected void onRestoreInstanceState(Bundle savedInstanceState) - { - super.onRestoreInstanceState(savedInstanceState); - webView.restoreState(savedInstanceState); - } - - @Override - protected void onResume() { - super.onResume(); - if (RSSOverview.notificationManager != null) { - RSSOverview.notificationManager.cancel(0); - } - uri = getIntent().getData(); - parentUri = FeedData.EntryColumns.PARENT_URI(uri.getPath()); - if (MainTabActivity.POSTGINGERBREAD) { - CompatibilityHelper.onResume(webView); - } - reload(); - } - - @Override - protected void onNewIntent(Intent intent) { - super.onNewIntent(intent); - setIntent(intent); - } - - private void reload() { - if (_id != null && _id.equals(uri.getLastPathSegment())) { - return; - } - - _id = uri.getLastPathSegment(); - - ContentValues values = new ContentValues(); - - values.put(FeedData.EntryColumns.READDATE, System.currentTimeMillis()); - - Cursor entryCursor = getContentResolver().query(uri, null, null, null, null); - - if (entryCursor.moveToFirst()) { - String abstractText = entryCursor.getString(abstractPosition); - - if (entryCursor.isNull(readDatePosition)) { - getContentResolver().update(uri, values, new StringBuilder(FeedData.EntryColumns.READDATE).append(Strings.DB_ISNULL).toString(), null); - } - if (abstractText == null) { - String link = entryCursor.getString(linkPosition); - - entryCursor.close(); - finish(); - startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(link))); - } else { - setTitle(entryCursor.getString(titlePosition)); - if (titleTextView != null) { - titleTextView.requestFocus(); // restart ellipsize - } - - int _feedId = entryCursor.getInt(feedIdPosition); - - if (feedId != _feedId) { - if (feedId != 0) { - iconBytes = null; // triggers re-fetch of the icon - } - feedId = _feedId; - } - - if (canShowIcon) { - if (iconBytes == null || iconBytes.length == 0) { - Cursor iconCursor = getContentResolver().query(FeedData.FeedColumns.CONTENT_URI(Integer.toString(feedId)), new String[] {FeedData.FeedColumns._ID, FeedData.FeedColumns.ICON}, null, null, null); - - if (iconCursor.moveToFirst()) { - iconBytes = iconCursor.getBlob(1); - } - iconCursor.close(); - } - - if (iconBytes != null && iconBytes.length > 0) { - int bitmapSizeInDip = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 24f, getResources().getDisplayMetrics()); - Bitmap bitmap = BitmapFactory.decodeByteArray(iconBytes, 0, iconBytes.length); - if (bitmap != null) { - if (bitmap.getHeight() != bitmapSizeInDip) { - bitmap = Bitmap.createScaledBitmap(bitmap, bitmapSizeInDip, bitmapSizeInDip, false); - } - - if (MainTabActivity.POSTGINGERBREAD) { - CompatibilityHelper.setActionBarDrawable(this, new BitmapDrawable(bitmap)); - } else { - setFeatureDrawable(Window.FEATURE_LEFT_ICON, new BitmapDrawable(bitmap)); - } - } - } - } - - long timestamp = entryCursor.getLong(datePosition); - - Date date = new Date(timestamp); - - StringBuilder dateStringBuilder = new StringBuilder(DateFormat.getDateFormat(this).format(date)).append(' ').append(DateFormat.getTimeFormat(this).format(date)); - - String author = entryCursor.getString(authorPosition); - - if (author != null) { - dateStringBuilder.append(BRACKET).append(author).append(')'); - } - - ((TextView) findViewById(R.id.entry_date)).setText(dateStringBuilder); - - final ImageView imageView = (ImageView) findViewById(android.R.id.icon); - - favorite = entryCursor.getInt(favoritePosition) == 1; - - imageView.setImageResource(favorite ? android.R.drawable.star_on : android.R.drawable.star_off); - imageView.setOnClickListener(new OnClickListener() { - public void onClick(View view) { - favorite = !favorite; - imageView.setImageResource(favorite ? android.R.drawable.star_on : android.R.drawable.star_off); - ContentValues values = new ContentValues(); - - values.put(FeedData.EntryColumns.FAVORITE, favorite ? 1 : 0); - getContentResolver().update(uri, values, null, null); - } - }); - // loadData does not recognize the encoding without correct html-header - localPictures = abstractText.indexOf(Strings.IMAGEID_REPLACEMENT) > -1; - - abstractText = abstractText.replace(Strings.IMAGEID_REPLACEMENT, uri.getLastPathSegment()+Strings.IMAGEFILE_IDSEPARATOR); - - Pattern linkP = Pattern.compile("]*href=[^>]*>"); - Matcher linkM = linkP.matcher(abstractText); - if(!linkM.find()) { - abstractText = abstractText.replaceAll("(?i)(https?://[^ \n\r\t\\[\\]]+)", "$1"); - } - - Pattern brP = Pattern.compile("]*>"); - Matcher brM = brP.matcher(abstractText); - if(!brM.find()) { - abstractText = abstractText.replaceAll("\n", "
"); - } - - abstractText = abstractText.replaceAll("(?i)\\[(/?(b|u))\\]", "<$1>"); - abstractText = abstractText.replaceAll("(?i)\\[img\\](https?://[^ \n\r\t\\[\\]]+)\\[/img\\]", ""); - abstractText = abstractText.replaceAll("(?i)\\[/?(center|color|size|img|url|pre)[^\\]]*\\]", ""); - - final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this); - - if (localPictures) { - abstractText = abstractText.replace(Strings.IMAGEID_REPLACEMENT, _id+Strings.IMAGEFILE_IDSEPARATOR); - } - - if (preferences.getBoolean(Strings.SETTINGS_DISABLEPICTURES, false)) { - abstractText = abstractText.replaceAll(Strings.HTML_IMG_REGEX, Strings.EMPTY); - webView.getSettings().setBlockNetworkImage(true); - } else { - if (webView.getSettings().getBlockNetworkImage()) { - /* - * setBlockNetwortImage(false) calls postSync, which takes time, - * so we clean up the html first and change the value afterwards - */ - webView.loadData(Strings.EMPTY, TEXT_HTML, UTF8); - webView.getSettings().setBlockNetworkImage(false); - } - } - - int fontsize = Integer.parseInt(preferences.getString(Strings.SETTINGS_FONTSIZE, Strings.ONE)); - - /* - if (abstractText.indexOf('<') > -1 && abstractText.indexOf('>') > -1) { - abstractText = abstractText.replace(NEWLINE, BR); - } - */ - - if (MainTabActivity.isLightTheme(this) || preferences.getBoolean(Strings.SETTINGS_BLACKTEXTONWHITE, false)) { - if (fontsize > 0) { - webView.loadDataWithBaseURL(null, new StringBuilder(CSS).append(FONTSIZE_START).append(fontsize).append(FONTSIZE_MIDDLE).append(abstractText).append(FONTSIZE_END).toString(), TEXT_HTML, UTF8, null); - } else { - webView.loadDataWithBaseURL(null, new StringBuilder(CSS).append(BODY_START).append(abstractText).append(BODY_END).toString(), TEXT_HTML, UTF8, null); - } - webView.setBackgroundColor(Color.WHITE); - content.setBackgroundColor(Color.WHITE); - } else { - if (fontsize > 0) { - webView.loadDataWithBaseURL(null, new StringBuilder(FONT_FONTSIZE_START).append(fontsize).append(FONTSIZE_MIDDLE).append(abstractText).append(FONT_END).toString(), TEXT_HTML, UTF8, null); - } else { - webView.loadDataWithBaseURL(null, new StringBuilder(FONT_START).append(abstractText).append(BODY_END).toString(), TEXT_HTML, UTF8, null); - } - webView.setBackgroundColor(Color.BLACK); - content.setBackgroundColor(Color.BLACK); - } - - link = entryCursor.getString(linkPosition); - - if (link != null && link.length() > 0) { - urlButton.setEnabled(true); - urlButton.setAlpha(BUTTON_ALPHA+20); - urlButton.setOnClickListener(new OnClickListener() { - public void onClick(View view) { - startActivityForResult(new Intent(Intent.ACTION_VIEW, Uri.parse(link)), 0); - } - }); - } else { - urlButton.setEnabled(false); - urlButton.setAlpha(80); - } - - final String enclosure = entryCursor.getString(enclosurePosition); - - if (enclosure != null && enclosure.length() > 6 && enclosure.indexOf(IMAGE_ENCLOSURE) == -1) { - playButton.setVisibility(View.VISIBLE); - playButton.setOnClickListener(new OnClickListener() { - public void onClick(View v) { - final int position1 = enclosure.indexOf(Strings.ENCLOSURE_SEPARATOR); - - final int position2 = enclosure.indexOf(Strings.ENCLOSURE_SEPARATOR, position1+3); - - final Uri uri = Uri.parse(enclosure.substring(0, position1)); - - if (preferences.getBoolean(Strings.SETTINGS_ENCLOSUREWARNINGSENABLED, true)) { - Builder builder = new AlertDialog.Builder(EntryActivity.this); - - builder.setTitle(R.string.question_areyousure); - builder.setIcon(android.R.drawable.ic_dialog_alert); - if (position2+4 > enclosure.length()) { - builder.setMessage(getString(R.string.question_playenclosure, uri, position2+4 > enclosure.length() ? Strings.QUESTIONMARKS : enclosure.substring(position2+3))); - } else { - try { - builder.setMessage(getString(R.string.question_playenclosure, uri, (Integer.parseInt(enclosure.substring(position2+3)) / 1024f)+getString(R.string.kb))); - } catch (Exception e) { - builder.setMessage(getString(R.string.question_playenclosure, uri, enclosure.substring(position2+3))); - } - } - builder.setCancelable(true); - builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - showEnclosure(uri, enclosure, position1, position2); - } - }); - builder.setNeutralButton(R.string.button_alwaysokforall, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - preferences.edit().putBoolean(Strings.SETTINGS_ENCLOSUREWARNINGSENABLED, false).commit(); - showEnclosure(uri, enclosure, position1, position2); - } - }); - builder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - dialog.dismiss(); - } - }); - builder.show(); - } else { - showEnclosure(uri, enclosure, position1, position2); - } - } - }); - } else { - playButton.setVisibility(View.GONE); - } - entryCursor.close(); - setupButton(previousButton, false, timestamp); - setupButton(nextButton, true, timestamp); - webView.scrollTo(scrollX, scrollY); // resets the scrolling - } - } else { - entryCursor.close(); - } - - /* - new Thread() { - public void run() { - sendBroadcast(new Intent(Strings.ACTION_UPDATEWIDGET)); // this is slow - } - }.start(); - */ - } - - private void showEnclosure(Uri uri, String enclosure, int position1, int position2) { - try { - startActivityForResult(new Intent(Intent.ACTION_VIEW).setDataAndType(uri, enclosure.substring(position1+3, position2)), 0); - } catch (Exception e) { - try { - startActivityForResult(new Intent(Intent.ACTION_VIEW, uri), 0); // fallbackmode - let the browser handle this - } catch (Throwable t) { - Toast.makeText(EntryActivity.this, t.getMessage(), Toast.LENGTH_LONG).show(); - } - } - } - - private void setupButton(ImageButton button, final boolean successor, long date) { - StringBuilder queryString = new StringBuilder(DATE).append(date).append(AND_ID).append(successor ? '>' : '<').append(_id).append(')').append(OR_DATE).append(successor ? '<' : '>').append(date); - - if (!showRead) { - queryString.append(Strings.DB_AND).append(EntriesListAdapter.READDATEISNULL); - } - - Cursor cursor = getContentResolver().query(parentUri, new String[] {FeedData.EntryColumns._ID}, queryString.toString() , null, successor ? DESC : ASC); - - if (cursor.moveToFirst()) { - button.setEnabled(true); - button.setAlpha(BUTTON_ALPHA); - - final String id = cursor.getString(0); - - if (successor) { - _nextId = id; - } else { - _previousId = id; - } - button.setOnClickListener(new OnClickListener() { - public void onClick(View view) { - if (successor) { - nextEntry(false); - } else { - previousEntry(false); - } - } - }); - } else { - button.setEnabled(false); - button.setAlpha(60); - } - cursor.close(); - } - - private void switchEntry(String id, boolean animate, Animation inAnimation, Animation outAnimation) { - uri = parentUri.buildUpon().appendPath(id).build(); - getIntent().setData(uri); - scrollX = 0; - scrollY = 0; - - if (animate) { - WebView dummy = webView; // switch reference - - webView = webView0; - webView0 = dummy; - } - - reload(); - - if (animate) { - viewFlipper.setInAnimation(inAnimation); - viewFlipper.setOutAnimation(outAnimation); - viewFlipper.addView(webView, layoutParams); - viewFlipper.showNext(); - viewFlipper.removeViewAt(0); - } - } - - private void nextEntry(boolean animate) { - switchEntry(_nextId, animate, Animations.SLIDE_IN_RIGHT, Animations.SLIDE_OUT_LEFT); - } - - private void previousEntry(boolean animate) { - switchEntry(_previousId, animate, Animations.SLIDE_IN_LEFT, Animations.SLIDE_OUT_RIGHT); - } - - @Override - protected void onPause() { - super.onPause(); - if (MainTabActivity.POSTGINGERBREAD) { - CompatibilityHelper.onPause(webView); - } - scrollX = webView.getScrollX(); - scrollY = webView.getScrollY(); - } - - @Override - protected void onSaveInstanceState(Bundle outState) - { - webView.saveState(outState); - super.onSaveInstanceState(outState); - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - getMenuInflater().inflate(R.menu.entry, menu); - return true; - } - - @Override - public boolean onMenuItemSelected(int featureId, MenuItem item) { - switch (item.getItemId()) { - case R.id.menu_copytoclipboard: { - if (link != null) { - ((ClipboardManager) getSystemService(CLIPBOARD_SERVICE)).setText(link); - } - break; - } - case R.id.menu_delete: { - getContentResolver().delete(uri, null, null); - if (localPictures) { - FeedData.deletePicturesOfEntry(_id); - } - - if (nextButton.isEnabled()) { - nextButton.performClick(); - } else { - if (previousButton.isEnabled()) { - previousButton.performClick(); - } else { - finish(); - } - } - break; - } - case R.id.menu_share: { - if (link != null) { - startActivity(Intent.createChooser(new Intent(Intent.ACTION_SEND).putExtra(Intent.EXTRA_TEXT, link).setType(TEXTPLAIN), getString(R.string.menu_share))); - } - break; - } - } - return true; - } - - @Override - public boolean onKeyDown(int keyCode, KeyEvent event) { - if (event.getAction() == KeyEvent.ACTION_DOWN) { - if (keyCode == 92 || keyCode == 94) { - scrollUp(); - return true; - } else if (keyCode == 93 || keyCode == 95) { - scrollDown(); - return true; - } - } - return super.onKeyDown(keyCode, event); - } - - private void scrollUp() { - if (webView != null) { - webView.pageUp(false); - } - } - - private void scrollDown() { - if (webView != null) { - webView.pageDown(false); - } - } - - /** - * Works around android issue 6191 - */ - @Override - public void unregisterReceiver(BroadcastReceiver receiver) { - try { - super.unregisterReceiver(receiver); - } catch (Exception e) { - // do nothing - } - } - -} diff --git a/src/de/shandschuh/sparserss/FeedConfigActivity.java b/src/de/shandschuh/sparserss/FeedConfigActivity.java deleted file mode 100644 index 996dec3..0000000 --- a/src/de/shandschuh/sparserss/FeedConfigActivity.java +++ /dev/null @@ -1,178 +0,0 @@ -/** - * Sparse rss - * - * Copyright (c) 2012 Stefan Handschuh - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - */ - -package de.shandschuh.sparserss; - -import android.app.Activity; -import android.content.ContentValues; -import android.content.Intent; -import android.database.Cursor; -import android.os.Bundle; -import android.view.View; -import android.view.View.OnClickListener; -import android.widget.Button; -import android.widget.CheckBox; -import android.widget.EditText; -import android.widget.Toast; -import de.shandschuh.sparserss.provider.FeedData; - -public class FeedConfigActivity extends Activity { - private static final String WASACTIVE = "wasactive"; - - private static final String[] PROJECTION = new String[] {FeedData.FeedColumns.NAME, FeedData.FeedColumns.URL, FeedData.FeedColumns.WIFIONLY}; - - private EditText nameEditText; - - private EditText urlEditText; - - private CheckBox refreshOnlyWifiCheckBox; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - setContentView(R.layout.feedsettings); - setResult(RESULT_CANCELED); - - Intent intent = getIntent(); - - nameEditText = (EditText) findViewById(R.id.feed_title); - urlEditText = (EditText) findViewById(R.id.feed_url); - refreshOnlyWifiCheckBox = (CheckBox) findViewById(R.id.wifionlycheckbox); - - if (intent.getAction().equals(Intent.ACTION_INSERT)) { - setTitle(R.string.newfeed_title); - restoreInstanceState(savedInstanceState); - ((Button) findViewById(R.id.button_ok)).setOnClickListener(new OnClickListener() { - public void onClick(View v) { - String url = urlEditText.getText().toString(); - - if (!url.startsWith(Strings.HTTP) && !url.startsWith(Strings.HTTPS)) { - url = Strings.HTTP+url; - } - - Cursor cursor = getContentResolver().query(FeedData.FeedColumns.CONTENT_URI, null, new StringBuilder(FeedData.FeedColumns.URL).append(Strings.DB_ARG).toString(), new String[] {url}, null); - - if (cursor.moveToFirst()) { - cursor.close(); - Toast.makeText(FeedConfigActivity.this, R.string.error_feedurlexists, Toast.LENGTH_LONG).show(); - } else { - cursor.close(); - ContentValues values = new ContentValues(); - - values.put(FeedData.FeedColumns.WIFIONLY, refreshOnlyWifiCheckBox.isChecked() ? 1 : 0); - values.put(FeedData.FeedColumns.URL, url); - values.put(FeedData.FeedColumns.ERROR, (String) null); - - String name = nameEditText.getText().toString(); - - if (name.trim().length() > 0) { - values.put(FeedData.FeedColumns.NAME, name); - } - getContentResolver().insert(FeedData.FeedColumns.CONTENT_URI, values); - setResult(RESULT_OK); - finish(); - } - } - }); - } else { - setTitle(R.string.editfeed_title); - - if (!restoreInstanceState(savedInstanceState)) { - Cursor cursor = getContentResolver().query(intent.getData(), PROJECTION, null, null, null); - - if (cursor.moveToNext()) { - nameEditText.setText(cursor.getString(0)); - urlEditText.setText(cursor.getString(1)); - refreshOnlyWifiCheckBox.setChecked(cursor.getInt(2) == 1); - cursor.close(); - } else { - cursor.close(); - Toast.makeText(FeedConfigActivity.this, R.string.error, Toast.LENGTH_LONG).show(); - finish(); - } - } - ((Button) findViewById(R.id.button_ok)).setOnClickListener(new OnClickListener() { - public void onClick(View v) { - String url = urlEditText.getText().toString(); - - Cursor cursor = getContentResolver().query(FeedData.FeedColumns.CONTENT_URI, new String[] {FeedData.FeedColumns._ID}, new StringBuilder(FeedData.FeedColumns.URL).append(Strings.DB_ARG).toString(), new String[] {url}, null); - - if (cursor.moveToFirst() && !getIntent().getData().getLastPathSegment().equals(cursor.getString(0))) { - cursor.close(); - Toast.makeText(FeedConfigActivity.this, R.string.error_feedurlexists, Toast.LENGTH_LONG).show(); - } else { - cursor.close(); - ContentValues values = new ContentValues(); - - if (!url.startsWith(Strings.HTTP) && !url.startsWith(Strings.HTTPS)) { - url = Strings.HTTP+url; - } - values.put(FeedData.FeedColumns.URL, url); - - String name = nameEditText.getText().toString(); - - values.put(FeedData.FeedColumns.NAME, name.trim().length() > 0 ? name : null); - values.put(FeedData.FeedColumns.FETCHMODE, 0); - values.put(FeedData.FeedColumns.WIFIONLY, refreshOnlyWifiCheckBox.isChecked() ? 1 : 0); - values.put(FeedData.FeedColumns.ERROR, (String) null); - getContentResolver().update(getIntent().getData(), values, null, null); - - setResult(RESULT_OK); - finish(); - } - } - - }); - - } - - ((Button) findViewById(R.id.button_cancel)).setOnClickListener(new OnClickListener() { - public void onClick(View v) { - finish(); - } - }); - } - - private boolean restoreInstanceState(Bundle savedInstanceState) { - if (savedInstanceState != null && savedInstanceState.getBoolean(WASACTIVE, false)) { - nameEditText.setText(savedInstanceState.getCharSequence(FeedData.FeedColumns.NAME)); - urlEditText.setText(savedInstanceState.getCharSequence(FeedData.FeedColumns.URL)); - refreshOnlyWifiCheckBox.setChecked(savedInstanceState.getBoolean(FeedData.FeedColumns.WIFIONLY)); - return true; - } else { - return false; - } - } - - @Override - protected void onSaveInstanceState(Bundle outState) { - outState.putBoolean(WASACTIVE, true); - outState.putCharSequence(FeedData.FeedColumns.NAME, nameEditText.getText()); - outState.putCharSequence(FeedData.FeedColumns.URL, urlEditText.getText()); - outState.putBoolean(FeedData.FeedColumns.WIFIONLY, refreshOnlyWifiCheckBox.isChecked()); - } - -} diff --git a/src/de/shandschuh/sparserss/MainTabActivity.java b/src/de/shandschuh/sparserss/MainTabActivity.java deleted file mode 100644 index 082aa21..0000000 --- a/src/de/shandschuh/sparserss/MainTabActivity.java +++ /dev/null @@ -1,293 +0,0 @@ -/** - * Sparse rss - * - * Copyright (c) 2010-2012 Stefan Handschuh - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - */ - -package de.shandschuh.sparserss; - -import android.app.Activity; -import android.app.ActivityManager; -import android.app.ActivityManager.RunningServiceInfo; -import android.app.AlertDialog; -import android.app.Dialog; -import android.app.TabActivity; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.DialogInterface; -import android.content.DialogInterface.OnKeyListener; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.SharedPreferences.Editor; -import android.os.Build; -import android.os.Bundle; -import android.preference.PreferenceManager; -import android.view.KeyEvent; -import android.view.Menu; -import android.view.MenuItem; -import android.view.View; -import android.view.View.OnClickListener; -import android.view.Window; -import android.widget.ScrollView; -import android.widget.TabHost; -import android.widget.TabHost.OnTabChangeListener; -import android.widget.TextView; -import de.shandschuh.sparserss.provider.FeedData; -import de.shandschuh.sparserss.service.FetcherService; - -public class MainTabActivity extends TabActivity { - private static final int DIALOG_LICENSEAGREEMENT = 0; - - private boolean tabsAdded; - - private static final String TAG_NORMAL = "normal"; - - private static final String TAG_ALL = "all"; - - private static final String TAG_FAVORITE = "favorite"; - - public static MainTabActivity INSTANCE; - - public static final boolean POSTGINGERBREAD = !Build.VERSION.RELEASE.startsWith("1") && - !Build.VERSION.RELEASE.startsWith("2"); // this way around is future save - - - private static Boolean LIGHTTHEME; - - public static boolean isLightTheme(Context context) { - if (LIGHTTHEME == null) { - LIGHTTHEME = PreferenceManager.getDefaultSharedPreferences(context).getBoolean(Strings.SETTINGS_LIGHTTHEME, false); - } - return LIGHTTHEME; - } - - private Menu menu; - - private BroadcastReceiver refreshReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - setProgressBarIndeterminateVisibility(true); - } - }; - - private boolean hasContent; - - public void onCreate(Bundle savedInstanceState) { - if (isLightTheme(this)) { - setTheme(R.style.Theme_Light); - } - super.onCreate(savedInstanceState); - - //We need to display progress information - requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS); - - setContentView(R.layout.tabs); - INSTANCE = this; - hasContent = false; - if (getPreferences(MODE_PRIVATE).getBoolean(Strings.PREFERENCE_LICENSEACCEPTED, false)) { - setContent(); - } else { - /* Workaround for android issue 4499 on 1.5 devices */ - getTabHost().addTab(getTabHost().newTabSpec(Strings.EMPTY).setIndicator(Strings.EMPTY).setContent(new Intent(this, EmptyActivity.class))); - - showDialog(DIALOG_LICENSEAGREEMENT); - } - } - - @Override - protected void onResume() - { - super.onResume(); - setProgressBarIndeterminateVisibility(isCurrentlyRefreshing()); - registerReceiver(refreshReceiver, new IntentFilter("de.shandschuh.sparserss.REFRESH")); - } - - @Override - protected void onPause() - { - unregisterReceiver(refreshReceiver); - super.onPause(); - } - - @Override - protected Dialog onCreateDialog(int id) { - AlertDialog.Builder builder = new AlertDialog.Builder(this); - - builder.setIcon(android.R.drawable.ic_dialog_alert); - builder.setTitle(R.string.dialog_licenseagreement); - builder.setNegativeButton(R.string.button_decline, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - dialog.cancel(); - finish(); - } - }); - builder.setPositiveButton(R.string.button_accept, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - dialog.dismiss(); - - Editor editor = getPreferences(MODE_PRIVATE).edit(); - - editor.putBoolean(Strings.PREFERENCE_LICENSEACCEPTED, true); - editor.commit(); - - /* Part of workaround for android issue 4499 on 1.5 devices */ - getTabHost().clearAllTabs(); - - /* we only want to invoke actions if the license is accepted */ - setContent(); - } - }); - setupLicenseText(builder); - builder.setOnKeyListener(new OnKeyListener() { - public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) { - if (keyCode == KeyEvent.KEYCODE_BACK) { - dialog.cancel(); - finish(); - } - return true; - } - }); - return builder.create(); - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - this.menu = menu; - - Activity activity = getCurrentActivity(); - - if (hasContent && activity != null) { - return activity.onCreateOptionsMenu(menu); - } else { - menu.add(Strings.EMPTY); // to let the menu be available - return true; - } - } - - @Override - public boolean onMenuItemSelected(int featureId, MenuItem item) { - Activity activity = getCurrentActivity(); - - if (hasContent && activity != null) { - return activity.onMenuItemSelected(featureId, item); - } else { - return super.onMenuItemSelected(featureId, item); - } - } - - @Override - public boolean onPrepareOptionsMenu(Menu menu) { - Activity activity = getCurrentActivity(); - - if (hasContent && activity != null) { - return activity.onPrepareOptionsMenu(menu); - } else { - return super.onPrepareOptionsMenu(menu); - } - } - - private void setContent() { - TabHost tabHost = getTabHost(); - - tabHost.addTab(tabHost.newTabSpec(TAG_NORMAL).setIndicator(getString(R.string.overview)).setContent(new Intent().setClass(this, RSSOverview.class))); - hasContent = true; - if (PreferenceManager.getDefaultSharedPreferences(this).getBoolean(Strings.SETTINGS_SHOWTABS, false)) { - tabHost.addTab(tabHost.newTabSpec(TAG_ALL).setIndicator(getString(R.string.all)).setContent(new Intent(Intent.ACTION_VIEW, FeedData.EntryColumns.CONTENT_URI).putExtra(EntriesListActivity.EXTRA_SHOWFEEDINFO, true))); - - tabHost.addTab(tabHost.newTabSpec(TAG_FAVORITE).setIndicator(getString(R.string.favorites), getResources().getDrawable(android.R.drawable.star_big_on)).setContent(new Intent(Intent.ACTION_VIEW, FeedData.EntryColumns.FAVORITES_CONTENT_URI).putExtra(EntriesListActivity.EXTRA_SHOWFEEDINFO, true).putExtra(EntriesListActivity.EXTRA_AUTORELOAD, true))); - tabsAdded = true; - getTabWidget().setVisibility(View.VISIBLE); - } - if (POSTGINGERBREAD) { - /* Change the menu also on ICS when tab is changed */ - tabHost.setOnTabChangedListener(new OnTabChangeListener() { - public void onTabChanged(String tabId) { - if (menu != null) { - menu.clear(); - onCreateOptionsMenu(menu); - } - } - }); - if (menu != null) { - menu.clear(); - onCreateOptionsMenu(menu); - } - } - } - - public void setTabWidgetVisible(boolean visible) { - if (visible) { - if (!tabsAdded) { - TabHost tabHost = getTabHost(); - - tabHost.addTab(tabHost.newTabSpec(TAG_ALL).setIndicator(getString(R.string.all)).setContent(new Intent(Intent.ACTION_VIEW, FeedData.EntryColumns.CONTENT_URI).putExtra(EntriesListActivity.EXTRA_SHOWFEEDINFO, true))); - tabHost.addTab(tabHost.newTabSpec(TAG_FAVORITE).setIndicator(getString(R.string.favorites), getResources().getDrawable(android.R.drawable.star_big_on)).setContent(new Intent(Intent.ACTION_VIEW, FeedData.EntryColumns.FAVORITES_CONTENT_URI).putExtra(EntriesListActivity.EXTRA_SHOWFEEDINFO, true))); - tabsAdded = true; - } - getTabWidget().setVisibility(View.VISIBLE); - } else { - getTabWidget().setVisibility(View.GONE); - } - - } - - void setupLicenseText(AlertDialog.Builder builder) { - View view = getLayoutInflater().inflate(R.layout.license, null); - - final TextView textView = (TextView) view.findViewById(R.id.license_text); - - textView.setTextColor(textView.getTextColors().getDefaultColor()); // disables color change on selection - textView.setText(new StringBuilder(getString(R.string.license_intro)).append(Strings.THREENEWLINES).append(getString(R.string.license))); - - final TextView contributorsTextView = (TextView) view.findViewById(R.id.contributors_togglebutton); - - contributorsTextView.setOnClickListener(new OnClickListener() { - boolean showingLicense = true; - - @Override - public void onClick(View view) { - if (showingLicense) { - textView.setText(R.string.contributors_list); - contributorsTextView.setText(R.string.license_word); - } else { - textView.setText(new StringBuilder(getString(R.string.license_intro)).append(Strings.THREENEWLINES).append(getString(R.string.license))); - contributorsTextView.setText(R.string.contributors); - } - showingLicense = !showingLicense; - } - - }); - builder.setView(view); - } - - private boolean isCurrentlyRefreshing() - { - ActivityManager manager = (ActivityManager)getSystemService(ACTIVITY_SERVICE); - for (RunningServiceInfo service: manager.getRunningServices(Integer.MAX_VALUE)) { - if (FetcherService.class.getName().equals(service.service.getClassName())) { - return true; - } - } - return false; - } - -} diff --git a/src/de/shandschuh/sparserss/RSSOverview.java b/src/de/shandschuh/sparserss/RSSOverview.java deleted file mode 100644 index 1552245..0000000 --- a/src/de/shandschuh/sparserss/RSSOverview.java +++ /dev/null @@ -1,608 +0,0 @@ -/** - * Sparse rss - * - * Copyright (c) 2010-2012 Stefan Handschuh - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - */ - -package de.shandschuh.sparserss; - -import java.io.File; -import java.io.FilenameFilter; - -import android.app.AlertDialog; -import android.app.AlertDialog.Builder; -import android.app.Dialog; -import android.app.ListActivity; -import android.app.NotificationManager; -import android.content.ContentValues; -import android.content.Context; -import android.content.DialogInterface; -import android.content.Intent; -import android.database.Cursor; -import android.graphics.Bitmap; -import android.net.ConnectivityManager; -import android.net.NetworkInfo; -import android.net.Uri; -import android.os.Bundle; -import android.os.Environment; -import android.preference.PreferenceManager; -import android.view.ContextMenu; -import android.view.ContextMenu.ContextMenuInfo; -import android.view.Gravity; -import android.view.Menu; -import android.view.MenuItem; -import android.view.MotionEvent; -import android.view.View; -import android.view.View.OnCreateContextMenuListener; -import android.view.View.OnTouchListener; -import android.view.WindowManager; -import android.view.WindowManager.LayoutParams; -import android.widget.AdapterView; -import android.widget.ImageView; -import android.widget.ListView; -import android.widget.TextView; -import android.widget.Toast; -import de.shandschuh.sparserss.provider.FeedData; -import de.shandschuh.sparserss.provider.OPML; -import de.shandschuh.sparserss.service.RefreshService; - -public class RSSOverview extends ListActivity { - private static final int DIALOG_ERROR_FEEDIMPORT = 3; - - private static final int DIALOG_ERROR_FEEDEXPORT = 4; - - private static final int DIALOG_ERROR_INVALIDIMPORTFILE = 5; - - private static final int DIALOG_ERROR_EXTERNALSTORAGENOTAVAILABLE = 6; - - private static final int DIALOG_ABOUT = 7; - - private static final int CONTEXTMENU_EDIT_ID = 3; - - private static final int CONTEXTMENU_REFRESH_ID = 4; - - private static final int CONTEXTMENU_DELETE_ID = 5; - - private static final int CONTEXTMENU_MARKASREAD_ID = 6; - - private static final int CONTEXTMENU_MARKASUNREAD_ID = 7; - - private static final int CONTEXTMENU_DELETEREAD_ID = 8; - - private static final int CONTEXTMENU_DELETEALLENTRIES_ID = 9; - - private static final int CONTEXTMENU_RESETUPDATEDATE_ID = 10; - - private static final int ACTIVITY_APPLICATIONPREFERENCES_ID = 1; - - private static final Uri CANGELOG_URI = Uri.parse("http://code.google.com/p/sparserss/wiki/Changelog"); - - private static final int CONTEXTMENU_SETTINGS_ID = 99; - - static NotificationManager notificationManager; // package scope - - boolean feedSort; - - private RSSOverviewListAdapter listAdapter; - - /** Called when the activity is first created. */ - @Override - public void onCreate(Bundle savedInstanceState) { - if (MainTabActivity.isLightTheme(this)) { - setTheme(R.style.Theme_Light); - } - super.onCreate(savedInstanceState); - - if (notificationManager == null) { - notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); - } - setContentView(R.layout.main); - listAdapter = new RSSOverviewListAdapter(this); - setListAdapter(listAdapter); - getListView().setOnCreateContextMenuListener(new OnCreateContextMenuListener() { - public void onCreateContextMenu(ContextMenu menu, View view, ContextMenuInfo menuInfo) { - menu.setHeaderTitle(((TextView) ((AdapterView.AdapterContextMenuInfo) menuInfo).targetView.findViewById(android.R.id.text1)).getText()); - menu.add(0, CONTEXTMENU_REFRESH_ID, Menu.NONE, R.string.contextmenu_refresh); - menu.add(0, CONTEXTMENU_MARKASREAD_ID, Menu.NONE, R.string.contextmenu_markasread); - menu.add(0, CONTEXTMENU_MARKASUNREAD_ID, Menu.NONE, R.string.contextmenu_markasunread); - menu.add(0, CONTEXTMENU_DELETEREAD_ID, Menu.NONE, R.string.contextmenu_deleteread); - menu.add(0, CONTEXTMENU_DELETEALLENTRIES_ID, Menu.NONE, R.string.contextmenu_deleteallentries); - menu.add(0, CONTEXTMENU_EDIT_ID, Menu.NONE, R.string.contextmenu_edit); - menu.add(0, CONTEXTMENU_RESETUPDATEDATE_ID, Menu.NONE, R.string.contextmenu_resetupdatedate); - menu.add(0, CONTEXTMENU_DELETE_ID, Menu.NONE, R.string.contextmenu_delete); - menu.add(0, CONTEXTMENU_SETTINGS_ID, Menu.NONE, R.string.contextmenu_settings); - } - }); - getListView().setOnTouchListener(new OnTouchListener() { - private int dragedItem = -1; - - private ImageView dragedView; - - private WindowManager windowManager = RSSOverview.this.getWindowManager(); - - private LayoutParams layoutParams; - - private int minY = 25; // is the header size --> needs to be changed - - private ListView listView = getListView(); - - public boolean onTouch(View v, MotionEvent event) { - if (feedSort) { - int action = event.getAction(); - - switch (action) { - case MotionEvent.ACTION_DOWN: - case MotionEvent.ACTION_MOVE: { - // this is the drag action - if (dragedItem == -1) { - dragedItem = listView.pointToPosition((int) event.getX(), (int) event.getY()); - if (dragedItem > -1) { - dragedView = new ImageView(listView.getContext()); - - View item = listView.getChildAt(dragedItem - listView.getFirstVisiblePosition()); - - if (item != null) { - View sortView = item.findViewById(R.id.sortitem); - - if (sortView.getLeft() <= event.getX()) { - item.setDrawingCacheEnabled(true); - dragedView.setImageBitmap(Bitmap.createBitmap(item.getDrawingCache())); - - layoutParams = new LayoutParams(); - layoutParams.height = WindowManager.LayoutParams.WRAP_CONTENT; - layoutParams.gravity = Gravity.TOP; - layoutParams.y = (int) event.getY(); - windowManager.addView(dragedView, layoutParams); - } else { - dragedItem = -1; - return false; // do not comsume - } - - } else { - dragedItem = -1; - } - } - } else if (dragedView != null) { - layoutParams.y = Math.max(minY, Math.max(0, Math.min((int) event.getY(), listView.getHeight()-minY))); - windowManager.updateViewLayout(dragedView, layoutParams); - } - break; - } - case MotionEvent.ACTION_UP: - case MotionEvent.ACTION_CANCEL: { - // this is the drop action - if (dragedItem > -1) { - windowManager.removeView(dragedView); - - int newPosition = listView.pointToPosition((int) event.getX(), (int) event.getY()); - - if (newPosition == -1) { - newPosition = listView.getCount()-1; - } - if (newPosition != dragedItem) { - ContentValues values = new ContentValues(); - - values.put(FeedData.FeedColumns.PRIORITY, newPosition); - getContentResolver().update(FeedData.FeedColumns.CONTENT_URI(listView.getItemIdAtPosition(dragedItem)), values, null, null); - } - dragedItem = -1; - return true; - } else { - return false; - } - } - } - return true; - } else { - return false; - } - } - }); - if (PreferenceManager.getDefaultSharedPreferences(this).getBoolean(Strings.SETTINGS_REFRESHENABLED, false)) { - startService(new Intent(this, RefreshService.class)); // starts the service independent to this activity - } else { - stopService(new Intent(this, RefreshService.class)); - } - if (PreferenceManager.getDefaultSharedPreferences(this).getBoolean(Strings.SETTINGS_REFRESHONPENENABLED, false)) { - new Thread() { - public void run() { - sendBroadcast(new Intent(Strings.ACTION_REFRESHFEEDS)); - } - }.start(); - } - } - - @Override - protected void onResume() { - super.onResume(); - if (RSSOverview.notificationManager != null) { - notificationManager.cancel(0); - } - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - getMenuInflater().inflate(R.menu.feedoverview, menu); - return true; - } - - @Override - public boolean onPrepareOptionsMenu(Menu menu) { - menu.setGroupVisible(R.id.menu_group_0, !feedSort); - menu.setGroupVisible(R.id.menu_group_1, feedSort); - return true; - } - - @SuppressWarnings("deprecation") - @Override - public boolean onMenuItemSelected(int featureId, final MenuItem item) { - setFeedSortEnabled(false); - switch (item.getItemId()) { - case R.id.menu_addfeed: { - startActivity(new Intent(Intent.ACTION_INSERT).setData(FeedData.FeedColumns.CONTENT_URI)); - break; - } - case R.id.menu_refresh: { - new Thread() { - public void run() { - sendBroadcast(new Intent(Strings.ACTION_REFRESHFEEDS).putExtra(Strings.SETTINGS_OVERRIDEWIFIONLY, PreferenceManager.getDefaultSharedPreferences(RSSOverview.this).getBoolean(Strings.SETTINGS_OVERRIDEWIFIONLY, false))); - } - }.start(); - break; - } - case CONTEXTMENU_EDIT_ID: { - startActivity(new Intent(Intent.ACTION_EDIT).setData(FeedData.FeedColumns.CONTENT_URI(((AdapterView.AdapterContextMenuInfo) item.getMenuInfo()).id))); - break; - } - case CONTEXTMENU_REFRESH_ID: { - final String id = Long.toString(((AdapterView.AdapterContextMenuInfo) item.getMenuInfo()).id); - - ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); - - final NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo(); - - if (networkInfo != null && networkInfo.getState() == NetworkInfo.State.CONNECTED) { // since we have acquired the networkInfo, we use it for basic checks - final Intent intent = new Intent(Strings.ACTION_REFRESHFEEDS).putExtra(Strings.FEEDID, id); - - final Thread thread = new Thread() { - public void run() { - sendBroadcast(intent); - } - }; - - if (networkInfo.getType() == ConnectivityManager.TYPE_WIFI || PreferenceManager.getDefaultSharedPreferences(RSSOverview.this).getBoolean(Strings.SETTINGS_OVERRIDEWIFIONLY, false)) { - intent.putExtra(Strings.SETTINGS_OVERRIDEWIFIONLY, true); - thread.start(); - } else { - Cursor cursor = getContentResolver().query(FeedData.FeedColumns.CONTENT_URI(id), new String[] {FeedData.FeedColumns.WIFIONLY}, null, null, null); - - cursor.moveToFirst(); - - if (cursor.isNull(0) || cursor.getInt(0) == 0) { - thread.start(); - } else { - Builder builder = new AlertDialog.Builder(this); - - builder.setIcon(android.R.drawable.ic_dialog_alert); - builder.setTitle(R.string.dialog_hint); - builder.setMessage(R.string.question_refreshwowifi); - builder.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - intent.putExtra(Strings.SETTINGS_OVERRIDEWIFIONLY, true); - thread.start(); - } - }); - builder.setNeutralButton(R.string.button_alwaysokforall, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - PreferenceManager.getDefaultSharedPreferences(RSSOverview.this).edit().putBoolean(Strings.SETTINGS_OVERRIDEWIFIONLY, true).commit(); - intent.putExtra(Strings.SETTINGS_OVERRIDEWIFIONLY, true); - thread.start(); - } - }); - builder.setNegativeButton(android.R.string.no, null); - builder.show(); - } - cursor.close(); - } - - } - break; - } - case CONTEXTMENU_DELETE_ID: { - String id = Long.toString(((AdapterView.AdapterContextMenuInfo) item.getMenuInfo()).id); - - Cursor cursor = getContentResolver().query(FeedData.FeedColumns.CONTENT_URI(id), new String[] {FeedData.FeedColumns.NAME}, null, null, null); - - cursor.moveToFirst(); - - Builder builder = new AlertDialog.Builder(this); - - builder.setIcon(android.R.drawable.ic_dialog_alert); - builder.setTitle(cursor.getString(0)); - builder.setMessage(R.string.question_deletefeed); - builder.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - new Thread() { - public void run() { - getContentResolver().delete(FeedData.FeedColumns.CONTENT_URI(Long.toString(((AdapterView.AdapterContextMenuInfo) item.getMenuInfo()).id)), null, null); - sendBroadcast(new Intent(Strings.ACTION_UPDATEWIDGET)); - } - }.start(); - } - }); - builder.setNegativeButton(android.R.string.no, null); - cursor.close(); - builder.show(); - break; - } - case CONTEXTMENU_MARKASREAD_ID: { - new Thread() { - public void run() { - String id = Long.toString(((AdapterView.AdapterContextMenuInfo) item.getMenuInfo()).id); - - if (getContentResolver().update(FeedData.EntryColumns.CONTENT_URI(id), getReadContentValues(), new StringBuilder(FeedData.EntryColumns.READDATE).append(Strings.DB_ISNULL).toString(), null) > 0) { - getContentResolver().notifyChange(FeedData.FeedColumns.CONTENT_URI(id), null); - } - } - }.start(); - break; - } - case CONTEXTMENU_MARKASUNREAD_ID: { - new Thread() { - public void run() { - String id = Long.toString(((AdapterView.AdapterContextMenuInfo) item.getMenuInfo()).id); - - if (getContentResolver().update(FeedData.EntryColumns.CONTENT_URI(id), getUnreadContentValues(), null, null) > 0) { - getContentResolver().notifyChange(FeedData.FeedColumns.CONTENT_URI(id), null);; - } - } - }.start(); - break; - } - case CONTEXTMENU_SETTINGS_ID: { - startActivity(new Intent(this, FeedPrefsActivity.class).putExtra(FeedData.FeedColumns._ID, Long.toString(((AdapterView.AdapterContextMenuInfo) item.getMenuInfo()).id))); - break; - } - case CONTEXTMENU_DELETEREAD_ID: { - new Thread() { - public void run() { - String id = Long.toString(((AdapterView.AdapterContextMenuInfo) item.getMenuInfo()).id); - - Uri uri = FeedData.EntryColumns.CONTENT_URI(id); - - String selection = Strings.READDATE_GREATERZERO+Strings.DB_AND+" ("+Strings.DB_EXCUDEFAVORITE+")"; - - FeedData.deletePicturesOfFeed(RSSOverview.this, uri, selection); - if (getContentResolver().delete(uri, selection, null) > 0) { - getContentResolver().notifyChange(FeedData.FeedColumns.CONTENT_URI(id), null); - } - } - }.start(); - break; - } - case CONTEXTMENU_DELETEALLENTRIES_ID: { - showDeleteAllEntriesQuestion(this, FeedData.EntryColumns.CONTENT_URI(Long.toString(((AdapterView.AdapterContextMenuInfo) item.getMenuInfo()).id))); - break; - } - case CONTEXTMENU_RESETUPDATEDATE_ID: { - ContentValues values = new ContentValues(); - - values.put(FeedData.FeedColumns.LASTUPDATE, 0); - values.put(FeedData.FeedColumns.REALLASTUPDATE, 0); - getContentResolver().update(FeedData.FeedColumns.CONTENT_URI(Long.toString(((AdapterView.AdapterContextMenuInfo) item.getMenuInfo()).id)), values, null, null); - break; - } - - case R.id.menu_settings: { - startActivityForResult(new Intent(this, ApplicationPreferencesActivity.class), ACTIVITY_APPLICATIONPREFERENCES_ID); - break; - } - case R.id.menu_allread: { - new Thread() { - public void run() { - if (getContentResolver().update(FeedData.EntryColumns.CONTENT_URI, getReadContentValues(), new StringBuilder(FeedData.EntryColumns.READDATE).append(Strings.DB_ISNULL).toString(), null) > 0) { - getContentResolver().notifyChange(FeedData.FeedColumns.CONTENT_URI, null); - } - } - }.start(); - break; - } - case R.id.menu_about: { - showDialog(DIALOG_ABOUT); - break; - } - case R.id.menu_import: { - if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED) ||Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED_READ_ONLY)) { - final AlertDialog.Builder builder = new AlertDialog.Builder(this); - - builder.setTitle(R.string.select_file); - - try { - final String[] fileNames = Environment.getExternalStorageDirectory().list(new FilenameFilter() { - public boolean accept(File dir, String filename) { - return new File(dir, filename).isFile(); - } - }); - builder.setItems(fileNames, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - try { - OPML.importFromFile(new StringBuilder(Environment.getExternalStorageDirectory().toString()).append(File.separator).append(fileNames[which]).toString(), RSSOverview.this); - } catch (Exception e) { - showDialog(DIALOG_ERROR_FEEDIMPORT); - } - } - }); - builder.show(); - } catch (Exception e) { - showDialog(DIALOG_ERROR_FEEDIMPORT); - } - } else { - showDialog(DIALOG_ERROR_EXTERNALSTORAGENOTAVAILABLE); - } - - break; - } - case R.id.menu_export: { - if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED) ||Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED_READ_ONLY)) { - try { - String filename = new StringBuilder(Environment.getExternalStorageDirectory().toString()).append("/sparse_rss_").append(System.currentTimeMillis()).append(".opml").toString(); - - OPML.exportToFile(filename, this); - Toast.makeText(this, String.format(getString(R.string.message_exportedto), filename), Toast.LENGTH_LONG).show(); - } catch (Exception e) { - showDialog(DIALOG_ERROR_FEEDEXPORT); - } - } else { - showDialog(DIALOG_ERROR_EXTERNALSTORAGENOTAVAILABLE); - } - break; - } - case R.id.menu_enablefeedsort: { - setFeedSortEnabled(true); - break; - } - case R.id.menu_deleteread: { - FeedData.deletePicturesOfFeedAsync(this, FeedData.EntryColumns.CONTENT_URI, Strings.READDATE_GREATERZERO); - getContentResolver().delete(FeedData.EntryColumns.CONTENT_URI, Strings.READDATE_GREATERZERO, null); - ((RSSOverviewListAdapter) getListAdapter()).notifyDataSetChanged(); - break; - } - case R.id.menu_deleteallentries: { - showDeleteAllEntriesQuestion(this, FeedData.EntryColumns.CONTENT_URI); - break; - } - case R.id.menu_disablefeedsort: { - // do nothing as the feed sort gets disabled anyway - break; - } - } - return true; - } - - public static final ContentValues getReadContentValues() { - ContentValues values = new ContentValues(); - - values.put(FeedData.EntryColumns.READDATE, System.currentTimeMillis()); - return values; - } - - public static final ContentValues getUnreadContentValues() { - ContentValues values = new ContentValues(); - - values.putNull(FeedData.EntryColumns.READDATE); - return values; - } - - @Override - protected void onListItemClick(ListView listView, View view, int position, long id) { - setFeedSortEnabled(false); - - Intent intent = new Intent(Intent.ACTION_VIEW, FeedData.EntryColumns.CONTENT_URI(Long.toString(id))); - - intent.putExtra(FeedData.FeedColumns._ID, id); - startActivity(intent); - } - - @Override - protected Dialog onCreateDialog(int id) { - Dialog dialog; - - switch (id) { - case DIALOG_ERROR_FEEDIMPORT: { - dialog = createErrorDialog(R.string.error_feedimport); - break; - } - case DIALOG_ERROR_FEEDEXPORT: { - dialog = createErrorDialog(R.string.error_feedexport); - break; - } - case DIALOG_ERROR_INVALIDIMPORTFILE: { - dialog = createErrorDialog(R.string.error_invalidimportfile); - break; - } - case DIALOG_ERROR_EXTERNALSTORAGENOTAVAILABLE: { - dialog = createErrorDialog(R.string.error_externalstoragenotavailable); - break; - } - case DIALOG_ABOUT: { - AlertDialog.Builder builder = new AlertDialog.Builder(this); - - builder.setIcon(android.R.drawable.ic_dialog_info); - builder.setTitle(R.string.menu_about); - MainTabActivity.INSTANCE.setupLicenseText(builder); - builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - dialog.cancel(); - } - }); - builder.setNeutralButton(R.string.changelog, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - startActivity(new Intent(Intent.ACTION_VIEW, CANGELOG_URI)); - } - }); - return builder.create(); - } - default: dialog = null; - } - return dialog; - } - - private Dialog createErrorDialog(int messageId) { - AlertDialog.Builder builder = new AlertDialog.Builder(this); - - builder.setMessage(messageId); - builder.setTitle(R.string.error); - builder.setIcon(android.R.drawable.ic_dialog_alert); - builder.setPositiveButton(android.R.string.ok, null); - return builder.create(); - } - - private static void showDeleteAllEntriesQuestion(final Context context, final Uri uri) { - Builder builder = new AlertDialog.Builder(context); - - builder.setIcon(android.R.drawable.ic_dialog_alert); - builder.setTitle(R.string.contextmenu_deleteallentries); - builder.setMessage(R.string.question_areyousure); - builder.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - new Thread() { - public void run() { - FeedData.deletePicturesOfFeed(context, uri, Strings.DB_EXCUDEFAVORITE); - if (context.getContentResolver().delete(uri, Strings.DB_EXCUDEFAVORITE, null) > 0) { - context.getContentResolver().notifyChange(FeedData.FeedColumns.CONTENT_URI, null); - } - } - }.start(); - } - }); - builder.setNegativeButton(android.R.string.no, null); - builder.show(); - } - - private void setFeedSortEnabled(boolean enabled) { - if (enabled != feedSort) { - listAdapter.setFeedSortEnabled(enabled); - feedSort = enabled; - } - } - -} diff --git a/src/de/shandschuh/sparserss/SimpleTask.java b/src/de/shandschuh/sparserss/SimpleTask.java deleted file mode 100644 index 8ad3ade..0000000 --- a/src/de/shandschuh/sparserss/SimpleTask.java +++ /dev/null @@ -1,80 +0,0 @@ -/** - * Sparse rss - * - * Copyright (c) 2012 Stefan Handschuh - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - */ - -package de.shandschuh.sparserss; - - -public abstract class SimpleTask implements Runnable { - private boolean canceled = false; - - private int postCount = 0; - - public abstract void runControlled(); - - public void cancel() { - canceled = true; - } - - public boolean isCanceled() { - return canceled; - } - - public void post() { - post(1); - } - - public synchronized void post(int count) { - postCount += count; - canceled = false; - } - - public boolean isPosted() { - return postCount > 0; - } - - public int getPostCount() { - return postCount; - } - - public final synchronized void run() { - if (!canceled) { - runControlled(); - } - postRun(); - postCount--; - } - - /** - * Override to use - */ - public void postRun() { - - } - - public void enable() { - canceled = false; - } - -} diff --git a/status_icon_23.svg b/status_icon_23.svg index 14b39d6..df88245 100644 --- a/status_icon_23.svg +++ b/status_icon_23.svg @@ -95,7 +95,7 @@