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