Android CS323 Cornez

Lab 15: Building Network Apps

Exercise 1:


Use an implicit intent in the creation of the app shown below.
Provide a button for the user to access downtown Redlands in Google Maps.





Exercise 2: HTTP Requests

  1. Construct an app that downloads an image from a server.
    Build the activity layout and name the button onClick hander getImage.
    Code MainActivity. Use a background thread to retrieve the image from the server.
    Use the main thread to update the ImageView.




The following code is taken from MainActivity.java. getImage() is the onClick handler.
    public void getImage (View view){
        new Thread() {
            public void run() {

                try {
                    //Step 1: Create and send a HTTP request to a URL.
                    Message msg = Message.obtain();
                    InputStream inputStream = null;
                    URL url = new URL("https://tcornez.com/ass6mockupbefore.png");
                    URLConnection urlConn = url.openConnection();
                    HttpURLConnection httpConnection = (HttpURLConnection)  urlConn;
                    httpConnection.setRequestMethod("GET");
                    httpConnection.connect();
                    inputStream = httpConnection.getInputStream();

                    //Step 2: Once the server replies, receive the response and parse it.
                    Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
                    Bundle bundle = new Bundle();
                    bundle.putParcelable("bitmap", bitmap);
                    msg.setData(bundle);
                    inputStream.close();

                    //Step 3: Using the main thread, update the UI
                    mHandler.sendMessage(msg);
                } catch (MalformedURLException e) {
                    e.printStackTrace();
                }
                catch (IOException e) {
                    e.printStackTrace();
                }
            }

        }.start();
    }

    private Handler mHandler = new Handler() {
        public void handleMessage (Message msg){
            imageView.setImageBitmap((Bitmap) (msg.getData().getParcelable("bitmap")));
        }
    };

 




