NotesListActivity.java

    /*
     * Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net)
     *
     * 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 net.micode.notes.ui;

    import android.app.Activity;
    import android.app.AlertDialog;
    import android.app.Dialog;
    import android.appwidget.AppWidgetManager;
    import android.content.AsyncQueryHandler;
    import android.content.ContentResolver;
    import android.content.ContentValues;
    import android.content.Context;
    import android.content.DialogInterface;
    import android.content.Intent;
    import android.content.SharedPreferences;
    import android.database.Cursor;
    import android.graphics.Bitmap;
    import android.graphics.BitmapFactory;
    import android.net.Uri;
    import android.os.AsyncTask;
    import android.os.Bundle;
    import android.preference.PreferenceManager;
    import android.text.Editable;
    import android.text.Spannable;
    import android.text.SpannableString;
    import android.text.TextUtils;
    import android.text.TextWatcher;
    import android.text.style.ImageSpan;
    import android.util.Log;
    import android.view.ActionMode;
    import android.view.ContextMenu;
    import android.view.ContextMenu.ContextMenuInfo;
    import android.view.Display;
    import android.view.HapticFeedbackConstants;
    import android.view.LayoutInflater;
    import android.view.Menu;
    import android.view.MenuItem;
    import android.view.MenuItem.OnMenuItemClickListener;
    import android.view.MotionEvent;
    import android.view.View;
    import android.view.View.OnClickListener;
    import android.view.View.OnCreateContextMenuListener;
    import android.view.View.OnTouchListener;
    import android.view.inputmethod.InputMethodManager;
    import android.widget.AbsListView;
    import android.widget.AdapterView;
    import android.widget.AdapterView.OnItemClickListener;
    import android.widget.AdapterView.OnItemLongClickListener;
    import android.widget.Button;
    import android.widget.EditText;
    import android.widget.ListView;
    import android.widget.PopupMenu;
    import android.widget.TextView;
    import android.widget.Toast;

    import net.micode.notes.R;
    import net.micode.notes.data.Notes;
    import net.micode.notes.data.Notes.NoteColumns;
    import net.micode.notes.gtask.remote.GTaskSyncService;
    import net.micode.notes.model.WorkingNote;
    import net.micode.notes.tool.BackupUtils;
    import net.micode.notes.tool.DataUtils;
    import net.micode.notes.tool.ResourceParser;
    import net.micode.notes.ui.NotesListAdapter.AppWidgetAttribute;
    import net.micode.notes.widget.NoteWidgetProvider_2x;
    import net.micode.notes.widget.NoteWidgetProvider_4x;

    import java.io.BufferedReader;
    import java.io.FileNotFoundException;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.InputStreamReader;
    import java.util.HashSet;

    public class NotesListActivity extends Activity implements OnClickListener, OnItemLongClickListener {

        private int mode=-1;
        private static final int FOLDER_NOTE_LIST_QUERY_TOKEN = 0;

        private static final int FOLDER_LIST_QUERY_TOKEN      = 1;

        private static final int MENU_FOLDER_DELETE = 0;

        private static final int MENU_FOLDER_VIEW = 1;

        private static final int MENU_FOLDER_CHANGE_NAME = 2;

        private static final String PREFERENCE_ADD_INTRODUCTION = "net.micode.notes.introduction";

        private enum ListEditState {
            NOTE_LIST, SUB_FOLDER, CALL_RECORD_FOLDER
        };

        private ListEditState mState;

        private BackgroundQueryHandler mBackgroundQueryHandler;

        private NotesListAdapter mNotesListAdapter;

        private ListView mNotesListView;

        private Button mAddNewNote;

        private boolean mDispatch;

        private int mOriginY;

        private int mDispatchY;

        private TextView mTitleBar;

        private long mCurrentFolderId;

        private ContentResolver mContentResolver;

        private ModeCallback mModeCallBack;

        private static final String TAG = "NotesListActivity";

        public static final int NOTES_LISTVIEW_SCROLL_RATE = 30;

        private NoteItemData mFocusNoteDataItem;

        private static final String NORMAL_SELECTION = NoteColumns.PARENT_ID + "=?";

        private static final String ROOT_FOLDER_SELECTION = "(" + NoteColumns.TYPE + "<>"
                + Notes.TYPE_SYSTEM + " AND " + NoteColumns.PARENT_ID + "=?)" + " OR ("
                + NoteColumns.ID + "=" + Notes.ID_CALL_RECORD_FOLDER + " AND "
                + NoteColumns.NOTES_COUNT + ">0)";

        private final static int REQUEST_CODE_OPEN_NODE = 102;
        private final static int REQUEST_CODE_NEW_NODE  = 103;

        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.note_list);

            getWindow().setBackgroundDrawableResource(R.drawable.menu_moon);
            getWindow().setBackgroundDrawableResource(R.drawable.menu_green);
            getWindow().setBackgroundDrawableResource(R.drawable.menu_ship);

            initResources();

            /**
             * Insert an introduction when user firstly use this application
             */
            setAppInfoFromRawRes();
        }

        @Override
        protected void onActivityResult(int requestCode, int resultCode, Intent data) {
            if (resultCode == RESULT_OK
                    && (requestCode == REQUEST_CODE_OPEN_NODE || requestCode == REQUEST_CODE_NEW_NODE)) {
                mNotesListAdapter.changeCursor(null);
            } else {
                super.onActivityResult(requestCode, resultCode, data);
            }
        }

    //    //重写onActivityResult()来处理返回的数据
    //    protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
    //        super.onActivityResult(requestCode, resultCode, intent);
    //        ContentResolver resolver = getContentResolver();
    //        switch (requestCode) {
    //            case PHOTO_REQUEST:
    //                Uri originalUri = intent.getData(); //1.获得图片的真实路径
    //                Bitmap bitmap = null;
    //                try {
    //                    bitmap = BitmapFactory.decodeStream(resolver.openInputStream(originalUri));//2.解码图片
    //                } catch (FileNotFoundException e) {
    //                    Log.d(TAG, "onActivityResult: get file_exception");
    //                    e.printStackTrace();
    //                }
    //
    //                if(bitmap != null){
    //                    //3.根据Bitmap对象创建ImageSpan对象
    //                    Log.d(TAG, "onActivityResult: bitmap is not null");
    //                    ImageSpan imageSpan;
    //                    imageSpan = new ImageSpan(NoteEditActivity.this, bitmap);
    //                    String path = getPath(this,originalUri);
    //                    //4.使用[local][/local]将path括起来，用于之后方便识别图片路径在note中的位置
    //                    String img_fragment= "[local]" + path + "[/local]";
    //                    //创建一个SpannableString对象，以便插入用ImageSpan对象封装的图像
    //                    SpannableString spannableString = new SpannableString(img_fragment);
    //                    spannableString.setSpan(imageSpan, 0, img_fragment.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
    //                    //5.将选择的图片追加到EditText中光标所在位置
    //                    NoteEditText e = (NoteEditText) findViewById(R.id.note_edit_view);
    //                    int index = e.getSelectionStart(); //获取光标所在位置
    //                    Log.d(TAG, "Index是: " + index);
    //                    Editable edit_text = e.getEditableText();
    //                    edit_text.insert(index, spannableString); //将图片插入到光标所在位置
    //
    //                    WorkingNote mWorkingNote;
    //                    mWorkingNote = null;
    //                    mWorkingNote.mContent = e.getText().toString();
    //                    //6.把改动提交到数据库中,两个数据库表都要改的
    //                    ContentResolver contentResolver = getContentResolver();
    //                    ContentValues contentValues = new ContentValues();
    //                    final long id = mWorkingNote.getNoteId();
    //                    contentValues.put("snippet",mWorkingNote.mContent);
    //                    contentResolver.update(Uri.parse("content://micode_notes/note"), contentValues,"_id=?",new String[]{""+id});
    //                    ContentValues contentValues1 = new ContentValues();
    //                    contentValues1.put("content",mWorkingNote.mContent);
    //                    contentResolver.update(Uri.parse("content://micode_notes/data"), contentValues1,"mime_type=? and note_id=?", new String[]{"vnd.android.cursor.item/text_note",""+id});
    //
    //                }else{
    //                    Toast.makeText(NoteEditActivity.this, "获取图片失败", Toast.LENGTH_SHORT).show();
    //                }
    //                break;
    //            default:
    //                break;
    //        }
    //    }

        private String getPath(NotesListActivity notesListActivity, Uri originalUri) {
            return null;
        }

        private void setAppInfoFromRawRes() {
            SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);
            if (!sp.getBoolean(PREFERENCE_ADD_INTRODUCTION, false)) {
                StringBuilder sb = new StringBuilder();
                InputStream in = null;
                try {
                     in = getResources().openRawResource(R.raw.introduction);
                    if (in != null) {
                        InputStreamReader isr = new InputStreamReader(in);
                        BufferedReader br = new BufferedReader(isr);
                        char [] buf = new char[1024];
                        int len = 0;
                        while ((len = br.read(buf)) > 0) {
                            sb.append(buf, 0, len);
                        }
                    } else {
                        Log.e(TAG, "Read introduction file error");
                        return;
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                    return;
                } finally {
                    if(in != null) {
                        try {
                            in.close();
                        } catch (IOException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                    }
                }

                WorkingNote note = WorkingNote.createEmptyNote(this, Notes.ID_ROOT_FOLDER,
                        AppWidgetManager.INVALID_APPWIDGET_ID, Notes.TYPE_WIDGET_INVALIDE,
                        ResourceParser.RED);
                note.setWorkingText(sb.toString());
                if (note.saveNote()) {
                    sp.edit().putBoolean(PREFERENCE_ADD_INTRODUCTION, true).commit();
                } else {
                    Log.e(TAG, "Save introduction note error");
                    return;
                }
            }
        }

        @Override
        protected void onStart() {
            super.onStart();
            startAsyncNotesListQuery();
        }

        private void initResources() {
            mContentResolver = this.getContentResolver();
            mBackgroundQueryHandler = new BackgroundQueryHandler(this.getContentResolver());
            mCurrentFolderId = Notes.ID_ROOT_FOLDER;
            mNotesListView = (ListView) findViewById(R.id.notes_list);
            mNotesListView.addFooterView(LayoutInflater.from(this).inflate(R.layout.note_list_footer, null),
                    null, false);
            mNotesListView.setOnItemClickListener(new OnListItemClickListener());
            mNotesListView.setOnItemLongClickListener(this);
            mNotesListAdapter = new NotesListAdapter(this);
            mNotesListView.setAdapter(mNotesListAdapter);
            mAddNewNote = (Button) findViewById(R.id.btn_new_note);
            mAddNewNote.setOnClickListener(this);
            mAddNewNote.setOnTouchListener(new NewNoteOnTouchListener());
            mDispatch = false;
            mDispatchY = 0;
            mOriginY = 0;
            mTitleBar = (TextView) findViewById(R.id.tv_title_bar);
            mState = ListEditState.NOTE_LIST;
            mModeCallBack = new ModeCallback();
        }

        private class ModeCallback implements ListView.MultiChoiceModeListener, OnMenuItemClickListener {
            private DropdownMenu mDropDownMenu;
            private ActionMode mActionMode;
            private MenuItem mMoveMenu;

            public boolean onCreateActionMode(ActionMode mode, Menu menu) {
                getMenuInflater().inflate(R.menu.note_list_options, menu);
                menu.findItem(R.id.delete).setOnMenuItemClickListener(this);
                mMoveMenu = menu.findItem(R.id.move);
                if (mFocusNoteDataItem.getParentId() == Notes.ID_CALL_RECORD_FOLDER
                        || DataUtils.getUserFolderCount(mContentResolver) == 0) {
                    mMoveMenu.setVisible(false);
                } else {
                    mMoveMenu.setVisible(true);
                    mMoveMenu.setOnMenuItemClickListener(this);
                }
                mActionMode = mode;
                mNotesListAdapter.setChoiceMode(true);
                mNotesListView.setLongClickable(false);
                mAddNewNote.setVisibility(View.GONE);

                View customView = LayoutInflater.from(NotesListActivity.this).inflate(
                        R.layout.note_list_dropdown_menu, null);
                mode.setCustomView(customView);
                mDropDownMenu = new DropdownMenu(NotesListActivity.this,
                        (Button) customView.findViewById(R.id.selection_menu),
                        R.menu.note_list_dropdown);
                mDropDownMenu.setOnDropdownMenuItemClickListener(new PopupMenu.OnMenuItemClickListener(){
                    public boolean onMenuItemClick(MenuItem item) {
                        mNotesListAdapter.selectAll(!mNotesListAdapter.isAllSelected());
                        updateMenu();
                        return true;
                    }

                });
                return true;
            }

            private void updateMenu() {
                int selectedCount = mNotesListAdapter.getSelectedCount();
                // Update dropdown menu
                String format = getResources().getString(R.string.menu_select_title, selectedCount);
                mDropDownMenu.setTitle(format);
                MenuItem item = mDropDownMenu.findItem(R.id.action_select_all);
                if (item != null) {
                    if (mNotesListAdapter.isAllSelected()) {
                        item.setChecked(true);
                        item.setTitle(R.string.menu_deselect_all);
                    } else {
                        item.setChecked(false);
                        item.setTitle(R.string.menu_select_all);
                    }
                }
            }

            public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
                // TODO Auto-generated method stub
                return false;
            }

            public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
                // TODO Auto-generated method stub
                return false;
            }

            public void onDestroyActionMode(ActionMode mode) {
                mNotesListAdapter.setChoiceMode(false);
                mNotesListView.setLongClickable(true);
                mAddNewNote.setVisibility(View.VISIBLE);
            }

            public void finishActionMode() {
                mActionMode.finish();
            }

            public void onItemCheckedStateChanged(ActionMode mode, int position, long id,
                    boolean checked) {
                mNotesListAdapter.setCheckedItem(position, checked);
                updateMenu();
            }

            public boolean onMenuItemClick(MenuItem item) {
                if (mNotesListAdapter.getSelectedCount() == 0) {
                    Toast.makeText(NotesListActivity.this, getString(R.string.menu_select_none),
                            Toast.LENGTH_SHORT).show();
                    return true;
                }

                switch (item.getItemId()) {
                    case R.id.delete:
                        AlertDialog.Builder builder = new AlertDialog.Builder(NotesListActivity.this);
                        builder.setTitle(getString(R.string.alert_title_delete));
                        builder.setIcon(android.R.drawable.ic_dialog_alert);
                        builder.setMessage(getString(R.string.alert_message_delete_notes,
                                                 mNotesListAdapter.getSelectedCount()));
                        builder.setPositiveButton(android.R.string.ok,
                                                 new DialogInterface.OnClickListener() {
                                                     public void onClick(DialogInterface dialog,
                                                             int which) {
                                                         batchDelete();
                                                     }
                                                 });
                        builder.setNegativeButton(android.R.string.cancel, null);
                        builder.show();
                        break;
                    case R.id.move:
                        startQueryDestinationFolders();
                        break;
                    default:
                        return false;
                }
                return true;
            }
        }

        private class NewNoteOnTouchListener implements OnTouchListener {

            public boolean onTouch(View v, MotionEvent event) {
                switch (event.getAction()) {
                    case MotionEvent.ACTION_DOWN: {
                        Display display = getWindowManager().getDefaultDisplay();
                        int screenHeight = display.getHeight();
                        int newNoteViewHeight = mAddNewNote.getHeight();
                        int start = screenHeight - newNoteViewHeight;
                        int eventY = start + (int) event.getY();
                        /**
                         * Minus TitleBar's height
                         */
                        if (mState == ListEditState.SUB_FOLDER) {
                            eventY -= mTitleBar.getHeight();
                            start -= mTitleBar.getHeight();
                        }
                        /**
                         * HACKME:When click the transparent part of "New Note" button, dispatch
                         * the event to the list view behind this button. The transparent part of
                         * "New Note" button could be expressed by formula y=-0.12x+94（Unit:pixel）
                         * and the line top of the button. The coordinate based on left of the "New
                         * Note" button. The 94 represents maximum height of the transparent part.
                         * Notice that, if the background of the button changes, the formula should
                         * also change. This is very bad, just for the UI designer's strong requirement.
                         */
                        if (event.getY() < (event.getX() * (-0.12) + 94)) {
                            View view = mNotesListView.getChildAt(mNotesListView.getChildCount() - 1
                                    - mNotesListView.getFooterViewsCount());
                            if (view != null && view.getBottom() > start
                                    && (view.getTop() < (start + 94))) {
                                mOriginY = (int) event.getY();
                                mDispatchY = eventY;
                                event.setLocation(event.getX(), mDispatchY);
                                mDispatch = true;
                                return mNotesListView.dispatchTouchEvent(event);
                            }
                        }
                        break;
                    }
                    case MotionEvent.ACTION_MOVE: {
                        if (mDispatch) {
                            mDispatchY += (int) event.getY() - mOriginY;
                            event.setLocation(event.getX(), mDispatchY);
                            return mNotesListView.dispatchTouchEvent(event);
                        }
                        break;
                    }
                    default: {
                        if (mDispatch) {
                            event.setLocation(event.getX(), mDispatchY);
                            mDispatch = false;
                            return mNotesListView.dispatchTouchEvent(event);
                        }
                        break;
                    }
                }
                return false;
            }

        };

        private void startAsyncNotesListQuery() {
            String selection = (mCurrentFolderId == Notes.ID_ROOT_FOLDER) ? ROOT_FOLDER_SELECTION
                    : NORMAL_SELECTION;
            mBackgroundQueryHandler.startQuery(FOLDER_NOTE_LIST_QUERY_TOKEN, null,
                    Notes.CONTENT_NOTE_URI, NoteItemData.PROJECTION, selection, new String[] {
                        String.valueOf(mCurrentFolderId)
                    }, NoteColumns.TYPE + " DESC," + NoteColumns.MODIFIED_DATE + " DESC");
        }

        private final class BackgroundQueryHandler extends AsyncQueryHandler {
            public BackgroundQueryHandler(ContentResolver contentResolver) {
                super(contentResolver);
            }

            @Override
            protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
                switch (token) {
                    case FOLDER_NOTE_LIST_QUERY_TOKEN:
                        mNotesListAdapter.changeCursor(cursor);
                        break;
                    case FOLDER_LIST_QUERY_TOKEN:
                        if (cursor != null && cursor.getCount() > 0) {
                            showFolderListMenu(cursor);
                        } else {
                            Log.e(TAG, "Query folder failed");
                        }
                        break;
                    default:
                        return;
                }
            }
        }

        private void showFolderListMenu(Cursor cursor) {
            AlertDialog.Builder builder = new AlertDialog.Builder(NotesListActivity.this);
            builder.setTitle(R.string.menu_title_select_folder);
            final FoldersListAdapter adapter = new FoldersListAdapter(this, cursor);
            builder.setAdapter(adapter, new DialogInterface.OnClickListener() {

                public void onClick(DialogInterface dialog, int which) {
                    DataUtils.batchMoveToFolder(mContentResolver,
                            mNotesListAdapter.getSelectedItemIds(), adapter.getItemId(which));
                    Toast.makeText(
                            NotesListActivity.this,
                            getString(R.string.format_move_notes_to_folder,
                                    mNotesListAdapter.getSelectedCount(),
                                    adapter.getFolderName(NotesListActivity.this, which)),
                            Toast.LENGTH_SHORT).show();
                    mModeCallBack.finishActionMode();
                }
            });
            builder.show();
        }

        private void createNewNote() {
            Intent intent = new Intent(this, NoteEditActivity.class);
            intent.setAction(Intent.ACTION_INSERT_OR_EDIT);
            intent.putExtra(Notes.INTENT_EXTRA_FOLDER_ID, mCurrentFolderId);
            this.startActivityForResult(intent, REQUEST_CODE_NEW_NODE);
        }

        private void batchDelete() {
            new AsyncTask<Void, Void, HashSet<AppWidgetAttribute>>() {
                protected HashSet<AppWidgetAttribute> doInBackground(Void... unused) {
                    HashSet<AppWidgetAttribute> widgets = mNotesListAdapter.getSelectedWidget();
                    if (!isSyncMode()) {
                        // if not synced, delete notes directly
                        if (DataUtils.batchDeleteNotes(mContentResolver, mNotesListAdapter
                                .getSelectedItemIds())) {
                        } else {
                            Log.e(TAG, "Delete notes error, should not happens");
                        }
                    } else {
                        // in sync mode, we'll move the deleted note into the trash
                        // folder
                        if (!DataUtils.batchMoveToFolder(mContentResolver, mNotesListAdapter
                                .getSelectedItemIds(), Notes.ID_TRASH_FOLER)) {
                            Log.e(TAG, "Move notes to trash folder error, should not happens");
                        }
                    }
                    return widgets;
                }

                @Override
                protected void onPostExecute(HashSet<AppWidgetAttribute> widgets) {
                    if (widgets != null) {
                        for (AppWidgetAttribute widget : widgets) {
                            if (widget.widgetId != AppWidgetManager.INVALID_APPWIDGET_ID
                                    && widget.widgetType != Notes.TYPE_WIDGET_INVALIDE) {
                                updateWidget(widget.widgetId, widget.widgetType);
                            }
                        }
                    }
                    mModeCallBack.finishActionMode();
                }
            }.execute();
        }

        private void deleteFolder(long folderId) {
            if (folderId == Notes.ID_ROOT_FOLDER) {
                Log.e(TAG, "Wrong folder id, should not happen " + folderId);
                return;
            }

            HashSet<Long> ids = new HashSet<Long>();
            ids.add(folderId);
            HashSet<AppWidgetAttribute> widgets = DataUtils.getFolderNoteWidget(mContentResolver,
                    folderId);
            if (!isSyncMode()) {
                // if not synced, delete folder directly
                DataUtils.batchDeleteNotes(mContentResolver, ids);
            } else {
                // in sync mode, we'll move the deleted folder into the trash folder
                DataUtils.batchMoveToFolder(mContentResolver, ids, Notes.ID_TRASH_FOLER);
            }
            if (widgets != null) {
                for (AppWidgetAttribute widget : widgets) {
                    if (widget.widgetId != AppWidgetManager.INVALID_APPWIDGET_ID
                            && widget.widgetType != Notes.TYPE_WIDGET_INVALIDE) {
                        updateWidget(widget.widgetId, widget.widgetType);
                    }
                }
            }
        }

        private void openNode(NoteItemData data) {
            Intent intent = new Intent(this, NoteEditActivity.class);
            intent.setAction(Intent.ACTION_VIEW);
            intent.putExtra(Intent.EXTRA_UID, data.getId());
            this.startActivityForResult(intent, REQUEST_CODE_OPEN_NODE);
        }

        private void openFolder(NoteItemData data) {
            mCurrentFolderId = data.getId();
            startAsyncNotesListQuery();
            if (data.getId() == Notes.ID_CALL_RECORD_FOLDER) {
                mState = ListEditState.CALL_RECORD_FOLDER;
                mAddNewNote.setVisibility(View.GONE);
            } else {
                mState = ListEditState.SUB_FOLDER;
            }
            if (data.getId() == Notes.ID_CALL_RECORD_FOLDER) {
                mTitleBar.setText(R.string.call_record_folder_name);
            } else {
                mTitleBar.setText(data.getSnippet());
            }
            mTitleBar.setVisibility(View.VISIBLE);
        }

        public void onClick(View v) {
            switch (v.getId()) {
                case R.id.btn_new_note:
                    createNewNote();
                    break;
                default:
                    break;
            }
        }

        private void showSoftInput() {
            InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
            if (inputMethodManager != null) {
                inputMethodManager.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0);
            }
        }

        private void hideSoftInput(View view) {
            InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
            inputMethodManager.hideSoftInputFromWindow(view.getWindowToken(), 0);
        }

        private void showCreateOrModifyFolderDialog(final boolean create) {
            final AlertDialog.Builder builder = new AlertDialog.Builder(this);
            View view = LayoutInflater.from(this).inflate(R.layout.dialog_edit_text, null);
            final EditText etName = (EditText) view.findViewById(R.id.et_foler_name);
            showSoftInput();
            if (!create) {
                if (mFocusNoteDataItem != null) {
                    etName.setText(mFocusNoteDataItem.getSnippet());
                    builder.setTitle(getString(R.string.menu_folder_change_name));
                } else {
                    Log.e(TAG, "The long click data item is null");
                    return;
                }
            } else {
                etName.setText("");
                builder.setTitle(this.getString(R.string.menu_create_folder));
            }

            builder.setPositiveButton(android.R.string.ok, null);
            builder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int which) {
                    hideSoftInput(etName);
                }
            });

            final Dialog dialog = builder.setView(view).show();
            final Button positive = (Button)dialog.findViewById(android.R.id.button1);
            positive.setOnClickListener(new OnClickListener() {
                public void onClick(View v) {
                    hideSoftInput(etName);
                    String name = etName.getText().toString();
                    if (DataUtils.checkVisibleFolderName(mContentResolver, name)) {
                        Toast.makeText(NotesListActivity.this, getString(R.string.folder_exist, name),
                                Toast.LENGTH_LONG).show();
                        etName.setSelection(0, etName.length());
                        return;
                    }
                    if (!create) {
                        if (!TextUtils.isEmpty(name)) {
                            ContentValues values = new ContentValues();
                            values.put(NoteColumns.SNIPPET, name);
                            values.put(NoteColumns.TYPE, Notes.TYPE_FOLDER);
                            values.put(NoteColumns.LOCAL_MODIFIED, 1);
                            mContentResolver.update(Notes.CONTENT_NOTE_URI, values, NoteColumns.ID
                                    + "=?", new String[] {
                                String.valueOf(mFocusNoteDataItem.getId())
                            });
                        }
                    } else if (!TextUtils.isEmpty(name)) {
                        ContentValues values = new ContentValues();
                        values.put(NoteColumns.SNIPPET, name);
                        values.put(NoteColumns.TYPE, Notes.TYPE_FOLDER);
                        mContentResolver.insert(Notes.CONTENT_NOTE_URI, values);
                    }
                    dialog.dismiss();
                }
            });

            if (TextUtils.isEmpty(etName.getText())) {
                positive.setEnabled(false);
            }
            /**
             * When the name edit text is null, disable the positive button
             */
            etName.addTextChangedListener(new TextWatcher() {
                public void beforeTextChanged(CharSequence s, int start, int count, int after) {
                    // TODO Auto-generated method stub

                }

                public void onTextChanged(CharSequence s, int start, int before, int count) {
                    if (TextUtils.isEmpty(etName.getText())) {
                        positive.setEnabled(false);
                    } else {
                        positive.setEnabled(true);
                    }
                }

                public void afterTextChanged(Editable s) {
                    // TODO Auto-generated method stub

                }
            });
        }

        @Override
        public void onBackPressed() {
            switch (mState) {
                case SUB_FOLDER:
                    mCurrentFolderId = Notes.ID_ROOT_FOLDER;
                    mState = ListEditState.NOTE_LIST;
                    startAsyncNotesListQuery();
                    mTitleBar.setVisibility(View.GONE);
                    break;
                case CALL_RECORD_FOLDER:
                    mCurrentFolderId = Notes.ID_ROOT_FOLDER;
                    mState = ListEditState.NOTE_LIST;
                    mAddNewNote.setVisibility(View.VISIBLE);
                    mTitleBar.setVisibility(View.GONE);
                    startAsyncNotesListQuery();
                    break;
                case NOTE_LIST:
                    super.onBackPressed();
                    break;
                default:
                    break;
            }
        }

        private void updateWidget(int appWidgetId, int appWidgetType) {
            Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
            if (appWidgetType == Notes.TYPE_WIDGET_2X) {
                intent.setClass(this, NoteWidgetProvider_2x.class);
            } else if (appWidgetType == Notes.TYPE_WIDGET_4X) {
                intent.setClass(this, NoteWidgetProvider_4x.class);
            } else {
                Log.e(TAG, "Unspported widget type");
                return;
            }

            intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, new int[] {
                appWidgetId
            });

            sendBroadcast(intent);
            setResult(RESULT_OK, intent);
        }

        private final OnCreateContextMenuListener mFolderOnCreateContextMenuListener = new OnCreateContextMenuListener() {
            public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
                if (mFocusNoteDataItem != null) {
                    menu.setHeaderTitle(mFocusNoteDataItem.getSnippet());
                    menu.add(0, MENU_FOLDER_VIEW, 0, R.string.menu_folder_view);
                    menu.add(0, MENU_FOLDER_DELETE, 0, R.string.menu_folder_delete);
                    menu.add(0, MENU_FOLDER_CHANGE_NAME, 0, R.string.menu_folder_change_name);
                }
            }
        };

        @Override
        public void onContextMenuClosed(Menu menu) {
            if (mNotesListView != null) {
                mNotesListView.setOnCreateContextMenuListener(null);
            }
            super.onContextMenuClosed(menu);
        }

        @Override
        public boolean onContextItemSelected(MenuItem item) {
            if (mFocusNoteDataItem == null) {
                Log.e(TAG, "The long click data item is null");
                return false;
            }
            switch (item.getItemId()) {
                case MENU_FOLDER_VIEW:
                    openFolder(mFocusNoteDataItem);
                    break;
                case MENU_FOLDER_DELETE:
                    AlertDialog.Builder builder = new AlertDialog.Builder(this);
                    builder.setTitle(getString(R.string.alert_title_delete));
                    builder.setIcon(android.R.drawable.ic_dialog_alert);
                    builder.setMessage(getString(R.string.alert_message_delete_folder));
                    builder.setPositiveButton(android.R.string.ok,
                            new DialogInterface.OnClickListener() {
                                public void onClick(DialogInterface dialog, int which) {
                                    deleteFolder(mFocusNoteDataItem.getId());
                                }
                            });
                    builder.setNegativeButton(android.R.string.cancel, null);
                    builder.show();
                    break;
                case MENU_FOLDER_CHANGE_NAME:
                    showCreateOrModifyFolderDialog(false);
                    break;
                default:
                    break;
            }

            return true;
        }

        @Override
        public boolean onPrepareOptionsMenu(Menu menu) {
            menu.clear();
            if (mState == ListEditState.NOTE_LIST) {
                getMenuInflater().inflate(R.menu.note_list, menu);
                // set sync or sync_cancel
                menu.findItem(R.id.menu_sync).setTitle(
                        GTaskSyncService.isSyncing() ? R.string.menu_sync_cancel : R.string.menu_sync);
            } else if (mState == ListEditState.SUB_FOLDER) {
                getMenuInflater().inflate(R.menu.sub_folder, menu);
            } else if (mState == ListEditState.CALL_RECORD_FOLDER) {
                getMenuInflater().inflate(R.menu.call_record_folder, menu);
            } else {
                Log.e(TAG, "Wrong state:" + mState);
            }

            if(mode==-1)
                menu.findItem(R.id.menu_moon).setVisible(false);
            else if (mode==0)
                menu.findItem(R.id.menu_green).setVisible(false);
            else if (mode==1)
                menu.findItem(R.id.menu_ship).setVisible(false);

            return true;
        }

        @Override
        public boolean onOptionsItemSelected(MenuItem item) {
            switch (item.getItemId()) {
                case R.id.menu_moon:{
                    mode=-1;
                    getWindow().setBackgroundDrawableResource(R.drawable.menu_moon);
                    break;
                }
                case R.id.menu_green:{
                    mode=-1;
                    getWindow().setBackgroundDrawableResource(R.drawable.menu_green);
                    break;
                }
                case R.id.menu_ship:{
                    mode=-1;
                    getWindow().setBackgroundDrawableResource(R.drawable.menu_ship);
                    break;
                }

                case R.id.menu_new_folder: {
                    showCreateOrModifyFolderDialog(true);
                    break;
                }
                case R.id.menu_export_text: {
                    exportNoteToText();
                    break;
                }
                case R.id.menu_sync: {
                    if (isSyncMode()) {
                        if (TextUtils.equals(item.getTitle(), getString(R.string.menu_sync))) {
                            GTaskSyncService.startSync(this);
                        } else {
                            GTaskSyncService.cancelSync(this);
                        }
                    } else {
                        startPreferenceActivity();
                    }
                    break;
                }
                case R.id.menu_setting: {
                    startPreferenceActivity();
                    break;
                }
                case R.id.menu_new_note: {
                    createNewNote();
                    break;
                }
                case R.id.menu_search:
                    onSearchRequested();
                    break;
                default:
                    break;
            }
            return true;
        }

        @Override
        public boolean onSearchRequested() {
            startSearch(null, false, null /* appData */, false);
            return true;
        }

        private void exportNoteToText() {
            final BackupUtils backup = BackupUtils.getInstance(NotesListActivity.this);
            new AsyncTask<Void, Void, Integer>() {

                @Override
                protected Integer doInBackground(Void... unused) {
                    return backup.exportToText();
                }

                @Override
                protected void onPostExecute(Integer result) {
                    if (result == BackupUtils.STATE_SD_CARD_UNMOUONTED) {
                        AlertDialog.Builder builder = new AlertDialog.Builder(NotesListActivity.this);
                        builder.setTitle(NotesListActivity.this
                                .getString(R.string.failed_sdcard_export));
                        builder.setMessage(NotesListActivity.this
                                .getString(R.string.error_sdcard_unmounted));
                        builder.setPositiveButton(android.R.string.ok, null);
                        builder.show();
                    } else if (result == BackupUtils.STATE_SUCCESS) {
                        AlertDialog.Builder builder = new AlertDialog.Builder(NotesListActivity.this);
                        builder.setTitle(NotesListActivity.this
                                .getString(R.string.success_sdcard_export));
                        builder.setMessage(NotesListActivity.this.getString(
                                R.string.format_exported_file_location, backup
                                        .getExportedTextFileName(), backup.getExportedTextFileDir()));
                        builder.setPositiveButton(android.R.string.ok, null);
                        builder.show();
                    } else if (result == BackupUtils.STATE_SYSTEM_ERROR) {
                        AlertDialog.Builder builder = new AlertDialog.Builder(NotesListActivity.this);
                        builder.setTitle(NotesListActivity.this
                                .getString(R.string.failed_sdcard_export));
                        builder.setMessage(NotesListActivity.this
                                .getString(R.string.error_sdcard_export));
                        builder.setPositiveButton(android.R.string.ok, null);
                        builder.show();
                    }
                }

            }.execute();
        }

        private boolean isSyncMode() {
            return NotesPreferenceActivity.getSyncAccountName(this).trim().length() > 0;
        }

        private void startPreferenceActivity() {
            Activity from = getParent() != null ? getParent() : this;
            Intent intent = new Intent(from, NotesPreferenceActivity.class);
            from.startActivityIfNeeded(intent, -1);
        }

        private class OnListItemClickListener implements OnItemClickListener {

            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                if (view instanceof NotesListItem) {
                    NoteItemData item = ((NotesListItem) view).getItemData();
                    if (mNotesListAdapter.isInChoiceMode()) {
                        if (item.getType() == Notes.TYPE_NOTE) {
                            position = position - mNotesListView.getHeaderViewsCount();
                            mModeCallBack.onItemCheckedStateChanged(null, position, id,
                                    !mNotesListAdapter.isSelectedItem(position));
                        }
                        return;
                    }

                    switch (mState) {
                        case NOTE_LIST:
                            if (item.getType() == Notes.TYPE_FOLDER
                                    || item.getType() == Notes.TYPE_SYSTEM) {
                                openFolder(item);
                            } else if (item.getType() == Notes.TYPE_NOTE) {
                                openNode(item);
                            } else {
                                Log.e(TAG, "Wrong note type in NOTE_LIST");
                            }
                            break;
                        case SUB_FOLDER:
                        case CALL_RECORD_FOLDER:
                            if (item.getType() == Notes.TYPE_NOTE) {
                                openNode(item);
                            } else {
                                Log.e(TAG, "Wrong note type in SUB_FOLDER");
                            }
                            break;
                        default:
                            break;
                    }
                }
            }

        }

        private void startQueryDestinationFolders() {
            String selection = NoteColumns.TYPE + "=? AND " + NoteColumns.PARENT_ID + "<>? AND " + NoteColumns.ID + "<>?";
            selection = (mState == ListEditState.NOTE_LIST) ? selection:
                "(" + selection + ") OR (" + NoteColumns.ID + "=" + Notes.ID_ROOT_FOLDER + ")";

            mBackgroundQueryHandler.startQuery(FOLDER_LIST_QUERY_TOKEN,
                    null,
                    Notes.CONTENT_NOTE_URI,
                    FoldersListAdapter.PROJECTION,
                    selection,
                    new String[] {
                            String.valueOf(Notes.TYPE_FOLDER),
                            String.valueOf(Notes.ID_TRASH_FOLER),
                            String.valueOf(mCurrentFolderId)
                    },
                    NoteColumns.MODIFIED_DATE + " DESC");
        }

        public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
            if (view instanceof NotesListItem) {
                mFocusNoteDataItem = ((NotesListItem) view).getItemData();
                if (mFocusNoteDataItem.getType() == Notes.TYPE_NOTE && !mNotesListAdapter.isInChoiceMode()) {
                    if (mNotesListView.startActionMode(mModeCallBack) != null) {
                        mModeCallBack.onItemCheckedStateChanged(null, position, id, true);
                        mNotesListView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
                    } else {
                        Log.e(TAG, "startActionMode fails");
                    }
                } else if (mFocusNoteDataItem.getType() == Notes.TYPE_FOLDER) {
                    mNotesListView.setOnCreateContextMenuListener(mFolderOnCreateContextMenuListener);
                }
            }
            return false;
        }
    }