Welcome to the Treehouse Community

The Treehouse Community is a meeting place for developers, designers, and programmers of all backgrounds and skill levels to get support. Collaborate here on code errors or bugs that you need feedback on, or asking for an extra set of eyes on your latest project. Join thousands of Treehouse students and alumni in the community today. (Note: Only Treehouse students can comment or ask questions, but non-students are welcome to browse our conversations.)

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and a supportive community. Start your free trial today.

Android Build a Self-Destructing Message Android App Sending Messages Sending the Message

Lucian Thomaz da Silva
Lucian Thomaz da Silva
9,631 Points

Choose pic and video works, Take pic and video crash

Hello guys, Basically the app works fine for choosing an existing picture or video but crashes when I try to take a picture or a video. When debugging the app I found out that the variable mMediaUri was getting a null value if I put a break point on the RecipientsActivity.java only to check its value. But, what is really weird is that if I put a break point right in MainActivity.java, the mMediaUri never gets a null value, it always works. So I can't understand what is happening, is the proccess just so fast that the variable doesn't even get time to be set? Saying that out aloud sounds like a joke haha. I'm testing it on a real device Galaxy s4 by the way. I really apreciate any help.

[Update] I've tested on Genymotion and it works fine, with no problem at all. I have android 5.0 on my Galaxy S4 and I've used Google Nexus 5 with android 4.4.4 on Genymotion. It may be related to my device itself or with the android version perhaps. I'd really like to get it working on my device, but at least I'm feeling better now knowing that it works on the emulator. [Update]

MainActivity.java

public class MainActivity extends ActionBarActivity implements ActionBar.TabListener {

    public static final String TAG = MainActivity.class.getSimpleName();

    public static final int TAKE_PHOTO_REQUEST = 0;
    public static final int TAKE_VIDEO_REQUEST = 1;
    public static final int PICK_PHOTO_REQUEST = 2;
    public static final int PICK_VIDEO_REQUEST = 3;

    public static final int MEDIA_TYPE_IMAGE = 4;
    public static final int MEDIA_TYPE_VIDEO = 5;

    public static final int FILE_SIZE_LIMIT = 1024*1024*10; // 10 MB

    protected Uri mMediaUri;

