saphion.fragments.alarm.AlarmFragment.java Source code

Java tutorial

Introduction

Here is the source code for saphion.fragments.alarm.AlarmFragment.java

Source

/*
 * Copyright (C) 2007 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package saphion.fragments.alarm;

import static com.nineoldandroids.view.ViewPropertyAnimator.animate;

import java.text.DateFormatSymbols;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashSet;
import java.util.Locale;
import java.util.concurrent.ConcurrentHashMap;

import net.simonvt.numberpicker.NumberPicker;

//import org.jraf.android.backport.switchwidget.Switch;
import me.yugy.github.lswitchbackport.library.Switch;

import saphion.batterycaster.AboutClass;
import saphion.batterycaster.MainPreference;
import saphion.batterycaster.R;
import saphion.batterycaster.providers.Alarm;
import saphion.batterycaster.providers.DaysOfWeek;
import saphion.logger.Log;
import saphion.messagebar.MessageBar;
import saphion.messagebar.MessageBar.OnMessageClickListener;
import saphion.services.ForegroundService.Controller;
import saphion.utils.Constants;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.ContentResolver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.database.Cursor;
import android.database.DataSetObserver;
import android.graphics.Rect;
import android.graphics.Typeface;
import android.media.Ringtone;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Parcelable;
import android.os.SystemClock;
import android.os.Vibrator;
import android.support.v4.app.Fragment;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.Loader;
import android.support.v4.widget.CursorAdapter;
import android.support.v7.widget.PopupMenu;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.view.ViewTreeObserver;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.EditText;
import android.widget.FrameLayout;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.ToggleButton;

import com.nineoldandroids.animation.Animator;
import com.nineoldandroids.animation.Animator.AnimatorListener;
import com.nineoldandroids.animation.AnimatorInflater;
import com.nineoldandroids.animation.AnimatorListenerAdapter;
import com.nineoldandroids.animation.ValueAnimator;

/**
 * AlarmClock application.
 */
public class AlarmFragment extends Fragment implements LoaderManager.LoaderCallbacks<Cursor>, View.OnTouchListener {
    private static final float EXPAND_DECELERATION = 1f;
    private static final float COLLAPSE_DECELERATION = 0.7f;
    private static final int ANIMATION_DURATION = 300;
    private static final String KEY_EXPANDED_IDS = "expandedIds";
    private static final String KEY_REPEAT_CHECKED_IDS = "repeatCheckedIds";
    private static final String KEY_RINGTONE_TITLE_CACHE = "ringtoneTitleCache";
    private static final String KEY_SELECTED_ALARMS = "selectedAlarms";
    private static final String KEY_DELETED_ALARM = "deletedAlarm";
    private static final String KEY_UNDO_SHOWING = "undoShowing";
    private static final String KEY_PREVIOUS_DAY_MAP = "previousDayMap";
    private static final String KEY_SELECTED_ALARM = "selectedAlarm";
    // private static final String KEY_DELETE_CONFIRMATION =
    // "deleteConfirmation";

    private static final int REQUEST_CODE_RINGTONE = 1;

    // This extra is used when receiving an intent to create an alarm, but no
    // alarm details
    // have been passed in, so the alarm page should start the process of
    // creating a new alarm.
    public static final String ALARM_CREATE_NEW_INTENT_EXTRA = "deskclock.create.new";

    // This extra is used when receiving an intent to scroll to specific alarm.
    // If alarm
    // can not be found, and toast message will pop up that the alarm has be
    // deleted.
    public static final String SCROLL_TO_ALARM_INTENT_EXTRA = "deskclock.scroll.to.alarm";

    private ListView mAlarmsList;
    private AlarmItemAdapter mAdapter;
    private View mEmptyView;
    private ImageView mAddAlarmButton;

    private View mFooterView;

    private Bundle mRingtoneTitleCache; // Key: ringtone uri, value: ringtone
    // title
    // private ActionableToastBar mUndoBar;
    // private View mUndoFrame;

    private Alarm mSelectedAlarm;
    private long mScrollToAlarmId = -1;

    private Loader<Cursor> mCursorLoader = null;

    // Saved states for undo
    private Alarm mDeletedAlarm;
    private Alarm mAddedAlarm;
    private boolean mUndoShowing = false;

    private Animator mFadeIn;
    private Animator mFadeOut;

    private Interpolator mExpandInterpolator;
    private Interpolator mCollapseInterpolator;

    public void onPageChanged(int page) {
        // Do nothing here , only in derived classes
    }

    /**
     * Installs click and touch listeners on a fake overflow menu button.
     * 
     * @param menuButton
     *            the fragment's fake overflow menu button
     */
    public void setupFakeOverflowMenuButton(View menuButton) {
        final PopupMenu fakeOverflow = new PopupMenu(menuButton.getContext(), menuButton) {
            @Override
            public void show() {
                getActivity().onPrepareOptionsMenu(getMenu());
                super.show();
            }
        };
        Menu menu = fakeOverflow.getMenu();// .inflate(R.menu.bmenu);
        MenuItem noti = menu.add("Notification Settings");
        noti.setIcon(R.drawable.noti);
        noti.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {

            @Override
            public boolean onMenuItemClick(MenuItem item) {
                getActivity().startActivity(new Intent(getBaseContext(), Controller.class));
                getActivity().overridePendingTransition(R.anim.slide_in_left, R.anim.slide_out_right);
                return true;
            }
        });

