ch.ethz.twimight.activities.ComposeTweetActivity.java Source code

Java tutorial

Introduction

Here is the source code for ch.ethz.twimight.activities.ComposeTweetActivity.java

Source

/*******************************************************************************
 * Copyright (c) 2011 ETH Zurich.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Public License v2.0
 * which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
 * 
 * Contributors:
 *     Paolo Carta - Implementation
 *     Theus Hossmann - Implementation
 *     Dominik Schatzmann - Message specification
 ******************************************************************************/

package ch.ethz.twimight.activities;

import twitter4j.util.CharacterUtil;
import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.location.Location;
import android.net.ConnectivityManager;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.provider.MediaStore;
import android.text.Editable;
import android.text.Html;
import android.text.TextWatcher;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import ch.ethz.twimight.R;
import ch.ethz.twimight.location.LocationHelper;
import ch.ethz.twimight.net.twitter.Tweets;
import ch.ethz.twimight.net.twitter.TwitterSyncService;
import ch.ethz.twimight.net.twitter.TwitterUsers;
import ch.ethz.twimight.util.Constants;
import ch.ethz.twimight.util.Preferences;
import ch.ethz.twimight.util.SDCardHelper;
import ch.ethz.twimight.views.ClickableImageView;

import com.nostra13.universalimageloader.core.ImageLoader;

/**
 * The activity to write a new tweet.
 * 
 * @author thossmann
 * @author pcarta
 */
public class ComposeTweetActivity extends ThemeSelectorActivity {

    private static final String TAG = ComposeTweetActivity.class.getSimpleName();

    public static final String EXTRA_KEY_TEXT = "EXTRA_KEY_TEXT";
    public static final String EXTRA_KEY_IS_REPLY_TO = "EXTRA_KEY_IS_REPLY_TO";

    private boolean mUseLocation;
    private EditText mEtTweetText;
    private TextView mTvCharacterCounter;
    private Button mBtnSend;
    private View mPhotoPreviewContainer;
    private ClickableImageView mPhotoPreview;

    private long mIsReplyTo;

    // the following are all to deal with location
    private ImageButton mBtnLocation;

    private TextWatcher mTextWatcher;

    // uploading photos
    private static final int IMAGE_FROM_CAMERA_REQUEST_CODE = 1;
    private static final int IMAGE_FROM_FILE_REQUEST_CODE = 2;
    private String mTempPhotoPath; // path storing photos on SDcard
    private String mFinalPhotoPath; // path storing photos on SDcard
    private String mFinalPhotoName; // file name of uploaded photo
    private Uri mTempPhotoUri; // uri storing temp photos
    private Uri mPhotoUri; // uri storing photos

    private boolean mHasMedia = false;
    private Bitmap mPhotoBitmap = null;

    // SDcard helper
    private SDCardHelper mSdCardHelper;

    // LOGS
    LocationHelper mLocationHelper;
    long mTimestamp;

