[npr-android-app] push by justinfr...@gmail.com - 2.4 updates & library refresh on 2012-07-18 18:25 GMT

202 views
Skip to first unread message

npr-and...@googlecode.com

unread,
Jul 18, 2012, 2:25:53 PM7/18/12
to npr-a...@googlegroups.com
Revision: ce46f6fe9235
Author: Justin Friberg <justin...@gmail.com>
Date: Wed Jul 18 11:24:15 2012
Log: 2.4 updates & library refresh

http://code.google.com/p/npr-android-app/source/detail?r=ce46f6fe9235

Added:
/Npr/default.properties
/Npr/libs/crittercism_v2_1_7_crashonly.jar
/Npr/libs/jackson-core-2.0.4.jar
/Npr/libs/jackson-databind-2.0.4.jar
/Npr/res/layout/news_image.xml
/Npr/src/org/npr/android/news/NewsImageActivity.java
/Npr/src/org/npr/android/util/Program.java
/Npr_Test/default.properties
Deleted:
/Npr/libs/crittercism_v1_2_3.jar
/Npr/src/org/npr/api/Program.java
Modified:
/Npr/.classpath
/Npr/.project
/Npr/AndroidManifest.xml
/Npr/Npr.iml
/Npr/libs/libGoogleAnalytics.jar
/Npr/res/layout/main.xml
/Npr/res/layout/news.xml
/Npr/res/values/strings.xml
/Npr/res/values/styles.xml
/Npr/src/org/npr/android/news/AllProgramsActivity.java
/Npr/src/org/npr/android/news/NewsListActivity.java
/Npr/src/org/npr/android/news/NewsListAdapter.java
/Npr/src/org/npr/android/news/NewsStoryActivity.java
/Npr/src/org/npr/android/news/PlaybackService.java
/Npr/src/org/npr/android/news/PlaylistView.java
/Npr/src/org/npr/android/news/ProgramStoryListActivity.java
/Npr/src/org/npr/android/news/RootActivity.java
/Npr/src/org/npr/android/util/PlaylistRepository.java
/Npr/src/org/npr/android/util/Tracker.java
/Npr/src/org/npr/api/ApiConstants.java
/Npr/src/org/npr/api/Story.java
/Npr_Test/Npr_Test.iml

