org.mariotaku.twidere.activity.ComposeActivity.java Source code

Java tutorial

Introduction

Here is the source code for org.mariotaku.twidere.activity.ComposeActivity.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.activity;

import static android.os.Environment.getExternalStorageState;
import static android.text.TextUtils.isEmpty;
import static org.mariotaku.twidere.util.Utils.addIntentToSubMenu;
import static org.mariotaku.twidere.util.Utils.getAccountColors;
import static org.mariotaku.twidere.util.Utils.getAccountIds;
import static org.mariotaku.twidere.util.Utils.getAccountScreenName;
import static org.mariotaku.twidere.util.Utils.getImagePathFromUri;
import static org.mariotaku.twidere.util.Utils.getImageUploadStatus;
import static org.mariotaku.twidere.util.Utils.getShareStatus;
import static org.mariotaku.twidere.util.Utils.openImage;
import static org.mariotaku.twidere.util.Utils.parseString;
import static org.mariotaku.twidere.util.Utils.showErrorToast;

import java.io.File;

import org.mariotaku.menubar.MenuBar;
import org.mariotaku.menubar.MenuBar.OnMenuItemClickListener;
import org.mariotaku.popupmenu.PopupMenu;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.fragment.BaseDialogFragment;
import org.mariotaku.twidere.model.ParcelableLocation;
import org.mariotaku.twidere.provider.TweetStore.Drafts;
import org.mariotaku.twidere.util.ArrayUtils;
import org.mariotaku.twidere.util.AsyncTwitterWrapper;
import org.mariotaku.twidere.util.BitmapDecodeHelper;
import org.mariotaku.twidere.util.EnvironmentAccessor;
import org.mariotaku.twidere.view.ColorView;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.ActivityNotFoundException;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.graphics.PorterDuff.Mode;
import android.graphics.drawable.Drawable;
import android.location.Criteria;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
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.LoaderManager;
import android.support.v4.app.LoaderManager.LoaderCallbacks;
import android.support.v4.app.NavUtils;
import android.support.v4.content.AsyncTaskLoader;
import android.support.v4.content.Loader;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnLongClickListener;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.TextView.OnEditorActionListener;
import android.widget.Toast;

import com.twitter.Validator;