        MenuItem prefs = menu.add("Preferences");
        prefs.setIcon(R.drawable.prefs);
        prefs.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {

            @Override
            public boolean onMenuItemClick(MenuItem item) {
                startActivity(new Intent(getBaseContext(), MainPreference.class));
                getActivity().overridePendingTransition(R.anim.slide_in_left, R.anim.slide_out_right);
                return true;
            }
        });

        MenuItem share = menu.add("Share");
        share.setIcon(R.drawable.share);
        share.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {

            @Override
            public boolean onMenuItemClick(MenuItem item) {
                getActivity().startActivity(createShareIntent());
                return true;
            }
        });

        MenuItem more = menu.add("More By Developer");
        more.setIcon(R.drawable.morebydev);
        more.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {

            @Override
            public boolean onMenuItemClick(MenuItem item) {
                getActivity().startActivity(new Intent(Intent.ACTION_VIEW,
                        Uri.parse("http://play.google.com/store/apps/developer?id=sachin+shinde")));
                return true;
            }
        });

        MenuItem about = menu.add("About");
        about.setIcon(R.drawable.about);
        about.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {

            @Override
            public boolean onMenuItemClick(MenuItem item) {
                startActivity(new Intent(getBaseContext(), AboutClass.class));
                getActivity().overridePendingTransition(R.anim.slide_in_left, R.anim.slide_out_right);
                return true;
            }
        });

        fakeOverflow.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
            @Override
            public boolean onMenuItemClick(MenuItem item) {
                return getActivity().onOptionsItemSelected(item);
            }
        });

        menuButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                fakeOverflow.show();
            }
        });
    }

    private Intent createShareIntent() {
        final Intent intent = new Intent(Intent.ACTION_SEND);
        intent.setType("text/plain");

        intent.putExtra(Intent.EXTRA_TEXT, "Checkout this Amazing App\nBattery Caster\nGet it now from Playstore\n"
                + Uri.parse("http://play.google.com/store/apps/details?id=" + getActivity().getPackageName()));

        return Intent.createChooser(intent, "Share");
    }

    // Cached layout positions of items in listview prior to add/removal of
    // alarm item
    private ConcurrentHashMap<Long, Integer> mItemIdTopMap = new ConcurrentHashMap<Long, Integer>();

    public static AlarmFragment newInstance(String content) {

        AlarmFragment fragment = new AlarmFragment();

        StringBuilder builder = new StringBuilder();
        for (int i = 0; i < 20; i++) {
            builder.append(content).append(" ");
        }
        builder.deleteCharAt(builder.length() - 1);

        return fragment;
    }

    @Override
    public void onCreate(Bundle savedState) {
        super.onCreate(savedState);

    }

    MessageBar mMessageBar;

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

        mCursorLoader = getActivity().getSupportLoaderManager().initLoader(0, null, this);
        try {
            if (!created)
                mCursorLoader.forceLoad();
        } catch (Exception ex) {
        }
        // Inflate the layout for this fragment
        final View v = inflater.inflate(R.layout.alarm_listview, container, false);

        long[] expandedIds = null;
        long[] repeatCheckedIds = null;
        long[] selectedAlarms = null;
        Bundle previousDayMap = null;
        if (savedState != null) {
            expandedIds = savedState.getLongArray(KEY_EXPANDED_IDS);
            repeatCheckedIds = savedState.getLongArray(KEY_REPEAT_CHECKED_IDS);
            mRingtoneTitleCache = savedState.getBundle(KEY_RINGTONE_TITLE_CACHE);
            mDeletedAlarm = savedState.getParcelable(KEY_DELETED_ALARM);
            mUndoShowing = savedState.getBoolean(KEY_UNDO_SHOWING);
            selectedAlarms = savedState.getLongArray(KEY_SELECTED_ALARMS);
            previousDayMap = savedState.getBundle(KEY_PREVIOUS_DAY_MAP);
            mSelectedAlarm = savedState.getParcelable(KEY_SELECTED_ALARM);
        }

        mMessageBar = new MessageBar(getActivity());

        mExpandInterpolator = new DecelerateInterpolator(EXPAND_DECELERATION);
        mCollapseInterpolator = new DecelerateInterpolator(COLLAPSE_DECELERATION);

        mAddAlarmButton = (ImageButton) v.findViewById(R.id.alarm_add_alarm);
        mAddAlarmButton.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                hideUndoBar(true, null);
                startCreatingAlarm();
            }
        });
        // For landscape, put the add button on the right and the menu in the
        // actionbar.
        FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) mAddAlarmButton.getLayoutParams();
        boolean isLandscape = getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE;
        if (isLandscape) {
            layoutParams.gravity = Gravity.RIGHT;
        } else {
            layoutParams.gravity = Gravity.CENTER;
        }
        mAddAlarmButton.setLayoutParams(layoutParams);

        View menuButton = v.findViewById(R.id.menu_button);
        if (menuButton != null) {
            if (isLandscape) {
                menuButton.setVisibility(View.GONE);
            } else {
                menuButton.setVisibility(View.VISIBLE);
                setupFakeOverflowMenuButton(menuButton);
            }
        }

        mEmptyView = v.findViewById(R.id.alarms_empty_view);
        mEmptyView.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                startCreatingAlarm();
            }
        });
        mAlarmsList = (ListView) v.findViewById(R.id.alarms_list);

        mFadeIn = AnimatorInflater.loadAnimator(getActivity(), R.anim.fade_in);
        mFadeIn.setDuration(ANIMATION_DURATION);
        mFadeIn.addListener(new AnimatorListener() {

            @Override
            public void onAnimationStart(Animator animation) {
                mEmptyView.setVisibility(View.VISIBLE);
            }

            @Override
            public void onAnimationCancel(Animator animation) {
                // Do nothing.
            }

            @Override
            public void onAnimationEnd(Animator animation) {
                // Do nothing.
            }

            @Override
            public void onAnimationRepeat(Animator animation) {
                // Do nothing.
            }
        });
        mFadeIn.setTarget(mEmptyView);
        mFadeOut = AnimatorInflater.loadAnimator(getActivity(), R.anim.fade_out);
        mFadeOut.setDuration(ANIMATION_DURATION);
        mFadeOut.addListener(new AnimatorListener() {

            @Override
            public void onAnimationStart(Animator arg0) {
                mEmptyView.setVisibility(View.VISIBLE);
            }

            @Override
            public void onAnimationCancel(Animator arg0) {
                // Do nothing.
            }

            @Override
            public void onAnimationEnd(Animator arg0) {
                mEmptyView.setVisibility(View.GONE);
            }

            @Override
            public void onAnimationRepeat(Animator arg0) {
                // Do nothing.
            }
        });
        mFadeOut.setTarget(mEmptyView);

        mFooterView = v.findViewById(R.id.alarms_footer_view);
        mFooterView.setOnTouchListener(this);

        mAdapter = new AlarmItemAdapter(getActivity(), expandedIds, repeatCheckedIds, selectedAlarms,
                previousDayMap, mAlarmsList);

        hideandshow(mAdapter.getCount());

        mAdapter.registerDataSetObserver(new DataSetObserver() {

            private int prevAdapterCount = -1;

            @Override
            public void onChanged() {

                final int count = mAdapter.getCount();
                if (mDeletedAlarm != null && prevAdapterCount > count) {
                    showUndoBar();
                }

                hideandshow(count);
                // Cache this adapter's count for when the adapter changes.
                prevAdapterCount = count;
                super.onChanged();
            }
        });

        if (mRingtoneTitleCache == null) {
            mRingtoneTitleCache = new Bundle();
        }

        mAlarmsList.setAdapter(mAdapter);
        mAlarmsList.setVerticalScrollBarEnabled(true);
        mAlarmsList.setOnCreateContextMenuListener(this);

        if (mUndoShowing) {
            showUndoBar();
        }
        return v;
    }

    public void hideandshow(int count) {
        // If there are no alarms in the adapter...
        if (count == 0) {
            mAddAlarmButton.setBackgroundResource(R.drawable.main_button_red);

            if (mEmptyView.getVisibility() == View.GONE)
                mFadeIn.start();
            // If there is no timeline view, just show the
            // "no alarms" icon.
            mEmptyView.setVisibility(View.VISIBLE);

        } else {

            // Otherwise, if the adapter DOES contain alarms...
            mAddAlarmButton.setBackgroundResource(R.drawable.main_button_blue);

            // ...and if there exists a timeline view (currently in
            // tablet landscape mode)
            if (mEmptyView.getVisibility() == View.VISIBLE)
                mFadeOut.start();
            // If there is no timeline view, just hide the
            // "no alarms" icon.
            mEmptyView.setVisibility(View.GONE);

        }

    }

    boolean created = false;

    @Override
    public void onResume() {
        super.onResume();
        // Check if another app asked us to create a blank new alarm.
        final Intent intent = getActivity().getIntent();
        if (intent.hasExtra(ALARM_CREATE_NEW_INTENT_EXTRA)) {
            if (intent.getBooleanExtra(ALARM_CREATE_NEW_INTENT_EXTRA, false)) {
                // An external app asked us to create a blank alarm.
                startCreatingAlarm();
            }

            // Remove the CREATE_NEW extra now that we've processed it.
            intent.removeExtra(ALARM_CREATE_NEW_INTENT_EXTRA);
        } else if (intent.hasExtra(SCROLL_TO_ALARM_INTENT_EXTRA)) {
            long alarmId = intent.getLongExtra(SCROLL_TO_ALARM_INTENT_EXTRA, Alarm.INVALID_ID);
            if (alarmId != Alarm.INVALID_ID) {
                mScrollToAlarmId = alarmId;
                if (mCursorLoader != null && mCursorLoader.isStarted()) {
                    // We need to force a reload here to make sure we have the
                    // latest view
                    // of the data to scroll to.
                    mCursorLoader.forceLoad();
                }
            }

            // Remove the SCROLL_TO_ALARM extra now that we've processed it.
            intent.removeExtra(SCROLL_TO_ALARM_INTENT_EXTRA);
        }

        // Make sure to use the child FragmentManager. We have to use that one
        // for the
        // case where an intent comes in telling the activity to load the
        // timepicker,
        // which means we have to use that one everywhere so that the fragment
        // can get
        // correctly picked up here if it's open.
        /*
         * TimePickerDialog tpd = (TimePickerDialog) getFragmentManager()
         * .findFragmentByTag(AlarmUtils.FRAG_TAG_TIME_PICKER); if (tpd != null)
         * { // The dialog is already open so we need to set the listener again.
         * tpd.setOnTimeSetListener(this); }
         */
    }

    private void hideUndoBar(boolean animate, MotionEvent event) {

        if (mUndoShowing)
            mMessageBar.hide();

        mDeletedAlarm = null;
        mUndoShowing = false;
    }

    private void showUndoBar() {

        if (mDeletedAlarm != null) {
            mMessageBar.clear();
            mMessageBar.setOnClickListener(new OnMessageClickListener() {

                @Override
                public void onMessageClick(Parcelable token) {

                    asyncAddAlarm(mDeletedAlarm);
                    mDeletedAlarm = null;
                    mUndoShowing = false;
                }
            });

            mMessageBar.show("Alarm Deleted", "UNDO", R.drawable.ic_action_undo);
        }
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);

        outState.putLongArray(KEY_EXPANDED_IDS, mAdapter.getExpandedArray());
        outState.putLongArray(KEY_REPEAT_CHECKED_IDS, mAdapter.getRepeatArray());
        outState.putLongArray(KEY_SELECTED_ALARMS, mAdapter.getSelectedAlarmsArray());
        outState.putBundle(KEY_RINGTONE_TITLE_CACHE, mRingtoneTitleCache);
        outState.putParcelable(KEY_DELETED_ALARM, mDeletedAlarm);
        outState.putBoolean(KEY_UNDO_SHOWING, mUndoShowing);
        outState.putBundle(KEY_PREVIOUS_DAY_MAP, mAdapter.getPreviousDaysOfWeekMap());
        outState.putParcelable(KEY_SELECTED_ALARM, mSelectedAlarm);
    }

    @Override
    public void onDestroyView() {

        created = false;
        super.onDestroyView();
    }

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

        // ToastMaster.cancelToast();
    }

    @Override
    public void onPause() {
        super.onPause();
        // When the user places the app in the background by pressing "home",
        // dismiss the toast bar. However, since there is no way to determine if
        // home was pressed, just dismiss any existing toast bar when restarting
        // the app.

        hideUndoBar(false, null);
    }

    public Context getBaseContext() {
        return getActivity();
    }

    private void showLabelDialog(final Alarm alarm) {
        /*
         * final FragmentTransaction ft =
         * getFragmentManager().beginTransaction(); final Fragment prev =
         * getFragmentManager().findFragmentByTag( "label_dialog"); if (prev !=
         * null) { ft.remove(prev); } ft.addToBackStack(null);
         * 
         * // Create and show the dialog. final LabelDialogFragment newFragment
         * = LabelDialogFragment .newInstance(alarm, alarm.label, getTag());
         * newFragment.show(ft, "label_dialog");
         */
        AlertDialog.Builder builder = new AlertDialog.Builder(getBaseContext());
        builder.setTitle("Enter Label");
        View view = LayoutInflater.from(getBaseContext()).inflate(R.layout.label_picker, null);
        final EditText picker = (EditText) view.findViewById(R.id.labelPicker);

        picker.setText(alarm.label);
        picker.selectAll();
        (new Handler()).postDelayed(new Runnable() {

            @SuppressLint("Recycle")
            public void run() {
                picker.dispatchTouchEvent(MotionEvent.obtain(SystemClock.uptimeMillis(), SystemClock.uptimeMillis(),
                        MotionEvent.ACTION_DOWN, 0, 0, 0));
                picker.dispatchTouchEvent(MotionEvent.obtain(SystemClock.uptimeMillis(), SystemClock.uptimeMillis(),
                        MotionEvent.ACTION_UP, 0, 0, 0));
                picker.selectAll();

            }
        }, 200);
        builder.setView(view);
        builder.setPositiveButton("Ok", new DialogInterface.OnClickListener() {

            @Override
            public void onClick(DialogInterface dialog, int which) {
                setLabel(alarm, picker.getText().toString());

            }
        });
        builder.setNegativeButton(android.R.string.cancel, null);
        builder.show();

    }

    public void setLabel(Alarm alarm, String label) {
        alarm.label = label;
        asyncUpdateAlarm(alarm, false);
    }

    @SuppressLint("InlinedApi")
    @Override
    public Loader<Cursor> onCreateLoader(int id, Bundle args) {

        final Context context = AlarmFragment.this.getActivity().getApplicationContext();
        final AsyncTask<Void, Void, Void> updateTask = new AsyncTask<Void, Void, Void>() {

            @Override
            protected Void doInBackground(Void... parameters) {
                ArrayList<AlarmItems> prevAlarms = AlarmPreference.retAlarms(getBaseContext());

                for (AlarmItems alarm : prevAlarms)

                    if (context != null && alarm != null) {
                        ContentResolver cr = context.getContentResolver();
                        if (!Alarm.contains(context.getContentResolver(), new Alarm(alarm)))
                            Alarm.addAlarm(cr, alarm);

                    }
                return null;
            }

            @Override
            protected void onPostExecute(Void result) {
                super.onPostExecute(result);
                getActivity().getSharedPreferences("saphion.batterycaster_preferences", Context.MODE_MULTI_PROCESS)
                        .edit().putBoolean("FirstAfterUpdate", false).commit();
            }

        };
        if (getActivity().getSharedPreferences("saphion.batterycaster_preferences", Context.MODE_MULTI_PROCESS)
                .getBoolean("FirstAfterUpdate", true)) {

            updateTask.execute();
        }
        created = true;

        return Alarm.getAlarmsCursorLoader(getActivity());
    }

    @Override
    public void onLoadFinished(Loader<Cursor> cursorLoader, final Cursor data) {

        mAdapter.swapCursor(data);
        if (mScrollToAlarmId != -1) {
            scrollToAlarm(mScrollToAlarmId);
            mScrollToAlarmId = -1;
        }
    }

    /**
     * Scroll to alarm with given alarm id.
     * 
     * @param alarmId
     *            The alarm id to scroll to.
     */

    private void scrollToAlarm(long alarmId) {
        int alarmPosition = -1;
        for (int i = 0; i < mAdapter.getCount(); i++) {
            long id = mAdapter.getItemId(i);
            if (id == alarmId) {
                alarmPosition = i;
                break;
            }
        }

        if (alarmPosition >= 0) {
            mAdapter.setNewAlarm(alarmId);
            // mAlarmsList.smoothScrollToPosition(alarmPosition);//smoothScrollToPosition(alarmPosition);//
        } else {
            // Trying to display a deleted alarm should only happen from a
            // missed notification for
            // an alarm that has been marked deleted after use.
            Context context = getActivity().getApplicationContext();
            Toast toast = Toast.makeText(context, "", Toast.LENGTH_LONG);
            // ToastMaster.setToast(toast);
            toast.show();
        }
    }

    @Override
    public void onLoaderReset(Loader<Cursor> cursorLoader) {

        mAdapter.swapCursor(null);
    }

    private void launchRingTonePicker(Alarm alarm) {
        mSelectedAlarm = alarm;
        Uri oldRingtone = Alarm.NO_RINGTONE_URI.equals(alarm.alert) ? null : alarm.alert;
        final Intent intent = new Intent(RingtoneManager.ACTION_RINGTONE_PICKER);
        intent.putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, oldRingtone);
        intent.putExtra(RingtoneManager.EXTRA_RINGTONE_TYPE, RingtoneManager.TYPE_ALARM);
        intent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_DEFAULT, false);
        startActivityForResult(intent, REQUEST_CODE_RINGTONE);
    }

    private void saveRingtoneUri(Intent intent) {
        Uri uri = intent.getParcelableExtra(RingtoneManager.EXTRA_RINGTONE_PICKED_URI);
        if (uri == null) {
            uri = Alarm.NO_RINGTONE_URI;
        }
        mSelectedAlarm.alert = uri;

        // Save the last selected ringtone as the default for new alarms
        if (!Alarm.NO_RINGTONE_URI.equals(uri)) {
            RingtoneManager.setActualDefaultRingtoneUri(getActivity(), RingtoneManager.TYPE_ALARM, uri);
        }
        asyncUpdateAlarm(mSelectedAlarm, false);
    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        // Toast.makeText(getActivity(), "Result recieved!!",
        // Toast.LENGTH_LONG).show();
        if (resultCode == Activity.RESULT_OK) {
            switch (requestCode) {
            case REQUEST_CODE_RINGTONE:
                saveRingtoneUri(data);
                break;
            default:
                Log.d("Unhandled request code in onActivityResult: " + requestCode);
            }
        }
    }

    public class AlarmItemAdapter extends CursorAdapter {
        private static final int EXPAND_DURATION = 300;
        private static final int COLLAPSE_DURATION = 250;

        private final Context mContext;
        private final LayoutInflater mFactory;
        private final String[] mShortWeekDayStrings;
        private final String[] mLongWeekDayStrings;
        private final int mColorLit;
        private final int mColorLited;
        private final int mColorDim;
        private final int mBackgroundColorExpanded;
        private final int mBackgroundColor;
        private final Typeface mRobotoNormal;
        private final Typeface mRobotoNormalOwn;
        private final Typeface mRobotoBold;
        private final Typeface mRobotoMed;
        private final ListView mList;

        private final HashSet<Long> mExpanded = new HashSet<Long>();
        private final HashSet<Long> mRepeatChecked = new HashSet<Long>();
        private final HashSet<Long> mSelectedAlarms = new HashSet<Long>();
        private Bundle mPreviousDaysOfWeekMap = new Bundle();

        private final boolean mHasVibrator;
        private final int mCollapseExpandHeight;

        // This determines the order in which it is shown and processed in the
        // UI.
        private final int[] DAY_ORDER = new int[] { Calendar.SUNDAY, Calendar.MONDAY, Calendar.TUESDAY,
                Calendar.WEDNESDAY, Calendar.THURSDAY, Calendar.FRIDAY, Calendar.SATURDAY, };

        private final int[] CHARGE_ORDER = new int[] { 0, 1 };

        public class ItemHolder {

            // views for optimization
            LinearLayout alarmItem;
            TextView level;
            Switch onoff;
            TextView daysOfWeek;
            TextView label;
            ImageView delete;
            View expandArea;
            View summary;
            TextView clickableLabel;
            CheckBox repeat;
            LinearLayout repeatDays;
            ViewGroup[] dayButtonParents = new ViewGroup[7];
            ToggleButton[] dayButtons = new ToggleButton[7];

            // new addition for charge and discharge
            LinearLayout repeatCharge;
            ViewGroup[] chargeButtonParents = new ViewGroup[2];
            ToggleButton[] chargeButtons = new ToggleButton[2];

            CheckBox vibrate;
            TextView ringtone;
            View hairLine;
            View arrow;
            View collapseExpandArea;
            View footerFiller;

            // Other states
            Alarm alarm;
        }

        // Used for scrolling an expanded item in the list to make sure it is
        // fully visible.
        private long mScrollAlarmId = -1;
        private final Runnable mScrollRunnable = new Runnable() {
            @Override
            public void run() {
                if (mScrollAlarmId != -1) {
                    View v = getViewById(mScrollAlarmId);
                    if (v != null) {
                        Rect rect = new Rect(v.getLeft(), v.getTop(), v.getRight(), v.getBottom());
                        mList.requestChildRectangleOnScreen(v, rect, false);
                    }
                    mScrollAlarmId = -1;
                }
            }
        };
        private CharSequence[] mChargeStrings = { "CHARGING", "DISCHARGING" };

        @SuppressLint("NewApi")
        public AlarmItemAdapter(Context context, long[] expandedIds, long[] repeatCheckedIds, long[] selectedAlarms,
                Bundle previousDaysOfWeekMap, ListView list) {
            super(context, null, 0);
            mContext = context;
            mFactory = LayoutInflater.from(context);
            mList = list;

            DateFormatSymbols dfs = new DateFormatSymbols();
            mShortWeekDayStrings = dfs.getShortWeekdays();
            mLongWeekDayStrings = dfs.getWeekdays();

            Resources res = mContext.getResources();
            mColorLit = res.getColor(R.color.clock_white);//
            mColorLited = res.getColor(R.color.main_button_blue_normal);//R.color.clock_white
            mColorDim = res.getColor(R.color.clock_gray);
            mBackgroundColorExpanded = res.getColor(R.color.alarm_whiteish);
            mBackgroundColor = R.drawable.alarm_background_normal;

            mRobotoBold = Typeface.create("sans-serif-condensed", Typeface.BOLD);
            mRobotoNormal = Typeface.create("sans-serif-condensed", Typeface.NORMAL);
            mRobotoNormalOwn = Typeface.createFromAsset(getBaseContext().getAssets(), Constants.FONT_ROBOTO);
            mRobotoMed = Typeface.createFromAsset(getBaseContext().getAssets(), Constants.FONT_ROBOTO_COND);

            if (expandedIds != null) {
                buildHashSetFromArray(expandedIds, mExpanded);
            }
            if (repeatCheckedIds != null) {
                buildHashSetFromArray(repeatCheckedIds, mRepeatChecked);
            }
            if (previousDaysOfWeekMap != null) {
                mPreviousDaysOfWeekMap = previousDaysOfWeekMap;
            }
            if (selectedAlarms != null) {
                buildHashSetFromArray(selectedAlarms, mSelectedAlarms);
            }

            mHasVibrator = Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB ? true
                    : ((Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE)).hasVibrator();

            mCollapseExpandHeight = (int) res.getDimension(R.dimen.collapse_expand_height);
        }

        public void removeSelectedId(int id) {
            mSelectedAlarms.remove(id);
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            if (!getCursor().moveToPosition(position)) {
                // May happen if the last alarm was deleted and the cursor
                // refreshed while the
                // list is updated.
                Log.d("couldn't move cursor to position " + position);
                return null;
            }
            View v;
            if (convertView == null) {
                v = newView(mContext, getCursor(), parent);
            } else {
                // TODO temporary hack to prevent the convertView from not
                // having stuff we need.
                boolean badConvertView = convertView.findViewById(R.id.digital_clock) == null;
                // Do a translation check to test for animation. Change this to
                // something more
                // reliable and robust in the future.
                if (badConvertView) {
                    // view was animated, reset
                    v = newView(mContext, getCursor(), parent);
                } else {
                    v = convertView;
                }
            }
            bindView(v, mContext, getCursor());
            ItemHolder holder = (ItemHolder) v.getTag();

            // We need the footer for the last element of the array to allow the
            // user to scroll
            // the item beyond the bottom button bar, which obscures the view.
            holder.footerFiller.setVisibility(position < getCount() - 1 ? View.GONE : View.VISIBLE);
            return v;
        }

        @Override
        public View newView(Context context, Cursor cursor, ViewGroup parent) {
            final View view = mFactory.inflate(R.layout.alarm_time, parent, false);
            setNewHolder(view);
            return view;
        }

        /**
         * In addition to changing the data set for the alarm list, swapCursor
         * is now also responsible for preparing the list view's pre-draw
         * operation for any animations that need to occur if an alarm was
         * removed or added.
         */
        @Override
        public synchronized Cursor swapCursor(Cursor cursor) {
            Cursor c = super.swapCursor(cursor);

            if (mItemIdTopMap.isEmpty() && mAddedAlarm == null) {
                return c;
            }

            final ListView list = mAlarmsList;
            final ViewTreeObserver observer = list.getViewTreeObserver();

            /*
             * Add a pre-draw listener to the observer to prepare for any
             * possible animations to the alarms within the list view. The
             * animations will occur if an alarm has been removed or added.
             * 
             * For alarm removal, the remaining children should all retain their
             * initial starting positions, and transition to their new
             * positions.
             * 
             * For alarm addition, the other children should all retain their
             * initial starting positions, transition to their new positions,
             * and at the end of that transition, the newly added alarm should
             * appear in the designated space.
             */
            observer.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {

                private View mAddedView;

                @Override
                public boolean onPreDraw() {
                    // Remove the pre-draw listener, as this only needs to occur
                    // once.
                    if (observer.isAlive()) {
                        observer.removeOnPreDrawListener(this);
                    }
                    boolean firstAnimation = true;
                    int firstVisiblePosition = list.getFirstVisiblePosition();

                    // Iterate through the children to prepare the add/remove
                    // animation.
                    for (int i = 0; i < list.getChildCount(); i++) {
                        final View child = list.getChildAt(i);

                        int position = firstVisiblePosition + i;
                        long itemId = mAdapter.getItemId(position);

                        // If this is the added alarm, set it invisible for now,
                        // and animate later.
                        if (mAddedAlarm != null && itemId == mAddedAlarm.id) {
                            mAddedView = child;
                            animate(mAddedView).alpha(0.0f);
                            continue;
                        }

                        // The cached starting position of the child view.
                        Integer startTop = mItemIdTopMap.get(itemId);
                        // The new starting position of the child view.
                        int top = child.getTop();

                        // If there is no cached starting position, determine
                        // whether the item has
                        // come from the top of bottom of the list view.
                        if (startTop == null) {
                            int childHeight = child.getHeight() + list.getDividerHeight();
                            startTop = top + (i > 0 ? childHeight : -childHeight);
                        }

                        Log.d("Start Top: " + startTop + ", Top: " + top);
                        // If the starting position of the child view is
                        // different from the
                        // current position, animate the child.
                        if (startTop != top) {
                            int delta = startTop - top;
                            animate(child).setDuration(0).translationYBy(delta);
                            animate(child).setDuration(ANIMATION_DURATION).translationY(0);
                            final View addedView = mAddedView;
                            if (firstAnimation) {

                                // If this is the first child being animated,
                                // then after the
                                // animation is complete, and animate in the
                                // added alarm (if one
                                // exists).
                                try {
                                    animate(child).setListener(new AnimatorListenerAdapter() {
                                        @Override
                                        public void onAnimationEnd(Animator animation) {
                                            // If there was an added
                                            // view, animate it in after
                                            // the other views have
                                            // animated.
                                            if (addedView != null) {
                                                animate(addedView).alpha(1.0f).setDuration(ANIMATION_DURATION)
                                                        .setListener(new AnimatorListenerAdapter() {
                                                            @Override
                                                            public void onAnimationEnd(Animator animation) {
                                                                list.setEnabled(true);
                                                            }
                                                        });
                                            } else {
                                                // Re-enable the list
                                                // after animations are
                                                // complete.
                                                list.setEnabled(true);
                                            }
                                        }
                                    });
                                } catch (Throwable e) {
                                    // If there was an added view, animate it in
                                    // after
                                    // the other views have animated.
                                    if (addedView != null) {

                                        animate(addedView).alpha(1.0f).setDuration(ANIMATION_DURATION)
                                                .setListener(new AnimatorListenerAdapter() {
                                                    @Override
                                                    public void onAnimationEnd(Animator animation) {
                                                        list.setEnabled(true);
                                                    }
                                                });
                                    } else {
                                        // Re-enable the list after animations
                                        // are complete.
                                        list.setEnabled(true);
                                    }
                                }

                                firstAnimation = false;
                            }
                        }
                    }

                    // If there were no child views (outside of a possible added
                    // view)
                    // that require animation...
                    if (firstAnimation) {
                        if (mAddedView != null) {
                            // If there is an added view, prepare animation for
                            // the added view.
                            Log.d("Animating added view...");
                            animate(mAddedView).alpha(1.0f).setDuration(ANIMATION_DURATION)
                                    .setListener(new AnimatorListenerAdapter() {
                                        @Override
                                        public void onAnimationEnd(Animator animation) {
                                            list.setEnabled(true);
                                        }
                                    });
                        } else {
                            // Re-enable the list after animations are complete.
                            list.setEnabled(true);
                        }
                    }

                    mAddedAlarm = null;
                    mItemIdTopMap.clear();
                    return true;
                }
            });
            return c;
        }

        private void setNewHolder(View view) {
            // standard view holder optimization
            final ItemHolder holder = new ItemHolder();
            holder.alarmItem = (LinearLayout) view.findViewById(R.id.alarm_item);
            holder.level = (TextView) view.findViewById(R.id.digital_clock);
            holder.level.setTypeface(mRobotoNormalOwn);
            holder.onoff = (Switch) view.findViewById(R.id.onoff);
            holder.onoff.setTypeface(mRobotoNormal);
            holder.daysOfWeek = (TextView) view.findViewById(R.id.daysOfWeek);
            holder.label = (TextView) view.findViewById(R.id.label);
            holder.delete = (ImageView) view.findViewById(R.id.delete);
            holder.summary = view.findViewById(R.id.summary);
            holder.expandArea = view.findViewById(R.id.expand_area);
            holder.hairLine = view.findViewById(R.id.hairline);
            holder.arrow = view.findViewById(R.id.arrow);
            holder.repeat = (CheckBox) view.findViewById(R.id.repeat_onoff);
            holder.clickableLabel = (TextView) view.findViewById(R.id.edit_label);
            holder.clickableLabel.setTypeface(mRobotoNormal);
            holder.repeatDays = (LinearLayout) view.findViewById(R.id.repeat_days);
            holder.repeatCharge = (LinearLayout) view.findViewById(R.id.repeat_charge);
            holder.collapseExpandArea = view.findViewById(R.id.collapse_expand);
            holder.footerFiller = view.findViewById(R.id.alarm_footer_filler);
            holder.footerFiller.setOnClickListener(new OnClickListener() {

                @Override
                public void onClick(View v) {
                    // Do nothing.
                }
            });

            // Build button for each day.
            for (int i = 0; i < 7; i++) {
                final ViewGroup viewgroup = (ViewGroup) mFactory.inflate(R.layout.day_button, holder.repeatDays,
                        false);
                final ToggleButton button = (ToggleButton) viewgroup.getChildAt(0);
                final int dayToShowIndex = DAY_ORDER[i];
                button.setText(mShortWeekDayStrings[dayToShowIndex].toUpperCase(Locale.getDefault()));
                button.setTextOn(mShortWeekDayStrings[dayToShowIndex].toUpperCase(Locale.getDefault()));
                button.setTextOff(mShortWeekDayStrings[dayToShowIndex].toUpperCase(Locale.getDefault()));
                button.setContentDescription(mLongWeekDayStrings[dayToShowIndex]);
                holder.repeatDays.addView(viewgroup);
                holder.dayButtons[i] = button;
                holder.dayButtonParents[i] = viewgroup;
            }

            // Build button for each charge.
            for (int i = 0; i < 2; i++) {
                final ViewGroup viewgroup = (ViewGroup) mFactory.inflate(R.layout.charge_button,
                        holder.repeatCharge, false);
                final ToggleButton button = (ToggleButton) viewgroup.getChildAt(0);
                final int dayToShowIndex = CHARGE_ORDER[i];
                button.setText(mChargeStrings[dayToShowIndex]);
                button.setTextOn(mChargeStrings[dayToShowIndex]);
                button.setTextOff(mChargeStrings[dayToShowIndex]);
                button.setContentDescription(mChargeStrings[dayToShowIndex]);
                holder.repeatCharge.addView(viewgroup);
                holder.chargeButtons[i] = button;
                holder.chargeButtonParents[i] = viewgroup;
            }

            holder.vibrate = (CheckBox) view.findViewById(R.id.vibrate_onoff);
            holder.ringtone = (TextView) view.findViewById(R.id.choose_ringtone);

            view.setTag(holder);
        }

        @Override
        public void bindView(final View view, Context context, final Cursor cursor) {
            final Alarm alarm = new Alarm(cursor);
            Object tag = view.getTag();
            if (tag == null) {
                // The view was converted but somehow lost its tag.
                setNewHolder(view);
            }
            final ItemHolder itemHolder = (ItemHolder) tag;
            itemHolder.alarm = alarm;

            // We must unset the listener first because this maybe a recycled
            // view so changing the
            // state would affect the wrong alarm.
            itemHolder.onoff.setOnCheckedChangeListener(null);
            itemHolder.onoff.setChecked(alarm.enabled);

            if (mSelectedAlarms.contains(itemHolder.alarm.id)) {
                itemHolder.alarmItem.setBackgroundColor(mBackgroundColorExpanded);
                setItemAlpha(itemHolder, true);
                itemHolder.onoff.setEnabled(false);
            } else {
                itemHolder.onoff.setEnabled(true);
                itemHolder.alarmItem.setBackgroundResource(mBackgroundColor);
                setItemAlpha(itemHolder, itemHolder.onoff.isChecked());
            }

            itemHolder.level.setText(alarm.battery + "");
            itemHolder.level.setClickable(true);
            itemHolder.level.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    mSelectedAlarm = itemHolder.alarm;
                    /*
                     * AlarmUtils.showTimeEditDialog(getFragmentManager(),
                     * alarm, AlarmClockFragment.this,
                     * DateFormat.is24HourFormat(getActivity()));
                     */

                    showNumberPicker(itemHolder.alarm);

                    if (!isAlarmExpanded(mSelectedAlarm))
                        expandAlarm(itemHolder, true);
                    itemHolder.alarmItem.post(mScrollRunnable);
                }
            });

            final CompoundButton.OnCheckedChangeListener onOffListener = new CompoundButton.OnCheckedChangeListener() {
                @Override
                public void onCheckedChanged(CompoundButton compoundButton, boolean checked) {
                    if (checked != alarm.enabled) {
                        setItemAlpha(itemHolder, checked);
                        alarm.enabled = checked;
                        asyncUpdateAlarm(alarm, alarm.enabled);
                        if (checked)
                            Log.CToast(getActivity(), "Alarm set for battery level " + alarm.battery + "%");
                    }
                }
            };

            itemHolder.onoff.setOnCheckedChangeListener(onOffListener);

            boolean expanded = isAlarmExpanded(alarm);
            itemHolder.expandArea.setVisibility(expanded ? View.VISIBLE : View.GONE);
            itemHolder.summary.setVisibility(expanded ? View.GONE : View.VISIBLE);

            String labelSpace = "";
            // Set the repeat text or leave it blank if it does not repeat.
            final String daysOfWeekStr = alarm.daysOfWeek.toString(AlarmFragment.this.getActivity(), false);
            if (daysOfWeekStr != null && daysOfWeekStr.length() != 0) {
                itemHolder.daysOfWeek.setText(daysOfWeekStr);
                itemHolder.daysOfWeek.setContentDescription(
                        alarm.daysOfWeek.toAccessibilityString(AlarmFragment.this.getActivity()));
                itemHolder.daysOfWeek.setVisibility(View.VISIBLE);
                labelSpace = "  ";
                itemHolder.daysOfWeek.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View view) {
                        expandAlarm(itemHolder, true);
                        itemHolder.alarmItem.post(mScrollRunnable);
                    }
                });

            } else {
                itemHolder.daysOfWeek.setVisibility(View.GONE);
            }

            if (alarm.label != null && alarm.label.length() != 0) {
                itemHolder.label.setText(alarm.label + labelSpace);
                itemHolder.label.setVisibility(View.VISIBLE);
                itemHolder.label.setContentDescription(
                        mContext.getResources().getString(R.string.todo) + " " + alarm.label);
                itemHolder.label.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View view) {
                        expandAlarm(itemHolder, true);
                        itemHolder.alarmItem.post(mScrollRunnable);
                    }
                });
            } else {
                itemHolder.label.setVisibility(View.GONE);
            }

            itemHolder.delete.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    mDeletedAlarm = alarm;
                    // expandAlarm(itemHolder, false);

                    try {
                        /*
                         * final ViewGroup.LayoutParams lp =
                         * view.getLayoutParams(); final int origHeight =
                         * view.getHeight()/2;
                         * 
                         * ValueAnimator animator =
                         * ValueAnimator.ofInt(origHeight,
                         * 1).setDuration(ANIMATION_DURATION);
                         * animator.addUpdateListener(new
                         * ValueAnimator.AnimatorUpdateListener() {
                         * 
                         * @Override public void onAnimationUpdate(ValueAnimator
                         * arg0) { lp.height = (Integer)
                         * arg0.getAnimatedValue(); view.setLayoutParams(lp); }
                         * });
                         * 
                         * animator.addListener(new AnimatorListenerAdapter(){
                         * 
                         * @Override public void onAnimationEnd( Animator
                         * animation) { asyncDeleteAlarm(mDeletedAlarm, view); }
                         * }); animator.start();
                         */

                        /*
                         * animate(view).setDuration(ANIMATION_DURATION).alpha(0)
                         * .setListener(new AnimatorListenerAdapter() {
                         * 
                         * @Override public void onAnimationEnd( Animator
                         * animation) {
                         */
                        asyncDeleteAlarm(mDeletedAlarm, view);
                        /*
                         * } });
                         */
                        // animateRemoval(mList, view);
                    } catch (Throwable e) {
                    }

                }
            });

            if (expanded) {
                expandAlarm(itemHolder, false);
            } else {
                collapseAlarm(itemHolder, false);
            }

            itemHolder.alarmItem.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    if (isAlarmExpanded(alarm)) {
                        collapseAlarm(itemHolder, true);
                    } else {
                        expandAlarm(itemHolder, true);
                    }
                }
            });
        }

        private void bindExpandArea(final ItemHolder itemHolder, final Alarm alarm) {
            // Views in here are not bound until the item is expanded.

            if (alarm.label != null && alarm.label.length() > 0) {
                itemHolder.clickableLabel.setText(alarm.label);
                itemHolder.clickableLabel.setTextColor(mColorLit);
            } else {
                itemHolder.clickableLabel.setText(R.string.label);
                itemHolder.clickableLabel.setTextColor(mColorDim);
            }
            itemHolder.clickableLabel.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    showLabelDialog(alarm);
                }
            });

            if (mRepeatChecked.contains(alarm.id) || itemHolder.alarm.daysOfWeek.isRepeating()) {
                itemHolder.repeat.setChecked(true);
                itemHolder.repeatDays.setVisibility(View.VISIBLE);
            } else {
                itemHolder.repeat.setChecked(false);
                itemHolder.repeatDays.setVisibility(View.GONE);
            }
            itemHolder.repeat.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    final boolean checked = ((CheckBox) view).isChecked();
                    if (checked) {
                        // Show days
                        itemHolder.repeatDays.setVisibility(View.VISIBLE);
                        mRepeatChecked.add(alarm.id);

                        // Set all previously set days
                        // or
                        // Set all days if no previous.
                        final int bitSet = mPreviousDaysOfWeekMap.getInt("" + alarm.id);
                        alarm.daysOfWeek.setBitSet(bitSet);
                        if (!alarm.daysOfWeek.isRepeating()) {
                            alarm.daysOfWeek.setDaysOfWeek(true, DAY_ORDER);
                        }
                        updateDaysOfWeekButtons(itemHolder, alarm.daysOfWeek);
                    } else {
                        itemHolder.repeatDays.setVisibility(View.GONE);
                        mRepeatChecked.remove(alarm.id);

                        // Remember the set days in case the user wants it back.
                        final int bitSet = alarm.daysOfWeek.getBitSet();
                        mPreviousDaysOfWeekMap.putInt("" + alarm.id, bitSet);

                        // Remove all repeat days
                        alarm.daysOfWeek.clearAllDays();
                    }
                    asyncUpdateAlarm(alarm, false);
                }
            });

            updateDaysOfWeekButtons(itemHolder, alarm.daysOfWeek);
            updateChargeButtons(itemHolder, alarm.charge);
            for (int i = 0; i < 7; i++) {
                final int buttonIndex = i;

                itemHolder.dayButtonParents[i].setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View view) {
                        itemHolder.dayButtons[buttonIndex].toggle();
                        final boolean checked = itemHolder.dayButtons[buttonIndex].isChecked();
                        int day = DAY_ORDER[buttonIndex];
                        alarm.daysOfWeek.setDaysOfWeek(checked, day);
                        if (checked) {
                            turnOnDayOfWeek(itemHolder, buttonIndex);
                        } else {
                            turnOffDayOfWeek(itemHolder, buttonIndex);

                            // See if this was the last day, if so,
                            // un-check the repeat box.
                            if (!alarm.daysOfWeek.isRepeating()) {
                                itemHolder.repeatDays.setVisibility(View.GONE);
                                itemHolder.repeat.setTextColor(mColorDim);
                                mRepeatChecked.remove(alarm.id);

                                // Set history to no days, so it will be
                                // everyday when repeat is
                                // turned back on
                                mPreviousDaysOfWeekMap.putInt("" + alarm.id, DaysOfWeek.NO_DAYS_SET);
                            }
                        }
                        asyncUpdateAlarm(alarm, false);
                    }
                });
            }

            for (int i = 0; i < 2; i++) {
                final int buttonIndex = i;

                itemHolder.chargeButtonParents[i].setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View view) {
                        itemHolder.chargeButtons[buttonIndex].toggle();
                        final boolean checked = itemHolder.chargeButtons[buttonIndex].isChecked();
                        int day = CHARGE_ORDER[buttonIndex];
                        switch (day) {
                        case 0:
                            if (checked)
                                alarm.charge = alarm.charge | 1;
                            else
                                alarm.charge = alarm.charge & ~1;
                            break;
                        case 1:
                            if (checked)
                                alarm.charge = alarm.charge | 2;
                            else
                                alarm.charge = alarm.charge & ~2;
                            break;
                        }

                        if (checked) {
                            turnOnCharge(itemHolder, buttonIndex);
                        } else {
                            turnOffCharge(itemHolder, buttonIndex);
                        }
                        asyncUpdateAlarm(alarm, false);
                    }
                });
            }

            if (!mHasVibrator) {
                itemHolder.vibrate.setVisibility(View.INVISIBLE);
            } else {
                itemHolder.vibrate.setVisibility(View.VISIBLE);
                if (!alarm.vibrate) {
                    itemHolder.vibrate.setChecked(false);
                    itemHolder.vibrate.setTextColor(mColorDim);
                } else {
                    itemHolder.vibrate.setChecked(true);
                    itemHolder.vibrate.setTextColor(mColorLit);
                }
            }

            itemHolder.vibrate.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    final boolean checked = ((CheckBox) v).isChecked();
                    if (checked) {
                        itemHolder.vibrate.setTextColor(mColorLit);
                    } else {
                        itemHolder.vibrate.setTextColor(mColorDim);
                    }
                    alarm.vibrate = checked;
                    asyncUpdateAlarm(alarm, false);
                }
            });

            final String ringtone;
            if (Alarm.NO_RINGTONE_URI.equals(alarm.alert)) {
                ringtone = mContext.getResources().getString(R.string.silent_alarm_summary);
            } else {
                ringtone = getRingToneTitle(alarm.alert);
            }
            itemHolder.ringtone.setText(ringtone);
            itemHolder.ringtone.setContentDescription(
                    mContext.getResources().getString(R.string.ringtone_description) + " " + ringtone);
            itemHolder.ringtone.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    launchRingTonePicker(alarm);
                }
            });
        }

        // Sets the alpha of the item except the on/off switch. This gives a
        // visual effect
        // for enabled/disabled alarm while leaving the on/off switch more
        // visible
        private void setItemAlpha(ItemHolder holder, boolean enabled) {
            float alpha = enabled ? 1f : 0.5f;
            animate(holder.level).alpha(alpha);
            animate(holder.summary).alpha(alpha);
            animate(holder.expandArea).alpha(alpha);
            animate(holder.delete).alpha(alpha);
            animate(holder.daysOfWeek).alpha(alpha);
        }

        private void updateDaysOfWeekButtons(ItemHolder holder, DaysOfWeek daysOfWeek) {
            HashSet<Integer> setDays = daysOfWeek.getSetDays();
            for (int i = 0; i < 7; i++) {
                if (setDays.contains(DAY_ORDER[i])) {
                    turnOnDayOfWeek(holder, i);
                } else {
                    turnOffDayOfWeek(holder, i);
                }
            }
        }

        private void updateChargeButtons(ItemHolder holder, int charge) {
            // HashSet<Integer> setDays = daysOfWeek.getSetDays();
            for (int i = 0; i < 2; i++) {
                if ((charge & (i + 1)) == (i + 1)) {
                    turnOnCharge(holder, i);

                } else {
                    turnOffCharge(holder, i);
                }
            }
        }

        public void toggleSelectState(View v) {
            // long press could be on the parent view or one of its childs, so
            // find the parent view
            v = getTopParent(v);
            if (v != null) {
                long id = ((ItemHolder) v.getTag()).alarm.id;
                if (mSelectedAlarms.contains(id)) {
                    mSelectedAlarms.remove(id);
                } else {
                    mSelectedAlarms.add(id);
                }
            }
        }

        private View getTopParent(View v) {
            while (v != null && v.getId() != R.id.alarm_item) {
                v = (View) v.getParent();
            }
            return v;
        }

        public int getSelectedItemsNum() {
            return mSelectedAlarms.size();
        }

        private void turnOffDayOfWeek(ItemHolder holder, int dayIndex) {
            holder.dayButtons[dayIndex].setChecked(false);
            holder.dayButtons[dayIndex].setTextColor(mColorDim);
            holder.dayButtons[dayIndex].setTypeface(mRobotoNormal);
        }

        private void turnOnDayOfWeek(ItemHolder holder, int dayIndex) {
            holder.dayButtons[dayIndex].setChecked(true);
            holder.dayButtons[dayIndex].setTextColor(mColorLited);
            holder.dayButtons[dayIndex].setTypeface(mRobotoMed);
        }

        private void turnOffCharge(ItemHolder holder, int dayIndex) {
            holder.chargeButtons[dayIndex].setChecked(false);
            holder.chargeButtons[dayIndex].setTextColor(mColorDim);
            holder.chargeButtons[dayIndex].setTypeface(mRobotoNormal);
        }

        private void turnOnCharge(ItemHolder holder, int dayIndex) {
            holder.chargeButtons[dayIndex].setChecked(true);
            holder.chargeButtons[dayIndex].setTextColor(mColorLited);
            holder.chargeButtons[dayIndex].setTypeface(mRobotoMed);
        }

        /**
         * Does a read-through cache for ringtone titles.
         * 
         * @param uri
         *            The uri of the ringtone.
         * @return The ringtone title. {@literal null} if no matching ringtone
         *         found.
         */
        private String getRingToneTitle(Uri uri) {
            // Try the cache first
            String title = mRingtoneTitleCache.getString(uri.toString());
            if (title == null) {
                // This is slow because a media player is created during
                // Ringtone object creation.
                Ringtone ringTone = RingtoneManager.getRingtone(mContext, uri);
                if (ringTone != null) {
                    title = ringTone.getTitle(mContext);
                    if (title != null) {

                        mRingtoneTitleCache.putString(uri.toString(), title);
                    }
                }

            }
            return title;
        }

        public void setNewAlarm(long alarmId) {
            mExpanded.add(alarmId);
        }

        /**
         * Expands the alarm for editing.
         * 
         * @param itemHolder
         *            The item holder instance.
         */
        private void expandAlarm(final ItemHolder itemHolder, boolean animate) {
            mExpanded.add(itemHolder.alarm.id);
            bindExpandArea(itemHolder, itemHolder.alarm);
            // Scroll the view to make sure it is fully viewed
            mScrollAlarmId = itemHolder.alarm.id;

            // Save the starting height so we can animate from this value.
            final int startingHeight = itemHolder.alarmItem.getHeight();

            // Set the expand area to visible so we can measure the height to
            // animate to.
            itemHolder.alarmItem.setBackgroundColor(mBackgroundColorExpanded);
            itemHolder.expandArea.setVisibility(View.VISIBLE);

            if (!animate) {
                // Set the "end" layout and don't do the animation.
                animate(itemHolder.arrow).rotationBy(180).setDuration(0);
                // We need to translate the hairline up, so the height of the
                // collapseArea
                // needs to be measured to know how high to translate it.
                final ViewTreeObserver observer = mAlarmsList.getViewTreeObserver();
                observer.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
                    @Override
                    public boolean onPreDraw() {
                        // We don't want to continue getting called for every
                        // listview drawing.
                        if (observer.isAlive()) {
                            observer.removeOnPreDrawListener(this);
                        }
                        int hairlineHeight = itemHolder.hairLine.getHeight();
                        int collapseHeight = itemHolder.collapseExpandArea.getHeight() - hairlineHeight;
                        animate(itemHolder.hairLine).setDuration(0).translationY(-collapseHeight);
                        return true;
                    }
                });
                return;
            }

            // Add an onPreDrawListener, which gets called after measurement but
            // before the draw.
            // This way we can check the height we need to animate to before any
            // drawing.
            // Note the series of events:
            // * expandArea is set to VISIBLE, which causes a layout pass
            // * the view is measured, and our onPreDrawListener is called
            // * we set up the animation using the start and end values.
            // * the height is set back to the starting point so it can be
            // animated down.
            // * request another layout pass.
            // * return false so that onDraw() is not called for the single
            // frame before
            // the animations have started.
            final ViewTreeObserver observer = mAlarmsList.getViewTreeObserver();
            observer.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
                @Override
                public boolean onPreDraw() {
                    // We don't want to continue getting called for every
                    // listview drawing.
                    if (observer.isAlive()) {
                        observer.removeOnPreDrawListener(this);
                    }
                    // Calculate some values to help with the animation.
                    final int endingHeight = itemHolder.alarmItem.getHeight();
                    final int distance = endingHeight - startingHeight;
                    final int collapseHeight = itemHolder.collapseExpandArea.getHeight();
                    int hairlineHeight = itemHolder.hairLine.getHeight();
                    final int hairlineDistance = collapseHeight - hairlineHeight;

                    // Set the height back to the start state of the animation.
                    itemHolder.alarmItem.getLayoutParams().height = startingHeight;
                    // To allow the expandArea to glide in with the expansion
                    // animation, set a
                    // negative top margin, which will animate down to a margin
                    // of 0 as the height
                    // is increased.
                    // Note that we need to maintain the bottom margin as a
                    // fixed value (instead of
                    // just using a listview, to allow for a flatter hierarchy)
                    // to fit the bottom
                    // bar underneath.
                    FrameLayout.LayoutParams expandParams = (FrameLayout.LayoutParams) itemHolder.expandArea
                            .getLayoutParams();
                    expandParams.setMargins(0, -distance, 0, collapseHeight);
                    itemHolder.alarmItem.requestLayout();

                    // Set up the animator to animate the expansion.
                    ValueAnimator animator = ValueAnimator.ofFloat(0f, 1f).setDuration(EXPAND_DURATION);
                    animator.setInterpolator(mExpandInterpolator);
                    animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                        @Override
                        public void onAnimationUpdate(ValueAnimator animator) {
                            Float value = (Float) animator.getAnimatedValue();

                            // For each value from 0 to 1, animate the various
                            // parts of the layout.
                            itemHolder.alarmItem
                                    .getLayoutParams().height = (int) (value * distance + startingHeight);
                            FrameLayout.LayoutParams expandParams = (FrameLayout.LayoutParams) itemHolder.expandArea
                                    .getLayoutParams();
                            expandParams.setMargins(0, (int) -((1 - value) * distance), 0, collapseHeight);
                            animate(itemHolder.arrow).rotation(180 * value).setDuration(0);
                            animate(itemHolder.hairLine).setDuration(0).translationY(-hairlineDistance * value);
                            animate(itemHolder.summary).alpha(1 - value);

                            itemHolder.alarmItem.requestLayout();
                        }
                    });
                    // Set everything to their final values when the animation's
                    // done.
                    animator.addListener(new AnimatorListener() {
                        @Override
                        public void onAnimationEnd(Animator animation) {
                            // Set it back to wrap content since we'd explicitly
                            // set the height.
                            itemHolder.alarmItem.getLayoutParams().height = LayoutParams.WRAP_CONTENT;
                            animate(itemHolder.arrow).rotation(180).setDuration(0);
                            animate(itemHolder.hairLine).setDuration(0).translationY(-hairlineDistance);
                            itemHolder.summary.setVisibility(View.GONE);
                        }

                        @Override
                        public void onAnimationCancel(Animator animation) {
                            // TODO we may have to deal with cancelations of the
                            // animation.
                        }

                        @Override
                        public void onAnimationRepeat(Animator animation) {
                        }

                        @Override
                        public void onAnimationStart(Animator animation) {
                        }
                    });
                    animator.start();

                    // Return false so this draw does not occur to prevent the
                    // final frame from
                    // being drawn for the single frame before the animations
                    // start.
                    return false;
                }
            });
        }

        private boolean isAlarmExpanded(Alarm alarm) {
            return mExpanded.contains(alarm.id);
        }

        private void collapseAlarm(final ItemHolder itemHolder, boolean animate) {
            mExpanded.remove(itemHolder.alarm.id);

            // Save the starting height so we can animate from this value.
            final int startingHeight = itemHolder.alarmItem.getHeight();

            // Set the expand area to gone so we can measure the height to
            // animate to.
            itemHolder.alarmItem.setBackgroundResource(mBackgroundColor);
            itemHolder.expandArea.setVisibility(View.GONE);

            if (!animate) {
                // Set the "end" layout and don't do the animation.
                animate(itemHolder.arrow).rotation(0).setDuration(0);
                animate(itemHolder.hairLine).translationY(0);
                return;
            }

            // Add an onPreDrawListener, which gets called after measurement but
            // before the draw.
            // This way we can check the height we need to animate to before any
            // drawing.
            // Note the series of events:
            // * expandArea is set to GONE, which causes a layout pass
            // * the view is measured, and our onPreDrawListener is called
            // * we set up the animation using the start and end values.
            // * expandArea is set to VISIBLE again so it can be shown
            // animating.
            // * request another layout pass.
            // * return false so that onDraw() is not called for the single
            // frame before
            // the animations have started.
            final ViewTreeObserver observer = mAlarmsList.getViewTreeObserver();
            observer.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
                @Override
                public boolean onPreDraw() {
                    if (observer.isAlive()) {
                        observer.removeOnPreDrawListener(this);
                    }

                    // Calculate some values to help with the animation.
                    final int endingHeight = itemHolder.alarmItem.getHeight();
                    final int distance = endingHeight - startingHeight;
                    int hairlineHeight = itemHolder.hairLine.getHeight();
                    final int hairlineDistance = mCollapseExpandHeight - hairlineHeight;

                    // Re-set the visibilities for the start state of the
                    // animation.
                    itemHolder.expandArea.setVisibility(View.VISIBLE);
                    itemHolder.summary.setVisibility(View.VISIBLE);
                    animate(itemHolder.summary).alpha(1);

                    // Set up the animator to animate the expansion.
                    ValueAnimator animator = ValueAnimator.ofFloat(0f, 1f).setDuration(COLLAPSE_DURATION);
                    animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                        @Override
                        public void onAnimationUpdate(ValueAnimator animator) {
                            Float value = (Float) animator.getAnimatedValue();

                            // For each value from 0 to 1, animate the various
                            // parts of the layout.
                            itemHolder.alarmItem
                                    .getLayoutParams().height = (int) (value * distance + startingHeight);
                            FrameLayout.LayoutParams expandParams = (FrameLayout.LayoutParams) itemHolder.expandArea
                                    .getLayoutParams();
                            expandParams.setMargins(0, (int) (value * distance), 0, mCollapseExpandHeight);
                            animate(itemHolder.arrow).rotation(180 * (1 - value)).setDuration(0);
                            animate(itemHolder.hairLine).setDuration(0)
                                    .translationY(-hairlineDistance * (1 - value));
                            animate(itemHolder.summary).alpha(value);

                            itemHolder.alarmItem.requestLayout();
                        }
                    });
                    animator.setInterpolator(mCollapseInterpolator);
                    // Set everything to their final values when the animation's
                    // done.
                    animator.addListener(new AnimatorListener() {
                        @Override
                        public void onAnimationEnd(Animator animation) {
                            // Set it back to wrap content since we'd explicitly
                            // set the height.
                            itemHolder.alarmItem.getLayoutParams().height = LayoutParams.WRAP_CONTENT;

                            FrameLayout.LayoutParams expandParams = (FrameLayout.LayoutParams) itemHolder.expandArea
                                    .getLayoutParams();
                            expandParams.setMargins(0, 0, 0, mCollapseExpandHeight);

                            itemHolder.expandArea.setVisibility(View.GONE);
                            animate(itemHolder.arrow).rotation(0).setDuration(0);
                            animate(itemHolder.hairLine).setDuration(0).translationY(0);
                        }

                        @Override
                        public void onAnimationCancel(Animator animation) {
                            // TODO we may have to deal with cancelations of the
                            // animation.
                        }

                        @Override
                        public void onAnimationRepeat(Animator animation) {
                        }

                        @Override
                        public void onAnimationStart(Animator animation) {
                        }
                    });
                    animator.start();

                    return false;
                }
            });
        }

        @Override
        public int getViewTypeCount() {
            return 1;
        }

        private View getViewById(long id) {
            for (int i = 0; i < mList.getCount(); i++) {
                View v = mList.getChildAt(i);
                if (v != null) {
                    ItemHolder h = (ItemHolder) (v.getTag());
                    if (h != null && h.alarm.id == id) {
                        return v;
                    }
                }
            }
            return null;
        }

        public long[] getExpandedArray() {
            int index = 0;
            long[] ids = new long[mExpanded.size()];
            for (long id : mExpanded) {
                ids[index] = id;
                index++;
            }
            return ids;
        }

        public long[] getSelectedAlarmsArray() {
            int index = 0;
            long[] ids = new long[mSelectedAlarms.size()];
            for (long id : mSelectedAlarms) {
                ids[index] = id;
                index++;
            }
            return ids;
        }

        public long[] getRepeatArray() {
            int index = 0;
            long[] ids = new long[mRepeatChecked.size()];
            for (long id : mRepeatChecked) {
                ids[index] = id;
                index++;
            }
            return ids;
        }

        public Bundle getPreviousDaysOfWeekMap() {
            return mPreviousDaysOfWeekMap;
        }

        private void buildHashSetFromArray(long[] ids, HashSet<Long> set) {
            for (long id : ids) {
                set.add(id);
            }
        }
    }

    private void startCreatingAlarm() {
        // Set the "selected" alarm as null, and we'll create the new one when
        // the timepicker
        // comes back.
        mSelectedAlarm = null;
        asyncAddAlarm(new Alarm(100));
        /*
         * AlarmUtils.showTimeEditDialog(getFragmentManager(), null,
         * AlarmClockFragment.this, DateFormat.is24HourFormat(getActivity()));
         */
    }

    private void asyncDeleteAlarm(final Alarm alarm, final View viewToRemove) {
        final Context context = AlarmFragment.this.getActivity().getApplicationContext();
        final AsyncTask<Void, Void, Void> deleteTask = new AsyncTask<Void, Void, Void>() {
            @Override
            public synchronized void onPreExecute() {
                if (viewToRemove == null) {
                    return;
                }
                // The alarm list needs to be disabled until the animation
                // finishes to prevent
                // possible concurrency issues. It becomes re-enabled after the
                // animations have
                // completed.
                mAlarmsList.setEnabled(false);

                // Store all of the current list view item positions in memory
                // for animation.
                final ListView list = mAlarmsList;
                int firstVisiblePosition = list.getFirstVisiblePosition();
                for (int i = 0; i < list.getChildCount(); i++) {
                    View child = list.getChildAt(i);
                    if (child != viewToRemove) {
                        int position = firstVisiblePosition + i;
                        long itemId = mAdapter.getItemId(position);
                        mItemIdTopMap.put(itemId, child.getTop());
                    }
                }
            }

            @Override
            protected Void doInBackground(Void... parameters) {
                // Activity may be closed at this point , make sure data is
                // still valid
                if (context != null && alarm != null) {
                    ContentResolver cr = context.getContentResolver();
                    // AlarmStateManager.deleteAllInstances(context, alarm.id);
                    Alarm.deleteAlarm(cr, alarm.id);
                }
                return null;
            }
        };
        mUndoShowing = true;
        deleteTask.execute();
    }

    private void asyncAddAlarm(final Alarm alarm) {
        final Context context = AlarmFragment.this.getActivity().getApplicationContext();
        final AsyncTask<Void, Void, Void> updateTask = new AsyncTask<Void, Void, Void>() {
            @Override
            public synchronized void onPreExecute() {
                final ListView list = mAlarmsList;
                // The alarm list needs to be disabled until the animation
                // finishes to prevent
                // possible concurrency issues. It becomes re-enabled after the
                // animations have
                // completed.
                mAlarmsList.setEnabled(false);

                // Store all of the current list view item positions in memory
                // for animation.
                int firstVisiblePosition = list.getFirstVisiblePosition();
                for (int i = 0; i < list.getChildCount(); i++) {
                    View child = list.getChildAt(i);
                    int position = firstVisiblePosition + i;
                    long itemId = mAdapter.getItemId(position);
                    mItemIdTopMap.put(itemId, child.getTop());
                }
            }

            @Override
            protected Void doInBackground(Void... parameters) {
                if (context != null && alarm != null) {
                    ContentResolver cr = context.getContentResolver();

                    // Add alarm to db
                    /* Alarm newAlarm = */
                    Alarm.addAlarm(cr, alarm);
                    // mScrollToAlarmId = newAlarm.id;

                    /*
                     * // Create and add instance to db if (newAlarm.enabled) {
                     * return setupAlarmInstance(context, newAlarm); }
                     */
                }
                return null;
            }

            @Override
            protected void onPostExecute(Void instance) {
                /*
                 * if (instance != null) { AlarmUtils.popAlarmSetToast(context,
                 * instance .getAlarmTime().getTimeInMillis()); }
                 */
            }
        };
        updateTask.execute();
    }

    private void asyncUpdateAlarm(final Alarm alarm, final boolean popToast) {
        final Context context = AlarmFragment.this.getActivity().getApplicationContext();
        final AsyncTask<Void, Void, Void> updateTask = new AsyncTask<Void, Void, Void>() {
            @Override
            protected Void doInBackground(Void... parameters) {
                ContentResolver cr = context.getContentResolver();

                /*
                 * // Dismiss all old instances
                 * AlarmStateManager.deleteAllInstances(context, alarm.id);
                 */

                // Update alarm
                Alarm.updateAlarm(cr, alarm);
                /*
                 * if (alarm.enabled) { return setupAlarmInstance(context,
                 * alarm); }
                 */

                return null;
            }

            @Override
            protected void onPostExecute(Void instance) {
                /*
                 * if (popToast && instance != null) {
                 * AlarmUtils.popAlarmSetToast(context, instance
                 * .getAlarmTime().getTimeInMillis()); }
                 */
            }
        };
        updateTask.execute();
    }

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        hideUndoBar(true, event);
        return false;
    }

    public void showNumberPicker(final Alarm alarm) {
        AlertDialog.Builder builder = new AlertDialog.Builder(getBaseContext());
        builder.setTitle("Select Battery Level");
        View view = LayoutInflater.from(getBaseContext()).inflate(R.layout.number_picker, null);
        final NumberPicker picker = (NumberPicker) view.findViewById(R.id.numberPicker);
        picker.setMinValue(1);
        picker.setMaxValue(100);
        picker.setValue(alarm.battery);
        builder.setView(view);
        builder.setPositiveButton("Ok", new DialogInterface.OnClickListener() {

            @Override
            public void onClick(DialogInterface dialog, int which) {

                setLevel(alarm, picker.getValue());

            }
        });
        builder.setNegativeButton(android.R.string.cancel, null);
        builder.show();
    }

    public void setLevel(Alarm alarm, int level) {
        alarm.battery = level;
        asyncUpdateAlarm(alarm, false);
    }

}