=======================================
--- /dev/null
+++ /Npr/default.properties Wed Jul 18 11:24:15 2012
@@ -0,0 +1,14 @@
+# This file is automatically generated by Android Tools.
+# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
+#
+# This file must be checked in Version Control Systems.
+#
+# To customize properties used by the Ant build system use,
+# "build.properties", and override values to adapt the script to your
+# project structure.
+
+# Indicates whether an apk should be generated for each density.
+split.density=false
+# Project target.
+target=android-4
+apk-configurations=
=======================================
--- /dev/null
+++ /Npr/libs/crittercism_v2_1_7_crashonly.jar Wed Jul 18 11:24:15 2012
Binary file, no diff available.
=======================================
--- /dev/null
+++ /Npr/libs/jackson-core-2.0.4.jar Wed Jul 18 11:24:15 2012
Binary file, no diff available.
=======================================
--- /dev/null
+++ /Npr/libs/jackson-databind-2.0.4.jar Wed Jul 18 11:24:15 2012
Binary file, no diff available.
=======================================
--- /dev/null
+++ /Npr/res/layout/news_image.xml Wed Jul 18 11:24:15 2012
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:background="@color/black"
+ android:orientation="vertical">
+ <FrameLayout
+ android:layout_height="wrap_content"
+ android:layout_width="fill_parent"
+ android:layout_weight="1">
+ <ImageView
+ android:id="@+id/NewsImageView"
+ android:layout_height="fill_parent"
+ android:layout_width="fill_parent"
+ android:scaleType="centerInside"/>
+ <ProgressBar
+ android:id="@+id/ImageProgressIndicator"
+ android:layout_width="40dp"
+ android:layout_height="40dp"
+ android:layout_gravity="center_horizontal|center_vertical"
+ android:visibility="invisible"
+ style="@android:style/Widget.ProgressBar.Small"/>
+ </FrameLayout>
+ <TextView
+ android:id="@+id/NewsImageCaption"
+ android:layout_height="wrap_content"
+ android:layout_width="fill_parent"
+ android:layout_weight="1"
+ android:textAppearance="@style/NewsImageCaptionText"/>
+ <TextView
+ android:id="@+id/NewsImageProvider"
+ android:layout_height="wrap_content"
+ android:layout_width="fill_parent"
+ android:textAppearance="@style/NewsImageProviderText"/>
+</LinearLayout>
=======================================
--- /dev/null
+++ /Npr/src/org/npr/android/news/NewsImageActivity.java Wed Jul 18
11:24:15 2012
@@ -0,0 +1,86 @@
+// Copyright 2011 NPR
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.npr.android.news;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.graphics.Bitmap;
+import android.os.Bundle;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.Window;
+import android.view.WindowManager;
+import android.widget.ImageView;
+import android.widget.ProgressBar;
+import android.widget.TextView;
+
+public class NewsImageActivity extends Activity {
+
+ public static final String EXTRA_IMAGE_URL = "EXTRA_IMAGE_URL";
+ public static final String EXTRA_IMAGE_CAPTION = "EXTRA_IMAGE_CAPTION";
+ public static final String EXTRA_IMAGE_PROVIDER = "EXTRA_IMAGE_PROVIDER";
+
+ ImageView newsImageView;
+ private ProgressBar progressIndicator;
+
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
+ requestWindowFeature(Window.FEATURE_NO_TITLE);
+ getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
+ WindowManager.LayoutParams.FLAG_FULLSCREEN);
+
+ setContentView(R.layout.news_image);
+
+ Intent intent = getIntent();
+ if (intent.hasExtra(EXTRA_IMAGE_CAPTION)) {
+ TextView caption = (TextView) findViewById(R.id.NewsImageCaption);
+ caption.setText(intent.getStringExtra(EXTRA_IMAGE_CAPTION));
+ }
+
+ if (intent.hasExtra(EXTRA_IMAGE_PROVIDER)) {
+ TextView provider = (TextView) findViewById(R.id.NewsImageProvider);
+ provider.setText(String.format(getString(R.string.msg_image_credit),
intent.getStringExtra(EXTRA_IMAGE_PROVIDER)));
+ }
+
+ progressIndicator = (ProgressBar)
findViewById(R.id.ImageProgressIndicator);
+ progressIndicator.setVisibility(View.VISIBLE);
+
+ new Thread(new Runnable() {
+ public void run() {
+ String url = getIntent().getStringExtra(EXTRA_IMAGE_URL);
+ url = url.replaceAll("&s=[0-9]+", "");
+ url = url.concat("&s=3");
+
+ final Bitmap bitmap = DownloadDrawable.createBitmapFromUrl(url);
+
+ newsImageView = (ImageView) findViewById(R.id.NewsImageView);
+ newsImageView.post(new Runnable() {
+ public void run() {
+ progressIndicator.setVisibility(View.INVISIBLE);
+ newsImageView.setImageBitmap(bitmap);
+ }
+ });
+ }
+ }).start();
+ }
+
+ @Override
+ public boolean dispatchTouchEvent(MotionEvent ev) {
+ finish();
+ return super.dispatchTouchEvent(ev);
+ }
+}
=======================================
--- /dev/null
+++ /Npr/src/org/npr/android/util/Program.java Wed Jul 18 11:24:15 2012
@@ -0,0 +1,174 @@
+// Copyright 2009 Google Inc.
+// Copyright 2011 NPR
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.npr.android.util;
+
+import com.fasterxml.jackson.core.JsonFactory;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonToken;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.npr.api.HttpHelper;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Hashtable;
+import java.util.LinkedList;
+import java.util.List;
+
+public class Program {
+
+ private String nprId;
+ private String source;
+ private String name;
+ private String liveStationsUrl;
+ private String platform;
+ private int sortOrder;
+
+ public Program(String nprId, String source, String name,
+ String liveStationsUrl, String platform, int sortOrder) {
+ this.nprId = nprId;
+ this.source = source;
+ this.name = name;
+ this.liveStationsUrl = liveStationsUrl;
+ this.platform = platform;
+ this.sortOrder = sortOrder;
+ }
+
+ public String getNprId() {
+ return nprId;
+ }
+
+ public String getSource() {
+ return source;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String getLiveStationsUrl() {
+ return liveStationsUrl;
+ }
+
+ public String getPlatform() {
+ return platform;
+ }
+
+ public int getSortOrder() {
+ return sortOrder;
+ }
+
+ public static class ProgramBuilder {
+ private String nprId;
+ private String source;
+ private String name;
+ private String liveStationsUrl;
+ private String platform;
+ private int sortOrder;
+
+ public ProgramBuilder withNprId(String nprId) {
+ this.nprId = nprId;
+ return this;
+ }
+
+ public ProgramBuilder withSource(String source) {
+ this.source = source;
+ return this;
+ }
+
+ public ProgramBuilder withName(String name) {
+ this.name = name;
+ return this;
+ }
+
+ public ProgramBuilder withLiveStationUrl(String liveStationsUrl) {
+ this.liveStationsUrl = liveStationsUrl;
+ return this;
+ }
+
+ public ProgramBuilder withPlatform(String platform) {
+ this.platform = platform;
+ return this;
+ }
+
+ public ProgramBuilder withSortOrder(int sortOrder) {
+ this.sortOrder = sortOrder;
+ return this;
+ }
+
+ public Program build() {
+ return new Program(nprId, source, name, liveStationsUrl, platform,
sortOrder);
+ }
+ }
+
+ public static class ProgramFactory {
+
+ private static final String programURL =
+ "http://www.npr.org/services/apps/iphone/news/programs.json";
+
+ public List<Program> downloadPrograms() throws IOException {
+
+ ArrayList<Program> listPrograms = new ArrayList<Program>();
+
+ InputStream json = HttpHelper.download(programURL);
+
+ JsonFactory jsonFactory = new JsonFactory();
+ JsonParser parser = jsonFactory.createJsonParser(json);
+ JsonToken token = parser.nextValue();
+ while (token != JsonToken.START_ARRAY && token !=
JsonToken.END_OBJECT) {
+ token = parser.nextValue();
+ }
+
+ if (token != JsonToken.END_OBJECT) {
+ listPrograms = new ArrayList<Program>();
+ int sortOrder = 0;
+
+ while (token != JsonToken.END_ARRAY) {
+ ProgramBuilder programBuilder = new ProgramBuilder();
+ programBuilder.withSortOrder(sortOrder++);
+ while (token != JsonToken.END_OBJECT) {
+ token = parser.nextToken();
+ if (token == JsonToken.FIELD_NAME) {
+ String fieldName = parser.getText();
+ token = parser.nextToken();
+
+ if (fieldName.equals("nprId")) {
+ programBuilder.withNprId(parser.getText());
+ } else if (fieldName.equals("src")) {
+ programBuilder.withSource(parser.getText());
+ } else if (fieldName.equals("name")) {
+ programBuilder.withName(parser.getText());
+ } else if (fieldName.equals("livestations")) {
+ programBuilder.withLiveStationUrl(parser.getText());
+ } else if (fieldName.equals("platform")) {
+ programBuilder.withPlatform(parser.getText());
+ }
+ }
+ }
+ Program program = programBuilder.build();
+ if (program.getName() != null) {
+ listPrograms.add(program);
+ }
+ token = parser.nextToken();
+ }
+ }
+
+ json.close();
+
+ return listPrograms;
+ }
+ }
+}
=======================================
--- /dev/null
+++ /Npr_Test/default.properties Wed Jul 18 11:24:15 2012
@@ -0,0 +1,11 @@
+# This file is automatically generated by Android Tools.
+# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
+#
+# This file must be checked in Version Control Systems.
+#
+# To customize properties used by the Ant build system use,
+# "build.properties", and override values to adapt the script to your
+# project structure.
+
+# Project target.
+target=android-4
=======================================
--- /Npr/libs/crittercism_v1_2_3.jar Wed Apr 25 14:01:45 2012
+++ /dev/null
Binary file, no diff available.
=======================================
--- /Npr/src/org/npr/api/Program.java Fri Jan 6 11:10:49 2012
+++ /dev/null
@@ -1,165 +0,0 @@
-// Copyright 2009 Google Inc.
-// Copyright 2011 NPR
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package org.npr.api;
-
-
-import android.content.ContentResolver;
-import android.database.Cursor;
-
-import java.util.Hashtable;
-import java.util.List;
-
-public class Program extends StoryGrouping {
-
- private String liveStreamUrl;
- private final String podcastUrl;
-
- public Program(String id, String title, int storycounttoday,
- int storycountmonth, int storycountall, String additionalInfo) {
- super(id, title, storycounttoday, storycountmonth, storycountall,
- additionalInfo);
- liveStreamUrl = null;
- podcastUrl = null;
- }
-
- public Program(String id, String title, int storycounttoday,
- int storycountmonth, int storycountall, String additionalInfo,
- String podcastUrl, String liveStreamUrl) {
- super(id, title, storycounttoday, storycountmonth, storycountall,
- additionalInfo);
- this.podcastUrl = podcastUrl;
- this.liveStreamUrl = liveStreamUrl;
- }
-
-
- public String getPodcastUrl() {
- return podcastUrl;
- }
-
- public String getLiveStreamUrl() {
- return liveStreamUrl;
- }
-
- private void setLiveStreamUrl(String url) {
- liveStreamUrl = url;
- }
-
-
-
-
- public static class ProgramFactory extends StoryGroupingFactory<Program>
{
-
- private final ContentResolver contentResolver;
-
- public ProgramFactory(ContentResolver resolver) {
- // Inherit from an instance of an NPRML factory
- super(Program.class, "3004");
- // Get a reference to the content resolver for the Conf file
- this.contentResolver = resolver;
- }
-
- @Override
- public List<Program> downloadStoryGroupings(int count) {
- // Get NPRML list
- List<Program> list = super.downloadStoryGroupings(-1);
-
- // Create a hashtable cache for quick look-up by topic id
- Hashtable<String, Program> lookup = new Hashtable<String, Program>();
- for (Program p : list) {
- lookup.put(p.getId(), p);
- }
-
- // Add any programs in the Conf file that aren't already listed
- Cursor cursor = contentResolver.query(
- IPhoneNewsAppProgramsConfProvider.CONTENT_URL, null, null, null,
null
- );
-
- if (cursor != null) {
- if (cursor.moveToFirst()) {
- do {
- String id = cursor.getString(
- cursor.getColumnIndex(
- IPhoneNewsAppProgramsConfProvider.Items.TOPIC_ID
- )
- );
- // Check it it's already in the list
- if (id != null && lookup.containsKey(id)) {
- lookup.get(id).setLiveStreamUrl(cursor.getString(
- cursor.getColumnIndex(
-
IPhoneNewsAppProgramsConfProvider.Items.LIVE_STREAM_URL
- )
- ));
- } else {
- // If not, add it to the list
- ProgramBuilder builder = new ProgramBuilder(id);
- String title = cursor.getString(
- cursor.getColumnIndex(
- IPhoneNewsAppProgramsConfProvider.Items.NAME
- )
- );
- builder.withTitle(title);
-
- builder.withPodcastUrl(cursor.getString(
- cursor.getColumnIndex(
- IPhoneNewsAppProgramsConfProvider.Items.PODCAST_URL
- )
- ));
- builder.withLiveStreamUrl(cursor.getString(
- cursor.getColumnIndex(
-
IPhoneNewsAppProgramsConfProvider.Items.LIVE_STREAM_URL
- )
- ));
-
- list.add(builder.build());
- }
- } while (cursor.moveToNext());
- }
- cursor.close();
- }
-
- return (count >= 0 && count < list.size()) ?
- list.subList(0, count) :
- list;
- }
- }
-
-
- public static class ProgramBuilder extends StoryGroupingBuilder<Program>
{
-
- private String liveStreamUrl;
- private String podcastUrl;
-
- public ProgramBuilder(String id) {
- super(Program.class, id, 0, 0, 0);
- }
-
-
- public void withPodcastUrl(String url) {
- this.podcastUrl = url;
- }
-
- public void withLiveStreamUrl(String url) {
- this.liveStreamUrl = url;
- }
-
- @Override
- public Program build() {
- return new Program(id, title, storycounttoday, storycountmonth,
- storycountall, additionalInfo, podcastUrl, liveStreamUrl);
- }
- }
-
-}
=======================================
--- /Npr/.classpath Wed Apr 25 17:02:51 2012
+++ /Npr/.classpath Wed Jul 18 11:24:15 2012
@@ -4,7 +4,9 @@
<classpathentry kind="src" path="gen"/>
<classpathentry kind="con"
path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
<classpathentry kind="lib" path="libs/libGoogleAnalytics.jar"/>
+ <classpathentry kind="lib" path="libs/crittercism_v2_1_7_crashonly.jar"/>
+ <classpathentry kind="lib" path="libs/jackson-core-2.0.4.jar"/>
+ <classpathentry kind="lib" path="libs/jackson-databind-2.0.4.jar"/>
<classpathentry kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
- <classpathentry kind="lib" path="libs/crittercism_v1_2_3.jar"/>
<classpathentry kind="output" path="bin/classes"/>
</classpath>
=======================================
--- /Npr/AndroidManifest.xml Wed Apr 25 17:02:51 2012
+++ /Npr/AndroidManifest.xml Wed Jul 18 11:24:15 2012
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
- package="org.npr.android.news" android:versionName="2.3"
+ package="org.npr.android.news" android:versionName="2.4"
android:versionCode="3">

<uses-permission
@@ -57,6 +57,9 @@
</intent-filter>
</activity>
<activity
+ android:name="NewsImageActivity"
+ android:screenOrientation="portrait"/>
+ <activity
android:name="NewsTopicActivity"
android:screenOrientation="portrait"/>
<activity
@@ -111,9 +114,6 @@
android:name="android.test.runner"/>

<!-- Start of Crittercism.com Code -->
- <activity android:name="com.crittercism.FeedbackActivity"/>
- <activity android:name="com.crittercism.FeedbackCreateActivity"/>
- <activity android:name="com.crittercism.FeedbackDetailsActivity"/>
<activity android:name="com.crittercism.NotificationActivity"/>
<!-- End of Crittercism.com Code -->

=======================================
--- /Npr/Npr.iml Tue Jul 17 16:02:43 2012
+++ /Npr/Npr.iml Wed Jul 18 11:24:15 2012
@@ -36,16 +36,7 @@
</content>
<orderEntry type="jdk" jdkName="Android 2.1 Platform" jdkType="Android
SDK" />
<orderEntry type="sourceFolder" forTests="false" />
- <orderEntry type="module-library">
- <library>
- <CLASSES>
- <root url="jar://$MODULE_DIR$/libs/libGoogleAnalytics.jar!/" />
- </CLASSES>
- <JAVADOC />
- <SOURCES />
- </library>
- </orderEntry>
- <orderEntry type="library" name="crittercism_v1_2_3" level="project" />
+ <orderEntry type="library" name="Libs" level="project" />
</component>
</module>

=======================================
--- /Npr/libs/libGoogleAnalytics.jar Mon Jul 12 18:48:24 2010
+++ /Npr/libs/libGoogleAnalytics.jar Wed Jul 18 11:24:15 2012
Binary file, no diff available.
=======================================
--- /Npr/res/layout/main.xml Fri May 11 20:03:52 2012
+++ /Npr/res/layout/main.xml Wed Jul 18 11:24:15 2012
@@ -10,32 +10,22 @@
android:orientation="horizontal"
android:background="@drawable/logo_bar_back_normal"
android:gravity="center">
- <ImageButton
- android:id="@+id/MainSearchButton"
- android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:layout_marginTop="14dip"
- android:layout_marginBottom="13dip"
- android:layout_marginLeft="20dip"
- android:layout_marginRight="20dip"
- android:src="@drawable/search_button"
- android:background="@android:color/transparent"
- android:contentDescription="@string/acd_search_button"
-
- />
-
<ImageButton
android:id="@+id/MainNavButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:src="@drawable/navigation_button"
android:background="@android:color/transparent"/>
-
+ android:layout_marginTop="14dip"
+ android:layout_marginBottom="13dip"
+ android:layout_marginLeft="20dip"
+ android:layout_marginRight="20dip"
+ android:src="@drawable/navigation_button"
+ android:background="@android:color/transparent"
+ android:contentDescription="@string/acd_menu_button"/>
<ImageView
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_marginTop="1dip"
- android:src="@drawable/logo_bar_divider"
- />
+ android:src="@drawable/logo_bar_divider"/>
<LinearLayout
android:layout_height="wrap_content"
android:layout_width="wrap_content"
@@ -56,23 +46,28 @@
android:id="@+id/Logo2"
/>
</LinearLayout>
- <ProgressBar
- android:id="@+id/WindowProgressIndicator"
- android:layout_width="20dp"
- android:layout_height="20dp"
- android:layout_marginRight="20dp"
- android:layout_marginLeft="20dp"
- android:visibility="invisible"
- style="@android:style/Widget.ProgressBar.Small"
- />
+ <ImageView
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:layout_marginTop="1dip"
+ android:src="@drawable/logo_bar_divider"/>
+ <ImageButton
+ android:id="@+id/MainSearchButton"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:layout_marginTop="14dip"
+ android:layout_marginBottom="13dip"
+ android:layout_marginLeft="20dip"
+ android:layout_marginRight="20dip"
+ android:src="@drawable/search_button"
+ android:background="@android:color/transparent"
+ android:contentDescription="@string/acd_search_button"/>
</LinearLayout>
-
<FrameLayout
android:id="@+id/SponsorshipBanner"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"/>
-
<FrameLayout
android:id="@+id/TitleContent"
android:layout_width="fill_parent"
@@ -80,5 +75,12 @@
android:layout_below="@id/LogoBar"
android:layout_above="@id/SponsorshipBanner">
</FrameLayout>
-
+ <ProgressBar
+ android:id="@+id/WindowProgressIndicator"
+ android:layout_width="20dp"
+ android:layout_height="20dp"
+ android:visibility="invisible"
+ style="@android:style/Widget.ProgressBar.Small"
+ android:layout_centerInParent="true"
+ />
</RelativeLayout>
=======================================
--- /Npr/res/layout/news.xml Sun May 22 12:54:47 2011
+++ /Npr/res/layout/news.xml Wed Jul 18 11:24:15 2012
@@ -1,8 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
-<ListView
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/ListView01"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:hapticFeedbackEnabled="true">
-</ListView>
+<RelativeLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent">
+ <ListView
+ android:id="@+id/ListView01"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:hapticFeedbackEnabled="true">
+ </ListView>
+ <FrameLayout
+ android:id="@+id/StoryLoadBar"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_alignParentBottom="true"
+ android:background="#f2f2f2"
+ android:visibility="invisible">
+ <ProgressBar
+ android:id="@+id/StoryLoadProgressIndicator"
+ android:layout_width="20dp"
+ android:layout_height="20dp"
+ android:layout_margin="5dp"
+ android:layout_gravity="center"
+ style="@android:style/Widget.ProgressBar.Small"
+ />
+ </FrameLayout>
+</RelativeLayout>
=======================================
--- /Npr/res/values/strings.xml Tue Jul 17 16:02:43 2012
+++ /Npr/res/values/strings.xml Wed Jul 18 11:24:15 2012
@@ -34,10 +34,12 @@
next item.</string>
<string name="msg_playback_connection_error">Connection error. Retrying
in 30 seconds.</string>
+ <string name="msg_playback_invalid_playable_error">Unable to play
selected item.</string>

<string name="msg_check_connection">Check connection and try
again.</string>

<string name="msg_share_story">Share this story</string>
+ <string name="msg_image_credit">Image Credit: %s</string>

<string name="msg_listen_nothing">Not playing</string>
<string name="msg_listen_playlist">Playlist</string>
@@ -173,6 +175,7 @@

<!-- Accessibility String Values -->
<string name="acd_about">About NPR</string>
+ <string name="acd_menu_button">Menu Button</string>
<string name="acd_search_button">Search Button</string>
<string name="acd_play_button">Play</string>
<string name="acd_pause_button">Pause</string>
=======================================
--- /Npr/res/values/styles.xml Tue Oct 25 08:27:38 2011
+++ /Npr/res/values/styles.xml Wed Jul 18 11:24:15 2012
@@ -57,6 +57,18 @@
<item name="android:typeface">sans</item>
<item name="android:textColor">#737373</item>
</style>
+ <style name="NewsImageCaptionText"
parent="@android:style/TextAppearance">
+ <item name="android:textSize">18sp</item>
+ <item name="android:typeface">sans</item>
+ <item name="android:textStyle">bold</item>
+ <item name="android:textColor">@android:color/white</item>
+ </style>
+ <style name="NewsImageProviderText"
parent="@android:style/TextAppearance">
+ <item name="android:textSize">10sp</item>
+ <item name="android:typeface">sans</item>
+ <item name="android:textStyle">bold</item>
+ <item name="android:textColor">@android:color/white</item>
+ </style>
<style name="PlayerStatusText"
parent="@android:style/TextAppearance">
<item name="android:textSize">10sp</item>
=======================================
--- /Npr/src/org/npr/android/news/AllProgramsActivity.java Wed Apr 25
17:02:51 2012
+++ /Npr/src/org/npr/android/news/AllProgramsActivity.java Wed Jul 18
11:24:15 2012
@@ -31,22 +31,14 @@

import org.npr.android.util.ArrayUtils;
import org.npr.android.util.DisplayUtils;
+import org.npr.android.util.Program;
import org.npr.android.util.Tracker;
import org.npr.api.ApiConstants;
-import org.npr.api.Program;
import org.npr.api.PublicBroadcastingClient;

import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * Author: Jeremy Wadsack
- */
+import java.util.*;
+
public class AllProgramsActivity extends TitleActivity implements
AdapterView.OnItemClickListener {
private static final String LOG_TAG =
AllProgramsActivity.class.getName();
@@ -75,21 +67,22 @@
};


+ @SuppressWarnings("unchecked")
protected int constructList() {
try {
nowPlayingIDs = PublicBroadcastingClient.getNowPlayingIds();
- } catch (IOException ignore) {
- }
- List<Program> programs = new
Program.ProgramFactory(getContentResolver())
- .downloadStoryGroupings(-1);
- listAdapter = new ProgramListAdapter(categorizePrograms(programs));
-
- int message = 0;
-
- if (programs == null) {
- message = 1;
- }
- return message;
+
+ List<Program> programs = new
Program.ProgramFactory().downloadPrograms();
+ listAdapter = new ProgramListAdapter(categorizePrograms(programs));
+
+ if (programs != null) {
+ return 0;
+ }
+
+ } catch (IOException e) {
+ Log.e(LOG_TAG, "Error constructing program list", e);
+ }
+ return 1;
}


