com.ogunwale.android.app.yaps.ui.PhotosActivity.java Source code

Java tutorial

Introduction

Here is the source code for com.ogunwale.android.app.yaps.ui.PhotosActivity.java

Source

/**
 * Copyright 2013 Olawale Ogunwale
 *
 * 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 com.ogunwale.android.app.yaps.ui;

import java.util.List;
import java.util.Locale;

import com.facebook.Session;
import com.facebook.UiLifecycleHelper;
import com.google.api.services.picasa.model.AlbumEntry;
import com.jess.ui.TwoWayAdapterView;
import com.jess.ui.TwoWayAdapterView.OnItemClickListener;
import com.jess.ui.TwoWayGridView;
import com.ogunwale.android.app.yaps.R;
import com.ogunwale.android.app.yaps.content.FacebookGraphAlbum;
import com.ogunwale.android.app.yaps.content.PhotosProvider;
import com.ogunwale.android.app.yaps.content.PhotosProviderAccess;
import com.ogunwale.android.app.yaps.content.PhotosSourceEnum;
import com.ogunwale.android.app.yaps.content.RemoteDataAlbumListener;
import com.ogunwale.android.app.yaps.content.RemoteDataRequest;
import com.ogunwale.android.app.yaps.content.SettingsManager;

import android.os.Bundle;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.DialogFragment;
import android.app.LoaderManager.LoaderCallbacks;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.CursorLoader;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.Loader;
import android.database.Cursor;
import android.graphics.BitmapFactory;
import android.support.v4.content.LocalBroadcastManager;
import android.util.Log;
import android.view.ActionProvider;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.Window;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.Spinner;
import android.widget.TextView;

/**
 * Activity display photos based on a selected source (Picasa or Facebook)
 *
 * @author ogunwale
 *
 */
public class PhotosActivity extends BaseActivity implements LoaderCallbacks<Cursor>, RemoteDataAlbumListener {

    private static final String sTAG = PhotosActivity.class.getSimpleName();

    /**
     * Intents extras and actions consumed by this activity when it starts.
     *
     * @author ogunwale
     *
     */
    public static interface Extras {
        public static final String INTENT_PREFIX = "com.ogunwale.android.apps.yaps.";

        /**
         * Activity starts with the photo source set to Picasa
         */
        public static final String ACTION_SET_PHOTO_SOURCE_PICASA = INTENT_PREFIX
                + "ACTION_SET_PHOTO_SOURCE_PICASA";

        /**
         * Activity starts with the photo source set to Facebook
         */
        public static final String ACTION_SET_PHOTO_SOURCE_FACEBOOK = INTENT_PREFIX
                + "ACTION_SET_PHOTO_SOURCE_FACEBOOK";

        /**
         * Request for album data refresh is complete.
         */
        public static final String ACTION_REMOTE_ALBUM_REQUEST_COMPLETE = INTENT_PREFIX
                + "ACTION_REMOTE_ALBUM_REQUEST_COMPLETE";
    }

