/* * Copyright (C) 2009 Android Shuffle Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.dodgybits.shuffle.android.editor.activity; import org.dodgybits.android.shuffle.R; import org.dodgybits.shuffle.android.core.activity.flurry.FlurryEnabledActivity; import org.dodgybits.shuffle.android.core.model.Entity; import org.dodgybits.shuffle.android.core.model.Id; import org.dodgybits.shuffle.android.core.model.encoding.EntityEncoder; import org.dodgybits.shuffle.android.core.model.persistence.EntityPersister; import org.dodgybits.shuffle.android.core.view.MenuUtils; import org.dodgybits.shuffle.android.list.activity.State; import org.dodgybits.shuffle.android.preference.model.Preferences; import android.content.ContentUris; import android.content.Intent; import android.database.Cursor; import android.net.Uri; import android.os.Bundle; import android.util.Log; import android.view.KeyEvent; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.Toast; /** * A generic activity for editing an item in a database. This can be used either * to simply view an item (Intent.VIEW_ACTION), view and edit an item * (Intent.EDIT_ACTION), or create a new item (Intent.INSERT_ACTION). */ public abstract class AbstractEditorActivity<E extends Entity> extends FlurryEnabledActivity implements View.OnClickListener, View.OnFocusChangeListener { private static final String cTag = "AbstractEditorActivity"; protected int mState; protected Uri mUri; protected Cursor mCursor; protected E mOriginalItem; protected Intent mNextIntent; @Override protected void onCreate(Bundle icicle) { Log.d(cTag, "onCreate+"); super.onCreate(icicle); processIntent(); setDefaultKeyMode(DEFAULT_KEYS_SHORTCUT); setContentView(getContentViewResId()); addSavePanelListeners(); Log.d(cTag, "onCreate-"); } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { switch (keyCode) { case KeyEvent.KEYCODE_BACK: doSaveAction(); break; } return super.onKeyDown(keyCode, event); } @Override public void finish() { if (mNextIntent != null) { startActivity(mNextIntent); } super.finish(); } @Override public boolean onPrepareOptionsMenu(Menu menu) { super.onCreateOptionsMenu(menu); MenuItem item = menu.findItem(MenuUtils.SYNC_ID); if (item != null) { item.setVisible(Preferences.validateTracksSettings(this)); } return true; } @Override public boolean onCreateOptionsMenu(Menu menu) { super.onCreateOptionsMenu(menu); MenuUtils.addEditorMenuItems(menu, mState); MenuUtils.addPrefsHelpMenuItems(this, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle all of the possible menu actions. switch (item.getItemId()) { case MenuUtils.SAVE_ID: doSaveAction(); break; case MenuUtils.SAVE_AND_ADD_ID: // create an Intent for the new item based on the current item startActivity(getInsertIntent()); doSaveAction(); break; case MenuUtils.DELETE_ID: doDeleteAction(); finish(); break; case MenuUtils.DISCARD_ID: doRevertAction(); break; case MenuUtils.REVERT_ID: doRevertAction(); break; } if (MenuUtils.checkCommonItemsSelected(item, this, MenuUtils.INBOX_ID)) { return true; } return super.onOptionsItemSelected(item); } @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); E item = createItemFromUI(); saveItem(outState, item); } @Override protected void onRestoreInstanceState(Bundle savedInstanceState) { super.onRestoreInstanceState(savedInstanceState); E item = restoreItem(savedInstanceState); updateUIFromItem(item); } public void onFocusChange(View v, boolean hasFocus) { // Because we're emulating a ListView, we need to setSelected() for // views as they are focused. v.setSelected(hasFocus); } public void onClick(View v) { switch (v.getId()) { case R.id.saveButton: doSaveAction(); break; case R.id.discardButton: doRevertAction(); break; } } protected void doSaveAction() { // Save or create the contact if needed Uri result = null; switch (mState) { case State.STATE_EDIT: result = save(); break; case State.STATE_INSERT: result = create(); break; default: Log.e(cTag, "Unknown state in doSaveAction: " + mState); break; } if (result == null) { setResult(RESULT_CANCELED); } else { setResult(RESULT_OK, new Intent().setData(result)); } finish(); } /** * Take care of canceling work on a item. Deletes the item if we had created * it, otherwise reverts to the original text. */ protected void doRevertAction() { if (mCursor != null) { if (mState == State.STATE_EDIT) { // Put the original item back into the database mCursor.close(); mCursor = null; getPersister().update(mOriginalItem); } else if (mState == State.STATE_INSERT) { // if inserting, there's nothing to delete } } setResult(RESULT_CANCELED); finish(); } /** * Take care of deleting a item. Simply deletes the entry. */ protected void doDeleteAction() { // if inserting, there's nothing to delete if (mState == State.STATE_EDIT && mCursor != null) { mCursor.close(); mCursor = null; Id id = Id.create(ContentUris.parseId(mUri)); getPersister().moveToTrash(id); } } protected final void showSaveToast() { String text; if (mState == State.STATE_EDIT) { text = getResources().getString(R.string.itemSavedToast, getItemName()); } else { text = getResources().getString(R.string.itemCreatedToast, getItemName()); } Toast.makeText(this, text, Toast.LENGTH_SHORT).show(); } protected boolean isValid() { return true; } protected Uri create() { Uri uri = null; if (isValid()) { E item = createItemFromUI(); uri = getPersister().insert(item); showSaveToast(); } return uri; } protected Uri save() { Uri uri = null; if (isValid()) { E item = createItemFromUI(); getPersister().update(item); showSaveToast(); uri = mUri; } return uri; } protected final E restoreItem(Bundle icicle) { return getEncoder().restore(icicle); } protected final void saveItem(Bundle outState, E item) { getEncoder().save(outState, item); } /** * @return id of layout for this view */ abstract protected int getContentViewResId(); abstract protected E createItemFromUI(); abstract protected void updateUIFromItem(E item); abstract protected void updateUIFromExtras(Bundle extras); abstract protected EntityPersister<E> getPersister(); abstract protected EntityEncoder<E> getEncoder(); abstract protected Intent getInsertIntent(); abstract protected CharSequence getItemName(); private void processIntent() { final Intent intent = getIntent(); // Do some setup based on the action being performed. final String action = intent.getAction(); mUri = intent.getData(); if (action.equals(Intent.ACTION_EDIT)) { // Requested to edit: set that state, and the data being edited. mState = State.STATE_EDIT; } else if (action.equals(Intent.ACTION_INSERT)) { // Requested to insert: set that state, and create a new entry // in the container. mState = State.STATE_INSERT; } else { // Whoops, unknown action! Bail. Log.e(cTag, "Unknown action " + action + ", exiting"); finish(); return; } } private void addSavePanelListeners() { // Setup the bottom buttons View view = findViewById(R.id.saveButton); view.setOnClickListener(this); view = findViewById(R.id.discardButton); view.setOnClickListener(this); } }