package de.jeisfeld.augendiagnoselib.activities; import android.annotation.SuppressLint; import android.app.DatePickerDialog; import android.app.Dialog; import android.app.DialogFragment; import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.text.InputType; import android.util.Log; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.View; import android.view.View.OnClickListener; import android.view.inputmethod.EditorInfo; import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.DatePicker; import android.widget.EditText; import android.widget.ImageView; import android.widget.TextView; import android.widget.TextView.OnEditorActionListener; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; import java.util.Comparator; import java.util.Date; import java.util.GregorianCalendar; import java.util.List; import de.jeisfeld.augendiagnoselib.Application; import de.jeisfeld.augendiagnoselib.Application.AuthorizationLevel; import de.jeisfeld.augendiagnoselib.R; import de.jeisfeld.augendiagnoselib.components.InstantAutoCompleteTextView; import de.jeisfeld.augendiagnoselib.fragments.ListFoldersBaseFragment; import de.jeisfeld.augendiagnoselib.util.DateUtil; import de.jeisfeld.augendiagnoselib.util.DialogUtil; import de.jeisfeld.augendiagnoselib.util.DialogUtil.ConfirmDialogFragment.ConfirmDialogListener; import de.jeisfeld.augendiagnoselib.util.PreferenceUtil; import de.jeisfeld.augendiagnoselib.util.TrackingUtil; import de.jeisfeld.augendiagnoselib.util.TrackingUtil.Category; import de.jeisfeld.augendiagnoselib.util.TwoImageSelectionHandler; import de.jeisfeld.augendiagnoselib.util.imagefile.EyePhoto; import de.jeisfeld.augendiagnoselib.util.imagefile.EyePhoto.RightLeft; import de.jeisfeld.augendiagnoselib.util.imagefile.FileUtil; import de.jeisfeld.augendiagnoselib.util.imagefile.ImageUtil; import de.jeisfeld.augendiagnoselib.util.imagefile.JpegMetadataUtil; import de.jeisfeld.augendiagnoselib.util.imagefile.MediaStoreUtil; import de.jeisfeld.augendiagnoselib.util.imagefile.PupilAndIrisDetector; /** * Activity to display a pair of new eye photos, choose a name and a date for them, and shift them into the * application's eye photo folder (with renaming). * * <p>The activity can be started either with a folder name, or with an array of file names. */ public class OrganizeNewPhotosActivity extends StandardActivity { /** * The resource key for the input folder. */ private static final String STRING_EXTRA_INPUTFOLDER = "de.jeisfeld.augendiagnoselib.INPUTFOLDER"; /** * The resource key for the list of input files. */ private static final String STRING_EXTRA_FILENAMES = "de.jeisfeld.augendiagnoselib.FILENAMES"; /** * The resource key for the flag indicating if the last picture is the right eye. */ private static final String STRING_EXTRA_RIGHTEYELAST = "de.jeisfeld.augendiagnoselib.RIGHTEYELAST"; /** * The resource key for the next action to be done after organizing a pair of images. */ private static final String STRING_EXTRA_NEXTACTION = "de.jeisfeld.augendiagnoselib.NEXTACTION"; /** * Result code passed to indicate that the activity should be finished. */ public static final int RESULT_FINISH = 2; /** * The input folder for images. */ private File mInputFolder; /** * The parent output folder for images. */ @Nullable private File mParentFolder; /** * The currently selected date to be given to the pictures. */ private Calendar mPictureDate = Calendar.getInstance(); /** * The flag indicating if the last picture is the right eye. */ private boolean mRightEyeLast; /** * The next action to be done after organizing a pair of images. */ private NextAction mNextAction; /** * The list of input images. */ private String[] mFileNames; /** * The total number of images in the input folder. */ private int mTotalImageCount; /** * The ImageViews displaying the eye photos. */ private ImageView mImageRight, mImageLeft; /** * The EditText with the name to which the photos should be assigned. */ private InstantAutoCompleteTextView mEditName; /** * The EditText with the data to which the photos should be assigned. */ private EditText mEditDate; /** * The currently chosen eye photos. */ @Nullable private EyePhoto mPhotoRight, mPhotoLeft; /** * Static helper method to start the activity, passing the source folder, the target folder, and a flag indicating * if the last picture is the right or the left eye. * * @param context The context in which the activity is started. * @param inputFolderName The folder containing the input files. * @param rightEyeLast A flag indicating if the last picture is the right eye. * @param nextAction The next action to be done after organizing a pair of images. */ public static void startActivity(@NonNull final Context context, final String inputFolderName, final boolean rightEyeLast, final NextAction nextAction) { Intent intent = new Intent(context, OrganizeNewPhotosActivity.class); intent.putExtra(STRING_EXTRA_INPUTFOLDER, inputFolderName); intent.putExtra(STRING_EXTRA_RIGHTEYELAST, rightEyeLast); intent.putExtra(STRING_EXTRA_NEXTACTION, nextAction); context.startActivity(intent); } /** * Static helper method to start the activity, passing the list of files, the target folder, and a flag indicating * if the last picture is the right or the left eye. * * @param context The context in which the activity is started. * @param fileNames The list of files. * @param rightEyeLast A flag indicating if the last picture is the right eye. * @param nextAction The next action to be done after organizing a pair of images. */ public static void startActivity(@NonNull final Context context, final String[] fileNames, final boolean rightEyeLast, final NextAction nextAction) { Intent intent = new Intent(context, OrganizeNewPhotosActivity.class); intent.putExtra(STRING_EXTRA_FILENAMES, fileNames); intent.putExtra(STRING_EXTRA_RIGHTEYELAST, rightEyeLast); intent.putExtra(STRING_EXTRA_NEXTACTION, nextAction); context.startActivity(intent); } /* * Create the activity, build the view, fill all content and add listeners. */ @Override protected final void onCreate(@Nullable final Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_organize_new_photos); String inputFolderString = getIntent().getStringExtra(STRING_EXTRA_INPUTFOLDER); if (inputFolderString != null) { mInputFolder = new File(inputFolderString); } mParentFolder = new File(PreferenceUtil.getSharedPreferenceString(R.string.key_folder_photos)); mRightEyeLast = getIntent().getBooleanExtra(STRING_EXTRA_RIGHTEYELAST, false); mNextAction = (NextAction) getIntent().getSerializableExtra(STRING_EXTRA_NEXTACTION); mFileNames = getIntent().getStringArrayExtra(STRING_EXTRA_FILENAMES); if (savedInstanceState != null) { mTotalImageCount = savedInstanceState.getInt("totalImageCount"); String rightEyePath = savedInstanceState.getString("rightEyePhoto"); mPhotoRight = rightEyePath == null ? null : new EyePhoto(rightEyePath); String leftEyePath = savedInstanceState.getString("leftEyePhoto"); mPhotoLeft = leftEyePath == null ? null : new EyePhoto(leftEyePath); } mImageRight = (ImageView) findViewById(R.id.imageOrganizeRight); mImageLeft = (ImageView) findViewById(R.id.imageOrganizeLeft); // when editing the "name" field, show suggestions mEditName = (InstantAutoCompleteTextView) findViewById(R.id.editName); mEditName.setAdapter(new ArrayAdapter<>(this, R.layout.adapter_list_names, ListFoldersBaseFragment .getFolderNames(mParentFolder))); // Ensure that Keyboard "ok" click already triggers next step. mEditName.setOnEditorActionListener(new OnEditorActionListener() { @Override public boolean onEditorAction(final TextView v, final int actionId, final KeyEvent event) { if (actionId == EditorInfo.IME_ACTION_DONE) { onOkClick(v); return true; } return false; } }); // when touching the "date" field, open a dialog. mEditDate = (EditText) findViewById(R.id.editDate); mEditDate.setInputType(InputType.TYPE_NULL); mEditDate.setOnTouchListener(new View.OnTouchListener() { @SuppressLint("ClickableViewAccessibility") @Override public boolean onTouch(final View v, @NonNull final MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_DOWN) { openDateDialog(v); } return true; } }); if (mPhotoLeft == null && mPhotoRight == null) { // initial fill setPicturesAndValues(false); } else { // only load predefined images updateImages(true); } // Ensure that target folder exists if (!mParentFolder.exists()) { boolean success = mParentFolder.mkdirs(); if (!success) { Log.w(Application.TAG, "Failed to create folder" + mParentFolder); } } configureButtons(); if (getString(R.string.section_select_photos).length() == 0) { findViewById(R.id.textViewSelectPhotos).setVisibility(View.GONE); } if (savedInstanceState == null) { PreferenceUtil.incrementCounter(R.string.key_statistics_countorganizestart); TrackingUtil.sendEvent(Category.EVENT_USER, "Organize", "Start"); } DialogUtil.displayTip(this, R.string.message_tip_organizephotos, R.string.key_tip_organizephotos); } /** * Configure the buttons "Cancel" and "Other Pictures". */ private void configureButtons() { // Set on-click action for selecting other pictures and for cancelling activity. Button buttonOtherPictures = (Button) findViewById(R.id.buttonOrganizeOtherPictures); Button buttonCancel = (Button) findViewById(R.id.buttonOrganizeCancel); if (getResources().getBoolean(R.bool.flag_overwrite_by_camera_from_organize)) { buttonOtherPictures.setText(getString(R.string.button_camera)); buttonOtherPictures.setOnClickListener(new OnClickListener() { @Override public void onClick(final View v) { CameraActivity.startActivity(OrganizeNewPhotosActivity.this, mPhotoRight == null ? null : mPhotoRight.getAbsolutePath(), mPhotoLeft == null ? null : mPhotoLeft.getAbsolutePath()); finish(); } }); buttonCancel.setText(getString(R.string.button_delete)); buttonCancel.setOnClickListener(new OnClickListener() { @Override public void onClick(final View v) { ConfirmDialogListener listenerDelete = new ConfirmDialogListener() { /** * The serial version id. */ private static final long serialVersionUID = 1L; @Override public void onDialogPositiveClick(final DialogFragment dialog) { // delete images if (mPhotoLeft != null) { mPhotoLeft.delete(); } if (mPhotoRight != null) { mPhotoRight.delete(); } finish(); } @Override public void onDialogNegativeClick(final DialogFragment dialog) { finish(); } }; DialogUtil.displayConfirmationMessage(OrganizeNewPhotosActivity.this, listenerDelete, R.string.button_delete, R.string.message_dialog_confirm_delete_two_photos); } }); } else { buttonOtherPictures.setText(getString(R.string.button_other_pictures)); buttonOtherPictures.setOnClickListener(new OnClickListener() { @Override public void onClick(final View v) { if (mInputFolder != null) { SelectTwoPicturesActivity.startActivity(OrganizeNewPhotosActivity.this, mInputFolder.getAbsolutePath()); } else { SelectTwoPicturesActivity.startActivity(OrganizeNewPhotosActivity.this, mFileNames); } } }); buttonCancel.setText(getString(R.string.button_cancel)); buttonCancel.setOnClickListener(new OnClickListener() { @Override public void onClick(final View v) { finish(); } }); } } @Override protected final int getHelpResource() { return R.string.html_organize_photos; } @Override protected final void onDestroy() { super.onDestroy(); TwoImageSelectionHandler.clean(); } /** * Helper methods to load the pictures and to preset the date (from the pictures). * * @param update Value true means that values are not initially filled, but updated after organizing an eye photo pair. */ private void setPicturesAndValues(final boolean update) { File[] files; if (mInputFolder != null) { // retrieve files from Input Folder files = mInputFolder.listFiles(new ImageUtil.ImageFileFilter()); if (files == null) { if (update) { finish(); } else { DialogUtil.displayError(this, R.string.message_dialog_no_picture, true); } return; } // Sort files by date Arrays.sort(files, new Comparator<File>() { @Override public int compare(@NonNull final File f1, @NonNull final File f2) { return Long.valueOf(f2.lastModified()).compareTo(f1.lastModified()); } }); } else { ArrayList<File> fileList = new ArrayList<>(); ArrayList<String> fileNameList = new ArrayList<>(); for (String fileName : mFileNames) { File file = new File(fileName); if (file.exists() && file.isFile()) { if (!update || !isCurrentlyDisplayed(file)) { fileList.add(file); fileNameList.add(fileName); } } } files = fileList.toArray(new File[fileList.size()]); mFileNames = fileNameList.toArray(new String[fileNameList.size()]); } if (files.length > 0) { EyePhoto photoLast = new EyePhoto(files[0]); EyePhoto photoLastButOne = files.length == 1 ? null : new EyePhoto(files[1]); // Override last modified time by EXIF time if (photoLastButOne != null) { boolean isRealLast = photoLast.getDate().compareTo(photoLastButOne.getDate()) >= 0; if (!isRealLast) { EyePhoto temp = photoLast; photoLast = photoLastButOne; photoLastButOne = temp; } } // Organize left vs. right if (photoLast.getRightLeft() == RightLeft.RIGHT) { mPhotoRight = photoLast; mPhotoLeft = photoLastButOne; } else if (photoLast.getRightLeft() == RightLeft.LEFT) { mPhotoLeft = photoLast; mPhotoRight = photoLastButOne; } else if (mRightEyeLast) { mPhotoRight = photoLast; mPhotoLeft = photoLastButOne; } else { mPhotoLeft = photoLast; mPhotoRight = photoLastButOne; } updateImages(true); } else { if (update) { finish(); } else { // Error message if there are less than two files DialogUtil.displayError(this, R.string.message_dialog_no_picture, true); } } mTotalImageCount = files.length; } /** * Check if a file is currently displayed as right or left eye. * * @param file the file. * @return true if it is displayed. */ private boolean isCurrentlyDisplayed(final File file) { return (mPhotoRight != null && mPhotoRight.getAbsolutePath().equals(file.getAbsolutePath())) || (mPhotoLeft != null && mPhotoLeft.getAbsolutePath().equals(file.getAbsolutePath())); } /** * Display the two images. As these are only two thumbnails, we do this in the main thread. Separate thread may lead * to issues when returning from SelectTwoImages after orientation change * * @param updateDate if true, then the date will be updated from the images. */ private void updateImages(final boolean updateDate) { if (mPhotoRight == null) { mImageRight.setImageResource(android.R.color.transparent); } else { mImageRight.setImageBitmap(mPhotoRight.getImageBitmap(MediaStoreUtil.MINI_THUMB_SIZE)); mImageRight.invalidate(); } if (mPhotoLeft == null) { mImageLeft.setImageResource(android.R.color.transparent); } else { mImageLeft.setImageBitmap(mPhotoLeft.getImageBitmap(MediaStoreUtil.MINI_THUMB_SIZE)); mImageLeft.invalidate(); } if (updateDate) { Date date = mPhotoRight == null ? mPhotoLeft.getDate() : mPhotoRight.getDate(); mPictureDate.setTime(date); mEditDate.setText(DateUtil.getDisplayDate(mPictureDate)); mEditDate.invalidate(); } if (mInputFolder != null) { PupilAndIrisDetector.determineAndStoreIrisPosition(mPhotoRight); PupilAndIrisDetector.determineAndStoreIrisPosition(mPhotoLeft); } } /** * Helper method to display an error message. * * @param resource The resource containing the error message. * @param args The arguments of the error message. */ private void displayError(final int resource, final Object... args) { DialogUtil.displayError(this, resource, false, args); } /** * onClick action for Button "Switch images". * * @param view The view triggering the onClick action. */ public final void switchImages(final View view) { mRightEyeLast = !mRightEyeLast; EyePhoto temp = mPhotoLeft; mPhotoLeft = mPhotoRight; mPhotoRight = temp; updateImages(false); } /** * onClick action for Button "Ok". Moves and renames the selected files after making JPG validation. * * @param view The view triggering the onClick action. */ public final void onOkClick(final View view) { final String name = mEditName.getText().toString().trim(); if (name.length() < 1) { displayError(R.string.message_dialog_select_name); return; } List<String> existingNames = ListFoldersBaseFragment.getFolderNames(mParentFolder); if (Application.getAuthorizationLevel() == AuthorizationLevel.TRIAL_ACCESS && !existingNames.contains(name) && existingNames.size() >= ListFoldersBaseFragment.TRIAL_MAX_NAMES) { // Error due to trial version. DialogUtil.displayAuthorizationError(this, R.string.message_dialog_trial_names); } else { validateAndMovePhotos(); } } /** * Move and rename the selected files after making JPG validation. */ private void validateAndMovePhotos() { final String name = mEditName.getText().toString(); if (name.length() < 1) { displayError(R.string.message_dialog_select_name); return; } Date date = new Date(mPictureDate.getTimeInMillis()); File targetFolder = new File(mParentFolder, name); if (targetFolder.exists() && !targetFolder.isDirectory()) { displayError(R.string.message_dialog_cannot_create_folder, targetFolder.getAbsolutePath()); return; } else if (!targetFolder.exists()) { boolean success = FileUtil.mkdir(targetFolder); if (!success) { displayError(R.string.message_dialog_cannot_create_folder, targetFolder.getAbsolutePath()); return; } } final EyePhoto targetPhotoRight = mPhotoRight == null ? null : new EyePhoto(targetFolder.getAbsolutePath(), name, date, RightLeft.RIGHT, mPhotoRight.getSuffix()); final EyePhoto targetPhotoLeft = mPhotoLeft == null ? null : new EyePhoto(targetFolder.getAbsolutePath(), name, date, RightLeft.LEFT, mPhotoLeft.getSuffix()); try { if (mPhotoRight != null) { JpegMetadataUtil.checkJpeg(mPhotoRight.getAbsolutePath()); } if (mPhotoLeft != null) { JpegMetadataUtil.checkJpeg(mPhotoLeft.getAbsolutePath()); } } catch (IOException e) { ConfirmDialogListener confirmationListener = new ConfirmDialogListener() { /** * The serial version id. */ private static final long serialVersionUID = -3186094978749077352L; @Override public void onDialogPositiveClick(final DialogFragment dialog) { movePhotos(targetPhotoRight, targetPhotoLeft, name); } @Override public void onDialogNegativeClick(final DialogFragment dialog) { // Do nothing } }; DialogUtil.displayConfirmationMessage(this, confirmationListener, R.string.button_move, R.string.message_dialog_confirm_no_jpeg); return; } if (mPhotoRight != null && !mPhotoRight.exists()) { displayError(R.string.message_dialog_file_does_not_exist, mPhotoRight.getAbsolutePath()); return; } if (mPhotoLeft != null && !mPhotoLeft.exists()) { displayError(R.string.message_dialog_file_does_not_exist, mPhotoLeft.getAbsolutePath()); return; } if ((targetPhotoRight != null && targetPhotoRight.exists()) || (targetPhotoLeft != null && targetPhotoLeft.exists())) { DialogUtil.displayConfirmationMessage(this, new ConfirmDialogListener() { /** * The serial version id. */ private static final long serialVersionUID = 1L; @Override public void onDialogPositiveClick(final DialogFragment dialog) { if (targetPhotoRight != null && targetPhotoRight.exists()) { MediaStoreUtil.deleteThumbnail(targetPhotoRight.getAbsolutePath()); } if (targetPhotoLeft != null && targetPhotoLeft.exists()) { MediaStoreUtil.deleteThumbnail(targetPhotoLeft.getAbsolutePath()); } movePhotos(targetPhotoRight, targetPhotoLeft, name); } @Override public void onDialogNegativeClick(final DialogFragment dialog) { // Do nothing } }, R.string.button_overwrite, R.string.message_dialog_confirm_overwrite, name, DateUtil.format(date)); return; } movePhotos(targetPhotoRight, targetPhotoLeft, name); if (mInputFolder == null) { PupilAndIrisDetector.determineAndStoreIrisPosition(targetPhotoRight); PupilAndIrisDetector.determineAndStoreIrisPosition(targetPhotoLeft); } } /** * Move and rename the selected files. * * @param targetPhotoRight The right eye photo. * @param targetPhotoLeft The left eye photo. * @param name The selected name. */ private void movePhotos(final EyePhoto targetPhotoRight, final EyePhoto targetPhotoLeft, final String name) { if (mInputFolder != null) { // in case of input folder, move files if (mPhotoRight != null && !mPhotoRight.moveTo(targetPhotoRight, true)) { displayError(R.string.message_dialog_failed_to_move_file, mPhotoRight.getAbsolutePath(), targetPhotoRight.getAbsolutePath()); return; } if (mPhotoLeft != null && !mPhotoLeft.moveTo(targetPhotoLeft, true)) { displayError(R.string.message_dialog_failed_to_move_file, mPhotoLeft.getAbsolutePath(), targetPhotoLeft.getAbsolutePath()); return; } } else { // in case of input files, copy files if (mPhotoRight != null && !mPhotoRight.copyTo(targetPhotoRight)) { displayError(R.string.message_dialog_failed_to_move_file, mPhotoRight.getAbsolutePath(), targetPhotoRight.getAbsolutePath()); return; } if (mPhotoLeft != null && !mPhotoLeft.copyTo(targetPhotoLeft)) { displayError(R.string.message_dialog_failed_to_move_file, mPhotoLeft.getAbsolutePath(), targetPhotoLeft.getAbsolutePath()); return; } } if (mPhotoRight != null && targetPhotoRight != null) { targetPhotoRight.storeDefaultMetadata(); targetPhotoRight.addToMediaStore(); } if (mPhotoLeft != null && targetPhotoLeft != null) { targetPhotoLeft.storeDefaultMetadata(); targetPhotoLeft.addToMediaStore(); } // Store the name so that it may be opened automatically PreferenceUtil.setSharedPreferenceString(R.string.key_internal_last_name, name); PreferenceUtil.setSharedPreferenceBoolean(R.string.key_internal_organized_new_photo, true); PreferenceUtil.incrementCounter(R.string.key_statistics_countorganizeend); TrackingUtil.sendEvent(Category.EVENT_USER, "Organize", "End"); switch (mNextAction) { case NEXT_IMAGES: setPicturesAndValues(true); DialogUtil.displayToast(this, R.string.message_dialog_organized_photos); break; case VIEW_IMAGES: ListFoldersForDisplayActivity.startActivity(this); finish(); break; default: break; } } /* * Handle the result of a called activity - either the selection of the name or the selection of two pictures. */ @Override protected final void onActivityResult(final int requestCode, final int resultCode, final Intent data) { switch (requestCode) { case SelectTwoPicturesActivity.REQUEST_CODE: if (resultCode == RESULT_FINISH) { finish(); return; } String fileName1 = SelectTwoPicturesActivity.getResultFile1(resultCode, data); String fileName2 = SelectTwoPicturesActivity.getResultFile2(resultCode, data); if (fileName1 == null && fileName2 == null) { setPicturesAndValues(true); } else { mPhotoRight = fileName1 == null ? null : new EyePhoto(fileName1); mPhotoLeft = fileName2 == null ? null : new EyePhoto(fileName2); updateImages(true); } break; default: super.onActivityResult(requestCode, resultCode, data); } } /** * onClick action for date field. Opens a date picker dialog. * * @param view The view triggering the onClick action. */ private void openDateDialog(final View view) { Bundle bundle = new Bundle(); bundle.putInt("Year", mPictureDate.get(Calendar.YEAR)); bundle.putInt("Month", mPictureDate.get(Calendar.MONTH)); bundle.putInt("Date", mPictureDate.get(Calendar.DAY_OF_MONTH)); DateDialogFragment fragment = new DateDialogFragment(); fragment.setArguments(bundle); fragment.show(getFragmentManager(), DateDialogFragment.class.toString()); } @Override protected final void onSaveInstanceState(@NonNull final Bundle outState) { super.onSaveInstanceState(outState); if (mPhotoRight != null || mPhotoLeft != null) { outState.putInt("totalImageCount", mTotalImageCount); if (mPhotoRight != null) { outState.putString("rightEyePhoto", mPhotoRight.getAbsolutePath()); } if (mPhotoLeft != null) { outState.putString("leftEyePhoto", mPhotoLeft.getAbsolutePath()); } } } /** * Set the displayed date. * * @param yearSelected The year. * @param monthOfYear The month of the year. * @param dayOfMonth The day of the month. */ private void setDate(final int yearSelected, final int monthOfYear, final int dayOfMonth) { mPictureDate = new GregorianCalendar(yearSelected, monthOfYear, dayOfMonth); mEditDate.setText(DateUtil.getDisplayDate(mPictureDate)); mEditDate.invalidate(); } /** * onClick action for displaying the two pictures. * * @param view The view triggering the onClick action. */ public final void displayNewImages(final View view) { if (mPhotoRight != null && mPhotoLeft != null) { DisplayTwoActivity.startActivity(this, mPhotoRight.getAbsolutePath(), mPhotoLeft.getAbsolutePath(), true); } else if (mPhotoRight != null) { DisplayOneActivity.startActivity(this, mPhotoRight.getAbsolutePath()); } else if (mPhotoLeft != null) { DisplayOneActivity.startActivity(this, mPhotoLeft.getAbsolutePath()); } } /** * onClick action - overrides other onClick action to ensure that nothing happens. * * @param view The view triggering the onClick action. */ public final void doNothing(final View view) { // do nothing } /** * Fragment for the date dialog. */ public static class DateDialogFragment extends DialogFragment { @NonNull @Override public final Dialog onCreateDialog(final Bundle savedInstanceState) { int year = getArguments().getInt("Year"); int month = getArguments().getInt("Month"); int date = getArguments().getInt("Date"); DatePickerDialog.OnDateSetListener dateSetListener = new DatePickerDialog.OnDateSetListener() { @Override public void onDateSet(final DatePicker view, final int yearSelected, final int monthOfYear, final int dayOfMonth) { ((OrganizeNewPhotosActivity) getActivity()).setDate(yearSelected, monthOfYear, dayOfMonth); } }; return new DatePickerDialog(getActivity(), dateSetListener, year, month, date); } } /** * The next action to be done after organizing photos. */ public enum NextAction { /** * Continue the activity with the next image pair (and finish if not existing). */ NEXT_IMAGES, /** * Continue with viewing images. */ VIEW_IMAGES } }