Back to project page MyTwitter-Android.
The source code is released under:
Apache License
If you think the Android project MyTwitter-Android listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.
package org.fukata.android.mytw; //from w w w . j ava 2s. com import java.util.ArrayList; import java.util.List; import java.util.Timer; import java.util.TimerTask; import org.fukata.android.exandroid.loader.process.BaseRequest; import org.fukata.android.exandroid.loader.process.ProcessLoader; import org.fukata.android.exandroid.util.StringUtil; import org.fukata.android.mytw.TimelineActivity.LoadMode; import org.fukata.android.mytw.database.dto.TweetDto; import org.fukata.android.mytw.database.schema.TweetSchema.TweetType; import org.fukata.android.mytw.util.PrettyDateUtil; import org.fukata.android.mytw.util.SettingUtil; import org.fukata.android.mytw.util.StringMatchUtils; import org.fukata.android.mytw.util.StringUtils; import android.app.Activity; import android.app.AlertDialog; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.net.Uri; import android.os.Handler; import android.util.Log; import android.view.MotionEvent; import android.view.View; import android.widget.AdapterView; import android.widget.AdapterView.OnItemLongClickListener; import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.ListView; import android.widget.Toast; public class TimelineView extends ListView implements View.OnClickListener, OnItemLongClickListener { // ??????????????????????????????????????????????? static final int UPDATE_TIMELINE_CHECK_INVERVAL = 10000; private static final int NOTIFY_NEW_TWEET = 1; TimelineActivity parentActivity; List<TimelineItem> items; TimelineAdapter adapter; Button more; int lastLoadCount; String oldestStatusId; //??????????????????????tweet???statusId String latestStatusId; //???????????????????????tweet???statusId long lastUpdateTimeline = System.currentTimeMillis(); Timer intervalUpdateTimer; boolean isFirstLoad = true; ItemDialog itemDialog; NotificationManager notificationManager; Handler handler = new Handler(); public TimelineView(Context context, TimelineActivity activity) { super(context); parentActivity = activity; items = new ArrayList<TimelineItem>(); adapter = newInstanceTimelineAdapter(context, items); itemDialog = newInstanceItemDialog(); notificationManager = (NotificationManager)parentActivity.getSystemService(Context.NOTIFICATION_SERVICE); View footerView = activity.getLayoutInflater().inflate(R.layout.timeline_footer, null); more = (Button) footerView.findViewById(R.id.more); more.setOnClickListener(this); addFooterView(footerView); setOnItemLongClickListener(this); setAdapter(adapter); initTimeline(); attachUpdateInterval(); } void initTimeline() { adapter.clear(); List<TweetDto> tweets = parentActivity.tweetDao.findByType(getTweetType(), SettingUtil.getTimelineCount()); for (TweetDto tweet : tweets) { TimelineItem item = generateTimelineItem(tweet); adapter.add(item); } //????????tweets???????????????statusId?????????? if (tweets.size() > 0) { this.oldestStatusId = tweets.get(tweets.size() - 1).statusId; this.latestStatusId = tweets.get(0).statusId; } } TimelineItem generateTimelineItem(TweetDto tweet) { TimelineItem item = new TimelineItem(); item.setStatusId(tweet.statusId); item.setStatus(tweet.status); item.setUsername(tweet.username); item.setUserId(tweet.userId); item.setSource(tweet.source); item.setInReplytoStatusId(tweet.inReplyToStatusId); item.setCreatedAt(tweet.createdAt); return item; } TweetDto generateTweetDto(TimelineItem item) { TweetDto dto = new TweetDto(); dto.statusId = item.getStatusId(); dto.status = item.getStatus(); dto.username = item.getUsername(); dto.userId = item.getUserId(); dto.source = item.getSource(); dto.inReplyToStatusId = item.getInReplytoStatusId(); dto.createdAt = item.getCreatedAt(); dto.tweetType = getTweetType(); return dto; } ItemDialog newInstanceItemDialog() { return new ItemDialog(parentActivity); } void attachUpdateInterval() { intervalUpdateTimer = new Timer(); TimerTask task = new TimerTask() { @Override public void run() { long now = System.currentTimeMillis(); int interval = SettingUtil.getAutoInterval()*1000; if (interval>0 && now>lastUpdateTimeline+interval) { // ????????????????????????????????? if (parentActivity.timelineLoader.getLoaderQueue().size()==0) { loadTimeline(LoadMode.NEW); } } } }; intervalUpdateTimer.schedule(task, UPDATE_TIMELINE_CHECK_INVERVAL, UPDATE_TIMELINE_CHECK_INVERVAL); } TimelineAdapter newInstanceTimelineAdapter(Context context, List<TimelineItem> items) { return new TimelineAdapter(context, items); } TweetType getTweetType() { return TweetType.HOME; } void loadTimeline(final LoadMode mode) { preLoadTimeline(mode); final List<TimelineItem> timeline = new ArrayList<TimelineItem>(); Runnable successCallback = generateSuccessCallback(timeline, mode); processLoadTimeline(timeline, mode, successCallback); } void preLoadTimeline(LoadMode mode) { if (LoadMode.REFRESH==mode) { more.setEnabled(false); more.setText(R.string.retrieving); } else if (LoadMode.NEW==mode) { } else if (LoadMode.MORE==mode) { more.setEnabled(false); more.setText(R.string.retrieving); } } void processLoadTimeline(final List<TimelineItem> timeline, final LoadMode mode, Runnable successCallback) { parentActivity.timelineLoader.load(new BaseRequest(successCallback, null) { @Override public void processRequest(ProcessLoader loader) { lastLoadCount = 0; List<TimelineItem> list = null; if (LoadMode.REFRESH==mode) { list = getTimeline(); timeline.addAll(list); // 1?????????????????????????????????????? if (list.size() > 0) { refreshCache(timeline); } } else if (LoadMode.NEW==mode) { list = getNewTimeline(latestStatusId); lastLoadCount = list.size(); timeline.addAll(list); addCache(list); } else if (LoadMode.MORE==mode) { list = getMoreTimeline(oldestStatusId); timeline.addAll(list); addCache(list); } super.processRequest(loader); } void addCache(final List<TimelineItem> newLoadedItems) { Log.d(getClass().getSimpleName(), "addCache"); List<TweetDto> tweets = new ArrayList<TweetDto>(); int count = SettingUtil.getTimelineCount(); int len = timeline.size() > count ? count : timeline.size(); for (int i=0; i<len; i++) { TimelineItem item = timeline.get(i); tweets.add( generateTweetDto(item) ); } parentActivity.tweetDao.addTweets(tweets, getTweetType()); } void refreshCache(final List<TimelineItem> timeline) { Log.d(getClass().getSimpleName(), "refreshCache"); List<TweetDto> tweets = new ArrayList<TweetDto>(); int count = SettingUtil.getTimelineCount(); int len = timeline.size() > count ? count : timeline.size(); for (int i=0; i<len; i++) { TimelineItem item = timeline.get(i); tweets.add( generateTweetDto(item) ); } parentActivity.tweetDao.refreshTweets(tweets, getTweetType()); } }); } List<TimelineItem> getMoreTimeline(String lastStatuseId) { return parentActivity.twitter.getMoreHomeTimeline(lastStatuseId); } List<TimelineItem> getNewTimeline(String latestStatuseId) { return parentActivity.twitter.getNewHomeTimeline(latestStatuseId); } List<TimelineItem> getTimeline() { return parentActivity.twitter.getHomeTimeline(); } Runnable generateSuccessCallback(final List<TimelineItem> timeline, final LoadMode mode) { Log.d(getClass().getSimpleName(), "generateSuccessCallback"); Runnable callback = new Runnable() { @Override public void run() { // ????????????????????????????? int firstItemPosition = getFirstVisiblePosition(); int firstItemTop = getChildCount()==0 || getChildAt(0)==null ? 0 : getChildAt(0).getTop(); Log.d(getClass().getSimpleName(), "firstItemPosition="+firstItemPosition); Log.d(getClass().getSimpleName(), "firstItemTop="+firstItemTop); processUpdateTimeline(mode, timeline); processFocusItem(mode,firstItemPosition,firstItemTop); processNotification(mode); lastUpdateTimeline = System.currentTimeMillis(); }; }; return callback; } void processUpdateTimeline(LoadMode mode, final List<TimelineItem> timeline) { more.setText(R.string.more); more.setEnabled(true); if (timeline.size()>0) { if (LoadMode.REFRESH==mode) { latestStatusId = timeline.get(0).getStatusId(); oldestStatusId = timeline.get(timeline.size()-1).getStatusId(); adapter.clear(); for (TimelineItem item : timeline) { adapter.add(item); } if (hasWindowFocus()) { Toast.makeText(parentActivity.getApplicationContext(), R.string.update_successful, Toast.LENGTH_LONG).show(); } } else if (LoadMode.NEW==mode) { int insertAt = 0; for (TimelineItem item : timeline) { if (!StringUtil.equals(latestStatusId, item.getStatusId())) { adapter.insert(item, insertAt); insertAt++; } } latestStatusId = timeline.get(0).getStatusId(); } else if (LoadMode.MORE==mode) { for (TimelineItem item : timeline) { if (!StringUtil.equals(oldestStatusId, item.getStatusId())) { adapter.add(item); } } oldestStatusId = timeline.get(timeline.size()-1).getStatusId(); if (hasWindowFocus()) { Toast.makeText(parentActivity.getApplicationContext(), R.string.update_successful, Toast.LENGTH_LONG).show(); } } } } void processNotification(LoadMode mode) { if (hasWindowFocus() || !SettingUtil.isNotificationEnabled()) { return; } if (mode == LoadMode.NEW && lastLoadCount>0) { notificationNewTweet(); } } void notificationNewTweet() { String ticker = parentActivity.getString(R.string.notify_new_tweet, lastLoadCount); Intent intent = new Intent(parentActivity, TimelineActivity.class); intent.setAction(Intent.ACTION_VIEW); PendingIntent contentIntent = PendingIntent.getActivity(parentActivity, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); Notification notification = new Notification(android.R.drawable.ic_menu_add, ticker, System.currentTimeMillis()); notification.setLatestEventInfo(parentActivity.getApplicationContext(), parentActivity.getString(R.string.app_name), ticker, contentIntent); notification.flags = Notification.FLAG_AUTO_CANCEL; notificationManager.notify(NOTIFY_NEW_TWEET, notification); } void processFocusItem(LoadMode mode, int firstItemPosition, int firstItemTop) { if (mode == LoadMode.NEW) { //?????????????????????? setSelectionFromTop(firstItemPosition+lastLoadCount, firstItemTop); } } void doResume() { Log.d(getClass().getSimpleName(), "doResume"); boolean noCachedTimeline = this.latestStatusId == null; //???????????????????true??????? if (isFirstLoad && noCachedTimeline) { loadTimeline(LoadMode.REFRESH); } else { loadTimeline(LoadMode.NEW); } isFirstLoad = false; } @Override public void onClick(View v) { if (v.getId()==R.id.more) { loadTimeline(LoadMode.MORE); } } @Override public boolean onItemLongClick(AdapterView<?> parent, View v, int position, long id) { if (items.size()<=position) { return false; } TimelineItem item = items.get(position); if (item==null) { return false; } itemDialog.show(item); return false; } @Override public boolean onTouchEvent(MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_UP && this.getScrollY() < -60) { // ????????????????????????????? loadTimeline(LoadMode.REFRESH); } return super.onTouchEvent(event); } // CharSequence getTitle() { // return parentActivity.getString(R.string.title_home); // } void postRetweet(final TimelineItem item) { Runnable successCallback = new Runnable() { @Override public void run() { Toast.makeText(parentActivity.getApplicationContext(), R.string.retweet_successful, Toast.LENGTH_LONG).show(); loadTimeline(LoadMode.NEW); } }; parentActivity.timelineLoader.load(new BaseRequest(successCallback, null) { @Override public void processRequest(ProcessLoader loader) { parentActivity.twitter.postReTweet(item.getStatusId()); super.processRequest(loader); } }); } void postFavorites(final TimelineItem item) { Runnable successCallback = new Runnable() { @Override public void run() { Toast.makeText(parentActivity.getApplicationContext(), R.string.favorites_successful, Toast.LENGTH_LONG).show(); } }; parentActivity.timelineLoader.load(new BaseRequest(successCallback, null) { @Override public void processRequest(ProcessLoader loader) { parentActivity.twitter.postFavorites(item.getStatusId()); super.processRequest(loader); } }); } void deleteTweet(final TimelineItem item) { //FIXME ??? } class ItemDialog extends AlertDialog.Builder { ListView optionsView; ArrayAdapter<String> optionsAdapter; Activity activity; public ItemDialog(Activity activity) { super(activity); this.activity = activity; setTitle(R.string.options); } public void show(final TimelineItem item) { final TimelineMenu menu = new TimelineMenu(item, parentActivity); String[] options = menu.getMenuOptions(); setItems(options, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int index) { TimelineMenuOption which = menu.getAction(index); if (TimelineMenuOption.RETWEET == which) { postRetweet(item); } else if (TimelineMenuOption.RETWEET_WITH_COMMENT==which) { Intent intent = new Intent(Intent.ACTION_SEND); intent.setClass(activity, UpdateStatusActivity.class); intent.putExtra(Intent.EXTRA_TEXT, " RT @"+item.getUsername()+": "+item.getStatus()); intent.putExtra(MyTwitterApp.INTENT_EXTRA_SELECTION, MyTwitterApp.INTENT_EXTRA_SELECTION_HEAD); parentActivity.startActivity(intent); } else if (TimelineMenuOption.REPLY==which) { Intent intent = new Intent(Intent.ACTION_SEND); intent.setClass(activity, UpdateStatusActivity.class); intent.putExtra(Intent.EXTRA_TEXT, "@"+item.getUsername()+" "); intent.putExtra(MyTwitterApp.INTENT_EXTRA_SELECTION, MyTwitterApp.INTENT_EXTRA_SELECTION_END); parentActivity.startActivity(intent); } else if (TimelineMenuOption.FAVORITES == which) { postFavorites(item); } else if (TimelineMenuOption.URLS == which) { final List<String> urls = StringMatchUtils.getUrls(item.getStatus()); if (urls.size() == 1) { //URL???????????????????????????????????????????? openOnExternalWebBrowser(urls.get(0)); } else if (urls.size() > 1) { //URL?????????????????????????????????? String[] urlMenus = new String[urls.size()]; for (int i = 0; i < urls.size(); i++) { urlMenus[i] = parentActivity.getString(R.string.jump_to, StringUtils.strimwidth(urls.get(i), 40, "...")); } setItems(urlMenus, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { openOnExternalWebBrowser(urls.get(which)); } }); create().show(); } } else if (TimelineMenuOption.MENTIONED_FOR == which) { (new Thread(new Runnable() { @Override public void run() { final TimelineItem mentionFor = parentActivity.twitter.show(item.getInReplytoStatusId()); handler.post(new Runnable() { @Override public void run() { if (mentionFor != null) { AlertDialog.Builder bld = new AlertDialog.Builder(parentActivity); bld.setTitle(mentionFor.getUsername() + " " + PrettyDateUtil.toString(mentionFor.getCreatedAt())); bld.setMessage(mentionFor.getStatus()); bld.show(); } else { Toast.makeText( parentActivity.getApplicationContext(), "ERROR: failed to retreive a mention. " + item.getInReplytoStatusId(), Toast.LENGTH_LONG).show(); } } }); } })).start(); } } /** * ?????????URL?????? */ private void openOnExternalWebBrowser(String url) { try { Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); parentActivity.startActivity(intent); } catch (Exception e) { Toast.makeText(parentActivity.getApplicationContext(), R.string.update_unsuccessful, Toast.LENGTH_LONG).show(); } } }); create().show(); } } /** * ???????????????????????????????? */ enum TimelineMenuOption { RETWEET(R.string.retweet), RETWEET_WITH_COMMENT(R.string.retweet_with_comment), REPLY(R.string.reply), FAVORITES(R.string.favorites), URLS(R.string.urls), MENTIONED_FOR(R.string.mentioned_for); private int resourceId; private TimelineMenuOption(int resourceId) { this.resourceId = resourceId; } public int getResourceId() { return this.resourceId; } } /** * ??????????????? */ class TimelineMenu { private List<TimelineMenuOption> options = new ArrayList<TimelineMenuOption>(); private TimelineActivity parentActivity; public TimelineMenu(TimelineItem item, TimelineActivity parentActivity) { this.parentActivity = parentActivity; //compose menu item. options.add(TimelineMenuOption.RETWEET); options.add(TimelineMenuOption.RETWEET_WITH_COMMENT); options.add(TimelineMenuOption.REPLY); options.add(TimelineMenuOption.FAVORITES); List<String> urls = StringMatchUtils.getUrls(item.getStatus()); if (urls.size() > 0) { options.add(TimelineMenuOption.URLS); } String inReplyToStatusId = item.getInReplytoStatusId(); Log.d(getClass().getSimpleName(), "inreplytostatusId:" + inReplyToStatusId); if (inReplyToStatusId != null && inReplyToStatusId.length() > 0) { options.add(TimelineMenuOption.MENTIONED_FOR); } } public String[] getMenuOptions() { List<String> options = new ArrayList<String>(); for (TimelineMenuOption o : this.options) { options.add(this.parentActivity.getString(o.getResourceId())); } return options.toArray(new String[0]); } public TimelineMenuOption getAction(int index) { return this.options.get(index); } } }