public class ComposeActivity extends BaseDialogWhenLargeActivity
        implements TextWatcher, LocationListener, OnMenuItemClickListener, OnClickListener, OnLongClickListener,
        PopupMenu.OnMenuItemClickListener, OnEditorActionListener, LoaderCallbacks<Bitmap> {

    private static final String FAKE_IMAGE_LINK = "https://www.example.com/fake_image.jpg";
    private static final String INTENT_KEY_CONTENT_MODIFIED = "content_modified";
    private static final String INTENT_KEY_IS_NAVIGATE_UP = "is_navigate_up";
    private static final String INTENT_KEY_IS_POSSIBLY_SENSITIVE = "is_possibly_sensitive";

    private AsyncTwitterWrapper mTwitterWrapper;
    private LocationManager mLocationManager;
    private SharedPreferences mPreferences;
    private ParcelableLocation mRecentLocation;
    private ContentResolver mResolver;
    private final Validator mValidator = new Validator();

    private PopupMenu mPopupMenu;

    private static final int THUMBNAIL_SIZE = 36;

    private ColorView mColorIndicator;
    private EditText mEditText;
    private TextView mTextCount;
    private ImageView mImageThumbnailPreview;
    private MenuBar mMenuBar;

    private boolean mIsImageAttached, mIsPhotoAttached;
    private long[] mAccountIds;
    private String mText;
    private Uri mImageUri;
    private long mInReplyToStatusId = -1;
    private String mInReplyToScreenName, mInReplyToName;
    private boolean mIsQuote, mUploadUseExtension, mContentModified, mIsPossiblySensitive;

    private DialogFragment mUnsavedTweetDialogFragment;

    private boolean mLoaderInitialized;

    @Override
    public void afterTextChanged(final Editable s) {

    }

    @Override
    public void beforeTextChanged(final CharSequence s, final int start, final int count, final int after) {

    }

    @Override
    public void onActivityResult(final int requestCode, final int resultCode, final Intent intent) {
        switch (requestCode) {
        case REQUEST_TAKE_PHOTO: {
            if (resultCode == Activity.RESULT_OK) {
                final File file = new File(mImageUri.getPath());
                if (file.exists()) {
                    mIsImageAttached = false;
                    mIsPhotoAttached = true;
                    mImageThumbnailPreview.setVisibility(View.VISIBLE);
                    reloadAttachedImageThumbnail(file);
                } else {
                    mIsPhotoAttached = false;
                }
                setMenu();
            } else {
                mImageUri = null;
            }
            break;
        }
        case REQUEST_PICK_IMAGE: {
            if (resultCode == Activity.RESULT_OK) {
                final Uri uri = intent.getData();
                final String path = getImagePathFromUri(this, uri);
                final File file = path == null ? null : new File(path);
                if (file != null && file.exists()) {
                    mImageUri = Uri.fromFile(file);
                    mIsPhotoAttached = false;
                    mIsImageAttached = true;
                    mImageThumbnailPreview.setVisibility(View.VISIBLE);
                    reloadAttachedImageThumbnail(file);
                } else {
                    mIsImageAttached = false;
                }
                setMenu();
            }
            break;
        }
        case REQUEST_SELECT_ACCOUNT: {
            if (resultCode == Activity.RESULT_OK) {
                final Bundle bundle = intent.getExtras();
                if (bundle == null) {
                    break;
                }
                final long[] account_ids = bundle.getLongArray(INTENT_KEY_IDS);
                if (account_ids != null) {
                    mAccountIds = account_ids;
                    if (mInReplyToStatusId <= 0) {
                        final SharedPreferences.Editor editor = mPreferences.edit();
                        editor.putString(PREFERENCE_KEY_COMPOSE_ACCOUNTS,
                                ArrayUtils.toString(mAccountIds, ',', false));
                        editor.commit();
                    }
                    mColorIndicator.setColors(getAccountColors(this, account_ids));
                }
            }
            break;
        }
        case REQUEST_EDIT_IMAGE: {
            if (resultCode == Activity.RESULT_OK) {
                final Uri uri = intent.getData();
                final File file = uri == null ? null : new File(getImagePathFromUri(this, uri));
                if (file != null && file.exists()) {
                    mImageUri = Uri.fromFile(file);
                    reloadAttachedImageThumbnail(file);
                } else {
                    break;
                }
                setMenu();
            }
            break;
        }
        case REQUEST_EXTENSION_COMPOSE: {
            if (resultCode == Activity.RESULT_OK) {
                final Bundle extras = intent.getExtras();
                if (extras == null) {
                    break;
                }
                final String text = extras.getString(INTENT_KEY_TEXT);
                final String append = extras.getString(INTENT_KEY_APPEND_TEXT);
                final Uri image_uri = extras.getParcelable(INTENT_KEY_IMAGE_URI);
                if (text != null) {
                    mEditText.setText(text);
                    mText = parseString(mEditText.getText());
                } else if (append != null) {
                    mEditText.append(append);
                    mText = parseString(mEditText.getText());
                }
                final File file = image_uri == null ? null : new File(getImagePathFromUri(this, image_uri));
                if (file != null && file.exists()) {
                    mImageUri = Uri.fromFile(file);
                    reloadAttachedImageThumbnail(file);
                }
                setMenu();
            }
            break;
        }
        }

    }

    @Override
    public void onBackPressed() {
        final String text = mEditText != null ? parseString(mEditText.getText()) : null;
        if (mContentModified && !isEmpty(text)) {
            mUnsavedTweetDialogFragment = (DialogFragment) Fragment.instantiate(this,
                    UnsavedTweetDialogFragment.class.getName());
            final Bundle args = new Bundle();
            args.putBoolean(INTENT_KEY_IS_NAVIGATE_UP, false);
            mUnsavedTweetDialogFragment.setArguments(args);
            mUnsavedTweetDialogFragment.show(getSupportFragmentManager(), "unsaved_tweet");
            return;
        }
        super.onBackPressed();
    }

    @Override
    public void onClick(final View view) {
        switch (view.getId()) {
        case R.id.image_thumbnail_preview: {
            if (mPopupMenu != null) {
                mPopupMenu.dismiss();
            }
            mPopupMenu = PopupMenu.getInstance(this, view);
            mPopupMenu.inflate(R.menu.action_attached_image);
            final Menu menu = mPopupMenu.getMenu();
            final MenuItem extensions = menu.findItem(MENU_EXTENSIONS_SUBMENU);
            if (extensions != null) {
                final Intent intent = new Intent(INTENT_ACTION_EXTENSION_EDIT_IMAGE);
                intent.setData(mImageUri);
                addIntentToSubMenu(this, extensions.getSubMenu(), intent);
            }
            mPopupMenu.setOnMenuItemClickListener(this);
            mPopupMenu.show();
            break;
        }
        }

    }

    @Override
    public void onContentChanged() {
        super.onContentChanged();
        mColorIndicator = (ColorView) findViewById(R.id.account_colors);
        mEditText = (EditText) findViewById(R.id.edit_text);
        mTextCount = (TextView) findViewById(R.id.text_count);
        mImageThumbnailPreview = (ImageView) findViewById(R.id.image_thumbnail_preview);
        mMenuBar = (MenuBar) findViewById(R.id.menu_bar);
    }

    @Override
    public void onCreate(final Bundle savedInstanceState) {
        mLocationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
        mPreferences = getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE);
        mTwitterWrapper = getTwidereApplication().getTwitterWrapper();
        mResolver = getContentResolver();
        super.onCreate(savedInstanceState);
        final long[] account_ids = getAccountIds(this);
        if (account_ids.length <= 0) {
            final Intent intent = new Intent(INTENT_ACTION_TWITTER_LOGIN);
            intent.setClass(this, SignInActivity.class);
            startActivity(intent);
            finish();
            return;
        }
        setContentView(R.layout.compose);
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);

        final Bundle bundle = savedInstanceState != null ? savedInstanceState : getIntent().getExtras();
        final long account_id = bundle != null ? bundle.getLong(INTENT_KEY_ACCOUNT_ID) : -1;
        mAccountIds = bundle != null ? bundle.getLongArray(INTENT_KEY_IDS) : null;
        mInReplyToStatusId = bundle != null ? bundle.getLong(INTENT_KEY_IN_REPLY_TO_ID) : -1;
        mInReplyToScreenName = bundle != null ? bundle.getString(INTENT_KEY_IN_REPLY_TO_SCREEN_NAME) : null;
        mInReplyToName = bundle != null ? bundle.getString(INTENT_KEY_IN_REPLY_TO_NAME) : null;
        mIsImageAttached = bundle != null ? bundle.getBoolean(INTENT_KEY_IS_IMAGE_ATTACHED) : false;
        mIsPhotoAttached = bundle != null ? bundle.getBoolean(INTENT_KEY_IS_PHOTO_ATTACHED) : false;
        mImageUri = bundle != null ? (Uri) bundle.getParcelable(INTENT_KEY_IMAGE_URI) : null;
        final String[] mentions = bundle != null ? bundle.getStringArray(INTENT_KEY_MENTIONS) : null;
        final int notification_id = bundle != null ? bundle.getInt(INTENT_KEY_NOTIFICATION_ID, -1) : -1;
        if (notification_id != -1) {
            mTwitterWrapper.clearNotification(notification_id);
        }
        final String account_screen_name = getAccountScreenName(this, account_id);
        int text_selection_start = -1;
        if (mInReplyToStatusId > 0) {
            if (bundle != null && bundle.getString(INTENT_KEY_TEXT) != null
                    && (mentions == null || mentions.length < 1)) {
                mText = bundle.getString(INTENT_KEY_TEXT);
            } else if (mentions != null) {
                final StringBuilder builder = new StringBuilder();
                for (final String mention : mentions) {
                    if (mentions.length == 1 && mentions[0].equalsIgnoreCase(account_screen_name)) {
                        builder.append('@' + account_screen_name + ' ');
                    } else if (!mention.equalsIgnoreCase(account_screen_name)) {
                        builder.append('@' + mention + ' ');
                    }
                }
                mText = builder.toString();
                text_selection_start = mText.indexOf(' ') + 1;
            }

            mIsQuote = bundle != null ? bundle.getBoolean(INTENT_KEY_IS_QUOTE, false) : false;

            final boolean display_screen_name = NAME_DISPLAY_OPTION_SCREEN_NAME
                    .equals(mPreferences.getString(PREFERENCE_KEY_NAME_DISPLAY_OPTION, NAME_DISPLAY_OPTION_BOTH));
            if (mInReplyToScreenName != null && mInReplyToName != null) {
                setTitle(getString(mIsQuote ? R.string.quote_user : R.string.reply_to,
                        display_screen_name ? mInReplyToScreenName : mInReplyToName));
            }
            if (mAccountIds == null || mAccountIds.length == 0) {
                mAccountIds = new long[] { account_id };
            }
        } else {
            if (mentions != null) {
                final StringBuilder builder = new StringBuilder();
                for (final String mention : mentions) {
                    if (mentions.length == 1 && mentions[0].equalsIgnoreCase(account_screen_name)) {
                        builder.append('@' + account_screen_name + ' ');
                    } else if (!mention.equalsIgnoreCase(account_screen_name)) {
                        builder.append('@' + mention + ' ');
                    }
                }
                mText = builder.toString();
            }
            if (mAccountIds == null || mAccountIds.length == 0) {
                final long[] ids_in_prefs = ArrayUtils
                        .fromString(mPreferences.getString(PREFERENCE_KEY_COMPOSE_ACCOUNTS, null), ',');
                final long[] intersection = ArrayUtils.intersection(ids_in_prefs, account_ids);
                mAccountIds = intersection.length > 0 ? intersection : account_ids;
            }
            final String action = getIntent().getAction();
            if (Intent.ACTION_SEND.equals(action) || Intent.ACTION_SEND_MULTIPLE.equals(action)) {
                setTitle(R.string.share);
                final Bundle extras = getIntent().getExtras();
                if (extras != null) {
                    if (mText == null) {
                        final CharSequence extra_subject = extras.getCharSequence(Intent.EXTRA_SUBJECT);
                        final CharSequence extra_text = extras.getCharSequence(Intent.EXTRA_TEXT);
                        mText = getShareStatus(this, parseString(extra_subject), parseString(extra_text));
                    } else {
                        mText = bundle.getString(INTENT_KEY_TEXT);
                    }
                    if (mImageUri == null) {
                        final Uri extra_stream = extras.getParcelable(Intent.EXTRA_STREAM);
                        final String content_type = getIntent().getType();
                        if (extra_stream != null && content_type != null && content_type.startsWith("image/")) {
                            final String real_path = getImagePathFromUri(this, extra_stream);
                            final File file = real_path != null ? new File(real_path) : null;
                            if (file != null && file.exists()) {
                                mImageUri = Uri.fromFile(file);
                                mIsImageAttached = true;
                                mIsPhotoAttached = false;
                            } else {
                                mImageUri = null;
                                mIsImageAttached = false;
                            }
                        }
                    }
                }
            } else if (bundle != null) {
                if (bundle.getString(INTENT_KEY_TEXT) != null) {
                    mText = bundle.getString(INTENT_KEY_TEXT);
                }
            }
        }

        final File image_file = mImageUri != null && "file".equals(mImageUri.getScheme())
                ? new File(mImageUri.getPath())
                : null;
        final boolean image_file_valid = image_file != null && image_file.exists();
        mImageThumbnailPreview.setVisibility(image_file_valid ? View.VISIBLE : View.GONE);
        if (image_file_valid) {
            reloadAttachedImageThumbnail(image_file);
        }

        mImageThumbnailPreview.setOnClickListener(this);
        mImageThumbnailPreview.setOnLongClickListener(this);
        mMenuBar.setOnMenuItemClickListener(this);
        mMenuBar.inflate(R.menu.menu_compose);
        final Menu menu = mMenuBar.getMenu();
        final MenuItem extensions = menu.findItem(MENU_EXTENSIONS_SUBMENU);
        if (extensions != null) {
            final Intent intent = new Intent(INTENT_ACTION_EXTENSION_COMPOSE);
            final Bundle extras = new Bundle();
            final String screen_name = mAccountIds != null && mAccountIds.length > 0
                    ? getAccountScreenName(this, mAccountIds[0])
                    : null;
            extras.putString(INTENT_KEY_TEXT, parseString(mEditText.getText()));
            extras.putString(INTENT_KEY_IN_REPLY_TO_SCREEN_NAME, mInReplyToScreenName);
            extras.putString(INTENT_KEY_IN_REPLY_TO_NAME, mInReplyToName);
            extras.putString(INTENT_KEY_SCREEN_NAME, screen_name);
            extras.putLong(INTENT_KEY_IN_REPLY_TO_ID, mInReplyToStatusId);
            intent.putExtras(extras);
            addIntentToSubMenu(this, extensions.getSubMenu(), intent);
        }
        mMenuBar.show();
        if (mPreferences.getBoolean(PREFERENCE_KEY_QUICK_SEND, false)) {
            mEditText.setOnEditorActionListener(this);
        }
        mEditText.addTextChangedListener(this);
        if (mText != null) {
            mEditText.setText(mText);
            if (mIsQuote) {
                mEditText.setSelection(0);
            } else if (text_selection_start != -1 && text_selection_start < mEditText.length()
                    && mEditText.length() > 0) {
                mEditText.setSelection(text_selection_start, mEditText.length() - 1);
            } else if (mEditText.length() > 0) {
                mEditText.setSelection(mEditText.length());
            }
        }
        setMenu();
        mColorIndicator.setColors(getAccountColors(this, mAccountIds));
        mContentModified = savedInstanceState != null ? savedInstanceState.getBoolean(INTENT_KEY_CONTENT_MODIFIED)
                : false;
        mIsPossiblySensitive = savedInstanceState != null
                ? savedInstanceState.getBoolean(INTENT_KEY_IS_POSSIBLY_SENSITIVE)
                : false;
    }

    @Override
    public Loader<Bitmap> onCreateLoader(final int id, final Bundle args) {
        return new AttachedImageThumbnailLoader(this, args.getString(INTENT_KEY_FILENAME));
    }

    @Override
    public boolean onCreateOptionsMenu(final Menu menu) {
        getMenuInflater().inflate(R.menu.menu_compose_actionbar, menu);
        return super.onCreateOptionsMenu(menu);
    }

    @Override
    public boolean onEditorAction(final TextView view, final int actionId, final KeyEvent event) {
        if (event == null)
            return false;
        switch (event.getKeyCode()) {
        case KeyEvent.KEYCODE_ENTER: {
            send();
            return true;
        }
        }
        return false;
    }

    @Override
    public void onLoaderReset(final Loader<Bitmap> loader) {
        mImageThumbnailPreview.setVisibility(View.GONE);
        mImageThumbnailPreview.setImageBitmap(null);
    }

    @Override
    public void onLoadFinished(final Loader<Bitmap> loader, final Bitmap data) {
        mImageThumbnailPreview.setVisibility(data != null ? View.VISIBLE : View.GONE);
        mImageThumbnailPreview.setImageBitmap(data);

    }

    @Override
    public void onLocationChanged(final Location location) {
        if (mRecentLocation == null) {
            mRecentLocation = location != null ? new ParcelableLocation(location) : null;
            setSupportProgressBarIndeterminateVisibility(false);
        }
    }

    @Override
    public boolean onLongClick(final View view) {
        switch (view.getId()) {
        case R.id.image_thumbnail_preview: {
            onClick(view);
            return true;
        }
        }
        return false;
    }

    @Override
    public boolean onMenuItemClick(final MenuItem item) {
        switch (item.getItemId()) {
        case MENU_TAKE_PHOTO: {
            takePhoto();
            break;
        }
        case MENU_ADD_IMAGE: {
            pickImage();
            break;
        }
        case MENU_ADD_LOCATION: {
            final boolean attach_location = mPreferences.getBoolean(PREFERENCE_KEY_ATTACH_LOCATION, false);
            if (!attach_location) {
                getLocation();
            }
            mPreferences.edit().putBoolean(PREFERENCE_KEY_ATTACH_LOCATION, !attach_location).commit();
            setMenu();
            break;
        }
        case MENU_DRAFTS: {
            startActivity(new Intent(INTENT_ACTION_DRAFTS));
            break;
        }
        case MENU_DELETE: {
            if (mImageUri == null)
                return false;
            if (mIsPhotoAttached && !mIsImageAttached) {
                final File image_file = "file".equals(mImageUri.getScheme()) ? new File(mImageUri.getPath()) : null;
                if (image_file != null) {
                    image_file.delete();
                }
            }
            mImageUri = null;
            mIsPhotoAttached = false;
            mIsImageAttached = false;
            reloadAttachedImageThumbnail(null);
            setMenu();
            break;
        }
        case MENU_VIEW: {
            openImage(this, mImageUri, false);
            break;
        }
        case MENU_TOGGLE_SENSITIVE: {
            final boolean has_media = (mIsImageAttached || mIsPhotoAttached) && mImageUri != null;
            if (!has_media)
                return false;
            mIsPossiblySensitive = !mIsPossiblySensitive;
            setMenu();
            break;
        }
        default: {
            final Intent intent = item.getIntent();
            if (intent != null) {
                try {
                    if (INTENT_ACTION_EXTENSION_COMPOSE.equals(intent.getAction())) {
                        startActivityForResult(intent, REQUEST_EXTENSION_COMPOSE);
                    } else if (INTENT_ACTION_EXTENSION_EDIT_IMAGE.equals(intent.getAction())) {
                        startActivityForResult(intent, REQUEST_EDIT_IMAGE);
                    } else {
                        startActivity(intent);
                    }
                } catch (final ActivityNotFoundException e) {
                    Log.w(LOGTAG, e);
                    return false;
                }
            }
            break;
        }
        }
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(final MenuItem item) {
        switch (item.getItemId()) {
        case MENU_HOME: {
            final String text = mEditText != null ? parseString(mEditText.getText()) : null;
            if (mContentModified && !isEmpty(text)) {
                mUnsavedTweetDialogFragment = (DialogFragment) Fragment.instantiate(this,
                        UnsavedTweetDialogFragment.class.getName());
                final Bundle args = new Bundle();
                args.putBoolean(INTENT_KEY_IS_NAVIGATE_UP, true);
                mUnsavedTweetDialogFragment.setArguments(args);
                mUnsavedTweetDialogFragment.show(getSupportFragmentManager(), "unsaved_tweet");
            } else {
                // NavUtils.navigateUpFromSameTask(this);
                onBackPressed();
            }
            break;
        }
        case MENU_SEND: {
            send();
            break;
        }
        case MENU_SELECT_ACCOUNT: {
            final Intent intent = new Intent(INTENT_ACTION_SELECT_ACCOUNT);
            final Bundle bundle = new Bundle();
            bundle.putBoolean(INTENT_KEY_ACTIVATED_ONLY, false);
            bundle.putLongArray(INTENT_KEY_IDS, mAccountIds);
            intent.putExtras(bundle);
            startActivityForResult(intent, REQUEST_SELECT_ACCOUNT);
            break;
        }
        }
        return super.onOptionsItemSelected(item);
    }

    @Override
    public boolean onPrepareOptionsMenu(final Menu menu) {
        if (menu == null || mEditText == null || mTextCount == null)
            return false;
        final String text_orig = parseString(mEditText.getText());
        final String text = mIsPhotoAttached || mIsImageAttached
                ? mUploadUseExtension ? getImageUploadStatus(this, FAKE_IMAGE_LINK, text_orig)
                        : text_orig + " " + FAKE_IMAGE_LINK
                : text_orig;
        final int count = mValidator.getTweetLength(text);
        final float hue = count < Validator.MAX_TWEET_LENGTH
                ? count >= Validator.MAX_TWEET_LENGTH - 10 ? 5 * (Validator.MAX_TWEET_LENGTH - count) : 50
                : 0;
        final float[] hsv = new float[] { hue, 1.0f, 1.0f };
        mTextCount
                .setTextColor(count >= Validator.MAX_TWEET_LENGTH - 10 ? Color.HSVToColor(0x80, hsv) : 0x80808080);
        mTextCount.setText(parseString(Validator.MAX_TWEET_LENGTH - count));
        final MenuItem sendItem = menu.findItem(MENU_SEND);
        if (sendItem != null) {
            sendItem.setEnabled(text_orig.length() > 0);
        }
        return super.onPrepareOptionsMenu(menu);
    }

    @Override
    public void onProviderDisabled(final String provider) {
        setSupportProgressBarIndeterminateVisibility(false);
    }

    @Override
    public void onProviderEnabled(final String provider) {
    }

    @Override
    public void onSaveInstanceState(final Bundle outState) {
        mText = parseString(mEditText.getText());
        outState.putLongArray(INTENT_KEY_IDS, mAccountIds);
        outState.putString(INTENT_KEY_TEXT, mText);
        outState.putLong(INTENT_KEY_IN_REPLY_TO_ID, mInReplyToStatusId);
        outState.putString(INTENT_KEY_IN_REPLY_TO_NAME, mInReplyToName);
        outState.putString(INTENT_KEY_IN_REPLY_TO_SCREEN_NAME, mInReplyToScreenName);
        outState.putBoolean(INTENT_KEY_IS_QUOTE, mIsQuote);
        outState.putBoolean(INTENT_KEY_IS_IMAGE_ATTACHED, mIsImageAttached);
        outState.putBoolean(INTENT_KEY_IS_PHOTO_ATTACHED, mIsPhotoAttached);
        outState.putParcelable(INTENT_KEY_IMAGE_URI, mImageUri);
        outState.putBoolean(INTENT_KEY_CONTENT_MODIFIED, mContentModified);
        outState.putBoolean(INTENT_KEY_IS_POSSIBLY_SENSITIVE, mIsPossiblySensitive);
        super.onSaveInstanceState(outState);
    }

    @Override
    public void onStatusChanged(final String provider, final int status, final Bundle extras) {

    }

    @Override
    public void onTextChanged(final CharSequence s, final int start, final int before, final int count) {
        invalidateSupportOptionsMenu();
        mContentModified = true;
    }

    //
    // @Override
    // public void onTitleChanged(final CharSequence title, final int color) {
    // mActionBarCompat.setTitle(title);
    // super.onTitleChanged(title, color);
    // }

    public void saveToDrafts() {
        final String text = mEditText != null ? parseString(mEditText.getText()) : null;
        final ContentValues values = new ContentValues();
        values.put(Drafts.TEXT, text);
        values.put(Drafts.ACCOUNT_IDS, ArrayUtils.toString(mAccountIds, ',', false));
        values.put(Drafts.IN_REPLY_TO_STATUS_ID, mInReplyToStatusId);
        values.put(Drafts.IN_REPLY_TO_NAME, mInReplyToName);
        values.put(Drafts.IN_REPLY_TO_SCREEN_NAME, mInReplyToScreenName);
        values.put(Drafts.IS_QUOTE, mIsQuote ? 1 : 0);
        values.put(Drafts.LOCATION, ParcelableLocation.toString(mRecentLocation));
        values.put(Drafts.IS_POSSIBLY_SENSITIVE, mIsPossiblySensitive ? 1 : 0);
        if (mImageUri != null) {
            values.put(Drafts.IS_IMAGE_ATTACHED, mIsImageAttached);
            values.put(Drafts.IS_PHOTO_ATTACHED, mIsPhotoAttached);
            values.put(Drafts.IMAGE_URI, parseString(mImageUri));
        }
        mResolver.insert(Drafts.CONTENT_URI, values);
    }

    @Override
    protected void onStart() {
        super.onStart();
        final String uploader_component = mPreferences.getString(PREFERENCE_KEY_IMAGE_UPLOADER, null);
        mUploadUseExtension = !isEmpty(uploader_component);
        if (mMenuBar != null) {
            setMenu();
        }
        final int text_size = mPreferences.getInt(PREFERENCE_KEY_TEXT_SIZE, PREFERENCE_DEFAULT_TEXT_SIZE);
        mEditText.setTextSize(text_size * 1.25f);
    }

    @Override
    protected void onStop() {
        if (mPopupMenu != null) {
            mPopupMenu.dismiss();
        }
        mLocationManager.removeUpdates(this);
        super.onStop();
    }

    /**
     * The Location Manager manages location providers. This code searches for
     * the best provider of data (GPS, WiFi/cell phone tower lookup, some other
     * mechanism) and finds the last known location.
     **/
    private boolean getLocation() {
        final Criteria criteria = new Criteria();
        criteria.setAccuracy(Criteria.ACCURACY_FINE);
        final String provider = mLocationManager.getBestProvider(criteria, true);

        if (provider != null) {
            final Location location;
            if (mLocationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) {
                location = mLocationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
            } else {
                location = mLocationManager.getLastKnownLocation(provider);
            }
            if (location == null) {
                mLocationManager.requestLocationUpdates(provider, 0, 0, this);
                setSupportProgressBarIndeterminateVisibility(true);
            }
            mRecentLocation = location != null ? new ParcelableLocation(location) : null;
        } else {
            Toast.makeText(this, R.string.cannot_get_location, Toast.LENGTH_SHORT).show();
        }
        return provider != null;
    }

    private void pickImage() {
        final Intent i = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
        try {
            startActivityForResult(i, REQUEST_PICK_IMAGE);
        } catch (final ActivityNotFoundException e) {
            showErrorToast(this, null, e, false);
        }
    }

    private void reloadAttachedImageThumbnail(final File file) {
        final LoaderManager lm = getSupportLoaderManager();
        lm.destroyLoader(0);
        final Bundle args = new Bundle();
        args.putString(INTENT_KEY_FILENAME, file != null ? file.getPath() : null);
        if (mLoaderInitialized) {
            lm.restartLoader(0, args, this);
        } else {
            lm.initLoader(0, args, this);
            mLoaderInitialized = true;
        }
    }

    private void send() {
        final String text = mEditText != null ? parseString(mEditText.getText()) : null;
        if (isEmpty(text) || isFinishing())
            return;
        final boolean has_media = (mIsImageAttached || mIsPhotoAttached) && mImageUri != null;
        final boolean attach_location = mPreferences.getBoolean(PREFERENCE_KEY_ATTACH_LOCATION, false);
        if (mRecentLocation == null && attach_location) {
            final Location location;
            if (mLocationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) {
                location = mLocationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
            } else {
                location = null;
            }
            mRecentLocation = location != null ? new ParcelableLocation(location) : null;
        }
        mTwitterWrapper.updateStatus(mAccountIds, text, attach_location ? mRecentLocation : null, mImageUri,
                mInReplyToStatusId, has_media && mIsPossiblySensitive, mIsPhotoAttached && !mIsImageAttached);
        setResult(Activity.RESULT_OK);
        finish();
    }

    private void setMenu() {
        final Menu menu = mMenuBar.getMenu();
        final int activated_color = getResources().getColor(R.color.holo_blue_bright);
        final MenuItem itemAddImage = menu.findItem(MENU_ADD_IMAGE);
        final Drawable iconAddImage = itemAddImage.getIcon().mutate();
        if (mIsImageAttached && !mIsPhotoAttached) {
            iconAddImage.setColorFilter(activated_color, Mode.MULTIPLY);
            itemAddImage.setTitle(R.string.remove_image);
        } else {
            iconAddImage.clearColorFilter();
            itemAddImage.setTitle(R.string.add_image);
        }
        final MenuItem itemTakePhoto = menu.findItem(MENU_TAKE_PHOTO);
        final Drawable iconTakePhoto = itemTakePhoto.getIcon().mutate();
        if (!mIsImageAttached && mIsPhotoAttached) {
            iconTakePhoto.setColorFilter(activated_color, Mode.MULTIPLY);
            itemTakePhoto.setTitle(R.string.remove_photo);
        } else {
            iconTakePhoto.clearColorFilter();
            itemTakePhoto.setTitle(R.string.take_photo);
        }
        final MenuItem itemAttachLocation = menu.findItem(MENU_ADD_LOCATION);
        final Drawable iconAttachLocation = itemAttachLocation.getIcon().mutate();
        final boolean attach_location = mPreferences.getBoolean(PREFERENCE_KEY_ATTACH_LOCATION, false);
        if (attach_location && getLocation()) {
            iconAttachLocation.setColorFilter(activated_color, Mode.MULTIPLY);
            itemAttachLocation.setTitle(R.string.remove_location);
        } else {
            mPreferences.edit().putBoolean(PREFERENCE_KEY_ATTACH_LOCATION, false).commit();
            iconAttachLocation.clearColorFilter();
            itemAttachLocation.setTitle(R.string.add_location);
        }
        final MenuItem itemMore = menu.findItem(R.id.more_submenu);
        final MenuItem itemDrafts = menu.findItem(MENU_DRAFTS);
        final MenuItem itemToggleSensitive = menu.findItem(MENU_TOGGLE_SENSITIVE);
        if (itemMore != null) {
            if (itemDrafts != null) {
                final Cursor drafts_cur = getContentResolver().query(Drafts.CONTENT_URI, new String[0], null, null,
                        null);
                final Drawable iconMore = itemMore.getIcon().mutate();
                final Drawable iconDrafts = itemDrafts.getIcon().mutate();
                if (drafts_cur.getCount() > 0) {
                    iconMore.setColorFilter(activated_color, Mode.MULTIPLY);
                    iconDrafts.setColorFilter(activated_color, Mode.MULTIPLY);
                } else {
                    iconMore.clearColorFilter();
                    iconDrafts.clearColorFilter();
                }
                drafts_cur.close();
            }
            if (itemToggleSensitive != null) {
                final boolean has_media = (mIsImageAttached || mIsPhotoAttached) && mImageUri != null;
                itemToggleSensitive.setVisible(has_media);
                if (has_media) {
                    final Drawable iconToggleSensitive = itemToggleSensitive.getIcon().mutate();
                    if (mIsPossiblySensitive) {
                        itemToggleSensitive.setTitle(R.string.remove_sensitive_mark);
                        iconToggleSensitive.setColorFilter(activated_color, Mode.MULTIPLY);
                    } else {
                        itemToggleSensitive.setTitle(R.string.mark_as_sensitive);
                        iconToggleSensitive.clearColorFilter();
                    }
                }
            }
        }
        mMenuBar.invalidate();
        invalidateSupportOptionsMenu();
    }

    private void takePhoto() {
        final Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        if (getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
            final File cache_dir = EnvironmentAccessor.getExternalCacheDir(this);
            final File file = new File(cache_dir, "tmp_photo_" + System.currentTimeMillis() + ".jpg");
            mImageUri = Uri.fromFile(file);
            intent.putExtra(MediaStore.EXTRA_OUTPUT, mImageUri);
            try {
                startActivityForResult(intent, REQUEST_TAKE_PHOTO);
            } catch (final ActivityNotFoundException e) {
                showErrorToast(this, null, e, false);
            }
        }
    }

    public static final class AttachedImageThumbnailLoader extends AsyncTaskLoader<Bitmap> {

        private final File file;

        public AttachedImageThumbnailLoader(final Context context, final String path) {
            super(context);
            file = path != null ? new File(path) : null;
        }

        @Override
        public Bitmap loadInBackground() {
            if (file != null && file.exists()) {
                final int thumbnail_size_px = (int) (THUMBNAIL_SIZE
                        * getContext().getResources().getDisplayMetrics().density);
                final BitmapFactory.Options o = new BitmapFactory.Options();
                o.inJustDecodeBounds = true;
                BitmapFactory.decodeFile(file.getPath(), o);
                final int tmp_width = o.outWidth;
                final int tmp_height = o.outHeight;
                if (tmp_width == 0 || tmp_height == 0)
                    return null;
                final BitmapFactory.Options o2 = new BitmapFactory.Options();
                o2.inSampleSize = Math.round(Math.max(tmp_width, tmp_height) / thumbnail_size_px);
                return BitmapDecodeHelper.decode(file.getPath(), o2);
            }
            return null;
        }

        @Override
        protected void onStartLoading() {
            forceLoad();
        }
    }

    public static class UnsavedTweetDialogFragment extends BaseDialogFragment
            implements DialogInterface.OnClickListener {

        private boolean mIsNavigateUp;

        @Override
        public void onActivityCreated(final Bundle savedInstanceState) {
            super.onActivityCreated(savedInstanceState);
            final Bundle args = getArguments();
            if (args != null) {
                // mIsNavigateUp = args.getBoolean(INTENT_KEY_IS_NAVIGATE_UP);
            }
        }

        @Override
        public void onClick(final DialogInterface dialog, final int which) {
            final FragmentActivity activity = getActivity();
            switch (which) {
            case DialogInterface.BUTTON_POSITIVE: {
                if (activity instanceof ComposeActivity) {
                    ((ComposeActivity) activity).saveToDrafts();
                    if (mIsNavigateUp) {
                        NavUtils.navigateUpFromSameTask(activity);
                    } else {
                        activity.finish();
                    }
                }
                break;
            }
            case DialogInterface.BUTTON_NEGATIVE: {
                if (mIsNavigateUp) {
                    NavUtils.navigateUpFromSameTask(activity);
                } else {
                    activity.finish();
                }
                break;
            }
            }

        }

        @Override
        public Dialog onCreateDialog(final Bundle savedInstanceState) {
            final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
            builder.setMessage(R.string.unsaved_tweet);
            builder.setPositiveButton(R.string.save, this);
            builder.setNegativeButton(R.string.discard, this);
            return builder.create();
        }

    }
}