com.yattatech.dbtc.activity.MainScreen.java Source code

Java tutorial

Introduction

Here is the source code for com.yattatech.dbtc.activity.MainScreen.java

Source

/*
 * Copyright (c) 2014, Yatta Tech and/or its affiliates. All rights reserved.
 * YATTATECH PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 */
package com.yattatech.dbtc.activity;

import static com.yattatech.dbtc.Constants.RESTORE_KEY;
import static com.yattatech.dbtc.Constants.TASK_KEY;
import static com.yattatech.dbtc.activity.AsyncMessages.ADD_NEW_TASK_ACTION;
import static com.yattatech.dbtc.activity.AsyncMessages.ADD_NEW_TASK_FAILED;
import static com.yattatech.dbtc.activity.AsyncMessages.ADD_NEW_TASK_SUCCESS;
import static com.yattatech.dbtc.activity.AsyncMessages.BACKUP_RESTORE_ACTION;
import static com.yattatech.dbtc.activity.AsyncMessages.BACKUP_RESTORE_FAILED;
import static com.yattatech.dbtc.activity.AsyncMessages.BACKUP_RESTORE_SUCCESS;
import static com.yattatech.dbtc.activity.AsyncMessages.EDIT_TASK_ACTION;
import static com.yattatech.dbtc.activity.AsyncMessages.EDIT_TASK_FAILED;
import static com.yattatech.dbtc.activity.AsyncMessages.EDIT_TASK_SUCCESS;
import static com.yattatech.dbtc.activity.AsyncMessages.REMOVE_TASK_ACTION;
import static com.yattatech.dbtc.activity.AsyncMessages.REMOVE_TASK_FAILED;
import static com.yattatech.dbtc.activity.AsyncMessages.REMOVE_TASK_SUCCESS;

import java.util.List;

import org.apache.commons.io.IOUtils;

import android.app.ActionBar;
import android.app.AlertDialog;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.Bitmap;
import android.graphics.Point;
import android.graphics.drawable.ColorDrawable;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.Parcelable;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.ContextThemeWrapper;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.AdapterContextMenuInfo;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ImageView;
import android.widget.ListView;

import com.dropbox.client2.DropboxAPI;
import com.dropbox.client2.DropboxAPI.DropboxInputStream;
import com.dropbox.client2.DropboxAPI.Entry;
import com.dropbox.client2.android.AndroidAuthSession;
import com.dropbox.client2.exception.DropboxServerException;
import com.dropbox.client2.session.AppKeyPair;
import com.mobeta.android.dslv.DragSortListView;
import com.yattatech.dbtc.Constants;
import com.yattatech.dbtc.R;
import com.yattatech.dbtc.adapter.TaskListAdapter;
import com.yattatech.dbtc.domain.Task;
import com.yattatech.dbtc.io.BackupInputStream;
import com.yattatech.dbtc.log.Debug;
import com.yattatech.dbtc.receiver.Broadcaster;
import com.yattatech.dbtc.util.DateUtil;
import com.yattatech.dbtc.util.StringUtils;

/**
 * Main Screen where the user can add/edit and delete 
 * items into the don't break the chain.
 * 
 * @author Adriano Braga Alencar (adrianobragaalencar@gmail.com)
 *
 */
public final class MainScreen extends GenericFragmentActivity {

    private enum DropBoxOp {
        SYNC, RESTORE, UNKNOWN
    }