    protected DialogInterface.OnClickListener mDialogListener = new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialog, int which) {
            switch(which){
                case 0: // Take picture
                    Intent takePhotoItent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
                    mMediaUri = getOutputMediaFileUri(MEDIA_TYPE_IMAGE);
                    if(mMediaUri == null) {
                        // display an error
                        Toast.makeText(MainActivity.this, R.string.error_external_storage, Toast.LENGTH_LONG).show();
                    }
                    else {
                        takePhotoItent.putExtra(MediaStore.EXTRA_OUTPUT, mMediaUri);
                        startActivityForResult(takePhotoItent, TAKE_PHOTO_REQUEST);
                    }
                    break;
                case 1: // Take video
                    Intent videoIntent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
                    mMediaUri = getOutputMediaFileUri(MEDIA_TYPE_VIDEO);
                    if(mMediaUri == null) {
                        // display an error
                        Toast.makeText(MainActivity.this, R.string.error_external_storage, Toast.LENGTH_LONG).show();
                    }
                    else {
                        videoIntent.putExtra(MediaStore.EXTRA_OUTPUT, mMediaUri);
                        videoIntent.putExtra(MediaStore.EXTRA_DURATION_LIMIT, 10);
                        videoIntent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 0);
                        startActivityForResult(videoIntent, TAKE_VIDEO_REQUEST);
                    }
                    break;
                case 2: //Choose picture
                    Intent choosePhotoIntent = new Intent(Intent.ACTION_GET_CONTENT);
                    choosePhotoIntent.setType("image/*");
                    startActivityForResult(choosePhotoIntent, PICK_PHOTO_REQUEST);
                    break;
                case 3: // Choose video
                    Intent chooseVideoIntent = new Intent(Intent.ACTION_GET_CONTENT);
                    chooseVideoIntent .setType("video/*");
                    Toast.makeText(MainActivity.this, getString(R.string.video_file_size_warning), Toast.LENGTH_LONG).show();
                    startActivityForResult(chooseVideoIntent, PICK_VIDEO_REQUEST);
                    break;
            }
        }

        private Uri getOutputMediaFileUri(int mediaType) {
            // To be safe, you should check that the SDCard is mounted
            // using Environment.getExternalStorageState() before doing this.

            if (isExternalStorageAvailable()) {
                // get the Uri

                //1. Get the external storage directory
                String appName = MainActivity.this.getString(R.string.app_name);
                File mediaStorageDir = new File(
                        Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),
                        appName);

                //2. Create our subdirectory
                if (! mediaStorageDir.exists()) {
                    if(! mediaStorageDir.mkdirs()){
                        Log.e(TAG, "Failed to create directory.");
                        return null;
                    }
                }
                //3. Create a file name
                //4. Create the file
                File mediaFile;
                Date now = new Date();
                String timestamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.US).format(now);

                String path = mediaStorageDir.getPath() + File.separator;
                if (mediaType == MEDIA_TYPE_IMAGE){
                    mediaFile = new File(path + "IMG_" + timestamp + ".jpg");
                }
                else if (mediaType == MEDIA_TYPE_VIDEO) {
                    mediaFile = new File(path + "VID_" + timestamp + ".mp4");
                } else {
                    return null;
                }
                Log.d(TAG, "File: " + Uri.fromFile(mediaFile));
                //5. Return the file's URI
                return Uri.fromFile(mediaFile);
            } else {
                return null;
            }
        }

        private boolean isExternalStorageAvailable() {
            String state = Environment.getExternalStorageState();

            if (state.equals(Environment.MEDIA_MOUNTED)){
                return true;
            } else {
                return false;
            }
        }
    };



    /**
     * The {@link android.support.v4.view.PagerAdapter} that will provide
     * fragments for each of the sections. We use a
     * {@link FragmentPagerAdapter} derivative, which will keep every
     * loaded fragment in memory. If this becomes too memory intensive, it
     * may be best to switch to a
     * {@link android.support.v4.app.FragmentStatePagerAdapter}.
     */
    SectionsPagerAdapter mSectionsPagerAdapter;

    /**
     * The {@link ViewPager} that will host the section contents.
     */
    ViewPager mViewPager;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        ParseUser currentUser = ParseUser.getCurrentUser();
        if (currentUser == null){
            navigateToLogin();
        } else {
            Log.i(TAG, currentUser.getUsername());
        }

        // Set up the action bar.
        final ActionBar actionBar = getSupportActionBar();
        actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);

        // Create the adapter that will return a fragment for each of the three
        // primary sections of the activity.
        mSectionsPagerAdapter = new SectionsPagerAdapter(this, getSupportFragmentManager());

        // Set up the ViewPager with the sections adapter.
        mViewPager = (ViewPager) findViewById(R.id.pager);
        mViewPager.setAdapter(mSectionsPagerAdapter);

        // When swiping between different sections, select the corresponding
        // tab. We can also use ActionBar.Tab#select() to do this if we have
        // a reference to the Tab.
        mViewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
            @Override
            public void onPageSelected(int position) {
                actionBar.setSelectedNavigationItem(position);
            }
        });

        // For each of the sections in the app, add a tab to the action bar.
        for (int i = 0; i < mSectionsPagerAdapter.getCount(); i++) {
            // Create a tab with text corresponding to the page title defined by
            // the adapter. Also specify this Activity object, which implements
            // the TabListener interface, as the callback (listener) for when
            // this tab is selected.
            actionBar.addTab(
                    actionBar.newTab()
                            .setText(mSectionsPagerAdapter.getPageTitle(i))
                            .setTabListener(this));
        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        if (resultCode == RESULT_OK){
            if (requestCode == PICK_PHOTO_REQUEST || requestCode == PICK_VIDEO_REQUEST){
                if (data == null) {
                    Toast.makeText(this, getString(R.string.general_error), Toast.LENGTH_LONG).show();
                }
                else {
                    mMediaUri = data.getData();
                }
                Log.i(TAG, "Media UIR: " + mMediaUri);
                if (requestCode == PICK_VIDEO_REQUEST) {
                    // make sure the file is less than 10 MB
                    int fileSize = 0;
                    InputStream inputStream = null;

                    try{
                        inputStream = getContentResolver().openInputStream(mMediaUri);
                        fileSize = inputStream.available();
                    }
                    catch(FileNotFoundException e) {
                        Toast.makeText(this, getString(R.string.error_openning_file), Toast.LENGTH_LONG).show();
                        return;
                    }
                    catch(IOException e) {
                        Toast.makeText(this, getString(R.string.error_openning_file), Toast.LENGTH_LONG).show();
                        return;
                    }
                    finally {
                        try {
                            inputStream.close();
                        } catch (IOException e) {
                            //Intentionally blank
                        }
                    }

                    if (fileSize >= FILE_SIZE_LIMIT) {
                        Toast.makeText(this, getString(R.string.error_file_size_too_large), Toast.LENGTH_LONG).show();
                        return;
                    }
                }
            }
            else{
                Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
                mediaScanIntent.setData(mMediaUri);
                sendBroadcast(mediaScanIntent);
            }

            Intent recipientsIntent = new Intent(this, RecipientsActivity.class);
            recipientsIntent.setData(mMediaUri);

            String fileType;
            if (requestCode == PICK_PHOTO_REQUEST || requestCode == TAKE_PHOTO_REQUEST) {
                fileType = ParseConstants.TYPE_IMAGE;
            }
            else {
                fileType = ParseConstants.TYPE_VIDEO;
            }

            recipientsIntent.putExtra(ParseConstants.KEY_FILE_TYPE, fileType);
            startActivity(recipientsIntent);

        } else if(resultCode != RESULT_CANCELED){
            Toast.makeText(this, R.string.general_error, Toast.LENGTH_LONG).show();
        }
    }

    private void navigateToLogin() {
        Intent intent = new Intent(this, LoginActivity.class);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
        startActivity(intent);
    }


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        switch(id){
            case R.id.action_logout:
                ParseUser.logOut();
                navigateToLogin();
            case R.id.action_edit_friends:
                Intent intent = new Intent(this, EditFriendsActivity.class);
                startActivity(intent);
            case R.id.action_camera:
                AlertDialog.Builder builder = new AlertDialog.Builder(this);
                builder.setItems(R.array.camera_choices, mDialogListener);
                AlertDialog dialog = builder.create();
                dialog.show();
        }

        return super.onOptionsItemSelected(item);
    }

    @Override
    public void onTabSelected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
        // When the given tab is selected, switch to the corresponding page in
        // the ViewPager.
        mViewPager.setCurrentItem(tab.getPosition());
    }

    @Override
    public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
    }

    @Override
    public void onTabReselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
    }

}

