net.niyonkuru.koodroid.ui.DataDetailFragment.java Source code

Java tutorial

Introduction

Here is the source code for net.niyonkuru.koodroid.ui.DataDetailFragment.java

Source

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

package net.niyonkuru.koodroid.ui;

import android.content.Context;
import android.database.Cursor;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
import android.text.format.DateUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.FrameLayout.LayoutParams;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

import java.sql.Date;
import java.util.Calendar;

import net.niyonkuru.koodroid.R;
import net.niyonkuru.koodroid.provider.AccountContract.Subscribers;
import net.niyonkuru.koodroid.provider.AccountContract.Usages;
import net.niyonkuru.koodroid.util.CalendarUtils;

import org.achartengine.ChartFactory;
import org.achartengine.GraphicalView;
import org.achartengine.chart.BarChart.Type;
import org.achartengine.model.SeriesSelection;
import org.achartengine.model.XYMultipleSeriesDataset;
import org.achartengine.model.XYSeries;
import org.achartengine.renderer.SimpleSeriesRenderer;
import org.achartengine.renderer.XYMultipleSeriesRenderer;

/**
 * Displays daily {@link Usages} for a subscriber.
 */
public class DataDetailFragment extends DetailFragment {
    // private static final String TAG = "DataDetailFragment";

    private AlternatingColorAdapter mAdapter;

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

        setTitle(null);
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);

        /* load data again to be used by the graph */
        getLoaderManager().initLoader(0, null, this);

        ListView lv = getListView();

        LayoutInflater inflater = LayoutInflater.from(mContext);

        View graph = inflater.inflate(R.layout.usage_graph, lv, false);
        lv.addHeaderView(graph, null, false);

        View header = inflater.inflate(R.layout.usage_list_item_labels, lv, false);
        lv.addHeaderView(header, null, false);

        lv.setDividerHeight(0);

        mAdapter = new UsageAdapter(mContext);

        setListAdapter(mAdapter);

        setListShown(false);
    }

    @Override
    public Loader<Cursor> onCreateLoader(int id, Bundle args) {
        String dataUsage = getResources().getString(R.string.parser_usage_service_data);

        CursorLoader loader = new CursorLoader(mContext, Subscribers.buildUsagesUri(getSubscriber()),
                UsagesQuery.PROJECTION, Usages.USAGE_SERVICE + "='" + dataUsage + "'", null, Usages.DEFAULT_SORT);
        loader.setUpdateThrottle(DateUtils.SECOND_IN_MILLIS);

        return loader;
    }

    @Override
    public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
        if (loader.getId() == 0) {
            mAdapter.swapCursor(data);

            if (isResumed()) {
                setListShown(true);
            } else {
                setListShownNoAnimation(true);
            }
        } else { /* graph data processed here */

            new GraphingTask().execute(data);
        }
    }

    private class GraphingTask extends AsyncTask<Cursor, Integer, XYMultipleSeriesDataset> {
        private XYMultipleSeriesRenderer mRenderer;

        @Override
        protected XYMultipleSeriesDataset doInBackground(Cursor... params) {
            int minX = 1, maxX = 30;

            mRenderer = getBarRenderer(minX, maxX);

            return getBarDataset(params[0], minX, maxX);
        }

        @Override
        protected void onPostExecute(XYMultipleSeriesDataset dataset) {
            if (dataset == null)
                return;

            final GraphicalView chart = ChartFactory.getBarChartView(mContext, dataset, mRenderer, Type.DEFAULT);

            chart.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    SeriesSelection seriesSelection = chart.getCurrentSeriesAndPoint();
                    if (seriesSelection != null) {
                        int value = (int) seriesSelection.getValue();

                        String kilobytes = getResources().getQuantityString(R.plurals.kilobytes, value, value);

                        Toast.makeText(mContext, kilobytes, Toast.LENGTH_SHORT).show();
                    }
                }
            });

            FrameLayout graphView = (FrameLayout) getView().findViewById(R.id.chart);
            graphView.removeAllViews();

            graphView.addView(chart, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
        }
    }

    private XYMultipleSeriesDataset getBarDataset(Cursor cursor, int x, int maxX) {
        XYMultipleSeriesDataset dataset = new XYMultipleSeriesDataset();

        XYSeries series = new XYSeries(null);

        Calendar cal = Calendar.getInstance();
        CalendarUtils.trimTimestamp(cal);

        if (cursor.isClosed() || !cursor.moveToFirst())
            return null;

        while (x <= maxX) {
            double count = 0;

            if (!cursor.isAfterLast()) { /* cursor has data */
                Date rowDate = new Date(cal.getTimeInMillis());
                Date currDate = Date.valueOf(cursor.getString(UsagesQuery.DATE));

                if (rowDate.equals(currDate)) {
                    count = cursor.getDouble(UsagesQuery.COUNT);
                    cursor.moveToNext();
                }
            }
            cal.add(Calendar.DAY_OF_YEAR, -1);

            series.add(x++, count);
        }
        dataset.addSeries(series);

        return dataset;
    }

    private XYMultipleSeriesRenderer getBarRenderer(int minX, int maxX) {
        XYMultipleSeriesRenderer renderer = new XYMultipleSeriesRenderer();
        renderer.setShowLegend(false);
        renderer.setShowAxes(false);
        renderer.setShowGrid(false);
        renderer.setShowLabels(false);
        renderer.setInScroll(true);

        renderer.setZoomEnabled(false, false);
        renderer.setPanEnabled(false, false);

        renderer.setBarSpacing(0.1);
        renderer.setMargins(new int[] { 0, 0, -1, 0 });

        /* this avoid a bug that cuts off the first and last bar */
        renderer.setXAxisMin(minX - 1);
        renderer.setXAxisMax(maxX + 1);

        SimpleSeriesRenderer r = new SimpleSeriesRenderer();
        r.setColor(getResources().getColor(R.color.blue));

        renderer.addSeriesRenderer(r);

        return renderer;
    }

    @Override
    public void onLoaderReset(Loader<Cursor> loader) {
        mAdapter.swapCursor(null);
    }

    public class UsageAdapter extends AlternatingColorAdapter {
        public UsageAdapter(Context context) {
            super(context);
        }

        @Override
        public void bindView(View view, Context context, Cursor cursor) {
            ViewHolder holder = (ViewHolder) view.getTag();
            if (holder == null) {
                holder = new ViewHolder();

                holder.usage_date = (TextView) view.findViewById(R.id.usage_date);
                holder.usage_cost = (TextView) view.findViewById(R.id.usage_cost);
                holder.usage = (TextView) view.findViewById(R.id.usage);
                view.setTag(holder);
            }

            holder.usage_date.setText(cursor.getString(UsagesQuery.DATE));
            holder.usage_cost.setText(formatMoney(cursor.getString(UsagesQuery.AMOUNT)));
            holder.usage.setText(cursor.getString(UsagesQuery.COUNT));
        }

        @Override
        public View newView(Context context, Cursor cursor, ViewGroup parent) {
            return LayoutInflater.from(context).inflate(R.layout.usage_list_item, parent, false);
        }

        class ViewHolder {
            TextView usage_date, usage, usage_cost;
        }
    }

    /**
     * {@link Usages} query parameters
     */
    public interface UsagesQuery {
        String[] PROJECTION = { Usages._ID, Usages.USAGE_DATE, Usages.USAGE_COUNT, Usages.USAGE_AMOUNT };

        int DATE = 1;
        int COUNT = 2;
        int AMOUNT = 3;
    }
}