de.vanita5.twittnuker.activity.support.ComposeActivity.java Source code

Java tutorial

Introduction

Here is the source code for de.vanita5.twittnuker.activity.support.ComposeActivity.java

Source

/*
 * Twittnuker - Twitter client for Android
 *
 * Copyright (C) 2013-2014 vanita5 <mail@vanita5.de>
 *
 * This program incorporates a modified version of Twidere.
 * Copyright (C) 2012-2014 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 de.vanita5.twittnuker.activity.support;

import static android.os.Environment.getExternalStorageState;
import static android.text.TextUtils.isEmpty;
import static de.vanita5.twittnuker.model.ParcelableLocation.isValidLocation;
import static de.vanita5.twittnuker.util.ParseUtils.parseString;
import static de.vanita5.twittnuker.util.ThemeUtils.getActionBarBackground;
import static de.vanita5.twittnuker.util.ThemeUtils.getComposeThemeResource;
import static de.vanita5.twittnuker.util.ThemeUtils.getUserThemeColor;
import static de.vanita5.twittnuker.util.ThemeUtils.getWindowContentOverlayForCompose;
import static de.vanita5.twittnuker.util.UserColorNicknameUtils.getUserColor;
import static de.vanita5.twittnuker.util.Utils.copyStream;
import static de.vanita5.twittnuker.util.Utils.getAccountColors;
import static de.vanita5.twittnuker.util.Utils.getAccountIds;
import static de.vanita5.twittnuker.util.Utils.getAccountScreenName;
import static de.vanita5.twittnuker.util.Utils.getCardHighlightColor;
import static de.vanita5.twittnuker.util.Utils.getDefaultTextSize;
import static de.vanita5.twittnuker.util.Utils.getDisplayName;
import static de.vanita5.twittnuker.util.Utils.getImageUploadStatus;
import static de.vanita5.twittnuker.util.Utils.getQuoteStatus;
import static de.vanita5.twittnuker.util.Utils.getShareStatus;
import static de.vanita5.twittnuker.util.Utils.getStatusTypeIconRes;
import static de.vanita5.twittnuker.util.Utils.getUserTypeIconRes;
import static de.vanita5.twittnuker.util.Utils.showErrorMessage;
import static de.vanita5.twittnuker.util.Utils.showMenuItemToast;

import android.annotation.TargetApi;
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.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.PorterDuff.Mode;
import android.graphics.Rect;
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.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.Parcelable;
import android.provider.MediaStore;
import android.support.v4.app.DialogFragment;
import android.support.v4.util.LongSparseArray;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MenuItem.OnMenuItemClickListener;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnLongClickListener;
import android.view.ViewGroup;
import android.widget.EditText;
import android.widget.GridView;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.ScrollView;
import android.widget.TextView;
import android.widget.TextView.OnEditorActionListener;
import android.widget.Toast;

import org.mariotaku.dynamicgridview.DraggableArrayAdapter;

import com.nostra13.universalimageloader.utils.IoUtils;
import com.scvngr.levelup.views.gallery.AdapterView;
import com.scvngr.levelup.views.gallery.AdapterView.OnItemClickListener;
import com.scvngr.levelup.views.gallery.AdapterView.OnItemLongClickListener;
import com.scvngr.levelup.views.gallery.Gallery;
import com.twitter.Extractor;

import de.keyboardsurfer.android.widget.crouton.Crouton;
import de.keyboardsurfer.android.widget.crouton.CroutonStyle;

import org.mariotaku.menucomponent.widget.MenuBar;
import org.mariotaku.menucomponent.widget.PopupMenu;
import de.vanita5.twittnuker.R;
import de.vanita5.twittnuker.adapter.BaseArrayAdapter;
import de.vanita5.twittnuker.app.TwittnukerApplication;
import de.vanita5.twittnuker.fragment.support.BaseSupportDialogFragment;
import de.vanita5.twittnuker.model.Account;
import de.vanita5.twittnuker.model.DraftItem;
import de.vanita5.twittnuker.model.ParcelableLocation;
import de.vanita5.twittnuker.model.ParcelableMedia;
import de.vanita5.twittnuker.model.ParcelableMediaUpdate;
import de.vanita5.twittnuker.model.ParcelableStatus;
import de.vanita5.twittnuker.model.ParcelableStatusUpdate;
import de.vanita5.twittnuker.model.ParcelableUser;
import de.vanita5.twittnuker.preference.ServicePickerPreference;
import de.vanita5.twittnuker.provider.TweetStore.Drafts;
import de.vanita5.twittnuker.task.AsyncTask;
import de.vanita5.twittnuker.util.ArrayUtils;
import de.vanita5.twittnuker.util.AsyncTwitterWrapper;
import de.vanita5.twittnuker.util.ContentValuesCreator;
import de.vanita5.twittnuker.util.ImageLoaderWrapper;
import de.vanita5.twittnuker.util.MathUtils;
import de.vanita5.twittnuker.util.ParseUtils;
import de.vanita5.twittnuker.util.SharedPreferencesWrapper;
import de.vanita5.twittnuker.util.ThemeUtils;
import de.vanita5.twittnuker.util.TwidereValidator;
import de.vanita5.twittnuker.util.accessor.ViewAccessor;
import de.vanita5.twittnuker.view.StatusTextCountView;
import de.vanita5.twittnuker.view.holder.StatusViewHolder;
import de.vanita5.twittnuker.view.iface.IColorLabelView;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.TreeSet;

public class ComposeActivity extends BaseSupportDialogActivity
        implements TextWatcher, LocationListener, OnMenuItemClickListener, OnClickListener, OnEditorActionListener,
        OnItemClickListener, OnItemLongClickListener, OnLongClickListener {

    private static final String FAKE_IMAGE_LINK = "https://www.example.com/fake_image.jpg";

    private static final String EXTRA_IS_POSSIBLY_SENSITIVE = "is_possibly_sensitive";

    private static final String EXTRA_SHOULD_SAVE_ACCOUNTS = "should_save_accounts";

    private static final String EXTRA_ORIGINAL_TEXT = "original_text";

    private static final String EXTRA_TEMP_URI = "temp_uri";
    private static final String EXTRA_SHARE_SCREENSHOT = "share_screenshot";

    private TwidereValidator mValidator;
    private final Extractor mExtractor = new Extractor();

    private AsyncTwitterWrapper mTwitterWrapper;
    private LocationManager mLocationManager;
    private SharedPreferencesWrapper mPreferences;
    private ParcelableLocation mRecentLocation;

    private ContentResolver mResolver;
    private AsyncTask<Void, Void, ?> mTask;
    private PopupMenu mPopupMenu;
    private TextView mTitleView, mSubtitleView;
    private GridView mMediasPreviewGrid;

    private MenuBar mBottomMenuBar, mActionMenuBar;
    private IColorLabelView mColorIndicator;
    private EditText mEditText;
    private ProgressBar mProgress;
    private Gallery mAccountSelector;
    private View mAccountSelectorDivider, mBottomSendDivider;
    private View mBottomMenuContainer;
    private View mSendView, mBottomSendView;
    private StatusTextCountView mSendTextCountView, mBottomSendTextCountView;

    private MediaPreviewAdapter mMediaPreviewAdapter;
    private AccountSelectorAdapter mAccountSelectorAdapter;

    private boolean mIsPossiblySensitive, mShouldSaveAccounts;

    private long[] mAccountIds, mSendAccountIds;

    private Uri mTempPhotoUri;
    private boolean mImageUploaderUsed, mStatusShortenerUsed;
    private ParcelableStatus mInReplyToStatus;

    private ParcelableUser mMentionUser;
    private DraftItem mDraftItem;
    private long mInReplyToStatusId;
    private String mOriginalText;

    private boolean mBottomSendButton;

    private final Rect mWindowDecorHitRect = new Rect();

    @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 int getOverrideAccentColor() {
        return ThemeUtils.getUserThemeColor(this);
    }

    @Override
    public int getThemeResourceId() {
        return getComposeThemeResource(this);
    }

    public boolean handleMenuItem(final MenuItem item) {
        switch (item.getItemId()) {
        case MENU_TAKE_PHOTO: {
            takePhoto();
            break;
        }
        case MENU_ADD_IMAGE: {
            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT || !openDocument()) {
                pickImage();
            }
            break;
        }
        case MENU_ADD_LOCATION: {
            final boolean attachLocation = mPreferences.getBoolean(KEY_ATTACH_LOCATION, false);
            if (!attachLocation) {
                getLocation();
            } else {
                mLocationManager.removeUpdates(this);
            }
            mPreferences.edit().putBoolean(KEY_ATTACH_LOCATION, !attachLocation).apply();
            setMenu();
            updateTextCount();
            break;
        }
        case MENU_DRAFTS: {
            startActivity(new Intent(INTENT_ACTION_DRAFTS));
            break;
        }
        case MENU_DELETE: {
            new DeleteImageTask(this).execute();
            break;
        }
        case MENU_TOGGLE_SENSITIVE: {
            if (!hasMedia())
                return false;
            mIsPossiblySensitive = !mIsPossiblySensitive;
            setMenu();
            updateTextCount();
            break;
        }
        case MENU_VIEW: {
            if (mInReplyToStatus == null)
                return false;
            final DialogFragment fragment = new ViewStatusDialogFragment();
            final Bundle args = new Bundle();
            args.putParcelable(EXTRA_STATUS, mInReplyToStatus);
            fragment.setArguments(args);
            fragment.show(getSupportFragmentManager(), "view_status");
            break;
        }
        default: {
            break;
        }
        }
        return true;
    }

    @Override
    public void onActivityResult(final int requestCode, final int resultCode, final Intent intent) {
        switch (requestCode) {
        case REQUEST_TAKE_PHOTO: {
            if (resultCode == Activity.RESULT_OK) {
                mTask = new AddMediaTask(this, mTempPhotoUri, createTempImageUri(), ParcelableMedia.TYPE_IMAGE,
                        true).execute();
                mTempPhotoUri = null;
            }
            break;
        }
        case REQUEST_PICK_IMAGE: {
            if (resultCode == Activity.RESULT_OK) {
                final Uri src = intent.getData();
                mTask = new AddMediaTask(this, src, createTempImageUri(), ParcelableMedia.TYPE_IMAGE, false)
                        .execute();
            }
            break;
        }
        case REQUEST_OPEN_DOCUMENT: {
            if (resultCode == Activity.RESULT_OK) {
                final Uri src = intent.getData();
                mTask = new AddMediaTask(this, src, createTempImageUri(), ParcelableMedia.TYPE_IMAGE, false)
                        .execute();
            }
            break;
        }
        case REQUEST_EDIT_IMAGE: {
            if (resultCode == Activity.RESULT_OK) {
                final Uri uri = intent.getData();
                if (uri != null) {
                    //
                } else {
                    break;
                }
                setMenu();
                updateTextCount();
            }
            break;
        }
        }

    }

    @Override
    public void onBackPressed() {
        if (mTask != null && mTask.getStatus() == AsyncTask.Status.RUNNING)
            return;
        final String option = mPreferences.getString(KEY_COMPOSE_QUIT_ACTION, VALUE_COMPOSE_QUIT_ACTION_ASK);
        final String text = mEditText != null ? ParseUtils.parseString(mEditText.getText()) : null;
        final boolean textChanged = text != null && !text.isEmpty() && !text.equals(mOriginalText);
        final boolean isEditingDraft = INTENT_ACTION_EDIT_DRAFT.equals(getIntent().getAction());
        if (VALUE_COMPOSE_QUIT_ACTION_DISCARD.equals(option)) {
            mTask = new DiscardTweetTask(this).execute();
        } else if (textChanged || hasMedia() || isEditingDraft) {
            if (VALUE_COMPOSE_QUIT_ACTION_SAVE.equals(option)) {
                saveToDrafts();
                Toast.makeText(this, R.string.status_saved_to_draft, Toast.LENGTH_SHORT).show();
                finish();
            } else {
                new UnsavedTweetDialogFragment().show(getSupportFragmentManager(), "unsaved_tweet");
            }
        } else {
            mTask = new DiscardTweetTask(this).execute();
        }
    }

    @Override
    public void onClick(final View view) {
        switch (view.getId()) {
        case R.id.close: {
            onBackPressed();
            break;
        }
        case R.id.send: {
            if (isQuotingProtectedStatus()) {
                new RetweetProtectedStatusWarnFragment().show(getSupportFragmentManager(),
                        "retweet_protected_status_warning_message");
            } else {
                updateStatus();
            }
            break;
        }
        }
    }

    @Override
    public void onContentChanged() {
        super.onContentChanged();
        findViewById(R.id.close).setOnClickListener(this);
        mColorIndicator = (IColorLabelView) findViewById(R.id.accounts_color);
        mEditText = (EditText) findViewById(R.id.edit_text);
        mTitleView = (TextView) findViewById(R.id.actionbar_title);
        mSubtitleView = (TextView) findViewById(R.id.actionbar_subtitle);
        mMediasPreviewGrid = (GridView) findViewById(R.id.medias_thumbnail_preview);
        mBottomMenuBar = (MenuBar) findViewById(R.id.bottom_menu);
        mBottomMenuContainer = findViewById(R.id.bottom_menu_container);
        mActionMenuBar = (MenuBar) findViewById(R.id.action_menu);
        mProgress = (ProgressBar) findViewById(R.id.actionbar_progress_indeterminate);
        mAccountSelectorDivider = findViewById(R.id.account_selector_divider);
        mBottomSendDivider = findViewById(R.id.bottom_send_divider);
        mAccountSelector = (Gallery) findViewById(R.id.account_selector);
        final View composeActionBar = findViewById(R.id.compose_actionbar);
        final View composeBottomBar = findViewById(R.id.compose_bottombar);
        mSendView = composeActionBar.findViewById(R.id.send);
        mBottomSendView = composeBottomBar.findViewById(R.id.send);
        mSendTextCountView = (StatusTextCountView) mSendView.findViewById(R.id.status_text_count);
        mBottomSendTextCountView = (StatusTextCountView) mBottomSendView.findViewById(R.id.status_text_count);
        ViewAccessor.setBackground(findViewById(R.id.compose_content), getWindowContentOverlayForCompose(this));
        ViewAccessor.setBackground(composeActionBar, getActionBarBackground(this, getCurrentThemeResourceId()));
    }

    @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: {
            updateStatus();
            return true;
        }
        }
        return false;
    }

    @Override
    public void onItemClick(final AdapterView<?> parent, final View view, final int position, final long id) {
        if (isSingleAccount())
            return;
        final boolean selected = !view.isActivated();
        final Account account = mAccountSelectorAdapter.getItem(position);
        mAccountSelectorAdapter.setAccountSelected(account.account_id, selected);
        mSendAccountIds = mAccountSelectorAdapter.getSelectedAccountIds();
        updateAccountSelection();
    }

    @Override
    public boolean onItemLongClick(final AdapterView<?> parent, final View view, final int position,
            final long id) {
        final Account account = mAccountSelectorAdapter.getItem(position);
        final String displayName = getDisplayName(this, account.account_id, account.name, account.screen_name);
        showMenuItemToast(view, displayName, true);
        return true;
    }

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

    @Override
    public boolean onLongClick(final View v) {
        switch (v.getId()) {
        case R.id.send: {
            showMenuItemToast(v, getString(R.string.send), mBottomSendButton);
            return true;
        }
        }
        return false;
    }

    @Override
    public boolean onMenuItemClick(final MenuItem item) {
        return handleMenuItem(item);
    }

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

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

    @Override
    public void onSaveInstanceState(final Bundle outState) {
        outState.putLongArray(EXTRA_ACCOUNT_IDS, mSendAccountIds);
        outState.putParcelableArrayList(EXTRA_MEDIAS, new ArrayList<Parcelable>(getMediasList()));
        outState.putBoolean(EXTRA_IS_POSSIBLY_SENSITIVE, mIsPossiblySensitive);
        outState.putParcelable(EXTRA_STATUS, mInReplyToStatus);
        outState.putLong(EXTRA_STATUS_ID, mInReplyToStatusId);
        outState.putParcelable(EXTRA_USER, mMentionUser);
        outState.putParcelable(EXTRA_DRAFT, mDraftItem);
        outState.putBoolean(EXTRA_SHOULD_SAVE_ACCOUNTS, mShouldSaveAccounts);
        outState.putString(EXTRA_ORIGINAL_TEXT, mOriginalText);
        outState.putParcelable(EXTRA_TEMP_URI, mTempPhotoUri);
        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) {
        setMenu();
        updateTextCount();
    }

    @Override
    public boolean onTouchEvent(final MotionEvent event) {
        switch (event.getActionMasked()) {
        case MotionEvent.ACTION_DOWN: {
            getWindow().getDecorView().getHitRect(mWindowDecorHitRect);
            if (!mWindowDecorHitRect.contains(Math.round(event.getX()), Math.round(event.getY()))) {
                onBackPressed();
                return true;
            }
            break;
        }
        }
        return super.onTouchEvent(event);
    }

    public void removeAllMedia(final List<ParcelableMediaUpdate> list) {
        mMediaPreviewAdapter.removeAll(list);
        updateMediasPreview();
    }

    public void saveToDrafts() {
        final String text = mEditText != null ? ParseUtils.parseString(mEditText.getText()) : null;
        final ParcelableStatusUpdate.Builder builder = new ParcelableStatusUpdate.Builder();
        builder.accounts(Account.getAccounts(this, mSendAccountIds));
        builder.text(text);
        builder.inReplyToStatusId(mInReplyToStatusId);
        builder.location(mRecentLocation);
        builder.isPossiblySensitive(mIsPossiblySensitive);
        if (hasMedia()) {
            builder.medias(getMedias());
        }
        final ContentValues values = ContentValuesCreator.makeStatusDraftContentValues(builder.build());
        mResolver.insert(Drafts.CONTENT_URI, values);
    }

    @Override
    protected void onCreate(final Bundle savedInstanceState) {
        // requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
        super.onCreate(savedInstanceState);
        mLocationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
        mPreferences = SharedPreferencesWrapper.getInstance(this, SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE);
        mBottomSendButton = mPreferences.getBoolean(KEY_BOTTOM_SEND_BUTTON, false);
        mTwitterWrapper = getTwittnukerApplication().getTwitterWrapper();
        mResolver = getContentResolver();
        mValidator = new TwidereValidator(this);
        setContentView(getLayoutInflater().inflate(R.layout.activity_compose, null));
        setProgressBarIndeterminateVisibility(false);
        setFinishOnTouchOutside(false);
        mAccountIds = getAccountIds(this);
        if (mAccountIds.length <= 0) {
            final Intent intent = new Intent(INTENT_ACTION_TWITTER_LOGIN);
            intent.setClass(this, SignInActivity.class);
            startActivity(intent);
            finish();
            return;
        }
        mBottomMenuBar.setIsBottomBar(true);
        mBottomMenuBar.setOnMenuItemClickListener(this);
        mActionMenuBar.setOnMenuItemClickListener(this);
        mEditText.setOnEditorActionListener(mPreferences.getBoolean(KEY_QUICK_SEND, false) ? this : null);
        mEditText.addTextChangedListener(this);
        mAccountSelectorAdapter = new AccountSelectorAdapter(this);
        mAccountSelector.setAdapter(mAccountSelectorAdapter);
        mAccountSelector.setOnItemClickListener(this);
        mAccountSelector.setOnItemLongClickListener(this);
        mAccountSelector.setScrollAfterItemClickEnabled(false);
        mAccountSelector.setScrollRightSpacingEnabled(false);

        mMediaPreviewAdapter = new MediaPreviewAdapter(this);
        mMediasPreviewGrid.setAdapter(mMediaPreviewAdapter);

        final Intent intent = getIntent();

        if (savedInstanceState != null) {
            // Restore from previous saved state
            mSendAccountIds = savedInstanceState.getLongArray(EXTRA_ACCOUNT_IDS);
            mIsPossiblySensitive = savedInstanceState.getBoolean(EXTRA_IS_POSSIBLY_SENSITIVE);
            final ArrayList<ParcelableMediaUpdate> mediasList = savedInstanceState
                    .getParcelableArrayList(EXTRA_MEDIAS);
            if (mediasList != null) {
                addMedias(mediasList);
            }
            mInReplyToStatus = savedInstanceState.getParcelable(EXTRA_STATUS);
            mInReplyToStatusId = savedInstanceState.getLong(EXTRA_STATUS_ID);
            mMentionUser = savedInstanceState.getParcelable(EXTRA_USER);
            mDraftItem = savedInstanceState.getParcelable(EXTRA_DRAFT);
            mShouldSaveAccounts = savedInstanceState.getBoolean(EXTRA_SHOULD_SAVE_ACCOUNTS);
            mOriginalText = savedInstanceState.getString(EXTRA_ORIGINAL_TEXT);
            mTempPhotoUri = savedInstanceState.getParcelable(EXTRA_TEMP_URI);
        } else {
            // The activity was first created
            final int notificationId = intent.getIntExtra(EXTRA_NOTIFICATION_ID, -1);
            final long notificationAccount = intent.getLongExtra(EXTRA_NOTIFICATION_ACCOUNT, -1);
            if (notificationId != -1) {
                mTwitterWrapper.clearNotificationAsync(notificationId, notificationAccount);
            }
            if (!handleIntent(intent)) {
                handleDefaultIntent(intent);
            }
            if (mSendAccountIds == null || mSendAccountIds.length == 0) {
                final long[] ids_in_prefs = ArrayUtils
                        .parseLongArray(mPreferences.getString(KEY_COMPOSE_ACCOUNTS, null), ',');
                final long[] intersection = ArrayUtils.intersection(ids_in_prefs, mAccountIds);
                mSendAccountIds = intersection.length > 0 ? intersection : mAccountIds;
            }
            mOriginalText = ParseUtils.parseString(mEditText.getText());
        }
        if (!setComposeTitle(intent)) {
            setTitle(R.string.compose);
        }

        final boolean useBottomMenu = isSingleAccount() || !mBottomSendButton;
        if (useBottomMenu) {
            mBottomMenuBar.inflate(R.menu.menu_compose);
        } else {
            mActionMenuBar.inflate(R.menu.menu_compose);
        }
        mBottomMenuBar.setVisibility(useBottomMenu ? View.VISIBLE : View.GONE);
        mActionMenuBar.setVisibility(useBottomMenu ? View.GONE : View.VISIBLE);
        mSendView.setVisibility(mBottomSendButton ? View.GONE : View.VISIBLE);
        mBottomSendDivider.setVisibility(mBottomSendButton ? View.VISIBLE : View.GONE);
        mBottomSendView.setVisibility(mBottomSendButton ? View.VISIBLE : View.GONE);
        mSendView.setOnClickListener(this);
        mBottomSendView.setOnClickListener(this);
        mSendView.setOnLongClickListener(this);
        mBottomSendView.setOnLongClickListener(this);
        final LinearLayout.LayoutParams bottomMenuContainerParams = (LinearLayout.LayoutParams) mBottomMenuContainer
                .getLayoutParams();
        final LinearLayout.LayoutParams accountSelectorParams = (LinearLayout.LayoutParams) mAccountSelector
                .getLayoutParams();
        final int maxItemsShown;
        final Resources res = getResources();
        if (isSingleAccount()) {
            accountSelectorParams.weight = 0;
            accountSelectorParams.width = ViewGroup.LayoutParams.WRAP_CONTENT;
            bottomMenuContainerParams.weight = 1;
            bottomMenuContainerParams.width = ViewGroup.LayoutParams.MATCH_PARENT;
            maxItemsShown = res.getInteger(R.integer.max_compose_menu_buttons_bottom_singleaccount);
            mAccountSelectorDivider.setVisibility(View.VISIBLE);
        } else {
            accountSelectorParams.weight = 1;
            accountSelectorParams.width = ViewGroup.LayoutParams.MATCH_PARENT;
            bottomMenuContainerParams.weight = 0;
            bottomMenuContainerParams.width = ViewGroup.LayoutParams.WRAP_CONTENT;
            maxItemsShown = res.getInteger(R.integer.max_compose_menu_buttons_bottom);
            mAccountSelectorDivider.setVisibility(mBottomSendButton ? View.GONE : View.VISIBLE);
        }
        mBottomMenuContainer.setLayoutParams(bottomMenuContainerParams);
        mBottomMenuBar.setMaxItemsShown(maxItemsShown);
        setMenu();
        updateAccountSelection();
        updateMediasPreview();
    }

    @Override
    protected void onStart() {
        super.onStart();
        mImageUploaderUsed = !ServicePickerPreference.isNoneValue(mPreferences.getString(KEY_MEDIA_UPLOADER, null));
        mStatusShortenerUsed = !ServicePickerPreference
                .isNoneValue(mPreferences.getString(KEY_STATUS_SHORTENER, null));
        setMenu();
        updateTextCount();
        final int text_size = mPreferences.getInt(KEY_TEXT_SIZE, getDefaultTextSize(this));
        mEditText.setTextSize(text_size * 1.25f);
    }

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

    @Override
    protected void onTitleChanged(final CharSequence title, final int color) {
        super.onTitleChanged(title, color);
        mTitleView.setText(title);
    }

    private void addMedia(final ParcelableMediaUpdate media) {
        mMediaPreviewAdapter.add(media);
        updateMediasPreview();
    }

    private void addMedias(final List<ParcelableMediaUpdate> medias) {
        mMediaPreviewAdapter.addAll(medias);
        updateMediasPreview();
    }

    private void clearMedia() {
        mMediaPreviewAdapter.clear();
        updateMediasPreview();
    }

    private Uri createTempImageUri() {
        final File file = new File(getCacheDir(), "tmp_image_" + System.currentTimeMillis());
        return Uri.fromFile(file);
    }

    /**
     * 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);
                setProgressVisibility(true);
            }
            mRecentLocation = location != null ? new ParcelableLocation(location) : null;
        } else {
            Crouton.showText(this, R.string.cannot_get_location, CroutonStyle.ALERT);
        }
        return provider != null;
    }

    private ParcelableMediaUpdate[] getMedias() {
        final List<ParcelableMediaUpdate> list = getMediasList();
        return list.toArray(new ParcelableMediaUpdate[list.size()]);
    }

    private List<ParcelableMediaUpdate> getMediasList() {
        return mMediaPreviewAdapter.getAsList();
    }

    private boolean handleDefaultIntent(final Intent intent) {
        if (intent == null)
            return false;
        final String action = intent.getAction();
        mShouldSaveAccounts = !Intent.ACTION_SEND.equals(action) && !Intent.ACTION_SEND_MULTIPLE.equals(action);
        final Uri data = intent.getData();
        final CharSequence extraSubject = intent.getCharSequenceExtra(Intent.EXTRA_SUBJECT);
        final CharSequence extraText = intent.getCharSequenceExtra(Intent.EXTRA_TEXT);
        final Uri extraStream = intent.getParcelableExtra(Intent.EXTRA_STREAM);
        if (extraStream != null) {
            new AddMediaTask(this, extraStream, createTempImageUri(), ParcelableMedia.TYPE_IMAGE, false).execute();
        } else if (data != null) {
            new AddMediaTask(this, data, createTempImageUri(), ParcelableMedia.TYPE_IMAGE, false).execute();
        } else if (intent.hasExtra(EXTRA_SHARE_SCREENSHOT)) {
            final Bitmap bitmap = intent.getParcelableExtra(EXTRA_SHARE_SCREENSHOT);
            if (bitmap != null) {
                try {
                    new AddBitmapTask(this, bitmap, createTempImageUri(), ParcelableMedia.TYPE_IMAGE).execute();
                } catch (IOException e) {
                    // ignore
                    bitmap.recycle();
                }
            }
        }
        mEditText.setText(getShareStatus(this, extraSubject, extraText));
        final int selection_end = mEditText.length();
        mEditText.setSelection(selection_end);
        return true;
    }

    private boolean handleEditDraftIntent(final DraftItem draft) {
        if (draft == null)
            return false;
        mEditText.setText(draft.text);
        final int selection_end = mEditText.length();
        mEditText.setSelection(selection_end);
        mSendAccountIds = draft.account_ids;
        if (draft.medias != null) {
            addMedias(Arrays.asList(draft.medias));
        }
        mIsPossiblySensitive = draft.is_possibly_sensitive;
        mInReplyToStatusId = draft.in_reply_to_status_id;
        return true;
    }

    private boolean handleIntent(final Intent intent) {
        final String action = intent.getAction();
        mShouldSaveAccounts = false;
        mMentionUser = intent.getParcelableExtra(EXTRA_USER);
        mInReplyToStatus = intent.getParcelableExtra(EXTRA_STATUS);
        mInReplyToStatusId = mInReplyToStatus != null ? mInReplyToStatus.id : -1;
        if (INTENT_ACTION_REPLY.equals(action))
            return handleReplyIntent(mInReplyToStatus);
        else if (INTENT_ACTION_QUOTE.equals(action))
            return handleQuoteIntent(mInReplyToStatus);
        else if (INTENT_ACTION_EDIT_DRAFT.equals(action)) {
            mDraftItem = intent.getParcelableExtra(EXTRA_DRAFT);
            return handleEditDraftIntent(mDraftItem);
        } else if (INTENT_ACTION_MENTION.equals(action))
            return handleMentionIntent(mMentionUser);
        else if (INTENT_ACTION_REPLY_MULTIPLE.equals(action)) {
            final String[] screenNames = intent.getStringArrayExtra(EXTRA_SCREEN_NAMES);
            final long accountId = intent.getLongExtra(EXTRA_ACCOUNT_ID, -1);
            final long inReplyToUserId = intent.getLongExtra(EXTRA_IN_REPLY_TO_ID, -1);
            return handleReplyMultipleIntent(screenNames, accountId, inReplyToUserId);
        } else if (INTENT_ACTION_COMPOSE_TAKE_PHOTO.equals(action)) {
            takePhoto();
            return true;
        } else if (INTENT_ACTION_COMPOSE_PICK_IMAGE.equals(action)) {
            pickImage();
            return true;
        }
        // Unknown action or no intent extras
        return false;
    }

    private boolean handleMentionIntent(final ParcelableUser user) {
        if (user == null || user.id <= 0)
            return false;
        final String my_screen_name = getAccountScreenName(this, user.account_id);
        if (isEmpty(my_screen_name))
            return false;
        mEditText.setText("@" + user.screen_name + " ");
        final int selection_end = mEditText.length();
        mEditText.setSelection(selection_end);
        mSendAccountIds = new long[] { user.account_id };
        return true;
    }

    private boolean handleQuoteIntent(final ParcelableStatus status) {
        if (status == null || status.id <= 0)
            return false;
        mEditText.setText(getQuoteStatus(this, status.user_screen_name, status.text_plain));
        mEditText.setSelection(0);
        mSendAccountIds = new long[] { status.account_id };
        return true;
    }

    private boolean handleReplyIntent(final ParcelableStatus status) {
        if (status == null || status.id <= 0)
            return false;
        final String myScreenName = getAccountScreenName(this, status.account_id);
        if (isEmpty(myScreenName))
            return false;
        mEditText.append("@" + status.user_screen_name + " ");
        final int selectionStart = mEditText.length();
        if (!isEmpty(status.retweeted_by_screen_name)) {
            mEditText.append("@" + status.retweeted_by_screen_name + " ");
        }
        final Collection<String> mentions = new TreeSet<String>(String.CASE_INSENSITIVE_ORDER);
        mentions.addAll(mExtractor.extractMentionedScreennames(status.text_plain));
        for (final String mention : mentions) {
            if (mention.equalsIgnoreCase(status.user_screen_name) || mention.equalsIgnoreCase(myScreenName)
                    || mention.equalsIgnoreCase(status.retweeted_by_screen_name)) {
                continue;
            }
            mEditText.append("@" + mention + " ");
        }
        final int selectionEnd = mEditText.length();
        mEditText.setSelection(selectionStart, selectionEnd);
        mSendAccountIds = new long[] { status.account_id };
        return true;
    }

    private boolean handleReplyMultipleIntent(final String[] screenNames, final long accountId,
            final long inReplyToStatusId) {
        if (screenNames == null || screenNames.length == 0 || accountId <= 0)
            return false;
        final String myScreenName = getAccountScreenName(this, accountId);
        if (isEmpty(myScreenName))
            return false;
        for (final String screenName : screenNames) {
            if (screenName.equalsIgnoreCase(myScreenName)) {
                continue;
            }
            mEditText.append("@" + screenName + " ");
        }
        mEditText.setSelection(mEditText.length());
        mSendAccountIds = new long[] { accountId };
        mInReplyToStatusId = inReplyToStatusId;
        return true;
    }

    private boolean hasMedia() {
        return !mMediaPreviewAdapter.isEmpty();
    }

    private boolean isQuotingProtectedStatus() {
        if (INTENT_ACTION_QUOTE.equals(getIntent().getAction()) && mInReplyToStatus != null)
            return mInReplyToStatus.user_is_protected && mInReplyToStatus.account_id != mInReplyToStatus.user_id;
        return false;
    }

    private boolean isSingleAccount() {
        return mAccountIds != null && mAccountIds.length == 1;
    }

    private boolean noReplyContent(final String text) {
        if (text == null)
            return true;
        final String action = getIntent().getAction();
        final boolean is_reply = INTENT_ACTION_REPLY.equals(action) || INTENT_ACTION_REPLY_MULTIPLE.equals(action);
        return is_reply && text.equals(mOriginalText);
    }

    @TargetApi(Build.VERSION_CODES.KITKAT)
    private boolean openDocument() {
        final Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
        final String[] mimeTypes = { "image/png", "image/jpeg", "image/gif" };
        intent.setType("image/*");
        intent.putExtra(Intent.EXTRA_MIME_TYPES, mimeTypes);
        intent.addCategory(Intent.CATEGORY_OPENABLE);
        intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
        try {
            startActivityForResult(intent, REQUEST_OPEN_DOCUMENT);
        } catch (final ActivityNotFoundException e) {
            return false;
        }
        return true;
    }

    private void pickImage() {
        final Intent intent = new Intent(Intent.ACTION_PICK);
        intent.setType("image/*");
        intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
        try {
            startActivityForResult(intent, REQUEST_PICK_IMAGE);
        } catch (final ActivityNotFoundException e) {
            showErrorMessage(this, null, e, false);
        }
    }

    private void setCommonMenu(final Menu menu) {
        final boolean hasMedia = hasMedia();
        final int activatedColor = getUserThemeColor(this);
        final MenuItem itemAddImageSubmenu = menu.findItem(R.id.add_image_submenu);
        if (itemAddImageSubmenu != null) {
            final Drawable iconAddImage = itemAddImageSubmenu.getIcon();
            iconAddImage.mutate();
            if (hasMedia) {
                iconAddImage.setColorFilter(activatedColor, Mode.SRC_ATOP);
            } else {
                iconAddImage.clearColorFilter();
            }
        }
        final MenuItem itemAttachLocation = menu.findItem(MENU_ADD_LOCATION);
        if (itemAttachLocation != null) {
            final Drawable iconAttachLocation = itemAttachLocation.getIcon().mutate();
            final boolean attachLocation = mPreferences.getBoolean(KEY_ATTACH_LOCATION, false);
            if (attachLocation && getLocation()) {
                iconAttachLocation.setColorFilter(activatedColor, Mode.SRC_ATOP);
                itemAttachLocation.setTitle(R.string.remove_location);
                itemAttachLocation.setChecked(true);
            } else {
                setProgressVisibility(false);
                mPreferences.edit().putBoolean(KEY_ATTACH_LOCATION, false).commit();
                iconAttachLocation.clearColorFilter();
                itemAttachLocation.setTitle(R.string.add_location);
                itemAttachLocation.setChecked(false);
            }
        }
        final MenuItem viewItem = menu.findItem(MENU_VIEW);
        if (viewItem != null) {
            viewItem.setVisible(mInReplyToStatus != null);
        }
        final MenuItem itemToggleSensitive = menu.findItem(MENU_TOGGLE_SENSITIVE);
        if (itemToggleSensitive != null) {
            itemToggleSensitive.setVisible(hasMedia);
            itemToggleSensitive.setEnabled(hasMedia);
            itemToggleSensitive.setChecked(hasMedia && mIsPossiblySensitive);
            if (hasMedia) {
                final Drawable iconToggleSensitive = itemToggleSensitive.getIcon().mutate();
                if (mIsPossiblySensitive) {
                    itemToggleSensitive.setTitle(R.string.remove_sensitive_mark);
                    iconToggleSensitive.setColorFilter(activatedColor, Mode.SRC_ATOP);
                } else {
                    itemToggleSensitive.setTitle(R.string.mark_as_sensitive);
                    iconToggleSensitive.clearColorFilter();
                }
            }
        }
    }

    private boolean setComposeTitle(final Intent intent) {
        final String action = intent.getAction();
        if (INTENT_ACTION_REPLY.equals(action)) {
            if (mInReplyToStatus == null)
                return false;
            final String display_name = getDisplayName(this, mInReplyToStatus.user_id, mInReplyToStatus.user_name,
                    mInReplyToStatus.user_screen_name);
            setTitle(getString(R.string.reply_to, display_name));
        } else if (INTENT_ACTION_QUOTE.equals(action)) {
            if (mInReplyToStatus == null)
                return false;
            final String display_name = getDisplayName(this, mInReplyToStatus.user_id, mInReplyToStatus.user_name,
                    mInReplyToStatus.user_screen_name);
            setTitle(getString(R.string.quote_user, display_name));
            mSubtitleView.setVisibility(
                    mInReplyToStatus.user_is_protected && mInReplyToStatus.account_id != mInReplyToStatus.user_id
                            ? View.VISIBLE
                            : View.GONE);
        } else if (INTENT_ACTION_EDIT_DRAFT.equals(action)) {
            if (mDraftItem == null)
                return false;
            setTitle(R.string.edit_draft);
        } else if (INTENT_ACTION_MENTION.equals(action)) {
            if (mMentionUser == null)
                return false;
            final String display_name = getDisplayName(this, mMentionUser.id, mMentionUser.name,
                    mMentionUser.screen_name);
            setTitle(getString(R.string.mention_user, display_name));
        } else if (INTENT_ACTION_REPLY_MULTIPLE.equals(action)) {
            setTitle(R.string.reply);
        } else if (Intent.ACTION_SEND.equals(action) || Intent.ACTION_SEND_MULTIPLE.equals(action)) {
            setTitle(R.string.share);
        } else {
            setTitle(R.string.compose);
        }
        return true;
    }

    private void setMenu() {
        if (mBottomMenuBar == null || mActionMenuBar == null)
            return;
        final Menu bottomMenu = mBottomMenuBar.getMenu(), actionMenu = mActionMenuBar.getMenu();
        setCommonMenu(bottomMenu);
        setCommonMenu(actionMenu);
        mActionMenuBar.show();
        mBottomMenuBar.show();
    }

    private void setProgressVisibility(final boolean visible) {
        mProgress.setVisibility(visible ? View.VISIBLE : View.GONE);
    }

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

    private void updateAccountSelection() {
        if (mSendAccountIds == null)
            return;
        if (mShouldSaveAccounts) {
            final SharedPreferences.Editor editor = mPreferences.edit();
            editor.putString(KEY_COMPOSE_ACCOUNTS, ArrayUtils.toString(mSendAccountIds, ',', false));
            editor.commit();
        }
        mAccountSelectorAdapter.clearAccountSelection();
        for (final long accountId : mSendAccountIds) {
            mAccountSelectorAdapter.setAccountSelected(accountId, true);
        }
        mColorIndicator.drawEnd(getAccountColors(this, mSendAccountIds));
    }

    private void updateMediasPreview() {
        final int count = mMediaPreviewAdapter.getCount();
        final Resources res = getResources();
        final int maxColumns = res.getInteger(R.integer.grid_column_image_preview);
        mMediasPreviewGrid.setNumColumns(MathUtils.clamp(count, maxColumns, 1));
    }

    private void updateStatus() {
        if (isFinishing())
            return;
        final boolean hasMedia = hasMedia();
        final String text = mEditText != null ? ParseUtils.parseString(mEditText.getText()) : null;
        final int tweetLength = mValidator.getTweetLength(text), maxLength = mValidator.getMaxTweetLength();
        if (!mStatusShortenerUsed && tweetLength > maxLength) {
            mEditText.setError(getString(R.string.error_message_status_too_long));
            final int text_length = mEditText.length();
            mEditText.setSelection(text_length - (tweetLength - maxLength), text_length);
            return;
        } else if (!hasMedia && (isEmpty(text) || noReplyContent(text))) {
            mEditText.setError(getString(R.string.error_message_no_content));
            return;
        }
        final boolean attach_location = mPreferences.getBoolean(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;
        }
        final boolean isQuote = INTENT_ACTION_QUOTE.equals(getIntent().getAction());
        final ParcelableLocation statusLocation = attach_location ? mRecentLocation : null;
        final boolean linkToQuotedTweet = mPreferences.getBoolean(KEY_LINK_TO_QUOTED_TWEET, true);
        final long inReplyToStatusId = !isQuote || linkToQuotedTweet ? mInReplyToStatusId : -1;
        final boolean isPossiblySensitive = hasMedia && mIsPossiblySensitive;
        mTwitterWrapper.updateStatusAsync(mSendAccountIds, text, statusLocation, getMedias(), inReplyToStatusId,
                isPossiblySensitive);
        if (mPreferences.getBoolean(KEY_NO_CLOSE_AFTER_TWEET_SENT, false)
                && (mInReplyToStatus == null || mInReplyToStatusId <= 0)) {
            mIsPossiblySensitive = false;
            mShouldSaveAccounts = true;
            mTempPhotoUri = null;
            mInReplyToStatus = null;
            mMentionUser = null;
            mDraftItem = null;
            mInReplyToStatusId = -1;
            mOriginalText = null;
            mEditText.setText(null);
            clearMedia();
            final Intent intent = new Intent(INTENT_ACTION_COMPOSE);
            setIntent(intent);
            setComposeTitle(intent);
            handleIntent(intent);
            setMenu();
            updateTextCount();
        } else {
            setResult(Activity.RESULT_OK);
            finish();
        }
    }

    private void updateTextCount() {
        final StatusTextCountView textCountView = mBottomSendButton ? mBottomSendTextCountView : mSendTextCountView;
        if (textCountView != null && mEditText != null) {
            final String textOrig = mEditText != null ? parseString(mEditText.getText()) : null;
            final String text = hasMedia() && textOrig != null
                    ? mImageUploaderUsed ? getImageUploadStatus(this, new String[] { FAKE_IMAGE_LINK }, textOrig)
                            : textOrig + " " + FAKE_IMAGE_LINK
                    : textOrig;
            final int validatedCount = text != null ? mValidator.getTweetLength(text) : 0;
            textCountView.setTextCount(validatedCount);
        }
    }

    public static class RetweetProtectedStatusWarnFragment extends BaseSupportDialogFragment
            implements DialogInterface.OnClickListener {

        @Override
        public void onClick(final DialogInterface dialog, final int which) {
            final Activity activity = getActivity();
            switch (which) {
            case DialogInterface.BUTTON_POSITIVE: {
                if (activity instanceof ComposeActivity) {
                    ((ComposeActivity) activity).updateStatus();
                }
                break;
            }
            }

        }

        @Override
        public Dialog onCreateDialog(final Bundle savedInstanceState) {
            final Context wrapped = ThemeUtils.getDialogThemedContext(getActivity());
            final AlertDialog.Builder builder = new AlertDialog.Builder(wrapped);
            builder.setMessage(R.string.quote_protected_status_warning_message);
            builder.setPositiveButton(R.string.send_anyway, this);
            builder.setNegativeButton(android.R.string.cancel, null);
            return builder.create();
        }
    }

    public static class UnsavedTweetDialogFragment extends BaseSupportDialogFragment
            implements DialogInterface.OnClickListener {

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

        }

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

    public static class ViewStatusDialogFragment extends BaseSupportDialogFragment {

        private StatusViewHolder mHolder;

        public ViewStatusDialogFragment() {
            setStyle(STYLE_NO_TITLE, 0);
        }

        @Override
        public void onActivityCreated(final Bundle savedInstanceState) {
            super.onActivityCreated(savedInstanceState);
            final Bundle args = getArguments();
            if (args == null || args.getParcelable(EXTRA_STATUS) == null) {
                dismiss();
                return;
            }
            final TwittnukerApplication application = getApplication();
            final ImageLoaderWrapper loader = application.getImageLoaderWrapper();
            final SharedPreferences prefs = getSharedPreferences(SHARED_PREFERENCES_NAME, MODE_PRIVATE);
            final ParcelableStatus status = args.getParcelable(EXTRA_STATUS);
            mHolder.setShowAsGap(false);
            mHolder.setAccountColorEnabled(true);
            mHolder.setTextSize(prefs.getInt(KEY_TEXT_SIZE, getDefaultTextSize(getActivity())));
            ((View) mHolder.content).setPadding(0, 0, 0, 0);
            mHolder.content.setItemBackground(null);
            mHolder.content.setItemSelector(null);
            mHolder.text.setText(status.text_unescaped);
            mHolder.name.setText(status.user_name);
            mHolder.screen_name.setText("@" + status.user_screen_name);
            mHolder.screen_name.setVisibility(View.VISIBLE);

            final String retweeted_by_name = status.retweeted_by_name;
            final String retweeted_by_screen_name = status.retweeted_by_screen_name;

            final boolean is_my_status = status.account_id == status.user_id;
            final boolean hasMedia = status.medias != null && status.medias.length > 0;
            mHolder.setUserColor(getUserColor(getActivity(), status.user_id, true));
            mHolder.setHighlightColor(getCardHighlightColor(status, false));

            mHolder.setIsMyStatus(is_my_status && !prefs.getBoolean(KEY_INDICATE_MY_STATUS, true));

            mHolder.name.setCompoundDrawablesWithIntrinsicBounds(0, 0,
                    getUserTypeIconRes(status.user_is_verified, status.user_is_protected), 0);
            mHolder.time.setTime(status.timestamp);
            final int type_icon = getStatusTypeIconRes(status.is_favorite, isValidLocation(status.location),
                    hasMedia, status.is_possibly_sensitive, status.my_retweet_id > 0);
            mHolder.time.setCompoundDrawablesWithIntrinsicBounds(0, 0, type_icon, 0);
            mHolder.reply_retweet_status.setVisibility(
                    status.in_reply_to_status_id != -1 || status.is_retweet ? View.VISIBLE : View.GONE);
            if (status.is_retweet && !TextUtils.isEmpty(retweeted_by_name)
                    && !TextUtils.isEmpty(retweeted_by_screen_name)) {
                if (!prefs.getBoolean(KEY_NAME_FIRST, true)) {
                    mHolder.reply_retweet_status.setText(status.retweet_count > 1
                            ? getString(R.string.retweeted_by_with_count, retweeted_by_screen_name,
                                    status.retweet_count - 1)
                            : getString(R.string.retweeted_by, retweeted_by_screen_name));
                } else {
                    mHolder.reply_retweet_status.setText(status.retweet_count > 1
                            ? getString(R.string.retweeted_by_with_count, retweeted_by_name,
                                    status.retweet_count - 1)
                            : getString(R.string.retweeted_by, retweeted_by_name));
                }
                mHolder.reply_retweet_status.setText(status.retweet_count > 1
                        ? getString(R.string.retweeted_by_with_count, retweeted_by_name, status.retweet_count - 1)
                        : getString(R.string.retweeted_by, retweeted_by_name));
                mHolder.reply_retweet_status
                        .setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_indicator_retweet, 0, 0, 0);
            } else if (status.in_reply_to_status_id > 0 && !TextUtils.isEmpty(status.in_reply_to_screen_name)) {
                mHolder.reply_retweet_status
                        .setText(getString(R.string.in_reply_to, status.in_reply_to_screen_name));
                mHolder.reply_retweet_status
                        .setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_indicator_conversation, 0, 0, 0);
            }
            if (prefs.getBoolean(KEY_DISPLAY_PROFILE_IMAGE, true)) {
                loader.displayProfileImage(mHolder.my_profile_image, status.user_profile_image_url);
                loader.displayProfileImage(mHolder.profile_image, status.user_profile_image_url);
            } else {
                mHolder.profile_image.setVisibility(View.GONE);
                mHolder.my_profile_image.setVisibility(View.GONE);
            }
            mHolder.image_preview_container.setVisibility(View.GONE);
        }

        @Override
        public View onCreateView(final LayoutInflater inflater, final ViewGroup parent,
                final Bundle savedInstanceState) {
            final ScrollView view = (ScrollView) inflater.inflate(R.layout.dialog_scrollable_status, parent, false);
            mHolder = new StatusViewHolder(view.getChildAt(0));
            return view;
        }

    }

    private static class AccountSelectorAdapter extends BaseArrayAdapter<Account> {

        private final LongSparseArray<Boolean> mAccountSelectStates = new LongSparseArray<Boolean>();

        public AccountSelectorAdapter(final Context context) {
            super(context, R.layout.gallery_item_compose_account, Account.getAccountsList(context, false));
        }

        public void clearAccountSelection() {
            mAccountSelectStates.clear();
            notifyDataSetChanged();
        }

        public long[] getSelectedAccountIds() {
            final ArrayList<Long> list = new ArrayList<Long>();
            for (int i = 0, j = getCount(); i < j; i++) {
                final Account account = getItem(i);
                if (mAccountSelectStates.get(account.account_id, false)) {
                    list.add(account.account_id);
                }
            }
            return ArrayUtils.fromList(list);
        }

        @Override
        public View getView(final int position, final View convertView, final ViewGroup parent) {
            final View view = super.getView(position, convertView, parent);
            final Account account = getItem(position);
            final ImageLoaderWrapper loader = getImageLoader();
            final ImageView icon = (ImageView) view.findViewById(android.R.id.icon);
            loader.displayProfileImage(icon, account.profile_image_url);
            view.setActivated(mAccountSelectStates.get(account.account_id, false));
            return view;
        }

        public void setAccountSelected(final long accountId, final boolean selected) {
            mAccountSelectStates.put(accountId, selected);
            notifyDataSetChanged();
        }

    }

    private static class AddBitmapTask extends AddMediaTask {

        private final Bitmap mBitmap;

        AddBitmapTask(ComposeActivity activity, Bitmap bitmap, Uri dst, int media_type) throws IOException {
            super(activity, Uri.fromFile(File.createTempFile("tmp_bitmap", null)), dst, media_type, true);
            mBitmap = bitmap;
        }

        @Override
        protected Boolean doInBackground(Void... params) {
            if (mBitmap == null || mBitmap.isRecycled())
                return false;
            FileOutputStream os = null;
            try {
                os = new FileOutputStream(getSrc().getPath());
                mBitmap.compress(Bitmap.CompressFormat.PNG, 0, os);
                mBitmap.recycle();
            } catch (IOException e) {
                return false;
            } finally {
                IoUtils.closeSilently(os);
            }
            return super.doInBackground(params);
        }

    }

    private static class AddMediaTask extends AsyncTask<Void, Void, Boolean> {

        private final ComposeActivity activity;
        private final int media_type;
        private final Uri src, dst;
        private final boolean delete_src;

        Uri getSrc() {
            return src;
        }

        AddMediaTask(final ComposeActivity activity, final Uri src, final Uri dst, final int media_type,
                final boolean delete_src) {
            this.activity = activity;
            this.src = src;
            this.dst = dst;
            this.media_type = media_type;
            this.delete_src = delete_src;
        }

        @Override
        protected Boolean doInBackground(final Void... params) {
            try {
                final ContentResolver resolver = activity.getContentResolver();
                final InputStream is = resolver.openInputStream(src);
                final OutputStream os = resolver.openOutputStream(dst);
                copyStream(is, os);
                os.close();
                if (ContentResolver.SCHEME_FILE.equals(src.getScheme()) && delete_src) {
                    new File(src.getPath()).delete();
                }
            } catch (final Exception e) {
                return false;
            }
            return true;
        }

        @Override
        protected void onPostExecute(final Boolean result) {
            activity.setProgressVisibility(false);
            activity.addMedia(new ParcelableMediaUpdate(dst.toString(), media_type));
            activity.setMenu();
            activity.updateTextCount();
            if (!result) {
                Crouton.showText(activity, R.string.error_occurred, CroutonStyle.ALERT);
            }
        }

        @Override
        protected void onPreExecute() {
            activity.setProgressVisibility(true);
        }
    }

    private static class DeleteImageTask extends AsyncTask<Void, Void, Boolean> {

        final ComposeActivity activity;
        private final ParcelableMediaUpdate[] medias;

        DeleteImageTask(final ComposeActivity activity, final ParcelableMediaUpdate... medias) {
            this.activity = activity;
            this.medias = medias;
        }

        @Override
        protected Boolean doInBackground(final Void... params) {
            if (medias == null)
                return false;
            try {
                for (final ParcelableMediaUpdate media : medias) {
                    final Uri target = Uri.parse(media.uri);
                    if (ContentResolver.SCHEME_FILE.equals(target.getScheme())) {
                        new File(target.getPath()).delete();
                    }
                }
            } catch (final Exception e) {
                return false;
            }
            return true;
        }

        @Override
        protected void onPostExecute(final Boolean result) {
            activity.setProgressVisibility(false);
            activity.removeAllMedia(Arrays.asList(medias));
            activity.setMenu();
            if (!result) {
                Crouton.showText(activity, R.string.error_occurred, CroutonStyle.ALERT);
            }
        }

        @Override
        protected void onPreExecute() {
            activity.setProgressVisibility(true);
        }
    }

    private static class DiscardTweetTask extends AsyncTask<Void, Void, Void> {

        final ComposeActivity activity;

        DiscardTweetTask(final ComposeActivity activity) {
            this.activity = activity;
        }

        @Override
        protected Void doInBackground(final Void... params) {
            try {
                for (final ParcelableMediaUpdate media : activity.getMediasList()) {
                    final Uri uri = Uri.parse(media.uri);
                    if (uri == null)
                        return null;
                    if (ContentResolver.SCHEME_FILE.equals(uri.getScheme())) {
                        new File(uri.getPath()).delete();
                    }
                }
            } catch (final Exception e) {
            }
            return null;
        }

        @Override
        protected void onPostExecute(final Void result) {
            activity.setProgressVisibility(false);
            activity.finish();
        }

        @Override
        protected void onPreExecute() {
            activity.setProgressVisibility(true);
        }
    }

    private static class MediaPreviewAdapter extends DraggableArrayAdapter<ParcelableMediaUpdate> {

        private final ImageLoaderWrapper mImageLoader;

        public MediaPreviewAdapter(final Context context) {
            super(context, R.layout.grid_item_media_editor);
            mImageLoader = TwittnukerApplication.getInstance(context).getImageLoaderWrapper();
        }

        @Override
        public View getView(final int position, final View convertView, final ViewGroup parent) {
            final View view = super.getView(position, convertView, parent);
            final ParcelableMediaUpdate media = getItem(position);
            final ImageView image = (ImageView) view.findViewById(R.id.image);
            mImageLoader.displayPreviewImage(image, media.uri);
            return view;
        }

    }
}