@@ -142,13 +135,13 @@
return;
}
Intent i = new Intent(this, ProgramStoryListActivity.class);
- i.putExtra(Constants.EXTRA_LIVE_STREAM_RSS_URL,
item.getLiveStreamUrl());
+ i.putExtra(Constants.EXTRA_LIVE_STREAM_RSS_URL,
item.getLiveStationsUrl());
i.putExtra(Constants.EXTRA_TEASER_ONLY, true);

String grouping = getString(type);
- String description = item.getTitle();
- String topicId = item.getId();
- String url = item.getPodcastUrl();
+ String description = item.getName();
+ String topicId = item.getNprId();
+ String url = item.getSource();
if (url != null) {
i.putExtra(Constants.EXTRA_PODCAST_URL, url);
} else {
@@ -204,20 +197,15 @@
// Lower category index first
int ret = categoryIndex - other.categoryIndex;
if (ret == 0 && program != null) {
- // If same category, then sort preferred programs first
- ret = getTitleRank(program.getTitle()) -
- getTitleRank(other.program.getTitle());
- }
- if (ret == 0 && program != null) {
- // Last resort, just sort alphabetically
- ret = program.getTitle().compareTo(other.program.getTitle());
+ // Sort by order read
+ ret = program.getSortOrder() - other.program.getSortOrder();
}
return ret;
}