    /**
     * Called when the activity is first created.
     */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.compose_tweet);

        captureViews();
        hideImagePreview();

        // User settings: do we use location or not?
        mUseLocation = Preferences.getBoolean(this, R.string.pref_key_use_location,
                Constants.TWEET_DEFAULT_LOCATION);

        if (mUseLocation) {
            mBtnLocation.setImageResource(R.drawable.ic_location_on);
        } else {
            mBtnLocation.setImageResource(R.drawable.ic_location_off);
        }
        // get username and picture
        Uri uri = Uri.parse("content://" + TwitterUsers.TWITTERUSERS_AUTHORITY + "/" + TwitterUsers.TWITTERUSERS);
        Cursor c = getContentResolver().query(uri, null,
                TwitterUsers.COL_TWITTER_USER_ID + "=" + LoginActivity.getTwitterId(this), null, null);
        if (c.moveToFirst()) {

            ImageView ivProfileImage = (ImageView) findViewById(R.id.ivProfileImage);
            String profilePictureUri = c.getString(c.getColumnIndex(TwitterUsers.COL_PROFILE_IMAGE_URI));
            ImageLoader.getInstance().displayImage(profilePictureUri, ivProfileImage);

            TextView tvName = (TextView) findViewById(R.id.tvName);
            String userName = c.getString(c.getColumnIndex(TwitterUsers.COL_NAME));
            tvName.setText(userName);

            TextView tvScreenName = (TextView) findViewById(R.id.tvScreenname);
            String userScreenName = c.getString(c.getColumnIndex(TwitterUsers.COL_SCREEN_NAME));
            tvScreenName.setText("@" + userScreenName);
        }

        mLocationHelper = LocationHelper.getInstance(this);

        // SDCard helper
        mSdCardHelper = new SDCardHelper();

        // prepare image saving

        mTempPhotoPath = Tweets.PHOTO_PATH + "/" + "tmp";
        mFinalPhotoPath = Tweets.PHOTO_PATH + "/" + LoginActivity.getTwitterId(this);
        String[] filePaths = { mTempPhotoPath, mFinalPhotoPath };
        if (mSdCardHelper.checkSDState(filePaths)) {
            mSdCardHelper.clearTempDirectory(mTempPhotoPath);
        }

        // Did we get some extras in the intent?
        Intent i = getIntent();
        if (i.hasExtra(EXTRA_KEY_TEXT)) {
            mEtTweetText.setText(Html.fromHtml("<i>" + i.getStringExtra(EXTRA_KEY_TEXT) + "</i>"));
        }
        if (mEtTweetText.getText().length() == 0) {
            mBtnSend.setEnabled(false);
        }

        mTvCharacterCounter = (TextView) findViewById(R.id.tweet_characters);
        checkTweetLength();

        if (i.hasExtra(EXTRA_KEY_IS_REPLY_TO)) {
            mIsReplyTo = i.getLongExtra(EXTRA_KEY_IS_REPLY_TO, 0);
        }

        // This makes sure we do not enter more than 140 characters

        mTvCharacterCounter.setText(Integer.toString(Constants.TWEET_LENGTH));
        mTextWatcher = new TextWatcher() {
            public void afterTextChanged(Editable s) {
                checkTweetLength();
            }

            public void beforeTextChanged(CharSequence s, int start, int count, int after) {
            }

            public void onTextChanged(CharSequence s, int start, int before, int count) {
            }
        };
        mEtTweetText.addTextChangedListener(mTextWatcher);
        mEtTweetText.setSelection(mEtTweetText.getText().length());
    }

    private void checkTweetLength() {
        int usedTextChars = CharacterUtil.count(mEtTweetText.getText().toString());
        int usedMediaChars = mHasMedia ? Constants.CHARACTERS_RESERVED_PER_MEDIA : 0;
        int numCharsLeft = Constants.TWEET_LENGTH - usedTextChars - usedMediaChars;

        if (numCharsLeft < 0) {
            mEtTweetText.setText(mEtTweetText.getText().subSequence(0, Constants.TWEET_LENGTH - usedMediaChars));
            mEtTweetText.setSelection(mEtTweetText.getText().length());
            usedTextChars = CharacterUtil.count(mEtTweetText.getText().toString());
            numCharsLeft = Constants.TWEET_LENGTH - usedTextChars - usedMediaChars;
        }

        if (numCharsLeft <= 0) {
            mTvCharacterCounter.setTextColor(Color.RED);
        } else {
            mTvCharacterCounter.setTextColor(getResources().getColor(R.color.medium_gray));
        }

        if (numCharsLeft == Constants.TWEET_LENGTH) {
            mBtnSend.setEnabled(false);
        } else {
            mBtnSend.setEnabled(true);
        }

        mTvCharacterCounter.setText(Integer.toString(numCharsLeft));
    }

    private void captureViews() {
        mPhotoPreviewContainer = findViewById(R.id.photoPreviewContainer);
        mPhotoPreview = (ClickableImageView) findViewById(R.id.ivPhotoPreview);
        mBtnSend = (Button) findViewById(R.id.tweet_send);
        mBtnLocation = (ImageButton) findViewById(R.id.tweet_location);
        mEtTweetText = (EditText) findViewById(R.id.tweetText);
    }

    @Override
    protected void setDisasterTheme() {
        setTheme(R.style.TwimightHolo_DisasterMode_Translucent);
    }

    @Override
    protected void setNormalTheme() {
        setTheme(R.style.TwimightHolo_NormalMode_Translucent);
    }

    /**
     * OnClick callback for the cancel button (set in xml layout)
     * 
     * @param unused
     */
    public void cancel(View unused) {
        finish();
    }

    /**
     * OnClick callback for the delete photo button (set in xml layout)
     * 
     * @param unused
     */
    public void deletePhoto(View unused) {
        mSdCardHelper.deleteFile(mTempPhotoUri.getPath());
        mHasMedia = false;
        hideImagePreview();
        checkTweetLength();
    }

    public void sendTweet(View unused) {
        new SendTweetTask().execute();
    }

    public void toggleLocation(View unused) {
        if (mUseLocation) {
            mLocationHelper.unRegisterLocationListener();
            Toast.makeText(ComposeTweetActivity.this, getString(R.string.location_off), Toast.LENGTH_SHORT).show();
            mBtnLocation.setImageResource(R.drawable.ic_location_off);
            mUseLocation = false;
        } else {
            mLocationHelper.registerLocationListener();
            Toast.makeText(ComposeTweetActivity.this, getString(R.string.location_on), Toast.LENGTH_SHORT).show();
            mBtnLocation.setImageResource(R.drawable.ic_location_on);
            mUseLocation = true;
        }
    }

    /**
     * onResume
     */
    @Override
    public void onResume() {
        super.onResume();
        if (mUseLocation) {
            mLocationHelper.registerLocationListener();
        }
    }

    /**
     * onPause
     */
    @Override
    public void onPause() {
        super.onPause();
        mLocationHelper.unRegisterLocationListener();
    }

    /**
     * On Destroy
     */
    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.d(TAG, "onDestroy");
        if (mHasMedia) {
            mSdCardHelper.deleteFile(mTempPhotoUri.getPath());
            mHasMedia = false;
        }
        if (mLocationHelper != null) {
            mLocationHelper.unRegisterLocationListener();
        }

        mEtTweetText.removeTextChangedListener(mTextWatcher);
        mTextWatcher = null;

        TwimightBaseActivity.unbindDrawables(findViewById(R.id.composeTweetRoot));
    }

    /**
     * Checks whether we are in disaster mode and inserts the content values
     * into the content provider.
     * 
     * @author pcarta
     * 
     */
    private class SendTweetTask extends AsyncTask<Void, Void, Boolean> {
        Uri insertUri = null;

        @Override
        protected Boolean doInBackground(Void... params) {
            boolean result = false;

            // Statistics
            mTimestamp = System.currentTimeMillis();

            if (mHasMedia) {
                try {
                    mFinalPhotoName = "twimight" + String.valueOf(mTimestamp) + ".jpg";
                    mPhotoUri = Uri.fromFile(mSdCardHelper.getFileFromSDCard(mFinalPhotoPath, mFinalPhotoName));// photoFileParent,
                    // photoFilename));
                    String fromFile = mTempPhotoUri.getPath();
                    String toFile = mPhotoUri.getPath();
                    if (mSdCardHelper.copyFile(fromFile, toFile)) {
                        if (TwimightBaseActivity.D) {
                            Log.i(TAG, "file copy successful");
                        }
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            // if no connectivity, notify user that the tweet will be send later

            ContentValues cv = createContentValues();

            if (Preferences.getBoolean(ComposeTweetActivity.this, R.string.pref_key_disaster_mode, false)) {

                // our own tweets go into the my disaster tweets buffer
                cv.put(Tweets.COL_BUFFER, Tweets.BUFFER_TIMELINE | Tweets.BUFFER_MYDISASTER);

                insertUri = getContentResolver().insert(Uri.parse("content://" + Tweets.TWEET_AUTHORITY + "/"
                        + Tweets.TWEETS + "/" + Tweets.TWEETS_TABLE_TIMELINE + "/" + Tweets.TWEETS_SOURCE_DISASTER),
                        cv);
                getContentResolver().notifyChange(Tweets.TABLE_TIMELINE_URI, null);
            } else {
                // our own tweets go into the timeline buffer
                cv.put(Tweets.COL_BUFFER, Tweets.BUFFER_TIMELINE);
                // we publish on twitter directly only normal tweets
                cv.put(Tweets.COL_FLAGS, Tweets.FLAG_TO_INSERT);

                insertUri = getContentResolver().insert(Uri.parse("content://" + Tweets.TWEET_AUTHORITY + "/"
                        + Tweets.TWEETS + "/" + Tweets.TWEETS_TABLE_TIMELINE + "/" + Tweets.TWEETS_SOURCE_NORMAL),
                        cv);
                getContentResolver().notifyChange(Tweets.TABLE_TIMELINE_URI, null);
                // getContentResolver().notifyChange(insertUri, null);
                ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
                if (cm.getActiveNetworkInfo() == null || !cm.getActiveNetworkInfo().isConnected()) {
                    result = true;
                }
            }

            return result;

        }

        @Override
        protected void onPostExecute(Boolean result) {
            if (result)
                Toast.makeText(ComposeTweetActivity.this, getString(R.string.no_connection_upload_tweet),
                        Toast.LENGTH_SHORT).show();

            if (insertUri != null) {
                // schedule the tweet for uploading to twitter
                Intent i = new Intent(ComposeTweetActivity.this, TwitterSyncService.class);
                i.putExtra(TwitterSyncService.EXTRA_KEY_ACTION, TwitterSyncService.EXTRA_ACTION_SYNC_LOCAL_TWEET);
                i.putExtra(TwitterSyncService.EXTRA_KEY_TWEET_ROW_ID, Long.valueOf(insertUri.getLastPathSegment()));
                startService(i);
            }
            finish();
        }
    }

    /**
     * Prepares the content values of the tweet for insertion into the DB.
     * 
     * @return
     */
    private ContentValues createContentValues() {
        ContentValues tweetContentValues = new ContentValues();

        tweetContentValues.put(Tweets.COL_TEXT, mEtTweetText.getText().toString());
        tweetContentValues.put(Tweets.COL_TEXT_PLAIN, mEtTweetText.getText().toString());
        tweetContentValues.put(Tweets.COL_USER_TID, LoginActivity.getTwitterId(this));
        tweetContentValues.put(Tweets.COL_SCREEN_NAME, LoginActivity.getTwitterScreenname(this));
        if (mIsReplyTo > 0) {
            tweetContentValues.put(Tweets.COL_REPLY_TO_TWEET_TID, mIsReplyTo);
        }
        // set the current timestamp
        tweetContentValues.put(Tweets.COL_CREATED_AT, System.currentTimeMillis());

        if (mUseLocation) {
            Location loc = mLocationHelper.getLocation();
            if (loc != null) {
                tweetContentValues.put(Tweets.COL_LAT, loc.getLatitude());
                tweetContentValues.put(Tweets.COL_LNG, loc.getLongitude());
            }
        }
        // if there is a photo, put the path of photo in the cv
        if (mHasMedia) {
            tweetContentValues.put(Tweets.COL_MEDIA_URIS, mPhotoUri.toString());
            Log.i(TAG, Tweets.COL_MEDIA_URIS + ":" + mFinalPhotoName);
        }

        return tweetContentValues;
    }

    // methods photo uploading

    /**
     * upload photo from camera
     */
    public void uploadFromCamera(View unused) {

        if ((mTempPhotoUri = mSdCardHelper.createTmpPhotoStoragePath(mTempPhotoPath)) != null) {
            Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);

            intent.putExtra(MediaStore.EXTRA_OUTPUT, mTempPhotoUri);

            try {
                intent.putExtra("return-data", true);
                startActivityForResult(intent, IMAGE_FROM_CAMERA_REQUEST_CODE);
            } catch (ActivityNotFoundException e) {
                e.printStackTrace();
            }
        } else {
            Log.i(TAG, "path for storing photos cannot be created!");
            hideImagePreview();
        }

    }

    /**
     * upload photo by taking a picture
     */
    public void uploadFromGallery(View unused) {
        if ((mTempPhotoUri = mSdCardHelper.createTmpPhotoStoragePath(mTempPhotoPath)) != null) {
            Intent intent = new Intent();
            intent.setType("image/*");
            intent.setAction(Intent.ACTION_GET_CONTENT);
            startActivityForResult(Intent.createChooser(intent, getString(R.string.picker)),
                    IMAGE_FROM_FILE_REQUEST_CODE);
        } else {
            Log.i(TAG, "path for storing photos cannot be created!");
            hideImagePreview();
        }

    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (resultCode != RESULT_OK)
            return;

        mHasMedia = true;
        switch (requestCode) {
        case IMAGE_FROM_CAMERA_REQUEST_CODE:

            // display the picture
            mPhotoBitmap = mSdCardHelper.decodeBitmapFile(mTempPhotoUri.getPath());
            showImagePreview();
            break;

        case IMAGE_FROM_FILE_REQUEST_CODE:

            // display the photo
            Uri mImageGalleryUri = data.getData();

            // get the real path for chosen photo
            mImageGalleryUri = Uri.parse(
                    mSdCardHelper.getRealPathFromUri((Activity) ComposeTweetActivity.this, mImageGalleryUri));

            // copy the photo from gallery to tmp directory
            String fromFile = mImageGalleryUri.getPath();
            String toFile = mTempPhotoUri.getPath();
            if (mSdCardHelper.copyFile(fromFile, toFile)) {
                mPhotoBitmap = mSdCardHelper.decodeBitmapFile(toFile);
                showImagePreview();
            }
            break;
        }
    }

    private void hideImagePreview() {
        mPhotoPreviewContainer.setVisibility(View.GONE);
    }

    private void showImagePreview() {
        mPhotoPreview.setImageBitmap(mPhotoBitmap);
        Intent imageClickIntent = new Intent(this, PhotoViewActivity.class);
        imageClickIntent.putExtra(PhotoViewActivity.EXTRA_KEY_IMAGE_URI, mTempPhotoUri.toString());
        mPhotoPreview.setOnClickActivityIntent(imageClickIntent);
        mPhotoPreviewContainer.setVisibility(View.VISIBLE);
        checkTweetLength();
    }
}