/* * Copyright 2010 John R. Hicks * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.determinato.feeddroid.activity; import java.io.IOException; import android.app.Activity; import android.app.AlertDialog; import android.content.ContentResolver; import android.content.ContentUris; import android.content.ContentValues; import android.content.Context; import android.content.Intent; import android.database.Cursor; import android.graphics.Color; import android.media.MediaPlayer; import android.net.Uri; import android.os.Bundle; import android.text.TextUtils; import android.view.KeyEvent; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.View.OnClickListener; import android.webkit.WebView; import android.widget.Button; import android.widget.ImageButton; import android.widget.TextView; import android.widget.Toast; import com.determinato.feeddroid.R; import com.determinato.feeddroid.ads.FeedDroidAdConstants; import com.determinato.feeddroid.ads.FeedDroidAdSenseSpec; import com.determinato.feeddroid.provider.FeedDroid; import com.determinato.feeddroid.util.KeyUtils; import com.determinato.feeddroid.view.ChannelHeader; import com.google.ads.AdSenseSpec; import com.google.ads.GoogleAdView; import com.google.ads.AdSenseSpec.AdType; import com.google.ads.AdSenseSpec.ExpandDirection; /** * Activity to view a RSS post. * * @author John R. Hicks <john@determinato.com> * */ public class PostViewActivity extends Activity { private static final String TAG = "PostView"; private static final int NEXT_POST_ID = Menu.FIRST; private static final int PREV_POST_ID = Menu.FIRST + 1; private static final String[] PROJECTION = new String[] { FeedDroid.Posts._ID, FeedDroid.Posts.CHANNEL_ID, FeedDroid.Posts.TITLE, FeedDroid.Posts.BODY, FeedDroid.Posts.READ, FeedDroid.Posts.URL, FeedDroid.Posts.STARRED, FeedDroid.Posts.PODCAST_URL, FeedDroid.Posts.PODCAST_MIME_TYPE}; private long mChannelId = -1; private long mPostId = -1; private Cursor mCursor; private Context mContext; private long mPrevPostId = -1; private long mNextPostId = -1; private TextView mTxtStarred; private ContentResolver mResolver; private ImageButton mStarred; /** * {@inheritDoc} * */ @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.post_view); mContext = this; Uri uri = getIntent().getData(); String postId = uri.getPathSegments().get(1); mResolver = getContentResolver(); mCursor = mResolver.query(uri, PROJECTION, "_id=" + postId, null, "posted_on desc"); if (mCursor.getCount() == 0) { Toast.makeText(this, "Unable to locate post", Toast.LENGTH_LONG).show(); finish(); } mCursor.moveToFirst(); mTxtStarred = (TextView) findViewById(R.id.txt_starred); mStarred = (ImageButton) findViewById(R.id.star_post); mStarred.setBackgroundColor(Color.TRANSPARENT); mStarred.setOnClickListener(btn_listener); int starred = mCursor.getInt(mCursor.getColumnIndex(FeedDroid.Posts.STARRED)); if (starred == 1) { mTxtStarred.setText(R.string.starred); mStarred.setImageResource(android.R.drawable.star_on); } else { mTxtStarred.setText(R.string.star_this); mStarred.setImageResource(android.R.drawable.star_off); } mChannelId = mCursor.getLong(mCursor.getColumnIndex(FeedDroid.Posts.CHANNEL_ID)); mPostId = Long.parseLong(uri.getPathSegments().get(1)); initWithData(); // Set up ads AdSenseSpec spec = new FeedDroidAdSenseSpec(FeedDroidAdConstants.CLIENT_ID) .setCompanyName(FeedDroidAdConstants.COMPANY_NAME) .setAppName(getString(R.string.app_name)) .setChannel(FeedDroidAdConstants.CHANNEL_ID) .setAdType(AdType.TEXT_IMAGE) .setExpandDirection(ExpandDirection.TOP) .setAdTestEnabled(FeedDroidAdConstants.AD_TEST_ENABLED); GoogleAdView adView = (GoogleAdView) findViewById(R.id.adview); adView.showAds(spec); } /** * Listener for starred button. */ OnClickListener btn_listener = new OnClickListener() { public void onClick(View v) { Uri uri = getIntent().getData(); Cursor c = mResolver.query(uri, PROJECTION, "_id=" + mPostId, null, null); c.moveToFirst(); int starred = c.getInt(c.getColumnIndex(FeedDroid.Posts.STARRED)); if (starred == 0) starred = 1; else starred = 0; ContentValues values = new ContentValues(); values.put("starred", starred); mResolver.update(uri, values, "_id=" + mPostId, null); if (starred == 0) { mTxtStarred.setText(R.string.star_this); mStarred.setImageResource(android.R.drawable.star_off); } else if (starred == 1){ mTxtStarred.setText(R.string.starred); mStarred.setImageResource(android.R.drawable.star_on); } } }; /** * {@inheritDoc} */ @Override public void onStart() { super.onStart(); if (mCursor == null || !mCursor.moveToFirst()) return; ContentResolver resolver = getContentResolver(); ContentValues values = new ContentValues(); values.put("read", 1); resolver.update(FeedDroid.Posts.CONTENT_URI, values, "_id=?", new String[] {Long.toString(mPostId)}); } /** * Initializes data for the view. */ public void initWithData() { ContentResolver resolver = getContentResolver(); Cursor cChannel = resolver.query(ContentUris.withAppendedId(FeedDroid.Channels.CONTENT_URI, mChannelId), new String[] { FeedDroid.Channels.ICON, FeedDroid.Channels.LOGO, FeedDroid.Channels.TITLE}, null, null, null); if (cChannel.getCount() != 1) return; cChannel.moveToFirst(); ChannelHeader head = (ChannelHeader) findViewById(R.id.postViewHead); head.setLogo(cChannel); cChannel.close(); TextView postTitle = (TextView) findViewById(R.id.postTitle); postTitle.setText(mCursor.getString(mCursor.getColumnIndex(FeedDroid.Posts.TITLE))); WebView postText = (WebView)findViewById(R.id.postText); String html = "<html><head><style type=\"text/css\">body { background-color: #003333; color: white; } a { color: #ddf; }</style></head><body>" + getBody() + "</body></html>"; postText.loadData(html, "text/html", "utf-8"); // Podcast support: If post contains a URL to a podcast, enable option to download // the podcast mp3 and play it in the Media Player. mCursor.requery(); mCursor.moveToFirst(); final String podcastUrl = mCursor.getString(mCursor.getColumnIndex(FeedDroid.Posts.PODCAST_URL)); final String podcastName = mCursor.getString(mCursor.getColumnIndex(FeedDroid.Posts.TITLE)); final String podcastMimeType = mCursor.getString(mCursor.getColumnIndex(FeedDroid.Posts.PODCAST_MIME_TYPE)); Button listenBtn = (Button) findViewById(R.id.btnListen); Button downloadBtn = (Button) findViewById(R.id.btnDownload); if (!TextUtils.isEmpty(podcastUrl)) { listenBtn.setEnabled(true); listenBtn.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { Intent player = new Intent(mContext, PodcastPlayerActivity.class); player.putExtra("url", podcastUrl); player.putExtra("name", podcastName); player.putExtra("type", podcastMimeType); startActivity(player); } }); } else { listenBtn.setVisibility(View.INVISIBLE); downloadBtn.setVisibility(View.INVISIBLE); } } /** * Gets body of post from the database and appends a "Read more..." link. * @return body of post */ private String getBody() { String body = mCursor.getString(mCursor.getColumnIndex(FeedDroid.Posts.BODY)); String url = mCursor.getString(mCursor.getColumnIndex(FeedDroid.Posts.URL)); if (body == null) body = ""; if (!hasMoreLink(body, url)) body += "<p><a href=\"" + url + "\">Read more...</a></p>"; return body; } /** * Determines if a post has a "Read More" link * @param body RSS post body * @param url RSS post URL * @return true if link exists, false otherwise */ private boolean hasMoreLink(String body, String url) { int urlPos; if ((body == null) || (urlPos = body.indexOf(url)) <= 0) return false; try { if (body.charAt(urlPos - 1) != '>') return false; if (body.charAt(urlPos + url.length() + 1) != '<') return false; } catch (IndexOutOfBoundsException e) { return false; } return true; } /** * Gets children. */ private void getSiblings() { if (mNextPostId < 0 || mPrevPostId < 0) { Cursor cPostList = getContentResolver().query(ContentUris.withAppendedId(FeedDroid.Posts.CONTENT_URI_LIST, mChannelId), new String[] {FeedDroid.Posts._ID}, null, null, null); cPostList.moveToFirst(); int indexId = cPostList.getColumnIndex(FeedDroid.Posts._ID); long lastId = -1; for (cPostList.moveToFirst(); cPostList.isLast(); cPostList.moveToNext()) { long thisId = cPostList.getLong(indexId); if (thisId == mPostId) break; lastId = thisId; } if (mNextPostId < 0) mNextPostId = lastId; if (mPrevPostId < 0) { if (!cPostList.isLast()) { cPostList.moveToNext(); mPrevPostId = cPostList.getLong(indexId); } } } } /* @Override public boolean onPrepareOptionsMenu(Menu menu) { menu.removeGroup(0); getSiblings(); MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.post_view_menu, menu); return true; } */ private void moveTo(long id) { Intent i = new Intent(Intent.ACTION_VIEW, ContentUris.withAppendedId(FeedDroid.Posts.CONTENT_URI, id)); startActivity(i); finish(); } private boolean prevPost() { if (mPrevPostId < 0) return false; moveTo(mPrevPostId); return true; } private boolean nextPost() { if (mNextPostId < 0) return false; moveTo(mNextPostId); return true; } /** * {@inheritDoc} */ @Override public boolean onOptionsItemSelected(MenuItem item) { switch(item.getItemId()) { case PREV_POST_ID: return prevPost(); case NEXT_POST_ID: return nextPost(); } return super.onOptionsItemSelected(item); } /** * {@inheritDoc} */ @Override public boolean onKeyUp(int keyCode, KeyEvent event) { switch(KeyUtils.intrepretDirection(keyCode)) { case KeyEvent.KEYCODE_DPAD_LEFT: getSiblings(); return nextPost(); case KeyEvent.KEYCODE_DPAD_RIGHT: getSiblings(); return prevPost(); } return false; } /** * {@inheritDoc} */ @Override public boolean onKeyDown(int keyCode, KeyEvent event) { switch(KeyUtils.intrepretDirection(keyCode)) { case KeyEvent.KEYCODE_BACK: finish(); } return false; } /** * {@inheritDoc} */ @Override protected void onDestroy() { mCursor.close(); super.onDestroy(); } }