    private DropboxAPI<AndroidAuthSession> mDropboxAPI;
    private TaskListAdapter mTaskListAdapter;
    private DragSortListView mTaskList;
    private int mIndex;
    private String mToken;
    private UploadBackupAsyncTask mUploadBackupAsyncTask;
    private RestoreBackupAsyncTask mRestoreBackupAsyncTask;
    private DropBoxOp mDropBoxOp;
    private final OnItemClickListener mTaskListListener = new OnItemClickListener() {

        /*
         * (non-Javadoc)
         * @see android.widget.AdapterView.OnItemClickListener#onItemClick(android.widget.AdapterView, android.view.View, int, long)
         */
        @Override
        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
            if (Debug.isDebugable()) {
                Debug.d(mTag,
                        "onItemClick parent=" + parent + " view=" + view + " position=" + position + " id=" + id);
            }
            mIndex = position;
            final Task task = getSelectedTask(false);
            if (task != null) {
                if (Debug.isDebugable()) {
                    Debug.d(mTag, "chaining task=" + task);
                }
                startActivityWithTask(task, task.mDefined ? FixedChainTaskScreen.class : ChainTaskScreen.class);
            }
        }
    };
    private DragSortListView.DropListener mDropListener = new DragSortListView.DropListener() {

        /*
         * (non-Javadoc)
         * @see com.mobeta.android.dslv.DragSortListView.DropListener#drop(int, int)
         */
        @Override
        public void drop(int from, int to) {

            final Task item = mTaskListAdapter.getItem(from);
            mTaskListAdapter.removeElement(item);
            mTaskListAdapter.insertElementAt(item, to);
        }
    };
    private DragSortListView.DragScrollProfile mScrollProfile = new DragSortListView.DragScrollProfile() {

        /*
         * (non-Javadoc)
         * @see com.mobeta.android.dslv.DragSortListView.DragScrollProfile#getSpeed(float, long)
         */
        @Override
        public float getSpeed(float w, long t) {
            if (w > 0.8F) {
                return ((float) mTaskListAdapter.getCount()) / 0.001F;
            }
            return 10.0F * w;
        }
    };
    private final Handler mH = new Handler() {

        /*
         * (non-Javadoc)
         * @see android.os.Handler#handleMessage(android.os.Message)
         */
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
            case ADD_NEW_TASK_SUCCESS:
                Debug.d(mTag, "task added successfully, let's update ui");
                mTaskListAdapter.addElement((Task) msg.obj);
                break;
            case ADD_NEW_TASK_FAILED:
                Debug.d(mTag, "task add failed");
                showMessage(R.string.add_task_fail);
                break;
            case EDIT_TASK_SUCCESS:
                Debug.d(mTag, "task edited successfully, let's update ui");
                final List<Task> tasks = mTaskListAdapter.getSource();
                final Task task = (Task) msg.obj;
                for (int i = 0, s = tasks.size(); i < s; ++i) {
                    if (task.mId == tasks.get(i).mId) {
                        tasks.set(i, task);
                        mTaskListAdapter.notifyDataSetChanged();
                        break;
                    }
                }
                break;
            case EDIT_TASK_FAILED:
                Debug.d(mTag, "task edit failed");
                showMessage(R.string.edit_task_fail);
                break;
            case REMOVE_TASK_SUCCESS:
                Debug.d(mTag, "task removed successfully, let's update ui");
                mTaskListAdapter.removeElement((Task) msg.obj);
                break;
            case REMOVE_TASK_FAILED:
                break;
            case BACKUP_RESTORE_SUCCESS:
                Debug.d(mTag, "Backup restore done successfully");
                mTaskListAdapter.clear();
                // getting newest restored list
                mTaskListAdapter.setElements(FACADE.getTasks());
                break;
            case BACKUP_RESTORE_FAILED:
                Debug.d(mTag, "Backup restore has failed");
                showMessage(R.string.lab_data_restore_failed);
                break;
            }
        }
    };
    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {

        /*
         * (non-Javadoc)
         * @see android.content.BroadcastReceiver#onReceive(android.content.Context, android.content.Intent)
         */
        @Override
        public void onReceive(Context context, Intent intent) {
            final String action = intent.getAction();
            final Task task = intent.getParcelableExtra(TASK_KEY);
            if (Debug.isDebugable()) {
                Debug.d(mTag, "action=" + action + " task=" + task);
            }
            if (ADD_NEW_TASK_ACTION.equals(action)) {
                sendMsg(task == null ? ADD_NEW_TASK_FAILED : ADD_NEW_TASK_SUCCESS, task);
            } else if (EDIT_TASK_ACTION.equals(action)) {
                sendMsg(task == null ? EDIT_TASK_FAILED : EDIT_TASK_SUCCESS, task);
            } else if (REMOVE_TASK_ACTION.equals(action)) {
                sendMsg(task == null ? REMOVE_TASK_FAILED : REMOVE_TASK_SUCCESS, task);
            } else if (BACKUP_RESTORE_ACTION.equals(action)) {
                if (mProgressDialog != null) {
                    mProgressDialog.dismiss();
                }
                final boolean result = intent.getBooleanExtra(RESTORE_KEY, false);
                sendMsg(result ? BACKUP_RESTORE_SUCCESS : BACKUP_RESTORE_FAILED, null);
            }
        }
    };
    private final BroadcastReceiver mLocaleChangedReceiver = new BroadcastReceiver() {

        /*
         * (non-Javadoc)
         * @see android.content.BroadcastReceiver#onReceive(android.content.Context, android.content.Intent)
         */
        @Override
        public void onReceive(Context context, Intent intent) {
            final String action = intent.getAction();
            if (Debug.isDebugable()) {
                Debug.d(mTag, "action=" + action);
            }
            if (Intent.ACTION_LOCALE_CHANGED.equals(action)) {
                Debug.d(mTag, "Update tasklist description");
                // A little expensive operation but not common to user
                // go back and forth in locale change screen, it's supposed
                // to happen very rarely into the entire app lifecycle
                DateUtil.updateLocale();
                mTaskListAdapter.setElements(FACADE.getTasks());
            }
        }
    };
    private IntentFilter mFilter;
    private IntentFilter mLocaleChangedFilter;

    /*
     * (non-Javadoc)
     * @see com.yattatech.dbtc.activity.GenericFragmentActivity#onCreate(android.os.Bundle)
     */
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.layout_main_screen);
        final int color = getResources().getColor(R.color.grey2);
        final ActionBar actionBar = getActionBar();
        mFilter = new IntentFilter();
        mLocaleChangedFilter = new IntentFilter();
        mTaskList = (DragSortListView) findViewById(R.id.taskList);
        mTaskListAdapter = new TaskListAdapter(this);
        final String appKey = getString(R.string.dropbox_key);
        final String appSecret = getString(R.string.dropbox_secret);
        final AppKeyPair pair = new AppKeyPair(appKey, appSecret);
        final AndroidAuthSession session = new AndroidAuthSession(pair);
        mDropboxAPI = new DropboxAPI<AndroidAuthSession>(session);
        mToken = FACADE.getDropBoxToken();
        mTaskList.setAdapter(mTaskListAdapter);
        mTaskList.setOnItemClickListener(mTaskListListener);
        mTaskList.setDropListener(mDropListener);
        mTaskList.setDragScrollProfile(mScrollProfile);
        mTaskList.setFloatViewManager(new MainViewManager(mTaskList));
        mFilter.addAction(ADD_NEW_TASK_ACTION);
        mFilter.addAction(EDIT_TASK_ACTION);
        mFilter.addAction(REMOVE_TASK_ACTION);
        mFilter.addAction(BACKUP_RESTORE_ACTION);
        mLocaleChangedFilter.addAction(Intent.ACTION_LOCALE_CHANGED);
        actionBar.setIcon(R.drawable.ic_task);
        actionBar.setTitle(R.string.app_name);
        actionBar.setBackgroundDrawable(new ColorDrawable(color));
        Broadcaster.registerLocalReceiver(mReceiver, mFilter);
        registerReceiver(mLocaleChangedReceiver, mLocaleChangedFilter);
        registerForContextMenu(mTaskList);
        final List<Task> tasks = FACADE.getTasks();
        mTaskListAdapter.setElements(FACADE.restoreDataOrder(tasks));
    }

    /*
     * (non-Javadoc)
     * @see android.app.Activity#onCreateOptionsMenu(android.view.Menu)
     */
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        super.onCreateOptionsMenu(menu);
        getMenuInflater().inflate(R.menu.main_menu, menu);
        return true;
    }

    /*
     * (non-Javadoc)
     * @see android.app.Activity#onCreateContextMenu(android.view.ContextMenu, android.view.View, android.view.ContextMenu.ContextMenuInfo)
     */
    @Override
    public void onCreateContextMenu(ContextMenu menu, View view, ContextMenuInfo menuInfo) {
        super.onCreateContextMenu(menu, view, menuInfo);
        final AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo;
        mIndex = info.position;
        final Task task = getSelectedTask(false);
        final int menuRes = ((task == null) || (!task.mFinished)) ? R.menu.context_menu
                : R.menu.disable_context_menu;
        getMenuInflater().inflate(menuRes, menu);
    }

    /*
     * (non-Javadoc)
     * @see com.yattatech.dbtc.activity.GenericFragmentActivity#onResume()
     */
    @Override
    protected void onResume() {
        super.onResume();
        // TODO
        // FIXME
        // XXX
        // It's expensive so make more tests here to see the impact on
        // performance
        mTaskListAdapter.notifyDataSetChanged();
        if (mDropBoxOp == DropBoxOp.UNKNOWN) {
            // Workaround to avoid reentrant method whenever
            // user go back after has authenticated
            return;
        }
        if (mDropboxAPI.getSession().authenticationSuccessful()) {
            mDropboxAPI.getSession().finishAuthentication();
            mToken = mDropboxAPI.getSession().getOAuth2AccessToken();
            FACADE.setDropBoxToken(mToken);
            if (mDropBoxOp == DropBoxOp.SYNC) {
                Debug.d(mTag, "syncing data");
                startUpload();
            } else if (mDropBoxOp == DropBoxOp.RESTORE) {
                Debug.d(mTag, "restoring data");
                restoreContent();
            } else {
                Debug.d(mTag, "unknown state");
            }
        }
    }

    /*
     * (non-Javadoc)
     * @see android.app.Activity#onOptionsItemSelected(android.view.MenuItem)
     */
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        if (Debug.isDebugable()) {
            Debug.d(mTag, "onOptionsItemSelected=" + item);
        }
        switch (item.getItemId()) {
        case R.id.addItem: {
            Debug.d(mTag, "creating a new task into the chain");
            startNewActivity(NewTaskScreen.class);
            break;
        }
        case R.id.editItem: {
            Debug.d(mTag, "editing task into the chain");
            final Task task = getSelectedTask(false);
            if (task != null) {
                startActivityWithTask(task, NewTaskScreen.class);
            }
            break;
        }
        case R.id.removeItem: {
            Debug.d(mTag, "removing a task from the chain");
            final Task task = getSelectedTask(true);
            if (task != null) {
                FACADE.removeTask(task);
            }
            break;
        }
        case R.id.syncItem: {
            Debug.d(mTag, "calling sync screen");
            if (isConnected()) {
                syncContent();
            } else {
                showMessage(R.string.lab_no_connection);
            }
            break;
        }
        case R.id.restoreItem: {
            Debug.d(mTag, "restoring backup items");
            if (isConnected()) {
                restoreContent();
            } else {
                showMessage(R.string.lab_no_connection);
            }
            break;
        }
        case R.id.logoffItem: {
            Debug.d(mTag, "logoff from DropBox");
            dropboxLogout();
            break;
        }
        case R.id.creditsItem: {
            Debug.d(mTag, "calling credits screen");
            break;
        }
        case R.id.settingsItem: {
            Debug.d(mTag, "calling settings screen");
            break;
        }
        case R.id.exitItem: {
            Debug.d(mTag, "exiting DBTC app");
            finish();
            break;
        }
        default: {
            // It's not supposed to reach here
            assert false;
        }
        }
        return true;
    }

    /*
     * (non-Javadoc)
     * @see android.app.Activity#onContextItemSelected(android.view.MenuItem)
     */
    @Override
    public boolean onContextItemSelected(MenuItem item) {
        final AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
        mIndex = info.position;
        if (Debug.isDebugable()) {
            Debug.d(mTag, "onContextItemSelected item=" + item + " view=" + info.targetView + " position="
                    + info.position + " id=" + info.id);
        }
        switch (item.getItemId()) {
        case R.id.editItem: {
            Debug.d(mTag, "editing task into the chain");
            final Task task = getSelectedTask(false);
            if (task != null) {
                startActivityWithTask(task, NewTaskScreen.class);
            }
            break;
        }
        case R.id.removeItem: {
            Debug.d(mTag, "removing a task from the chain");
            final Task task = getSelectedTask(true);
            if (task != null) {
                FACADE.removeTask(task);
            }
            break;
        }
        case R.id.finishItem: {
            Debug.d(mTag, "Marking task as finished");
            final Task task = getSelectedTask(true);
            if (!task.mFinished) {
                task.mFinished = true;
                FACADE.editTask(task);
            }
            break;
        }
        default: {
            // It's not supposed to reach here
            assert false;
        }
        }
        return true;
    }

    /*
     * (non-Javadoc)
     * @see com.yattatech.dbtc.activity.GenericFragmentActivity#onDestroy()
     */
    @Override
    protected void onDestroy() {
        super.onDestroy();
        Broadcaster.unregisterLocalReceiver(mReceiver);
        unregisterReceiver(mLocaleChangedReceiver);
    }

    /*
      * (non-Javadoc)
      * @see com.yattatech.dbtc.activity.GenericFragmentActivity#onBackPressed()
      */
    @Override
    public void onBackPressed() {
        FACADE.saveDataOrder(mTaskListAdapter.getSource());
        super.onBackPressed();
    }

    public boolean isTaskChecked(Task task) {
        return FACADE.isTaskChecked(task);
    }

    public int getChecksCountByTask(final Task task) {
        return FACADE.getChecksCountByTask(task);
    }

    private Task getSelectedTask(boolean remove) {
        Task task = null;
        if (mTaskListAdapter.hasElements()) {
            task = mTaskListAdapter.getItem(mIndex);
            if (remove) {
                final int count = mTaskListAdapter.getCount() - 1; // pretend to act as object has been already removed
                if (count == 0) { // nothing to do
                    Debug.d(mTag, "TaskList empty");
                } else if (count <= mIndex) { // last index element 
                    mIndex = count - 1;
                } else { // nothing to do neither
                    Debug.d(mTag, "Index is between 0 and maxSize");
                }
            }
        }
        return task;
    }

    private void dropboxLogout() {
        FACADE.dropboxLogout();
        mToken = null;
        mDropboxAPI.getSession().unlink();
    }

    private void startActivityWithTask(final Task task, Class<?> clazz) {
        final Intent intent = new Intent(this, clazz);
        intent.putExtra(Constants.TASK_KEY, (Parcelable) task);
        startActivity(intent);
    }

    private void sendMsg(final int what, final Task task) {
        final Message msg = mH.obtainMessage(what, task);
        mH.sendMessage(msg);
    }

    private void syncContent() {
        mDropBoxOp = DropBoxOp.SYNC;
        if (mDropboxAPI.getSession().isLinked()) {
            Debug.d(mTag, "DropBox already linked");
            startUpload();
        } else {
            mToken = FACADE.getDropBoxToken();
            if (StringUtils.isEmpty(mToken)) {
                mDropboxAPI.getSession().startOAuth2Authentication(this);
            } else {
                mDropboxAPI.getSession().setOAuth2AccessToken(mToken);
                startUpload();
            }
        }
    }

    private void restoreContent() {
        mDropBoxOp = DropBoxOp.RESTORE;
        if (mDropboxAPI.getSession().isLinked()) {
            Debug.d(mTag, "DropBox already linked");
            startRestore();
        } else {
            mToken = FACADE.getDropBoxToken();
            if (StringUtils.isEmpty(mToken)) {
                mDropboxAPI.getSession().startOAuth2Authentication(this);
            } else {
                mDropboxAPI.getSession().setOAuth2AccessToken(mToken);
                startRestore();
            }
        }
    }

    private void startUpload() {
        mDropBoxOp = DropBoxOp.UNKNOWN;
        if (!isConnected()) {
            showMessage(R.string.lab_no_connection);
        } else if (FACADE.hasTasks()) {
            cancelAsyncTask(mUploadBackupAsyncTask);
            mUploadBackupAsyncTask = new UploadBackupAsyncTask();
            mUploadBackupAsyncTask.execute();
        } else {
            Debug.d(mTag, "Has no task to be sync");
            showMessage(R.string.lab_no_data_sync);
        }
    }

    private void startRestoreAsync() {
        cancelAsyncTask(mRestoreBackupAsyncTask);
        mRestoreBackupAsyncTask = new RestoreBackupAsyncTask();
        mRestoreBackupAsyncTask.execute();
    }

    private void startRestore() {
        mDropBoxOp = DropBoxOp.UNKNOWN;
        if (!isConnected()) {
            showMessage(R.string.lab_no_connection);
        } else if (FACADE.hasTasks()) {
            showRestoreMessage();
        } else {
            Debug.d(mTag, "No data to be lost, restore anyway");
            startRestoreAsync();
        }
    }

    private void showRestoreMessage() {
        new AlertDialog.Builder(new ContextThemeWrapper(this, R.style.AlertDialogCustom))
                .setTitle(R.string.lab_confirm).setMessage(R.string.lab_data_lost).setCancelable(false)
                .setPositiveButton(R.string.lab_yes, new DialogInterface.OnClickListener() {

                    /*
                     * (non-Javadoc)
                     * @see android.content.DialogInterface.OnClickListener#onClick(android.content.DialogInterface, int)
                     */
                    @Override
                    public void onClick(DialogInterface dialog, int buttonId) {
                        startRestoreAsync();
                    }
                }).setNegativeButton(R.string.lab_no, new DialogInterface.OnClickListener() {

                    /*
                     * (non-Javadoc)
                     * @see android.content.DialogInterface.OnClickListener#onClick(android.content.DialogInterface, int)
                     */
                    @Override
                    public void onClick(DialogInterface dialog, int buttonId) {
                    }
                }).create().show();
    }

    private final class RestoreBackupAsyncTask extends AsyncTask<Void, Long, List<Task>> {

        private String mDropboxErrorMsg;

        /*
         * (non-Javadoc)
         * @see android.os.AsyncTask#onPreExecute()
         */
        @Override
        protected void onPreExecute() {
            showSpinnerProgressBar(R.string.lab_restore_title);
        }

        /*
         * (non-Javadoc)
         * @see android.os.AsyncTask#doInBackground(java.lang.Object[])
         */
        @Override
        protected List<Task> doInBackground(Void... params) {
            DropboxInputStream in = null;
            try {
                in = mDropboxAPI.getFileStream(Constants.BACKUP_FILE_NAME, null);
                String json = IOUtils.toString(in, "UTF-8");
                return FACADE.getTasksFromJson(json);
            } catch (DropboxServerException e) {
                Debug.e(mTag, "Failed:", e);
                Debug.e(mTag, "parsedResponse" + e.parsedResponse);
                mDropboxErrorMsg = (String) e.parsedResponse.get("error");
            } catch (Exception e) {
                Debug.e(mTag, "Failed:", e);
            } finally {
                IOUtils.closeQuietly(in);
            }
            return null;
        }

        /*
         * (non-Javadoc)
         * @see android.os.AsyncTask#onPostExecute(java.lang.Object)
         */
        @Override
        protected void onPostExecute(List<Task> result) {
            if (mDropboxErrorMsg != null) {
                mProgressDialog.dismiss();
                showMessage(R.string.backup_fail_detail, mDropboxErrorMsg);
            } else if (result == null) {
                mProgressDialog.dismiss();
                showMessage(R.string.lab_data_restore_failed);
            } else if (result.isEmpty()) {
                mProgressDialog.dismiss();
                showMessage(R.string.lab_no_data_restore);
            } else {
                FACADE.restoreTasks(result);
            }
        }
    }

    private final class UploadBackupAsyncTask extends AsyncTask<Void, Void, Entry> {

        /*
         * (non-Javadoc)
         * @see android.os.AsyncTask#onPreExecute()
         */
        @Override
        protected void onPreExecute() {
            showSpinnerProgressBar(R.string.lab_sync_title);
        }

        /*
         * (non-Javadoc)
         * @see android.os.AsyncTask#doInBackground(java.lang.Object[])
         */
        @Override
        protected Entry doInBackground(Void... params) {
            Entry entry = null;
            BackupInputStream in = null;
            try {
                in = FACADE.getBackupInputStream();
                entry = mDropboxAPI.putFileOverwrite(Constants.BACKUP_FILE_NAME, in, in.mLength, null);
            } catch (Exception e) {
                Debug.e(mTag, "Failed:", e);
            } finally {
                IOUtils.closeQuietly(in);
            }
            return entry;
        }

        /*
         * (non-Javadoc)
         * @see android.os.AsyncTask#onPostExecute(java.lang.Object)
         */
        @Override
        protected void onPostExecute(Entry result) {
            mProgressDialog.dismiss();
            if (result == null) {
                showMessage(R.string.backup_fail);
            } else {
                showMessage(R.string.backup_success);
            }
        }
    }

    private final class MainViewManager implements DragSortListView.FloatViewManager {

        private Bitmap mFloatBitmap;
        private ImageView mImageView;
        private ViewGroup.LayoutParams mLayoutParams;
        private final ListView mListView;

        public MainViewManager(ListView listView) {
            mListView = listView;
        }

        /*
         * (non-Javadoc)
         * @see com.mobeta.android.dslv.DragSortListView.FloatViewManager#onCreateFloatView(int)
         */
        @Override
        public View onCreateFloatView(int position) {
            final View view = mListView
                    .getChildAt(position + mListView.getHeaderViewsCount() - mListView.getFirstVisiblePosition());
            if (view == null) {
                return null;
            }
            view.setPressed(false);

            // Create a copy of the drawing cache so that it does not get
            // recycled by the framework when the list tries to clean up memory
            //v.setDrawingCacheQuality(View.DRAWING_CACHE_QUALITY_HIGH);
            view.setDrawingCacheEnabled(true);
            mFloatBitmap = Bitmap.createBitmap(view.getDrawingCache());
            view.setDrawingCacheEnabled(false);
            if (mImageView == null) {
                mImageView = new ImageView(mListView.getContext());
            }
            if (mLayoutParams == null) {
                mLayoutParams = new ViewGroup.LayoutParams(view.getWidth(), view.getHeight());
            }
            mImageView.setImageBitmap(mFloatBitmap);
            mImageView.setLayoutParams(mLayoutParams);
            return mImageView;
        }

        /*
         * (non-Javadoc)
         * @see com.mobeta.android.dslv.DragSortListView.FloatViewManager#onDragFloatView(android.view.View, android.graphics.Point, android.graphics.Point)
         */
        @Override
        public void onDragFloatView(View floatView, Point position, Point touch) {
        }

        /*
         * (non-Javadoc)
         * @see com.mobeta.android.dslv.DragSortListView.FloatViewManager#onDestroyFloatView(android.view.View)
         */
        @Override
        public void onDestroyFloatView(View floatView) {
            ((ImageView) floatView).setImageDrawable(null);
            mFloatBitmap.recycle();
            mFloatBitmap = null;
        }
    }
}