com.google.android.apps.paco.ExperimentScheduleActivity.java Source code

Java tutorial

Introduction

Here is the source code for com.google.android.apps.paco.ExperimentScheduleActivity.java

Source

/*
 * Copyright 2011 Google Inc. All Rights Reserved.
 * Copyright 2011 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance  with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package com.google.android.apps.paco;

import java.util.ArrayList;
import java.util.List;

import org.joda.time.DateMidnight;
import org.joda.time.DateTime;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnMultiChoiceClickListener;
import android.content.Intent;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.RadioGroup.OnCheckedChangeListener;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.TimePicker;
import android.widget.Toast;

import com.google.common.base.Strings;
import com.pacoapp.paco.R;
import com.pacoapp.paco.model.Experiment;
import com.pacoapp.paco.model.ExperimentProviderUtil;
import com.pacoapp.paco.shared.model2.ExperimentGroup;
import com.pacoapp.paco.shared.model2.Schedule;
import com.pacoapp.paco.shared.model2.ScheduleTrigger;
import com.pacoapp.paco.shared.model2.SignalTime;
import com.pacoapp.paco.ui.ExperimentLoadingActivity;
import com.pacoapp.paco.ui.ScheduleDetailFragment;
import com.pacoapp.paco.ui.Validation;
import com.pacoapp.paco.utils.IntentExtraHelper;

public class ExperimentScheduleActivity extends Activity implements ExperimentLoadingActivity {

    private static final String TIME_FORMAT_STRING = "hh:mm aa";

    private Experiment experiment;
    private ExperimentProviderUtil experimentProviderUtil;
    private TimePicker timePicker;
    private TextView startHourField;
    private TextView endHourField;
    private Spinner repeatRate;
    private boolean[] selections;
    private Button dowButton;

    private Spinner domSpinner;

    private Spinner nthOfMonthSpinner;

    private TextView nthOfMonthText;

    private TextView dayOfMonthText;

    private RadioGroup radioGroup;

    private ListView timeList;

    private LayoutInflater inflater;

    private LinearLayout timesScheduleLayout;

    private Schedule schedule;

    private boolean userEditable = true;

    private ExperimentGroup experimentGroup;

    private ScheduleTrigger scheduleTrigger;

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

        final Intent intent = getIntent();

        experimentProviderUtil = new ExperimentProviderUtil(this);
        IntentExtraHelper.loadExperimentInfoFromIntent(this, intent, experimentProviderUtil);

        if (experiment == null) {
            Toast.makeText(this, R.string.cannot_find_the_experiment_warning, Toast.LENGTH_SHORT).show();
            finish();
        } else {
            loadScheduleFromIntent();
            if (schedule == null) {
                Toast.makeText(this, R.string.cannot_find_the_experiment_warning, Toast.LENGTH_SHORT).show();
                finish();
            } else {
                userEditable = getUserEditableFromIntent();
                setUpSchedulingLayout();
            }
        }

    }

    private boolean getUserEditableFromIntent() {
        if (getIntent().getExtras() != null) {
            return getIntent().getBooleanExtra(ScheduleDetailFragment.USER_EDITABLE_SCHEDULE, true);
        }
        return false;
    }

    private void loadScheduleFromIntent() {
        if (getIntent().getExtras() != null) {
            long scheduleTriggerId = getIntent().getExtras().getLong(ScheduleDetailFragment.SCHEDULE_TRIGGER_ID);
            Long scheduleId = getIntent().getExtras().getLong(ScheduleDetailFragment.SCHEDULE_ID);
            scheduleTrigger = (ScheduleTrigger) experimentGroup.getActionTriggerById(scheduleTriggerId);
            schedule = scheduleTrigger.getSchedulesById(scheduleId);
        }
    }

    private void setUpSchedulingLayout() {
        // setup ui pieces for times lists and esm start/end timepickers
        inflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
        timesScheduleLayout = (LinearLayout) inflater.inflate(R.layout.times_schedule, null);
        timePicker = (TimePicker) timesScheduleLayout.findViewById(R.id.DailyScheduleTimePicker);
        timePicker.setIs24HourView(false);
        // end setup ui pieces

        if (schedule == null) {
            setContentView(R.layout.self_report_schedule);
            save();
            return;
        }

        createSelections();

        if (schedule.getScheduleType().equals(Schedule.WEEKDAY)
                || schedule.getScheduleType().equals(Schedule.DAILY)) {
            showDailyScheduleConfiguration();
        } else if (schedule.getScheduleType().equals(Schedule.WEEKLY)) {
            showWeeklyScheduleConfiguration();
        } else if (schedule.getScheduleType().equals(Schedule.MONTHLY)) {
            showMonthlyScheduleConfiguration();
        } else if (schedule.getScheduleType().equals(Schedule.ESM)) {
            showEsmScheduleConfiguration();
        }
        setupScheduleSaving();
    }

    // Visible for testing
    public void setActivityProperties(Experiment experiment, ExperimentProviderUtil experimentProviderUtil) {
        this.experiment = experiment;
        this.experimentProviderUtil = experimentProviderUtil;

        // TODO: Uncomment this to do true instrumentation testing.
        // setUpSchedulingLayout();
    }

    private void setupScheduleSaving() {
        if (userEditable) {
            save();
        } else {
            setupSaveButton();
        }
    }

    private void showEsmScheduleConfiguration() {
        setContentView(R.layout.esm_schedule);
        TextView title = (TextView) findViewById(R.id.experimentNameSchedule);
        title.setText(experiment.getExperimentDAO().getTitle());

        startHourField = (Button) findViewById(R.id.startHourTimePickerLabel);
        startHourField.setText(new DateMidnight().toDateTime()
                .withMillisOfDay(schedule.getEsmStartHour().intValue()).toString(TIME_FORMAT_STRING));

        endHourField = (Button) findViewById(R.id.endHourTimePickerLabel);
        endHourField.setText(new DateMidnight().toDateTime().withMillisOfDay(schedule.getEsmEndHour().intValue())
                .toString(TIME_FORMAT_STRING));

        // TODO (bobevans): get rid of this duplication

        startHourField.setOnClickListener(new OnClickListener() {

            public void onClick(View v) {
                final AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(ExperimentScheduleActivity.this);
                unsetTimesViewParent();
                dialogBuilder.setView(timesScheduleLayout);
                final AlertDialog dialog = dialogBuilder.setTitle(R.string.start_time_title).create();

                Long offset = schedule.getEsmStartHour();
                DateTime startHour = new DateMidnight().toDateTime().withMillisOfDay(offset.intValue());
                timePicker.setCurrentHour(startHour.getHourOfDay());
                timePicker.setCurrentMinute(startHour.getMinuteOfHour());

                dialog.setButton(Dialog.BUTTON_POSITIVE, getString(R.string.save_button),
                        new DialogInterface.OnClickListener() {

                            public void onClick(DialogInterface dialog, int which) {
                                schedule.setEsmStartHour(getHourOffsetFromPicker());
                                startHourField.setText(getTextFromPicker(schedule.getEsmStartHour().intValue()));
                            }

                        });
                dialog.show();
            }
        });

        //

        endHourField.setOnClickListener(new OnClickListener() {

            public void onClick(View v) {
                final AlertDialog.Builder endHourDialogBuilder = new AlertDialog.Builder(
                        ExperimentScheduleActivity.this);
                unsetTimesViewParent();
                endHourDialogBuilder.setView(timesScheduleLayout);
                final AlertDialog endHourDialog = endHourDialogBuilder.setTitle(R.string.end_time_title).create();

                Long offset = schedule.getEsmEndHour();
                DateTime endHour = new DateMidnight().toDateTime().withMillisOfDay(offset.intValue());
                timePicker.setCurrentHour(endHour.getHourOfDay());
                timePicker.setCurrentMinute(endHour.getMinuteOfHour());

                endHourDialog.setButton(Dialog.BUTTON_POSITIVE, getString(R.string.save_button),
                        new DialogInterface.OnClickListener() {

                            public void onClick(DialogInterface dialog, int which) {
                                schedule.setEsmEndHour(getHourOffsetFromPicker());
                                endHourField.setText(getTextFromPicker(schedule.getEsmEndHour().intValue()));
                            }

                        });
                endHourDialog.show();
            }
        });

    }

    private void unsetTimesViewParent() {
        if (timesScheduleLayout.getParent() != null) {
            ((ViewGroup) timesScheduleLayout.getParent()).removeView(timesScheduleLayout);
        }
    }

    private void showDailyScheduleConfiguration() {
        setContentView(R.layout.daily_schedule);
        if (schedule.getScheduleType().equals(Schedule.DAILY)) {
            createRepeatRate(getString(R.string.days));
        } else {
            hideRepeatRate();
        }
        createTimesList();
    }

    private void hideRepeatRate() {
        LinearLayout repeatRateLayout = (LinearLayout) findViewById(R.id.RepeatPeriodLayout);
        repeatRateLayout.setVisibility(View.GONE);
    }

    private void showWeeklyScheduleConfiguration() {
        setContentView(R.layout.weekly_schedule);
        createRepeatRate(getString(R.string.weeks));

        createDaysOfWeekPicker();
        createTimesList();
    }

    private void showMonthlyScheduleConfiguration() {
        setContentView(R.layout.monthly_schedule);
        createRepeatRate(getString(R.string.months));

        createDayOfMonth();

        createNthOfMonth();
        createDaysOfWeekPicker();

        radioGroup = (RadioGroup) findViewById(R.id.RadioGroup01);

        if (schedule.getByDayOfMonth()) {
            ((RadioButton) findViewById(R.id.domRadio)).setChecked(true);
        } else {
            ((RadioButton) findViewById(R.id.dowRadio)).setChecked(true);
        }
        radioGroup.setOnCheckedChangeListener(new OnCheckedChangeListener() {
            public void onCheckedChanged(RadioGroup group, int checkedId) {
                toggleByDayOfMonth_DayOfWeekWidgets(checkedId == R.id.domRadio);
            }

        });
        toggleByDayOfMonth_DayOfWeekWidgets(schedule.getByDayOfMonth());
        createTimesList();
    }

    private void createDayOfMonth() {
        dayOfMonthText = (TextView) findViewById(R.id.dayOfMonthText);
        domSpinner = (Spinner) findViewById(R.id.dayOfMonthSpinner);
        ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(this, R.array.repeat_range,
                android.R.layout.simple_spinner_item);
        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        domSpinner.setAdapter(adapter);
        domSpinner.setSelection(schedule.getDayOfMonth() - 1);
        domSpinner.setOnItemSelectedListener(new OnItemSelectedListener() {

            public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
                schedule.setDayOfMonth(arg2 + 1);
            }

            public void onNothingSelected(AdapterView<?> arg0) {
            }
        });
    }

    private void createNthOfMonth() {
        nthOfMonthSpinner = (Spinner) findViewById(R.id.NthOfMonthSpinner);
        nthOfMonthText = (TextView) findViewById(R.id.NthOfMonthText);
        ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(this, R.array.nth_of_month,
                android.R.layout.simple_spinner_item);
        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        nthOfMonthSpinner.setAdapter(adapter);
        nthOfMonthSpinner.setSelection(schedule.getNthOfMonth());
        nthOfMonthSpinner.setOnItemSelectedListener(new OnItemSelectedListener() {

            public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
                schedule.setNthOfMonth(arg2);
            }

            public void onNothingSelected(AdapterView<?> arg0) {
            }
        });

    }

    private void toggleByDayOfMonth_DayOfWeekWidgets(boolean isByDayOfMonth) {
        if (isByDayOfMonth) {
            schedule.setByDayOfMonth(Boolean.TRUE);
            nthOfMonthText.setVisibility(View.GONE);
            nthOfMonthSpinner.setVisibility(View.GONE);
            dayOfMonthText.setVisibility(View.VISIBLE);
            dowButton.setVisibility(View.GONE);
            domSpinner.setVisibility(View.VISIBLE);
        } else {
            schedule.setByDayOfMonth(Boolean.FALSE);
            nthOfMonthText.setVisibility(View.VISIBLE);
            nthOfMonthSpinner.setVisibility(View.VISIBLE);
            dayOfMonthText.setVisibility(View.GONE);
            dowButton.setVisibility(View.VISIBLE);
            domSpinner.setVisibility(View.GONE);
        }
    }

    private void createDaysOfWeekPicker() {
        dowButton = (Button) findViewById(R.id.dow_button);
        dowButton.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                showDialog(0);
            }
        });
    }

    private void createRepeatRate(String period) {
        repeatRate = (Spinner) findViewById(R.id.RepeatRate);
        ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(this, R.array.repeat_range,
                android.R.layout.simple_spinner_item);
        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        repeatRate.setAdapter(adapter);
        repeatRate.setSelection(schedule.getRepeatRate() - 1);

        repeatRate.setOnItemSelectedListener(new OnItemSelectedListener() {

            public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
                schedule.setRepeatRate(position + 1);
            }

            public void onNothingSelected(AdapterView<?> parent) {
                // Nothing to be done here.
            }
        });

        TextView repeatPeriodLabel = (TextView) findViewById(R.id.RepeatPeriodLabel);
        repeatPeriodLabel.setText(" " + period);
    }

    private void createTimesList() {
        TextView title = (TextView) findViewById(R.id.experimentNameSchedule);
        title.setText(experiment.getExperimentDAO().getTitle());

        timeList = (ListView) findViewById(R.id.timesList);
        final List<SignalTime> times = schedule.getSignalTimes();
        setArrayAdapter(times);

        // timeList.setOnItemClickListener(new OnItemClickListener() {
        // public void onItemClick(AdapterView<?> listview, View textview, final int
        // position, long id) {
        // final AlertDialog.Builder dialogBuilder = new
        // AlertDialog.Builder(ExperimentScheduleActivity.this);
        // unsetTimesViewParent();
        // dialogBuilder.setView(timesScheduleLayout);
        // final AlertDialog dialog =
        // dialogBuilder.setTitle("Modify Time").create();
        //
        // DateTime selectedDateTime = new
        // DateTime().withMillisOfDay(times.get(position).intValue());
        // timePicker.setCurrentHour(selectedDateTime.getHourOfDay());
        // timePicker.setCurrentMinute(selectedDateTime.getMinuteOfHour());
        //
        // dialog.setButton(Dialog.BUTTON_POSITIVE, "Save", new
        // DialogInterface.OnClickListener() {
        //
        // public void onClick(DialogInterface dialog, int which) {
        // long offsetMillis = timePicker.getCurrentHour() * 60 * 60 * 1000 +
        // timePicker.getCurrentMinute() * 60 * 1000;
        // times.set(position, offsetMillis);
        // //timeAdapter.notifyDataSetChanged();
        // setArrayAdapter(times);
        // }
        //
        // });
        // dialog.show();
        // }
        // });
    }

    private void setArrayAdapter(final List<SignalTime> times) {
        List<String> timeStrs = new ArrayList<String>();
        for (SignalTime time : times) {
            timeStrs.add(getStringForTime(time));
        }

        final ArrayAdapter<String> timeAdapter = new ButtonArrayAdapter(this, R.layout.timelist_item, timeStrs);
        timeList.setAdapter(timeAdapter);
    }

    private String getStringForTime(SignalTime time) {
        if (time.getType() == SignalTime.FIXED_TIME) {
            return new DateTime().withMillisOfDay(time.getFixedTimeMillisFromMidnight()).toString("hh:mm a");
        } else {
            return "+" + time.getOffsetTimeMillis() / 1000 / 60 + " mins";
        }
    }

    class ButtonArrayAdapter extends ArrayAdapter<String> {
        public ButtonArrayAdapter(Context context, int textViewResourceId, List<String> objects) {
            super(context, textViewResourceId, objects);
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            String text = getItem(position);
            if (null == convertView) {
                convertView = inflater.inflate(R.layout.timelist_item, null);
            }

            TextView label = (TextView) convertView.findViewById(R.id.textView1);
            String labelText = schedule.getSignalTimes().get(position).getLabel();
            if (Strings.isNullOrEmpty(labelText)) {
                labelText = "Time " + Integer.toString(position + 1);
            }
            label.setText(labelText + ": ");
            Button btn = (Button) convertView.findViewById(R.id.timePickerLabel);
            btn.setText(text);
            if (text.startsWith("+")) {
                btn.setEnabled(false);
            } else {
                btn.setEnabled(true);
            }
            // set listener for the whole row
            // convertView.setOnClickListener(new OnItemClickListener(position));
            btn.setOnClickListener(new OnItemClickListener(position));
            return convertView;
        }
    }

    private class OnItemClickListener implements OnClickListener {
        private int position;

        OnItemClickListener(int position) {
            this.position = position;
        }

        public void onClick(View arg0) {
            final List<SignalTime> times = schedule.getSignalTimes();
            final AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(ExperimentScheduleActivity.this);
            unsetTimesViewParent();
            dialogBuilder.setView(timesScheduleLayout);
            final AlertDialog dialog = dialogBuilder.setTitle(R.string.modify_time_title).create();

            DateTime selectedDateTime = new DateTime()
                    .withMillisOfDay(times.get(position).getFixedTimeMillisFromMidnight());
            timePicker.setCurrentHour(selectedDateTime.getHourOfDay());
            timePicker.setCurrentMinute(selectedDateTime.getMinuteOfHour());

            dialog.setButton(Dialog.BUTTON_POSITIVE, getString(R.string.save_button),
                    new DialogInterface.OnClickListener() {

                        public void onClick(DialogInterface dialog, int which) {
                            timePicker.clearFocus(); // Maybe this will save whatever value is
                            // there,
                            // so that the current hour will work when the user is editing it
                            // directly.
                            int offsetMillis = timePicker.getCurrentHour() * 60 * 60 * 1000
                                    + timePicker.getCurrentMinute() * 60 * 1000;
                            times.get(position).setFixedTimeMillisFromMidnight(offsetMillis);
                            // timeAdapter.notifyDataSetChanged();
                            setArrayAdapter(times);
                        }

                    });
            dialog.show();
        }
    }

    private boolean[] createSelections() {
        selections = new boolean[7];
        int weekDaysScheduled = schedule.getWeekDaysScheduled();
        for (int i = 0; i < Schedule.DAYS_OF_WEEK.length; i++) {
            selections[i] = (weekDaysScheduled & Schedule.DAYS_OF_WEEK[i]) == Schedule.DAYS_OF_WEEK[i];
        }
        return selections;
    }

    private void setupSaveButton() {
    }

    private void save() {
        Validation valid = isValid();
        if (!valid.ok()) {
            Toast.makeText(this, valid.errorMessage(), Toast.LENGTH_LONG).show();
            return;
        } else {
            setResult(RESULT_OK, serialize(schedule));
        }
    }

    private Intent serialize(Schedule schedule2) {
        Intent intent = new Intent();
        intent.putExtra(Experiment.ACTION_TRIGGER_SPEC_ID, schedule2.getId());
        //intent.putExtra(Experiment.ACTION_TRIGGER_SPEC, JsonConverter.schedule2);
        return intent;
    }

    private Validation isValid() {
        Validation validation = new Validation();
        if (schedule != null && schedule.getScheduleType().equals(Schedule.ESM)) {
            if (schedule.getEsmStartHour() >= schedule.getEsmEndHour()) {
                validation.addMessage(getString(R.string.start_hour_must_be_before_end_hour_warning));
            }
        }
        return validation;
    }

    private Long getHourOffsetFromPicker() {
        return new Long(new DateMidnight().toDateTime().withHourOfDay(timePicker.getCurrentHour())
                .withMinuteOfHour(timePicker.getCurrentMinute()).getMillisOfDay());
    }

    private String getTextFromPicker(int esmOffset) {
        return new DateMidnight().toDateTime().withMillisOfDay(esmOffset).toString(TIME_FORMAT_STRING);
    }

    protected Dialog onCreateDialog(int id, Bundle args) {
        return getDaysOfWeekDialog();
    }

    @Override
    protected Dialog onCreateDialog(int id) {
        return super.onCreateDialog(id);
    }

    private AlertDialog getDaysOfWeekDialog() {
        AlertDialog.Builder dialogBldr = new AlertDialog.Builder(this).setTitle(R.string.days_of_week_title);

        if (schedule.getScheduleType().equals(Schedule.WEEKLY)) {
            dialogBldr.setMultiChoiceItems(R.array.days_of_week, selections, new OnMultiChoiceClickListener() {
                public void onClick(DialogInterface dialog, int which, boolean isChecked) {
                    selections[which] = isChecked;
                }
            });
        } else {
            int selected = 0;
            for (int i = 0; i < selections.length; i++) {
                if (selections[i]) {
                    selected = i;
                    break;
                }
            }
            dialogBldr.setSingleChoiceItems(R.array.days_of_week, selected, new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int which) {
                    for (int i = 0; i < selections.length; i++) {
                        selections[i] = (i == which);
                    }
                }
            });
        }

        dialogBldr.setPositiveButton(R.string.accept, new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int which) {
                int selected = 0;

                for (int i = 0; i < 7; i++) {
                    if (selections[i]) {
                        selected |= Schedule.DAYS_OF_WEEK[i];
                    }
                }
                schedule.setWeekDaysScheduled(selected);
            }

        });
        return dialogBldr.create();

    }

    // Visible for testing
    public Experiment getExperiment() {
        return experiment;
    }

    @Override
    public void setExperiment(Experiment experimentByServerId) {
        this.experiment = experimentByServerId;

    }

    @Override
    public void setExperimentGroup(ExperimentGroup groupByName) {
        this.experimentGroup = groupByName;

    }

}