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