com.kentph.ttcnextbus.CreateDatabaseActivity.java Source code

Java tutorial

Introduction

Here is the source code for com.kentph.ttcnextbus.CreateDatabaseActivity.java

Source

/*
 * Copyright (C) 2012 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 com.kentph.ttcnextbus;

import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.database.sqlite.SQLiteDatabase;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.AsyncTask;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.v4.app.NavUtils;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.webkit.WebView;
import android.widget.Toast;

import com.kentph.ttcnextbus.NextBusRouteConfigXmlParser.RouteConfig;
import com.kentph.ttcnextbus.NextBusRouteListXmlParser.Route;

import org.xmlpull.v1.XmlPullParserException;

import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.List;

import static android.database.DatabaseUtils.InsertHelper;
import static com.kentph.ttcnextbus.NextBusRouteConfigXmlParser.Path;
import static com.kentph.ttcnextbus.NextBusRouteConfigXmlParser.PathPoint;
import static com.kentph.ttcnextbus.RouteDbHelper.RouteDbContract.PathsTable;
import static com.kentph.ttcnextbus.RouteDbHelper.RouteDbContract.StopsTable;

/**
 * Main Activity for the sample application.
 *
 * This activity does the following:
 *
 * o Presents a WebView screen to users. This WebView has a list of HTML links to the latest
 *   questions tagged 'android' on stackoverflow.com.
 *
 * o Parses the StackOverflow XML feed using XMLPullParser.
 *
 * o Uses AsyncTask to download and process the XML feed.
 *
 * o Monitors preferences and the device's network connection to determine whether
 *   to refresh the WebView content.
 */
public class CreateDatabaseActivity extends Activity {
    public static final String WIFI = "Wi-Fi";
    public static final String ANY = "Any";

    // Whether there is a Wi-Fi connection.
    private static boolean wifiConnected = false;
    // Whether there is a mobile connection.
    private static boolean mobileConnected = false;
    // Whether the display should be refreshed.
    public static boolean refreshDisplay = true;

    // The user's current network preference setting.
    public static String sPref = null;

    // The BroadcastReceiver that tracks network connectivity changes.
    private NetworkReceiver receiver = new NetworkReceiver();

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