RecipientsActivity.java

public class RecipientsActivity extends ListActivity {

    public static final String TAG = RecipientsActivity.class.getSimpleName();

    protected ParseRelation<ParseUser> mFriendsRelation;
    protected ParseUser mCurrentUser;
    protected List<ParseUser> mFriends;
    protected MenuItem mSendMenuItem;
    protected Uri mMediaUri;
    protected String mFileType;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
        setContentView(R.layout.activity_recipients);
        getListView().setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);

        mMediaUri = getIntent().getData();
        mFileType = getIntent().getExtras().getString(ParseConstants.KEY_FILE_TYPE);
    }

    @Override
    public void onResume() {
        super.onResume();

        mCurrentUser = ParseUser.getCurrentUser();
        mFriendsRelation = mCurrentUser.getRelation(ParseConstants.KEY_FRIENDS_RELATION);

        setProgressBarIndeterminateVisibility(true);

        ParseQuery<ParseUser> query = mFriendsRelation.getQuery();
        query.addAscendingOrder(ParseConstants.KEY_USERNAME);
        query.findInBackground(new FindCallback<ParseUser>() {
            @Override
            public void done(List<ParseUser> friends, ParseException e) {
                setProgressBarIndeterminateVisibility(false);

                if (e == null) {
                    mFriends = friends;
                    String[] usernames = new String[mFriends.size()];
                    int i = 0;
                    for (ParseUser user : mFriends) {
                        usernames[i] = user.getUsername();
                        i++;

                    }
                    ArrayAdapter<String> adapter = new ArrayAdapter<String>(
                            getListView().getContext(),
                            android.R.layout.simple_list_item_checked,
                            usernames);
                    setListAdapter(adapter);
                } else {
                    //error
                    Log.e(TAG, e.getMessage());
                    AlertDialog.Builder builder = new AlertDialog.Builder(RecipientsActivity.this);
                    builder.setMessage(e.getMessage())
                            .setTitle(R.string.error_title)
                            .setPositiveButton(android.R.string.ok, null);
                    AlertDialog dialog = builder.create();
                    dialog.show();
                }
            }
        });
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_recipients, menu);
        mSendMenuItem = menu.getItem(0);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();
        switch (id) {
            case android.R.id.home:
                NavUtils.navigateUpFromSameTask(this);
                return true;
            case R.id.action_send:
                ParseObject message = createMessage();
                if (message == null) {
                    //error
                    AlertDialog.Builder builder = new AlertDialog.Builder(this);
                    builder.setMessage(getString(R.string.error_selecting_file))
                            .setTitle(getString(R.string.error_selecting_file_title))
                            .setPositiveButton(android.R.string.ok, null);
                    AlertDialog dialog = builder.create();
                    dialog.show();
                } else {
                    send(message);
                    finish();
                }
                return true;
        }

        return super.onOptionsItemSelected(item);
    }

    @Override
    protected void onListItemClick(ListView l, View v, int position, long id) {
        super.onListItemClick(l, v, position, id);

        if (l.getCheckedItemCount() > 0) {
            mSendMenuItem.setVisible(true);
        }
        else {
            mSendMenuItem.setVisible(false);
        }
    }

    protected ParseObject createMessage() {
        ParseObject message = new ParseObject(ParseConstants.CLASS_MESSAGES);
        message.put(ParseConstants.KEY_SENDER_ID, ParseUser.getCurrentUser().getObjectId());
        message.put(ParseConstants.KEY_SENDER_NAME, ParseUser.getCurrentUser().getUsername());
        message.put(ParseConstants.KEY_RECIPIENT_IDS, getRecipientIds());
        message.put(ParseConstants.KEY_FILE_TYPE, mFileType);

        byte[] fileBytes = FileHelper.getByteArrayFromFile(this, mMediaUri);

        if (fileBytes == null) {
            return null;
        } else {
            if (mFileType.equals(ParseConstants.TYPE_IMAGE)) {
                fileBytes = FileHelper.reduceImageForUpload(fileBytes);
            }

            String fileName = FileHelper.getFileName(this, mMediaUri, mFileType);
            ParseFile file = new ParseFile(fileName, fileBytes);
            message.put(ParseConstants.KEY_FILE, file);

            return message;
        }
    }

    protected ArrayList<String> getRecipientIds() {
        ArrayList<String> recipientIds = new ArrayList<String>();
        for (int i = 0; i < getListView().getCount(); i++) {
            if (getListView().isItemChecked(i)) {
                recipientIds.add(mFriends.get(i).getObjectId());
            }
        }
        return recipientIds;
    }

    protected void send(ParseObject message) {
        message.saveInBackground(new SaveCallback() {
            @Override
            public void done(ParseException e) {
                if (e == null) {
                    // success!
                    Toast.makeText(RecipientsActivity.this, getString(R.string.success_message), Toast.LENGTH_LONG).show();
                } else {
                    AlertDialog.Builder builder = new AlertDialog.Builder(RecipientsActivity.this);
                    builder.setMessage(getString(R.string.error_sending_message))
                            .setTitle(getString(R.string.error_selecting_file_title))
                            .setPositiveButton(android.R.string.ok, null);
                    AlertDialog dialog = builder.create();
                    dialog.show();
                }
            }
        });
    }
}