    /**
     * Processes local broadcast for this activity
     */
    private BroadcastReceiver mLocalBroadcastReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            if (intent != null) {
                String action = intent.getAction();

                if (Extras.ACTION_SET_PHOTO_SOURCE_FACEBOOK.equals(action)
                        && mSourceSelection != PhotosSourceEnum.FACEBOOK) {
                    changeSource(PhotosSourceEnum.FACEBOOK);
                } else if (Extras.ACTION_SET_PHOTO_SOURCE_PICASA.equals(action)
                        && mSourceSelection != PhotosSourceEnum.PICASA) {
                    changeSource(PhotosSourceEnum.PICASA);
                } else if (Extras.ACTION_REMOTE_ALBUM_REQUEST_COMPLETE.equals(action)) {
                    mGettingRemoteData = false;
                    // invalidate options menu so we can hide the refresh
                    // button.
                    invalidateOptionsMenu();
                    // hide progress spinner.
                    setProgressBarIndeterminateVisibility(false);
                }
            }
        }
    };

    private static PhotosSourceEnum mSourceSelection;

    private PhotosSimpleCursorAdapter mAdapter;

    private TwoWayGridView mGridView;

    private boolean mGettingRemoteData = false;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);

        mSourceSelection = SettingsManager.getInstance(getApplicationContext()).getAlbumSelection();

        setContentView(R.layout.activity_photos);

        // Set-up cursor adapter
        mAdapter = new PhotosSimpleCursorAdapter(this);

        // Set-up thumbnail grid
        mGridView = (TwoWayGridView) findViewById(R.id.photo_gridview);
        mGridView.setAdapter(mAdapter);
        mGridView.setOnItemClickListener(new OnItemClickListener() {
            @Override
            public void onItemClick(TwoWayAdapterView<?> parent, View view, int position, long id) {
                Cursor cursor = mAdapter.getCursor();
                if (cursor.moveToPosition(position)) {
                    DialogFragment df = TransferDialogFragment.newInstance(cursor, id);
                    df.show(getFragmentManager(), "transfer_dialog");
                } else {
                    Log.e(sTAG, "Can not move cursor to: " + position);
                }
            }
        });

        // Prepare the database loader.
        getLoaderManager().initLoader(0, null, this);

        // Register for local broadcasts
        IntentFilter iFilter = new IntentFilter();
        iFilter.addAction(Extras.ACTION_SET_PHOTO_SOURCE_FACEBOOK);
        iFilter.addAction(Extras.ACTION_SET_PHOTO_SOURCE_PICASA);
        iFilter.addAction(Extras.ACTION_REMOTE_ALBUM_REQUEST_COMPLETE);
        LocalBroadcastManager.getInstance(getApplicationContext()).registerReceiver(mLocalBroadcastReceiver,
                iFilter);
    }

    public static class TransferDialogFragment extends DialogFragment {

        private static final String ROW_ID = "row_id";
        private static final String IMAGE_BLOB = "image_blob";
        private static final String TITLE = "title";
        private static final String LOCATION = "location";
        private static final String PHOTOS_COUNT = "photos_count";

        public static TransferDialogFragment newInstance(Cursor cursor, long rowId) {
            TransferDialogFragment frag = new TransferDialogFragment();

            Bundle args = new Bundle();
            args.putLong(ROW_ID, rowId);
            args.putByteArray(IMAGE_BLOB, cursor
                    .getBlob(cursor.getColumnIndexOrThrow(PhotosProvider.AlbumTable.COLUMN_NAME_COVER_BITMAP)));
            args.putString(TITLE,
                    cursor.getString(cursor.getColumnIndexOrThrow(PhotosProvider.AlbumTable.COLUMN_NAME_TITLE)));
            args.putString(LOCATION,
                    cursor.getString(cursor.getColumnIndexOrThrow(PhotosProvider.AlbumTable.COLUMN_NAME_LOCATION)));
            args.putInt(PHOTOS_COUNT, cursor
                    .getInt(cursor.getColumnIndexOrThrow(PhotosProvider.AlbumTable.COLUMN_NAME_PHOTOS_COUNT)));

            frag.setArguments(args);
            return frag;
        }

        @Override
        public Dialog onCreateDialog(Bundle savedInstanceState) {
            final long rowId = getArguments().getLong(ROW_ID);

            LayoutInflater li = LayoutInflater.from(getActivity());
            View view = li.inflate(R.layout.layout_transfer_dialog, null);

            ImageView image = (ImageView) view.findViewById(R.id.transfer_dialog_image);
            byte[] blob = getArguments().getByteArray(IMAGE_BLOB);
            if (blob != null && blob.length > 0)
                image.setImageBitmap(BitmapFactory.decodeByteArray(blob, 0, blob.length));

            TextView text = (TextView) view.findViewById(R.id.transfer_dialog_text);
            String title = getArguments().getString(TITLE);
            String location = getArguments().getString(LOCATION);
            int count = getArguments().getInt(PHOTOS_COUNT);
            text.setText(location + "\n" + count);

            AlertDialog.Builder dialog = new AlertDialog.Builder(getActivity());
            dialog.setTitle(title);
            dialog.setView(view);
            dialog.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    dialog.dismiss();
                }
            });
            int positiveString = (mSourceSelection == PhotosSourceEnum.PICASA) ? R.string.transfer_to_facebook
                    : R.string.transfer_to_picasa;
            dialog.setPositiveButton(positiveString, new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    // TODO
                }
            });

            return dialog.create();
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.action_bar_sort_photos_providers, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
        case R.id.menu_item_refresh: {
            mGettingRemoteData = true;
            // Request/update album data from source
            updateAlbumData();
            // invalidate options menu so we can hide the refresh button.
            invalidateOptionsMenu();
            // display progress spinner.
            setProgressBarIndeterminateVisibility(true);
            return true;
        }
        }
        return super.onOptionsItemSelected(item);
    }

    @Override
    public boolean onPrepareOptionsMenu(Menu menu) {
        if (mGettingRemoteData)
            menu.removeItem(R.id.menu_item_refresh);
        else if (menu.findItem(R.id.menu_item_refresh) == null)
            menu.add(R.id.menu_item_refresh);

        return super.onPrepareOptionsMenu(menu);
    }

    /**
     * Updates album data
     */
    private void updateAlbumData() {
        switch (mSourceSelection) {
        case FACEBOOK:
        case PICASA: {
            RemoteDataRequest.RequestType requestType = (mSourceSelection == PhotosSourceEnum.FACEBOOK)
                    ? RemoteDataRequest.RequestType.FACEBOOK_ALBUMS
                    : RemoteDataRequest.RequestType.PICASA_ALBUMS;

            new RemoteDataRequest(this, true, requestType, this);
            break;
        }
        case INVALID:
        default:
            break;

        }
    }

    @Override
    public void RequestComplete(Status status) {
        LocalBroadcastManager.getInstance(this)
                .sendBroadcast(new Intent(Extras.ACTION_REMOTE_ALBUM_REQUEST_COMPLETE));
    }

    @Override
    public void facebookAlbums(List<FacebookGraphAlbum> albums, Session session) {
        if (albums != null) {
            for (FacebookGraphAlbum album : albums) {
                PhotosProviderAccess.Album.updateIfChanged(getContentResolver(), album, session);
            }
        }
    }

    @Override
    public void picasaAlbums(List<AlbumEntry> albums) {
        if (albums != null) {
            for (AlbumEntry album : albums) {
                PhotosProviderAccess.Album.updateIfChanged(getContentResolver(), album);
            }
        }
    }

    /**
     * Class implements action provider used to display photo source and sort
     * selection in the action bar.
     *
     * @author ogunwale
     *
     */
    public static class PhotosActionProvider extends ActionProvider {

        private final Context mContext;

        public PhotosActionProvider(Context context) {
            super(context);
            mContext = context;
        }

        @Override
        public View onCreateActionView() {
            LayoutInflater li = LayoutInflater.from(mContext);
            View view = li.inflate(R.layout.action_bar_sort_photos_providers, null);

            // Set-up source selection spinner
            Spinner sourceSpinner = (Spinner) view.findViewById(R.id.photo_source);
            ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(mContext, R.array.sources,
                    android.R.layout.simple_spinner_dropdown_item);
            adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
            sourceSpinner.setAdapter(adapter);
            sourceSpinner.setSelection(mSourceSelection.getValue());
            sourceSpinner.setOnItemSelectedListener(new OnItemSelectedListener() {

                @Override
                public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
                    if (position != mSourceSelection.getValue()) {
                        Intent intent = new Intent();

                        switch (PhotosSourceEnum.getEnum(position)) {
                        case FACEBOOK:
                            intent.setAction(Extras.ACTION_SET_PHOTO_SOURCE_FACEBOOK);
                            break;
                        case PICASA:
                            intent.setAction(Extras.ACTION_SET_PHOTO_SOURCE_PICASA);
                            break;
                        case INVALID:
                        default:
                            break;
                        }

                        if (intent.getAction() != null)
                            LocalBroadcastManager.getInstance(mContext).sendBroadcast(intent);
                    }
                }

                @Override
                public void onNothingSelected(AdapterView<?> parent) {
                }
            });

            return view;
        }
    }

    /**
     * Change photo source
     */
    private void changeSource(PhotosSourceEnum source) {
        if (source != mSourceSelection) {
            mSourceSelection = source;
            SettingsManager.getInstance(getApplicationContext()).setAlbumSelection(mSourceSelection);
            updateAlbumData();
            getLoaderManager().restartLoader(0, null, this);
        }
    }

    @Override
    public Loader<Cursor> onCreateLoader(int id, Bundle args) {
        // This is called when a new Loader needs to be created. We
        // only has one Loader, so we don't care about the ID.

        //@formatter:off
        String[] projection = new String[] { PhotosProvider.AlbumTable._ID,
                PhotosProvider.AlbumTable.COLUMN_NAME_COVER_BITMAP, PhotosProvider.AlbumTable.COLUMN_NAME_TITLE,
                PhotosProvider.AlbumTable.COLUMN_NAME_PHOTOS_COUNT,
                PhotosProvider.AlbumTable.COLUMN_NAME_LOCATION };
        String selection = String.format(Locale.getDefault(), "%s=?", PhotosProvider.AlbumTable.COLUMN_NAME_SOURCE);
        String[] selectionArgs = new String[] { String.valueOf(mSourceSelection.getValue()) };
        //@formatter:on

        // Create and return a CursorLoader that will take care of
        // creating a Cursor for the data being displayed.
        return new CursorLoader(this, PhotosProvider.AlbumTable.CONTENT_URI, projection, selection, selectionArgs,
                null);
    }

    @Override
    public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
        // Swap the new cursor in. (The framework will take care of closing the
        // old cursor once we return.)
        mAdapter.swapCursor(data);
    }

    @Override
    public void onLoaderReset(Loader<Cursor> loader) {
        // This is called when the last Cursor provided to onLoadFinished()
        // above is about to be closed. We need to make sure we are no longer
        // using it.
        mAdapter.swapCursor(null);
    }

    @Override
    protected void onDestory() {
        super.onDestroy();
        LocalBroadcastManager.getInstance(getApplicationContext()).unregisterReceiver(mLocalBroadcastReceiver);
    }

}