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