4 Answers

Harry James
Harry James
14,780 Points

Hey Lucian!

What camera app are you using? It it one custom to the S4?

If so, try using a third-party camera like Google Camera and see if it works with this instead.

To reset the default camera, go to Settings >> Apps >> All >> Select your default camera app >> Clear defaults.

Then, next time you click "Take Picture", it will prompt you to select a camera app.


Hope it helps and let me know how it goes :)

Lucian Thomaz da Silva
Lucian Thomaz da Silva
9,631 Points

It works Harry James :D . Did not even went through my mind that it could do the trick. Thank you.

Harry James
Harry James
14,780 Points

Woohoo! Glad it's working! To me, it sounds like the Camera app used by your phone isn't correctly responding to the intents we give it and so, the app crashes.

This would be at fault of the camera app developers however, so there's nothing we can do to fix the issue (Unless we were to use the Camera without an Intent).

L B
L B
28,323 Points

Have you got the correct permissions in your manifest file?

Lucian Thomaz da Silva
Lucian Thomaz da Silva
9,631 Points

I believe so L B . As I mentioned, what is weird is that if I let the app flows to RecipientsActivity.java and put a break point there I'll get a null value for mMediaUri, but if I put a break point on the MainActivity.java the mMediaUri will get a valid value, and the app will run smoothly with no error.

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.lucianthomaz.ribbit" >

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

    <uses-feature
        android:name="android.hardware.camera"
        android:required="true" />

    <application
        android:name=".RibbitApplication"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name"
            android:screenOrientation="portrait" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity
            android:name=".LoginActivity"
            android:label="@string/title_activity_login"
            android:screenOrientation="portrait" >
        </activity>
        <activity
            android:name=".SignUpActivity"
            android:label="@string/title_activity_sign_up"
            android:parentActivityName=".MainActivity"
            android:screenOrientation="portrait" >
        </activity>
        <activity
            android:name=".EditFriendsActivity"
            android:label="@string/title_activity_edit_friends"
            android:parentActivityName=".MainActivity"
            android:screenOrientation="portrait" >
            <meta-data
                android:name="android.support.PARENT_ACTIVITY"
                android:value="com.lucianthomaz.ribbit.MainActivity" />
        </activity>
        <activity
            android:name=".RecipientsActivity"
            android:theme="@android:style/Theme.Holo.Light.DarkActionBar"
            android:label="@string/title_activity_recipients"
            android:screenOrientation="portrait"
            android:parentActivityName=".MainActivity" >
            <meta-data
                android:name="android.support.PARENT_ACTIVITY"
                android:value="com.lucianthomaz.ribbit.MainActivity" />
        </activity>
    </application>

