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