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.ListActivity;
     21 import android.content.Context;
     22 import android.content.Intent;
     23 import android.net.Uri;
     24 import android.os.Bundle;
     25 import android.util.Log;
     26 import android.view.ContextMenu;
     27 import android.view.ContextMenu.ContextMenuInfo;
     28 import android.view.LayoutInflater;
     29 import android.view.Menu;
     30 import android.view.MenuItem;
     31 import android.view.View;
     32 import android.view.ViewGroup;
     33 import android.widget.AdapterView;
     34 import android.widget.AdapterView.AdapterContextMenuInfo;
     35 import android.widget.ArrayAdapter;
     36 import android.widget.ImageView;
     37 import android.widget.ListView;
     38 import android.widget.TextView;
     39 import android.widget.Toast;
     40 
     41 import com.android.mms.R;
     42 import com.android.mms.model.IModelChangedObserver;
     43 import com.android.mms.model.Model;
     44 import com.android.mms.model.SlideModel;
     45 import com.android.mms.model.SlideshowModel;
     46 import com.google.android.mms.MmsException;
     47 import com.google.android.mms.pdu.PduBody;
     48 import com.google.android.mms.pdu.PduPersister;
     49 
     50 /**
     51  * A list of slides which allows user to edit each item in it.
     52  */
     53 public class SlideshowEditActivity extends ListActivity {
     54     private final static String TAG = "SlideshowEditActivity";
     55     private static final boolean DEBUG = false;
     56     private static final boolean LOCAL_LOGV = false;
     57 
     58     // Menu ids.
     59     private final static int MENU_MOVE_UP           = 0;
     60     private final static int MENU_MOVE_DOWN         = 1;
     61     private final static int MENU_REMOVE_SLIDE      = 2;
     62     private final static int MENU_ADD_SLIDE         = 3;
     63     private final static int MENU_DISCARD_SLIDESHOW = 4;
     64 
     65     private final static int REQUEST_CODE_EDIT_SLIDE         = 6;
     66 
     67     // State.
     68     private final static String STATE = "state";
     69     private final static String SLIDE_INDEX = "slide_index";
     70     private final static String MESSAGE_URI = "message_uri";
     71 
     72     private ListView mList;
     73     private SlideListAdapter mSlideListAdapter;
     74 
     75     private SlideshowModel mSlideshowModel = null;
     76     private SlideshowEditor mSlideshowEditor = null;
     77 
     78     private Bundle mState;
     79     private Uri mUri;
     80     private Intent mResultIntent;
     81     private boolean mDirty;
     82     private View mAddSlideItem;
     83 
     84     @Override
     85     protected void onCreate(Bundle icicle) {
     86         super.onCreate(icicle);
     87 
     88         mList = getListView();
     89         mAddSlideItem = createAddSlideItem();
     90         mList.addFooterView(mAddSlideItem);
     91         mAddSlideItem.setVisibility(View.GONE);
     92 
     93         if (icicle != null) {
     94             // Retrieve previously saved state of this activity.
     95             mState = icicle.getBundle(STATE);
     96         }
     97 
     98         if (mState != null) {
     99             mUri = Uri.parse(mState.getString(MESSAGE_URI));
    100         } else {
    101             mUri = getIntent().getData();
    102         }
    103 
    104         if (mUri == null) {
    105             Log.e(TAG, "Cannot startup activity, null Uri.");
    106             finish();
    107             return;
    108         }
    109 
    110         // Return the Uri of the message to whoever invoked us.
    111         mResultIntent = new Intent();
    112         mResultIntent.setData(mUri);
    113 
    114         try {
    115             initSlideList();
    116             adjustAddSlideVisibility();
    117         } catch (MmsException e) {
    118             Log.e(TAG, "Failed to initialize the slide-list.", e);
    119             finish();
    120         }
    121 
    122         registerForContextMenu(mList);
    123     }
    124 
    125     private View createAddSlideItem() {
    126         View v = ((LayoutInflater) getSystemService(
    127                 Context.LAYOUT_INFLATER_SERVICE)).inflate(R.layout.slideshow_edit_item, null);
    128 
    129         //  Add slide.
    130         TextView text = (TextView) v.findViewById(R.id.slide_number_text);
    131         text.setText(R.string.add_slide);
    132 
    133         text = (TextView) v.findViewById(R.id.text_preview);
    134         text.setText(R.string.add_slide_hint);
    135         text.setVisibility(View.VISIBLE);
    136 
    137         ImageView image = (ImageView) v.findViewById(R.id.image_preview);
    138         image.setImageResource(R.drawable.ic_attach_slideshow_holo_light);
    139 
    140         return v;
    141     }
    142 
    143     @Override
    144     protected void onListItemClick(ListView l, View v, int position, long id) {
    145         if (position == (l.getCount() - 1)) {
    146             addNewSlide();
    147         } else {
    148             openSlide(position);
    149         }
    150     }
    151 
    152     @Override
    153     protected void onResume() {
    154         super.onResume();
    155 
    156         if (mState != null) {
    157             mList.setSelection(mState.getInt(SLIDE_INDEX, 0));
    158         }
    159     }
    160 
    161     /*
    162      * (non-Javadoc)
    163      * @see android.app.Activity#onSaveInstanceState(android.os.Bundle)
    164      */
    165     @Override
    166     protected void onSaveInstanceState(Bundle outState) {
    167         super.onSaveInstanceState(outState);
    168 
    169         mState = new Bundle();
    170         if (mList.getSelectedItemPosition() >= 0) {
    171             mState.putInt(SLIDE_INDEX, mList.getSelectedItemPosition());
    172         }
    173 
    174         if (mUri != null) {
    175             mState.putString(MESSAGE_URI, mUri.toString());
    176         }
    177 
    178         if (LOCAL_LOGV) {
    179             Log.v(TAG, "Saving state: " + mState);
    180         }
    181         outState.putBundle(STATE, mState);
    182     }
    183 
    184     @Override
    185     protected void onPause()  {
    186         super.onPause();
    187 
    188         synchronized (this) {
    189             if (mDirty) {
    190                 try {
    191                     PduBody pb = mSlideshowModel.toPduBody();
    192                     PduPersister.getPduPersister(this).updateParts(mUri, pb, null);
    193                     mSlideshowModel.sync(pb);
    194                 }  catch (MmsException e) {
    195                     Log.e(TAG, "Cannot update the message: " + mUri, e);
    196                 }
    197             }
    198         }
    199     }
    200 
    201     @Override
    202     protected void onDestroy() {
    203         super.onDestroy();
    204         cleanupSlideshowModel();
    205     }
    206 
    207     private void cleanupSlideshowModel() {
    208         if (mSlideshowModel != null) {
    209             mSlideshowModel.unregisterModelChangedObserver(
    210                     mModelChangedObserver);
    211             mSlideshowModel = null;
    212         }
    213     }
    214 
    215     private void initSlideList() throws MmsException {
    216         cleanupSlideshowModel();
    217         mSlideshowModel = SlideshowModel.createFromMessageUri(this, mUri);
    218         mSlideshowModel.registerModelChangedObserver(mModelChangedObserver);
    219         mSlideshowEditor = new SlideshowEditor(this, mSlideshowModel);
    220         mSlideListAdapter = new SlideListAdapter(
    221                 this, R.layout.slideshow_edit_item, mSlideshowModel);
    222         mList.setAdapter(mSlideListAdapter);
    223     }
    224 
    225     @Override
    226     public boolean onPrepareOptionsMenu(Menu menu) {
    227         menu.clear();
    228 
    229         int position = mList.getSelectedItemPosition();
    230         if ((position >= 0) && (position != (mList.getCount() - 1))) {
    231             // Selected one slide.
    232             if (position > 0) {
    233                 menu.add(0, MENU_MOVE_UP, 0, R.string.move_up).setIcon(R.drawable.ic_menu_move_up);
    234             }
    235 
    236             if (position < (mSlideListAdapter.getCount() - 1)) {
    237                 menu.add(0, MENU_MOVE_DOWN, 0, R.string.move_down).setIcon(
    238                         R.drawable.ic_menu_move_down);
    239             }
    240 
    241             menu.add(0, MENU_ADD_SLIDE, 0, R.string.add_slide).setIcon(R.drawable.ic_menu_add_slide);
    242 
    243             menu.add(0, MENU_REMOVE_SLIDE, 0, R.string.remove_slide).setIcon(
    244                     android.R.drawable.ic_menu_delete);
    245         } else {
    246             menu.add(0, MENU_ADD_SLIDE, 0, R.string.add_slide).setIcon(R.drawable.ic_menu_add_slide);
    247         }
    248 
    249         menu.add(0, MENU_DISCARD_SLIDESHOW, 0,
    250                 R.string.discard_slideshow).setIcon(R.drawable.ic_menu_delete_played);
    251 
    252         return true;
    253     }
    254 
    255     @Override
    256     public boolean onOptionsItemSelected(MenuItem item) {
    257         int position = mList.getSelectedItemPosition();
    258 
    259         switch (item.getItemId()) {
    260             case MENU_MOVE_UP:
    261                 if ((position > 0) && (position < mSlideshowModel.size())) {
    262                     mSlideshowEditor.moveSlideUp(position);
    263                     mSlideListAdapter.notifyDataSetChanged();
    264                     mList.setSelection(position - 1);
    265                 }
    266                 break;
    267             case MENU_MOVE_DOWN:
    268                 if ((position >= 0) && (position < mSlideshowModel.size() - 1)) {
    269                     mSlideshowEditor.moveSlideDown(position);
    270                     mSlideListAdapter.notifyDataSetChanged();
    271                     mList.setSelection(position + 1);
    272                 }
    273                 break;
    274             case MENU_REMOVE_SLIDE:
    275                 if ((position >= 0) && (position < mSlideshowModel.size())) {
    276                     mSlideshowEditor.removeSlide(position);
    277                     mSlideListAdapter.notifyDataSetChanged();
    278                 }
    279                 break;
    280             case MENU_ADD_SLIDE:
    281                 addNewSlide();
    282                 break;
    283             case MENU_DISCARD_SLIDESHOW:
    284                 // delete all slides from slideshow.
    285                 mSlideshowEditor.removeAllSlides();
    286                 mSlideListAdapter.notifyDataSetChanged();
    287                 finish();
    288                 break;
    289         }
    290 
    291         return true;
    292     }
    293 
    294     private void openSlide(int index) {
    295         Intent intent = new Intent(this, SlideEditorActivity.class);
    296         intent.setData(mUri);
    297         intent.putExtra(SlideEditorActivity.SLIDE_INDEX, index);
    298         startActivityForResult(intent, REQUEST_CODE_EDIT_SLIDE);
    299     }
    300 
    301     private void adjustAddSlideVisibility() {
    302         if (mSlideshowModel.size() >= SlideshowEditor.MAX_SLIDE_NUM) {
    303             mAddSlideItem.setVisibility(View.GONE);
    304         } else {
    305             mAddSlideItem.setVisibility(View.VISIBLE);
    306         }
    307     }
    308 
    309     private void addNewSlide() {
    310         if ( mSlideshowEditor.addNewSlide() ) {
    311             // add successfully
    312             mSlideListAdapter.notifyDataSetChanged();
    313 
    314             // Select the new slide.
    315             mList.requestFocus();
    316             mList.setSelection(mSlideshowModel.size() - 1);
    317         } else {
    318             Toast.makeText(this, R.string.cannot_add_slide_anymore,
    319                     Toast.LENGTH_SHORT).show();
    320         }
    321     }
    322 
    323     @Override
    324     protected void onActivityResult(int requestCode, int resultCode,
    325             Intent data) {
    326         if (resultCode != RESULT_OK) {
    327             return;
    328         }
    329 
    330         switch(requestCode) {
    331             case REQUEST_CODE_EDIT_SLIDE:
    332                 synchronized (this) {
    333                     mDirty = true;
    334                 }
    335                 setResult(RESULT_OK, mResultIntent);
    336 
    337                 if ((data != null) && data.getBooleanExtra("done", false)) {
    338                     finish();
    339                     return;
    340                 }
    341 
    342                 try {
    343                     initSlideList();
    344                     adjustAddSlideVisibility();
    345                 } catch (MmsException e) {
    346                     Log.e(TAG, "Failed to initialize the slide-list.", e);
    347                     finish();
    348                     return;
    349                 }
    350                 break;
    351         }
    352     }
    353 
    354     private static class SlideListAdapter extends ArrayAdapter<SlideModel> {
    355         private final Context mContext;
    356         private final int mResource;
    357         private final LayoutInflater mInflater;
    358         private final SlideshowModel mSlideshow;
    359 
    360         public SlideListAdapter(Context context, int resource,
    361                 SlideshowModel slideshow) {
    362             super(context, resource, slideshow);
    363 
    364             mContext = context;
    365             mResource = resource;
    366             mInflater = LayoutInflater.from(context);
    367             mSlideshow = slideshow;
    368         }
    369 
    370         @Override
    371         public View getView(int position, View convertView, ViewGroup parent) {
    372             return createViewFromResource(position, convertView, mResource);
    373         }
    374 
    375         private View createViewFromResource(int position, View convertView, int resource) {
    376             SlideListItemView slideListItemView;
    377             slideListItemView = (SlideListItemView) mInflater.inflate(
    378                     resource, null);
    379 
    380             // Show slide number.
    381             TextView text;
    382             text = (TextView) slideListItemView.findViewById(R.id.slide_number_text);
    383             text.setText(mContext.getString(R.string.slide_number, position + 1));
    384 
    385             SlideModel slide = getItem(position);
    386             int dur = slide.getDuration() / 1000;
    387             text = (TextView) slideListItemView.findViewById(R.id.duration_text);
    388             text.setText(mContext.getResources().
    389                          getQuantityString(R.plurals.slide_duration, dur, dur));
    390 
    391             Presenter presenter = PresenterFactory.getPresenter(
    392                     "SlideshowPresenter", mContext, slideListItemView, mSlideshow);
    393             ((SlideshowPresenter) presenter).setLocation(position);
    394             presenter.present(null);
    395 
    396             return slideListItemView;
    397         }
    398     }
    399 
    400     private final IModelChangedObserver mModelChangedObserver =
    401         new IModelChangedObserver() {
    402             public void onModelChanged(Model model, boolean dataChanged) {
    403                 synchronized (SlideshowEditActivity.this) {
    404                     mDirty = true;
    405                 }
    406                 setResult(RESULT_OK, mResultIntent);
    407                 adjustAddSlideVisibility();
    408             }
    409         };
    410 
    411     @Override
    412     public void onCreateContextMenu(ContextMenu menu, View v,
    413             ContextMenuInfo menuInfo) {
    414         menu.setHeaderTitle(R.string.slideshow_options);
    415 
    416         AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo;
    417         int position = info.position;
    418 
    419         if ((position >= 0) && (position != (mList.getCount() - 1))) {
    420             // Selected one slide.
    421             if (position > 0) {
    422                 menu.add(0, MENU_MOVE_UP, 0, R.string.move_up).setIcon(R.drawable.ic_menu_move_up);
    423             }
    424             if (position < (mSlideListAdapter.getCount() - 1)) {
    425                 menu.add(0, MENU_MOVE_DOWN, 0, R.string.move_down).setIcon(
    426                         R.drawable.ic_menu_move_down);
    427             }
    428 
    429             menu.add(0, MENU_ADD_SLIDE, 0, R.string.add_slide).setIcon(
    430                     R.drawable.ic_menu_add_slide);
    431 
    432             menu.add(0, MENU_REMOVE_SLIDE, 0, R.string.remove_slide).setIcon(
    433                     android.R.drawable.ic_menu_delete);
    434         }
    435     }
    436 
    437     @Override
    438     public boolean onContextItemSelected(MenuItem item) {
    439         AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
    440         int position = info.position;
    441 
    442         switch(item.getItemId()) {
    443             case MENU_MOVE_UP:
    444                 if ((position > 0) && (position < mSlideshowModel.size())) {
    445                     mSlideshowEditor.moveSlideUp(position);
    446                     mSlideListAdapter.notifyDataSetChanged();
    447                     mList.setSelection(position - 1);
    448                 }
    449                 break;
    450             case MENU_MOVE_DOWN:
    451                 if ((position >= 0) && (position < mSlideshowModel.size() - 1)) {
    452                     mSlideshowEditor.moveSlideDown(position);
    453                     mSlideListAdapter.notifyDataSetChanged();
    454                     mList.setSelection(position + 1);
    455                 }
    456                 break;
    457             case MENU_REMOVE_SLIDE:
    458                 if ((position >= 0) && (position < mSlideshowModel.size())) {
    459                     mSlideshowEditor.removeSlide(position);
    460                     mSlideListAdapter.notifyDataSetChanged();
    461                 }
    462                 break;
    463             case MENU_ADD_SLIDE:
    464                 addNewSlide();
    465                 break;
    466             default:
    467                 break;
    468         }
    469 
    470         return true;
    471     }
    472 }
    473