Exercise 3: Data Queries and JSON

  1. Part 1: Construct an initial Earthquake App that uses fake data.
    Create an adapter that takes the list of earthquakes as input.
    Set the adapter so the list can be populated in the user interface.


    layout_main.xml
      <?xml version="1.0" encoding="utf-8"?>
      <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
          android:layout_width="match_parent"
          android:layout_height="match_parent"
          android:orientation="vertical">
    
          <TextView
              android:layout_width="match_parent"
              android:layout_height="wrap_content"
              android:background="#5a90f5"
              android:text="Earthquakes"
              android:textColor="#e7dddd"
              android:textSize="32sp"
              android:paddingTop="10dp"/>
    
          <ListView
              android:id="@+id/listView"
              android:layout_width="match_parent"
              android:layout_height="wrap_content" />
    
      </LinearLayout>
    
    



    list_item.xml
    
         <?xml version="1.0" encoding="utf-8"?>
         <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
             android:layout_width="match_parent"
             android:layout_height="match_parent"
             android:orientation="vertical"
             android:padding="16dp">
    
             <LinearLayout
                 android:layout_width="match_parent"
                 android:layout_height="match_parent"
                 android:orientation="horizontal">
    
                 <TextView
                     android:id="@+id/textView1"
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
                     android:background="@drawable/abc_text_select_handle_middle_mtrl_dark"
                     android:text="magnitude"
                     android:textSize="32sp" />
    
                 <TextView
                     android:id="@+id/textView3"
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
                     android:paddingTop="50dp"
                     android:text="Date" />
             </LinearLayout>
    
    
             <TextView
                 android:id="@+id/textView2"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
                 android:text="location" />
    
    
         </LinearLayout>
      



    Earthquake.java
          public class Earthquake {
              public String mag;
              public String city;
              public String mDate;
    
              public Earthquake(String m, String c, String d){
                  mag = m;
                  city = c;
                  mDate = d;
              }
          }
       



    EarthquakeAdapter.java
           public class EarthquakeAdapter extends ArrayAdapter {
               public EarthquakeAdapter (Activity context, ArrayList earthquakeList) {
                   super (context, 0, earthquakeList);
               }
    
               @Override
               public View getView(int position, View convertView, ViewGroup parent){
    
                   //TASK 1: Check if there is an existing list item view to be recycled.
                   // Otherwise, if convertView is null, inflate a new list item layout.
                   View listItemView = convertView;
                   if (listItemView == null) {
                       listItemView = LayoutInflater.from(getContext()).inflate(R.layout.list_item, parent, false);
                   }
    
                   //TASK 2: Find the earthquake at the given position in the list of earthquakes.
                   Earthquake currentQuake = getItem(position);
    
                   //TASK 3: find the TextViews in the list item and populate them with data from
                   //        the currentQuake data.
                   TextView magTextView = (TextView) listItemView.findViewById(R.id.textView1);
                   magTextView.setText(currentQuake.mag);
                   TextView cityTextView = (TextView) listItemView.findViewById(R.id.textView2);
                   cityTextView.setText(currentQuake.city);
                   TextView dateTextView = (TextView) listItemView.findViewById(R.id.textView3);
                   dateTextView.setText(currentQuake.mDate);
    
                   //TASK 4: return the list item view that is now showing the appropriate data
                   return listItemView;
               }
    
           }
    
        



    MainActivity.java
            public class MainActivity extends AppCompatActivity {
    
                @Override
                protected void onCreate(Bundle savedInstanceState) {
                    super.onCreate(savedInstanceState);
                    //setContentView(R.layout.activity_main);
                    setContentView(R.layout.layout_main);
    
                    //Task 1:  Find a reference to the ListView in the layout
                    ListView listView = (ListView) findViewById(R.id.listView);
    
    
                    //Task 2: Create an ArrayList to hold earthquakes
                    ArrayList earthquakes = new ArrayList<>();
                    // Task 3: Create a fake list of earthquake locations as a JSON string
    
                    final  String SAMPLE_JSON_RESPONSE = "{\"type\":\"FeatureCollection\",\"metadata\":{\"generated\":1462295443000,\"url\":\"http://earthquake.usgs.gov/fdsnws/event/1/query?format=geojson&starttime=2016-01-01&endtime=2016-01-31&minmag=6&limit=10\",\"title\":\"USGS Earthquakes\",\"status\":200,\"api\":\"1.5.2\",\"limit\":10,\"offset\":1,\"count\":10},\"features\":[{\"type\":\"Feature\",\"properties\":{\"mag\":7.2,\"place\":\"88km N of Yelizovo, Russia\",\"time\":1454124312220,\"updated\":1460674294040,\"tz\":720,\"url\":\"http://earthquake.usgs.gov/earthquakes/eventpage/us20004vvx\",\"detail\":\"http://earthquake.usgs.gov/fdsnws/event/1/query?eventid=us20004vvx&format=geojson\",\"felt\":2,\"cdi\":3.4,\"mmi\":5.82,\"alert\":\"green\",\"status\":\"reviewed\",\"tsunami\":1,\"sig\":798,\"net\":\"us\",\"code\":\"20004vvx\",\"ids\":\",at00o1qxho,pt16030050,us20004vvx,gcmt20160130032510,\",\"sources\":\",at,pt,us,gcmt,\",\"types\":\",cap,dyfi,finite-fault,general-link,general-text,geoserve,impact-link,impact-text,losspager,moment-tensor,nearby-cities,origin,phase-data,shakemap,tectonic-summary,\",\"nst\":null,\"dmin\":0.958,\"rms\":1.19,\"gap\":17,\"magType\":\"mww\",\"type\":\"earthquake\",\"title\":\"M 7.2 - 88km N of Yelizovo, Russia\"},\"geometry\":{\"type\":\"Point\",\"coordinates\":[158.5463,53.9776,177]},\"id\":\"us20004vvx\"},\n" +
                            "{\"type\":\"Feature\",\"properties\":{\"mag\":6.1,\"place\":\"94km SSE of Taron, Papua New Guinea\",\"time\":1453777820750,\"updated\":1460156775040,\"tz\":600,\"url\":\"http://earthquake.usgs.gov/earthquakes/eventpage/us20004uks\",\"detail\":\"http://earthquake.usgs.gov/fdsnws/event/1/query?eventid=us20004uks&format=geojson\",\"felt\":null,\"cdi\":null,\"mmi\":4.1,\"alert\":\"green\",\"status\":\"reviewed\",\"tsunami\":1,\"sig\":572,\"net\":\"us\",\"code\":\"20004uks\",\"ids\":\",us20004uks,gcmt20160126031023,\",\"sources\":\",us,gcmt,\",\"types\":\",cap,geoserve,losspager,moment-tensor,nearby-cities,origin,phase-data,shakemap,tectonic-summary,\",\"nst\":null,\"dmin\":1.537,\"rms\":0.74,\"gap\":25,\"magType\":\"mww\",\"type\":\"earthquake\",\"title\":\"M 6.1 - 94km SSE of Taron, Papua New Guinea\"},\"geometry\":{\"type\":\"Point\",\"coordinates\":[153.2454,-5.2952,26]},\"id\":\"us20004uks\"},\n" +
                            "{\"type\":\"Feature\",\"properties\":{\"mag\":6.3,\"place\":\"50km NNE of Al Hoceima, Morocco\",\"time\":1453695722730,\"updated\":1460156773040,\"tz\":0,\"url\":\"http://earthquake.usgs.gov/earthquakes/eventpage/us10004gy9\",\"detail\":\"http://earthquake.usgs.gov/fdsnws/event/1/query?eventid=us10004gy9&format=geojson\",\"felt\":117,\"cdi\":7.2,\"mmi\":5.28,\"alert\":\"green\",\"status\":\"reviewed\",\"tsunami\":0,\"sig\":695,\"net\":\"us\",\"code\":\"10004gy9\",\"ids\":\",us10004gy9,gcmt20160125042203,\",\"sources\":\",us,gcmt,\",\"types\":\",cap,dyfi,geoserve,impact-text,losspager,moment-tensor,nearby-cities,origin,phase-data,shakemap,tectonic-summary,\",\"nst\":null,\"dmin\":2.201,\"rms\":0.92,\"gap\":20,\"magType\":\"mww\",\"type\":\"earthquake\",\"title\":\"M 6.3 - 50km NNE of Al Hoceima, Morocco\"},\"geometry\":{\"type\":\"Point\",\"coordinates\":[-3.6818,35.6493,12]},\"id\":\"us10004gy9\"},\n" +
                            "{\"type\":\"Feature\",\"properties\":{\"mag\":7.1,\"place\":\"86km E of Old Iliamna, Alaska\",\"time\":1453631430230,\"updated\":1460156770040,\"tz\":-540,\"url\":\"http://earthquake.usgs.gov/earthquakes/eventpage/us10004gqp\",\"detail\":\"http://earthquake.usgs.gov/fdsnws/event/1/query?eventid=us10004gqp&format=geojson\",\"felt\":1816,\"cdi\":7.2,\"mmi\":6.6,\"alert\":\"green\",\"status\":\"reviewed\",\"tsunami\":1,\"sig\":1496,\"net\":\"us\",\"code\":\"10004gqp\",\"ids\":\",at00o1gd6r,us10004gqp,ak12496371,gcmt20160124103030,\",\"sources\":\",at,us,ak,gcmt,\",\"types\":\",cap,dyfi,finite-fault,general-link,general-text,geoserve,impact-link,impact-text,losspager,moment-tensor,nearby-cities,origin,phase-data,shakemap,tectonic-summary,trump-origin,\",\"nst\":null,\"dmin\":0.72,\"rms\":2.11,\"gap\":19,\"magType\":\"mww\",\"type\":\"earthquake\",\"title\":\"M 7.1 - 86km E of Old Iliamna, Alaska\"},\"geometry\":{\"type\":\"Point\",\"coordinates\":[-153.4051,59.6363,129]},\"id\":\"us10004gqp\"},\n" +
                            "{\"type\":\"Feature\",\"properties\":{\"mag\":6.6,\"place\":\"215km SW of Tomatlan, Mexico\",\"time\":1453399617650,\"updated\":1459963829040,\"tz\":-420,\"url\":\"http://earthquake.usgs.gov/earthquakes/eventpage/us10004g4l\",\"detail\":\"http://earthquake.usgs.gov/fdsnws/event/1/query?eventid=us10004g4l&format=geojson\",\"felt\":11,\"cdi\":2.7,\"mmi\":3.92,\"alert\":\"green\",\"status\":\"reviewed\",\"tsunami\":1,\"sig\":673,\"net\":\"us\",\"code\":\"10004g4l\",\"ids\":\",at00o1bebo,pt16021050,us10004g4l,gcmt20160121180659,\",\"sources\":\",at,pt,us,gcmt,\",\"types\":\",cap,dyfi,geoserve,impact-link,impact-text,losspager,moment-tensor,nearby-cities,origin,phase-data,shakemap,tectonic-summary,\",\"nst\":null,\"dmin\":2.413,\"rms\":0.98,\"gap\":74,\"magType\":\"mww\",\"type\":\"earthquake\",\"title\":\"M 6.6 - 215km SW of Tomatlan, Mexico\"},\"geometry\":{\"type\":\"Point\",\"coordinates\":[-106.9337,18.8239,10]},\"id\":\"us10004g4l\"},\n" +
                            "{\"type\":\"Feature\",\"properties\":{\"mag\":6.7,\"place\":\"52km SE of Shizunai, Japan\",\"time\":1452741933640,\"updated\":1459304879040,\"tz\":540,\"url\":\"http://earthquake.usgs.gov/earthquakes/eventpage/us10004ebx\",\"detail\":\"http://earthquake.usgs.gov/fdsnws/event/1/query?eventid=us10004ebx&format=geojson\",\"felt\":51,\"cdi\":5.8,\"mmi\":6.45,\"alert\":\"green\",\"status\":\"reviewed\",\"tsunami\":1,\"sig\":720,\"net\":\"us\",\"code\":\"10004ebx\",\"ids\":\",us10004ebx,pt16014050,at00o0xauk,gcmt20160114032534,\",\"sources\":\",us,pt,at,gcmt,\",\"types\":\",associate,cap,dyfi,geoserve,impact-link,impact-text,losspager,moment-tensor,nearby-cities,origin,phase-data,shakemap,\",\"nst\":null,\"dmin\":0.281,\"rms\":0.98,\"gap\":22,\"magType\":\"mww\",\"type\":\"earthquake\",\"title\":\"M 6.7 - 52km SE of Shizunai, Japan\"},\"geometry\":{\"type\":\"Point\",\"coordinates\":[142.781,41.9723,46]},\"id\":\"us10004ebx\"},\n" +
                            "{\"type\":\"Feature\",\"properties\":{\"mag\":6.1,\"place\":\"12km WNW of Charagua, Bolivia\",\"time\":1452741928270,\"updated\":1459304879040,\"tz\":-240,\"url\":\"http://earthquake.usgs.gov/earthquakes/eventpage/us10004ebw\",\"detail\":\"http://earthquake.usgs.gov/fdsnws/event/1/query?eventid=us10004ebw&format=geojson\",\"felt\":3,\"cdi\":2.2,\"mmi\":2.21,\"alert\":\"green\",\"status\":\"reviewed\",\"tsunami\":0,\"sig\":573,\"net\":\"us\",\"code\":\"10004ebw\",\"ids\":\",us10004ebw,gcmt20160114032528,\",\"sources\":\",us,gcmt,\",\"types\":\",cap,dyfi,geoserve,impact-text,losspager,moment-tensor,nearby-cities,origin,phase-data,shakemap,tectonic-summary,\",\"nst\":null,\"dmin\":5.492,\"rms\":1.04,\"gap\":16,\"magType\":\"mww\",\"type\":\"earthquake\",\"title\":\"M 6.1 - 12km WNW of Charagua, Bolivia\"},\"geometry\":{\"type\":\"Point\",\"coordinates\":[-63.3288,-19.7597,582.56]},\"id\":\"us10004ebw\"},\n" +
                            "{\"type\":\"Feature\",\"properties\":{\"mag\":6.2,\"place\":\"74km NW of Rumoi, Japan\",\"time\":1452532083920,\"updated\":1459304875040,\"tz\":540,\"url\":\"http://earthquake.usgs.gov/earthquakes/eventpage/us10004djn\",\"detail\":\"http://earthquake.usgs.gov/fdsnws/event/1/query?eventid=us10004djn&format=geojson\",\"felt\":8,\"cdi\":3.4,\"mmi\":3.74,\"alert\":\"green\",\"status\":\"reviewed\",\"tsunami\":0,\"sig\":594,\"net\":\"us\",\"code\":\"10004djn\",\"ids\":\",us10004djn,gcmt20160111170803,\",\"sources\":\",us,gcmt,\",\"types\":\",cap,dyfi,geoserve,impact-text,losspager,moment-tensor,nearby-cities,origin,phase-data,shakemap,tectonic-summary,\",\"nst\":null,\"dmin\":1.139,\"rms\":0.96,\"gap\":33,\"magType\":\"mww\",\"type\":\"earthquake\",\"title\":\"M 6.2 - 74km NW of Rumoi, Japan\"},\"geometry\":{\"type\":\"Point\",\"coordinates\":[141.0867,44.4761,238.81]},\"id\":\"us10004djn\"},\n" +
                            "{\"type\":\"Feature\",\"properties\":{\"mag\":6.5,\"place\":\"227km SE of Sarangani, Philippines\",\"time\":1452530285900,\"updated\":1459304874040,\"tz\":480,\"url\":\"http://earthquake.usgs.gov/earthquakes/eventpage/us10004dj5\",\"detail\":\"http://earthquake.usgs.gov/fdsnws/event/1/query?eventid=us10004dj5&format=geojson\",\"felt\":1,\"cdi\":2.7,\"mmi\":7.5,\"alert\":\"green\",\"status\":\"reviewed\",\"tsunami\":1,\"sig\":650,\"net\":\"us\",\"code\":\"10004dj5\",\"ids\":\",at00o0srjp,pt16011050,us10004dj5,gcmt20160111163807,\",\"sources\":\",at,pt,us,gcmt,\",\"types\":\",cap,dyfi,geoserve,impact-link,impact-text,losspager,moment-tensor,nearby-cities,origin,phase-data,shakemap,tectonic-summary,\",\"nst\":null,\"dmin\":3.144,\"rms\":0.72,\"gap\":22,\"magType\":\"mww\",\"type\":\"earthquake\",\"title\":\"M 6.5 - 227km SE of Sarangani, Philippines\"},\"geometry\":{\"type\":\"Point\",\"coordinates\":[126.8621,3.8965,13]},\"id\":\"us10004dj5\"},\n" +
                            "{\"type\":\"Feature\",\"properties\":{\"mag\":6,\"place\":\"Pacific-Antarctic Ridge\",\"time\":1451986454620,\"updated\":1459202978040,\"tz\":-540,\"url\":\"http://earthquake.usgs.gov/earthquakes/eventpage/us10004bgk\",\"detail\":\"http://earthquake.usgs.gov/fdsnws/event/1/query?eventid=us10004bgk&format=geojson\",\"felt\":0,\"cdi\":1,\"mmi\":0,\"alert\":\"green\",\"status\":\"reviewed\",\"tsunami\":0,\"sig\":554,\"net\":\"us\",\"code\":\"10004bgk\",\"ids\":\",us10004bgk,gcmt20160105093415,\",\"sources\":\",us,gcmt,\",\"types\":\",cap,dyfi,geoserve,losspager,moment-tensor,nearby-cities,origin,phase-data,shakemap,\",\"nst\":null,\"dmin\":30.75,\"rms\":0.67,\"gap\":71,\"magType\":\"mww\",\"type\":\"earthquake\",\"title\":\"M 6.0 - Pacific-Antarctic Ridge\"},\"geometry\":{\"type\":\"Point\",\"coordinates\":[-136.2603,-54.2906,10]},\"id\":\"us10004bgk\"}],\"bbox\":[-153.4051,-54.2906,10,158.5463,59.6363,582.56]}";
                    try {
                        // Parse the response given by the SAMPLE_JSON_RESPONSE string and
                        // build up a list of Earthquake objects with the corresponding data.
    
                        //TASK 4: CREATE A JSONObject from the SAMPLE_JSON_RESPONSE string
                        JSONObject baseJsonResponse = new JSONObject(SAMPLE_JSON_RESPONSE);
    
                        //TASK 5: Extract the JSONArray associated with the key called "features",
                        //        which represents a list of features (or earthquakes).
                        JSONArray earthquakeArray = baseJsonResponse.optJSONArray("features");
    
                        // TASK 6: For each earthquake in the earthquakeArray, create an {@link Earthquake} object
                        for (int i = 0; i < earthquakeArray.length(); i++) {
                            //SUBTASK A: GRAB THE CURRENT EARTHQUAKE OBJECT AND EXTRACT THE THREE COMPONENTS
                            JSONObject currentEarthquake = earthquakeArray.getJSONObject(i);
                            JSONObject properties = currentEarthquake.getJSONObject("properties");
                            String magnitude = properties.getString("mag");
                            String location = properties.getString("place");
                            String time = properties.getString("time");
    
                            //SUBTASK B: ADD AN EARTHQUAKE OBJECT TO THE ARRAYLIST
                            earthquakes.add(new Earthquake(magnitude, location, time));
                        }
    
                        // Task 7: Create a new "custom" adapter that takes the list of earthquakes as input.
                        EarthquakeAdapter itemsAdapter = new EarthquakeAdapter(this, earthquakes);
    
                        // Task 8: Set the adapter so the list can be populated in the user interface
                        listView.setAdapter(itemsAdapter);
    
                    } catch (JSONException e) {
                        Log.e("QueryUtils", "Problem parsing the earthquake JSON results", e);
                    }
    
    
    
    
                }
    
            }
         



  2. Part 2: Build the Earthquake App so that the fake list uses JSON
    For example, create a fake list of earthquake locations as a JSON string. Parse the response given by the JSON string and build a list of Earthquake objects with the corresponding data. Create a JSONObject from the JSON response string and extract the JSONArray associated with the key called "features". NOTE: "features" represents a list of earthquakes.

  3. Part 3: Rebuild the Earthquake App so that it uses a separate class, QueryUtils, as a query utility to extract earthquakes to an ArrayList. QueryUtils is a JSON helper class that will perform the requesting and receiving of earthquake data.