        // Register BroadcastReceiver to track connection changes.
        IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
        receiver = new NetworkReceiver();
        this.registerReceiver(receiver, filter);

    }

    // Refreshes the display if the network connection and the
    // pref settings allow it.
    @Override
    public void onStart() {
        super.onStart();

        // Gets the user's network preference settings
        SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);

        // Retrieves a string value for the preferences. The second parameter
        // is the default value to use if a preference value is not found.
        sPref = sharedPrefs.getString("listPref", "Wi-Fi");

        updateConnectedFlags();

        // Only loads the page if refreshDisplay is true. Otherwise, keeps previous
        // display. For example, if the user has set "Wi-Fi only" in prefs and the
        // device loses its Wi-Fi connection midway through the user using the app,
        // you don't want to refresh the display--this would force the display of
        // an error page instead of stackoverflow.com content.
        if (refreshDisplay) {
            loadPage();
        }
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        if (receiver != null) {
            this.unregisterReceiver(receiver);
        }
    }

    // Checks the network connection and sets the wifiConnected and mobileConnected
    // variables accordingly.
    private void updateConnectedFlags() {
        ConnectivityManager connMgr = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);

        NetworkInfo activeInfo = connMgr.getActiveNetworkInfo();
        if (activeInfo != null && activeInfo.isConnected()) {
            wifiConnected = activeInfo.getType() == ConnectivityManager.TYPE_WIFI;
            mobileConnected = activeInfo.getType() == ConnectivityManager.TYPE_MOBILE;
        } else {
            wifiConnected = false;
            mobileConnected = false;
        }
    }

    // Uses AsyncTask subclass to download the XML feed from stackoverflow.com.
    // This avoids UI lock up. To prevent network operations from
    // causing a delay that results in a poor user experience, always perform
    // network operations on a separate thread from the UI.
    private void loadPage() {
        if (((sPref.equals(ANY)) && (wifiConnected || mobileConnected))
                || ((sPref.equals(WIFI)) && (wifiConnected))) {
            // AsyncTask subclass
            new DownloadXmlTask().execute();
        } else {
            showErrorPage();
        }
    }

    // Displays an error if the app is unable to load content.
    private void showErrorPage() {
        setContentView(R.layout.activity_network);

        // The specified network connection is not available. Displays error message.
        WebView myWebView = (WebView) findViewById(R.id.webview);
        myWebView.loadData(getResources().getString(R.string.connection_error), "text/html", null);
    }

    // Populates the activity's options menu.
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.mainmenu, menu);
        return true;
    }

    // Handles the user's menu selection.
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
        case R.id.settings:
            Intent settingsActivity = new Intent(getBaseContext(), SettingsActivity.class);
            startActivity(settingsActivity);
            return true;
        case R.id.refresh:
            loadPage();
            return true;
        case android.R.id.home:
            // This ID represents the Home or Up button. In the case of this
            // activity, the Up button is shown. Use NavUtils to allow users
            // to navigate up one level in the application structure. For
            // more details, see the Navigation pattern on Android Design:
            //
            // http://developer.android.com/design/patterns/navigation.html#up-vs-back
            //
            NavUtils.navigateUpFromSameTask(this);
            return true;
        default:
            return super.onOptionsItemSelected(item);
        }
    }

    // Implementation of AsyncTask used to download XML feed from stackoverflow.com.
    private class DownloadXmlTask extends AsyncTask<Void, String, String> {
        //        private ProgressDialog pd;
        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            //            pd = new ProgressDialog(getApplicationContext());
            //            pd.setMessage("Starting...");
            //            pd.show();
        }

        @Override
        protected String doInBackground(Void... params) {
            try {
                InputStream stream = null;
                NextBusRouteListXmlParser nextBusRouteListXmlParser = new NextBusRouteListXmlParser();
                NextBusRouteConfigXmlParser nextBusRouteConfigXmlParser = new NextBusRouteConfigXmlParser();
                List<Route> routes = null;
                RouteConfig routeConfig = null;

                StringBuilder htmlString = new StringBuilder();

                RouteDbHelper mDbHelper = new RouteDbHelper(getBaseContext());
                // Gets the data repository in write mode
                SQLiteDatabase db = mDbHelper.getWritableDatabase();

                // use insertHelper to speed up insertions
                InsertHelper ihPathsTable = new InsertHelper(db, "paths");
                InsertHelper ihStopsTable = new InsertHelper(db, "stops");

                // get column indices
                final int pathRouteNumberColumn = ihPathsTable.getColumnIndex(PathsTable.COLUMN_NAME_ROUTE_NUMBER);
                final int pathIdColumn = ihPathsTable.getColumnIndex(PathsTable.COLUMN_NAME_PATH_ID);
                final int pathLatColumn = ihPathsTable.getColumnIndex(PathsTable.COLUMN_NAME_LAT);
                final int pathLonColumn = ihPathsTable.getColumnIndex(PathsTable.COLUMN_NAME_LON);

                final int stopRouteNumberColumn = ihStopsTable.getColumnIndex(StopsTable.COLUMN_NAME_ROUTE_NUMBER);
                final int stopRouteNameColumn = ihStopsTable.getColumnIndex(StopsTable.COLUMN_NAME_ROUTE_NAME);
                final int stopIdColumn = ihStopsTable.getColumnIndex(StopsTable.COLUMN_NAME_STOP_ID);
                final int stopTagColumn = ihStopsTable.getColumnIndex(StopsTable.COLUMN_NAME_STOP_TAG);
                final int stopTitleColumn = ihStopsTable.getColumnIndex(StopsTable.COLUMN_NAME_STOP_TITLE);
                final int stopDirectionColumn = ihStopsTable.getColumnIndex(StopsTable.COLUMN_NAME_DIRECTION);
                final int stopBranchColumn = ihStopsTable.getColumnIndex(StopsTable.COLUMN_NAME_BRANCH);
                final int stopLatColumn = ihStopsTable.getColumnIndex(StopsTable.COLUMN_NAME_LAT);
                final int stopLonColumn = ihStopsTable.getColumnIndex(StopsTable.COLUMN_NAME_LON);
                final int gridLatColumn = ihStopsTable.getColumnIndex(StopsTable.COLUMN_NAME_GRID_LAT);
                final int gridLonColumn = ihStopsTable.getColumnIndex(StopsTable.COLUMN_NAME_GRID_LON);

                // create only 1 transaction for speed
                db.beginTransaction();

                // get route list
                try {
                    stream = downloadUrl(
                            "http://webservices.nextbus.com/service/publicXMLFeed?command=routeList&a=ttc");
                    routes = nextBusRouteListXmlParser.parse(stream);

                    for (Route route : routes) {
                        stream = downloadUrl(
                                "http://webservices.nextbus.com/service/publicXMLFeed?command=routeConfig&a=ttc&r="
                                        .concat(route.routeNumber));
                        routeConfig = nextBusRouteConfigXmlParser.parse(stream);

                        // import into path table
                        int pathCount = 0;
                        for (Path path : routeConfig.paths) {
                            for (PathPoint pathPoint : path.path) {
                                ihPathsTable.prepareForInsert();
                                ihPathsTable.bind(pathRouteNumberColumn, routeConfig.routeNumber);
                                ihPathsTable.bind(pathIdColumn, pathCount);
                                ihPathsTable.bind(pathLatColumn, pathPoint.lat);
                                ihPathsTable.bind(pathLonColumn, pathPoint.lon);

                                ihPathsTable.execute();
                            }
                            pathCount++;
                        }

                        // import into stop table
                        for (NextBusRouteConfigXmlParser.Stop stop : routeConfig.stops) {
                            ihStopsTable.prepareForInsert();
                            ihStopsTable.bind(stopRouteNumberColumn, routeConfig.routeNumber);
                            ihStopsTable.bind(stopRouteNameColumn, routeConfig.routeName);
                            ihStopsTable.bind(stopIdColumn, stop.stopId);
                            ihStopsTable.bind(stopTagColumn, stop.tag);
                            ihStopsTable.bind(stopTitleColumn, stop.title);
                            ihStopsTable.bind(stopDirectionColumn, stop.direction);
                            ihStopsTable.bind(stopBranchColumn, stop.branch);
                            ihStopsTable.bind(stopLatColumn, stop.lat);
                            ihStopsTable.bind(stopLonColumn, stop.lon);
                            // we want integer division to get grid IDs
                            ihStopsTable.bind(gridLatColumn, (int) (stop.lat / 0.004));
                            ihStopsTable.bind(gridLonColumn, (int) (stop.lon / 0.004));

                            ihStopsTable.execute();
                        }
                        //                        publishProgress(routeConfig.routeNumber);
                    }

                    // if all stops/paths imported...
                    db.setTransactionSuccessful();

                    // Makes sure that the InputStream is closed after the app is
                    // finished using it.
                } finally {
                    // end transaction whether or not successful
                    db.endTransaction();

                    //ihPathsTable.close();
                    // ihStopsTable.close();

                    if (stream != null) {
                        stream.close();
                    }
                }

                htmlString.append("<p>Done</p>");
                return htmlString.toString();
            } catch (IOException e) {
                return getResources().getString(R.string.connection_error);
            } catch (XmlPullParserException e) {
                return getResources().getString(R.string.xml_error);
            }
        }

        @Override
        protected void onProgressUpdate(String... values) {
            //            pd.setMessage("Getting route " + values[0]);
            //            pd.show();
        }

        @Override
        protected void onPostExecute(String result) {
            setContentView(R.layout.activity_network);
            // Displays the HTML string in the UI via a WebView
            WebView myWebView = (WebView) findViewById(R.id.webview);
            myWebView.loadData(result, "text/html", null);
            //            pd.setMessage("Done!");
            //            pd.show();
        }
    }

    // Given a string representation of a URL, sets up a connection and gets
    // an input stream.
    private InputStream downloadUrl(String urlString) throws IOException {
        URL url = new URL(urlString);
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        conn.setReadTimeout(10000 /* milliseconds */);
        conn.setConnectTimeout(15000 /* milliseconds */);
        conn.setRequestMethod("GET");
        conn.setDoInput(true);
        // Starts the query
        conn.connect();
        InputStream stream = conn.getInputStream();
        return stream;
    }

    /**
     *
     * This BroadcastReceiver intercepts the android.net.ConnectivityManager.CONNECTIVITY_ACTION,
     * which indicates a connection change. It checks whether the type is TYPE_WIFI.
     * If it is, it checks whether Wi-Fi is connected and sets the wifiConnected flag in the
     * main activity accordingly.
     *
     */
    public class NetworkReceiver extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {
            ConnectivityManager connMgr = (ConnectivityManager) context
                    .getSystemService(Context.CONNECTIVITY_SERVICE);
            NetworkInfo networkInfo = connMgr.getActiveNetworkInfo();

            // Checks the user prefs and the network connection. Based on the result, decides
            // whether
            // to refresh the display or keep the current display.
            // If the userpref is Wi-Fi only, checks to see if the device has a Wi-Fi connection.
            if (WIFI.equals(sPref) && networkInfo != null
                    && networkInfo.getType() == ConnectivityManager.TYPE_WIFI) {
                // If device has its Wi-Fi connection, sets refreshDisplay
                // to true. This causes the display to be refreshed when the user
                // returns to the app.
                refreshDisplay = true;
                Toast.makeText(context, R.string.wifi_connected, Toast.LENGTH_SHORT).show();

                // If the setting is ANY network and there is a network connection
                // (which by process of elimination would be mobile), sets refreshDisplay to true.
            } else if (ANY.equals(sPref) && networkInfo != null) {
                refreshDisplay = true;

                // Otherwise, the app can't download content--either because there is no network
                // connection (mobile or Wi-Fi), or because the pref setting is WIFI, and there
                // is no Wi-Fi connection.
                // Sets refreshDisplay to false.
            } else {
                refreshDisplay = false;
                Toast.makeText(context, R.string.lost_connection, Toast.LENGTH_SHORT).show();
            }
        }
    }
}