</manifest>
Lucian Thomaz da Silva
Lucian Thomaz da Silva
9,631 Points

I've just tested on Genymotion and it works fine, with no problem at all. It might be something with my device itself, or the Android version maybe? I'm using 5.0 on my S4, and I've used 4.4 on Genymotion.

Hey please tag me when you figure it out. That happens as well on my s4 but another s4 without the new recent update can't take pictures they can only choose.

Harry James Thanks a bunch for helping me with all the other problems. This is the link that has the app crashes. I will post my code in as well for main activity and recipients. When I click take photo it works and takes me to the Recipients activity. From there when I try to send that photo that was taken via the app it will crash..only for 5.0 though...it works find with an s4 that is running kitkat verison.

I have read this form http://stackoverflow.com/questions/29145976/android-lollipop-camera-issue as well

package com.thegreathoudini.kevin.odysity;

import android.app.AlertDialog; import android.content.DialogInterface; import android.content.Intent; import android.net.Uri; import android.os.Environment; import android.provider.MediaStore; import android.support.v7.app.ActionBarActivity; import android.support.v7.app.ActionBar; import android.support.v4.app.FragmentTransaction; import android.support.v4.app.FragmentPagerAdapter; import android.os.Bundle; import android.support.v4.view.ViewPager; import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.view.Window; import android.widget.Toast;

import com.parse.ParseAnalytics; import com.parse.ParseUser;

import java.io.File; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Locale;

public class MainActivity extends ActionBarActivity implements ActionBar.TabListener {

/**
 * The {@link android.support.v4.view.PagerAdapter} that will provide
 * fragments for each of the sections. We use a
 * {@link FragmentPagerAdapter} derivative, which will keep every
 * loaded fragment in memory. If this becomes too memory intensive, it
 * may be best to switch to a
 * {@link android.support.v4.app.FragmentStatePagerAdapter}.
 */
SectionsPagerAdapter mSectionsPagerAdapter;
public static final String TAG = MainActivity.class.getSimpleName();


public static final int TAKE_PHOTO_REQUEST_CODE = 1;
public static final int CHOOSE_PHOTO_REQUEST_CODE = 100;
public static final int CHOOSE_DEFAULT_PICTURE_CODE = 200;



protected static final int MEDIA_TYPE_IMAGE = 400;

protected Uri mMediaUri;

protected DialogInterface.OnClickListener mDialoglistener = new DialogInterface.OnClickListener() {
    @Override
    public void onClick(DialogInterface dialog, int which) {

        switch (which){
            case 0://Take Picture
                Intent takePhotoIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
                mMediaUri = getOutputMediaFileUri(MEDIA_TYPE_IMAGE);


                if(mMediaUri == null){
                    Toast.makeText(MainActivity.this, R.string.camera_external_toast, Toast.LENGTH_LONG).show();
                }
                else{
                    takePhotoIntent.putExtra(MediaStore.EXTRA_OUTPUT, mMediaUri);
                    startActivityForResult(takePhotoIntent, TAKE_PHOTO_REQUEST_CODE);
                }
                break;

            case 1: //Choose Picture
                    Intent choosePhotoIntent = new Intent(Intent.ACTION_GET_CONTENT);
                        choosePhotoIntent.setType("image/*");
                    startActivityForResult(choosePhotoIntent, CHOOSE_PHOTO_REQUEST_CODE);
                break;
            case 2: //Change Default Picture

                Intent changeDefaultPicture = new Intent(Intent.ACTION_GET_CONTENT);
                     changeDefaultPicture.setType("image/*");
                startActivityForResult(changeDefaultPicture, CHOOSE_DEFAULT_PICTURE_CODE);
                break;


        }
    }

    private Uri getOutputMediaFileUri(int mediaType) {
        // To be safe, you should check that the SDCard is mounted
        // using Environment.getExternalStorageState() before doing this.
        //http://developer.android.com/guide/topics/media/camera.html#saving-media
        if(isExternalStorageAvailable()){

            //Get Uri
            String appname = MainActivity.this.getString(R.string.app_name);
            // 1) Get the External storage directory
            File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), appname);
            // 2) Create our subdirectory

            if(! mediaStorageDir.exists()){
               if(!mediaStorageDir.mkdir()){
                   Log.e(TAG, "Failed to make Dir");
                   return null;
               }
            }
            // 3) Create our file name
            // 4) Create the file
            File mediaFile;
            Date now = new Date();
            String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.US).format(now);

