ch.eitchnet.android.mabea.activity.TodayFragment.java Source code

Java tutorial

Introduction

Here is the source code for ch.eitchnet.android.mabea.activity.TodayFragment.java

Source

/*
 * Copyright (c) 2012, Robert von Burg
 *
 * All rights reserved.
 *
 * This file is part of the XXX.
 *
 *  XXX is free software: you can redistribute 
 *  it and/or modify it under the terms of the GNU General Public License as 
 *  published by the Free Software Foundation, either version 3 of the License, 
 *  or (at your option) any later version.
 *
 *  XXX is distributed in the hope that it will 
 *  be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with XXX.  If not, see 
 *  <http://www.gnu.org/licenses/>.
 */
package ch.eitchnet.android.mabea.activity;

import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.joda.time.LocalDateTime;

import android.app.ProgressDialog;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.SimpleAdapter;
import android.widget.TextView;
import android.widget.ToggleButton;
import ch.eitchnet.android.mabea.MabeaApplication;
import ch.eitchnet.android.mabea.MabeaConnection;
import ch.eitchnet.android.mabea.R;
import ch.eitchnet.android.mabea.model.Booking;
import ch.eitchnet.android.mabea.model.MabeaContext;
import ch.eitchnet.android.mabea.model.MabeaState;
import ch.eitchnet.android.mabea.model.MabeaState.State;
import ch.eitchnet.android.mabea.model.Today;
import ch.eitchnet.android.util.DialogUtil;
import ch.eitchnet.android.util.JodaHelper;
import ch.eitchnet.android.util.Logger;
import ch.eitchnet.android.util.SyncExec;

/**
 * @author Robert von Burg <eitch@eitchnet.ch>
 * 
 */
public class TodayFragment extends Fragment {

    private static final String TAG = TodayFragment.class.getSimpleName();

    private View rootView;
    private ToggleButton toggleStateBtn;
    private ProgressBar progressBar;
    private ProgressDialog progressDlg;
    private ListView bookingsToday;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        Logger.i(TAG, "onCreateView", "called");
        this.rootView = inflater.inflate(R.layout.fragment_today_layout, container, false);

        this.progressBar = (ProgressBar) this.rootView.findViewById(R.id.progressBar);
        this.progressBar.setVisibility(View.INVISIBLE);

        this.toggleStateBtn = (ToggleButton) this.rootView.findViewById(R.id.toggleLoggedIn);

        this.bookingsToday = (ListView) this.rootView.findViewById(R.id.bookingsToday);
        List<? extends Map<String, ?>> data = new ArrayList<Map<String, ?>>();
        int resource = R.layout.list_item_booking_today;
        String[] from = new String[] {};
        int[] to = new int[] {};
        SimpleAdapter adapter = new SimpleAdapter(getActivity(), data, resource, from, to);

        this.bookingsToday.setAdapter(adapter);

        registerObservers();

