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