org.mariotaku.twidere.util.Utils.java Source code

Java tutorial

Introduction

Here is the source code for org.mariotaku.twidere.util.Utils.java

Source

/*
 *            Twidere - Twitter client for Android
 * 
 * Copyright (C) 2012 Mariotaku Lee <mariotaku.lee@gmail.com>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package org.mariotaku.twidere.util;

import static android.content.res.Configuration.SCREENLAYOUT_LAYOUTDIR_RTL;
import static android.text.TextUtils.isEmpty;
import static org.mariotaku.twidere.provider.TweetStore.CACHE_URIS;
import static org.mariotaku.twidere.provider.TweetStore.DIRECT_MESSAGES_URIS;
import static org.mariotaku.twidere.provider.TweetStore.STATUSES_URIS;
import static org.mariotaku.twidere.util.TwidereLinkify.IMGLY_GROUP_ID;
import static org.mariotaku.twidere.util.TwidereLinkify.IMGUR_GROUP_ID;
import static org.mariotaku.twidere.util.TwidereLinkify.INSTAGRAM_GROUP_ID;
import static org.mariotaku.twidere.util.TwidereLinkify.MOBYPICTURE_GROUP_ID;
import static org.mariotaku.twidere.util.TwidereLinkify.PATTERN_IMGLY;
import static org.mariotaku.twidere.util.TwidereLinkify.PATTERN_IMGUR;
import static org.mariotaku.twidere.util.TwidereLinkify.PATTERN_INSTAGRAM;
import static org.mariotaku.twidere.util.TwidereLinkify.PATTERN_LOCKERZ_AND_PLIXI;
import static org.mariotaku.twidere.util.TwidereLinkify.PATTERN_MOBYPICTURE;
import static org.mariotaku.twidere.util.TwidereLinkify.PATTERN_PHOTOZOU;
import static org.mariotaku.twidere.util.TwidereLinkify.PATTERN_SINA_WEIBO_IMAGES;
import static org.mariotaku.twidere.util.TwidereLinkify.PATTERN_TWITGOO;
import static org.mariotaku.twidere.util.TwidereLinkify.PATTERN_TWITPIC;
import static org.mariotaku.twidere.util.TwidereLinkify.PATTERN_TWITTER_IMAGES;
import static org.mariotaku.twidere.util.TwidereLinkify.PATTERN_TWITTER_PROFILE_IMAGES;
import static org.mariotaku.twidere.util.TwidereLinkify.PATTERN_YFROG;
import static org.mariotaku.twidere.util.TwidereLinkify.PHOTOZOU_GROUP_ID;
import static org.mariotaku.twidere.util.TwidereLinkify.SINA_WEIBO_IMAGES_AVAILABLE_SIZES;
import static org.mariotaku.twidere.util.TwidereLinkify.TWITGOO_GROUP_ID;
import static org.mariotaku.twidere.util.TwidereLinkify.TWITPIC_GROUP_ID;
import static org.mariotaku.twidere.util.TwidereLinkify.TWITTER_PROFILE_IMAGES_AVAILABLE_SIZES;
import static org.mariotaku.twidere.util.TwidereLinkify.YFROG_GROUP_ID;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.MalformedURLException;
import java.net.Proxy;
import java.net.SocketAddress;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;

import org.apache.http.NameValuePair;
import org.json.JSONException;
import org.json.JSONObject;
import org.mariotaku.gallery3d.app.ImageViewerGLActivity;
import org.mariotaku.twidere.Constants;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.activity.CameraCropActivity;
import org.mariotaku.twidere.activity.DualPaneActivity;
import org.mariotaku.twidere.activity.HomeActivity;
import org.mariotaku.twidere.activity.ImageViewerActivity;
import org.mariotaku.twidere.app.TwidereApplication;
import org.mariotaku.twidere.fragment.ActivitiesAboutMeFragment;
import org.mariotaku.twidere.fragment.DirectMessagesConversationFragment;
import org.mariotaku.twidere.fragment.IncomingFriendshipsFragment;
import org.mariotaku.twidere.fragment.SavedSearchesListFragment;
import org.mariotaku.twidere.fragment.SearchTweetsFragment;
import org.mariotaku.twidere.fragment.SearchUsersFragment;
import org.mariotaku.twidere.fragment.SensitiveContentWaringDialogFragment;
import org.mariotaku.twidere.fragment.StatusFragment;
import org.mariotaku.twidere.fragment.TrendsFragment;
import org.mariotaku.twidere.fragment.UserBlocksListFragment;
import org.mariotaku.twidere.fragment.UserFavoritesFragment;
import org.mariotaku.twidere.fragment.UserFollowersFragment;
import org.mariotaku.twidere.fragment.UserFriendsFragment;
import org.mariotaku.twidere.fragment.UserListDetailsFragment;
import org.mariotaku.twidere.fragment.UserListMembersFragment;
import org.mariotaku.twidere.fragment.UserListSubscribersFragment;
import org.mariotaku.twidere.fragment.UserListTimelineFragment;
import org.mariotaku.twidere.fragment.UserListsListFragment;
import org.mariotaku.twidere.fragment.UserMentionsFragment;
import org.mariotaku.twidere.fragment.UserProfileFragment;
import org.mariotaku.twidere.fragment.UserTimelineFragment;
import org.mariotaku.twidere.model.DirectMessageCursorIndices;
import org.mariotaku.twidere.model.ImageSpec;
import org.mariotaku.twidere.model.ParcelableDirectMessage;
import org.mariotaku.twidere.model.ParcelableStatus;
import org.mariotaku.twidere.model.ParcelableUser;
import org.mariotaku.twidere.model.PreviewImage;
import org.mariotaku.twidere.model.StatusCursorIndices;
import org.mariotaku.twidere.model.TabSpec;
import org.mariotaku.twidere.provider.TweetStore;
import org.mariotaku.twidere.provider.TweetStore.Accounts;
import org.mariotaku.twidere.provider.TweetStore.CachedStatuses;
import org.mariotaku.twidere.provider.TweetStore.CachedTrends;
import org.mariotaku.twidere.provider.TweetStore.CachedUsers;
import org.mariotaku.twidere.provider.TweetStore.DirectMessages;
import org.mariotaku.twidere.provider.TweetStore.Filters;
import org.mariotaku.twidere.provider.TweetStore.Statuses;
import org.mariotaku.twidere.provider.TweetStore.Tabs;
import org.mariotaku.twidere.util.HtmlLinkExtractor.HtmlLink;
import org.mariotaku.twidere.util.httpclient.HttpClientImpl;

import twitter4j.DirectMessage;
import twitter4j.EntitySupport;
import twitter4j.GeoLocation;
import twitter4j.MediaEntity;
import twitter4j.RateLimitStatus;
import twitter4j.ResponseList;
import twitter4j.Status;
import twitter4j.Trend;
import twitter4j.Trends;
import twitter4j.Twitter;
import twitter4j.TwitterException;
import twitter4j.TwitterFactory;
import twitter4j.URLEntity;
import twitter4j.User;
import twitter4j.UserList;
import twitter4j.auth.AccessToken;
import twitter4j.auth.BasicAuthorization;
import twitter4j.auth.TwipOModeAuthorization;
import twitter4j.conf.Configuration;
import twitter4j.conf.ConfigurationBuilder;
import twitter4j.http.HostAddressResolver;
import twitter4j.http.HttpClientWrapper;
import twitter4j.http.HttpResponse;
import android.app.Activity;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.UriMatcher;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.res.Resources;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PorterDuff.Mode;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.Shader;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.Uri;
import android.os.BatteryManager;
import android.os.Build;
import android.os.Bundle;
import android.provider.BaseColumns;
import android.provider.MediaStore;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.text.format.DateFormat;
import android.text.format.DateUtils;
import android.text.format.Time;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.SubMenu;
import android.widget.Toast;

public final class Utils implements Constants {

    private static final UriMatcher CONTENT_PROVIDER_URI_MATCHER = new UriMatcher(UriMatcher.NO_MATCH);

    private static final UriMatcher LINK_HANDLER_URI_MATCHER = new UriMatcher(UriMatcher.NO_MATCH);

    public static final HashMap<String, Class<? extends Fragment>> CUSTOM_TABS_FRAGMENT_MAP = new HashMap<String, Class<? extends Fragment>>();

    public static final HashMap<String, Integer> CUSTOM_TABS_TYPE_NAME_MAP = new HashMap<String, Integer>();
    public static final HashMap<String, Integer> CUSTOM_TABS_ICON_NAME_MAP = new HashMap<String, Integer>();
    static {
        CONTENT_PROVIDER_URI_MATCHER.addURI(TweetStore.AUTHORITY, TABLE_STATUSES, TABLE_ID_STATUSES);
        CONTENT_PROVIDER_URI_MATCHER.addURI(TweetStore.AUTHORITY, TABLE_ACCOUNTS, TABLE_ID_ACCOUNTS);
        CONTENT_PROVIDER_URI_MATCHER.addURI(TweetStore.AUTHORITY, TABLE_MENTIONS, TABLE_ID_MENTIONS);
        CONTENT_PROVIDER_URI_MATCHER.addURI(TweetStore.AUTHORITY, TABLE_DRAFTS, TABLE_ID_DRAFTS);
        CONTENT_PROVIDER_URI_MATCHER.addURI(TweetStore.AUTHORITY, TABLE_CACHED_USERS, TABLE_ID_CACHED_USERS);
        CONTENT_PROVIDER_URI_MATCHER.addURI(TweetStore.AUTHORITY, TABLE_FILTERED_USERS, TABLE_ID_FILTERED_USERS);
        CONTENT_PROVIDER_URI_MATCHER.addURI(TweetStore.AUTHORITY, TABLE_FILTERED_KEYWORDS,
                TABLE_ID_FILTERED_KEYWORDS);
        CONTENT_PROVIDER_URI_MATCHER.addURI(TweetStore.AUTHORITY, TABLE_FILTERED_SOURCES,
                TABLE_ID_FILTERED_SOURCES);
        CONTENT_PROVIDER_URI_MATCHER.addURI(TweetStore.AUTHORITY, TABLE_FILTERED_LINKS, TABLE_ID_FILTERED_LINKS);
        CONTENT_PROVIDER_URI_MATCHER.addURI(TweetStore.AUTHORITY, TABLE_DIRECT_MESSAGES, TABLE_ID_DIRECT_MESSAGES);
        CONTENT_PROVIDER_URI_MATCHER.addURI(TweetStore.AUTHORITY, TABLE_DIRECT_MESSAGES_INBOX,
                TABLE_ID_DIRECT_MESSAGES_INBOX);
        CONTENT_PROVIDER_URI_MATCHER.addURI(TweetStore.AUTHORITY, TABLE_DIRECT_MESSAGES_OUTBOX,
                TABLE_ID_DIRECT_MESSAGES_OUTBOX);
        CONTENT_PROVIDER_URI_MATCHER.addURI(TweetStore.AUTHORITY, TABLE_DIRECT_MESSAGES_CONVERSATION + "/#/#",
                TABLE_ID_DIRECT_MESSAGES_CONVERSATION);
        CONTENT_PROVIDER_URI_MATCHER.addURI(TweetStore.AUTHORITY,
                TABLE_DIRECT_MESSAGES_CONVERSATION_SCREEN_NAME + "/#/*",
                TABLE_ID_DIRECT_MESSAGES_CONVERSATION_SCREEN_NAME);
        CONTENT_PROVIDER_URI_MATCHER.addURI(TweetStore.AUTHORITY, TABLE_DIRECT_MESSAGES_CONVERSATIONS_ENTRY,
                TABLE_ID_DIRECT_MESSAGES_CONVERSATIONS_ENTRY);
        CONTENT_PROVIDER_URI_MATCHER.addURI(TweetStore.AUTHORITY, TABLE_TRENDS_LOCAL, TABLE_ID_TRENDS_LOCAL);
        CONTENT_PROVIDER_URI_MATCHER.addURI(TweetStore.AUTHORITY, TABLE_TABS, TABLE_ID_TABS);
        CONTENT_PROVIDER_URI_MATCHER.addURI(TweetStore.AUTHORITY, TABLE_CACHED_STATUSES, TABLE_ID_CACHED_STATUSES);
        CONTENT_PROVIDER_URI_MATCHER.addURI(TweetStore.AUTHORITY, TABLE_CACHED_HASHTAGS, TABLE_ID_CACHED_HASHTAGS);
        CONTENT_PROVIDER_URI_MATCHER.addURI(TweetStore.AUTHORITY, TABLE_CACHED_HASHTAGS, TABLE_ID_CACHED_HASHTAGS);
        CONTENT_PROVIDER_URI_MATCHER.addURI(TweetStore.AUTHORITY, TABLE_NOTIFICATIONS + "/#",
                VIRTUAL_TABLE_ID_NOTIFICATIONS);
        CONTENT_PROVIDER_URI_MATCHER.addURI(TweetStore.AUTHORITY, TABLE_CONSUMER_KEY_SECRET,
                VIRTUAL_TABLE_ID_CONSUMER_KEY_SECRET);
        CONTENT_PROVIDER_URI_MATCHER.addURI(TweetStore.AUTHORITY, TABLE_PERMISSIONS, VIRTUAL_TABLE_ID_PERMISSIONS);

        LINK_HANDLER_URI_MATCHER.addURI(AUTHORITY_STATUS, null, LINK_ID_STATUS);
        LINK_HANDLER_URI_MATCHER.addURI(AUTHORITY_USER, null, LINK_ID_USER);
        LINK_HANDLER_URI_MATCHER.addURI(AUTHORITY_USER_TIMELINE, null, LINK_ID_USER_TIMELINE);
        LINK_HANDLER_URI_MATCHER.addURI(AUTHORITY_USER_FOLLOWERS, null, LINK_ID_USER_FOLLOWERS);
        LINK_HANDLER_URI_MATCHER.addURI(AUTHORITY_USER_FRIENDS, null, LINK_ID_USER_FRIENDS);
        LINK_HANDLER_URI_MATCHER.addURI(AUTHORITY_USER_FAVORITES, null, LINK_ID_USER_FAVORITES);
        LINK_HANDLER_URI_MATCHER.addURI(AUTHORITY_USER_BLOCKS, null, LINK_ID_USER_BLOCKS);
        LINK_HANDLER_URI_MATCHER.addURI(AUTHORITY_DIRECT_MESSAGES_CONVERSATION, null,
                LINK_ID_DIRECT_MESSAGES_CONVERSATION);
        LINK_HANDLER_URI_MATCHER.addURI(AUTHORITY_LIST_DETAILS, null, LINK_ID_LIST_DETAILS);
        LINK_HANDLER_URI_MATCHER.addURI(AUTHORITY_LIST_TYPES, null, LINK_ID_LISTS);
        LINK_HANDLER_URI_MATCHER.addURI(AUTHORITY_LIST_TIMELINE, null, LINK_ID_LIST_TIMELINE);
        LINK_HANDLER_URI_MATCHER.addURI(AUTHORITY_LIST_MEMBERS, null, LINK_ID_LIST_MEMBERS);
        LINK_HANDLER_URI_MATCHER.addURI(AUTHORITY_LISTS, null, LINK_ID_LISTS);
        LINK_HANDLER_URI_MATCHER.addURI(AUTHORITY_SAVED_SEARCHES, null, LINK_ID_SAVED_SEARCHES);
        LINK_HANDLER_URI_MATCHER.addURI(AUTHORITY_USER_MENTIONS, null, LINK_ID_USER_MENTIONS);
        LINK_HANDLER_URI_MATCHER.addURI(AUTHORITY_INCOMING_FRIENDSHIPS, null, LINK_ID_INCOMING_FRIENDSHIPS);

        CUSTOM_TABS_FRAGMENT_MAP.put(AUTHORITY_LISTS, UserListsListFragment.class);
        CUSTOM_TABS_FRAGMENT_MAP.put(AUTHORITY_LIST_MEMBERS, UserListMembersFragment.class);
        CUSTOM_TABS_FRAGMENT_MAP.put(AUTHORITY_LISTS, UserListSubscribersFragment.class);
        CUSTOM_TABS_FRAGMENT_MAP.put(AUTHORITY_LIST_TIMELINE, UserListTimelineFragment.class);
        CUSTOM_TABS_FRAGMENT_MAP.put(AUTHORITY_SAVED_SEARCHES, SavedSearchesListFragment.class);
        CUSTOM_TABS_FRAGMENT_MAP.put(AUTHORITY_SEARCH_TWEETS, SearchTweetsFragment.class);
        CUSTOM_TABS_FRAGMENT_MAP.put(AUTHORITY_SEARCH_USERS, SearchUsersFragment.class);
        CUSTOM_TABS_FRAGMENT_MAP.put(AUTHORITY_USER_FAVORITES, UserFavoritesFragment.class);
        CUSTOM_TABS_FRAGMENT_MAP.put(AUTHORITY_USER_FOLLOWERS, UserFollowersFragment.class);
        CUSTOM_TABS_FRAGMENT_MAP.put(AUTHORITY_USER_FRIENDS, UserFriendsFragment.class);
        CUSTOM_TABS_FRAGMENT_MAP.put(AUTHORITY_USER_MENTIONS, UserMentionsFragment.class);
        CUSTOM_TABS_FRAGMENT_MAP.put(AUTHORITY_USER_TIMELINE, UserTimelineFragment.class);
        CUSTOM_TABS_FRAGMENT_MAP.put(AUTHORITY_TRENDS, TrendsFragment.class);
        CUSTOM_TABS_FRAGMENT_MAP.put(AUTHORITY_ACTIVITIES_ABOUT_ME, ActivitiesAboutMeFragment.class);

        CUSTOM_TABS_TYPE_NAME_MAP.put(AUTHORITY_LIST_MEMBERS, R.string.list_members);
        CUSTOM_TABS_TYPE_NAME_MAP.put(AUTHORITY_LISTS, R.string.user_list);
        CUSTOM_TABS_TYPE_NAME_MAP.put(AUTHORITY_LIST_TIMELINE, R.string.list_timeline);
        CUSTOM_TABS_TYPE_NAME_MAP.put(AUTHORITY_SAVED_SEARCHES, R.string.saved_searches);
        CUSTOM_TABS_TYPE_NAME_MAP.put(AUTHORITY_SEARCH_TWEETS, R.string.search_tweets);
        CUSTOM_TABS_TYPE_NAME_MAP.put(AUTHORITY_SEARCH_USERS, R.string.search_users);
        CUSTOM_TABS_TYPE_NAME_MAP.put(AUTHORITY_USER_FAVORITES, R.string.favorites);
        CUSTOM_TABS_TYPE_NAME_MAP.put(AUTHORITY_USER_FOLLOWERS, R.string.followers);
        CUSTOM_TABS_TYPE_NAME_MAP.put(AUTHORITY_USER_FRIENDS, R.string.following);
        CUSTOM_TABS_TYPE_NAME_MAP.put(AUTHORITY_USER_MENTIONS, R.string.user_mentions);
        CUSTOM_TABS_TYPE_NAME_MAP.put(AUTHORITY_USER_TIMELINE, R.string.user_timeline);
        CUSTOM_TABS_TYPE_NAME_MAP.put(AUTHORITY_TRENDS, R.string.trends);
        CUSTOM_TABS_TYPE_NAME_MAP.put(AUTHORITY_ACTIVITIES_ABOUT_ME, R.string.activities_about_me);

        CUSTOM_TABS_ICON_NAME_MAP.put("accounts", R.drawable.ic_tab_accounts);
        CUSTOM_TABS_ICON_NAME_MAP.put("fire", R.drawable.ic_tab_fire);
        CUSTOM_TABS_ICON_NAME_MAP.put("hasmter", R.drawable.ic_tab_hasmter);
        CUSTOM_TABS_ICON_NAME_MAP.put("heart", R.drawable.ic_tab_heart);
        CUSTOM_TABS_ICON_NAME_MAP.put("home", R.drawable.ic_tab_home);
        CUSTOM_TABS_ICON_NAME_MAP.put("list", R.drawable.ic_tab_list);
        CUSTOM_TABS_ICON_NAME_MAP.put("mention", R.drawable.ic_tab_mention);
        CUSTOM_TABS_ICON_NAME_MAP.put("message", R.drawable.ic_tab_message);
        CUSTOM_TABS_ICON_NAME_MAP.put("neko", R.drawable.ic_tab_neko);
        CUSTOM_TABS_ICON_NAME_MAP.put("person", R.drawable.ic_tab_person);
        CUSTOM_TABS_ICON_NAME_MAP.put("pin", R.drawable.ic_tab_pin);
        CUSTOM_TABS_ICON_NAME_MAP.put("ribbon", R.drawable.ic_tab_ribbon);
        CUSTOM_TABS_ICON_NAME_MAP.put("search", R.drawable.ic_tab_search);
        CUSTOM_TABS_ICON_NAME_MAP.put("star", R.drawable.ic_tab_star);
        CUSTOM_TABS_ICON_NAME_MAP.put("trends", R.drawable.ic_tab_trends);
        CUSTOM_TABS_ICON_NAME_MAP.put("twitter", R.drawable.ic_tab_twitter);
        CUSTOM_TABS_ICON_NAME_MAP.put(ICON_SPECIAL_TYPE_CUSTOMIZE, -1);

    }
    private static Map<Long, Integer> sAccountColors = new LinkedHashMap<Long, Integer>();
    private static Map<Long, Integer> sUserColors = new LinkedHashMap<Long, Integer>(512, 0.75f, true);

    private static Map<Long, String> sAccountScreenNames = new LinkedHashMap<Long, String>();
    private static Map<Long, String> sAccountNames = new LinkedHashMap<Long, String>();

    private Utils() {
        throw new AssertionError("You are trying to create an instance for this utility class!");
    }

    public static void addIntentToSubMenu(final Context context, final SubMenu menu, final Intent query_intent) {
        if (context == null || menu == null || query_intent == null)
            return;
        final PackageManager pm = context.getPackageManager();
        final List<ResolveInfo> activities = pm.queryIntentActivities(query_intent, 0);
        for (final ResolveInfo info : activities) {
            final Intent intent = new Intent(query_intent);
            intent.setClassName(info.activityInfo.packageName, info.activityInfo.name);
            menu.add(info.loadLabel(pm)).setIcon(info.loadIcon(pm)).setIntent(intent);
        }
    }

    public static Uri appendQueryParameters(final Uri uri, final NameValuePair... params) {
        final Uri.Builder builder = uri.buildUpon();
        if (params != null) {
            for (final NameValuePair param : params) {
                builder.appendQueryParameter(param.getName(), param.getValue());
            }
        }
        return builder.build();
    }

    public static String buildActivatedStatsWhereClause(final Context context, final String selection) {
        if (context == null)
            return null;
        final long[] account_ids = getActivatedAccountIds(context);
        final StringBuilder builder = new StringBuilder();
        if (selection != null) {
            builder.append(selection);
            builder.append(" AND ");
        }

        builder.append(Statuses.ACCOUNT_ID + " IN ( ");
        builder.append(ArrayUtils.toString(account_ids, ',', true));
        builder.append(" )");

        return builder.toString();
    }

    public static String buildArguments(final Bundle args) {
        final Set<String> keys = args.keySet();
        final JSONObject json = new JSONObject();
        for (final String key : keys) {
            final Object value = args.get(key);
            if (value == null) {
                continue;
            }
            try {
                if (value instanceof Boolean) {
                    json.put(key, args.getBoolean(key));
                } else if (value instanceof Integer) {
                    json.put(key, args.getInt(key));
                } else if (value instanceof Long) {
                    json.put(key, args.getLong(key));
                } else if (value instanceof String) {
                    json.put(key, args.getString(key));
                } else {
                    Log.w(LOGTAG, "Unknown type " + (value != null ? value.getClass().getSimpleName() : null)
                            + " in arguments key " + key);
                }
            } catch (final JSONException e) {
                e.printStackTrace();
            }
        }
        return json.toString();
    }

    public static Uri buildDirectMessageConversationUri(final long account_id, final long conversation_id,
            final String screen_name) {
        if (conversation_id <= 0 && screen_name == null)
            return TweetStore.CONTENT_URI_NULL;
        final Uri.Builder builder = conversation_id > 0 ? DirectMessages.Conversation.CONTENT_URI.buildUpon()
                : DirectMessages.Conversation.CONTENT_URI_SCREEN_NAME.buildUpon();
        builder.appendPath(String.valueOf(account_id));
        builder.appendPath(conversation_id > 0 ? String.valueOf(conversation_id) : screen_name);
        return builder.build();
    }

    public static String buildStatusFilterWhereClause(final String table, final String selection) {
        if (table == null)
            return null;
        final StringBuilder builder = new StringBuilder();
        if (selection != null) {
            builder.append(selection);
            builder.append(" AND ");
        }
        builder.append(Statuses._ID + " NOT IN ( ");
        builder.append("SELECT DISTINCT " + table + "." + Statuses._ID + " FROM " + table);
        builder.append(" WHERE " + table + "." + Statuses.SCREEN_NAME + " IN ( SELECT " + TABLE_FILTERED_USERS + "."
                + Filters.Users.TEXT + " FROM " + TABLE_FILTERED_USERS + " )");
        builder.append(" AND " + table + "." + Statuses.IS_GAP + " IS NULL");
        builder.append(" OR " + table + "." + Statuses.IS_GAP + " == 0");
        builder.append(" UNION ");
        builder.append(
                "SELECT DISTINCT " + table + "." + Statuses._ID + " FROM " + table + ", " + TABLE_FILTERED_SOURCES);
        builder.append(" WHERE " + table + "." + Statuses.SOURCE + " LIKE '%>'||" + TABLE_FILTERED_SOURCES + "."
                + Filters.Sources.TEXT + "||'</a>%'");
        builder.append(" AND " + table + "." + Statuses.IS_GAP + " IS NULL");
        builder.append(" OR " + table + "." + Statuses.IS_GAP + " == 0");
        builder.append(" UNION ");
        builder.append("SELECT DISTINCT " + table + "." + Statuses._ID + " FROM " + table + ", "
                + TABLE_FILTERED_KEYWORDS);
        builder.append(" WHERE " + table + "." + Statuses.TEXT_PLAIN + " LIKE '%'||" + TABLE_FILTERED_KEYWORDS + "."
                + Filters.Keywords.TEXT + "||'%'");
        builder.append(" AND " + table + "." + Statuses.IS_GAP + " IS NULL");
        builder.append(" OR " + table + "." + Statuses.IS_GAP + " == 0");
        builder.append(" UNION ");
        builder.append(
                "SELECT DISTINCT " + table + "." + Statuses._ID + " FROM " + table + ", " + TABLE_FILTERED_LINKS);
        builder.append(" WHERE " + table + "." + Statuses.TEXT + " LIKE '%<a href=\"%'||" + TABLE_FILTERED_LINKS
                + "." + Filters.Links.TEXT + "||'%\">%'");
        builder.append(" OR " + table + "." + Statuses.TEXT + " LIKE '%>%'||" + TABLE_FILTERED_LINKS + "."
                + Filters.Links.TEXT + "||'%</a>%'");
        builder.append(" AND " + table + "." + Statuses.IS_GAP + " IS NULL");
        builder.append(" OR " + table + "." + Statuses.IS_GAP + " == 0");
        builder.append(" )");
        return builder.toString();
    }

    public static boolean bundleEquals(final Bundle bundle1, final Bundle bundle2) {
        if (bundle1 == null || bundle2 == null)
            return bundle1 == bundle2;
        final Iterator<String> keys = bundle1.keySet().iterator();
        while (keys.hasNext()) {
            final String key = keys.next();
            if (!objectEquals(bundle1.get(key), bundle2.get(key)))
                return false;
        }
        return true;
    }

    public static int cancelRetweet(final AsyncTwitterWrapper wrapper, final ParcelableStatus status) {
        if (wrapper == null || status == null)
            return -1;
        if (status.my_retweet_id > 0)
            return wrapper.destroyStatus(status.account_id, status.my_retweet_id);
        else if (status.retweeted_by_id == status.account_id)
            return wrapper.destroyStatus(status.account_id, status.retweet_id);
        return -1;
    }

    public static boolean checkActivityValidity(final Context context, final Intent intent) {
        final PackageManager pm = context.getPackageManager();
        return !pm.queryIntentActivities(intent, 0).isEmpty();
    }

    public static boolean classEquals(final Class<?> cls1, final Class<?> cls2) {
        if (cls1 == null || cls2 == null)
            return cls1 == cls2;
        return cls1.getName().equals(cls2.getName());
    }

    public static synchronized void cleanDatabasesByItemLimit(final Context context) {
        if (context == null)
            return;
        final ContentResolver resolver = context.getContentResolver();
        final int item_limit = context.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE)
                .getInt(PREFERENCE_KEY_DATABASE_ITEM_LIMIT, PREFERENCE_DEFAULT_DATABASE_ITEM_LIMIT);

        for (final long account_id : getAccountIds(context)) {
            // Clean statuses.
            for (final Uri uri : STATUSES_URIS) {
                if (CachedStatuses.CONTENT_URI.equals(uri)) {
                    continue;
                }
                final String table = getTableNameByUri(uri);
                final StringBuilder where = new StringBuilder();
                where.append(Statuses.ACCOUNT_ID + " = " + account_id);
                where.append(" AND ");
                where.append(Statuses._ID + " NOT IN (");
                where.append(" SELECT " + Statuses._ID + " FROM " + table);
                where.append(" WHERE " + Statuses.ACCOUNT_ID + " = " + account_id);
                where.append(" ORDER BY " + Statuses.STATUS_ID + " DESC");
                where.append(" LIMIT " + item_limit + ")");
                resolver.delete(uri, where.toString(), null);
            }
            for (final Uri uri : DIRECT_MESSAGES_URIS) {
                final String table = getTableNameByUri(uri);
                final StringBuilder where = new StringBuilder();
                where.append(DirectMessages.ACCOUNT_ID + " = " + account_id);
                where.append(" AND ");
                where.append(DirectMessages._ID + " NOT IN (");
                where.append(" SELECT " + DirectMessages._ID + " FROM " + table);
                where.append(" WHERE " + DirectMessages.ACCOUNT_ID + " = " + account_id);
                where.append(" ORDER BY " + DirectMessages.MESSAGE_ID + " DESC");
                where.append(" LIMIT " + item_limit + ")");
                resolver.delete(uri, where.toString(), null);
            }
        }
        // Clean cached values.
        for (final Uri uri : CACHE_URIS) {
            final String table = getTableNameByUri(uri);
            final StringBuilder where = new StringBuilder();
            where.append(Statuses._ID + " NOT IN (");
            where.append(" SELECT " + BaseColumns._ID + " FROM " + table);
            where.append(" LIMIT " + (int) (Math.sqrt(item_limit) * 100) + ")");
            resolver.delete(uri, where.toString(), null);
        }
    }

    public static void clearAccountColor() {
        sAccountColors.clear();
    }

    public static void clearAccountName() {
        sAccountScreenNames.clear();
    }

    public static void clearUserColor(final Context context, final long user_id) {
        if (context == null)
            return;
        final SharedPreferences prefs = context.getSharedPreferences(USER_COLOR_PREFERENCES_NAME,
                Context.MODE_PRIVATE);
        final SharedPreferences.Editor editor = prefs.edit();
        editor.remove(Long.toString(user_id));
        editor.commit();
        sUserColors.remove(user_id);
    }

    public static void copyStream(final InputStream is, final OutputStream os) throws IOException {
        final int buffer_size = 8192;
        final byte[] bytes = new byte[buffer_size];
        int count = is.read(bytes, 0, buffer_size);
        while (count != -1) {
            os.write(bytes, 0, count);
            count = is.read(bytes, 0, buffer_size);
        }
    }

    public static Bitmap createAlphaGradientBanner(final Bitmap orig) {
        if (orig == null)
            return null;
        final int width = orig.getWidth(), height = orig.getHeight();
        final Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
        final Canvas canvas = new Canvas(bitmap);
        final Paint paint = new Paint();
        final LinearGradient shader = new LinearGradient(width / 2, 0, width / 2, height, 0xffffffff, 0x00ffffff,
                Shader.TileMode.CLAMP);
        paint.setShader(shader);
        paint.setXfermode(new PorterDuffXfermode(Mode.DST_IN));
        canvas.drawBitmap(orig, 0, 0, null);
        canvas.drawRect(0, 0, width, height, paint);
        return bitmap;
    }

    public static Intent createPickImageIntent(final Uri uri) {
        final Intent intent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
        intent.setType("image/*");
        return intent;
    }

    public static Intent createPickImageIntent(final Uri uri, final Integer outputX, final Integer outputY,
            final Integer aspectX, final Integer aspectY, final boolean scaleUpIfNeeded) {
        final Intent intent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
        intent.setType("image/*");
        if (outputX != null && outputY != null) {
            intent.putExtra(CameraCropActivity.EXTRA_OUTPUT_X, outputX);
            intent.putExtra(CameraCropActivity.EXTRA_OUTPUT_Y, outputY);
        }
        if (aspectX != null && aspectY != null) {
            intent.putExtra(CameraCropActivity.EXTRA_ASPECT_X, aspectX);
            intent.putExtra(CameraCropActivity.EXTRA_ASPECT_Y, aspectY);
        }
        intent.putExtra("scale", true);
        intent.putExtra("scaleUpIfNeeded", scaleUpIfNeeded);
        intent.putExtra("crop", "true");
        intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
        return intent;
    }

    public static Intent createTakePhotoIntent(final Uri uri) {
        final Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
        return intent;
    }

    public static Intent createTakePhotoIntent(final Uri uri, final Integer outputX, final Integer outputY,
            final Integer aspectX, final Integer aspectY, final boolean scaleUpIfNeeded) {
        final Intent intent = new Intent(CameraCropActivity.INTENT_ACTION);
        intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
        if (outputX != null && outputY != null) {
            intent.putExtra(CameraCropActivity.EXTRA_OUTPUT_X, outputX);
            intent.putExtra(CameraCropActivity.EXTRA_OUTPUT_Y, outputY);
        }
        if (aspectX != null && aspectY != null) {
            intent.putExtra(CameraCropActivity.EXTRA_ASPECT_X, aspectX);
            intent.putExtra(CameraCropActivity.EXTRA_ASPECT_Y, aspectY);
        }
        intent.putExtra(CameraCropActivity.EXTRA_SCALE_UP_IF_NEEDED, scaleUpIfNeeded);
        return intent;
    }

    public static boolean equals(final Object object1, final Object object2) {
        if (object1 == null || object2 == null)
            return object1 == object2;
        return object1.equals(object2);
    }

    public static ParcelableDirectMessage findDirectMessageInDatabases(final Context context, final long account_id,
            final long message_id) {
        if (context == null)
            return null;
        final ContentResolver resolver = context.getContentResolver();
        ParcelableDirectMessage message = null;
        final String where = DirectMessages.ACCOUNT_ID + " = " + account_id + " AND " + DirectMessages.MESSAGE_ID
                + " = " + message_id;
        for (final Uri uri : DIRECT_MESSAGES_URIS) {
            final Cursor cur = resolver.query(uri, DirectMessages.COLUMNS, where, null, null);
            if (cur == null) {
                continue;
            }
            if (cur.getCount() > 0) {
                cur.moveToFirst();
                message = new ParcelableDirectMessage(cur, new DirectMessageCursorIndices(cur));
            }
            cur.close();
        }
        return message;
    }

    public static ParcelableStatus findStatus(final Context context, final long account_id, final long status_id)
            throws TwitterException {
        if (context == null || account_id <= 0 || status_id <= 0)
            return null;
        final ParcelableStatus p_status = findStatusInDatabases(context, account_id, status_id);
        if (p_status != null)
            return p_status;
        final Twitter twitter = getTwitterInstance(context, account_id, true);
        if (twitter == null)
            return null;
        final Status status = twitter.showStatus(status_id);
        if (status == null || status.getId() <= 0)
            return null;
        final String where = Statuses.ACCOUNT_ID + " = " + account_id + " AND " + Statuses.STATUS_ID + " = "
                + status.getId();
        final ContentResolver resolver = context.getContentResolver();
        final boolean large_profile_image = context.getResources().getBoolean(R.bool.hires_profile_image);
        resolver.delete(CachedStatuses.CONTENT_URI, where, null);
        resolver.insert(CachedStatuses.CONTENT_URI,
                makeStatusContentValues(status, account_id, large_profile_image));
        return new ParcelableStatus(status, account_id, false, large_profile_image, true);
    }

    public static ParcelableStatus findStatusInDatabases(final Context context, final long account_id,
            final long status_id) {
        if (context == null)
            return null;
        final ContentResolver resolver = context.getContentResolver();
        ParcelableStatus status = null;
        final String where = Statuses.ACCOUNT_ID + " = " + account_id + " AND " + Statuses.STATUS_ID + " = "
                + status_id;
        for (final Uri uri : STATUSES_URIS) {
            final Cursor cur = resolver.query(uri, Statuses.COLUMNS, where, null, null);
            if (cur == null) {
                continue;
            }
            if (cur.getCount() > 0) {
                cur.moveToFirst();
                status = new ParcelableStatus(cur, new StatusCursorIndices(cur));
            }
            cur.close();
        }
        return status;
    }

    public static UserList findUserList(final Twitter twitter, final long user_id, final String list_name)
            throws TwitterException {
        if (twitter == null || user_id <= 0 || list_name == null)
            return null;
        final ResponseList<UserList> response = twitter.getUserLists(user_id);
        for (final UserList list : response) {
            if (list_name.equals(list.getName()))
                return list;
        }
        return null;
    }

    public static UserList findUserList(final Twitter twitter, final long user_id, final String screen_name,
            final String list_name) throws TwitterException {
        if (user_id > 0)
            return findUserList(twitter, user_id, list_name);
        else if (screen_name != null)
            return findUserList(twitter, screen_name, list_name);
        return null;
    }

    public static UserList findUserList(final Twitter twitter, final String screen_name, final String list_name)
            throws TwitterException {
        if (twitter == null || screen_name == null || list_name == null)
            return null;
        final ResponseList<UserList> response = twitter.getUserLists(screen_name);
        for (final UserList list : response) {
            if (list_name.equals(list.getName()) && list.getUser() != null
                    && screen_name.equals(list.getUser().getScreenName()))
                return list;
        }
        return null;
    }

    public static String formatDirectMessageText(final DirectMessage message) {
        if (message == null)
            return null;
        final String raw_text = message.getRawText();
        if (raw_text == null)
            return null;
        final HtmlBuilder builder = new HtmlBuilder(raw_text.replace("\n", "<br/>"), false, false, false);
        parseEntities(builder, message);
        return builder.build();
    }

    @SuppressWarnings("deprecation")
    public static String formatSameDayTime(final Context context, final long timestamp) {
        if (context == null)
            return null;
        if (DateUtils.isToday(timestamp))
            return DateUtils.formatDateTime(context, timestamp,
                    DateFormat.is24HourFormat(context) ? DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_24HOUR
                            : DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_12HOUR);
        return DateUtils.formatDateTime(context, timestamp, DateUtils.FORMAT_SHOW_DATE);
    }

    public static String formatStatusText(final Status status) {
        if (status == null)
            return null;
        final String raw_text = status.getRawText();
        if (raw_text == null)
            return null;
        final HtmlBuilder builder = new HtmlBuilder(raw_text.replace("\n", "<br/>"), false, false, false);
        parseEntities(builder, status);
        return builder.build();
    }

    @SuppressWarnings("deprecation")
    public static String formatTimeStampString(final Context context, final long timestamp) {
        if (context == null)
            return null;
        final Time then = new Time();
        then.set(timestamp);
        final Time now = new Time();
        now.setToNow();

        int format_flags = DateUtils.FORMAT_NO_NOON_MIDNIGHT | DateUtils.FORMAT_ABBREV_ALL
                | DateUtils.FORMAT_CAP_AMPM;

        if (then.year != now.year) {
            format_flags |= DateUtils.FORMAT_SHOW_YEAR | DateUtils.FORMAT_SHOW_DATE;
        } else if (then.yearDay != now.yearDay) {
            format_flags |= DateUtils.FORMAT_SHOW_DATE;
        } else {
            format_flags |= DateUtils.FORMAT_SHOW_TIME;
        }

        return DateUtils.formatDateTime(context, timestamp, format_flags);
    }

    @SuppressWarnings("deprecation")
    public static String formatTimeStampString(final Context context, final String date_time) {
        if (context == null)
            return null;
        return formatTimeStampString(context, Date.parse(date_time));
    }

    @SuppressWarnings("deprecation")
    public static String formatToLongTimeString(final Context context, final long timestamp) {
        if (context == null)
            return null;
        final Time then = new Time();
        then.set(timestamp);
        final Time now = new Time();
        now.setToNow();

        int format_flags = DateUtils.FORMAT_NO_NOON_MIDNIGHT | DateUtils.FORMAT_ABBREV_ALL
                | DateUtils.FORMAT_CAP_AMPM;

        format_flags |= DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_TIME;

        return DateUtils.formatDateTime(context, timestamp, format_flags);
    }

    public static int getAccountColor(final Context context, final long account_id) {
        if (context == null)
            return Color.TRANSPARENT;
        Integer color = sAccountColors.get(account_id);
        if (color == null) {
            final Cursor cur = context.getContentResolver().query(Accounts.CONTENT_URI,
                    new String[] { Accounts.USER_COLOR }, Accounts.ACCOUNT_ID + " = " + account_id, null, null);
            if (cur == null)
                return Color.TRANSPARENT;
            if (cur.getCount() <= 0) {
                cur.close();
                return Color.TRANSPARENT;
            }
            cur.moveToFirst();
            sAccountColors.put(account_id, color = cur.getInt(cur.getColumnIndexOrThrow(Accounts.USER_COLOR)));
            cur.close();
        }
        return color;
    }

    public static int[] getAccountColors(final Context context, final long[] account_ids) {
        if (context == null || account_ids == null)
            return null;
        final int length = account_ids.length;
        final int[] colors = new int[length];
        for (int i = 0; i < length; i++) {
            colors[i] = getAccountColor(context, account_ids[i]);
        }
        return colors;
    }

    public static long getAccountId(final Context context, final String screen_name) {
        if (context == null)
            return -1;
        long user_id = -1;

        final Cursor cur = context.getContentResolver().query(Accounts.CONTENT_URI,
                new String[] { Accounts.ACCOUNT_ID }, Accounts.SCREEN_NAME + " = ?", new String[] { screen_name },
                null);
        if (cur == null)
            return user_id;

        if (cur.getCount() > 0) {
            cur.moveToFirst();
            user_id = cur.getLong(cur.getColumnIndexOrThrow(Accounts.ACCOUNT_ID));
        }
        cur.close();
        return user_id;
    }

    public static long[] getAccountIds(final Context context) {
        long[] accounts = new long[0];
        if (context == null)
            return accounts;
        final Cursor cur = context.getContentResolver().query(Accounts.CONTENT_URI,
                new String[] { Accounts.ACCOUNT_ID }, null, null, null);
        if (cur != null) {
            final int idx = cur.getColumnIndexOrThrow(Accounts.ACCOUNT_ID);
            cur.moveToFirst();
            accounts = new long[cur.getCount()];
            int i = 0;
            while (!cur.isAfterLast()) {
                accounts[i] = cur.getLong(idx);
                i++;
                cur.moveToNext();
            }
            cur.close();
        }
        return accounts;
    }

    public static String getAccountName(final Context context, final long account_id) {
        if (context == null)
            return null;
        String name = sAccountNames.get(account_id);
        if (name == null) {
            final Cursor cur = context.getContentResolver().query(Accounts.CONTENT_URI,
                    new String[] { Accounts.NAME }, Accounts.ACCOUNT_ID + " = " + account_id, null, null);
            if (cur == null)
                return name;

            if (cur.getCount() > 0) {
                cur.moveToFirst();
                name = cur.getString(cur.getColumnIndex(Accounts.NAME));
                sAccountNames.put(account_id, name);
            }
            cur.close();
        }
        return name;
    }

    public static String getAccountScreenName(final Context context, final long account_id) {
        if (context == null)
            return null;
        String screen_name = sAccountScreenNames.get(account_id);
        if (screen_name == null) {
            final Cursor cur = context.getContentResolver().query(Accounts.CONTENT_URI,
                    new String[] { Accounts.SCREEN_NAME }, Accounts.ACCOUNT_ID + " = " + account_id, null, null);
            if (cur == null)
                return screen_name;

            if (cur.getCount() > 0) {
                cur.moveToFirst();
                screen_name = cur.getString(cur.getColumnIndex(Accounts.SCREEN_NAME));
                sAccountScreenNames.put(account_id, screen_name);
            }
            cur.close();
        }
        return screen_name;
    }

    public static String[] getAccountScreenNames(final Context context) {
        String[] accounts = new String[0];
        if (context == null)
            return accounts;
        final String[] cols = new String[] { Accounts.SCREEN_NAME };
        final Cursor cur = context.getContentResolver().query(Accounts.CONTENT_URI, cols, null, null, null);
        if (cur != null) {
            final int idx = cur.getColumnIndexOrThrow(Accounts.SCREEN_NAME);
            cur.moveToFirst();
            accounts = new String[cur.getCount()];
            int i = 0;
            while (!cur.isAfterLast()) {
                accounts[i] = cur.getString(idx);
                i++;
                cur.moveToNext();
            }
            cur.close();
        }
        return accounts;
    }

    public static long[] getActivatedAccountIds(final Context context) {
        long[] accounts = new long[0];
        if (context == null)
            return accounts;
        final String[] cols = new String[] { Accounts.ACCOUNT_ID };
        final Cursor cur = context.getContentResolver().query(Accounts.CONTENT_URI, cols,
                Accounts.IS_ACTIVATED + "=1", null, Accounts.ACCOUNT_ID);
        if (cur != null) {
            final int idx = cur.getColumnIndexOrThrow(Accounts.ACCOUNT_ID);
            cur.moveToFirst();
            accounts = new long[cur.getCount()];
            int i = 0;
            while (!cur.isAfterLast()) {
                accounts[i] = cur.getLong(idx);
                i++;
                cur.moveToNext();
            }
            cur.close();
        }
        return accounts;
    }

    public static String[] getActivatedAccountScreenNames(final Context context) {
        String[] accounts = new String[0];
        if (context == null)
            return accounts;
        final String[] cols = new String[] { Accounts.SCREEN_NAME };
        final Cursor cur = context.getContentResolver().query(Accounts.CONTENT_URI, cols,
                Accounts.IS_ACTIVATED + "=1", null, null);
        if (cur != null) {
            final int idx = cur.getColumnIndexOrThrow(Accounts.SCREEN_NAME);
            cur.moveToFirst();
            accounts = new String[cur.getCount()];
            int i = 0;
            while (!cur.isAfterLast()) {
                accounts[i] = cur.getString(idx);
                i++;
                cur.moveToNext();
            }
            cur.close();
        }
        return accounts;
    }

    public static ImageSpec getAllAvailableImage(final String link) {
        if (link == null)
            return null;
        Matcher m;
        m = PATTERN_TWITTER_IMAGES.matcher(link);
        if (m.matches())
            return getTwitterImage(link, true);
        m = PATTERN_TWITPIC.matcher(link);
        if (m.matches())
            return getTwitpicImage(matcherGroup(m, TWITPIC_GROUP_ID), true);
        m = PATTERN_INSTAGRAM.matcher(link);
        if (m.matches())
            return getInstagramImage(matcherGroup(m, INSTAGRAM_GROUP_ID), true);
        m = PATTERN_IMGUR.matcher(link);
        if (m.matches())
            return getImgurImage(matcherGroup(m, IMGUR_GROUP_ID), true);
        m = PATTERN_IMGLY.matcher(link);
        if (m.matches())
            return getImglyImage(matcherGroup(m, IMGLY_GROUP_ID), true);
        m = PATTERN_YFROG.matcher(link);
        if (m.matches())
            return getYfrogImage(matcherGroup(m, YFROG_GROUP_ID), true);
        m = PATTERN_LOCKERZ_AND_PLIXI.matcher(link);
        if (m.matches())
            return getLockerzAndPlixiImage(link, true);
        m = PATTERN_SINA_WEIBO_IMAGES.matcher(link);
        if (m.matches())
            return getSinaWeiboImage(link, true);
        m = PATTERN_TWITGOO.matcher(link);
        if (m.matches())
            return getTwitgooImage(matcherGroup(m, TWITGOO_GROUP_ID), true);
        m = PATTERN_MOBYPICTURE.matcher(link);
        if (m.matches())
            return getMobyPictureImage(matcherGroup(m, MOBYPICTURE_GROUP_ID), true);
        m = PATTERN_PHOTOZOU.matcher(link);
        if (m.matches())
            return getPhotozouImage(matcherGroup(m, PHOTOZOU_GROUP_ID), true);
        return null;
    }

    public static int getAllStatusesCount(final Context context, final Uri uri) {
        if (context == null)
            return 0;
        final ContentResolver resolver = context.getContentResolver();
        final Cursor cur = resolver.query(uri, new String[] { Statuses.STATUS_ID },
                buildStatusFilterWhereClause(getTableNameByUri(uri), null), null, null);
        if (cur == null)
            return 0;
        try {
            return cur.getCount();
        } finally {
            cur.close();
        }
    }

    public static long[] getAllStatusesIds(final Context context, final Uri uri) {
        if (context == null)
            return new long[0];
        final ContentResolver resolver = context.getContentResolver();
        final Cursor cur = resolver.query(uri, new String[] { Statuses.STATUS_ID },
                buildStatusFilterWhereClause(getTableNameByUri(uri), null), null, null);
        if (cur == null)
            return new long[0];
        final long[] ids = new long[cur.getCount()];
        cur.moveToFirst();
        int i = 0;
        while (!cur.isAfterLast()) {
            ids[i] = cur.getLong(0);
            cur.moveToNext();
            i++;
        }
        cur.close();
        return ids;
    }

    public static boolean getAsBoolean(final ContentValues values, final String key, final boolean def) {
        if (values == null || key == null)
            return def;
        final Object value = values.get(key);
        if (value == null)
            return def;
        return Boolean.valueOf(value.toString());
    }

    public static long getAsInteger(final ContentValues values, final String key, final int def) {
        if (values == null || key == null)
            return def;
        final Object value = values.get(key);
        if (value == null)
            return def;
        return Integer.valueOf(value.toString());
    }

    public static long getAsLong(final ContentValues values, final String key, final long def) {
        if (values == null || key == null)
            return def;
        final Object value = values.get(key);
        if (value == null)
            return def;
        return Long.valueOf(value.toString());
    }

    public static String getBestBannerType(final int width) {
        if (width <= 320)
            return "mobile";
        else if (width <= 520)
            return "web";
        else if (width <= 626)
            return "ipad";
        else if (width <= 640)
            return "mobile_retina";
        else if (width <= 1040)
            return "web_retina";
        else
            return "ipad_retina";
    }

    public static File getBestCacheDir(final Context context, final String cache_dir_name) {
        final File ext_cache_dir = EnvironmentAccessor.getExternalCacheDir(context);
        if (ext_cache_dir != null && ext_cache_dir.isDirectory()) {
            final File cache_dir = new File(ext_cache_dir, cache_dir_name);
            if (cache_dir.isDirectory() || cache_dir.mkdirs())
                return cache_dir;
        }
        return new File(context.getCacheDir(), cache_dir_name);
    }

    public static String getBiggerTwitterProfileImage(final String url) {
        if (url == null)
            return null;
        if (PATTERN_TWITTER_PROFILE_IMAGES.matcher(url).matches())
            return replaceLast(url, "_" + TWITTER_PROFILE_IMAGES_AVAILABLE_SIZES, "_bigger");
        return url;
    }

    public static String getBrowserUserAgent(final Context context) {
        if (context == null)
            return null;
        return TwidereApplication.getInstance(context).getBrowserUserAgent();
    }

    public static Bitmap getColorPreviewBitmap(final Context context, final int color) {
        if (context == null)
            return null;
        final float density = context.getResources().getDisplayMetrics().density;
        final int width = (int) (32 * density), height = (int) (32 * density);

        final Bitmap bm = Bitmap.createBitmap(width, height, Config.ARGB_8888);
        final Canvas canvas = new Canvas(bm);

        final int rectrangle_size = (int) (density * 5);
        final int numRectanglesHorizontal = (int) Math.ceil(width / rectrangle_size);
        final int numRectanglesVertical = (int) Math.ceil(height / rectrangle_size);
        final Rect r = new Rect();
        boolean verticalStartWhite = true;
        for (int i = 0; i <= numRectanglesVertical; i++) {

            boolean isWhite = verticalStartWhite;
            for (int j = 0; j <= numRectanglesHorizontal; j++) {

                r.top = i * rectrangle_size;
                r.left = j * rectrangle_size;
                r.bottom = r.top + rectrangle_size;
                r.right = r.left + rectrangle_size;
                final Paint paint = new Paint();
                paint.setColor(isWhite ? Color.WHITE : Color.GRAY);

                canvas.drawRect(r, paint);

                isWhite = !isWhite;
            }

            verticalStartWhite = !verticalStartWhite;

        }
        canvas.drawColor(color);
        final Paint paint = new Paint();
        paint.setColor(Color.WHITE);
        paint.setStrokeWidth(2.0f);
        final float[] points = new float[] { 0, 0, width, 0, 0, 0, 0, height, width, 0, width, height, 0, height,
                width, height };
        canvas.drawLines(points, paint);

        return bm;
    }

    public static long getDefaultAccountId(final Context context) {
        if (context == null)
            return -1;
        final SharedPreferences prefs = context.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE);
        return prefs.getLong(PREFERENCE_KEY_DEFAULT_ACCOUNT_ID, -1);
    }

    public static String getDefaultAccountScreenName(final Context context) {
        if (context == null)
            return null;
        return getAccountScreenName(context, getDefaultAccountId(context));
    }

    public static Twitter getDefaultTwitterInstance(final Context context, final boolean include_entities) {
        if (context == null)
            return null;
        return getDefaultTwitterInstance(context, include_entities, true);
    }

    public static Twitter getDefaultTwitterInstance(final Context context, final boolean include_entities,
            final boolean use_httpclient) {
        if (context == null)
            return null;
        return getTwitterInstance(context, getDefaultAccountId(context), include_entities, use_httpclient);
    }

    public static HttpClientWrapper getHttpClient(final int timeout_millis, final boolean ignore_ssl_error,
            final Proxy proxy, final HostAddressResolver resolver, final String user_agent) {
        final ConfigurationBuilder cb = new ConfigurationBuilder();
        cb.setHttpConnectionTimeout(timeout_millis);
        cb.setIgnoreSSLError(ignore_ssl_error);
        if (proxy != null && !Proxy.NO_PROXY.equals(proxy)) {
            final SocketAddress address = proxy.address();
            if (address instanceof InetSocketAddress) {
                cb.setHttpProxyHost(((InetSocketAddress) address).getHostName());
                cb.setHttpProxyPort(((InetSocketAddress) address).getPort());
            }
        }
        cb.setHostAddressResolver(resolver);
        if (user_agent != null) {
            cb.setUserAgent(user_agent);
        }
        // cb.setHttpClientImplementation(HttpClientImpl.class);
        return new HttpClientWrapper(cb.build());
    }

    public static HttpClientWrapper getImageLoaderHttpClient(final Context context) {
        if (context == null)
            return null;
        final SharedPreferences prefs = context.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE);
        final int timeout_millis = prefs.getInt(PREFERENCE_KEY_CONNECTION_TIMEOUT, 10000) * 1000;
        final Proxy proxy = getProxy(context);
        final String user_agent = getBrowserUserAgent(context);
        // final HostAddressResolver resolver =
        // TwidereApplication.getInstance(context).getHostAddressResolver();
        final HostAddressResolver resolver = null;
        return getHttpClient(timeout_millis, true, proxy, resolver, user_agent);
    }

    public static String getImagePathFromUri(final Context context, final Uri uri) {
        if (context == null || uri == null)
            return null;

        final String media_uri_start = parseString(MediaStore.Images.Media.EXTERNAL_CONTENT_URI);

        if (parseString(uri).startsWith(media_uri_start)) {

            final String[] proj = { MediaStore.Images.Media.DATA };
            final Cursor cur = context.getContentResolver().query(uri, proj, null, null, null);

            if (cur == null)
                return null;

            final int column_index = cur.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);

            cur.moveToFirst();
            try {
                return cur.getString(column_index);
            } finally {
                cur.close();
            }
        } else {
            final String path = uri.getPath();
            if (path != null) {
                if (new File(path).exists())
                    return path;
            }
        }
        return null;
    }

    public static List<ImageSpec> getImagesInStatus(final String status_string) {
        if (status_string == null)
            return Collections.emptyList();
        final List<ImageSpec> images = new ArrayList<ImageSpec>();
        final HtmlLinkExtractor extractor = new HtmlLinkExtractor();
        extractor.grabLinks(status_string);
        for (final HtmlLink link : extractor.grabLinks(status_string)) {
            final ImageSpec spec = getAllAvailableImage(link.getLink());
            if (spec != null) {
                images.add(spec);
            }
        }
        return images;
    }

    public static String getImageUploadStatus(final Context context, final String link, final String text) {
        if (context == null)
            return null;
        String image_upload_format = context.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE)
                .getString(PREFERENCE_KEY_IMAGE_UPLOAD_FORMAT, PREFERENCE_DEFAULT_IMAGE_UPLOAD_FORMAT);
        if (isEmpty(image_upload_format)) {
            image_upload_format = PREFERENCE_DEFAULT_IMAGE_UPLOAD_FORMAT;
        }
        if (link == null)
            return text;
        return image_upload_format.replace(FORMAT_PATTERN_LINK, link).replace(FORMAT_PATTERN_TEXT, text);
    }

    public static ImageSpec getImglyImage(final String id, final boolean large_image_preview) {
        if (isEmpty(id))
            return null;
        final String full = "https://img.ly/show/full/" + id;
        final String preview = "https://img.ly/show/" + (large_image_preview ? "medium" : "thumb") + "/" + id;
        return new ImageSpec(preview, full);

    }

    public static ImageSpec getImgurImage(final String id, final boolean large_image_preview) {
        if (isEmpty(id))
            return null;
        final String full = "http://i.imgur.com/" + id + ".jpg";
        final String preview = "http://i.imgur.com/" + id + (large_image_preview ? "l.jpg" : "s.jpg");
        return new ImageSpec(preview, full);
    }

    public static int getInlineImagePreviewDisplayOptionInt(final Context context) {
        if (context == null)
            return INLINE_IMAGE_PREVIEW_DISPLAY_OPTION_CODE_NONE;
        final SharedPreferences prefs = context.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE);
        final String option = prefs.getString(PREFERENCE_KEY_INLINE_IMAGE_PREVIEW_DISPLAY_OPTION,
                INLINE_IMAGE_PREVIEW_DISPLAY_OPTION_NONE);
        return getInlineImagePreviewDisplayOptionInt(option);
    }

    public static int getInlineImagePreviewDisplayOptionInt(final String option) {
        if (INLINE_IMAGE_PREVIEW_DISPLAY_OPTION_LARGE.equals(option))
            return INLINE_IMAGE_PREVIEW_DISPLAY_OPTION_CODE_LARGE;
        else if (INLINE_IMAGE_PREVIEW_DISPLAY_OPTION_SMALL.equals(option))
            return INLINE_IMAGE_PREVIEW_DISPLAY_OPTION_CODE_SMALL;
        return INLINE_IMAGE_PREVIEW_DISPLAY_OPTION_CODE_NONE;
    }

    public static ImageSpec getInstagramImage(final String id, final boolean large_image_preview) {
        if (isEmpty(id))
            return null;
        final String full = "https://instagr.am/p/" + id + "/media/?size=l";
        final String preview = large_image_preview ? full : "https://instagr.am/p/" + id + "/media/?size=t";
        return new ImageSpec(preview, full);
    }

    public static ImageSpec getLockerzAndPlixiImage(final String url, final boolean large_image_preview) {
        if (isEmpty(url))
            return null;
        final String full = "https://api.plixi.com/api/tpapi.svc/imagefromurl?url=" + url + "&size=big";
        final String preview = large_image_preview ? full
                : "https://api.plixi.com/api/tpapi.svc/imagefromurl?url=" + url + "&size=small";
        return new ImageSpec(preview, full);

    }

    public static ImageSpec getMobyPictureImage(final String id, final boolean large_image_preview) {
        if (isEmpty(id))
            return null;
        final String full = "https://moby.to/" + id + ":full";
        final String preview = large_image_preview ? full : "https://moby.to/" + id + ":thumb";
        return new ImageSpec(preview, full);
    }

    public static int getNameDisplayOptionInt(final String option) {
        if (NAME_DISPLAY_OPTION_NAME.equals(option))
            return NAME_DISPLAY_OPTION_CODE_NAME;
        else if (NAME_DISPLAY_OPTION_SCREEN_NAME.equals(option))
            return NAME_DISPLAY_OPTION_CODE_SCREEN_NAME;
        return NAME_DISPLAY_OPTION_CODE_BOTH;
    }

    public static long[] getNewestMessageIdsFromDatabase(final Context context, final Uri uri) {
        if (context == null || uri == null)
            return null;
        final long[] account_ids = getActivatedAccountIds(context);
        final String[] cols = new String[] { DirectMessages.MESSAGE_ID };
        final ContentResolver resolver = context.getContentResolver();
        final long[] status_ids = new long[account_ids.length];
        int idx = 0;
        for (final long account_id : account_ids) {
            final String where = Statuses.ACCOUNT_ID + " = " + account_id;
            final Cursor cur = resolver.query(uri, cols, where, null, DirectMessages.DEFAULT_SORT_ORDER);
            if (cur == null) {
                continue;
            }

            if (cur.getCount() > 0) {
                cur.moveToFirst();
                status_ids[idx] = cur.getLong(cur.getColumnIndexOrThrow(DirectMessages.MESSAGE_ID));
            }
            cur.close();
            idx++;
        }
        return status_ids;
    }

    public static long[] getNewestStatusIdsFromDatabase(final Context context, final Uri uri) {
        if (context == null || uri == null)
            return null;
        final long[] account_ids = getActivatedAccountIds(context);
        final String[] cols = new String[] { Statuses.STATUS_ID };
        final ContentResolver resolver = context.getContentResolver();
        final long[] status_ids = new long[account_ids.length];
        int idx = 0;
        for (final long account_id : account_ids) {
            final String where = Statuses.ACCOUNT_ID + " = " + account_id;
            final Cursor cur = resolver.query(uri, cols, where, null, Statuses.DEFAULT_SORT_ORDER);
            if (cur == null) {
                continue;
            }

            if (cur.getCount() > 0) {
                cur.moveToFirst();
                status_ids[idx] = cur.getLong(cur.getColumnIndexOrThrow(Statuses.STATUS_ID));
            }
            cur.close();
            idx++;
        }
        return status_ids;
    }

    public static String getNormalTwitterProfileImage(final String url) {
        if (url == null)
            return null;
        if (PATTERN_TWITTER_PROFILE_IMAGES.matcher(url).matches())
            return replaceLast(url, "_" + TWITTER_PROFILE_IMAGES_AVAILABLE_SIZES, "_normal");
        return url;
    }

    public static long[] getOldestMessageIdsFromDatabase(final Context context, final Uri uri) {
        if (context == null || uri == null)
            return null;
        final long[] account_ids = getActivatedAccountIds(context);
        final String[] cols = new String[] { DirectMessages.MESSAGE_ID };
        final ContentResolver resolver = context.getContentResolver();
        final long[] status_ids = new long[account_ids.length];
        int idx = 0;
        for (final long account_id : account_ids) {
            final String where = Statuses.ACCOUNT_ID + " = " + account_id;
            final Cursor cur = resolver.query(uri, cols, where, null, DirectMessages.MESSAGE_ID);
            if (cur == null) {
                continue;
            }

            if (cur.getCount() > 0) {
                cur.moveToFirst();
                status_ids[idx] = cur.getLong(cur.getColumnIndexOrThrow(DirectMessages.MESSAGE_ID));
            }
            cur.close();
            idx++;
        }
        return status_ids;
    }

    public static long[] getOldestStatusIdsFromDatabase(final Context context, final Uri uri) {
        if (context == null || uri == null)
            return null;
        final long[] account_ids = getActivatedAccountIds(context);
        final String[] cols = new String[] { Statuses.STATUS_ID };
        final ContentResolver resolver = context.getContentResolver();
        final long[] status_ids = new long[account_ids.length];
        int idx = 0;
        for (final long account_id : account_ids) {
            final String where = Statuses.ACCOUNT_ID + " = " + account_id;
            final Cursor cur = resolver.query(uri, cols, where, null, Statuses.STATUS_ID);
            if (cur == null) {
                continue;
            }

            if (cur.getCount() > 0) {
                cur.moveToFirst();
                status_ids[idx] = cur.getLong(cur.getColumnIndexOrThrow(Statuses.STATUS_ID));
            }
            cur.close();
            idx++;
        }
        return status_ids;
    }

    public static String getOriginalTwitterProfileImage(final String url) {
        if (url == null)
            return null;
        if (PATTERN_TWITTER_PROFILE_IMAGES.matcher(url).matches())
            return replaceLast(url, "_" + TWITTER_PROFILE_IMAGES_AVAILABLE_SIZES, "");
        return url;
    }

    public static ImageSpec getPhotozouImage(final String id, final boolean large_image_preview) {
        if (isEmpty(id))
            return null;
        final String full = "http://photozou.jp/p/img/" + id;
        final String preview = large_image_preview ? full : "http://photozou.jp/p/thumb/" + id;
        return new ImageSpec(preview, full);
    }

    public static PreviewImage getPreviewImage(final String html, final int display_option) {
        if (html == null)
            return new PreviewImage(false, null, null);
        if (display_option == INLINE_IMAGE_PREVIEW_DISPLAY_OPTION_CODE_NONE)
            return new PreviewImage(html.contains(".twimg.com/") || html.contains("://instagr.am/")
                    || html.contains("://instagram.com/") || html.contains("://imgur.com/")
                    || html.contains("://i.imgur.com/") || html.contains("://twitpic.com/")
                    || html.contains("://img.ly/") || html.contains("://yfrog.com/")
                    || html.contains("://twitgoo.com/") || html.contains("://moby.to/")
                    || html.contains("://plixi.com/p/") || html.contains("://lockerz.com/s/")
                    || html.contains(".sinaimg.cn/") || html.contains("://photozou.jp/"), null, null);
        final boolean large_image_preview = display_option == INLINE_IMAGE_PREVIEW_DISPLAY_OPTION_CODE_LARGE;
        final HtmlLinkExtractor extractor = new HtmlLinkExtractor();
        for (final HtmlLink link : extractor.grabLinks(html)) {
            final String image_url = link.getLink();
            Matcher m;
            m = PATTERN_TWITTER_IMAGES.matcher(image_url);
            if (m.matches())
                return new PreviewImage(getTwitterImage(image_url, large_image_preview), image_url);
            m = PATTERN_TWITPIC.matcher(image_url);
            if (m.matches())
                return new PreviewImage(getTwitpicImage(matcherGroup(m, TWITPIC_GROUP_ID), large_image_preview),
                        image_url);
            m = PATTERN_INSTAGRAM.matcher(image_url);
            if (m.matches())
                return new PreviewImage(getInstagramImage(matcherGroup(m, INSTAGRAM_GROUP_ID), large_image_preview),
                        image_url);
            m = PATTERN_IMGUR.matcher(image_url);
            if (m.matches())
                return new PreviewImage(getImgurImage(matcherGroup(m, IMGUR_GROUP_ID), large_image_preview),
                        image_url);
            m = PATTERN_IMGLY.matcher(image_url);
            if (m.matches())
                return new PreviewImage(getImglyImage(matcherGroup(m, IMGLY_GROUP_ID), large_image_preview),
                        image_url);
            m = PATTERN_YFROG.matcher(image_url);
            if (m.matches())
                return new PreviewImage(getYfrogImage(matcherGroup(m, YFROG_GROUP_ID), large_image_preview),
                        image_url);
            m = PATTERN_LOCKERZ_AND_PLIXI.matcher(image_url);
            if (m.matches())
                return new PreviewImage(getLockerzAndPlixiImage(image_url, large_image_preview), image_url);
            m = PATTERN_SINA_WEIBO_IMAGES.matcher(image_url);
            if (m.matches())
                return new PreviewImage(getSinaWeiboImage(image_url, large_image_preview), image_url);
            m = PATTERN_TWITGOO.matcher(image_url);
            if (m.matches())
                return new PreviewImage(getTwitgooImage(matcherGroup(m, TWITGOO_GROUP_ID), large_image_preview),
                        image_url);
            m = PATTERN_MOBYPICTURE.matcher(image_url);
            if (m.matches())
                return new PreviewImage(
                        getMobyPictureImage(matcherGroup(m, MOBYPICTURE_GROUP_ID), large_image_preview), image_url);
            m = PATTERN_PHOTOZOU.matcher(image_url);
            if (m.matches())
                return new PreviewImage(getPhotozouImage(matcherGroup(m, PHOTOZOU_GROUP_ID), large_image_preview),
                        image_url);
        }
        return new PreviewImage(false, null, null);
    }

    public static Proxy getProxy(final Context context) {
        if (context == null)
            return null;
        final SharedPreferences prefs = context.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE);
        final boolean enable_proxy = prefs.getBoolean(PREFERENCE_KEY_ENABLE_PROXY, false);
        if (!enable_proxy)
            return Proxy.NO_PROXY;
        final String proxy_host = prefs.getString(PREFERENCE_KEY_PROXY_HOST, null);
        final int proxy_port = parseInt(prefs.getString(PREFERENCE_KEY_PROXY_PORT, "-1"));
        if (!isEmpty(proxy_host) && proxy_port > 0) {
            final SocketAddress addr = InetSocketAddress.createUnresolved(proxy_host, proxy_port);
            return new Proxy(Proxy.Type.HTTP, addr);
        }
        return Proxy.NO_PROXY;
    }

    public static String getQuoteStatus(final Context context, final String screen_name, final String text) {
        if (context == null)
            return null;
        String quote_format = context.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE)
                .getString(PREFERENCE_KEY_QUOTE_FORMAT, PREFERENCE_DEFAULT_QUOTE_FORMAT);
        if (isEmpty(quote_format)) {
            quote_format = PREFERENCE_DEFAULT_QUOTE_FORMAT;
        }
        return quote_format.replace(FORMAT_PATTERN_NAME, screen_name).replace(FORMAT_PATTERN_TEXT, text);
    }

    public static HttpResponse getRedirectedHttpResponse(final HttpClientWrapper client, final String url)
            throws TwitterException {
        if (url == null)
            return null;
        final ArrayList<String> urls = new ArrayList<String>();
        urls.add(url);
        HttpResponse resp;
        try {
            resp = client.get(url, url);
        } catch (final TwitterException te) {
            if (isRedirected(te.getStatusCode())) {
                resp = te.getHttpResponse();
            } else
                throw te;
        }
        while (resp != null && isRedirected(resp.getStatusCode())) {
            final String request_url = resp.getResponseHeader("Location");
            if (request_url == null)
                return null;
            if (urls.contains(request_url))
                throw new TwitterException("Too many redirects");
            urls.add(request_url);
            try {
                resp = client.get(request_url, request_url);
            } catch (final TwitterException te) {
                if (isRedirected(te.getStatusCode())) {
                    resp = te.getHttpResponse();
                } else
                    throw te;
            }
        }
        return resp;
    }

    public static String getShareStatus(final Context context, final String title, final String text) {
        if (context == null)
            return null;
        String share_format = context.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE)
                .getString(PREFERENCE_KEY_SHARE_FORMAT, PREFERENCE_DEFAULT_SHARE_FORMAT);
        if (isEmpty(share_format)) {
            share_format = PREFERENCE_DEFAULT_SHARE_FORMAT;
        }
        if (title == null)
            return text;
        return share_format.replace(FORMAT_PATTERN_TITLE, title).replace(FORMAT_PATTERN_TEXT, text);
    }

    public static ImageSpec getSinaWeiboImage(final String url, final boolean large_image_preview) {
        if (isEmpty(url))
            return null;
        final String full = url.replaceAll("\\/" + SINA_WEIBO_IMAGES_AVAILABLE_SIZES + "\\/", "/large/");
        final String preview = large_image_preview ? full
                : url.replaceAll("\\/" + SINA_WEIBO_IMAGES_AVAILABLE_SIZES + "\\/", "/thumbnail/");
        return new ImageSpec(preview, full);
    }

    public static int getStatusBackground(final boolean is_mention, final boolean is_favorite,
            final boolean is_retweet) {
        if (is_mention)
            return 0x1A33B5E5;
        else if (is_favorite)
            return 0x1AFFBB33;
        else if (is_retweet)
            return 0x1A66CC00;
        return Color.TRANSPARENT;
    }

    public static ArrayList<Long> getStatusIdsInDatabase(final Context context, final Uri uri,
            final long account_id) {
        final ArrayList<Long> list = new ArrayList<Long>();
        if (context == null)
            return list;
        final ContentResolver resolver = context.getContentResolver();
        final String where = Statuses.ACCOUNT_ID + " = " + account_id;
        final String[] projection = new String[] { Statuses.STATUS_ID };
        final Cursor cur = resolver.query(uri, projection, where, null, null);
        if (cur != null) {
            final int idx = cur.getColumnIndexOrThrow(Statuses.STATUS_ID);
            cur.moveToFirst();
            while (!cur.isAfterLast()) {
                list.add(cur.getLong(idx));
                cur.moveToNext();
            }
            cur.close();
        }
        return list;
    }

    public static int getStatusTypeIconRes(final boolean is_fav, final boolean has_location,
            final boolean has_media) {
        if (is_fav)
            return R.drawable.ic_indicator_starred;
        else if (has_media)
            return R.drawable.ic_indicator_has_media;
        else if (has_location)
            return R.drawable.ic_indicator_has_location;
        return 0;
    }

    public static Drawable getTabIconDrawable(final Context context, final Object icon_obj) {
        if (context == null)
            return null;
        final Resources res = context.getResources();
        if (icon_obj instanceof Integer) {
            try {
                return res.getDrawable((Integer) icon_obj);
            } catch (final Resources.NotFoundException e) {
                // Ignore.
            }
        } else if (icon_obj instanceof Bitmap)
            return new BitmapDrawable(res, (Bitmap) icon_obj);
        else if (icon_obj instanceof Drawable)
            return (Drawable) icon_obj;
        else if (icon_obj instanceof File) {
            final Bitmap b = getTabIconFromFile((File) icon_obj, res);
            if (b != null)
                return new BitmapDrawable(res, b);
        }
        return res.getDrawable(R.drawable.ic_tab_list);
    }

    public static Object getTabIconObject(final String type) {
        if (type == null)
            return R.drawable.ic_tab_list;
        final Integer value = CUSTOM_TABS_ICON_NAME_MAP.get(type);
        if (value != null)
            return value;
        else if (type.contains("/")) {
            try {
                final File file = new File(type);
                if (file.exists())
                    return file;
            } catch (final Exception e) {
                return R.drawable.ic_tab_list;
            }
        }
        return R.drawable.ic_tab_list;
    }

    public static int getTableId(final Uri uri) {
        if (uri == null)
            return -1;
        return CONTENT_PROVIDER_URI_MATCHER.match(uri);
    }

    public static String getTableNameById(final int id) {
        switch (id) {
        case TABLE_ID_ACCOUNTS:
            return TABLE_ACCOUNTS;
        case TABLE_ID_STATUSES:
            return TABLE_STATUSES;
        case TABLE_ID_MENTIONS:
            return TABLE_MENTIONS;
        case TABLE_ID_DRAFTS:
            return TABLE_DRAFTS;
        case TABLE_ID_CACHED_USERS:
            return TABLE_CACHED_USERS;
        case TABLE_ID_FILTERED_USERS:
            return TABLE_FILTERED_USERS;
        case TABLE_ID_FILTERED_KEYWORDS:
            return TABLE_FILTERED_KEYWORDS;
        case TABLE_ID_FILTERED_SOURCES:
            return TABLE_FILTERED_SOURCES;
        case TABLE_ID_FILTERED_LINKS:
            return TABLE_FILTERED_LINKS;
        case TABLE_ID_DIRECT_MESSAGES_INBOX:
            return TABLE_DIRECT_MESSAGES_INBOX;
        case TABLE_ID_DIRECT_MESSAGES_OUTBOX:
            return TABLE_DIRECT_MESSAGES_OUTBOX;
        case TABLE_ID_TRENDS_LOCAL:
            return TABLE_TRENDS_LOCAL;
        case TABLE_ID_TABS:
            return TABLE_TABS;
        case TABLE_ID_CACHED_STATUSES:
            return TABLE_CACHED_STATUSES;
        case TABLE_ID_CACHED_HASHTAGS:
            return TABLE_CACHED_HASHTAGS;
        default:
            return null;
        }
    }

    public static String getTableNameByUri(final Uri uri) {
        if (uri == null)
            return null;
        return getTableNameById(getTableId(uri));
    }

    public static List<TabSpec> getTabs(final Context context) {
        if (context == null)
            return Collections.emptyList();
        final ArrayList<TabSpec> tabs = new ArrayList<TabSpec>();
        final ContentResolver resolver = context.getContentResolver();
        final Cursor cur = resolver.query(Tabs.CONTENT_URI, Tabs.COLUMNS, null, null, Tabs.DEFAULT_SORT_ORDER);
        if (cur != null) {
            cur.moveToFirst();
            final int idx_name = cur.getColumnIndex(Tabs.NAME), idx_icon = cur.getColumnIndex(Tabs.ICON),
                    idx_type = cur.getColumnIndex(Tabs.TYPE), idx_arguments = cur.getColumnIndex(Tabs.ARGUMENTS),
                    idx_position = cur.getColumnIndex(Tabs.POSITION);
            while (!cur.isAfterLast()) {
                final int position = cur.getInt(idx_position) + HomeActivity.TAB_POSITION_MESSAGES + 1;
                final String icon_type = cur.getString(idx_icon);
                final String type = cur.getString(idx_type);
                final String name = cur.getString(idx_name);
                final Bundle args = parseArguments(cur.getString(idx_arguments));
                args.putBoolean(INTENT_KEY_IS_HOME_TAB, true);
                final Class<? extends Fragment> fragment = CUSTOM_TABS_FRAGMENT_MAP.get(type);
                if (name != null && fragment != null) {
                    tabs.add(new TabSpec(name, getTabIconObject(icon_type), fragment, args, position));
                }
                cur.moveToNext();
            }
            cur.close();
        }
        return tabs;
    }

    public static String getTabTypeName(final Context context, final String type) {
        if (context == null)
            return null;
        final Integer res_id = CUSTOM_TABS_TYPE_NAME_MAP.get(type);
        return res_id != null ? context.getString(res_id) : null;
    }

    public static long getTimestampFromDate(final Date date) {
        if (date == null)
            return -1;
        return date.getTime();
    }

    public static ImageSpec getTwitgooImage(final String id, final boolean large_image_preview) {
        if (isEmpty(id))
            return null;
        final String full = "https://twitgoo.com/show/img/" + id;
        final String preview = large_image_preview ? full : "https://twitgoo.com/show/thumb/" + id;
        return new ImageSpec(preview, full);
    }

    public static ImageSpec getTwitpicImage(final String id, final boolean large_image_preview) {
        if (isEmpty(id))
            return null;
        final String full = "https://twitpic.com/show/large/" + id;
        final String preview = large_image_preview ? full : "https://twitpic.com/show/thumb/" + id;
        return new ImageSpec(preview, full);
    }

    public static ImageSpec getTwitterImage(final String url, final boolean large_image_preview) {
        if (isEmpty(url))
            return null;
        return new ImageSpec(url + (large_image_preview ? ":large" : ":thumb"), url + ":large");
    }

    public static Twitter getTwitterInstance(final Context context, final long account_id,
            final boolean include_entities) {
        return getTwitterInstance(context, account_id, include_entities, true);
    }

    public static Twitter getTwitterInstance(final Context context, final long account_id,
            final boolean include_entities, final boolean use_httpclient) {
        if (context == null)
            return null;
        final TwidereApplication app = TwidereApplication.getInstance(context);
        final SharedPreferences preferences = context.getSharedPreferences(SHARED_PREFERENCES_NAME,
                Context.MODE_PRIVATE);
        final int connection_timeout = preferences.getInt(PREFERENCE_KEY_CONNECTION_TIMEOUT, 10) * 1000;
        final boolean enable_gzip_compressing = preferences.getBoolean(PREFERENCE_KEY_GZIP_COMPRESSING, true);
        final boolean ignore_ssl_error = preferences.getBoolean(PREFERENCE_KEY_IGNORE_SSL_ERROR, false);
        final boolean enable_proxy = preferences.getBoolean(PREFERENCE_KEY_ENABLE_PROXY, false);
        final String consumer_key = preferences.getString(PREFERENCE_KEY_CONSUMER_KEY, TWITTER_CONSUMER_KEY);
        final String consumer_secret = preferences.getString(PREFERENCE_KEY_CONSUMER_SECRET,
                TWITTER_CONSUMER_SECRET);

        Twitter twitter = null;
        final StringBuilder where = new StringBuilder();
        where.append(Accounts.ACCOUNT_ID + " = " + account_id);
        final Cursor cur = context.getContentResolver().query(Accounts.CONTENT_URI, Accounts.COLUMNS,
                where.toString(), null, null);
        if (cur != null) {
            if (cur.getCount() > 0) {
                cur.moveToFirst();
                final ConfigurationBuilder cb = new ConfigurationBuilder();
                cb.setHostAddressResolver(app.getHostAddressResolver());
                if (use_httpclient) {
                    cb.setHttpClientImplementation(HttpClientImpl.class);
                }
                cb.setHttpConnectionTimeout(connection_timeout);
                setUserAgent(context, cb);
                cb.setGZIPEnabled(enable_gzip_compressing);
                cb.setIgnoreSSLError(ignore_ssl_error);
                if (enable_proxy) {
                    final String proxy_host = preferences.getString(PREFERENCE_KEY_PROXY_HOST, null);
                    final int proxy_port = parseInt(preferences.getString(PREFERENCE_KEY_PROXY_PORT, "-1"));
                    if (!isEmpty(proxy_host) && proxy_port > 0) {
                        cb.setHttpProxyHost(proxy_host);
                        cb.setHttpProxyPort(proxy_port);
                    }
                }
                final String rest_base_url = cur.getString(cur.getColumnIndexOrThrow(Accounts.REST_BASE_URL));
                final String signing_rest_base_url = cur
                        .getString(cur.getColumnIndexOrThrow(Accounts.SIGNING_REST_BASE_URL));
                final String oauth_base_url = cur.getString(cur.getColumnIndexOrThrow(Accounts.OAUTH_BASE_URL));
                final String signing_oauth_base_url = cur
                        .getString(cur.getColumnIndexOrThrow(Accounts.SIGNING_OAUTH_BASE_URL));
                if (!isEmpty(rest_base_url)) {
                    cb.setRestBaseURL(rest_base_url);
                }
                if (!isEmpty(signing_rest_base_url)) {
                    cb.setSigningRestBaseURL(signing_rest_base_url);
                }
                if (!isEmpty(oauth_base_url)) {
                    cb.setOAuthBaseURL(oauth_base_url);
                }
                if (!isEmpty(signing_oauth_base_url)) {
                    cb.setSigningOAuthBaseURL(signing_oauth_base_url);
                }
                cb.setIncludeEntitiesEnabled(include_entities);
                switch (cur.getInt(cur.getColumnIndexOrThrow(Accounts.AUTH_TYPE))) {
                case Accounts.AUTH_TYPE_OAUTH:
                case Accounts.AUTH_TYPE_XAUTH: {
                    if (isEmpty(consumer_key) || isEmpty(consumer_secret)) {
                        cb.setOAuthConsumerKey(TWITTER_CONSUMER_KEY);
                        cb.setOAuthConsumerSecret(TWITTER_CONSUMER_SECRET);
                    } else {
                        cb.setOAuthConsumerKey(consumer_key);
                        cb.setOAuthConsumerSecret(consumer_secret);
                    }
                    final String oauth_token = cur.getString(cur.getColumnIndexOrThrow(Accounts.OAUTH_TOKEN));
                    final String token_secret = cur.getString(cur.getColumnIndexOrThrow(Accounts.TOKEN_SECRET));
                    if (!isEmpty(oauth_token) && !isEmpty(token_secret)) {
                        twitter = new TwitterFactory(cb.build())
                                .getInstance(new AccessToken(oauth_token, token_secret));
                    }
                    break;
                }
                case Accounts.AUTH_TYPE_BASIC: {
                    final String screen_name = cur.getString(cur.getColumnIndexOrThrow(Accounts.SCREEN_NAME));
                    final String password = cur.getString(cur.getColumnIndexOrThrow(Accounts.BASIC_AUTH_PASSWORD));
                    if (!isEmpty(screen_name) && !isEmpty(password)) {
                        twitter = new TwitterFactory(cb.build())
                                .getInstance(new BasicAuthorization(screen_name, password));
                    }
                    break;
                }
                case Accounts.AUTH_TYPE_TWIP_O_MODE: {
                    twitter = new TwitterFactory(cb.build()).getInstance(new TwipOModeAuthorization());
                    break;
                }
                default:
                }
            }
            cur.close();
        }
        return twitter;
    }

    public static String getUnescapedStatusString(final String string) {
        if (string == null)
            return null;
        return string.replace("&amp;", "&").replace("&lt;", "<").replace("&gt;", ">");
    }

    public static int getUserColor(final Context context, final long user_id) {
        if (context == null)
            return Color.TRANSPARENT;
        Integer color = sUserColors.get(user_id);
        if (color == null) {
            final SharedPreferences prefs = context.getSharedPreferences(USER_COLOR_PREFERENCES_NAME,
                    Context.MODE_PRIVATE);
            color = prefs.getInt(Long.toString(user_id), Color.TRANSPARENT);
            sUserColors.put(user_id, color);
        }
        return color != null ? color : Color.TRANSPARENT;
    }

    public static int getUserTypeIconRes(final boolean is_verified, final boolean is_protected) {
        if (is_verified)
            return R.drawable.ic_indicator_verified;
        else if (is_protected)
            return R.drawable.ic_indicator_is_protected;
        return 0;
    }

    public static ImageSpec getYfrogImage(final String id, final boolean large_image_preview) {
        if (isEmpty(id))
            return null;
        final String preview = "https://yfrog.com/" + id + ":iphone";
        final String full = "https://yfrog.com/" + id + (large_image_preview ? ":medium" : ":small");
        return new ImageSpec(preview, full);

    }

    public static boolean hasActiveConnection(final Context context) {
        if (context == null)
            return false;
        final ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        final NetworkInfo netInfo = cm.getActiveNetworkInfo();
        if (netInfo != null && netInfo.isConnected())
            return true;
        return false;
    }

    public static boolean isBatteryOkay(final Context context) {
        if (context == null)
            return false;
        final Context app = context.getApplicationContext();
        final IntentFilter filter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
        final Intent intent = app.registerReceiver(null, filter);
        if (intent == null)
            return false;
        final boolean plugged = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0) > 0;
        final float level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0);
        final float scale = intent.getIntExtra(BatteryManager.EXTRA_SCALE, 100);
        return plugged || level / scale > 0.15f;
    }

    public static boolean isFiltered(final SQLiteDatabase database, final ParcelableStatus status) {
        if (status == null)
            return false;
        return isFiltered(database, status.text_plain, status.text_html, status.screen_name, status.source);
    }

    public static boolean isFiltered(final SQLiteDatabase database, final String text_plain, final String text_html,
            final String screen_name, final String source) {
        if (database == null)
            return false;
        final StringBuilder builder = new StringBuilder();
        final String[] selection_args = new String[] { text_plain, text_html, screen_name, source };
        builder.append("SELECT NULL WHERE");
        builder.append("(SELECT 1 IN (SELECT ? LIKE '%'||" + TABLE_FILTERED_KEYWORDS + "." + Filters.TEXT
                + "||'%' FROM " + TABLE_FILTERED_KEYWORDS + "))");
        builder.append(" OR ");
        builder.append("(SELECT 1 IN (SELECT ? LIKE '%<a href=\"%'||" + TABLE_FILTERED_LINKS + "." + Filters.TEXT
                + "||'%\">%' FROM " + TABLE_FILTERED_LINKS + "))");
        builder.append(" OR ");
        builder.append("(SELECT ? IN (SELECT " + Filters.TEXT + " FROM " + TABLE_FILTERED_USERS + "))");
        builder.append(" OR ");
        builder.append("(SELECT 1 IN (SELECT ? LIKE '%>'||" + TABLE_FILTERED_SOURCES + "." + Filters.TEXT
                + "||'</a>%' FROM " + TABLE_FILTERED_SOURCES + "))");
        final Cursor cur = database.rawQuery(builder.toString(), selection_args);
        if (cur == null)
            return false;
        try {
            return cur.getCount() > 0;
        } finally {
            cur.close();
        }
    }

    public static boolean isMyAccount(final Context context, final long account_id) {
        if (context == null)
            return false;
        final ContentResolver resolver = context.getContentResolver();
        final String where = Accounts.ACCOUNT_ID + " = " + account_id;
        final Cursor cur = resolver.query(Accounts.CONTENT_URI, new String[0], where, null, null);
        try {
            return cur != null && cur.getCount() > 0;
        } finally {
            if (cur != null) {
                cur.close();
            }
        }
    }

    public static boolean isMyAccount(final Context context, final String screen_name) {
        if (context == null)
            return false;
        final ContentResolver resolver = context.getContentResolver();
        final String where = Accounts.SCREEN_NAME + " = ?";
        final Cursor cur = resolver.query(Accounts.CONTENT_URI, new String[0], where, new String[] { screen_name },
                null);
        try {
            return cur != null && cur.getCount() > 0;
        } finally {
            if (cur != null) {
                cur.close();
            }
        }
    }

    public static boolean isMyActivatedAccount(final Context context, final long account_id) {
        if (context == null || account_id <= 0)
            return false;
        final ContentResolver resolver = context.getContentResolver();
        final String where = Accounts.IS_ACTIVATED + " = 1 AND " + Accounts.ACCOUNT_ID + " = " + account_id;
        final Cursor cur = resolver.query(Accounts.CONTENT_URI, new String[0], where, null, null);
        try {
            return cur != null && cur.getCount() > 0;
        } finally {
            if (cur != null) {
                cur.close();
            }
        }
    }

    public static boolean isMyActivatedAccount(final Context context, final String screen_name) {
        if (context == null)
            return false;
        final ContentResolver resolver = context.getContentResolver();
        final String where = Accounts.IS_ACTIVATED + " = 1 AND " + Accounts.SCREEN_NAME + " = ?";
        final Cursor cur = resolver.query(Accounts.CONTENT_URI, new String[0], where, new String[] { screen_name },
                null);
        try {
            return cur != null && cur.getCount() > 0;
        } finally {
            if (cur != null) {
                cur.close();
            }
        }
    }

    public static boolean isMyRetweet(final ParcelableStatus status) {
        if (status == null)
            return false;
        return status.retweeted_by_id == status.account_id || status.my_retweet_id > 0;
    }

    public static boolean isMyUserName(final Context context, final String screen_name) {
        if (context == null)
            return false;
        for (final String account_screen_name : getAccountScreenNames(context)) {
            if (account_screen_name.equalsIgnoreCase(screen_name))
                return true;
        }
        return false;
    }

    public static boolean isRedirected(final int code) {
        return code == 301 || code == 302;
    }

    public static boolean isRTL(final Context context) {
        if (context == null)
            return false;
        final Resources res = context.getResources();
        return ConfigurationAccessor.getLayoutDirection(res.getConfiguration()) == SCREENLAYOUT_LAYOUTDIR_RTL;
    }

    public static boolean isUserLoggedIn(final Context context, final long account_id) {
        if (context == null)
            return false;
        final long[] ids = getAccountIds(context);
        if (ids == null)
            return false;
        for (final long id : ids) {
            if (id == account_id)
                return true;
        }
        return false;
    }

    public static ContentValues makeAccountContentValues(final Configuration conf, final String basic_password,
            final AccessToken access_token, final User user, final int auth_type, final int color) {
        if (user == null || user.getId() <= 0)
            return null;
        final ContentValues values = new ContentValues();
        switch (auth_type) {
        case Accounts.AUTH_TYPE_TWIP_O_MODE: {
            break;
        }
        case Accounts.AUTH_TYPE_BASIC: {
            if (basic_password == null)
                return null;
            values.put(Accounts.BASIC_AUTH_PASSWORD, basic_password);
            break;
        }
        case Accounts.AUTH_TYPE_OAUTH:
        case Accounts.AUTH_TYPE_XAUTH: {
            if (access_token == null)
                return null;
            if (user.getId() != access_token.getUserId())
                return null;
            values.put(Accounts.OAUTH_TOKEN, access_token.getToken());
            values.put(Accounts.TOKEN_SECRET, access_token.getTokenSecret());
            break;
        }
        }
        values.put(Accounts.AUTH_TYPE, auth_type);
        values.put(Accounts.ACCOUNT_ID, user.getId());
        values.put(Accounts.SCREEN_NAME, user.getScreenName());
        values.put(Accounts.NAME, user.getName());
        values.put(Accounts.PROFILE_IMAGE_URL, user.getProfileImageUrlHttps().toString());
        values.put(Accounts.USER_COLOR, color);
        values.put(Accounts.IS_ACTIVATED, 1);
        values.put(Accounts.REST_BASE_URL, conf.getRestBaseURL());
        values.put(Accounts.SIGNING_REST_BASE_URL, conf.getSigningRestBaseURL());
        values.put(Accounts.OAUTH_BASE_URL, conf.getOAuthBaseURL());
        values.put(Accounts.SIGNING_OAUTH_BASE_URL, conf.getSigningOAuthBaseURL());
        return values;
    }

    public static ContentValues makeCachedUserContentValues(final User user, final boolean large_profile_image) {
        if (user == null || user.getId() <= 0)
            return null;
        final String profile_image_url = parseString(user.getProfileImageUrlHttps());
        final ContentValues values = new ContentValues();
        values.put(CachedUsers.USER_ID, user.getId());
        values.put(CachedUsers.NAME, user.getName());
        values.put(CachedUsers.SCREEN_NAME, user.getScreenName());
        values.put(CachedUsers.PROFILE_IMAGE_URL,
                large_profile_image ? getBiggerTwitterProfileImage(profile_image_url) : profile_image_url);
        values.put(CachedUsers.CREATED_AT, user.getCreatedAt().getTime());
        values.put(CachedUsers.IS_PROTECTED, user.isProtected());
        values.put(CachedUsers.IS_VERIFIED, user.isVerified());
        values.put(CachedUsers.FAVORITES_COUNT, user.getFavouritesCount());
        values.put(CachedUsers.FOLLOWERS_COUNT, user.getFollowersCount());
        values.put(CachedUsers.FRIENDS_COUNT, user.getFriendsCount());
        values.put(CachedUsers.STATUSES_COUNT, user.getStatusesCount());
        values.put(CachedUsers.LOCATION, user.getLocation());
        values.put(CachedUsers.DESCRIPTION, user.getDescription());
        values.put(CachedUsers.URL, parseString(user.getURL()));
        values.put(CachedUsers.PROFILE_BANNER_URL, user.getProfileBannerImageUrl());
        return values;
    }

    public static ContentValues makeDirectMessageContentValues(final DirectMessage message, final long account_id,
            final boolean is_outgoing, final boolean large_profile_image) {
        if (message == null || message.getId() <= 0)
            return null;
        final ContentValues values = new ContentValues();
        final User sender = message.getSender(), recipient = message.getRecipient();
        if (sender == null || recipient == null)
            return null;
        final String sender_profile_image_url = parseString(sender.getProfileImageUrlHttps());
        final String recipient_profile_image_url = parseString(recipient.getProfileImageUrlHttps());
        values.put(DirectMessages.ACCOUNT_ID, account_id);
        values.put(DirectMessages.MESSAGE_ID, message.getId());
        values.put(DirectMessages.MESSAGE_TIMESTAMP, message.getCreatedAt().getTime());
        values.put(DirectMessages.SENDER_ID, sender.getId());
        values.put(DirectMessages.RECIPIENT_ID, recipient.getId());
        values.put(DirectMessages.TEXT, formatDirectMessageText(message));
        values.put(DirectMessages.TEXT_PLAIN, message.getText());
        values.put(DirectMessages.IS_OUTGOING, is_outgoing);
        values.put(DirectMessages.SENDER_NAME, sender.getName());
        values.put(DirectMessages.SENDER_SCREEN_NAME, sender.getScreenName());
        values.put(DirectMessages.RECIPIENT_NAME, recipient.getName());
        values.put(DirectMessages.RECIPIENT_SCREEN_NAME, recipient.getScreenName());
        values.put(DirectMessages.SENDER_PROFILE_IMAGE_URL,
                large_profile_image ? getBiggerTwitterProfileImage(sender_profile_image_url)
                        : sender_profile_image_url);
        values.put(DirectMessages.RECIPIENT_PROFILE_IMAGE_URL,
                large_profile_image ? getBiggerTwitterProfileImage(recipient_profile_image_url)
                        : recipient_profile_image_url);
        return values;
    }

    public static ContentValues makeStatusContentValues(Status status, final long account_id,
            final boolean large_profile_image) {
        if (status == null || status.getId() <= 0)
            return null;
        final ContentValues values = new ContentValues();
        values.put(Statuses.ACCOUNT_ID, account_id);
        values.put(Statuses.STATUS_ID, status.getId());
        values.put(Statuses.MY_RETWEET_ID, status.getCurrentUserRetweet());
        final boolean is_retweet = status.isRetweet();
        final Status retweeted_status = is_retweet ? status.getRetweetedStatus() : null;
        if (retweeted_status != null) {
            final User retweet_user = status.getUser();
            values.put(Statuses.RETWEET_ID, retweeted_status.getId());
            values.put(Statuses.RETWEETED_BY_ID, retweet_user.getId());
            values.put(Statuses.RETWEETED_BY_NAME, retweet_user.getName());
            values.put(Statuses.RETWEETED_BY_SCREEN_NAME, retweet_user.getScreenName());
            status = retweeted_status;
        }
        final User user = status.getUser();
        if (user != null) {
            final long user_id = user.getId();
            final String profile_image_url = parseString(user.getProfileImageUrlHttps());
            final String name = user.getName(), screen_name = user.getScreenName();
            values.put(Statuses.USER_ID, user_id);
            values.put(Statuses.NAME, name);
            values.put(Statuses.SCREEN_NAME, screen_name);
            values.put(Statuses.IS_PROTECTED, user.isProtected());
            values.put(Statuses.IS_VERIFIED, user.isVerified());
            values.put(Statuses.PROFILE_IMAGE_URL,
                    large_profile_image ? getBiggerTwitterProfileImage(profile_image_url) : profile_image_url);
        }
        if (status.getCreatedAt() != null) {
            values.put(Statuses.STATUS_TIMESTAMP, status.getCreatedAt().getTime());
        }
        values.put(Statuses.TEXT, formatStatusText(status));
        values.put(Statuses.TEXT_PLAIN, status.getText());
        values.put(Statuses.RETWEET_COUNT, status.getRetweetCount());
        values.put(Statuses.IN_REPLY_TO_SCREEN_NAME, status.getInReplyToScreenName());
        values.put(Statuses.IN_REPLY_TO_STATUS_ID, status.getInReplyToStatusId());
        values.put(Statuses.SOURCE, status.getSource());
        values.put(Statuses.IS_POSSIBLY_SENSITIVE, status.isPossiblySensitive());
        final GeoLocation location = status.getGeoLocation();
        if (location != null) {
            values.put(Statuses.LOCATION, location.getLatitude() + "," + location.getLongitude());
        }
        values.put(Statuses.IS_RETWEET, is_retweet);
        values.put(Statuses.IS_FAVORITE, status.isFavorited());
        return values;
    }

    public static ContentValues[] makeTrendsContentValues(final List<Trends> trends_list) {
        if (trends_list == null)
            return new ContentValues[0];
        final List<ContentValues> result_list = new ArrayList<ContentValues>();
        for (final Trends trends : trends_list) {
            if (trends == null) {
                continue;
            }
            final long timestamp = trends.getTrendAt().getTime();
            for (final Trend trend : trends.getTrends()) {
                final ContentValues values = new ContentValues();
                values.put(CachedTrends.NAME, trend.getName());
                values.put(CachedTrends.TIMESTAMP, timestamp);
                result_list.add(values);
            }
        }
        return result_list.toArray(new ContentValues[result_list.size()]);
    }

    public static final int matcherEnd(final Matcher matcher, final int group) {
        try {
            return matcher.end(group);
        } catch (final IllegalStateException e) {
            // Ignore.
        }
        return -1;
    }

    public static final String matcherGroup(final Matcher matcher, final int group) {
        try {
            return matcher.group(group);
        } catch (final IllegalStateException e) {
            // Ignore.
        }
        return null;
    }

    public static final int matcherStart(final Matcher matcher, final int group) {
        try {
            return matcher.start(group);
        } catch (final IllegalStateException e) {
            // Ignore.
        }
        return -1;
    }

    public static int matchLinkId(final Uri uri) {
        return LINK_HANDLER_URI_MATCHER.match(uri);
    }

    public static void notifyForUpdatedUri(final Context context, final Uri uri) {
        if (context == null)
            return;
        switch (getTableId(uri)) {
        case TABLE_ID_STATUSES: {
            context.sendBroadcast(new Intent(BROADCAST_HOME_TIMELINE_DATABASE_UPDATED));
            break;
        }
        case TABLE_ID_MENTIONS: {
            context.sendBroadcast(new Intent(BROADCAST_MENTIONS_DATABASE_UPDATED));
            break;
        }
        case TABLE_ID_DIRECT_MESSAGES_INBOX: {
            context.sendBroadcast(new Intent(BROADCAST_RECEIVED_DIRECT_MESSAGES_DATABASE_UPDATED));
            break;
        }
        case TABLE_ID_DIRECT_MESSAGES_OUTBOX: {
            context.sendBroadcast(new Intent(BROADCAST_SENT_DIRECT_MESSAGES_DATABASE_UPDATED));
            break;
        }
        default: {
            return;
        }
        }
        context.sendBroadcast(new Intent(BROADCAST_DATABASE_UPDATED));
    }

    public static boolean objectEquals(final Object object1, final Object object2) {
        if (object1 == null || object2 == null)
            return object1 == object2;
        return object1.equals(object2);
    }

    public static void openDirectMessagesConversation(final Activity activity, final long account_id,
            final long conversation_id) {
        if (activity == null)
            return;
        if (activity instanceof DualPaneActivity && ((DualPaneActivity) activity).isDualPaneMode()) {
            final DualPaneActivity dual_pane_activity = (DualPaneActivity) activity;
            final Fragment details_fragment = dual_pane_activity.getDetailsFragment();
            if (details_fragment instanceof DirectMessagesConversationFragment && details_fragment.isAdded()) {
                ((DirectMessagesConversationFragment) details_fragment).showConversation(account_id,
                        conversation_id);
                dual_pane_activity.showRightPane();
            } else {
                final Fragment fragment = new DirectMessagesConversationFragment();
                final Bundle args = new Bundle();
                if (account_id > 0 && conversation_id > 0) {
                    args.putLong(INTENT_KEY_ACCOUNT_ID, account_id);
                    if (conversation_id > 0) {
                        args.putLong(INTENT_KEY_CONVERSATION_ID, conversation_id);
                    }
                }
                fragment.setArguments(args);
                dual_pane_activity.showAtPane(PANE_RIGHT, fragment, true);
            }
        } else {
            final Uri.Builder builder = new Uri.Builder();
            builder.scheme(SCHEME_TWIDERE);
            builder.authority(AUTHORITY_DIRECT_MESSAGES_CONVERSATION);
            if (account_id > 0 && conversation_id > 0) {
                builder.appendQueryParameter(QUERY_PARAM_ACCOUNT_ID, String.valueOf(account_id));
                if (conversation_id > 0) {
                    builder.appendQueryParameter(QUERY_PARAM_CONVERSATION_ID, String.valueOf(conversation_id));
                }
            }
            activity.startActivity(new Intent(Intent.ACTION_VIEW, builder.build()));
        }
    }

    public static void openImage(final Context context, final Uri uri, final boolean is_possibly_sensitive) {
        if (context == null || uri == null)
            return;
        final Intent intent = new Intent(INTENT_ACTION_VIEW_IMAGE);
        intent.setDataAndType(uri, "image/*");
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD_MR1) {
            intent.setClass(context, ImageViewerGLActivity.class);
        } else {
            intent.setClass(context, ImageViewerActivity.class);
        }
        final SharedPreferences prefs = context.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE);
        if (context instanceof FragmentActivity && is_possibly_sensitive
                && !prefs.getBoolean(PREFERENCE_KEY_DISPLAY_SENSITIVE_CONTENTS, false)) {
            final FragmentActivity activity = (FragmentActivity) context;
            final FragmentManager fm = activity.getSupportFragmentManager();
            final DialogFragment fragment = new SensitiveContentWaringDialogFragment();
            final Bundle args = new Bundle();
            args.putParcelable(INTENT_KEY_URI, uri);
            fragment.setArguments(args);
            fragment.show(fm, "sensitive_content_warning");
        } else {
            context.startActivity(intent);
        }
    }

    public static void openIncomingFriendships(final Activity activity, final long account_id) {
        if (activity == null)
            return;
        if (activity instanceof DualPaneActivity && ((DualPaneActivity) activity).isDualPaneMode()) {
            final DualPaneActivity dual_pane_activity = (DualPaneActivity) activity;
            final Fragment fragment = new IncomingFriendshipsFragment();
            final Bundle args = new Bundle();
            args.putLong(INTENT_KEY_ACCOUNT_ID, account_id);
            fragment.setArguments(args);
            dual_pane_activity.showAtPane(DualPaneActivity.PANE_LEFT, fragment, true);
        } else {
            final Uri.Builder builder = new Uri.Builder();
            builder.scheme(SCHEME_TWIDERE);
            builder.authority(AUTHORITY_INCOMING_FRIENDSHIPS);
            builder.appendQueryParameter(QUERY_PARAM_ACCOUNT_ID, String.valueOf(account_id));
            activity.startActivity(new Intent(Intent.ACTION_VIEW, builder.build()));
        }
    }

    public static void openSavedSearches(final Activity activity, final long account_id) {
        if (activity == null)
            return;
        if (activity instanceof DualPaneActivity && ((DualPaneActivity) activity).isDualPaneMode()) {
            final DualPaneActivity dual_pane_activity = (DualPaneActivity) activity;
            final Fragment fragment = new SavedSearchesListFragment();
            final Bundle args = new Bundle();
            args.putLong(INTENT_KEY_ACCOUNT_ID, account_id);
            fragment.setArguments(args);
            dual_pane_activity.showAtPane(DualPaneActivity.PANE_LEFT, fragment, true);
        } else {
            final Uri.Builder builder = new Uri.Builder();
            builder.scheme(SCHEME_TWIDERE);
            builder.authority(AUTHORITY_SAVED_SEARCHES);
            builder.appendQueryParameter(QUERY_PARAM_ACCOUNT_ID, String.valueOf(account_id));
            activity.startActivity(new Intent(Intent.ACTION_VIEW, builder.build()));
        }
    }

    public static void openStatus(final Activity activity, final ParcelableStatus status) {
        if (activity == null || status == null)
            return;
        final long account_id = status.account_id, status_id = status.status_id;
        final Bundle bundle = new Bundle();
        bundle.putParcelable(INTENT_KEY_STATUS, status);
        if (activity instanceof DualPaneActivity && ((DualPaneActivity) activity).isDualPaneMode()) {
            final DualPaneActivity dual_pane_activity = (DualPaneActivity) activity;
            final Fragment details_fragment = dual_pane_activity.getDetailsFragment();
            if (details_fragment instanceof StatusFragment && details_fragment.isAdded()) {
                ((StatusFragment) details_fragment).displayStatus(status);
                dual_pane_activity.showRightPane();
            } else {
                final Fragment fragment = new StatusFragment();
                final Bundle args = new Bundle(bundle);
                args.putLong(INTENT_KEY_ACCOUNT_ID, account_id);
                args.putLong(INTENT_KEY_STATUS_ID, status_id);
                fragment.setArguments(args);
                dual_pane_activity.showAtPane(DualPaneActivity.PANE_RIGHT, fragment, true);
            }
        } else {
            final Uri.Builder builder = new Uri.Builder();
            builder.scheme(SCHEME_TWIDERE);
            builder.authority(AUTHORITY_STATUS);
            builder.appendQueryParameter(QUERY_PARAM_ACCOUNT_ID, String.valueOf(account_id));
            builder.appendQueryParameter(QUERY_PARAM_STATUS_ID, String.valueOf(status_id));
            final Intent intent = new Intent(Intent.ACTION_VIEW, builder.build());

            intent.putExtras(bundle);
            activity.startActivity(intent);
        }
    }

    public static void openTweetSearch(final Activity activity, final long account_id, final String query) {
        if (activity == null)
            return;
        if (activity instanceof DualPaneActivity && ((DualPaneActivity) activity).isDualPaneMode()) {
            final DualPaneActivity dual_pane_activity = (DualPaneActivity) activity;
            final Fragment fragment = new SearchTweetsFragment();
            final Bundle args = new Bundle();
            args.putLong(INTENT_KEY_ACCOUNT_ID, account_id);
            if (query != null) {
                args.putString(INTENT_KEY_QUERY, query);
            }
            fragment.setArguments(args);
            dual_pane_activity.showAtPane(DualPaneActivity.PANE_LEFT, fragment, true);
        } else {
            final Uri.Builder builder = new Uri.Builder();
            builder.scheme(SCHEME_TWIDERE);
            builder.authority(AUTHORITY_SEARCH);
            builder.appendQueryParameter(QUERY_PARAM_ACCOUNT_ID, String.valueOf(account_id));
            builder.appendQueryParameter(QUERY_PARAM_TYPE, QUERY_PARAM_VALUE_TWEETS);
            if (query != null) {
                builder.appendQueryParameter(QUERY_PARAM_QUERY, query);
            }
            activity.startActivity(new Intent(Intent.ACTION_VIEW, builder.build()));
        }
    }

    public static void openUserBlocks(final Activity activity, final long account_id) {
        if (activity == null)
            return;
        if (activity instanceof DualPaneActivity && ((DualPaneActivity) activity).isDualPaneMode()) {
            final DualPaneActivity dual_pane_activity = (DualPaneActivity) activity;
            final Fragment fragment = new UserBlocksListFragment();
            final Bundle args = new Bundle();
            args.putLong(INTENT_KEY_ACCOUNT_ID, account_id);
            fragment.setArguments(args);
            dual_pane_activity.showAtPane(DualPaneActivity.PANE_LEFT, fragment, true);
        } else {
            final Uri.Builder builder = new Uri.Builder();
            builder.scheme(SCHEME_TWIDERE);
            builder.authority(AUTHORITY_USER_BLOCKS);
            builder.appendQueryParameter(QUERY_PARAM_ACCOUNT_ID, String.valueOf(account_id));
            activity.startActivity(new Intent(Intent.ACTION_VIEW, builder.build()));
        }
    }

    public static void openUserFavorites(final Activity activity, final long account_id, final long user_id,
            final String screen_name) {
        if (activity == null)
            return;
        if (activity instanceof DualPaneActivity && ((DualPaneActivity) activity).isDualPaneMode()) {
            final DualPaneActivity dual_pane_activity = (DualPaneActivity) activity;
            final Fragment fragment = new UserFavoritesFragment();
            final Bundle args = new Bundle();
            args.putLong(INTENT_KEY_ACCOUNT_ID, account_id);
            if (user_id > 0) {
                args.putLong(INTENT_KEY_USER_ID, user_id);
            }
            if (screen_name != null) {
                args.putString(INTENT_KEY_SCREEN_NAME, screen_name);
            }
            fragment.setArguments(args);
            dual_pane_activity.showAtPane(DualPaneActivity.PANE_LEFT, fragment, true);
        } else {
            final Uri.Builder builder = new Uri.Builder();
            builder.scheme(SCHEME_TWIDERE);
            builder.authority(AUTHORITY_USER_FAVORITES);
            builder.appendQueryParameter(QUERY_PARAM_ACCOUNT_ID, String.valueOf(account_id));
            if (user_id > 0) {
                builder.appendQueryParameter(QUERY_PARAM_USER_ID, String.valueOf(user_id));
            }
            if (screen_name != null) {
                builder.appendQueryParameter(QUERY_PARAM_SCREEN_NAME, screen_name);
            }
            activity.startActivity(new Intent(Intent.ACTION_VIEW, builder.build()));
        }

    }

    public static void openUserFollowers(final Activity activity, final long account_id, final long user_id,
            final String screen_name) {
        if (activity == null)
            return;
        if (activity instanceof DualPaneActivity && ((DualPaneActivity) activity).isDualPaneMode()) {
            final DualPaneActivity dual_pane_activity = (DualPaneActivity) activity;
            final Fragment fragment = new UserFollowersFragment();
            final Bundle args = new Bundle();
            args.putLong(INTENT_KEY_ACCOUNT_ID, account_id);
            if (user_id > 0) {
                args.putLong(INTENT_KEY_USER_ID, user_id);
            }
            if (screen_name != null) {
                args.putString(INTENT_KEY_SCREEN_NAME, screen_name);
            }
            fragment.setArguments(args);
            dual_pane_activity.showAtPane(DualPaneActivity.PANE_LEFT, fragment, true);
        } else {
            final Uri.Builder builder = new Uri.Builder();
            builder.scheme(SCHEME_TWIDERE);
            builder.authority(AUTHORITY_USER_FOLLOWERS);
            builder.appendQueryParameter(QUERY_PARAM_ACCOUNT_ID, String.valueOf(account_id));
            if (user_id > 0) {
                builder.appendQueryParameter(QUERY_PARAM_USER_ID, String.valueOf(user_id));
            }
            if (screen_name != null) {
                builder.appendQueryParameter(QUERY_PARAM_SCREEN_NAME, screen_name);
            }
            activity.startActivity(new Intent(Intent.ACTION_VIEW, builder.build()));
        }

    }

    public static void openUserFriends(final Activity activity, final long account_id, final long user_id,
            final String screen_name) {
        if (activity == null)
            return;
        if (activity instanceof DualPaneActivity && ((DualPaneActivity) activity).isDualPaneMode()) {
            final DualPaneActivity dual_pane_activity = (DualPaneActivity) activity;
            final Fragment fragment = new UserFriendsFragment();
            final Bundle args = new Bundle();
            args.putLong(INTENT_KEY_ACCOUNT_ID, account_id);
            if (user_id > 0) {
                args.putLong(INTENT_KEY_USER_ID, user_id);
            }
            if (screen_name != null) {
                args.putString(INTENT_KEY_SCREEN_NAME, screen_name);
            }
            fragment.setArguments(args);
            dual_pane_activity.showAtPane(DualPaneActivity.PANE_LEFT, fragment, true);
        } else {
            final Uri.Builder builder = new Uri.Builder();
            builder.scheme(SCHEME_TWIDERE);
            builder.authority(AUTHORITY_USER_FRIENDS);
            builder.appendQueryParameter(QUERY_PARAM_ACCOUNT_ID, String.valueOf(account_id));
            if (user_id > 0) {
                builder.appendQueryParameter(QUERY_PARAM_USER_ID, String.valueOf(user_id));
            }
            if (screen_name != null) {
                builder.appendQueryParameter(QUERY_PARAM_SCREEN_NAME, screen_name);
            }
            activity.startActivity(new Intent(Intent.ACTION_VIEW, builder.build()));
        }

    }

    public static void openUserListDetails(final Activity activity, final long account_id, final int list_id,
            final long user_id, final String screen_name, final String list_name) {
        if (activity == null)
            return;
        if (activity instanceof DualPaneActivity && ((DualPaneActivity) activity).isDualPaneMode()) {
            final DualPaneActivity dual_pane_activity = (DualPaneActivity) activity;
            final Fragment fragment = new UserListDetailsFragment();
            final Bundle args = new Bundle();
            args.putLong(INTENT_KEY_ACCOUNT_ID, account_id);
            args.putInt(INTENT_KEY_LIST_ID, list_id);
            args.putLong(INTENT_KEY_USER_ID, user_id);
            args.putString(INTENT_KEY_SCREEN_NAME, screen_name);
            args.putString(INTENT_KEY_LIST_NAME, list_name);
            fragment.setArguments(args);
            dual_pane_activity.showFragment(fragment, true);
        } else {
            final Uri.Builder builder = new Uri.Builder();
            builder.scheme(SCHEME_TWIDERE);
            builder.authority(AUTHORITY_LIST_DETAILS);
            builder.appendQueryParameter(QUERY_PARAM_ACCOUNT_ID, String.valueOf(account_id));
            if (list_id > 0) {
                builder.appendQueryParameter(QUERY_PARAM_LIST_ID, String.valueOf(list_id));
            }
            if (user_id > 0) {
                builder.appendQueryParameter(QUERY_PARAM_USER_ID, String.valueOf(user_id));
            }
            if (screen_name != null) {
                builder.appendQueryParameter(QUERY_PARAM_SCREEN_NAME, screen_name);
            }
            if (list_name != null) {
                builder.appendQueryParameter(QUERY_PARAM_LIST_NAME, list_name);
            }
            activity.startActivity(new Intent(Intent.ACTION_VIEW, builder.build()));
        }
    }

    public static void openUserListMembers(final Activity activity, final long account_id, final int list_id,
            final long user_id, final String screen_name, final String list_name) {
        if (activity == null)
            return;
        if (activity instanceof DualPaneActivity && ((DualPaneActivity) activity).isDualPaneMode()) {
            final DualPaneActivity dual_pane_activity = (DualPaneActivity) activity;
            final Fragment fragment = new UserListMembersFragment();
            final Bundle args = new Bundle();
            args.putLong(INTENT_KEY_ACCOUNT_ID, account_id);
            args.putInt(INTENT_KEY_LIST_ID, list_id);
            args.putLong(INTENT_KEY_USER_ID, user_id);
            args.putString(INTENT_KEY_SCREEN_NAME, screen_name);
            args.putString(INTENT_KEY_LIST_NAME, list_name);
            fragment.setArguments(args);
            dual_pane_activity.showAtPane(DualPaneActivity.PANE_LEFT, fragment, true);
        } else {
            final Uri.Builder builder = new Uri.Builder();
            builder.scheme(SCHEME_TWIDERE);
            builder.authority(AUTHORITY_LIST_MEMBERS);
            builder.appendQueryParameter(QUERY_PARAM_ACCOUNT_ID, String.valueOf(account_id));
            if (list_id > 0) {
                builder.appendQueryParameter(QUERY_PARAM_LIST_ID, String.valueOf(list_id));
            }
            if (user_id > 0) {
                builder.appendQueryParameter(QUERY_PARAM_USER_ID, String.valueOf(user_id));
            }
            if (screen_name != null) {
                builder.appendQueryParameter(QUERY_PARAM_SCREEN_NAME, screen_name);
            }
            if (list_name != null) {
                builder.appendQueryParameter(QUERY_PARAM_LIST_NAME, list_name);
            }
            activity.startActivity(new Intent(Intent.ACTION_VIEW, builder.build()));
        }
    }

    public static void openUserLists(final Activity activity, final long account_id, final long user_id,
            final String screen_name) {
        if (activity == null)
            return;
        if (activity instanceof DualPaneActivity && ((DualPaneActivity) activity).isDualPaneMode()) {
            final DualPaneActivity dual_pane_activity = (DualPaneActivity) activity;
            final Fragment fragment = new UserListsListFragment();
            final Bundle args = new Bundle();
            args.putLong(INTENT_KEY_ACCOUNT_ID, account_id);
            args.putLong(INTENT_KEY_USER_ID, user_id);
            args.putString(INTENT_KEY_SCREEN_NAME, screen_name);
            fragment.setArguments(args);
            dual_pane_activity.showAtPane(DualPaneActivity.PANE_LEFT, fragment, true);
        } else {
            final Uri.Builder builder = new Uri.Builder();
            builder.scheme(SCHEME_TWIDERE);
            builder.authority(AUTHORITY_LISTS);
            builder.appendQueryParameter(QUERY_PARAM_ACCOUNT_ID, String.valueOf(account_id));
            if (user_id > 0) {
                builder.appendQueryParameter(QUERY_PARAM_USER_ID, String.valueOf(user_id));
            }
            if (screen_name != null) {
                builder.appendQueryParameter(QUERY_PARAM_SCREEN_NAME, screen_name);
            }
            activity.startActivity(new Intent(Intent.ACTION_VIEW, builder.build()));
        }
    }

    public static void openUserListSubscribers(final Activity activity, final long account_id, final int list_id,
            final long user_id, final String screen_name, final String list_name) {
        if (activity == null)
            return;
        if (activity instanceof DualPaneActivity && ((DualPaneActivity) activity).isDualPaneMode()) {
            final DualPaneActivity dual_pane_activity = (DualPaneActivity) activity;
            final Fragment fragment = new UserListSubscribersFragment();
            final Bundle args = new Bundle();
            args.putLong(INTENT_KEY_ACCOUNT_ID, account_id);
            args.putInt(INTENT_KEY_LIST_ID, list_id);
            args.putLong(INTENT_KEY_USER_ID, user_id);
            args.putString(INTENT_KEY_SCREEN_NAME, screen_name);
            args.putString(INTENT_KEY_LIST_NAME, list_name);
            fragment.setArguments(args);
            dual_pane_activity.showAtPane(DualPaneActivity.PANE_LEFT, fragment, true);
        } else {
            final Uri.Builder builder = new Uri.Builder();
            builder.scheme(SCHEME_TWIDERE);
            builder.authority(AUTHORITY_LISTS);
            builder.appendQueryParameter(QUERY_PARAM_ACCOUNT_ID, String.valueOf(account_id));
            if (list_id > 0) {
                builder.appendQueryParameter(QUERY_PARAM_LIST_ID, String.valueOf(list_id));
            }
            if (user_id > 0) {
                builder.appendQueryParameter(QUERY_PARAM_USER_ID, String.valueOf(user_id));
            }
            if (screen_name != null) {
                builder.appendQueryParameter(QUERY_PARAM_SCREEN_NAME, screen_name);
            }
            if (list_name != null) {
                builder.appendQueryParameter(QUERY_PARAM_LIST_NAME, list_name);
            }
            activity.startActivity(new Intent(Intent.ACTION_VIEW, builder.build()));
        }
    }

    public static void openUserListTimeline(final Activity activity, final long account_id, final int list_id,
            final long user_id, final String screen_name, final String list_name) {
        if (activity == null)
            return;
        if (activity instanceof DualPaneActivity && ((DualPaneActivity) activity).isDualPaneMode()) {
            final DualPaneActivity dual_pane_activity = (DualPaneActivity) activity;
            final Fragment fragment = new UserListTimelineFragment();
            final Bundle args = new Bundle();
            args.putLong(INTENT_KEY_ACCOUNT_ID, account_id);
            args.putInt(INTENT_KEY_LIST_ID, list_id);
            args.putLong(INTENT_KEY_USER_ID, user_id);
            args.putString(INTENT_KEY_SCREEN_NAME, screen_name);
            args.putString(INTENT_KEY_LIST_NAME, list_name);
            fragment.setArguments(args);
            dual_pane_activity.showAtPane(DualPaneActivity.PANE_LEFT, fragment, true);
        } else {
            final Uri.Builder builder = new Uri.Builder();
            builder.scheme(SCHEME_TWIDERE);
            builder.authority(AUTHORITY_LIST_TIMELINE);
            builder.appendQueryParameter(QUERY_PARAM_ACCOUNT_ID, String.valueOf(account_id));
            if (list_id > 0) {
                builder.appendQueryParameter(QUERY_PARAM_LIST_ID, String.valueOf(list_id));
            }
            if (user_id > 0) {
                builder.appendQueryParameter(QUERY_PARAM_USER_ID, String.valueOf(user_id));
            }
            if (screen_name != null) {
                builder.appendQueryParameter(QUERY_PARAM_SCREEN_NAME, screen_name);
            }
            if (list_name != null) {
                builder.appendQueryParameter(QUERY_PARAM_LIST_NAME, list_name);
            }
            activity.startActivity(new Intent(Intent.ACTION_VIEW, builder.build()));
        }
    }

    public static void openUserMentions(final Activity activity, final long account_id, final String screen_name) {
        if (activity == null)
            return;
        if (activity instanceof DualPaneActivity && ((DualPaneActivity) activity).isDualPaneMode()) {
            final DualPaneActivity dual_pane_activity = (DualPaneActivity) activity;
            final Fragment fragment = new UserMentionsFragment();
            final Bundle args = new Bundle();
            args.putLong(INTENT_KEY_ACCOUNT_ID, account_id);
            if (screen_name != null) {
                args.putString(INTENT_KEY_SCREEN_NAME, screen_name);
            }
            fragment.setArguments(args);
            dual_pane_activity.showAtPane(DualPaneActivity.PANE_LEFT, fragment, true);
        } else {
            final Uri.Builder builder = new Uri.Builder();
            builder.scheme(SCHEME_TWIDERE);
            builder.authority(AUTHORITY_USER_MENTIONS);
            builder.appendQueryParameter(QUERY_PARAM_ACCOUNT_ID, String.valueOf(account_id));
            if (screen_name != null) {
                builder.appendQueryParameter(QUERY_PARAM_SCREEN_NAME, screen_name);
            }
            activity.startActivity(new Intent(Intent.ACTION_VIEW, builder.build()));
        }
    }

    public static void openUserProfile(final Activity activity, final long account_id, final long user_id,
            final String screen_name) {
        if (activity == null || account_id <= 0 || user_id <= 0 && isEmpty(screen_name))
            return;
        if (activity instanceof DualPaneActivity && ((DualPaneActivity) activity).isDualPaneMode()) {
            final DualPaneActivity dual_pane_activity = (DualPaneActivity) activity;
            final Fragment fragment = new UserProfileFragment();
            final Bundle args = new Bundle();
            args.putLong(INTENT_KEY_ACCOUNT_ID, account_id);
            if (user_id > 0) {
                args.putLong(INTENT_KEY_USER_ID, user_id);
            }
            if (screen_name != null) {
                args.putString(INTENT_KEY_SCREEN_NAME, screen_name);
            }
            fragment.setArguments(args);
            dual_pane_activity.showAtPane(DualPaneActivity.PANE_RIGHT, fragment, true);
        } else {
            final Uri.Builder builder = new Uri.Builder();
            builder.scheme(SCHEME_TWIDERE);
            builder.authority(AUTHORITY_USER);
            builder.appendQueryParameter(QUERY_PARAM_ACCOUNT_ID, String.valueOf(account_id));
            if (user_id > 0) {
                builder.appendQueryParameter(QUERY_PARAM_USER_ID, String.valueOf(user_id));
            }
            if (screen_name != null) {
                builder.appendQueryParameter(QUERY_PARAM_SCREEN_NAME, screen_name);
            }
            final Intent intent = new Intent(Intent.ACTION_VIEW, builder.build());
            activity.startActivity(intent);
        }
    }

    public static void openUserProfile(final Activity activity, final ParcelableUser user) {
        if (activity == null || user == null)
            return;
        final Bundle bundle = new Bundle();
        bundle.putParcelable(INTENT_KEY_USER, user);
        if (activity instanceof DualPaneActivity && ((DualPaneActivity) activity).isDualPaneMode()) {
            final DualPaneActivity dual_pane_activity = (DualPaneActivity) activity;
            final Fragment details_fragment = dual_pane_activity.getDetailsFragment();
            if (details_fragment instanceof UserProfileFragment && details_fragment.isAdded()) {
                ((UserProfileFragment) details_fragment).displayUser(user);
                dual_pane_activity.showRightPane();
            } else {
                final Fragment fragment = new UserProfileFragment();
                final Bundle args = new Bundle(bundle);
                args.putLong(INTENT_KEY_ACCOUNT_ID, user.account_id);
                if (user.user_id > 0) {
                    args.putLong(INTENT_KEY_USER_ID, user.user_id);
                }
                if (user.screen_name != null) {
                    args.putString(INTENT_KEY_SCREEN_NAME, user.screen_name);
                }
                fragment.setArguments(args);
                dual_pane_activity.showAtPane(DualPaneActivity.PANE_RIGHT, fragment, true);
            }
        } else {
            final Uri.Builder builder = new Uri.Builder();
            builder.scheme(SCHEME_TWIDERE);
            builder.authority(AUTHORITY_USER);
            builder.appendQueryParameter(QUERY_PARAM_ACCOUNT_ID, String.valueOf(user.account_id));
            if (user.user_id > 0) {
                builder.appendQueryParameter(QUERY_PARAM_USER_ID, String.valueOf(user.user_id));
            }
            if (user.screen_name != null) {
                builder.appendQueryParameter(QUERY_PARAM_SCREEN_NAME, user.screen_name);
            }
            final Intent intent = new Intent(Intent.ACTION_VIEW, builder.build());
            intent.putExtras(bundle);
            activity.startActivity(intent);
        }
    }

    public static void openUserTimeline(final Activity activity, final long account_id, final long user_id,
            final String screen_name) {
        if (activity == null)
            return;
        if (activity instanceof DualPaneActivity && ((DualPaneActivity) activity).isDualPaneMode()) {
            final DualPaneActivity dual_pane_activity = (DualPaneActivity) activity;
            final Fragment fragment = new UserTimelineFragment();
            final Bundle args = new Bundle();
            args.putLong(INTENT_KEY_ACCOUNT_ID, account_id);
            if (user_id > 0) {
                args.putLong(INTENT_KEY_USER_ID, user_id);
            }
            if (screen_name != null) {
                args.putString(INTENT_KEY_SCREEN_NAME, screen_name);
            }
            fragment.setArguments(args);
            dual_pane_activity.showAtPane(DualPaneActivity.PANE_LEFT, fragment, true);
        } else {
            final Uri.Builder builder = new Uri.Builder();
            builder.scheme(SCHEME_TWIDERE);
            builder.authority(AUTHORITY_USER_TIMELINE);
            builder.appendQueryParameter(QUERY_PARAM_ACCOUNT_ID, String.valueOf(account_id));
            if (user_id > 0) {
                builder.appendQueryParameter(QUERY_PARAM_USER_ID, String.valueOf(user_id));
            }
            if (screen_name != null) {
                builder.appendQueryParameter(QUERY_PARAM_SCREEN_NAME, screen_name);
            }
            activity.startActivity(new Intent(Intent.ACTION_VIEW, builder.build()));
        }

    }

    public static Bundle parseArguments(final String string) {
        final Bundle bundle = new Bundle();
        if (string != null) {
            try {
                final JSONObject json = new JSONObject(string);
                final Iterator<?> it = json.keys();
                while (it.hasNext()) {
                    final Object key_obj = it.next();
                    if (key_obj == null) {
                        continue;
                    }
                    final String key = key_obj.toString();
                    final Object value = json.get(key);
                    if (value instanceof Boolean) {
                        bundle.putBoolean(key, json.getBoolean(key));
                    } else if (value instanceof Integer) {
                        // Simple workaround for account_id
                        if (INTENT_KEY_ACCOUNT_ID.equals(key)) {
                            bundle.putLong(key, json.getLong(key));
                        } else {
                            bundle.putInt(key, json.getInt(key));
                        }
                    } else if (value instanceof Long) {
                        bundle.putLong(key, json.getLong(key));
                    } else if (value instanceof String) {
                        bundle.putString(key, json.getString(key));
                    } else {
                        Log.w(LOGTAG,
                                "Unknown type " + value.getClass().getSimpleName() + " in arguments key " + key);
                    }
                }
            } catch (final JSONException e) {
                e.printStackTrace();
            } catch (final ClassCastException e) {
                e.printStackTrace();
            }
        }
        return bundle;
    }

    public static double parseDouble(final String source) {
        if (source == null)
            return -1;
        try {
            return Double.parseDouble(source);
        } catch (final NumberFormatException e) {
            // Wrong number format? Ignore them.
        }
        return -1;
    }

    public static int parseInt(final String source) {
        if (source == null)
            return -1;
        try {
            return Integer.valueOf(source);
        } catch (final NumberFormatException e) {
            // Wrong number format? Ignore them.
        }
        return -1;
    }

    public static long parseLong(final String source) {
        if (source == null)
            return -1;
        try {
            return Long.parseLong(source);
        } catch (final NumberFormatException e) {
            // Wrong number format? Ignore them.
        }
        return -1;
    }

    public static String parseString(final Object object) {
        return parseString(object, null);
    }

    public static String parseString(final Object object, final String def) {
        if (object == null)
            return def;
        return String.valueOf(object);
    }

    public static URL parseURL(final String url_string) {
        if (url_string == null)
            return null;
        try {
            return new URL(url_string);
        } catch (final MalformedURLException e) {
            // This should not happen.
        }
        return null;
    }

    public static String replaceLast(final String text, final String regex, final String replacement) {
        if (text == null || regex == null || replacement == null)
            return text;
        return text.replaceFirst("(?s)" + regex + "(?!.*?" + regex + ")", replacement);
    }

    /**
     * Resizes specific a Bitmap with keeping ratio.
     */
    public static Bitmap resizeBitmap(Bitmap orig, final int desireWidth, final int desireHeight) {
        final int width = orig.getWidth();
        final int height = orig.getHeight();

        if (0 < width && 0 < height && desireWidth < width || desireHeight < height) {
            // Calculate scale
            float scale;
            if (width < height) {
                scale = (float) desireHeight / (float) height;
                if (desireWidth < width * scale) {
                    scale = (float) desireWidth / (float) width;
                }
            } else {
                scale = (float) desireWidth / (float) width;
            }

            // Draw resized image
            final Matrix matrix = new Matrix();
            matrix.postScale(scale, scale);
            final Bitmap bitmap = Bitmap.createBitmap(orig, 0, 0, width, height, matrix, true);
            final Canvas canvas = new Canvas(bitmap);
            canvas.drawBitmap(bitmap, 0, 0, null);

            orig = bitmap;
        }

        return orig;
    }

    public static void restartActivity(final Activity activity) {
        if (activity == null)
            return;
        final int enter_anim = android.R.anim.fade_in;
        final int exit_anim = android.R.anim.fade_out;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ECLAIR) {
            ActivityAccessor.overridePendingTransition(activity, enter_anim, exit_anim);
        } else {
            activity.getWindow().setWindowAnimations(0);
        }
        activity.finish();
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ECLAIR) {
            ActivityAccessor.overridePendingTransition(activity, enter_anim, exit_anim);
        } else {
            activity.getWindow().setWindowAnimations(0);
        }
        activity.startActivity(activity.getIntent());
    }

    public static void setMenuForStatus(final Context context, final Menu menu, final ParcelableStatus status) {
        if (context == null || menu == null || status == null)
            return;
        final int activated_color = context.getResources().getColor(R.color.holo_blue_bright);
        final MenuItem delete = menu.findItem(R.id.delete_submenu);
        if (delete != null) {
            delete.setVisible(status.account_id == status.user_id && !isMyRetweet(status));
        }
        final MenuItem retweet = menu.findItem(MENU_RETWEET);
        if (retweet != null) {
            final Drawable icon = retweet.getIcon().mutate();
            retweet.setVisible(!status.is_protected || isMyRetweet(status));
            if (isMyRetweet(status)) {
                icon.setColorFilter(activated_color, Mode.MULTIPLY);
                retweet.setTitle(R.string.cancel_retweet);
            } else {
                icon.clearColorFilter();
                retweet.setTitle(R.string.retweet);
            }
        }
        final MenuItem favorite = menu.findItem(MENU_FAVORITE);
        if (favorite != null) {
            final Drawable icon = favorite.getIcon().mutate();
            if (status.is_favorite) {
                icon.setColorFilter(activated_color, Mode.MULTIPLY);
                favorite.setTitle(R.string.unfavorite);
            } else {
                icon.clearColorFilter();
                favorite.setTitle(R.string.favorite);
            }
        }
        final MenuItem extensions = menu.findItem(MENU_EXTENSIONS_SUBMENU);
        if (extensions != null) {
            final Intent intent = new Intent(INTENT_ACTION_EXTENSION_OPEN_STATUS);
            final Bundle extras = new Bundle();
            extras.putParcelable(INTENT_KEY_STATUS, status);
            intent.putExtras(extras);
            final PackageManager pm = context.getPackageManager();
            final List<ResolveInfo> activities = pm.queryIntentActivities(intent, 0);
            final boolean has_extension = !activities.isEmpty();
            extensions.setVisible(has_extension);
            if (has_extension) {
                addIntentToSubMenu(context, extensions.getSubMenu(), intent);
            }
        }
    }

    public static void setUserAgent(final Context context, final ConfigurationBuilder cb) {
        final SharedPreferences prefs = context.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE);
        final boolean gzip_compressing = prefs.getBoolean(PREFERENCE_KEY_GZIP_COMPRESSING, true);
        final PackageManager pm = context.getPackageManager();
        try {
            final PackageInfo pi = pm.getPackageInfo(context.getPackageName(), 0);
            final String version_name = pi.versionName;
            cb.setClientVersion(pi.versionName);
            cb.setClientName(APP_NAME);
            cb.setClientURL(APP_PROJECT_URL);
            cb.setUserAgent(
                    APP_NAME + " " + APP_PROJECT_URL + " / " + version_name + (gzip_compressing ? " (gzip)" : ""));
        } catch (final PackageManager.NameNotFoundException e) {

        }
    }

    public static void setUserColor(final Context context, final long user_id, final int color) {
        if (context == null)
            return;
        final SharedPreferences prefs = context.getSharedPreferences(USER_COLOR_PREFERENCES_NAME,
                Context.MODE_PRIVATE);
        final SharedPreferences.Editor editor = prefs.edit();
        editor.putInt(parseString(user_id), color);
        editor.commit();
        sUserColors.put(user_id, color);
    }

    public static void showErrorToast(final Context context, final int action, final String desc,
            final boolean long_message) {
        if (context == null)
            return;
        showErrorToast(context, context.getString(action), desc, long_message);
    }

    public static void showErrorToast(final Context context, final int action, final Throwable t,
            final boolean long_message) {
        if (context == null)
            return;
        showErrorToast(context, context.getString(action), t, long_message);
    }

    public static void showErrorToast(final Context context, final String message, final boolean long_message) {
        if (context == null)
            return;
        final String text;
        if (message != null) {
            text = context.getString(R.string.error_message, message);
        } else {
            text = context.getString(R.string.error_unknown_error);
        }
        final int length = long_message ? Toast.LENGTH_LONG : Toast.LENGTH_SHORT;
        final Toast toast = Toast.makeText(context, text, length);
        toast.show();
    }

    public static void showErrorToast(final Context context, final String action, final String desc,
            final boolean long_message) {
        if (context == null)
            return;
        final String message;
        if (desc != null) {
            message = context.getString(R.string.error_message, desc);
        } else {
            message = context.getString(R.string.error_unknown_error);
        }
        final int length = long_message ? Toast.LENGTH_LONG : Toast.LENGTH_SHORT;
        final Toast toast = Toast.makeText(context, message, length);
        toast.show();
    }

    @SuppressWarnings("deprecation")
    public static void showErrorToast(final Context context, final String action, final Throwable t,
            final boolean long_message) {
        if (context == null)
            return;
        final String message;
        if (t != null) {
            t.printStackTrace();
            final String t_message = trimLineBreak(t.getMessage());
            if (action != null) {
                if (t instanceof TwitterException) {
                    final TwitterException te = (TwitterException) t;
                    if (te.exceededRateLimitation()) {
                        final RateLimitStatus status = te.getRateLimitStatus();
                        final String next_reset_time_string = DateUtils.formatDateTime(context,
                                status.getResetTime().getTime(),
                                DateFormat.is24HourFormat(context)
                                        ? DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_24HOUR
                                        : DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_12HOUR);
                        message = context.getString(R.string.error_message_rate_limit, action,
                                next_reset_time_string);
                    } else {
                        message = context.getString(R.string.error_message_with_action, action, t_message);
                    }
                } else {
                    message = context.getString(R.string.error_message_with_action, action, t_message);
                }
            } else {
                message = context.getString(R.string.error_message, t_message);
            }
        } else {
            message = context.getString(R.string.error_unknown_error);
        }
        final int length = long_message ? Toast.LENGTH_LONG : Toast.LENGTH_SHORT;
        final Toast toast = Toast.makeText(context, message, length);
        toast.show();
    }

    public static String trimLineBreak(final String orig) {
        if (orig == null)
            return null;
        return orig.replaceAll("\\n+", "\n");
    }

    private static Bitmap getTabIconFromFile(final File file, final Resources res) {
        if (file == null || !file.exists())
            return null;
        final String path = file.getPath();
        final BitmapFactory.Options o = new BitmapFactory.Options();
        o.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(path, o);
        if (o.outHeight <= 0 || o.outWidth <= 0)
            return null;
        final BitmapFactory.Options o2 = new BitmapFactory.Options();
        o2.inSampleSize = (int) (Math.max(o.outWidth, o.outHeight) / (48 * res.getDisplayMetrics().density));
        return BitmapFactory.decodeFile(path, o2);
    }

    private static void parseEntities(final HtmlBuilder builder, final EntitySupport entities) {
        final URLEntity[] urls = entities.getURLEntities();
        // Format media.
        final MediaEntity[] medias = entities.getMediaEntities();
        if (medias != null) {
            for (final MediaEntity media : medias) {
                final URL media_url = media.getMediaURL();
                if (media_url != null) {
                    builder.addLink(parseString(media_url), media.getDisplayURL(), media.getStart(),
                            media.getEnd());
                }
            }
        }
        if (urls != null) {
            for (final URLEntity url : urls) {
                final URL expanded_url = url.getExpandedURL();
                if (expanded_url != null) {
                    builder.addLink(parseString(expanded_url), url.getDisplayURL(), url.getStart(), url.getEnd());
                }
            }
        }
    }
}