            String path = mediaStorageDir.getPath() + File.separator;
            if(mediaType == MEDIA_TYPE_IMAGE){
                mediaFile = new File(path +"IMG_"+ timeStamp + ".jpg");
            }
            else {
                return null;
            }

            Log.d(TAG,"File: " + Uri.fromFile(mediaFile));

            // 5) Return files Uri
            return Uri.fromFile(mediaFile);
        }
        else {
            return null;
        }
    }
    private boolean isExternalStorageAvailable(){

        String state = Environment.getExternalStorageState();

        if(state.equals(Environment.MEDIA_MOUNTED)){
            return true;
        }
        else {
            return false;
        }

    }
};

/**
 * The {@link ViewPager} that will host the section contents.
 */
ViewPager mViewPager;

@Override
protected void onCreate(Bundle savedInstanceState) {
    requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);


    //Parse analytics tool.
    ParseAnalytics.trackAppOpenedInBackground(getIntent());

    ParseUser currentUser = ParseUser.getCurrentUser();
    if(currentUser == null)
        {
            navigateToLogin();
        }
    else{
        //Log.i
        Log.i(TAG, currentUser.getUsername());
    }


    // Set up the action bar.
    final ActionBar actionBar = getSupportActionBar();
    actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);

    // Create the adapter that will return a fragment for each of the three
    // primary sections of the activity.
    mSectionsPagerAdapter = new SectionsPagerAdapter(this, getSupportFragmentManager());

    // Set up the ViewPager with the sections adapter.
    mViewPager = (ViewPager) findViewById(R.id.pager);
    mViewPager.setAdapter(mSectionsPagerAdapter);

    // When swiping between different sections, select the corresponding
    // tab. We can also use ActionBar.Tab#select() to do this if we have
    // a reference to the Tab.
    mViewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
        @Override
        public void onPageSelected(int position) {
            actionBar.setSelectedNavigationItem(position);
        }
    });

    // For each of the sections in the app, add a tab to the action bar.
    for (int i = 0; i < mSectionsPagerAdapter.getCount(); i++) {
        // Create a tab with text corresponding to the page title defined by
        // the adapter. Also specify this Activity object, which implements
        // the TabListener interface, as the callback (listener) for when
        // this tab is selected.
        actionBar.addTab(
                actionBar.newTab()
                        .setText(mSectionsPagerAdapter.getPageTitle(i))
                        .setTabListener(this));
    }
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);

    if(resultCode == RESULT_OK){

        if(requestCode == CHOOSE_PHOTO_REQUEST_CODE){
            if(data == null){
                //error
                Toast.makeText(this, R.string.general_error, Toast.LENGTH_LONG).show();
            }
            else{
                mMediaUri = data.getData();
            }

        }



        else {
            Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
                 mediaScanIntent.setData(mMediaUri);
            sendBroadcast(mediaScanIntent);
        }



        Intent recipientsIntent = new Intent(this, RecipientsActivity.class);
        recipientsIntent.setData(mMediaUri);



        String fileType = null;
        if(requestCode == TAKE_PHOTO_REQUEST_CODE || requestCode == CHOOSE_PHOTO_REQUEST_CODE) {
            fileType = ParseConstants.TYPE_IMAGE;
        }

        recipientsIntent.putExtra(ParseConstants.KEY_FILE_TYPE, fileType);
        startActivity(recipientsIntent);

    }
    else if(resultCode != RESULT_CANCELED){
        Toast.makeText(MainActivity.this, R.string.general_error, Toast.LENGTH_LONG).show();
    }
}

