package de.bsd.zwitscher;
import android.app.ActionBar;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.res.TypedArray;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.AsyncTask;
import android.preference.PreferenceManager;
import android.text.Html;
import android.text.method.LinkMovementMethod;
import android.view.*;
import android.widget.*;
import com.bugsense.trace.BugSenseHandler;
import de.bsd.zwitscher.account.Account;
import de.bsd.zwitscher.account.AccountHolder;
import de.bsd.zwitscher.helper.GetOneStatusTask;
import de.bsd.zwitscher.helper.NetworkHelper;
import de.bsd.zwitscher.helper.PicHelper;
import de.bsd.zwitscher.helper.UrlExtractHelper;
import de.bsd.zwitscher.helper.UrlPair;
import twitter4j.MediaEntity;
import twitter4j.Place;
import twitter4j.Status;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.speech.tts.TextToSpeech;
import android.speech.tts.TextToSpeech.OnInitListener;
import android.speech.tts.TextToSpeech.OnUtteranceCompletedListener;
import android.util.Log;
import twitter4j.URLEntity;
import twitter4j.User;
import twitter4j.UserMentionEntity;
import java.io.BufferedInputStream;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.net.URLEncoder;
import java.util.*;
import java.util.concurrent.ExecutionException;
/**
* This Activity displays one individual status.
* Layout definition is in res/layout/single_tweet
*
* @author Heiko W. Rupp
*/
public class OneTweetActivity extends Activity implements OnInitListener, OnUtteranceCompletedListener {
private Status status ;
private ImageView userPictureView;
private ProgressBar pg;
private boolean downloadPictures=false;
private TextToSpeech tts;
private TextView titleTextView;
private Account account;
int screenWidth;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.single_tweet);
screenWidth = getWindowManager().getDefaultDisplay().getWidth();
userPictureView = (ImageView) findViewById(R.id.UserPictureImageView);
NetworkHelper networkHelper = new NetworkHelper(this);
downloadPictures = networkHelper.mayDownloadImages();
Intent intent = getIntent();
String dataString = intent.getDataString();
Bundle bundle = intent.getExtras();
account = AccountHolder.getInstance(this).getAccount();
// If this is not null, we are called from another app
if ( dataString!=null) {
// Lets see what server type that is and get an account for it
// so that we can access the data
// This works even with multiple twitter or identica accounts, as we just need one
// account to access the data at all
if (dataString.contains("://twitter.com")) {
TweetDB tmp = TweetDB.getInstance(getApplicationContext());
account = tmp.getAccountForType(Account.Type.TWITTER);
}
else if (dataString.contains("://identi.ca")) {
TweetDB tmp = TweetDB.getInstance(getApplicationContext());
account = tmp.getAccountForType(Account.Type.IDENTICA);
}
else {
// TODO for e.g. generic status.net - loop over existing accounts and check if the base url matches?
}
if (dataString.matches("http://twitter.com/.*/status/.*$")) {
String tids = dataString.substring(dataString.lastIndexOf("/")+1);
Long tid = Long.parseLong(tids);
TwitterHelper th = new TwitterHelper(this, account);
try {
status = new GetOneStatusTask(th).execute(tid).get();
} catch (InterruptedException e) {
e.printStackTrace(); // TODO: Customise this generated block
} catch (ExecutionException e) {
e.printStackTrace(); // TODO: Customise this generated block
}
} else if (dataString.matches("http://twitter.com/#!/.*$")) {
// A user - forward to UserDetailActivity TODO: remove once this is coded in AndroidManifest.xml
String userName = dataString.substring(dataString.lastIndexOf("/")+1);
// TODO account needs to be a twitter one
Intent i = new Intent(this,UserDetailActivity.class);
i.putExtra("userName",userName);
startActivity(i);
finish();
} else if (dataString.matches("http://twitter.com/[a-zA-Z0-9_]*\\?.*")) {
// A user ref in email - forward to UserDetailActivity TODO: remove once this is coded in AndroidManifest.xml
// TODO account needs to be a twitter one
String userName = dataString.substring(19,dataString.indexOf("?"));
Intent i = new Intent(this,UserDetailActivity.class);
i.putExtra("userName",userName);
startActivity(i);
finish();
}
} else {
// Called from within Zwitscher
if (bundle!=null) {
status = (Status) bundle.get("status"); // NO-NLS
}
}
if (status==null) {
// e.g. when called from HTC Mail, which fails to forward the full
// http://twitter.com/#!/.../status/.. url, but only sends http://twitter.com
Log.w("OneTweetActivity","Status was null for Intent " + intent );
if (tts!=null)
tts.shutdown();
finish();
return;
}
Log.i("OneTweetActivity","Showing status: " + status.toString());
// Download the user profile image in a background task, as this may
// mean a network call.
if (status.getRetweetedStatus()==null)
new DownloadUserImageTask().execute(status.getUser());
else
new DownloadUserImageTask().execute(status.getRetweetedStatus().getUser());
// Check if the tweet contains urls to picture services and load thumbnails
// if needed
new DownloadImagePreviewsTask(status).execute();
TextView tv01 = (TextView) findViewById(R.id.TextView01);
StringBuilder sb = new StringBuilder("<b>");
if (status.getRetweetedStatus()==null) {
sb.append(status.getUser().getName());
sb.append(" (");
sb.append(status.getUser().getScreenName());
sb.append(")");
sb.append("</b>");
}
else {
sb.append(status.getRetweetedStatus().getUser().getName());
sb.append(" (");
sb.append(status.getRetweetedStatus().getUser().getScreenName());
sb.append(" )</b> ").append(getString(R.string.resent_by)).append(" <b>");
sb.append(status.getUser().getName());
sb.append("</b>");
}
tv01.setText(Html.fromHtml(sb.toString()));
TextView mtv = (TextView) findViewById(R.id.MiscTextView);
if (status.getInReplyToScreenName()!=null) {
String s = getString(R.string.in_reply_to);
mtv.setText(Html.fromHtml(s + " <b>" + status.getInReplyToScreenName() + "</b>"));
}
else {
mtv.setText("");
}
TextView tweetView = (TextView)findViewById(R.id.TweetTextView);
// tweetView.setText(status.getText());
setTweetText(tweetView);
TextView timeClientView = (TextView)findViewById(R.id.TimeTextView);
TwitterHelper th = new TwitterHelper(this, account);
String s = getString(R.string.via);
String text = th.getStatusDate(status) + s + status.getSource();
String from = getString(R.string.from);
if (status.getPlace()!=null) {
// See if we have some tool on the system to resolve geo: urls
// Otherwise we omit the link
Intent geoIntent = new Intent(Intent.ACTION_VIEW,Uri.parse("geo:0,0"));
List<ResolveInfo> resolveInfos = getPackageManager().queryIntentActivities(geoIntent, PackageManager.MATCH_DEFAULT_ONLY);
boolean supportsGeoUrls = !resolveInfos.isEmpty();
Place place = status.getPlace();
text += " " + from + " " ;
if (place.getFullName()!=null && supportsGeoUrls) {
text += "<a href=\"geo:0,0?q=" + place.getFullName() + ","+ place.getCountry() + "\">";
}
text += place.getFullName();
if (place.getFullName()!=null && supportsGeoUrls) {
text += "</a>";
}
}
timeClientView.setText(Html.fromHtml(text));
timeClientView.setMovementMethod(LinkMovementMethod.getInstance());
// Update Button state depending on Status' properties
ImageButton threadButton = (ImageButton) findViewById(R.id.ThreadButton);
if (status.getInReplyToScreenName()==null) {
if (threadButton!=null) // TODO Honeycomb?
threadButton.setEnabled(false);
}
ImageView favoriteButton = (ImageView) findViewById(R.id.FavoriteButton);
if (favoriteButton!=null) {
if (status.isFavorited())
favoriteButton.setImageResource(R.drawable.favorite_on);
}
ImageButton translateButon = (ImageButton) findViewById(R.id.TranslateButton);
if (translateButon!=null)
translateButon.setEnabled(networkHelper.isOnline());
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
boolean isNewUser = prefs.getBoolean("newUser",true);
if (!isNewUser) {
TextView hintView = (TextView) findViewById(R.id.HintView);
hintView.setVisibility(View.GONE);
}
boolean supportRIL = prefs.getBoolean("ril_enable",false);
if (supportRIL) {
Button rilButton = (Button) findViewById(R.id.ril_button);
if (rilButton!=null) {
rilButton.setVisibility(View.VISIBLE);
rilButton.setEnabled(true);
}
}
final Spinner spinner = (Spinner) findViewById(R.id.ot_spinner);
if (spinner!=null) {
final UserMentionEntity[] userMentionEntities = status.getUserMentionEntities();
if (userMentionEntities !=null && userMentionEntities.length>0) {
spinner.setVisibility(View.VISIBLE);
final List<String> users = new ArrayList<String>(userMentionEntities.length+2);
// Add an item 0 as dummy, as the spinner auto-selects it
users.add(getString(R.string.pick_a_user));
for (UserMentionEntity ume : userMentionEntities) {
String entry = "@" + ume.getScreenName() + " (" + ume.getName() + ")";
if (!users.contains(entry)) {
users.add(entry);
}
}
// Also add the retweeter to the list
if (status.isRetweet() ) {
String entry = "@" + status.getUser().getScreenName() +" (" + status.getUser().getName() + ")";
if (!users.contains(entry)) {
users.add(entry);
}
}
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item,
users);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(adapter);
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
// Our dummy is at position 0
if (position>0) {
Intent intent = new Intent(OneTweetActivity.this, UserDetailActivity.class);
String screenName = users.get(position);
screenName = screenName.substring(1); // Skip over initial @
screenName = screenName.substring(0,screenName.indexOf(' '));
intent.putExtra("userName", screenName);
startActivity(intent);
}
// reset to item 0, so that repeated selection of the same item works.
spinner.setSelection(0);
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
}
else {
spinner.setVisibility(View.INVISIBLE);
}
}
}
@Override
protected void onResume() {
super.onResume();
setupspeak();
}
@Override
protected void onPause() {
super.onPause();
if (tts!=null) {
tts.shutdown();
tts=null;
}
}
private void setTweetText(TextView tweetView) {
String[] tokens;
if (status.isRetweet()) {
tokens = status.getRetweetedStatus().getText().split(" ");
} else {
tokens = status.getText().split(" ");
}
StringBuilder builder = new StringBuilder();
for (String token: tokens) {
boolean found=false;
if (status.getMediaEntities()!=null) {
for (MediaEntity me : status.getMediaEntities()) {
if (me.getURL().equals(token)) {
builder.append(me.getDisplayURL());
found=true;
break;
}
}
}
if (!found && status.getURLEntities()!=null) {
for (URLEntity ue : status.getURLEntities()) {
if (ue.getURL()!=null && ue.getURL().equals(token)) {
if (ue.getExpandedURL() != null) {
builder.append(ue.getExpandedURL());
found = true;
break;
}
}
}
}
if (!found) {
builder.append(token);
}
builder.append(" "); // todo, not at the end
}
tweetView.setText(builder.toString());
}
/**
* Display display of the details of a user from pressing
* the user icon button.
* @param v View that has been clicked
*/
@SuppressWarnings("unused")
public void displayUserDetail(View v) {
Intent i = new Intent(this, UserDetailActivity.class);
User theUser;
if (status.getRetweetedStatus()==null) {
theUser = status.getUser();
} else {
theUser = status.getRetweetedStatus().getUser();
}
i.putExtra("userName", theUser.getScreenName());
i.putExtra("userId", theUser.getId());
startActivity(i);
}
/**
* Trigger replying to the current status.
* @param v View that has been clicked
*/
@SuppressWarnings("unused")
public void reply(View v) {
Intent i = new Intent(this, NewTweetActivity.class);
i.putExtra(getString(R.string.status), status);
i.putExtra("op", getString(R.string.reply));
startActivity(i);
}
/**
* Trigger replying to all users mentioned via @xxx in the
* current status. Opens an editor Window first
* @param v View that has been clicked
*/
@SuppressWarnings("unused")
public void replyAll(View v) {
Intent i = new Intent(this, NewTweetActivity.class);
i.putExtra(getString(R.string.status), status);
i.putExtra("op", getString(R.string.replyall));
startActivity(i);
}
/**
* Trigger a resent of the current status
* @param v View that has been clicked
*/
@SuppressWarnings("unused")
public void retweet(View v) {
UpdateRequest request = new UpdateRequest(UpdateType.RETWEET);
request.id = status.getId();
UpdateStatusService.sendUpdate(this,account,request);
}
/**
* Do the classical re-send thing by prefixing with 'RT'.
* Opens an editor window first.
* @param v View that has been clicked
*/
@SuppressWarnings("unused")
public void classicRetweet(View v) {
Intent i = new Intent(this, NewTweetActivity.class);
i.putExtra(getString(R.string.status), status);
i.putExtra("op", getString(R.string.classicretweet));
startActivity(i);
}
/**
* Starts a view that shows the conversation around the current
* status.
* @param v View that has been clicked
*/
@SuppressWarnings("unused")
public void threadView(View v) {
Intent i = new Intent(this,ThreadListActivity.class);
i.putExtra("startId", status.getId());
startActivity(i);
}
/**
* Marks the current status as (non) favorite
* @param v View that has been clicked
*/
@SuppressWarnings("unused")
public void favorite(View v) {
ImageView favoriteButton = (ImageView) findViewById(R.id.FavoriteButton);
UpdateRequest request = new UpdateRequest(UpdateType.FAVORITE);
request.status = status;
request.view = favoriteButton;
UpdateStatusService.sendUpdate(this,account,request);
}
/**
* Start sending a direct message to the user that sent this
* status.
* @param v View that has been clicked
*/
@SuppressWarnings("unused")
public void directMessage(View v) {
Intent i = new Intent(this, NewTweetActivity.class);
i.putExtra(getString(R.string.status), status);
i.putExtra("op", getString(R.string.direct));
startActivity(i);
}
/**
* Add the current status to the ReadIt Later list.
* @param v View that has been clicked
*/
@SuppressWarnings("unused")
public void readItLater(View v) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
String user = prefs.getString("ril_user","");
String password = prefs.getString("ril_password","");
if (user.equals("") || password.equals("")) {
Toast.makeText(this,getString(R.string.no_ril_user),Toast.LENGTH_LONG).show();
return;
}
String url = null;
if (account.isStatusNet())
url = "https://identi.ca/notice/" + status.getId();
else {
// If we have a RT; then the URLEntities are on the retweeted status
Status theStatus;
if (status.isRetweet()) {
theStatus = status.getRetweetedStatus();
} else {
theStatus = status;
}
// do not link to the status here, but to the link(s) inside
if (theStatus.getURLEntities()!=null && theStatus.getURLEntities().length>0) {
URLEntity ue = theStatus.getURLEntities()[0]; // TODO grab all urls
if (ue.getExpandedURL()!=null)
url = ue.getExpandedURL();
else if (ue.getURL()!=null)
url = ue.getURL();
}
if (url==null) // Fallback
url = "https://twitter.com/#!/" + status.getUser().getScreenName() + "/status/" + status.getId();
}
UpdateRequest request = new UpdateRequest(UpdateType.LATER_READING);
request.status = status;
request.url = url;
request.extUser = user;
request.extPassword = password;
UpdateStatusService.sendUpdate(this,account,request);
}
//////////////// speak related stuff ////////////////////
public void onInit(int status) {
}
public void onUtteranceCompleted(String utteranceId) {
Log.i("speak", "Utterance done: " + utteranceId);
}
/**
* Setup speak just in case we may need it.
* If directly called from within speak() it will not work
* because the onInit() listener is no ready early enough
*/
void setupspeak() {
tts = new TextToSpeech(this,this);
tts.setLanguage(Locale.US);
}
/**
* Speak the current status via TTS
* @param v View that has been clicked
*/
@SuppressWarnings("unused")
public void speak(View v)
{
int res = tts.setOnUtteranceCompletedListener(this);
if (res==TextToSpeech.ERROR) {
Log.e("1TA", "Failed to set on utterance listener");
}
BugSenseHandler.sendEvent("Speak used");
HashMap<String, String> ttsParams = new HashMap<String, String>();
ttsParams.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, "tweet_status_msg" + status.getUser().getScreenName());
tts.speak(status.getText(), TextToSpeech.QUEUE_FLUSH, ttsParams);
}
//////////////// speak related stuff end ////////////////////
/**
* Send a message via Email or ...
* Invoked from the send button
* @param v view this is invoked on
*/
@SuppressWarnings("unused")
public void send(View v) {
User user = status.getUser();
String s = getString(R.string.wrote);
String wrote = user.getName() + "(@" + user.getScreenName() + ") " + s + ":";
String text = wrote + "\n\n" + status.getText();
String url ;
if (account.getServerType().equals(Account.Type.TWITTER)) {
url = "http://twitter.com/#!/" + user.getScreenName() + "/status/" + status.getId();
text = text + "\n\n" + url;
}
Intent i = new Intent(Intent.ACTION_SEND);
i.setType("text/plain");
i.putExtra(Intent.EXTRA_TEXT,text);
String subject = getString(R.string.message_from_zwitscher);
i.putExtra(Intent.EXTRA_SUBJECT, subject);
startActivity(i);
}
/**
* Translate the current status by calling Google translate.
* Target language is the users current locale.
* @param v View that has been clicked
*/
@SuppressWarnings("unused")
public void translate(View v) {
String locale = Locale.getDefault().getLanguage();
String text = status.getText();
try {
text = URLEncoder.encode(text,"UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace(); // TODO: Customise this generated block
}
String url = "http://translate.google.com/#auto/" + locale + "/" + text;
Intent i = new Intent(Intent.ACTION_VIEW);
i.setData(Uri.parse(url));
startActivity(i);
}
/**
* Finishes this screen and returns to the list of statuses
* @param v View that has been clicked
*/
@SuppressWarnings("unused")
public void done(View v) {
if (tts!=null)
tts.shutdown();
finish();
}
/**
* Return urls for thumbnails of linked images if the url in the status is recognized
* as an image service
* @param status Status to analyze
* @return List of Bitmaps to display
*/
private List<UrlPair> parseForPictureUrls(Status status) {
Set<String> urls = new HashSet<String>();
ArrayList<UrlPair> urlPairs = new ArrayList<UrlPair>();
MediaEntity[] mediaEntities = status.getMediaEntities();
if (mediaEntities!=null) {
for (MediaEntity me : mediaEntities) {
String url = me.getURL();
String target;
target = me.getMediaURL();
target = target+ ":small";
UrlPair pair = new UrlPair(url, target);
urlPairs.add(pair);
}
}
if (urlPairs.size()>0)
return urlPairs; // Urls provided by twitter, so we're done.
URLEntity[] ures = status.getURLEntities();
if (ures!=null) {
for (URLEntity ue : ures) {
String url = ue.getExpandedURL();
if (url!=null)
urls.add(url);
}
}
// Nothing provided by twitter, so parse the text
if (urls.size()==0 && urlPairs.size()==0) {
String[] tokens = status.getText().split(" ");
for (String token : tokens) {
if (token.startsWith("http://") || token.startsWith("https://")) {
urls.add(token);
}
}
}
if (urls.size()==0)
return urlPairs;
// We have urls, so check for picture services
// TODO check http://stackoverflow.com/a/11014923/100957
for (String url : urls) {
String finalUrlString = UrlExtractHelper.extractOneUrl(url, screenWidth, status);
UrlPair pair = new UrlPair(url,finalUrlString);
urlPairs.add(pair);
}
return urlPairs;
}
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.one_tweet_menu,menu);
ActionBar actionBar = this.getActionBar();
actionBar.setDisplayHomeAsUpEnabled(true);
// Only enable the "delete" item for statuses we authored
if (status != null && status.getUser().getScreenName().equals(account.getName())) {
menu.findItem(R.id.delete).setEnabled(true);
}
else {
menu.findItem(R.id.delete).setEnabled(false);
}
return true;
}
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
finish();
break;
case R.id.reply:
reply(null);
break;
case R.id.retweet:
item.setEnabled(false); // TODO show busy spinner?
retweet(null);
break;
case R.id.direct:
directMessage(null);
break;
case R.id.thread:
threadView(null);
break;
case R.id.replyAll:
replyAll(null);
break;
case R.id.cl_retweet:
classicRetweet(null);
break;
case R.id.favorite:
favorite(null);
break;
case R.id.translate:
translate(null);
break;
case R.id.forward:
send(null);
break;
case R.id.speak:
speak(null);
break;
case R.id.ril:
readItLater(null);
break;
case R.id.report_as_spam:
report_spam();
break;
case R.id.show_on_web:
show_on_web();
break;
case R.id.delete:
deleteStatus();
break;
default:
Log.e("OneTweetActivity","Unknown menu item: " + item.toString());
}
return true;
// return super.onOptionsItemSelected(item);
}
private void deleteStatus() {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setCancelable(true);
builder.setTitle(R.string.delete_status);
builder.setCancelable(false);
String msg = getString(R.string.delete_status_really,status.getUser().getScreenName());
builder.setMessage(msg);
builder.setPositiveButton(R.string.yes,new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
UpdateRequest request = new UpdateRequest(UpdateType.DELETE_STATUS);
request.id = status.getId();
UpdateStatusService.sendUpdate(OneTweetActivity.this,account,request);
done(null);
}
});
builder.setNegativeButton(R.string.no, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
dialogInterface.cancel();
}
});
builder.create().show();
}
private void show_on_web() {
Intent i = new Intent(Intent.ACTION_VIEW);
String u;
if (!account.isStatusNet()) {
u = "https://mobile.twitter.com/" + status.getUser().getScreenName() + "/status/" + status.getId();
}
else {
u = "http://identi.ca/notice/" + status.getId();
}
i.setData(Uri.parse(u));
startActivity(i);
}
void report_spam() {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setCancelable(true);
builder.setTitle(R.string.report_as_spammer);
builder.setCancelable(false);
String msg = getString(R.string.report_as_spammer_really,status.getUser().getScreenName());
builder.setMessage(msg);
builder.setPositiveButton(R.string.yes,new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
UpdateRequest request = new UpdateRequest(UpdateType.REPORT_AS_SPAMMER);
request.id = status.getUser().getId();
UpdateStatusService.sendUpdate(OneTweetActivity.this,account,request);
}
});
builder.setNegativeButton(R.string.no, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
dialogInterface.cancel();
}
});
builder.create().show();
}
/**
* Load thumbnails of linked images for the passed listOfUrlPairs
* @param listOfUrlPairs list of images to load (thumbnail url, url to full img)
* @return List of bitmaps along
*/
private List<BitmapWithUrl> loadThumbnails(List<UrlPair> listOfUrlPairs) {
List<BitmapWithUrl> bitmaps = new ArrayList<BitmapWithUrl>(listOfUrlPairs.size());
for (UrlPair urlPair : listOfUrlPairs) {
Log.i("loadThumbnail", "URL to load is " + urlPair.getTarget());
if(urlPair.getTarget()==null)
continue;
try {
URL picUrl = new URL(urlPair.getTarget());
BufferedInputStream in = new BufferedInputStream(picUrl.openStream());
Bitmap bitmap = BitmapFactory.decodeStream(in);
in.close();
BitmapWithUrl bwu = new BitmapWithUrl(bitmap,urlPair.getSrc());
bitmaps.add(bwu);
}
catch (Exception e) {
e.printStackTrace();
}
}
return bitmaps;
}
/**
* Background task to download the user profile images.
*/
private class DownloadUserImageTask extends AsyncTask<User, Void,Bitmap> {
@Override
protected void onPreExecute() {
super.onPreExecute();
if (pg!=null)
pg.setVisibility(ProgressBar.VISIBLE);
}
protected Bitmap doInBackground(User... users) {
User user = users[0];
PicHelper picHelper = new PicHelper();
Bitmap bi;
if (downloadPictures)
bi = picHelper.fetchUserPic(user);
else
bi = picHelper.getBitMapForUserFromFile(user);
return bi;
}
protected void onPostExecute(Bitmap result) {
if (result!=null)
userPictureView.setImageBitmap(result);
if (pg!=null)
pg.setVisibility(ProgressBar.INVISIBLE);
}
}
/**
* Background task to download the thumbnails of linked images
*/
private class DownloadImagePreviewsTask extends AsyncTask<Void,Void,List<BitmapWithUrl>> {
private twitter4j.Status status;
private DownloadImagePreviewsTask(twitter4j.Status status) {
this.status = status;
}
@Override
protected void onPreExecute() {
super.onPreExecute();
if (pg!=null)
pg.setVisibility(ProgressBar.VISIBLE);
if (titleTextView!=null) {
String text = getString(R.string.get_preview);
titleTextView.setText(text);
}
}
@Override
protected List<BitmapWithUrl> doInBackground(Void... params) {
List<UrlPair> pictureUrls;
if (status.isRetweet())
pictureUrls = parseForPictureUrls(status.getRetweetedStatus());
else
pictureUrls = parseForPictureUrls(status);
List<BitmapWithUrl> bitmapList=null;
if (downloadPictures)
bitmapList = loadThumbnails(pictureUrls);
return bitmapList;
}
@Override
protected void onPostExecute(final List<BitmapWithUrl> bitmaps) {
super.onPostExecute(bitmaps);
View galleryProgress = findViewById(R.id.gallery_progress);
if (galleryProgress!=null)
galleryProgress.setVisibility(View.GONE);
if (bitmaps!=null) {
Gallery g = (Gallery) findViewById(R.id.gallery);
ImageAdapter adapter = new ImageAdapter();
adapter.addImages(bitmaps);
g.setAdapter(adapter);
g.setOnItemClickListener(new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
String url = bitmaps.get(position).url;
Uri uri = Uri.parse(url);
Intent i = new Intent(Intent.ACTION_VIEW, uri);
startActivity(i);
}
});
}
if (titleTextView!=null)
titleTextView.setText("");
if (pg!=null)
pg.setVisibility(ProgressBar.INVISIBLE);
}
}
/**
* Picture adapter for the Gallery that holds the images
* It is filled via data obtained via #loadThumbnails
*/
private class ImageAdapter extends BaseAdapter {
private List<BitmapWithUrl> mImages = new ArrayList<BitmapWithUrl>();
void addImages(List<BitmapWithUrl> images) {
mImages.addAll(images);
}
int mGalleryItemBackground;
public ImageAdapter() {
// See res/values/style.xml for the <declare-styleable> that defines
// Gallery1.
TypedArray a = obtainStyledAttributes(R.styleable.Gallery1);
mGalleryItemBackground = a.getResourceId(
R.styleable.Gallery1_android_galleryItemBackground, 0);
a.recycle();
}
public int getCount() {
return mImages.size();
}
public Object getItem(int position) {
return position;
}
public long getItemId(int position) {
return position;
}
public View getView(int position, View convertView, ViewGroup parent) {
ImageView i = new ImageView(getApplicationContext());
Bitmap bitmap = mImages.get(position).bitmap;
if (bitmap!=null) {
i.setImageBitmap(bitmap);
i.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
i.setAdjustViewBounds(true);
// Try to get the freaking scaling right
Display defaultDisplay = getWindow().getWindowManager().getDefaultDisplay();
int w = defaultDisplay.getWidth();
int h = defaultDisplay.getHeight();
int bw = bitmap.getWidth();
int bh = bitmap.getHeight();
double wf = (double)bw / (double)w;
double hf = (double)bw / (double)h;
double maf = Math.max(wf,hf);
if (maf < 0.3 )
maf = 2 * maf; // twitpic thumbs are 150px only, scale up a bit
if (maf>0) {
int fh = (int) (bh/maf);
int fw = (int) (bw/maf);
i.setLayoutParams(new Gallery.LayoutParams(fw,fh));
}
}
// The preferred Gallery item background
i.setBackgroundResource(mGalleryItemBackground);
return i;
}
}
/**
* Helper class that holds a bitmap along with the picture url,
* so that a click on the image in the gallery can start a browser
* window to the image service to browser the full size one.
*/
private static class BitmapWithUrl {
Bitmap bitmap;
String url;
public BitmapWithUrl(Bitmap bitmap, String picUrlString) {
this.bitmap = bitmap;
this.url = picUrlString;
}
}
}