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