private void navigateToLogin() {
    Intent intent = new Intent(MainActivity.this, LoginActivity.class);
    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
    startActivity(intent);
}


@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.menu_main, menu);
    return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    // Handle action bar item clicks here. The action bar will
    // automatically handle clicks on the Home/Up button, so long
    // as you specify a parent activity in AndroidManifest.xml.
    int id = item.getItemId();

    switch(id){
        case R.id.logoutMenu:
          ParseUser.logOutInBackground();
          navigateToLogin();
        break;

        case R.id.editFriendsMenu:
            Intent intent = new Intent(this, EditFriendsActivity.class);
            startActivity(intent);
        break;

        case R.id.camera_menu:
            AlertDialog.Builder builder = new AlertDialog.Builder(this);
                                builder.setItems(R.array.camera_Choices, mDialoglistener);
            AlertDialog dialog = builder.create();
            dialog.show();
        break;
    }






    return super.onOptionsItemSelected(item);
}

@Override
public void onTabSelected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
    // When the given tab is selected, switch to the corresponding page in
    // the ViewPager.
    mViewPager.setCurrentItem(tab.getPosition());
}

@Override
public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
}

@Override
public void onTabReselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
}

}

package com.thegreathoudini.kevin.odysity;

import android.app.AlertDialog; import android.app.ListActivity; import android.net.Uri; import android.os.Bundle; import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.ArrayAdapter; import android.widget.EditText; import android.widget.ListView; import android.widget.ProgressBar; import android.widget.Toast;

import com.parse.FindCallback; import com.parse.ParseException; import com.parse.ParseFile; import com.parse.ParseInstallation; import com.parse.ParseObject; import com.parse.ParsePush; import com.parse.ParseQuery; import com.parse.ParseRelation; import com.parse.ParseUser; import com.parse.SaveCallback;

import java.util.ArrayList; import java.util.List;

public class RecipientsActivity extends ListActivity {

public static final String TAG = RecipientsActivity.class.getSimpleName();

protected ParseRelation<ParseUser> mFriendsRelations;
protected ParseUser mCurrentUser;
protected List<ParseUser> mFriends;
protected ProgressBar mLoadingRecipients;
protected MenuItem mSendMenuItem;
protected Uri mMediaUri;
protected String mFileType;
protected EditText mCommentText;
protected String mComment;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_recipients);
    getActionBar();

    getListView().setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);

    mMediaUri = getIntent().getData();
    mFileType = getIntent().getExtras().getString(ParseConstants.KEY_FILE_TYPE);
}

@Override
protected void onResume() {
    super.onResume();

    mCommentText = (EditText) findViewById(R.id.commentEditText);
    mLoadingRecipients = (ProgressBar) findViewById(R.id.loadingRecipientsProgress);

    mCurrentUser = ParseUser.getCurrentUser();
    mFriendsRelations = mCurrentUser.getRelation(ParseConstants.KEY_Friends_Relations);


    mLoadingRecipients.setVisibility(View.VISIBLE);
    ParseQuery<ParseUser> query = mFriendsRelations.getQuery();
    query.orderByAscending(ParseConstants.KEY_USERNAME);
    query.setCachePolicy(ParseQuery.CachePolicy.CACHE_THEN_NETWORK);
    query.setLimit(1000);
    query.findInBackground(new FindCallback<ParseUser>() {
        @Override
        public void done(List<ParseUser> friends, ParseException e) {
            //Build the list of Parse relations

            mLoadingRecipients.setVisibility(View.INVISIBLE);
            if (e == null) {

                mFriends = friends;
                String[] friendsUsername = new String[mFriends.size()];
                int i = 0;
                for (ParseUser friendlist : mFriends) {
                    friendsUsername[i] = friendlist.get(ParseConstants.KEY_NAME).toString();
                    i++;

                    ArrayAdapter<String> adapter = new ArrayAdapter<String>(
                            RecipientsActivity.this, android.R.layout.simple_list_item_checked, friendsUsername);
                    setListAdapter(adapter);
                }

            } else {
                mLoadingRecipients.setVisibility(View.INVISIBLE);
                Log.e(TAG, e.getMessage());
                AlertDialog.Builder builder = new AlertDialog.Builder(RecipientsActivity.this);
                builder.setTitle(R.string.signup_error_title)
                        .setMessage(R.string.no_friends_found)
                        .setPositiveButton(android.R.string.ok, null);
                AlertDialog dialog = builder.create();
                dialog.show();

            }
        }
    });
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.menu_recipients, menu);
    mSendMenuItem = menu.getItem(0);
    return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    // Handle action bar item clicks here. The action bar will
    // automatically handle clicks on the Home/Up button, so long
    // as you specify a parent activity in AndroidManifest.xml.
    int id = item.getItemId();

    //noinspection SimplifiableIfStatement
    if (id == R.id.action_send) {

        mComment = mCommentText.getText().toString();

        if(mComment.isEmpty()){
            mComment = "";
        }

        mLoadingRecipients.setVisibility(View.VISIBLE);
        ParseObject message = createMessage();
        if(message == null){
            //error
            mLoadingRecipients.setVisibility(View.INVISIBLE);
            AlertDialog.Builder builder = new AlertDialog.Builder(this);
                                builder.setMessage(R.string.error_file)
                                       .setTitle(R.string.signup_error_title)
                                       .setPositiveButton(android.R.string.ok,null);
            AlertDialog dialog = builder.create();
            dialog.show();
        }
        else {


            Toast.makeText(RecipientsActivity.this, R.string.sending_message_toast, Toast.LENGTH_LONG).show();
            send(message);
            mLoadingRecipients.setVisibility(View.INVISIBLE);
            finish();
        }

        return true;
    }

    return super.onOptionsItemSelected(item);
}