The following code is taken from HelperQuery.java
  import org.json.JSONArray;
  import org.json.JSONException;
  import org.json.JSONObject;

  import java.io.BufferedReader;
  import java.io.IOException;
  import java.io.InputStream;
  import java.io.InputStreamReader;
  import java.net.HttpURLConnection;
  import java.net.MalformedURLException;
  import java.net.URL;
  import java.nio.charset.Charset;
  import java.util.ArrayList;

  /**
   *  NOTE 1: All methods in this class are used for requesting and receiving earthquake data from USGS.
   *  NOTE 2: This class holds four static methods.
   *  NOTE 3: The constructor is empty because all methods are static.
   */
  public class HelperQuery {

      //EMPTY CONSTRUCTOR
      private HelperQuery() {}

      //**************************** STATIC METHOD 1: extractEarthquakes() ************************
      // This method extracts Earthquake objects from the network.
      // It parses these objects from a JSON response from the url
      public static ArrayList extractEarthquakes(final String url) {

          // TASK 1: CREATE AN EMPTY ARRAYLIST.
          //         EARTHQUAKE OBJECTS COLLECTED FROM THE USGS NETWORK WILL BE ADDED TO THIS LIST.
          final ArrayList earthquakes = new ArrayList<>();

          // TASK 2: USE A BACKGROUND THREAD TO PROCESS EARTHQUAKE COLLECTED FROM THE HTTP REQUEST.
          new Thread() {
              public void run() {
                  // Parse the SAMPLE_JSON_RESPONSE. If there's a problem with the way the JSON
                  // is formatted, a JSONException exception object will be thrown.
                  // Catch the exception so the app doesn't crash, and print the error message to the logs.
                  try {
                      JSONObject jsonobj = new JSONObject(makeHttpRequest(createUrl(url)));
                      JSONArray features = jsonobj.getJSONArray("features");

                      for (int i = 0; i < features.length(); i++) {
                          JSONObject properties = features.getJSONObject(i).getJSONObject("properties");
                          earthquakes.add(new Earthquake(
                                  properties.getDouble("mag"),
                                  properties.getString("place"),
                                  properties.getLong("time"),
                                  properties.getString("url")
                          ));
                      }

                  } catch (JSONException e) {
                      // If an error is thrown when executing any of the above statements in the "try" block,
                      // catch the exception here, so the app doesn't crash. Print a log message
                      // with the message from the exception.
                      Log.e("QueryUtils", "Problem parsing the earthquake JSON results", e);
                  } catch (IOException e) {
                      Log.e("QueryUtils", "Problem with IO", e);
                  }
              }
          }.start();

          // TASK 3: RETURN THE ARRAYLIST OF EARTHQUAKE OBJECTS.
          return earthquakes;
      }

      //*************** STATIC METHOD 2: makeHttpRequest() ************************************************
      private static String makeHttpRequest(URL url) throws IOException {

          //TASK 1: CONSTRUCT AN HTTP REQUEST FOR A GIVEN URL.
          String jsonResponse = "";
          HttpURLConnection urlConnection = null;
          InputStream inputStream = null;
          try {
              urlConnection = (HttpURLConnection) url.openConnection();
              urlConnection.setRequestMethod("GET");
              urlConnection.setReadTimeout(10000 /* milliseconds */);
              urlConnection.setConnectTimeout(15000 /* milliseconds */);
              urlConnection.connect();
              inputStream = urlConnection.getInputStream();
              jsonResponse = readFromStream(inputStream);
          } catch (IOException e) {
              // Handle the exception
          } finally {
              if (urlConnection != null) {
                  urlConnection.disconnect();
              }
              if (inputStream != null) {
                  // function must handle java.io.IOException here
                  inputStream.close();
              }
          }
          // TASK 2: RETURN A STRING AS THE RESPONSE TO THE HTTP REQUEST.
          return jsonResponse;
      }


      //************************ STATIC METHOD 3: readFromStream() ************************************************
      private static String readFromStream(InputStream inputStream) throws IOException {
          // TASK 1: CREATE A STRING BUILDER TO STORE THE COMPLETE JSON RESPONSE
          StringBuilder output = new StringBuilder();

          //TASK 2: CONVERT THE INPUT STREAM INTO A STRING CONTAINING THE ENTIRE JSON RESPONSE FROM THE SERVER
          if (inputStream != null) {
              InputStreamReader inputStreamReader = new InputStreamReader(inputStream, Charset.forName("UTF-8"));
              BufferedReader reader = new BufferedReader(inputStreamReader);
              String line = reader.readLine();
              while (line != null) {
                  output.append(line);
                  line = reader.readLine();
              }
          }
          //TASK 3: RETURN THE STRING
          return output.toString();
      }


      //************************ STATIC METHOD 4: creatUrl() ************************************
      private static URL createUrl(String stringUrl) {
          //TASK 1: CONSTRUCT AN EMPTY URL OBJECT
          URL url = null;

          //TASK 2: USE TRY/CATCH TO BUILD THE URL FROM THE GIVEN STRING
          try {
              url = new URL(stringUrl);
          } catch (MalformedURLException exception) {
              return null;
          }
          //TASK 3: RETURN THE URL OBJECT
          return url;
      }
  }