edu.mit.mobile.android.livingpostcards.CardMediaEditFragment.java Source code

Java tutorial

Introduction

Here is the source code for edu.mit.mobile.android.livingpostcards.CardMediaEditFragment.java

Source

package edu.mit.mobile.android.livingpostcards;
/*
 * Copyright (C) 2012-2013  MIT Mobile Experience Lab
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation version 2
 * of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

import java.io.IOException;

import android.app.Activity;
import android.content.ContentUris;
import android.database.Cursor;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v4.app.Fragment;
import android.support.v4.app.LoaderManager.LoaderCallbacks;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
import android.util.Log;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;

import com.scvngr.levelup.views.gallery.AdapterView;
import com.scvngr.levelup.views.gallery.AdapterView.OnItemSelectedListener;
import com.scvngr.levelup.views.gallery.Gallery;

import edu.mit.mobile.android.flipr.BuildConfig;
import edu.mit.mobile.android.flipr.R;
import edu.mit.mobile.android.imagecache.ImageCache;
import edu.mit.mobile.android.imagecache.ImageCache.OnImageLoadListener;
import edu.mit.mobile.android.imagecache.ImageLoaderAdapter;
import edu.mit.mobile.android.imagecache.SimpleThumbnailCursorAdapter;
import edu.mit.mobile.android.livingpostcards.DeleteDialogFragment.OnDeleteListener;
import edu.mit.mobile.android.livingpostcards.auth.Authenticator;
import edu.mit.mobile.android.livingpostcards.data.CardMedia;
import edu.mit.mobile.android.locast.data.Authorable;

public class CardMediaEditFragment extends Fragment
        implements LoaderCallbacks<Cursor>, OnItemSelectedListener, OnImageLoadListener {
    public static final String ARGUMENT_URI = "uri";

    private static final String TAG = CardMediaEditFragment.class.getSimpleName();

    private static final int NO_PENDING = -1;

    private Uri mUri;

    private SimpleThumbnailCursorAdapter mAdapter;
    private Gallery mGallery;
    private ImageView mFrame;

    private ImageCache mImageCache;

    private int mShowBigId;

    private static final int THUMB_W = 160;
    private static final int THUMB_H = 120;

    private static final int HIGHRES_W = 640;
    private static final int HIGHRES_H = 480;

    private static final int HIGHRES_LOAD_DELAY = 100; // ms

    public static CardMediaEditFragment newInstance(Uri cardMedia) {
        final CardMediaEditFragment cmf = new CardMediaEditFragment();

        final Bundle args = new Bundle();
        args.putParcelable(ARGUMENT_URI, cardMedia);
        cmf.setArguments(args);
        return cmf;
    }

    @Override
    public void onAttach(Activity activity) {

        super.onAttach(activity);

        mCMEFHandler = new CMEFHandler(this);
        mImageCache = ImageCache.getInstance(activity);

    }

    @Override
    public void onDetach() {
        super.onDetach();

        mImageCache = null;
        mCMEFHandler.removeMessages(CMEFHandler.MSG_LOAD_HIGHRES);
        mCMEFHandler = null;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        if (getArguments() != null) {
            mUri = getArguments().getParcelable(ARGUMENT_URI);

            if (mUri != null) {
                getLoaderManager().initLoader(0, null, this);
            }
        }
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

        final View v = inflater.inflate(R.layout.card_media_edit_fragment, container, false);

        mAdapter = new SimpleThumbnailCursorAdapter(getActivity(), R.layout.card_media_thumb_square, null,
                new String[] { CardMedia.COL_LOCAL_URL, CardMedia.COL_MEDIA_URL },
                new int[] { R.id.card_media_thumbnail, R.id.card_media_thumbnail },
                new int[] { R.id.card_media_thumbnail }, 0);

        mGallery = (Gallery) v.findViewById(R.id.gallery);

        mGallery.setAdapter(new ImageLoaderAdapter(getActivity(), mAdapter, mImageCache,
                new int[] { R.id.card_media_thumbnail }, THUMB_W, THUMB_H, ImageLoaderAdapter.UNIT_PX, false));

        mGallery.setWrap(true);
        mGallery.setInfiniteScroll(true);

        mGallery.setOnItemSelectedListener(this);

        registerForContextMenu(mGallery);

        mFrame = (ImageView) v.findViewById(R.id.frame);

        return v;
    }

    @Override
    public void onPause() {
        super.onPause();
        mGallery.pause();

        mImageCache.unregisterOnImageLoadListener(this);
    }

    @Override
    public void onResume() {
        super.onResume();
        mImageCache.registerOnImageLoadListener(this);

        mGallery.resume();
    }

    @Override
    public Loader<Cursor> onCreateLoader(int arg0, Bundle arg1) {

        return new CursorLoader(getActivity(), mUri, new String[] { CardMedia._ID, CardMedia.COL_LOCAL_URL,
                CardMedia.COL_MEDIA_URL, CardMedia.COL_AUTHOR_URI }, null, null, null);
    }

    @Override
    public void onLoadFinished(Loader<Cursor> loader, Cursor c) {
        mAdapter.swapCursor(c);
    }

    @Override
    public void onLoaderReset(Loader<Cursor> loader) {
        mAdapter.swapCursor(null);
    }

    @Override
    public void onItemSelected(AdapterView<?> adapter, View view, int position, long id) {
        // detached
        if (mCMEFHandler == null) {
            return;
        }

        final Cursor item = (Cursor) mAdapter.getItem(position);
        if (item == null) {
            return;
        }
        String uri = item.getString(item.getColumnIndex(CardMedia.COL_LOCAL_URL));
        if (uri == null) {
            uri = item.getString(item.getColumnIndex(CardMedia.COL_MEDIA_URL));
        }
        if (uri == null) {
            return;
        }

        if (BuildConfig.DEBUG) {
            Log.d(TAG, "onItemSelected(" + adapter + ", " + view + ", " + position + ", " + id + ")");
        }

        // clear the highres request; if the load has already started, it won't be shown.
        mShowHighresId = NO_PENDING;
        mCMEFHandler.removeMessages(CMEFHandler.MSG_LOAD_HIGHRES);

        mShowBigId = mImageCache.getNewID();

        final Uri imageUri = Uri.parse(uri);
        try {
            final Drawable d = mImageCache.loadImage(mShowBigId, imageUri, THUMB_W, THUMB_H);
            if (d != null) {
                onImageLoaded(mShowBigId, imageUri, d);
            }
        } catch (final IOException e) {
            Log.e(TAG, "Error loading image", e);
        }
    }

    @Override
    public void onNothingSelected(AdapterView<?> adapter) {
        // TODO Auto-generated method stub

    }

    @Override
    public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
        switch (v.getId()) {
        case R.id.gallery: {
            getActivity().getMenuInflater().inflate(R.menu.context_card_media, menu);
            final Cursor c = mAdapter.getCursor();
            if (c == null) {
                return;
            }
            AdapterView.AdapterContextMenuInfo info;
            try {
                info = (AdapterView.AdapterContextMenuInfo) menuInfo;
            } catch (final ClassCastException e) {
                Log.e(TAG, "bad menuInfo", e);
                return;
            }

            // the below is a special case due to a bug in the infinite gallery spinner.

            c.moveToPosition(info.position % mAdapter.getCount());

            final String myUserUri = Authenticator.getUserUri(getActivity());

            final boolean isEditable = Authorable.canEdit(myUserUri, c);

            menu.findItem(R.id.delete).setVisible(isEditable);

        }
            break;
        default:
            super.onCreateContextMenu(menu, v, menuInfo);
        }

    }

    private void showDeleteDialog(Uri item) {
        final DeleteDialogFragment del = DeleteDialogFragment.newInstance(item,
                getActivity().getString(R.string.delete_postcard_image),
                getString(R.string.delete_postcard_image_confirm_message));
        del.registerOnDeleteListener(mOnDeleteListener);
        del.show(getFragmentManager(), "delete-item-dialog");
    }

    private final OnDeleteListener mOnDeleteListener = new OnDeleteListener() {

        @Override
        public void onDelete(Uri item, boolean deleted) {

        }
    };

    private int mShowHighresId;

    @Override
    public boolean onContextItemSelected(MenuItem item) {
        AdapterView.AdapterContextMenuInfo info;
        try {
            info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
        } catch (final ClassCastException e) {
            Log.e(TAG, "bad menuInfo", e);
            return false;
        }

        final Uri itemUri = ContentUris.withAppendedId(mUri, info.id);

        switch (item.getItemId()) {
        case R.id.delete:
            showDeleteDialog(itemUri);
            return true;
        default:
            return super.onContextItemSelected(item);
        }
    }

    @Override
    public void onImageLoaded(int id, Uri imageUri, Drawable image) {
        if (BuildConfig.DEBUG) {
            Log.d(TAG, "onImageLoaded(" + id + ", " + imageUri);
        }
        if (id == mShowBigId || id == mShowHighresId) {
            if (BuildConfig.DEBUG) {
                Log.d(TAG, "ID was either showBigId " + mShowBigId + " or highresId " + mShowHighresId);
            }
            image.setAlpha(255);
            mFrame.setImageDrawable(image);
            if (mShowHighresId != id) {
                // the cast below is not ideal, but MAX_VALUE at ~500 loads / second would yield 50
                // days worth of loads. It's unlikely that this will ever roll over unless the ID
                // generator changes to something other than a simple counter.
                if (!mCMEFHandler.sendMessageDelayed(
                        mCMEFHandler.obtainMessage(CMEFHandler.MSG_LOAD_HIGHRES, mShowBigId, 0, imageUri),
                        HIGHRES_LOAD_DELAY)) {
                    Log.e(TAG, "could not send highres load message");
                }
            } else {
                mShowHighresId = NO_PENDING;
            }
        }
    }

    public void setAnimationTiming(int timing) {
        mGallery.setInterframeDelay(timing);
    }

    public int getAnimationTiming() {
        return (int) mGallery.getInterframeDelay();
    }

    public static class CMEFHandler extends Handler {

        private final CardMediaEditFragment mCmef;
        public static final int MSG_LOAD_HIGHRES = 100;

        public CMEFHandler(CardMediaEditFragment cmef) {
            mCmef = cmef;
        }

        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
            case MSG_LOAD_HIGHRES:
                mCmef.loadHighres(msg.arg1, (Uri) msg.obj);
                break;
            }
        }
    }

    private CMEFHandler mCMEFHandler;

    public void loadHighres(int loadId, Uri image) {

        if (mShowBigId == loadId) {
            if (BuildConfig.DEBUG) {
                Log.d(TAG, "Load highres of image ID " + loadId + ": " + image);
            }
            mShowHighresId = mImageCache.getNewID();
            mImageCache.scheduleLoadImage(mShowHighresId, image, HIGHRES_W, HIGHRES_H);
        } else {
            Log.w(TAG, "Did not load highres of image ID " + loadId + ": " + image + " as ID didn't match");
        }
    }

    @Override
    public void onImageLoaded(long id, Uri imageUri, Drawable image) {
        // xxx

    }
}