/** * Copyright (c) 2012 Todoroo Inc * * See the file "LICENSE" for the full license governing this code. */ package com.todoroo.astrid.activity; import android.app.Activity; import android.app.Dialog; import android.content.ContentValues; import android.content.DialogInterface; import android.content.Intent; import android.net.Uri; import android.os.Bundle; import android.os.Handler; import android.support.v4.view.ViewPager; import android.text.TextUtils; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.View.MeasureSpec; import android.view.ViewGroup; import android.view.ViewGroup.LayoutParams; import android.view.ViewParent; import android.view.WindowManager; import android.widget.EditText; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.ScrollView; import android.widget.Toast; import com.todoroo.andlib.utility.AndroidUtilities; import com.todoroo.andlib.utility.DateUtilities; import com.todoroo.astrid.actfm.ActFmCameraModule; import com.todoroo.astrid.actfm.ActFmCameraModule.CameraResultCallback; import com.todoroo.astrid.alarms.AlarmService; import com.todoroo.astrid.api.PermaSql; import com.todoroo.astrid.dao.MetadataDao; import com.todoroo.astrid.dao.TagDataDao; import com.todoroo.astrid.dao.TaskAttachmentDao; import com.todoroo.astrid.dao.UserActivityDao; import com.todoroo.astrid.data.RemoteModel; import com.todoroo.astrid.data.Task; import com.todoroo.astrid.data.TaskAttachment; import com.todoroo.astrid.files.AACRecordingActivity; import com.todoroo.astrid.files.FileExplore; import com.todoroo.astrid.files.FilesControlSet; import com.todoroo.astrid.gcal.GCalControlSet; import com.todoroo.astrid.gcal.GCalHelper; import com.todoroo.astrid.helper.TaskEditControlSet; import com.todoroo.astrid.notes.EditNoteActivity; import com.todoroo.astrid.repeats.RepeatControlSet; import com.todoroo.astrid.service.TaskDeleter; import com.todoroo.astrid.service.TaskService; import com.todoroo.astrid.tags.TagService; import com.todoroo.astrid.tags.TagsControlSet; import com.todoroo.astrid.timers.TimerActionControlSet; import com.todoroo.astrid.timers.TimerControlSet; import com.todoroo.astrid.timers.TimerPlugin; import com.todoroo.astrid.ui.CheckableImageView; import com.todoroo.astrid.ui.DescriptionControlSet; import com.todoroo.astrid.ui.EditTitleControlSet; import com.todoroo.astrid.ui.HideUntilControlSet; import com.todoroo.astrid.ui.ImportanceControlSet; import com.todoroo.astrid.ui.PopupControlSet; import com.todoroo.astrid.ui.ReminderControlSet; import com.todoroo.astrid.utility.Flags; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.tasks.R; import org.tasks.activities.LocationPickerActivity; import org.tasks.activities.TimePickerActivity; import org.tasks.dialogs.DialogBuilder; import org.tasks.injection.InjectingFragment; import org.tasks.location.Geofence; import org.tasks.location.GeofenceService; import org.tasks.notifications.NotificationManager; import org.tasks.preferences.ActivityPreferences; import org.tasks.preferences.DeviceInfo; import org.tasks.ui.DeadlineControlSet; import org.tasks.ui.MenuColorizer; import java.io.File; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import javax.inject.Inject; import butterknife.Bind; import butterknife.ButterKnife; import static com.todoroo.andlib.utility.AndroidUtilities.preGingerbreadMR1; import static org.tasks.files.FileHelper.getPathFromUri; /** * This activity is responsible for creating new tasks and editing existing * ones. It saves a task when it is paused (screen rotated, back button pressed) * as long as the task has a title. * * @author timsu * */ public final class TaskEditFragment extends InjectingFragment implements ViewPager.OnPageChangeListener, EditNoteActivity.UpdatesChangedListener { private static final Logger log = LoggerFactory.getLogger(TaskEditFragment.class); public static final String TAG_TASKEDIT_FRAGMENT = "taskedit_fragment"; //$NON-NLS-1$ // --- bundle tokens /** * Task ID */ public static final String TOKEN_ID = "id"; //$NON-NLS-1$ public static final String TOKEN_UUID = "uuid"; /** * Content Values to set */ public static final String TOKEN_VALUES = "v"; //$NON-NLS-1$ public static final String TOKEN_OPEN_CONTROL = "open_control"; //$NON-NLS-1$ /** * Task in progress (during orientation change) */ private static final String TASK_IN_PROGRESS = "task_in_progress"; //$NON-NLS-1$ /** * Task remote id (during orientation change) */ private static final String TASK_UUID = "task_uuid"; //$NON-NLS-1$ /** * Token for saving a bitmap in the intent before it has been added with a comment */ public static final String TOKEN_PICTURE_IN_PROGRESS = "picture_in_progress"; //$NON-NLS-1$ // --- request codes public static final int REQUEST_CODE_RECORD = 30; public static final int REQUEST_CODE_ATTACH_FILE = 40; // --- result codes public static final String OVERRIDE_FINISH_ANIM = "finishAnim"; //$NON-NLS-1$ public static final String TOKEN_TAGS_CHANGED = "tags_changed"; //$NON-NLS-1$ // --- services public static final int TAB_VIEW_UPDATES = 0; @Inject TaskService taskService; @Inject TaskAttachmentDao taskAttachmentDao; @Inject TagService tagService; @Inject MetadataDao metadataDao; @Inject UserActivityDao userActivityDao; @Inject TaskDeleter taskDeleter; @Inject NotificationManager notificationManager; @Inject AlarmService alarmService; @Inject GCalHelper gcalHelper; @Inject ActivityPreferences preferences; @Inject TagDataDao tagDataDao; @Inject ActFmCameraModule actFmCameraModule; @Inject GeofenceService geofenceService; @Inject DeviceInfo deviceInfo; @Inject DialogBuilder dialogBuilder; // --- UI components private final HashMap controlSetMap = new HashMap<>(); private FilesControlSet filesControlSet; private TimerActionControlSet timerAction; private EditNoteActivity editNotes; private HideUntilControlSet hideUntilControls; private ReminderControlSet reminderControlSet; private GCalControlSet gcalControl; @Bind(R.id.title) EditText title; @Bind(R.id.pager) ViewPager mPager; @Bind(R.id.updatesFooter) View commentsBar; @Bind(R.id.completeBox) CheckableImageView checkbox; @Bind(R.id.timer_container) LinearLayout timerShortcut; @Bind(R.id.basic_controls) LinearLayout basicControls; @Bind(R.id.edit_scroll) ScrollView scrollView; @Bind(R.id.commentField) EditText commentField; private final List controls = Collections.synchronizedList(new ArrayList()); // --- other instance variables /** true if editing started with a new task */ private boolean isNewTask = false; /** task model */ Task model = null; /** whether task should be saved when this activity exits */ private boolean shouldSaveState = true; private boolean overrideFinishAnim; private String uuid = RemoteModel.NO_UUID; private boolean showEditComments; private boolean showTimerShortcut; /* * ====================================================================== * ======================================================= initialization * ====================================================================== */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // if we were editing a task already, restore it if (savedInstanceState != null && savedInstanceState.containsKey(TASK_IN_PROGRESS)) { Task task = savedInstanceState.getParcelable(TASK_IN_PROGRESS); if (task != null) { model = task; } if (savedInstanceState.containsKey(TASK_UUID)) { uuid = savedInstanceState.getString(TASK_UUID); } } showEditComments = preferences.getBoolean(R.string.p_show_task_edit_comments, true); showTimerShortcut = preferences.getBoolean(R.string.p_show_timer_shortcut, false); getActivity().setResult(Activity.RESULT_OK); } /* * ====================================================================== * ==================================================== UI initialization * ====================================================================== */ @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.task_edit_activity, container, false); ButterKnife.bind(this, view); return view; } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); // We have a menu item to show in action bar. setHasOptionsMenu(true); AstridActivity activity = (AstridActivity) getActivity(); setUpUIComponents(); overrideFinishAnim = false; if (activity != null) { if (activity.getIntent() != null) { overrideFinishAnim = activity.getIntent().getBooleanExtra( OVERRIDE_FINISH_ANIM, true); } } } private void instantiateEditNotes() { if (showEditComments) { long idParam = getActivity().getIntent().getLongExtra(TOKEN_ID, -1L); editNotes = new EditNoteActivity(actFmCameraModule, preferences, metadataDao, userActivityDao, taskService, this, getView(), idParam); editNotes.setLayoutParams(new FrameLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT)); editNotes.addListener(this); } } private void loadMoreContainer() { long idParam = getActivity().getIntent().getLongExtra(TOKEN_ID, -1L); int tabStyle = TaskEditViewPager.TAB_SHOW_ACTIVITY; if (!showEditComments) { tabStyle &= ~TaskEditViewPager.TAB_SHOW_ACTIVITY; } if (editNotes == null) { instantiateEditNotes(); } else { editNotes.loadViewForTaskID(idParam); } if (timerAction != null && editNotes != null) { timerAction.removeListener(editNotes); timerAction.addListener(editNotes); } if (editNotes != null) { editNotes.addListener(this); } if (tabStyle == 0) { return; } TaskEditViewPager adapter = new TaskEditViewPager(getActivity(), tabStyle); adapter.parent = this; mPager.setAdapter(adapter); setCurrentTab(TAB_VIEW_UPDATES); setPagerHeightForPosition(); Handler handler = new Handler(); handler.postDelayed(new Runnable() { @Override public void run() { updatesChanged(); } }, 500L); } private void setCurrentTab(int position) { mPager.setCurrentItem(position); } /** Initialize UI components */ private void setUpUIComponents() { // populate control set EditTitleControlSet editTitle = new EditTitleControlSet( taskService, getActivity(), title, checkbox); controls.add(editTitle); timerAction = new TimerActionControlSet(notificationManager, taskService, getActivity(), getView()); controls.add(timerAction); TagsControlSet tagsControlSet = new TagsControlSet(metadataDao, tagDataDao, preferences, tagService, getActivity(), dialogBuilder); controls.add(tagsControlSet); controlSetMap.put(getString(R.string.TEA_ctrl_lists_pref), tagsControlSet); RepeatControlSet repeatControls = new RepeatControlSet(preferences, getActivity(), dialogBuilder); controlSetMap.put(getString(R.string.TEA_ctrl_repeat_pref), repeatControls); gcalControl = new GCalControlSet(gcalHelper, preferences, this); controlSetMap.put(getString(R.string.TEA_ctrl_gcal), gcalControl); // The deadline control set contains the repeat controls and the // calendar controls. // NOTE: we add the gcalControl AFTER the // deadline control, because // otherwise the correct date may not be written to the calendar event. // Order matters! DeadlineControlSet deadlineControl = new DeadlineControlSet(getActivity(), preferences); controlSetMap.put(getString(R.string.TEA_ctrl_when_pref), deadlineControl); controls.add(repeatControls); repeatControls.addListener(editTitle); controls.add(deadlineControl); controls.add(gcalControl); ImportanceControlSet importanceControl = new ImportanceControlSet(getActivity()); controls.add(importanceControl); importanceControl.addListener(editTitle); controlSetMap.put(getString(R.string.TEA_ctrl_importance_pref), importanceControl); DescriptionControlSet notesControlSet = new DescriptionControlSet(getActivity()); controls.add(notesControlSet); controlSetMap.put(getString(R.string.TEA_ctrl_notes_pref), notesControlSet); reminderControlSet = new ReminderControlSet(alarmService, geofenceService, this, preferences); controls.add(reminderControlSet); controlSetMap.put(getString(R.string.TEA_ctrl_reminders_pref), reminderControlSet); hideUntilControls = new HideUntilControlSet(this); controls.add(hideUntilControls); controlSetMap.put(getString(R.string.TEA_ctrl_hide_until_pref), hideUntilControls); // TODO: Fix the fact that hideUntil doesn't update accordingly with date changes when lazy loaded. Until then, don't lazy load. hideUntilControls.getView(); TimerControlSet timerControl = new TimerControlSet(preferences, getActivity(), dialogBuilder); timerAction.addListener(timerControl); controls.add(timerControl); controlSetMap.put(getString(R.string.TEA_ctrl_timer_pref), timerControl); filesControlSet = new FilesControlSet(preferences, taskAttachmentDao, this, deviceInfo, actFmCameraModule); controls.add(filesControlSet); controlSetMap.put(getString(R.string.TEA_ctrl_files_pref), filesControlSet); loadEditPageOrder(); if (!showEditComments) { commentsBar.setVisibility(View.GONE); } if (!showTimerShortcut) { timerShortcut.setVisibility(View.GONE); } // Load task data in background new TaskEditBackgroundLoader().start(); } private void loadEditPageOrder() { ArrayList controlOrder = BeastModePreferences.constructOrderedControlList(preferences, getActivity()); String[] itemOrder = controlOrder.toArray(new String[controlOrder.size()]); String hideAlwaysTrigger = getString(R.string.TEA_ctrl_hide_section_pref); Class openControl = (Class) getActivity().getIntent().getSerializableExtra(TOKEN_OPEN_CONTROL); for (String item : itemOrder) { if (item.equals(hideAlwaysTrigger)) { break; // As soon as we hit the hide section, we're done } else { View controlSet = null; TaskEditControlSet curr = controlSetMap.get(item); if (curr != null) { controlSet = curr.getView(); } if (controlSet != null) { ImageView icon = (ImageView) controlSet.findViewById(R.id.icon); if (icon != null) { icon.setImageResource(curr.getIcon()); } basicControls.addView(controlSet); } if (curr != null && curr.getClass().equals(openControl) && curr instanceof PopupControlSet) { curr.getView().performClick(); } } } getActivity().getIntent().removeExtra(TOKEN_OPEN_CONTROL); } /** * Initialize task edit page in the background * * @author Tim Su * */ private class TaskEditBackgroundLoader extends Thread { @Override public void run() { AndroidUtilities.sleepDeep(500L); Activity activity = getActivity(); if (activity == null) { return; } activity.runOnUiThread(new Runnable() { @Override public void run() { if (getActivity() != null) { // todo: is this necessary? loadMoreContainer(); } } }); } } /* * ====================================================================== * =============================================== model reading / saving * ====================================================================== */ /** * Loads action item from the given intent */ private void loadItem(Intent intent) { if (model != null) { // came from bundle setIsNewTask(model.getTitle().length() == 0); return; } long idParam = intent.getLongExtra(TOKEN_ID, -1L); if (idParam > -1L) { model = taskService.fetchById(idParam, Task.PROPERTIES); if (model != null && model.containsNonNullValue(Task.UUID)) { uuid = model.getUUID(); } } // not found by id or was never passed an id if (model == null) { String valuesAsString = intent.getStringExtra(TOKEN_VALUES); ContentValues values = null; try { if (valuesAsString != null) { valuesAsString = PermaSql.replacePlaceholders(valuesAsString); values = AndroidUtilities.contentValuesFromSerializedString(valuesAsString); } } catch (Exception e) { // oops, can't serialize log.error(e.getMessage(), e); } model = taskService.createWithValues(values, null); getActivity().getIntent().putExtra(TOKEN_ID, model.getId()); } if (model.getTitle().length() == 0) { // set deletion date until task gets a title model.setDeletionDate(DateUtilities.now()); } setIsNewTask(model.getTitle().length() == 0); if (model == null) { log.error("task-edit-no-task", new NullPointerException("model")); getActivity().onBackPressed(); return; } notificationManager.cancel(model.getId()); } private void setIsNewTask(boolean isNewTask) { this.isNewTask = isNewTask; } /** Convenience method to populate fields after setting model to null */ public void repopulateFromScratch(Intent intent) { model = null; uuid = RemoteModel.NO_UUID; populateFields(intent); loadMoreContainer(); } /** Populate UI component values from the model */ public void populateFields(Intent intent) { loadItem(intent); synchronized (controls) { for (TaskEditControlSet controlSet : controls) { controlSet.readFromTask(model); } } } /** Save task model from values in UI components */ public void save(boolean onPause) { if (title == null) { return; } if (title.getText().length() > 0) { model.setDeletionDate(0L); } if (title.getText().length() == 0) { return; } synchronized (controls) { for (TaskEditControlSet controlSet : controls) { if (controlSet instanceof PopupControlSet) { // Save open control set PopupControlSet popup = (PopupControlSet) controlSet; Dialog d = popup.getDialog(); if (d != null && d.isShowing()) { getActivity().getIntent().putExtra(TOKEN_OPEN_CONTROL, popup.getClass()); } } controlSet.writeToModel(model); } } boolean tagsChanged = Flags.check(Flags.TAGS_CHANGED); model.putTransitory(TaskService.TRANS_EDIT_SAVE, true); // TODO: not used? taskService.save(model); if (!onPause) { boolean taskEditActivity = (getActivity() instanceof TaskEditActivity); if (taskEditActivity) { Intent data = new Intent(); data.putExtra(TOKEN_TAGS_CHANGED, tagsChanged); data.putExtra(TOKEN_ID, model.getId()); data.putExtra(TOKEN_UUID, model.getUuid()); getActivity().setResult(Activity.RESULT_OK, data); } else { // Notify task list fragment in multi-column case // since the activity isn't actually finishing TaskListActivity tla = (TaskListActivity) getActivity(); if (tagsChanged) { tla.tagsChanged(); } tla.refreshTaskList(); if (isNewTask) { tla.getTaskListFragment().onTaskCreated(model.getId(), model.getUuid()); } } removeExtrasFromIntent(getActivity().getIntent()); shouldSaveState = false; getActivity().onBackPressed(); } } public boolean onKeyDown(int keyCode) { if (keyCode == KeyEvent.KEYCODE_BACK) { if(title.getText().length() == 0) { discardButtonClick(); } else { saveButtonClick(); } return true; } return false; } @Override public void onDetach() { super.onDetach(); // abandon editing and delete the newly created task if // no title was entered Activity activity = getActivity(); if (overrideFinishAnim) { AndroidUtilities.callOverridePendingTransition(activity, R.anim.slide_right_in, R.anim.slide_right_out); } if (activity instanceof TaskListActivity) { if (title.getText().length() == 0 && isNewTask && model != null && model.isSaved()) { taskDeleter.delete(model); } } else if (activity instanceof TaskEditActivity) { if (title.getText().length() == 0 && isNewTask && model != null && model.isSaved()) { taskDeleter.delete(model); } } } /** * Helper to remove task edit specific info from activity intent */ public static void removeExtrasFromIntent(Intent intent) { if (intent != null) { intent.removeExtra(TaskListActivity.OPEN_TASK); intent.removeExtra(TOKEN_PICTURE_IN_PROGRESS); } } /* * ====================================================================== * ======================================================= event handlers * ====================================================================== */ protected void saveButtonClick() { save(false); } protected void discardButtonClick() { shouldSaveState = false; // abandon editing in this case if (title.getText().toString().trim().length() == 0 || TextUtils.isEmpty(model.getTitle())) { if (isNewTask) { TimerPlugin.updateTimer(notificationManager, taskService, getActivity(), model, false); taskDeleter.delete(model); if (getActivity() instanceof TaskListActivity) { TaskListActivity tla = (TaskListActivity) getActivity(); tla.refreshTaskList(); } } } removeExtrasFromIntent(getActivity().getIntent()); getActivity().onBackPressed(); } protected void deleteButtonClick() { dialogBuilder.newMessageDialog(R.string.DLG_delete_this_task_question) .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { TimerPlugin.updateTimer(notificationManager, taskService, getActivity(), model, false); taskDeleter.delete(model); shouldSaveState = false; Activity a = getActivity(); if (a instanceof TaskEditActivity) { getActivity().setResult(Activity.RESULT_OK); getActivity().onBackPressed(); } else if (a instanceof TaskListActivity) { discardButtonClick(); TaskListFragment tlf = ((TaskListActivity) a).getTaskListFragment(); if (tlf != null) { tlf.refresh(); } } } }) .setNegativeButton(android.R.string.cancel, null) .show(); } private void startRecordingAudio() { Intent recordAudio = new Intent(getActivity(), AACRecordingActivity.class); startActivityForResult(recordAudio, REQUEST_CODE_RECORD); } private void attachImage(Uri uri) { try { String path = getPathFromUri(getActivity(), uri); File file = new File(path); String extension = path.substring(path.lastIndexOf('.') + 1); filesControlSet.createNewFileAttachment(path, file.getName(), TaskAttachment.FILE_TYPE_IMAGE + extension); } catch (Exception e) { log.error(e.getMessage(), e); Toast.makeText(getActivity(), R.string.file_err_copy, Toast.LENGTH_LONG).show(); } } @Override public boolean onOptionsItemSelected(MenuItem item) { hideKeyboard(); switch (item.getItemId()) { case R.id.menu_save: saveButtonClick(); return true; case R.id.menu_discard: discardButtonClick(); return true; case R.id.menu_record_note: startRecordingAudio(); return true; case R.id.menu_delete: deleteButtonClick(); return true; case android.R.id.home: if (title.getText().toString().trim().length() == 0) { discardButtonClick(); } else { saveButtonClick(); } return true; } return super.onOptionsItemSelected(item); } @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { menu.clear(); inflater.inflate(R.menu.task_edit_fragment, menu); MenuColorizer.colorMenu(getActivity(), menu, getResources().getColor(android.R.color.white)); if (preGingerbreadMR1()) { // media recorder aac support requires api level 10 // approximately 1% of current installs are using api level 7-9 menu.findItem(R.id.menu_record_note).setVisible(false); } if (preferences.useTabletLayout()) { menu.findItem(R.id.menu_save).setVisible(true); } } @Override public void onPause() { super.onPause(); if (shouldSaveState) { save(true); } } @Override public void onStart() { super.onStart(); populateFields(getActivity().getIntent()); if (isNewTask) { title.requestFocus(); title.setCursorVisible(true); getActivity().getWindow() .setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE); } } @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { if (editNotes == null) { instantiateEditNotes(); } if (requestCode == HideUntilControlSet.REQUEST_HIDE_UNTIL && resultCode == Activity.RESULT_OK) { long timestamp = data.getLongExtra(TimePickerActivity.EXTRA_TIMESTAMP, 0L); if (timestamp > 0) { hideUntilControls.setCustomDate(timestamp); } else { log.error("Invalid timestamp"); } return; } else if (requestCode == ReminderControlSet.REQUEST_NEW_ALARM && resultCode == Activity.RESULT_OK) { long timestamp = data.getLongExtra(TimePickerActivity.EXTRA_TIMESTAMP, 0L); if (timestamp > 0) { reminderControlSet.addAlarmRow(timestamp); } else { log.error("Invalid timestamp"); } } else if (requestCode == ReminderControlSet.REQUEST_LOCATION_REMINDER && resultCode == Activity.RESULT_OK) { Geofence geofence = (Geofence) data.getSerializableExtra(LocationPickerActivity.EXTRA_GEOFENCE); if (geofence != null) { reminderControlSet.addGeolocationReminder(geofence); } else { log.error("Invalid geofence"); } } else if (editNotes != null && editNotes.activityResult(requestCode, resultCode, data)) { return; } else if (requestCode == REQUEST_CODE_RECORD && resultCode == Activity.RESULT_OK) { String recordedAudioPath = data.getStringExtra(AACRecordingActivity.RESULT_OUTFILE); String recordedAudioName = data.getStringExtra(AACRecordingActivity.RESULT_FILENAME); filesControlSet.createNewFileAttachment(recordedAudioPath, recordedAudioName, TaskAttachment.FILE_TYPE_AUDIO + "m4a"); //$NON-NLS-1$ } else if (requestCode == REQUEST_CODE_ATTACH_FILE && resultCode == Activity.RESULT_OK) { filesControlSet.attachFile(data.getStringExtra(FileExplore.RESULT_FILE_SELECTED)); } actFmCameraModule.activityResult(requestCode, resultCode, data, new CameraResultCallback() { @Override public void handleCameraResult(Uri uri) { attachImage(uri); } }); super.onActivityResult(requestCode, resultCode, data); } @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); // stick our task into the outState outState.putParcelable(TASK_IN_PROGRESS, model); outState.putString(TASK_UUID, uuid); } /* * ====================================================================== * ========================================== UI component helper classes * ====================================================================== */ public View getPageView() { return editNotes; } private void setPagerHeightForPosition() { int height = 0; View view = editNotes; if (mPager == null) { return; } int desiredWidth = MeasureSpec.makeMeasureSpec(view.getWidth(), MeasureSpec.AT_MOST); view.measure(desiredWidth, MeasureSpec.UNSPECIFIED); height = Math.max(view.getMeasuredHeight(), height); LayoutParams pagerParams = mPager.getLayoutParams(); if (height > 0 && height != pagerParams.height) { pagerParams.height = height; mPager.setLayoutParams(pagerParams); } } // Tab Page listener when page/tab changes @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { } @Override public void onPageSelected(final int position) { setPagerHeightForPosition(); } @Override public void onPageScrollStateChanged(int state) { } // EditNoteActivity Listener when there are new updates/comments @Override public void updatesChanged() { if (mPager != null && mPager.getCurrentItem() == TAB_VIEW_UPDATES) { setPagerHeightForPosition(); } } // EditNoteActivity Lisener when there are new updates/comments @Override public void commentAdded() { setCurrentTab(TAB_VIEW_UPDATES); setPagerHeightForPosition(); scrollToView(editNotes); } // Scroll to view in edit task public void scrollToView(View v) { View child = v; int top = v.getTop(); while (!child.equals(scrollView) ) { top += child.getTop(); ViewParent parentView = child.getParent(); if (parentView != null && View.class.isInstance(parentView)) { child = (View) parentView; } else { break; } } scrollView.smoothScrollTo(0, top); } private void hideKeyboard() { AndroidUtilities.hideSoftInputForViews(getActivity(), title, commentField); title.setCursorVisible(false); commentField.setCursorVisible(false); } }