@Override
public String toString() {
- return program == null ? categoryName : program.toString();
+ return program == null ? categoryName : program.getName();
}
}

@@ -240,7 +228,7 @@
if (icon != null) {
int id = -1;
if (item != null && item.program != null) {
- String topicId = item.program.getId();
+ String topicId = item.program.getNprId();
if (topicId != null && Character.isDigit(topicId.charAt(0))) {
id = Integer.parseInt(topicId);
}
@@ -287,9 +275,9 @@

// Associate each program with its category
for (Program p : programs) {
- int i = getCategoryById(p.getId());
+ int i = getCategoryById(p.getNprId());
if (i < 0) {
- i = getCategoryByTitle(p.getTitle());
+ i = getCategoryByTitle(p.getName());
}
if (i < 0 ) {
i = categories.length - 1;
@@ -354,58 +342,4 @@
}
return -1;
}
-
-
-
- // Order of stories by preferred rank as shown on npr.org in Programs
menu
- private final List<String> sortedProgramTitles = Arrays.asList(
- "Morning Edition",
- "All Things Considered",
- "Fresh Air from WHYY",
- "Diane Rehm (WAMU)",
- "On the Media (WNYC)",
- "On Point (WBUR)",
- "Talk of the Nation",
- "Science Friday",
- "Tell Me More",
- "Weekend Edition Saturday",
- "Weekend Edition Sunday",
- "Also heard on NPR stations:",
- "Marketplace APM",
- "Car Talk",
- "Radiolab (WNYC)",
- "Snap Judgment",
- "Wait Wait...Don't Tell Me!",
- "Also heard on NPR stations:",
- "This American Life PRI",
- "A Prairie Home Companion APM",
- "All Songs Considered",
- "From the Top",
- "JazzSet",
- "Piano Jazz",
- "Mountain Stage",
- "Song of the Day",
- "Thistle & Shamrock",
- "World Cafe",
- "StoryCorps",
- "Planet Money",
- "Picture Show",
- "Krulwich Wonders..."
- );
-
- private HashMap<String, Integer> programTitlesRank = null;
-
- private int getTitleRank(String title) {
- if (programTitlesRank == null) {
- programTitlesRank =
- new HashMap<String, Integer>(sortedProgramTitles.size());
- for (int i = 0; i < sortedProgramTitles.size(); i++) {
- programTitlesRank.put(sortedProgramTitles.get(i), i + 1);
- }
- }
-
- Integer rank = programTitlesRank.get(title);
- return rank == null ? Integer.MAX_VALUE : rank;
- }
-
-}
+}
=======================================
--- /Npr/src/org/npr/android/news/NewsListActivity.java Wed Apr 25 17:02:51
2012
+++ /Npr/src/org/npr/android/news/NewsListActivity.java Wed Jul 18 11:24:15
2012
@@ -29,11 +29,8 @@
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
-import android.widget.AdapterView;
+import android.widget.*;
import android.widget.AdapterView.OnItemClickListener;
-import android.widget.ImageView;
-import android.widget.ListView;
-import android.widget.TextView;
import org.npr.android.util.*;
import org.npr.android.util.Tracker.StoryListMeasurement;
import org.npr.api.ApiConstants;
@@ -226,13 +223,30 @@
registerReceiver(playlistChangedReceiver,
new IntentFilter(PlaylistRepository.PLAYLIST_CHANGED));

+ startIndeterminateProgressIndicator();
addStories();
}
+
+ protected void startStoryLoadProgressIndicator() {
+ FrameLayout storyLoadProgress = (FrameLayout)
findViewById(R.id.StoryLoadBar);
+ if (storyLoadProgress != null) {
+ storyLoadProgress.setVisibility(View.VISIBLE);
+ }
+ }
+
+ protected void stopStoryLoadProgressIndicator() {
+ FrameLayout storyLoadProgress = (FrameLayout)
findViewById(R.id.StoryLoadBar);
+ if (storyLoadProgress != null) {
+ storyLoadProgress.setVisibility(View.INVISIBLE);
+ }
+ }

private NewsListAdapter.StoriesLoadedListener listener = new
NewsListAdapter.StoriesLoadedListener() {
@Override
public void storiesLoaded() {
bannerView.startCloseTimer();
+ stopIndeterminateProgressIndicator();
+ stopStoryLoadProgressIndicator();
}
};

@@ -267,6 +281,7 @@

Story s = (Story) parent.getAdapter().getItem(position);
if (s == null) {
+ startStoryLoadProgressIndicator();
addStories();
} else {
Intent i = new Intent(this, NewsStoryActivity.class);
=======================================
--- /Npr/src/org/npr/android/news/NewsListAdapter.java Fri Jan 6 11:10:49
2012
+++ /Npr/src/org/npr/android/news/NewsListAdapter.java Wed Jul 18 11:24:15
2012
@@ -38,6 +38,7 @@
import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
import java.util.List;
+import java.util.Map;


public class NewsListAdapter extends ArrayAdapter<Story> {
@@ -88,10 +89,6 @@
.getText(R.string.msg_check_connection),
Toast.LENGTH_LONG).show();
}
- if (rootActivity != null) {
- rootActivity.stopIndeterminateProgressIndicator();
- }
-
}
};

