• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2008 Esmertec AG.
3  * Copyright (C) 2008 The Android Open Source Project
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 package com.android.mms.ui;
19 
20 import android.app.Activity;
21 import android.app.AlertDialog;
22 import android.content.ContentUris;
23 import android.content.Context;
24 import android.content.DialogInterface;
25 import android.content.Intent;
26 import android.content.res.Resources;
27 import android.media.RingtoneManager;
28 import android.net.Uri;
29 import android.os.Bundle;
30 import android.os.Handler;
31 import android.provider.Settings;
32 import android.text.InputFilter;
33 import android.text.InputFilter.LengthFilter;
34 import android.text.TextUtils;
35 import android.util.Log;
36 import android.view.Menu;
37 import android.view.MenuItem;
38 import android.view.SubMenu;
39 import android.view.View;
40 import android.view.View.OnClickListener;
41 import android.widget.Button;
42 import android.widget.EditText;
43 import android.widget.ImageButton;
44 import android.widget.Toast;
45 
46 import com.android.mms.ExceedMessageSizeException;
47 import com.android.mms.LogTag;
48 import com.android.mms.MmsApp;
49 import com.android.mms.MmsConfig;
50 import com.android.mms.R;
51 import com.android.mms.ResolutionException;
52 import com.android.mms.TempFileProvider;
53 import com.android.mms.UnsupportContentTypeException;
54 import com.android.mms.model.IModelChangedObserver;
55 import com.android.mms.model.LayoutModel;
56 import com.android.mms.model.Model;
57 import com.android.mms.model.SlideModel;
58 import com.android.mms.model.SlideshowModel;
59 import com.android.mms.ui.BasicSlideEditorView.OnTextChangedListener;
60 import com.android.mms.ui.MessageUtils.ResizeImageResultCallback;
61 import com.google.android.mms.ContentType;
62 import com.google.android.mms.MmsException;
63 import com.google.android.mms.pdu.PduBody;
64 import com.google.android.mms.pdu.PduPart;
65 import com.google.android.mms.pdu.PduPersister;
66 
67 /**
68  * This activity allows user to edit the contents of a slide.
69  */
70 public class SlideEditorActivity extends Activity {
71     private static final String TAG = LogTag.TAG;
72     private static final boolean DEBUG = false;
73     private static final boolean LOCAL_LOGV = false;
74 
75     // Key for extra data.
76     public static final String SLIDE_INDEX = "slide_index";
77 
78     // Menu ids.
79     private final static int MENU_REMOVE_TEXT       = 0;
80     private final static int MENU_ADD_PICTURE       = 1;
81     private final static int MENU_TAKE_PICTURE      = 2;
82     private final static int MENU_DEL_PICTURE       = 3;
83     private final static int MENU_ADD_AUDIO         = 4;
84     private final static int MENU_DEL_AUDIO         = 5;
85     private final static int MENU_ADD_VIDEO         = 6;
86     private final static int MENU_ADD_SLIDE         = 7;
87     private final static int MENU_DEL_VIDEO         = 8;
88     private final static int MENU_LAYOUT            = 9;
89     private final static int MENU_DURATION          = 10;
90     private final static int MENU_PREVIEW_SLIDESHOW = 11;
91     private final static int MENU_RECORD_SOUND      = 12;
92     private final static int MENU_SUB_AUDIO         = 13;
93     private final static int MENU_TAKE_VIDEO        = 14;
94 
95     // Request code.
96     private final static int REQUEST_CODE_EDIT_TEXT          = 0;
97     private final static int REQUEST_CODE_CHANGE_PICTURE     = 1;
98     private final static int REQUEST_CODE_TAKE_PICTURE       = 2;
99     private final static int REQUEST_CODE_CHANGE_MUSIC       = 3;
100     private final static int REQUEST_CODE_RECORD_SOUND       = 4;
101     private final static int REQUEST_CODE_CHANGE_VIDEO       = 5;
102     private final static int REQUEST_CODE_CHANGE_DURATION    = 6;
103     private final static int REQUEST_CODE_TAKE_VIDEO         = 7;
104 
105     // number of items in the duration selector dialog that directly map from
106     // item index to duration in seconds (duration = index + 1)
107     private final static int NUM_DIRECT_DURATIONS = 10;
108 
109     private ImageButton mNextSlide;
110     private ImageButton mPreSlide;
111     private Button mPreview;
112     private Button mReplaceImage;
113     private Button mRemoveSlide;
114     private EditText mTextEditor;
115     private Button mDone;
116     private BasicSlideEditorView mSlideView;
117 
118     private SlideshowModel mSlideshowModel;
119     private SlideshowEditor mSlideshowEditor;
120     private SlideshowPresenter mPresenter;
121     private boolean mDirty;
122 
123     private int mPosition;
124     private Uri mUri;
125 
126     private final static String MESSAGE_URI = "message_uri";
127     private AsyncDialog mAsyncDialog;   // Used for background tasks.
128 
129     @Override
onCreate(Bundle savedInstanceState)130     protected void onCreate(Bundle savedInstanceState) {
131         super.onCreate(savedInstanceState);
132         setContentView(R.layout.edit_slide_activity);
133 
134         mSlideView = (BasicSlideEditorView) findViewById(R.id.slide_editor_view);
135         mSlideView.setOnTextChangedListener(mOnTextChangedListener);
136 
137         mPreSlide = (ImageButton) findViewById(R.id.pre_slide_button);
138         mPreSlide.setOnClickListener(mOnNavigateBackward);
139 
140         mNextSlide = (ImageButton) findViewById(R.id.next_slide_button);
141         mNextSlide.setOnClickListener(mOnNavigateForward);
142 
143         mPreview = (Button) findViewById(R.id.preview_button);
144         mPreview.setOnClickListener(mOnPreview);
145 
146         mReplaceImage = (Button) findViewById(R.id.replace_image_button);
147         mReplaceImage.setOnClickListener(mOnReplaceImage);
148 
149         mRemoveSlide = (Button) findViewById(R.id.remove_slide_button);
150         mRemoveSlide.setOnClickListener(mOnRemoveSlide);
151 
152         mTextEditor = (EditText) findViewById(R.id.text_message);
153         mTextEditor.setFilters(new InputFilter[] {
154                 new LengthFilter(MmsConfig.getMaxTextLimit())});
155 
156         mDone = (Button) findViewById(R.id.done_button);
157         mDone.setOnClickListener(mDoneClickListener);
158 
159         initActivityState(savedInstanceState, getIntent());
160 
161         try {
162             mSlideshowModel = SlideshowModel.createFromMessageUri(this, mUri);
163             // Confirm that we have at least 1 slide to display
164             if (mSlideshowModel.size() == 0) {
165                 Log.e(TAG, "Loaded slideshow is empty; can't edit nothingness, exiting.");
166                 finish();
167                 return;
168             }
169             // Register an observer to watch whether the data model is changed.
170             mSlideshowModel.registerModelChangedObserver(mModelChangedObserver);
171             mSlideshowEditor = new SlideshowEditor(this, mSlideshowModel);
172             mPresenter = (SlideshowPresenter) PresenterFactory.getPresenter(
173                     "SlideshowPresenter", this, mSlideView, mSlideshowModel);
174 
175             // Sanitize mPosition
176             if (mPosition >= mSlideshowModel.size()) {
177                 mPosition = Math.max(0, mSlideshowModel.size() - 1);
178             } else if (mPosition < 0) {
179                 mPosition = 0;
180             }
181 
182             showCurrentSlide();
183         } catch (MmsException e) {
184             Log.e(TAG, "Create SlideshowModel failed!", e);
185             finish();
186             return;
187         }
188     }
189 
initActivityState(Bundle savedInstanceState, Intent intent)190     private void initActivityState(Bundle savedInstanceState, Intent intent) {
191         if (savedInstanceState != null) {
192             mUri = (Uri) savedInstanceState.getParcelable(MESSAGE_URI);
193             mPosition = savedInstanceState.getInt(SLIDE_INDEX, 0);
194         } else {
195             mUri = intent.getData();
196             mPosition = intent.getIntExtra(SLIDE_INDEX, 0);
197         }
198     }
199 
200     @Override
onSaveInstanceState(Bundle outState)201     protected void onSaveInstanceState(Bundle outState) {
202         super.onSaveInstanceState(outState);
203 
204         outState.putInt(SLIDE_INDEX, mPosition);
205         outState.putParcelable(MESSAGE_URI, mUri);
206     }
207 
208     @Override
onPause()209     protected void onPause()  {
210         super.onPause();
211 
212         // remove any callback to display a progress spinner
213         if (mAsyncDialog != null) {
214             mAsyncDialog.clearPendingProgressDialog();
215         }
216 
217         synchronized (this) {
218             if (mDirty) {
219                 try {
220                     PduBody pb = mSlideshowModel.toPduBody();
221                     PduPersister.getPduPersister(this).updateParts(mUri, pb, null);
222                     mSlideshowModel.sync(pb);
223                 }  catch (MmsException e) {
224                     Log.e(TAG, "Cannot update the message: " + mUri, e);
225                 }
226             }
227         }
228     }
229 
230     @Override
onDestroy()231     protected void onDestroy() {
232         super.onDestroy();
233 
234         if (mSlideshowModel != null) {
235             mSlideshowModel.unregisterModelChangedObserver(
236                     mModelChangedObserver);
237         }
238     }
239 
240     private final IModelChangedObserver mModelChangedObserver =
241         new IModelChangedObserver() {
242             public void onModelChanged(Model model, boolean dataChanged) {
243                 synchronized (SlideEditorActivity.this) {
244                     mDirty = true;
245                 }
246                 setResult(RESULT_OK);
247             }
248         };
249 
250     private final OnClickListener mOnRemoveSlide = new OnClickListener() {
251         public void onClick(View v) {
252             // Validate mPosition
253             if (mPosition >= 0 && mPosition < mSlideshowModel.size()) {
254                 mSlideshowEditor.removeSlide(mPosition);
255                 int size = mSlideshowModel.size();
256                 if (size > 0) {
257                     if (mPosition >= size) {
258                         mPosition--;
259                     }
260                     showCurrentSlide();
261                 } else {
262                     finish();
263                     return;
264                 }
265             }
266         }
267     };
268 
269     private final OnTextChangedListener mOnTextChangedListener = new OnTextChangedListener() {
270         public void onTextChanged(String s) {
271             if (!isFinishing()) {
272                 mSlideshowEditor.changeText(mPosition, s);
273             }
274         }
275     };
276 
277     private final OnClickListener mOnPreview = new OnClickListener() {
278         public void onClick(View v) {
279             previewSlideshow();
280         }
281     };
282 
283     private final OnClickListener mOnReplaceImage = new OnClickListener() {
284         public void onClick(View v) {
285             SlideModel slide = mSlideshowModel.get(mPosition);
286             if (slide != null && slide.hasVideo()) {
287                 Toast.makeText(SlideEditorActivity.this, R.string.cannot_add_picture_and_video,
288                         Toast.LENGTH_SHORT).show();
289                 return;
290             }
291             Intent intent = new Intent(Intent.ACTION_GET_CONTENT, null);
292             intent.setType(ContentType.IMAGE_UNSPECIFIED);
293             startActivityForResult(intent, REQUEST_CODE_CHANGE_PICTURE);
294         }
295     };
296 
297     private final OnClickListener mOnNavigateBackward = new OnClickListener() {
298         public void onClick(View v) {
299             if (mPosition > 0) {
300                 mPosition --;
301                 showCurrentSlide();
302             }
303         }
304     };
305 
306     private final OnClickListener mOnNavigateForward = new OnClickListener() {
307         public void onClick(View v) {
308             if (mPosition < mSlideshowModel.size() - 1) {
309                 mPosition ++;
310                 showCurrentSlide();
311             }
312         }
313     };
314 
315     private final OnClickListener mDoneClickListener = new OnClickListener() {
316         public void onClick(View v) {
317             Intent data = new Intent();
318             data.putExtra("done", true);
319             setResult(RESULT_OK, data);
320             finish();
321         }
322     };
323 
getAsyncDialog()324     private AsyncDialog getAsyncDialog() {
325         if (mAsyncDialog == null) {
326             mAsyncDialog = new AsyncDialog(this);
327         }
328         return mAsyncDialog;
329     }
330 
previewSlideshow()331     private void previewSlideshow() {
332         MessageUtils.viewMmsMessageAttachment(SlideEditorActivity.this, mUri, mSlideshowModel,
333                 getAsyncDialog());
334     }
335 
updateTitle()336     private void updateTitle() {
337         setTitle(getString(R.string.slide_show_part, (mPosition + 1), mSlideshowModel.size()));
338     }
339 
340     @Override
onPrepareOptionsMenu(Menu menu)341     public boolean onPrepareOptionsMenu(Menu menu) {
342         if (isFinishing()) {
343             return false;
344         }
345         menu.clear();
346 
347         SlideModel slide = mSlideshowModel.get(mPosition);
348 
349         if (slide == null) {
350             return false;
351         }
352 
353         // Preview slideshow.
354         menu.add(0, MENU_PREVIEW_SLIDESHOW, 0, R.string.preview_slideshow).setIcon(
355                 com.android.internal.R.drawable.ic_menu_play_clip);
356 
357         // Text
358         if (slide.hasText() && !TextUtils.isEmpty(slide.getText().getText())) {
359             //"Change text" if text is set.
360             menu.add(0, MENU_REMOVE_TEXT, 0, R.string.remove_text).setIcon(
361                     R.drawable.ic_menu_remove_text);
362         }
363 
364         // Picture
365         if (slide.hasImage()) {
366             menu.add(0, MENU_DEL_PICTURE, 0, R.string.remove_picture).setIcon(
367                     R.drawable.ic_menu_remove_picture);
368         } else if (!slide.hasVideo()) {
369             menu.add(0, MENU_ADD_PICTURE, 0, R.string.add_picture).setIcon(
370                     R.drawable.ic_menu_picture);
371             menu.add(0, MENU_TAKE_PICTURE, 0, R.string.attach_take_photo).setIcon(
372                     R.drawable.ic_menu_picture);
373         }
374 
375         // Music
376         if (slide.hasAudio()) {
377             menu.add(0, MENU_DEL_AUDIO, 0, R.string.remove_music).setIcon(
378                     R.drawable.ic_menu_remove_sound);
379         } else if (!slide.hasVideo()) {
380             if (MmsConfig.getAllowAttachAudio()) {
381                 SubMenu subMenu = menu.addSubMenu(0, MENU_SUB_AUDIO, 0, R.string.add_music)
382                     .setIcon(R.drawable.ic_menu_add_sound);
383                 subMenu.add(0, MENU_ADD_AUDIO, 0, R.string.attach_sound);
384                 subMenu.add(0, MENU_RECORD_SOUND, 0, R.string.attach_record_sound);
385             } else {
386                 menu.add(0, MENU_RECORD_SOUND, 0, R.string.attach_record_sound)
387                     .setIcon(R.drawable.ic_menu_add_sound);
388             }
389         }
390 
391         // Video
392         if (slide.hasVideo()) {
393             menu.add(0, MENU_DEL_VIDEO, 0, R.string.remove_video).setIcon(
394                     R.drawable.ic_menu_remove_video);
395         } else if (!slide.hasAudio() && !slide.hasImage()) {
396             menu.add(0, MENU_ADD_VIDEO, 0, R.string.add_video).setIcon(R.drawable.ic_menu_movie);
397             menu.add(0, MENU_TAKE_VIDEO, 0, R.string.attach_record_video)
398                 .setIcon(R.drawable.ic_menu_movie);
399         }
400 
401         // Add slide
402         menu.add(0, MENU_ADD_SLIDE, 0, R.string.add_slide).setIcon(
403                 R.drawable.ic_menu_add_slide);
404 
405         // Slide duration
406         String duration = getResources().getString(R.string.duration_sec);
407         menu.add(0, MENU_DURATION, 0,
408                 duration.replace("%s", String.valueOf(slide.getDuration() / 1000))).setIcon(
409                         R.drawable.ic_menu_duration);
410 
411         // Slide layout
412         int resId;
413         if (mSlideshowModel.getLayout().getLayoutType() == LayoutModel.LAYOUT_TOP_TEXT) {
414             resId = R.string.layout_top;
415         } else {
416             resId = R.string.layout_bottom;
417         }
418         // FIXME: set correct icon when layout icon is available.
419         menu.add(0, MENU_LAYOUT, 0, resId).setIcon(R.drawable.ic_menu_picture);
420         return true;
421     }
422 
423     @Override
onOptionsItemSelected(MenuItem item)424     public boolean onOptionsItemSelected(MenuItem item) {
425         switch (item.getItemId()) {
426             case MENU_PREVIEW_SLIDESHOW:
427                 previewSlideshow();
428                 break;
429 
430             case MENU_REMOVE_TEXT:
431                 SlideModel slide = mSlideshowModel.get(mPosition);
432                 if (slide != null) {
433                     slide.removeText();
434                 }
435                 break;
436 
437             case MENU_ADD_PICTURE:
438                 Intent intent = new Intent(Intent.ACTION_GET_CONTENT, null);
439                 intent.setType(ContentType.IMAGE_UNSPECIFIED);
440                 startActivityForResult(intent, REQUEST_CODE_CHANGE_PICTURE);
441                 break;
442 
443             case MENU_TAKE_PICTURE:
444                 MessageUtils.capturePicture(this, REQUEST_CODE_TAKE_PICTURE);
445                 break;
446 
447             case MENU_DEL_PICTURE:
448                 mSlideshowEditor.removeImage(mPosition);
449                 setReplaceButtonText(R.string.add_picture);
450                 break;
451 
452             case MENU_ADD_AUDIO:
453                 MessageUtils.selectAudio(this, REQUEST_CODE_CHANGE_MUSIC);
454                 break;
455 
456             case MENU_RECORD_SOUND:
457                 slide = mSlideshowModel.get(mPosition);
458                 int currentSlideSize = slide.getSlideSize();
459                 long sizeLimit = ComposeMessageActivity.computeAttachmentSizeLimit(mSlideshowModel,
460                         currentSlideSize);
461                 MessageUtils.recordSound(this, REQUEST_CODE_RECORD_SOUND, sizeLimit);
462                 break;
463 
464             case MENU_DEL_AUDIO:
465                 mSlideshowEditor.removeAudio(mPosition);
466                 break;
467 
468             case MENU_ADD_VIDEO:
469                 intent = new Intent(Intent.ACTION_GET_CONTENT);
470                 intent.setType(ContentType.VIDEO_UNSPECIFIED);
471                 intent.putExtra(Intent.EXTRA_LOCAL_ONLY, true);
472                 startActivityForResult(intent, REQUEST_CODE_CHANGE_VIDEO);
473                 break;
474 
475             case MENU_TAKE_VIDEO:
476                 slide = mSlideshowModel.get(mPosition);
477                 currentSlideSize = slide.getSlideSize();
478                 sizeLimit = ComposeMessageActivity.computeAttachmentSizeLimit(mSlideshowModel,
479                         currentSlideSize);
480                 if (sizeLimit > 0) {
481                     MessageUtils.recordVideo(this, REQUEST_CODE_TAKE_VIDEO, sizeLimit);
482                 } else {
483                     Toast.makeText(this,
484                             getString(R.string.message_too_big_for_video),
485                             Toast.LENGTH_SHORT).show();
486                 }
487                 break;
488 
489             case MENU_DEL_VIDEO:
490                 mSlideshowEditor.removeVideo(mPosition);
491                 break;
492 
493             case MENU_ADD_SLIDE:
494                 mPosition++;
495                 if ( mSlideshowEditor.addNewSlide(mPosition) ) {
496                     // add successfully
497                     showCurrentSlide();
498                 } else {
499                     // move position back
500                     mPosition--;
501                     Toast.makeText(this, R.string.cannot_add_slide_anymore,
502                             Toast.LENGTH_SHORT).show();
503                 }
504                 break;
505 
506             case MENU_LAYOUT:
507                 showLayoutSelectorDialog();
508                 break;
509 
510             case MENU_DURATION:
511                 showDurationDialog();
512                 break;
513         }
514 
515         return true;
516     }
517 
setReplaceButtonText(int text)518     private void setReplaceButtonText(int text) {
519         mReplaceImage.setText(text);
520     }
521 
showDurationDialog()522     private void showDurationDialog() {
523         AlertDialog.Builder builder = new AlertDialog.Builder(this);
524         builder.setIcon(R.drawable.ic_mms_duration);
525         String title = getResources().getString(R.string.duration_selector_title);
526         builder.setTitle(title + (mPosition + 1) + "/" + mSlideshowModel.size());
527 
528         builder.setItems(R.array.select_dialog_items,
529                 new DialogInterface.OnClickListener() {
530             public void onClick(DialogInterface dialog, int which) {
531                 if ((which >= 0) && (which < NUM_DIRECT_DURATIONS)) {
532                     mSlideshowEditor.changeDuration(
533                             mPosition, (which + 1) * 1000);
534                 } else {
535                     Intent intent = new Intent(SlideEditorActivity.this,
536                             EditSlideDurationActivity.class);
537                     intent.putExtra(EditSlideDurationActivity.SLIDE_INDEX, mPosition);
538                     intent.putExtra(EditSlideDurationActivity.SLIDE_TOTAL,
539                             mSlideshowModel.size());
540                     intent.putExtra(EditSlideDurationActivity.SLIDE_DUR,
541                             mSlideshowModel.get(mPosition).getDuration() / 1000); // in seconds
542                     startActivityForResult(intent, REQUEST_CODE_CHANGE_DURATION);
543                 }
544                 dialog.dismiss();
545             }
546         });
547 
548         builder.show();
549     }
550 
showLayoutSelectorDialog()551     private void showLayoutSelectorDialog() {
552         AlertDialog.Builder builder = new AlertDialog.Builder(this);
553         builder.setIcon(R.drawable.ic_mms_layout);
554 
555         String title = getResources().getString(R.string.layout_selector_title);
556         builder.setTitle(title + (mPosition + 1) + "/" + mSlideshowModel.size());
557 
558         LayoutSelectorAdapter adapter = new LayoutSelectorAdapter(this);
559         builder.setAdapter(adapter, new DialogInterface.OnClickListener() {
560             public void onClick(DialogInterface dialog, int which) {
561                 switch (which) {
562                     case 0: // Top text.
563                         mSlideshowEditor.changeLayout(LayoutModel.LAYOUT_TOP_TEXT);
564                         break;
565                     case 1: // Bottom text.
566                         mSlideshowEditor.changeLayout(LayoutModel.LAYOUT_BOTTOM_TEXT);
567                         break;
568                 }
569                 dialog.dismiss();
570             }
571         });
572 
573         builder.show();
574     }
575 
576     @Override
onActivityResult(int requestCode, int resultCode, Intent data)577     protected void onActivityResult(int requestCode, int resultCode, Intent data) {
578         if (resultCode != RESULT_OK) {
579             return;
580         }
581 
582         switch(requestCode) {
583             case REQUEST_CODE_EDIT_TEXT:
584                 // XXX where does this come from?  Action is probably not the
585                 // right place to have the text...
586                 mSlideshowEditor.changeText(mPosition, data.getAction());
587                 break;
588 
589             case REQUEST_CODE_TAKE_PICTURE:
590                 Uri pictureUri = null;
591                 boolean showError = false;
592                 try {
593                     pictureUri = TempFileProvider.renameScrapFile(".jpg",
594                             Integer.toString(mPosition), this);
595 
596                     if (pictureUri == null) {
597                         showError = true;
598                     } else {
599                         // Remove the old captured picture's thumbnail from the cache
600                         MmsApp.getApplication().getThumbnailManager().removeThumbnail(pictureUri);
601 
602                         mSlideshowEditor.changeImage(mPosition, pictureUri);
603                         setReplaceButtonText(R.string.replace_image);
604                     }
605                 } catch (MmsException e) {
606                     Log.e(TAG, "add image failed", e);
607                     showError = true;
608                 } catch (UnsupportContentTypeException e) {
609                     MessageUtils.showErrorDialog(SlideEditorActivity.this,
610                             getResourcesString(R.string.unsupported_media_format, getPictureString()),
611                             getResourcesString(R.string.select_different_media, getPictureString()));
612                 } catch (ResolutionException e) {
613                     MessageUtils.resizeImageAsync(this, pictureUri, new Handler(),
614                             mResizeImageCallback, false);
615                 } catch (ExceedMessageSizeException e) {
616                     MessageUtils.resizeImageAsync(this, pictureUri, new Handler(),
617                             mResizeImageCallback, false);
618                 }
619                 if (showError) {
620                     notifyUser("add picture failed");
621                     Toast.makeText(SlideEditorActivity.this,
622                             getResourcesString(R.string.failed_to_add_media, getPictureString()),
623                             Toast.LENGTH_SHORT).show();
624                 }
625                 break;
626 
627             case REQUEST_CODE_CHANGE_PICTURE:
628                 try {
629                     mSlideshowEditor.changeImage(mPosition, data.getData());
630                     setReplaceButtonText(R.string.replace_image);
631                 } catch (MmsException e) {
632                     Log.e(TAG, "add image failed", e);
633                     notifyUser("add picture failed");
634                     Toast.makeText(SlideEditorActivity.this,
635                             getResourcesString(R.string.failed_to_add_media, getPictureString()),
636                             Toast.LENGTH_SHORT).show();
637                 } catch (UnsupportContentTypeException e) {
638                     MessageUtils.showErrorDialog(SlideEditorActivity.this,
639                             getResourcesString(R.string.unsupported_media_format, getPictureString()),
640                             getResourcesString(R.string.select_different_media, getPictureString()));
641                 } catch (ResolutionException e) {
642                     MessageUtils.resizeImageAsync(this, data.getData(), new Handler(),
643                             mResizeImageCallback, false);
644                 } catch (ExceedMessageSizeException e) {
645                     MessageUtils.resizeImageAsync(this, data.getData(), new Handler(),
646                             mResizeImageCallback, false);
647                 }
648                 break;
649 
650             case REQUEST_CODE_CHANGE_MUSIC:
651             case REQUEST_CODE_RECORD_SOUND:
652                 Uri uri;
653                 if (requestCode == REQUEST_CODE_CHANGE_MUSIC) {
654                     uri = (Uri) data.getParcelableExtra(RingtoneManager.EXTRA_RINGTONE_PICKED_URI);
655                     if (Settings.System.DEFAULT_RINGTONE_URI.equals(uri)) {
656                         return;
657                     }
658                 } else {
659                     uri = data.getData();
660                 }
661 
662                 try {
663                     mSlideshowEditor.changeAudio(mPosition, uri);
664                 } catch (MmsException e) {
665                     Log.e(TAG, "add audio failed", e);
666                     notifyUser("add music failed");
667                     Toast.makeText(SlideEditorActivity.this,
668                             getResourcesString(R.string.failed_to_add_media, getAudioString()),
669                             Toast.LENGTH_SHORT).show();
670                 } catch (UnsupportContentTypeException e) {
671                     MessageUtils.showErrorDialog(SlideEditorActivity.this,
672                             getResourcesString(R.string.unsupported_media_format, getAudioString()),
673                             getResourcesString(R.string.select_different_media, getAudioString()));
674                 } catch (ExceedMessageSizeException e) {
675                     MessageUtils.showErrorDialog(SlideEditorActivity.this,
676                             getResourcesString(R.string.exceed_message_size_limitation),
677                             getResourcesString(R.string.failed_to_add_media, getAudioString()));
678                 }
679                 break;
680 
681             case REQUEST_CODE_TAKE_VIDEO:
682                 try {
683                     Uri videoUri = TempFileProvider.renameScrapFile(".3gp",
684                             Integer.toString(mPosition), this);
685 
686                     mSlideshowEditor.changeVideo(mPosition, videoUri);
687                 } catch (MmsException e) {
688                     notifyUser("add video failed");
689                     Toast.makeText(SlideEditorActivity.this,
690                             getResourcesString(R.string.failed_to_add_media, getVideoString()),
691                             Toast.LENGTH_SHORT).show();
692                 } catch (UnsupportContentTypeException e) {
693                     MessageUtils.showErrorDialog(SlideEditorActivity.this,
694                             getResourcesString(R.string.unsupported_media_format, getVideoString()),
695                             getResourcesString(R.string.select_different_media, getVideoString()));
696                 } catch (ExceedMessageSizeException e) {
697                     MessageUtils.showErrorDialog(SlideEditorActivity.this,
698                             getResourcesString(R.string.exceed_message_size_limitation),
699                             getResourcesString(R.string.failed_to_add_media, getVideoString()));
700                 }
701                 break;
702 
703             case REQUEST_CODE_CHANGE_VIDEO:
704                 try {
705                     mSlideshowEditor.changeVideo(mPosition, data.getData());
706                 } catch (MmsException e) {
707                     Log.e(TAG, "add video failed", e);
708                     notifyUser("add video failed");
709                     Toast.makeText(SlideEditorActivity.this,
710                             getResourcesString(R.string.failed_to_add_media, getVideoString()),
711                             Toast.LENGTH_SHORT).show();
712                 } catch (UnsupportContentTypeException e) {
713                     MessageUtils.showErrorDialog(SlideEditorActivity.this,
714                             getResourcesString(R.string.unsupported_media_format, getVideoString()),
715                             getResourcesString(R.string.select_different_media, getVideoString()));
716                 } catch (ExceedMessageSizeException e) {
717                     MessageUtils.showErrorDialog(SlideEditorActivity.this,
718                             getResourcesString(R.string.exceed_message_size_limitation),
719                             getResourcesString(R.string.failed_to_add_media, getVideoString()));
720                 }
721                 break;
722 
723             case REQUEST_CODE_CHANGE_DURATION:
724                 mSlideshowEditor.changeDuration(mPosition,
725                     Integer.valueOf(data.getAction()) * 1000);
726                 break;
727         }
728     }
729 
730     private final ResizeImageResultCallback mResizeImageCallback = new ResizeImageResultCallback() {
731         public void onResizeResult(PduPart part, boolean append) {
732             Context context = SlideEditorActivity.this;
733             if (part == null) {
734                 Toast.makeText(SlideEditorActivity.this,
735                         getResourcesString(R.string.failed_to_add_media, getPictureString()),
736                         Toast.LENGTH_SHORT).show();
737                 return;
738             }
739 
740             try {
741                 long messageId = ContentUris.parseId(mUri);
742                 PduPersister persister = PduPersister.getPduPersister(context);
743                 Uri newUri = persister.persistPart(part, messageId, null);
744                 mSlideshowEditor.changeImage(mPosition, newUri);
745 
746                 setReplaceButtonText(R.string.replace_image);
747             } catch (MmsException e) {
748                 notifyUser("add picture failed");
749                 Toast.makeText(SlideEditorActivity.this,
750                         getResourcesString(R.string.failed_to_add_media, getPictureString()),
751                         Toast.LENGTH_SHORT).show();
752             } catch (UnsupportContentTypeException e) {
753                 MessageUtils.showErrorDialog(SlideEditorActivity.this,
754                         getResourcesString(R.string.unsupported_media_format, getPictureString()),
755                         getResourcesString(R.string.select_different_media, getPictureString()));
756             } catch (ResolutionException e) {
757                 MessageUtils.showErrorDialog(SlideEditorActivity.this,
758                         getResourcesString(R.string.failed_to_resize_image),
759                         getResourcesString(R.string.resize_image_error_information));
760             } catch (ExceedMessageSizeException e) {
761                 MessageUtils.showErrorDialog(SlideEditorActivity.this,
762                         getResourcesString(R.string.exceed_message_size_limitation),
763                         getResourcesString(R.string.failed_to_add_media, getPictureString()));
764             }
765         }
766     };
767 
getResourcesString(int id, String mediaName)768     private String getResourcesString(int id, String mediaName) {
769         Resources r = getResources();
770         return r.getString(id, mediaName);
771     }
772 
getResourcesString(int id)773     private String getResourcesString(int id) {
774         Resources r = getResources();
775         return r.getString(id);
776     }
777 
getAudioString()778     private String getAudioString() {
779         return getResourcesString(R.string.type_audio);
780     }
781 
getPictureString()782     private String getPictureString() {
783         return getResourcesString(R.string.type_picture);
784     }
785 
getVideoString()786     private String getVideoString() {
787         return getResourcesString(R.string.type_video);
788     }
789 
notifyUser(String message)790     private void notifyUser(String message) {
791         if (LOCAL_LOGV) {
792             Log.v(TAG, "notifyUser: message=" + message);
793         }
794     }
795 
showCurrentSlide()796     private void showCurrentSlide() {
797         mPresenter.setLocation(mPosition);
798         mPresenter.present(null);
799         updateTitle();
800 
801         if (mSlideshowModel.get(mPosition).hasImage()) {
802             setReplaceButtonText(R.string.replace_image);
803         } else {
804             setReplaceButtonText(R.string.add_picture);
805         }
806     }
807 }
808