        return this.rootView;
    }

    @Override
    public void onPause() {
        Logger.i(TAG, "onPause", "Pausing.");
        super.onPause();
    }

    @Override
    public void onResume() {
        updateUi();
        Logger.i(TAG, "onPause", "Resumed.");
        super.onResume();
    }

    private void registerObservers() {
        this.toggleStateBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                TodayFragment.this.progressBar.setVisibility(View.VISIBLE);
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        toggleLoginState();
                    }
                }, "ToggleState").start();
            }
        });
    }

    private void toggleLoginState() {
        try {

            // validate the context
            MabeaContext context = MabeaApplication.getContext();
            if (!context.isInitialized()) {
                String title = "State change failed";
                String msg = "The settings have not yet been validated, please use the settings tab to configure and validate the settings.";
                DialogUtil.showErrorDialog(getActivity(), title, msg);

                updateUiOnUiThread();
                return;
            }

            // first see what state we expect
            // but since the UI button was pressed and thus toggled, we must negate current UI
            MabeaState.State expectedState = !toggleStateBtn.isChecked() ? State.LOGGED_IN : State.LOGGED_OUT;

            // get the connection and see if we need to refresh the state
            MabeaConnection connection = context.getConnection();
            if (!checkConnection()) {
                Logger.i(TAG, "toggleLoginState", "refresh failed as connection is not ok. Stopping");
                updateUiOnUiThread();
                return;
            }

            // check that we don't have a state mismatch
            MabeaState currentMabeaState = connection.getMabeaState();
            if (!handleCurrentState(expectedState, currentMabeaState)) {
                Logger.i(TAG, "toggleLoginState",
                        "It seems the current server state is invalid and not recoverable. Stopping");
                updateUiOnUiThread();
                return;
            }

            // now toggle the actual state
            State currentState = currentMabeaState.getState();
            if (currentState == State.LOGGED_OUT) {
                login();
            } else if (currentState == State.LOGGED_IN) {
                logout();
            } else {
                throw new IllegalStateException("Current state is " + currentState + " can't toggle that!");
            }

            updateUiOnUiThread();

        } catch (Exception e) {
            Logger.e(TAG, "toggleLoginState", e.getMessage(), e);
            DialogUtil.showExceptionDialog(getActivity(), TAG, e);

            if (progressDlg != null)
                progressDlg.dismiss();

            updateUiOnUiThread();
        }
    }

    /**
     * @param expectedState
     * @param currentState
     * @return
     */
    private boolean handleCurrentState(State expectedState, MabeaState currentState) {

        // if the state is as expected, then all is good
        if (expectedState.equals(currentState.getState())) {
            return true;
        }

        // we have a mismatch. We can recover from it, if the time stamp is 
        // later than what we have currently registered

        // so check if the server state is later than the current booking
        Today today = MabeaApplication.getContext().getToday();
        Booking latestBooking = today.getLatestBooking();
        LocalDateTime expectedDate = latestBooking.getTimestamp();
        LocalDateTime currentDate = currentState.getStateTime();
        if (expectedDate.isAfter(currentDate) && currentDate.isBefore(LocalDateTime.now())) {

            String title = "State mismatch";
            String msg = "The state on the server is {0} which is not the expected state {1}.\n\nThe local state can't be toggled as the local timestamp {2} is after the new state from the server. Please check your expected state.";
            msg = MessageFormat.format(msg, currentState.getState(), expectedState,
                    JodaHelper.toDateHourMinute(expectedDate), JodaHelper.toDateHourMinute(currentDate));
            DialogUtil.showErrorDialog(getActivity(), title, msg);
            return false;
        }

        // fix state mismatch by adding a new booking
        Booking booking = new Booking(currentState.getState(), currentDate, currentState.getBalance());
        today.addBooking(booking);

        // notify user of fix
        String title = "State mismatch";
        String msg = "The state on the server is {0} which is not the expected state {1}.\n\nAs the time stamp of the current state is later than the latest booking, a new booking was added to today. Please check your expected state.";
        msg = MessageFormat.format(msg, currentState.getState(), expectedState,
                JodaHelper.toDateHourMinute(expectedDate), JodaHelper.toDateHourMinute(currentDate));
        DialogUtil.showErrorDialog(getActivity(), title, msg);

        return true;
    }

    private boolean checkConnection() {
        MabeaContext context = MabeaApplication.getContext();
        MabeaConnection connection = context.getConnection();

        if (!connection.needsRefresh()) {
            return true;
        }

        SyncExec action = new SyncExec() {
            @Override
            protected void execute() {
                String title = "Refreshing connection";
                String msg = "Connection needs to be refreshed, please wait...";
                progressDlg = ProgressDialog.show(getActivity(), title, msg);
            }
        };
        action.runOnUiThread(getActivity());

        Logger.i(TAG, "toggleLoginState", "refreshing connection...");

        State state = connection.checkConnection();
        if (state == State.UNKNOWN) {
            String title = "Toggling login state failed";
            String msg = "Connection could not be verified due to error: " + connection.getErrorMsg();
            DialogUtil.showErrorDialog(getActivity(), title, msg);
        }

        if (progressDlg != null)
            progressDlg.dismiss();

        return !connection.hasError();
    }

    private void login() {

        MabeaContext context = MabeaApplication.getContext();
        MabeaConnection connection = context.getConnection();
        State state = connection.login();
        if (state == State.LOGGED_IN) {
            MabeaState mabeaState = connection.getMabeaState();
            Booking newBooking = new Booking(mabeaState.getState(), mabeaState.getStateTime(),
                    mabeaState.getBalance());
            context.getToday().addBooking(newBooking);
        } else {
            String title = "Logging in failed";
            String msg = "Failed to login due to error: " + connection.getErrorMsg();
            DialogUtil.showErrorDialog(getActivity(), title, msg);
        }
    }

    private void logout() {

        MabeaContext context = MabeaApplication.getContext();
        MabeaConnection connection = context.getConnection();
        State state = connection.logout();
        if (state == State.LOGGED_OUT) {
            MabeaState mabeaState = connection.getMabeaState();
            context.getToday().addBooking(
                    new Booking(mabeaState.getState(), mabeaState.getStateTime(), mabeaState.getBalance()));
        } else {
            String title = "Logging out failed";
            String msg = "Failed to logout due to error: " + connection.getErrorMsg();
            DialogUtil.showErrorDialog(getActivity(), title, msg);
        }
    }

    public void updateUiOnUiThread() {
        getActivity().runOnUiThread(new Runnable() {
            @Override
            public void run() {
                updateUi();
            }
        });
    }

    public void updateUi() {
        if (this.rootView == null) {
            return;
        }

        try {
            Logger.i(TAG, "updateUi", "Updating UI...");
            this.progressBar.setVisibility(View.INVISIBLE);

            MabeaContext context = MabeaApplication.getContext();
            if (!context.isConnectionOk()) {
                Logger.i(TAG, "updateUi", "Connection not ok. Stopping.");
                this.toggleStateBtn.setChecked(false);
                return;
            }

            MabeaState connectionState = context.getConnection().getMabeaState();
            TextView nameTxt = (TextView) this.rootView.findViewById(R.id.txtName);
            nameTxt.setText(connectionState.getName() + "(" + context.getSetting().getUsername() + ")");

            Today today = context.getToday();
            TextView status1Txt = (TextView) this.rootView.findViewById(R.id.txtStatus1);
            Booking booking = today.getLatestBooking();
            String time = JodaHelper.toHourMinute(booking.getTimestamp());
            State loginState = booking.getState();
            if (loginState == State.LOGGED_IN) {
                status1Txt.setText("Logged in since " + time + " / Balance: "
                        + JodaHelper.toHourMinute(today.getActualBalance()));
                this.toggleStateBtn.setChecked(true);
            } else if (loginState == State.LOGGED_OUT) {
                status1Txt.setText("Logged out since " + time + " / Balance: "
                        + JodaHelper.toHourMinute(today.getActualBalance()));
                this.toggleStateBtn.setChecked(false);
            } else {
                status1Txt.setText("Unknown state since " + time + " / Balance: "
                        + JodaHelper.toHourMinute(today.getActualBalance()));
                this.toggleStateBtn.setChecked(false);
            }
            TextView status2Txt = (TextView) this.rootView.findViewById(R.id.txtStatus2);
            status2Txt.setText("Balance: " + JodaHelper.toHourMinute(today.getEstimatedBalance()) + " / Work: "
                    + JodaHelper.toHourMinute(today.getWorkToday()) + " ("
                    + JodaHelper.toHourMinute(today.getRemainingWork()) + ")");

        } catch (Exception e) {
            DialogUtil.showExceptionDialog(getActivity(), "Update UI failed", e);
            this.progressBar.setVisibility(View.INVISIBLE);
        }
    }
}