com.nadmm.airports.aeronav.ChartsDownloadFragment.java Source code

Java tutorial

Introduction

Here is the source code for com.nadmm.airports.aeronav.ChartsDownloadFragment.java

Source

/*
 * FlightIntel for Pilots
 *
 * Copyright 2012-2015 Nadeem Hasan <nhasan@nadmm.com>
 *
 * This program 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.
 *
 * This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package com.nadmm.airports.aeronav;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteQueryBuilder;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.content.LocalBroadcastManager;
import android.support.v7.app.AlertDialog;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.LinearLayout.LayoutParams;
import android.widget.ProgressBar;
import android.widget.RelativeLayout;
import android.widget.TextView;

import com.nadmm.airports.Application;
import com.nadmm.airports.data.DatabaseManager;
import com.nadmm.airports.data.DatabaseManager.Dtpp;
import com.nadmm.airports.data.DatabaseManager.DtppCycle;
import com.nadmm.airports.FragmentBase;
import com.nadmm.airports.R;
import com.nadmm.airports.utils.CursorAsyncTask;
import com.nadmm.airports.utils.NetworkUtils;
import com.nadmm.airports.utils.TimeUtils;
import com.nadmm.airports.utils.UiUtils;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Locale;

public class ChartsDownloadFragment extends FragmentBase {

    private String mTppCycle;
    private String mTppVolume;
    private Cursor mCursor;
    private IntentFilter mFilter;
    private BroadcastReceiver mReceiver;
    private View mSelectedRow;
    private ProgressBar mProgressBar;
    private OnClickListener mOnClickListener;
    private boolean mExpired;
    private boolean mIsOk;
    private boolean mStop;
    private HashMap<String, View> mVolumeRowMap = new HashMap<>();

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

        mFilter = new IntentFilter();
        mFilter.addAction(AeroNavService.ACTION_GET_CHARTS);
        mFilter.addAction(AeroNavService.ACTION_CHECK_CHARTS);
        mFilter.addAction(AeroNavService.ACTION_COUNT_CHARTS);

        mReceiver = new BroadcastReceiver() {

            @Override
            public void onReceive(Context context, Intent intent) {
                String action = intent.getAction();
                switch (action) {
                case AeroNavService.ACTION_GET_CHARTS:
                    onChartDownload(context, intent);
                    break;
                case AeroNavService.ACTION_CHECK_CHARTS:
                    onChartDelete(context, intent);
                    break;
                case AeroNavService.ACTION_COUNT_CHARTS:
                    onChartCount(context, intent);
                    break;
                }
            }
        };

        mOnClickListener = new OnClickListener() {

            @Override
            public void onClick(View v) {
                if (mSelectedRow == null) {
                    mStop = false;
                    int total = (Integer) v.getTag(R.id.DTPP_CHART_TOTAL);
                    int avail = (Integer) v.getTag(R.id.DTPP_CHART_AVAIL);
                    if (avail < total) {
                        if (mIsOk && !mExpired) {
                            confirmStartDownload(v);
                        } else {
                            UiUtils.showToast(getActivity(), "Cannot start download");
                        }
                    } else {
                        confirmChartDelete(v);
                    }
                } else if (v == mSelectedRow) {
                    confirmStopDownload();
                }
            }
        };
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View v = inflate(R.layout.charts_download_view);
        return createContentView(v);
    }

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

        setBackgroundTask(new ChartsDownloadTask()).execute();
    }

    @Override
    public void onResume() {
        LocalBroadcastManager bm = LocalBroadcastManager.getInstance(getActivity());
        bm.registerReceiver(mReceiver, mFilter);

        super.onResume();
    }

    @Override
    public void onPause() {
        LocalBroadcastManager bm = LocalBroadcastManager.getInstance(getActivity());
        bm.unregisterReceiver(mReceiver);
        finishOperation();

        super.onPause();
    }

    private void confirmStartDownload(final View v) {
        int total = (Integer) v.getTag(R.id.DTPP_CHART_TOTAL);
        int avail = (Integer) v.getTag(R.id.DTPP_CHART_AVAIL);
        String tppVolume = (String) v.getTag(R.id.DTPP_VOLUME_NAME);
        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
        builder.setTitle("Start Download");
        builder.setMessage(
                String.format("Do you want to download %d charts for %s volume?", total - avail, tppVolume));
        builder.setPositiveButton("Yes", new DialogInterface.OnClickListener() {

            @Override
            public void onClick(DialogInterface dialog, int which) {
                startChartDownload(v);
            }
        });
        builder.setNegativeButton("No", null);
        builder.show();
    }

    private void startChartDownload(View v) {
        mSelectedRow = v;
        String tppVolume = (String) mSelectedRow.getTag(R.id.DTPP_VOLUME_NAME);
        VolumeDownloadTask task = new VolumeDownloadTask();
        task.execute(tppVolume);
    }

    private void confirmChartDelete(final View v) {
        int avail = (Integer) v.getTag(R.id.DTPP_CHART_AVAIL);
        String tppVolume = (String) v.getTag(R.id.DTPP_VOLUME_NAME);
        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
        builder.setTitle("Confirm Delete");
        builder.setMessage(
                String.format("Are you sure you want to delete all %d charts for %s volume?", avail, tppVolume));
        builder.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {

            @Override
            public void onClick(DialogInterface dialog, int which) {
                startChartDelete(v);
            }
        });
        builder.setNegativeButton(android.R.string.no, null);
        builder.show();
    }

    private void startChartDelete(View v) {
        mSelectedRow = v;
        String tppVolume = (String) mSelectedRow.getTag(R.id.DTPP_VOLUME_NAME);
        VolumeDeleteTask task = new VolumeDeleteTask();
        task.execute(tppVolume);
    }

    private void confirmStopDownload() {
        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
        builder.setTitle("Stop Download");
        builder.setMessage("Do you want to stop the chart download?");
        builder.setPositiveButton("Yes", new DialogInterface.OnClickListener() {

            @Override
            public void onClick(DialogInterface dialog, int which) {
                mStop = true;
            }
        });
        builder.setNegativeButton("No", null);
        builder.show();
    }

    private class ChartsDownloadTask extends CursorAsyncTask {

        @Override
        protected Cursor[] doInBackground(String... params) {
            Cursor[] result = new Cursor[2];
            SQLiteDatabase db = getDatabase(DatabaseManager.DB_DTPP);

            SQLiteQueryBuilder builder = new SQLiteQueryBuilder();
            builder.setTables(DtppCycle.TABLE_NAME);
            Cursor c = builder.query(db, new String[] { "*" }, null, null, null, null, null, null);
            result[0] = c;

            builder = new SQLiteQueryBuilder();
            builder.setTables(Dtpp.TABLE_NAME);
            c = builder.query(db,
                    new String[] { Dtpp.TPP_VOLUME, "count(DISTINCT " + Dtpp.PDF_NAME + ") AS total" },
                    Dtpp.USER_ACTION + "!='D'", null, Dtpp.TPP_VOLUME, null, null, null);
            result[1] = c;

            return result;
        }

        @Override
        protected boolean onResult(final Cursor[] result) {
            // Add delay to allow navigation drawer to close without stutter
            new Handler().postDelayed(new Runnable() {

                @Override
                public void run() {
                    showChartInfo(result);
                }
            }, 250);

            // Do not close cursors now
            return false;
        }
    }

    private void showChartInfo(Cursor[] result) {
        Cursor c = result[0];
        if (c.moveToFirst()) {
            mTppCycle = c.getString(c.getColumnIndex(DtppCycle.TPP_CYCLE));
        } else {
            UiUtils.showToast(getActivity(), "d-TPP database is not installed");
            getActivity().finish();
            return;
        }

        getSupportActionBar().setSubtitle(String.format("AeroNav Cycle %s", mTppCycle));

        String expiry = c.getString(c.getColumnIndex(DtppCycle.TO_DATE));
        SimpleDateFormat df = new SimpleDateFormat("HHmm'Z' MM/dd/yy", Locale.US);
        df.setTimeZone(java.util.TimeZone.getTimeZone("UTC"));
        Date endDate = null;
        try {
            endDate = df.parse(expiry);
        } catch (ParseException ignored) {
        }

        // Determine if chart cycle has expired
        Date now = new Date();
        if (now.getTime() > endDate.getTime()) {
            mExpired = true;
        }

        TextView tv = (TextView) findViewById(R.id.charts_cycle_expiry);
        if (mExpired) {
            tv.setText("This chart cycle has expired on "
                    + TimeUtils.formatDateTime(getActivity(), endDate.getTime()));
        } else {
            tv.setText("This chart cycle expires on " + TimeUtils.formatDateTime(getActivity(), endDate.getTime()));
        }

        tv = (TextView) findViewById(R.id.charts_download_msg);
        tv.setText("Each TPP volume is about 150-250MB in size and may take 15-30 mins"
                + " to download. The Instrument Procedure charts are in PDF format and"
                + " stored on the external SD card storage. These are not the sectional charts."
                + " Press 'Back' button to stop a running download.\n\n"
                + "All charts for a cycle are automatically deleted at the end of that cycle");

        String msg;
        if (!Application.sDonationDone) {
            msg = "This function is only available after a donation";
            mIsOk = false;
        } else if (mExpired) {
            msg = "Chart cycle has expired";
            mIsOk = false;
        } else if (!NetworkUtils.isNetworkAvailable(getActivity())) {
            msg = "Not connected to the internet";
            mIsOk = false;
        } else if (NetworkUtils.canDownloadData(getActivity())) {
            msg = "Connected to an unmetered network";
            mIsOk = true;
        } else {
            msg = "Connected to a metered network";
            mIsOk = false;
        }

        tv = (TextView) findViewById(R.id.charts_download_warning);
        tv.setText(msg);
        UiUtils.setTextViewDrawable(tv, mIsOk ? R.drawable.ic_check : R.drawable.ic_highlight_remove);

        LinearLayout layout = (LinearLayout) findViewById(R.id.vol_chart_details);
        c = result[1];
        if (c.moveToFirst()) {
            do {
                String tppVolume = c.getString(c.getColumnIndex(Dtpp.TPP_VOLUME));
                int total = c.getInt(c.getColumnIndex("total"));
                addTppVolumeRow(layout, tppVolume, total);
            } while (c.moveToNext());
        }

        // Close all cursors here
        for (Cursor cursor : result) {
            cursor.close();
        }

        setFragmentContentShown(true);
    }

    private class VolumeDownloadTask extends CursorAsyncTask {

        @Override
        protected Cursor[] doInBackground(String... params) {
            mTppVolume = params[0];
            SQLiteDatabase db = getDatabase(DatabaseManager.DB_DTPP);

            Cursor[] result = new Cursor[1];

            SQLiteQueryBuilder builder = new SQLiteQueryBuilder();
            builder.setTables(Dtpp.TABLE_NAME);
            Cursor c = builder.query(db, new String[] { Dtpp.PDF_NAME },
                    Dtpp.TPP_VOLUME + "=? AND " + Dtpp.USER_ACTION + "!=?", new String[] { mTppVolume, "D" },
                    Dtpp.PDF_NAME + "," + Dtpp.TPP_VOLUME, null, null);
            result[0] = c;

            return result;
        }

        @Override
        protected boolean onResult(Cursor[] result) {
            mCursor = result[0];
            mCursor.moveToFirst();
            mProgressBar = (ProgressBar) mSelectedRow.findViewById(R.id.progress);
            mProgressBar.setMax(mCursor.getCount());
            mProgressBar.setProgress(0);
            mProgressBar.setVisibility(View.VISIBLE);
            getNextChart();
            return false;
        }
    }

    protected void onChartDownload(Context context, Intent intent) {
        if (mCursor != null) {
            mProgressBar.setProgress(mCursor.getPosition());
            if (!mStop && mCursor.moveToNext()) {
                getNextChart();
            } else {
                getChartCount(mTppCycle, mTppVolume);
                finishOperation();
            }
        }
    }

    protected void getNextChart() {
        String pdfName = mCursor.getString(mCursor.getColumnIndex(Dtpp.PDF_NAME));
        ArrayList<String> pdfNames = new ArrayList<>();
        pdfNames.add(pdfName);
        Intent service = new Intent(getActivity(), DtppService.class);
        service.setAction(AeroNavService.ACTION_GET_CHARTS);
        service.putExtra(AeroNavService.CYCLE_NAME, mTppCycle);
        service.putExtra(AeroNavService.TPP_VOLUME, mTppVolume);
        service.putExtra(AeroNavService.PDF_NAMES, pdfNames);
        getActivity().startService(service);
    }

    private class VolumeDeleteTask extends CursorAsyncTask {

        @Override
        protected Cursor[] doInBackground(String... params) {
            mTppVolume = params[0];
            SQLiteDatabase db = getDatabase(DatabaseManager.DB_DTPP);

            Cursor[] result = new Cursor[1];

            SQLiteQueryBuilder builder = new SQLiteQueryBuilder();
            builder.setTables(Dtpp.TABLE_NAME);
            Cursor c = builder.query(db, new String[] { Dtpp.PDF_NAME },
                    Dtpp.TPP_VOLUME + "=? AND " + Dtpp.USER_ACTION + "!=?", new String[] { mTppVolume, "D" },
                    Dtpp.PDF_NAME + "," + Dtpp.TPP_VOLUME, null, null);
            result[0] = c;

            return result;
        }

        @Override
        protected boolean onResult(Cursor[] result) {
            mCursor = result[0];
            mCursor.moveToFirst();
            mProgressBar = (ProgressBar) mSelectedRow.findViewById(R.id.progress);
            mProgressBar.setMax(mCursor.getCount());
            mProgressBar.setProgress(0);
            mProgressBar.setVisibility(View.VISIBLE);
            deleteNextChart();
            return false;
        }
    }

    protected void onChartDelete(Context context, Intent intent) {
        if (mCursor != null) {
            mProgressBar.setProgress(mCursor.getPosition());
            if (!mStop && mCursor.moveToNext()) {
                deleteNextChart();
            } else {
                getChartCount(mTppCycle, mTppVolume);
                finishOperation();
            }
        }
    }

    protected void deleteNextChart() {
        String pdfName = mCursor.getString(mCursor.getColumnIndex(Dtpp.PDF_NAME));
        ArrayList<String> pdfNames = new ArrayList<>();
        pdfNames.add(pdfName);
        Intent service = new Intent(getActivity(), DtppService.class);
        service.setAction(AeroNavService.ACTION_DELETE_CHARTS);
        service.putExtra(AeroNavService.CYCLE_NAME, mTppCycle);
        service.putExtra(AeroNavService.TPP_VOLUME, mTppVolume);
        service.putExtra(AeroNavService.PDF_NAMES, pdfNames);
        getActivity().startService(service);
    }

    protected void finishOperation() {
        mTppVolume = null;
        mSelectedRow = null;
        if (mProgressBar != null) {
            mProgressBar.setVisibility(View.GONE);
            mProgressBar = null;
        }
        if (mCursor != null) {
            mCursor.close();
            mCursor = null;
        }
    }

    protected void getChartCount(String tppCycle, String tppVolume) {
        Intent service = new Intent(getActivity(), DtppService.class);
        service.setAction(AeroNavService.ACTION_COUNT_CHARTS);
        service.putExtra(AeroNavService.CYCLE_NAME, tppCycle);
        service.putExtra(AeroNavService.TPP_VOLUME, tppVolume);
        getActivity().startService(service);
    }

    protected View addTppVolumeRow(LinearLayout layout, String tppVolume, int total) {
        if (layout.getChildCount() > 0) {
            addSeparator(layout);
        }

        RelativeLayout row = (RelativeLayout) inflate(R.layout.list_item_with_progressbar);

        TextView tv = (TextView) row.findViewById(R.id.item_label);
        tv.setText(tppVolume);
        tv = (TextView) row.findViewById(R.id.item_value);
        tv.setText(String.format("%d charts", total));

        row.setTag(R.id.DTPP_VOLUME_NAME, tppVolume);
        row.setTag(R.id.DTPP_CHART_TOTAL, total);

        showStatus(row, 0, total);

        layout.addView(row, new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));

        mVolumeRowMap.put(tppVolume, row);
        getChartCount(mTppCycle, tppVolume);

        return row;
    }

    protected void onChartCount(Context context, Intent intent) {
        String tppVolume = intent.getStringExtra(AeroNavService.TPP_VOLUME);
        int avail = intent.getIntExtra(AeroNavService.PDF_COUNT, 0);
        View row = mVolumeRowMap.get(tppVolume);
        if (row != null) {
            row.setOnClickListener(mOnClickListener);
            int background = UiUtils.getSelectableItemBackgroundResource(getActivity());
            row.setBackgroundResource(background);
            row.setTag(R.id.DTPP_CHART_AVAIL, avail);
            int total = (Integer) row.getTag(R.id.DTPP_CHART_TOTAL);
            showStatus(row, avail, total);
        }
    }

    protected void showStatus(View row, int avail, int total) {
        TextView tv = (TextView) row.findViewById(R.id.item_label);
        if (avail == total) {
            UiUtils.setTextViewDrawable(tv, R.drawable.ic_check_box);
        } else {
            UiUtils.setTextViewDrawable(tv, R.drawable.ic_check_box_outline_blank);
        }
    }

}