@@ -164,7 +161,14 @@
if (story.getThumbnails().size() > 0) {
imageUrl = story.getThumbnails().get(0).getMedium();
} else if (story.getImages().size() > 0) {
- imageUrl = story.getImages().get(0).getSrc();
+ for (Map.Entry<String, Story.Image> entry :
story.getImages().entrySet()) {
+ if (imageUrl == null) {
+ imageUrl = entry.getValue().getSrc();
+ } else if (entry.getValue().getType().equals("primary")) {
+ imageUrl = entry.getValue().getSrc();
+ break;
+ }
+ }
}
if (imageUrl != null) {
Drawable cachedImage = imageLoader.loadImage(
@@ -191,9 +195,6 @@
}

public void addMoreStories(final String url, final int count) {
- if (rootActivity != null) {
- rootActivity.startIndeterminateProgressIndicator();
- }
new Thread(new Runnable() {
@Override
public void run() {
=======================================
--- /Npr/src/org/npr/android/news/NewsStoryActivity.java Wed Apr 25
14:01:45 2012
+++ /Npr/src/org/npr/android/news/NewsStoryActivity.java Wed Jul 18
11:24:15 2012
@@ -20,6 +20,7 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
+import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Environment;
import android.text.Html;
@@ -49,6 +50,7 @@
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
+import java.util.Map;

public class NewsStoryActivity extends RootActivity implements
WorkspaceView.OnScreenChangeListener {
@@ -56,6 +58,8 @@

private WorkspaceView workspace;
private LayoutInflater inflater;
+ private ImageThreadLoader imageLoader;
+
// Sample date from api: Tue, 09 Jun 2009 15:20:00 -0400
public static final SimpleDateFormat apiDateFormat
= new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss Z");
@@ -109,6 +113,7 @@

workspace = new WorkspaceView(this, null);
inflater = (LayoutInflater)
getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ imageLoader = ImageThreadLoader.getOnDiskInstance(this);

FrameLayout.LayoutParams layout = new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.FILL_PARENT,
@@ -185,19 +190,39 @@
View storyView = inflater.inflate(R.layout.news_story, null, false);
workspace.addView(storyView);

+ loadStory(story, position, total, storyView, teaserOnly);
+
+ Button listenNow =
+ (Button) storyView.findViewById(R.id.NewsStoryListenNowButton);
+ Button enqueue =
+ (Button) storyView.findViewById(R.id.NewsStoryListenEnqueueButton);
+ Button share = (Button)
storyView.findViewById(R.id.NewsStoryShareButton);
+
+ StoryClickListener listener = new StoryClickListener(position);
+
+ listenNow.setOnClickListener(listener);
+ enqueue.setOnClickListener(listener);
+ share.setOnClickListener(listener);
+ boolean isListenable = story.getPlayableUrl() != null;
+ listenNow.setVisibility(isListenable ? View.VISIBLE : View.INVISIBLE);
+ listenNow.setEnabled(isListenable);
+ enqueue.setVisibility(isListenable ? View.VISIBLE : View.INVISIBLE);
+ enqueue.setEnabled(isListenable &&
+ playlistRepository.getPlaylistItemFromStoryId(story.getId()) ==
null);
+ }
+
+ private void loadStory(Story story, int position, int total, View
storyView, boolean teaserOnly) {
+ WebView storyWebView = (WebView)
storyView.findViewById(R.id.NewsStoryWebView);
+ storyWebView.getSettings().setJavaScriptEnabled(true);
+ storyWebView.setBackgroundColor(0);
+ storyWebView.addJavascriptInterface(new
ImageClickInterface(this), "click");
+
TextView index = (TextView)
storyView.findViewById(R.id.NewsStoryIndex);
TextView title = (TextView)
storyView.findViewById(R.id.NewsStoryTitleText);
TextView dateline =
(TextView) storyView.findViewById(R.id.NewsStoryDateline);
TextView byline =
(TextView) storyView.findViewById(R.id.NewsStoryByline);
- Button listenNow =
- (Button) storyView.findViewById(R.id.NewsStoryListenNowButton);
- Button enqueue =
- (Button) storyView.findViewById(R.id.NewsStoryListenEnqueueButton);
- Button share = (Button)
storyView.findViewById(R.id.NewsStoryShareButton);
- WebView textView = (WebView)
storyView.findViewById(R.id.NewsStoryWebView);
- textView.setBackgroundColor(0);

index.setText(String.format(getString(R.string.msg_story_count_format),
position + 1, total));
@@ -257,14 +282,58 @@
String textHtml;
if (!teaserOnly && text != null) {
StringBuilder sb = new StringBuilder();
- for (String paragraph : text.getParagraphs()) {
- sb.append("<p>").append(paragraph).append("</p>");
+ if (story.getLayout().getItems().size() > 0) {
+
+ for (Map.Entry<Integer, Story.Layout.LayoutItem> entry :
story.getLayout().getItems().entrySet()) {
+
+ if (entry.getValue().getType() == Story.Layout.Type.text) {
+
+ Integer paragraphNum = entry.getKey();
+ try {
+ paragraphNum =
Integer.parseInt(entry.getValue().getItemId());
+ } catch (NumberFormatException e) {
+ Log.w(LOG_TAG, "Unable to parse paragraph number: " +
entry.getValue().getItemId());
+ }
+ String paragraph = text.getParagraphs().get(paragraphNum);
+ // WebView can't load external images, so we need to strip
them or it
+ // may not render.
+ paragraph = paragraph.replaceAll("<img .*/>", "");
+ sb.append("<p>").append(paragraph).append("</p>");
+
+ } else if (entry.getValue().getType() == Story.Layout.Type.image
&&
+ externalStorageAvailable) {
+
+ Story.Image image =
story.getImages().get(entry.getValue().getItemId());
+ if (image != null) {
+ imageLoader.loadImage(image.getSrc(), new
ImageLoadListener(position));
+
+ String imageTag = String.format(
+ "<a
onClick=\"window.click.clickOnImage('%s', '%s', '%s')\">" +
+ "<div id=\"story-icon\"><img src=\"file://%s/%s\"
/></div></a>",
+ image.getSrc(),
+
image.getCaption().replace("'", "\\'").replace("\"", "&quot;"),
+
image.getAttribution().replace("'", "\\'").replace("\"", "&quot;"),
+ ImageThreadLoader.DiskCache.getCachePath(this),
+
ImageThreadLoader.DiskCache.makeCacheFileName(image.getSrc())
+ );
+ Log.d(LOG_TAG, "Adding tag for image " + imageTag);
+ sb.append(imageTag);
+ }
+ }
+ }
+ } else {
+
+ // No layout? Just add paragraphs
+ for (Map.Entry<Integer, String> entry :
text.getParagraphs().entrySet()) {
+ String paragraph = entry.getValue();
+ // WebView can't load external images, so we need to strip them
or it
+ // may not render.
+ paragraph = paragraph.replaceAll("<img .*/>", "");
+ sb.append("<p>").append(paragraph).append("</p>");
+ }
}

textHtml = String.format(HTML_FORMAT, sb.toString());
- // WebView can't load external images, so we need to strip them or it
- // may not render.
- textHtml = textHtml.replaceAll("<img .*/>", "");

// Load any book parents
for (Story.Parent parent : story.getParents()) {
@@ -299,33 +368,9 @@
+ "</p>");
}

- if (story.getImages().size() > 0 && externalStorageAvailable) {
- String imageTag = String.format(
- "<div id=\"story-icon\"><img src=\"file://%s/%s\" /></div>",
- ImageThreadLoader.DiskCache.getCachePath(this),
- ImageThreadLoader.DiskCache.makeCacheFileName(
- story.getImages().get(0).getSrc()
- )
- );
- Log.d(LOG_TAG, "Adding tag for image " + imageTag);
- textHtml = imageTag + textHtml;
- }
-
- textView.loadDataWithBaseURL(null, textHtml, "text/html", "utf-8",
null);
-
- StoryClickListener listener = new StoryClickListener(position);
-
- listenNow.setOnClickListener(listener);
- enqueue.setOnClickListener(listener);
- share.setOnClickListener(listener);
- boolean isListenable = story.getPlayableUrl() != null;
- listenNow.setVisibility(isListenable ? View.VISIBLE : View.INVISIBLE);
- listenNow.setEnabled(isListenable);
- enqueue.setVisibility(isListenable ? View.VISIBLE : View.INVISIBLE);
- enqueue.setEnabled(isListenable &&
- playlistRepository.getPlaylistItemFromStoryId(story.getId()) ==
null);
- }
-
+ storyWebView.loadDataWithBaseURL(null, textHtml, "text/html", "utf-8",
null);
+ }
+
private void playStory(boolean playNow, int position) {
if (position >= stories.size() || position == -1) {
Log.e(LOG_TAG, "Attempt to get story audio for position " + position
+
@@ -453,13 +498,13 @@
if (story == null) {
Log.e(LOG_TAG, "Story at position " + position + " is
null?");
} else {
- String shortlink = story.getShortLink();
- if (shortlink == null) {
- shortlink = "http://npr.org/" + story.getId();
+ String shortLink = story.getShortLink();
+ if (shortLink == null) {
+ shortLink = "http://npr.org/" + story.getId();
}
Intent shareIntent = new
Intent(android.content.Intent.ACTION_SEND);
shareIntent.putExtra(Intent.EXTRA_SUBJECT, story.getTitle());
- shareIntent.putExtra(Intent.EXTRA_TEXT, shortlink);
+ shareIntent.putExtra(Intent.EXTRA_TEXT, shortLink);
shareIntent.setType("text/plain");
startActivity(Intent.createChooser(shareIntent,
getString(R.string.msg_share_story)));
@@ -497,6 +542,7 @@
playable = bundle.getParcelable(Playable.PLAYABLE_TYPE);
} catch (PackageManager.NameNotFoundException e)
{
+ Log.e(LOG_TAG, "Unable to parse playing item information", e);
}
if (playable != null) {
playlistId = playable.getId();
@@ -515,4 +561,45 @@
}
}
}
-}
+
+ private class ImageLoadListener implements
ImageThreadLoader.ImageLoadedListener {
+
+ int position;
+
+ public ImageLoadListener(int position) {
+ this.position = position;
+ }
+
+ public void imageLoaded(Drawable imageBitmap) {
+ boolean teaserOnly =
getIntent().getBooleanExtra(Constants.EXTRA_TEASER_ONLY, false);
+ loadStory(
+ stories.get(position),
+ position,
+ stories.size(),
+ workspace.getChildAt(position),
+ teaserOnly);
+ }
+ }
+
+ final class ImageClickInterface {
+
+ private Context context;
+
+ public ImageClickInterface(Context context) {
+ this.context = context;
+ }
+
+ @SuppressWarnings("unused")
+ public void clickOnImage(final String url, final String caption, final
String provider) {
+ Log.v("Image click url: ", url + ", " + caption + ", " + provider);
+
+ if (url != null && url.length() > 0) {
+ Intent intent = new Intent(context, NewsImageActivity.class);
+ intent.putExtra(NewsImageActivity.EXTRA_IMAGE_URL, url);
+ intent.putExtra(NewsImageActivity.EXTRA_IMAGE_CAPTION, caption);
+ intent.putExtra(NewsImageActivity.EXTRA_IMAGE_PROVIDER, provider);
+ startActivityWithoutAnimation(intent);
+ }
+ }
+ }
+}
=======================================
--- /Npr/src/org/npr/android/news/PlaybackService.java Mon Apr 30 18:44:34
2012
+++ /Npr/src/org/npr/android/news/PlaybackService.java Wed Jul 18 11:24:15
2012
@@ -19,12 +19,10 @@
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
-import java.net.ConnectException;
-import java.net.URL;
-import java.net.URLConnection;
-import java.net.UnknownHostException;
+import java.net.*;
import java.util.List;

+import android.os.*;
import org.npr.android.util.AudioManagerProxy;
import org.npr.android.util.M3uParser;
import org.npr.android.util.PlaylistParser;
@@ -45,13 +43,6 @@
import android.media.MediaPlayer.OnInfoListener;
import android.media.MediaPlayer.OnPreparedListener;
import android.media.MediaPlayer.OnSeekCompleteListener;
-import android.os.Build;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.IBinder;
-import android.os.Looper;
-import android.os.Message;
-import android.os.SystemClock;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.util.Log;
@@ -99,7 +90,7 @@

public static final String EXTRA_ERROR = SERVICE_PREFIX + "ERROR";

- public static enum PLAYBACK_SERVICE_ERROR {Connection, Playback}
+ public static enum PLAYBACK_SERVICE_ERROR {Connection, Playback,
InvalidPlayable}

private MediaPlayer mediaPlayer;
private boolean isPrepared = false;
@@ -300,6 +291,14 @@
connectionErrorWaitTime = startingWaitTime;
while (errorCount < ERROR_RETRY_COUNT) {
try {
+ if (currentPlayable == null || currentPlayable.getUrl() == null) {
+ Intent intent = new Intent(SERVICE_ERROR_NAME);
+ intent.putExtra(EXTRA_ERROR,
PLAYBACK_SERVICE_ERROR.InvalidPlayable.ordinal());
+ getApplicationContext().sendBroadcast(intent);
+
+ return false;
+ }
+
prepareThenPlay(currentPlayable.getUrl(),
currentPlayable.isStream());
return true;
} catch (UnknownHostException e) {
@@ -400,12 +399,8 @@
stop();

if (isPlaylist(url)) {
- downloadPlaylist(url);
- if (playlistUrls.size() > 0) {
- url = playlistUrls.remove(0);
- } else {
- throw new IOException("Empty playlist downloaded");
- }
+ new downloadPlaylist().execute(url);
+ return;
}

Log.d(LOG_TAG, "listening to " + url + " stream=" + stream);
@@ -813,36 +808,57 @@
return url.contains("m3u") || url.contains("pls");
}

- private boolean downloadPlaylist(String url) throws IOException {
- Log.d(LOG_TAG, "downloading " + url);
- URLConnection cn = new URL(url).openConnection();
- cn.connect();
- InputStream stream = cn.getInputStream();
- if (stream == null) {
- Log.e(LOG_TAG, "Unable to create InputStream for url: + url");
- return false;
- }
-
- File downloadingMediaFile = new File(getCacheDir(), "playlist_data");
- FileOutputStream out = new FileOutputStream(downloadingMediaFile);
- byte buf[] = new byte[16384];
- int bytesRead;
- while ((bytesRead = stream.read(buf)) > 0) {
- out.write(buf, 0, bytesRead);
+ private class downloadPlaylist extends AsyncTask<String, Void, Boolean> {
+ protected Boolean doInBackground(String... urls) {
+ Log.d(LOG_TAG, "downloading " + urls[0]);
+ try {
+ URLConnection cn = new URL(urls[0]).openConnection();
+ cn.connect();
+ InputStream stream = cn.getInputStream();
+ if (stream == null) {
+ Log.e(LOG_TAG, "Unable to create InputStream for url: + url");
+ return false;
+ }
+
+ File downloadingMediaFile = new
File(getCacheDir(), "playlist_data");
+ FileOutputStream out = new FileOutputStream(downloadingMediaFile);
+ byte buf[] = new byte[16384];
+ int bytesRead;
+ while ((bytesRead = stream.read(buf)) > 0) {
+ out.write(buf, 0, bytesRead);
+ }
+
+ stream.close();
+ out.close();
+ PlaylistParser parser;
+ if (urls[0].contains("m3u")) {
+ parser = new M3uParser(downloadingMediaFile);
+ } else if (urls[0].contains("pls")) {
+ parser = new PlsParser(downloadingMediaFile);
+ } else {
+ return false;
+ }
+ playlistUrls = parser.getUrls();
+ } catch (IOException e) {
+ Log.e(LOG_TAG, "Unable to download playlist from url" + urls[0]);
+ return false;
+ }
+ return true;
}

- stream.close();
- out.close();
- PlaylistParser parser;
- if (url.contains("m3u")) {
- parser = new M3uParser(downloadingMediaFile);
- } else if (url.contains("pls")) {
- parser = new PlsParser(downloadingMediaFile);
- } else {
- return false;
- }
- playlistUrls = parser.getUrls();
- return true;
- }
-
-}
+ protected void onPostExecute(Boolean result) {
+ if (result && playlistUrls != null && playlistUrls.size() > 0) {
+ try {
+ prepareThenPlay(playlistUrls.remove(0),
currentPlayable.isStream());
+ } catch (IOException e) {
+ Log.e(LOG_TAG, "IOException on playlist entry " +
currentPlayable.getId(), e);
+ incrementErrorCount();
+ playCurrent(errorCount, connectionErrorWaitTime);
+ }
+ } else {
+ incrementErrorCount();
+ playCurrent(errorCount, connectionErrorWaitTime);
+ }
+ }
+ }
+}
=======================================
--- /Npr/src/org/npr/android/news/PlaylistView.java Tue Jul 17 16:02:43 2012
+++ /Npr/src/org/npr/android/news/PlaylistView.java Wed Jul 18 11:24:15 2012
@@ -498,16 +498,19 @@

playPauseButton.setImageResource(R.drawable.pause_button_normal);

playPauseButton.setContentDescription(getResources().getString(R.string.acd_pause_button));

contractedPlayButton.setImageResource(R.drawable.pause_button_normal);
+
contractedPlayButton.setContentDescription(getResources().getString(R.string.acd_pause_button));
} else {

playPauseButton.setImageResource(R.drawable.stop_button_normal);

playPauseButton.setContentDescription(getResources().getString(R.string.acd_stop_button));

contractedPlayButton.setImageResource(R.drawable.stop_button_normal);
+
contractedPlayButton.setContentDescription(getResources().getString(R.string.acd_stop_button));
}
playPauseShowsPlay = false;
} else {
playPauseButton.setImageResource(R.drawable.play_button_normal);

playPauseButton.setContentDescription(getResources().getString(R.string.acd_play_button));
-
contractedPlayButton.setImageResource(R.drawable.play_button_normal);
+
contractedPlayButton.setImageResource(R.drawable.play_button_normal);
+
contractedPlayButton.setContentDescription(getResources().getString(R.string.acd_play_button));
playPauseShowsPlay = true;
}
}
@@ -534,6 +537,9 @@
message = context.getString(R.string.msg_playback_error);
} else if (error ==
PlaybackService.PLAYBACK_SERVICE_ERROR.Connection.ordinal()) {
message =
context.getString(R.string.msg_playback_connection_error);
+ } else if (error ==
PlaybackService.PLAYBACK_SERVICE_ERROR.InvalidPlayable.ordinal()) {
+ message =
context.getString(R.string.msg_playback_invalid_playable_error);
+ clearPlayer();
}
Toast.makeText(context, message, Toast.LENGTH_LONG).show();
}
=======================================
--- /Npr/src/org/npr/android/news/ProgramStoryListActivity.java Wed Apr 25
17:02:51 2012
+++ /Npr/src/org/npr/android/news/ProgramStoryListActivity.java Wed Jul 18
11:24:15 2012
@@ -76,6 +76,7 @@
private NewsListAdapter.StoriesLoadedListener listener = new
NewsListAdapter.StoriesLoadedListener() {
@Override
public void storiesLoaded() {
+ stopIndeterminateProgressIndicator();
if (loadAll) {
loadAll = false;
PlaylistRepository playlistRepository =
=======================================
--- /Npr/src/org/npr/android/news/RootActivity.java Mon Apr 30 18:44:34 2012
+++ /Npr/src/org/npr/android/news/RootActivity.java Wed Jul 18 11:24:15 2012
@@ -18,6 +18,7 @@
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

+import android.view.*;
import org.npr.android.util.PlaylistEntry;
import org.npr.android.util.PlaylistRepository;
import org.npr.api.ApiConstants;
@@ -33,15 +34,10 @@
import android.os.Bundle;
import android.text.method.LinkMovementMethod;
import android.util.Log;
-import android.view.ContextMenu;
-import android.view.KeyEvent;
-import android.view.MenuInflater;
-import android.view.MenuItem;
-import android.view.View;
import android.view.View.OnClickListener;
-import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
-import android.view.Window;
+
+// import com.crittercism.app.Crittercism;
import android.widget.AdapterView;
import android.widget.ImageButton;
import android.widget.ProgressBar;
@@ -218,7 +214,6 @@
* @param playable A Playable stream or podcast to play.
*/
protected void playSingleNow(Playable playable) {
- startIndeterminateProgressIndicator();

if (updateReceiver != null) {
unregisterReceiver(updateReceiver);
@@ -244,6 +239,14 @@
}
}
}
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ showHideNavigationMenu();
+ // We're showing our own menu, so return false to keep the system one
+ // from being displayed
+ return false;
+ }

@Override
public void onCreateContextMenu(ContextMenu menu, View view,
=======================================
--- /Npr/src/org/npr/android/util/PlaylistRepository.java Wed Apr 25
17:02:51 2012
+++ /Npr/src/org/npr/android/util/PlaylistRepository.java Wed Jul 18
11:24:15 2012
@@ -211,7 +211,7 @@
String selection = PlaylistProvider.Items.PLAY_ORDER + " > ?";
String[] selectionArgs = new String[1];
selectionArgs[0] = Integer.toString(entry.playOrder);
- //String sort = PlaylistProvider.Items.PLAY_ORDER + " asc";
+ String sort = PlaylistProvider.Items.PLAY_ORDER + " asc";
PlaylistEntry playlistEntry = retrievePlaylistItem(selection,
selectionArgs, null);
if (playlistEntry == null) {
=======================================
--- /Npr/src/org/npr/android/util/Tracker.java Wed Apr 25 17:02:51 2012
+++ /Npr/src/org/npr/android/util/Tracker.java Wed Jul 18 11:24:15 2012
@@ -37,7 +37,7 @@

// Start the tracker in manual dispatch mode.
// Remember to dispatch() after every trackPageView
- gaTracker.start("UA-5828686-6", application);
+ gaTracker.startNewSession("UA-5828686-6", application);
gaTracker.trackPageView("/version%20" + getVersionName());
Log.d(LOG_TAG, "Tracking version " + getVersionName());
gaTracker.dispatch();
@@ -48,7 +48,7 @@

public void finish() {
if (gaTracker != null) {
- gaTracker.stop();
+ gaTracker.stopSession();
}
}

=======================================
--- /Npr/src/org/npr/api/ApiConstants.java Fri Jan 6 11:10:49 2012
+++ /Npr/src/org/npr/api/ApiConstants.java Wed Jul 18 11:24:15 2012
@@ -49,7 +49,8 @@
public static final String PARAM_REQUIRED_ASSETS = "requiredAssets";
public static final String PARAM_RANDOMIZE_STATIONS = "randomize";

- public static final String STORY_FIELDS
= "titles,teasers,storyDate,byline,text,audio,textWithHtml,image,organization,parent";
+ public static final String STORY_FIELDS
+
= "titles,teasers,storyDate,byline,audio,textWithHtml,image,organization,parent,layout";
private final String apiKey;
private static ApiConstants instance;

=======================================
--- /Npr/src/org/npr/api/Story.java Wed Apr 25 17:02:51 2012
+++ /Npr/src/org/npr/api/Story.java Wed Jul 18 11:24:15 2012
@@ -32,7 +32,6 @@
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
-import java.util.Map.Entry;
import java.util.SortedMap;
import java.util.TreeMap;

@@ -57,12 +56,13 @@
private final List<Toenail> toenails;
private final List<Organization> organizations;
private final List<Audio> audios;
- private final List<Image> images;
+ private final Map<String, Image> images;
private final List<RelatedLink> relatedLinks;
private final List<PullQuote> pullQuotes;
private final Text text;
private final TextWithHtml textWithHtml;
private final List<Parent> parents;
+ private final Layout layout;

public static class Thumbnail {
private final String medium;
@@ -104,6 +104,7 @@
return name;
}

+ @SuppressWarnings("unused")
public String getWebsite() {
return website;
}
@@ -131,10 +132,12 @@
return mp3;
}

+ @SuppressWarnings("unused")
public String getWm() {
return wm;
}

+ @SuppressWarnings("unused")
public String getRm() {
return rm;
}
@@ -167,30 +170,29 @@
public static class Image {
@SuppressWarnings("unused")
private final String id;
- @SuppressWarnings("unused")
private final String type;
@SuppressWarnings("unused")
private final String width;
private final String src;
@SuppressWarnings("unused")
private final String hasBorder;
+ private final String caption;
@SuppressWarnings("unused")
private final String linkUrl;
- @SuppressWarnings("unused")
private final String producer;
- @SuppressWarnings("unused")
private final String provider;
@SuppressWarnings("unused")
private final String copyright;

- public Image(String id, String type, String width, String src,
- String hasBorder, String linkUrl, String producer, String
provider,
+ public Image(String id, String type, String width, String src, String
hasBorder,
+ String caption, String linkUrl, String producer, String
provider,
String copyright) {
this.id = id;
this.type = type;
this.width = width;
this.src = src;
this.hasBorder = hasBorder;
+ this.caption = caption;
this.linkUrl = linkUrl;
this.producer = producer;
this.provider = provider;
@@ -200,6 +202,27 @@
public String getSrc() {
return src;
}
+
+ public String getCaption() {
+ return caption;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public String getAttribution() {
+ if (producer != null && producer.length() > 0) {
+ if (provider != null && provider.length() > 0) {
+ return producer + "/" + provider;
+ } else {
+ return producer;
+ }
+ } else if (provider != null && provider.length() > 0) {
+ return provider;
+ }
+ return "";
+ }
}

public static class RelatedLink {
@@ -233,25 +256,26 @@
}

public static class Text {
- private final List<String> paragraphs;
-
- public Text(List<String> paragraphs) {
+ private final Map<Integer, String> paragraphs;
+
+ public Text(Map<Integer, String> paragraphs) {
this.paragraphs = paragraphs;
}

- public List<String> getParagraphs() {
+ @SuppressWarnings("unused")
+ public Map<Integer, String> getParagraphs() {
return paragraphs;
}
}

public static class TextWithHtml {
- private final List<String> paragraphs;
-
- public TextWithHtml(List<String> paragraphs) {
+ private final Map<Integer, String> paragraphs;
+
+ public TextWithHtml(Map<Integer, String> paragraphs) {
this.paragraphs = paragraphs;
}

- public List<String> getParagraphs() {
+ public Map<Integer, String> getParagraphs() {
return paragraphs;
}
}
@@ -271,10 +295,12 @@
return name;
}

+ @SuppressWarnings("unused")
public String getHtmlLink() {
return htmlLink;
}

+ @SuppressWarnings("unused")
public String getApiLink() {
return apiLink;
}
@@ -319,16 +345,49 @@
return apiLink;
}
}
-
- public Story(String id, String link, String shortLink, String title,
- String subtitle,
+
+ public static class Layout {
+
+ public enum Type {text, image}
+
+ private final SortedMap<Integer, LayoutItem> items;
+
+ public Layout(SortedMap<Integer, LayoutItem> items) {
+ this.items = items;
+ }
+
+ public SortedMap<Integer, Layout.LayoutItem> getItems() {
+ return items;
+ }
+
+ public static class LayoutItem {
+
+ private final Type type;
+ private final String itemId;
+
+ public LayoutItem(Type type, String itemId) {
+ this.type = type;
+ this.itemId = itemId;
+ }
+
+ public Type getType() {
+ return type;
+ }
+
+ public String getItemId() {
+ return itemId;
+ }
+ }
+ }
+
+ public Story(String id, String link, String shortLink, String title,
String subtitle,
String shortTitle, String teaser, String miniTeaser, String
slug,
- String storyDate, String pubDate, String lastModifiedDate,
- String keywords, String priorityKeywords, List<Byline>
bylines,
- List<Thumbnail> thumbnails, List<Toenail> toenails,
- List<Organization> organizations, List<Audio> audios,
List<Image> images,
- List<RelatedLink> relatedLinks, List<PullQuote> pullQuotes,
Text text,
- TextWithHtml textWithHtml, List<Parent> parents) {
+ String storyDate, String pubDate, String lastModifiedDate,
String keywords,
+ String priorityKeywords, List<Byline> bylines,
List<Thumbnail> thumbnails,
+ List<Toenail> toenails, List<Organization> organizations,
List<Audio> audios,
+ Map<String, Image> images, List<RelatedLink> relatedLinks,
+ List<PullQuote> pullQuotes, Text text, TextWithHtml
textWithHtml,
+ List<Parent> parents, Layout layout) {
super(id);
this.link = link;
this.shortLink = shortLink;
@@ -354,8 +413,10 @@
this.text = text;
this.textWithHtml = textWithHtml;
this.parents = parents;
+ this.layout = layout;
}

+ @SuppressWarnings("unused")
public String getLink() {
return link;
}
@@ -368,10 +429,12 @@
return title;
}

+ @SuppressWarnings("unused")
public String getSubtitle() {
return subtitle;
}

+ @SuppressWarnings("unused")
public String getShortTitle() {
return shortTitle;
}
@@ -380,6 +443,7 @@
return teaser;
}

+ @SuppressWarnings("unused")
public String getMiniTeaser() {
return miniTeaser;
}
@@ -401,18 +465,22 @@
return storyDate == null ? pubDate : storyDate;
}

+ @SuppressWarnings("unused")
public String getPubDate() {
return pubDate;
}

+ @SuppressWarnings("unused")
public String getLastModifiedDate() {
return lastModifiedDate;
}

+ @SuppressWarnings("unused")
public String getKeywords() {
return keywords;
}

+ @SuppressWarnings("unused")
public String getPriorityKeywords() {
return priorityKeywords;
}
@@ -425,6 +493,7 @@
return thumbnails;
}

+ @SuppressWarnings("unused")
public List<Toenail> getToenails() {
return toenails;
}
@@ -437,14 +506,16 @@
return audios;
}

- public List<Image> getImages() {
+ public Map<String, Image> getImages() {
return images;
}

+ @SuppressWarnings("unused")
public List<RelatedLink> getRelatedLinks() {
return relatedLinks;
}

+ @SuppressWarnings("unused")
public List<PullQuote> getPullQuotes() {
return pullQuotes;
}
@@ -465,6 +536,10 @@
public List<Parent> getParents() {
return parents;
}
+
+ public Layout getLayout() {
+ return layout;
+ }

public static class StoryBuilder {
private final String id;
@@ -481,17 +556,18 @@
private String lastModifiedDate;
private String keywords;
private String priorityKeywords;
- private final List<Byline> bylines = new LinkedList<Byline>();
- private final List<Thumbnail> thumbnails = new LinkedList<Thumbnail>();
- private final List<Toenail> toenails = new LinkedList<Toenail>();
- private final List<Organization> organizations = new
LinkedList<Organization>();
- private final List<Audio> audios = new LinkedList<Audio>();
- private final List<Image> images = new LinkedList<Image>();
- private final List<RelatedLink> relatedLinks = new
LinkedList<RelatedLink>();
- private final List<PullQuote> pullQuotes = new LinkedList<PullQuote>();
+ private final List<Byline> bylines = new ArrayList<Byline>();
+ private final List<Thumbnail> thumbnails = new ArrayList<Thumbnail>();
+ private final List<Toenail> toenails = new ArrayList<Toenail>();
+ private final List<Organization> organizations = new
ArrayList<Organization>();
+ private final List<Audio> audios = new ArrayList<Audio>();
+ private final Map<String, Image> images = new HashMap<String, Image>();
+ private final List<RelatedLink> relatedLinks = new
ArrayList<RelatedLink>();
+ private final List<PullQuote> pullQuotes = new ArrayList<PullQuote>();
private Text text;
private TextWithHtml textWithHtml;
- private final List<Parent> parents = new LinkedList<Parent>();
+ private final List<Parent> parents = new ArrayList<Parent>();
+ private Layout layout;

public StoryBuilder(String id) {
this.id = id;
@@ -512,11 +588,13 @@
return this;
}

+ @SuppressWarnings("unused")
public StoryBuilder withSubtitle(String subtitle) {
this.subtitle = subtitle;
return this;
}

+ @SuppressWarnings("unused")
public StoryBuilder withShortTitle(String shortTitle) {
this.shortTitle = shortTitle;
return this;
@@ -547,16 +625,19 @@
return this;
}

+ @SuppressWarnings("unused")
public StoryBuilder withLastModifiedDate(String lastModifiedDate) {
this.lastModifiedDate = lastModifiedDate;
return this;
}

+ @SuppressWarnings("unused")
public StoryBuilder withKeywords(String keywords) {
this.keywords = keywords;
return this;
}

+ @SuppressWarnings("unused")
public StoryBuilder withPriorityKeywords(String priorityKeywords) {
this.priorityKeywords = priorityKeywords;
return this;
@@ -567,11 +648,13 @@
return this;
}

+ @SuppressWarnings("unused")
public StoryBuilder withThumbnail(Thumbnail thumbnail) {
this.thumbnails.add(thumbnail);
return this;
}

+ @SuppressWarnings("unused")
public StoryBuilder withToenail(Toenail toenail) {
this.toenails.add(toenail);
return this;
@@ -587,16 +670,18 @@
return this;
}

- public StoryBuilder withImage(Image image) {
- this.images.add(image);
+ public StoryBuilder withImage(String id, Image image) {
+ this.images.put(id, image);
return this;
}

+ @SuppressWarnings("unused")
public StoryBuilder withRelatedLink(RelatedLink relatedLink) {
this.relatedLinks.add(relatedLink);
return this;
}

+ @SuppressWarnings("unused")
public StoryBuilder withPullQuote(PullQuote pullQuote) {
this.pullQuotes.add(pullQuote);
return this;
@@ -616,16 +701,19 @@
this.parents.add(parent);
return this;
}
+
+ public StoryBuilder withLayout(Layout layout) {
+ this.layout = layout;
+ return this;
+ }

public Story build() {
return new Story(id, link, shortLink, title, subtitle, shortTitle,
- teaser,
- miniTeaser, slug, storyDate, pubDate, lastModifiedDate, keywords,
- priorityKeywords, bylines, thumbnails, toenails, organizations,
- audios, images, relatedLinks, pullQuotes, text, textWithHtml,
- parents);
- }
-
+ teaser, miniTeaser, slug, storyDate, pubDate, lastModifiedDate,
+ keywords, priorityKeywords, bylines, thumbnails, toenails,
+ organizations, audios, images, relatedLinks, pullQuotes, text,
+ textWithHtml, parents, layout);
+ }
}

public static class StoryFactory {
@@ -747,11 +835,14 @@
} else if (nodeName.equals("audio")) {
sb.withAudio(parseAudio(n));
} else if (nodeName.equals("image")) {
- sb.withImage(parseImage(n));
+ Image image = parseImage(n);
+ sb.withImage(image.id, image);
} else if (nodeName.equals("organization")) {
sb.withOrganization(parseOrganization(n));
} else if (nodeName.equals("parent")) {
sb.withParent(parseParent(n));
+ } else if (nodeName.equals("layout")) {
+ sb.withLayout(new Layout(parseLayout(n)));
}
}
} catch (Exception e) {
@@ -760,7 +851,59 @@
}
return sb.build();
}
-
+
+ private static SortedMap<Integer, Layout.LayoutItem> parseLayout(Node
node) {
+
+ SortedMap<Integer, Layout.LayoutItem> layout = new TreeMap<Integer,
Layout.LayoutItem>();
+
+ for (Node layoutChild : new IterableNodeList(node.getChildNodes())) {
+ if (layoutChild.getNodeName().equals("storytext")) {
+ for (Node layoutNode : new
IterableNodeList(layoutChild.getChildNodes())) {
+ String layoutType = layoutNode.getNodeName();
+ if (layoutType.equals("text")) {
+ Integer num = layout.size();
+ Attr numAttr = (Attr)
layoutNode.getAttributes().getNamedItem("num");
+ if (numAttr != null) {
+ try {
+ num = Integer.parseInt(numAttr.getValue());
+ } catch (NumberFormatException e) {
+ // Leave as the last item if parse fails
+ }
+ }
+ String paragraphNum;
+ Attr paragraphNumAttr =
+ (Attr)
layoutNode.getAttributes().getNamedItem("paragraphNum");
+ if (paragraphNumAttr != null) {
+ paragraphNum = paragraphNumAttr.getValue();
+ } else {
+ paragraphNum = num.toString();
+ }
+ Layout.LayoutItem item =
+ new Layout.LayoutItem(Layout.Type.text, paragraphNum);
+ layout.put(num, item);
+ } else if (layoutType.equals("image")) {
+ Integer num = layout.size();
+ Attr numAttr = (Attr)
layoutNode.getAttributes().getNamedItem("num");
+ if (numAttr != null) {
+ try {
+ num = Integer.parseInt(numAttr.getValue());
+ } catch (NumberFormatException e) {
+ // Leave as the last item if parse fails
+ }
+ }
+ Attr refIdAttr = (Attr)
layoutNode.getAttributes().getNamedItem("refId");
+ if (refIdAttr != null) {
+ Layout.LayoutItem item =
+ new Layout.LayoutItem(Layout.Type.image,
refIdAttr.getValue());
+ layout.put(num, item);
+ }
+ }
+ }
+ }
+ }
+ return layout;
+ }
+
private static Parent parseParent(Node node) {
String id = null, type = null, title = null, apiLink = null;
boolean isPrimary = false;
@@ -832,22 +975,32 @@
// Attributes
String id = null, type = null, width = null, src = null, hasBorder =
null;
// Sub-elements
- String linkUrl = null, producer = null, provider = null, copyright =
null;
+ String caption = null, linkUrl = null, producer = null, provider =
null, copyright = null;
Attr idAttr = (Attr) node.getAttributes().getNamedItem("id");
if (idAttr != null) {
id = idAttr.getValue();
}
+ Attr typeAttr = (Attr) node.getAttributes().getNamedItem("type");
+ if (typeAttr != null) {
+ type = typeAttr.getValue();
+ }

for (Node n : new IterableNodeList(node.getChildNodes())) {
if (n.getNodeName().equals("crop")) {
- Attr typeAttr = (Attr) n.getAttributes().getNamedItem("type");
- if (typeAttr != null && typeAttr.getValue().equals("square")) {
+ Attr cropTypeAttr = (Attr)
n.getAttributes().getNamedItem("type");
+ if (cropTypeAttr != null &&
cropTypeAttr.getValue().equals("square")) {
Attr srcAttr = (Attr) n.getAttributes().getNamedItem("src");
if (srcAttr != null) {
src = srcAttr.getValue();
break;
}
}
+ } else if (n.getNodeName().equals("caption")) {
+ caption = NodeUtils.getTextContent(n);
+ } else if (n.getNodeName().equals("producer")) {
+ producer = NodeUtils.getTextContent(n);
+ } else if (n.getNodeName().equals("provider")) {
+ provider = NodeUtils.getTextContent(n);
}
}

@@ -865,12 +1018,11 @@
Log.e(LOG_TAG, "Error replacing size in story image parsing");
}

- return new Image(id, type, width, src, hasBorder, linkUrl, producer,
+ return new Image(id, type, width, src, hasBorder, caption, linkUrl,
producer,
provider, copyright);
}

- private static List<String> parseParagraphs(Node node) {
- List<String> paragraphs = new LinkedList<String>();
+ private static Map<Integer, String> parseParagraphs(Node node) {
// Presumably, the paragraphs will be in order. However, in the rare
case
// that they are not, we can order them according to the number
attribute.
SortedMap<Integer, String> paragraphMap = new TreeMap<Integer,
String>();
@@ -886,10 +1038,7 @@
}
}
}
- for (Entry<Integer, String> e : paragraphMap.entrySet()) {
- paragraphs.add(e.getValue());
- }
- return paragraphs;
+ return paragraphMap;
}

private static Audio parseAudio(Node node) {
=======================================
--- /Npr_Test/Npr_Test.iml Tue Jul 17 16:02:43 2012
+++ /Npr_Test/Npr_Test.iml Wed Jul 18 11:24:15 2012
@@ -34,9 +34,9 @@
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/gen" isTestSource="false" />
</content>
- <orderEntry type="jdk" jdkName="Android 2.2 Platform" jdkType="Android
SDK" />
+ <orderEntry type="jdk" jdkName="Android 2.1 Platform" jdkType="Android
SDK" />
<orderEntry type="sourceFolder" forTests="false" />
- <orderEntry type="module" module-name="Npr" />
+ <orderEntry type="module" module-name="Npr" scope="PROVIDED" />
</component>
</module>

Reply all
Reply to author
Forward
0 new messages