@Override
protected void onListItemClick(ListView l, View v, int position, long id) {
    super.onListItemClick(l, v, position, id);

    if(l.getCheckedItemCount() > 0){
        mSendMenuItem.setVisible(true);
    }
    else {
        mSendMenuItem.setVisible(false);
    }


}

protected ParseObject createMessage(){

    ParseObject message = new ParseObject(ParseConstants.CLASS_MESSAGES);
                message.put(ParseConstants.KEY_SENDERS_IDS , ParseUser.getCurrentUser().getObjectId());
                message.put(ParseConstants.KEY_SENDER_NAME , ParseUser.getCurrentUser().get(ParseConstants.KEY_NAME));
                message.put(ParseConstants.KEY_RECIPIENTS_IDS, getRecipientsIds());
                message.put(ParseConstants.KEY_FILE_TYPE, mFileType);
                message.put(ParseConstants.KEY_COMMENT_TEXT, mComment);

    byte[] fileByte = FileHelper.getByteArrayFromFile(this, mMediaUri);

    if(fileByte == null){
        return null;
    }
    else {
     if (mFileType.equals(ParseConstants.TYPE_IMAGE)){
         fileByte = FileHelper.reduceImageForUpload(fileByte);

     }
        String fileName = FileHelper.getFileName(this, mMediaUri,mFileType);
        ParseFile file = new ParseFile(fileName, fileByte);
        message.put(ParseConstants.KEY_FILE, file);

        return message;

    }


}

protected ArrayList<String> getRecipientsIds(){
    ArrayList<String> recipientsList = new ArrayList<>();
    for(int i = 0; i<getListView().getCount() ; i++){
        if(getListView().isItemChecked(i)){
            recipientsList.add(mFriends.get(i).getObjectId());

        }

    }
    return  recipientsList;
}

protected void send(ParseObject message){
    message.saveInBackground(new SaveCallback() {
        @Override
        public void done(ParseException e) {

            if (e == null) {
                //success
                Toast.makeText(RecipientsActivity.this, R.string.success_message, Toast.LENGTH_LONG).show();

                sendPushNotification();


            } else {
                AlertDialog.Builder builder = new AlertDialog.Builder(RecipientsActivity.this);
                builder.setMessage(R.string.error_file)
                        .setTitle(R.string.signup_error_title)
                        .setPositiveButton(android.R.string.ok, null);
                AlertDialog dialog = builder.create();
                dialog.show();
            }

        }
    });
}
protected  void sendPushNotification (){
    ParseQuery<ParseInstallation> query = ParseInstallation.getQuery();
    query.whereContainedIn(ParseConstants.KEY_USER_ID, getRecipientsIds());

    //send push notification
    ParsePush push = new ParsePush();
    push.setQuery(query);
    push.setMessage(getString(R.string.push_string , ParseUser.getCurrentUser().get(ParseConstants.KEY_NAME)));

    push.sendInBackground();
}

}

Lucian Thomaz da Silva
Lucian Thomaz da Silva
9,631 Points

Kevin Nguyen I'm not really looking for the solution because it works in my emulator, so I decided to move on with the rest of the project, but if I find the solution I'll share it for sure. If you find an answer please share with me as well. :)