Abstraction

Android System Architecture
Physical Device Hardware, Android Operating System, Framework, App

urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setRequestMethod("GET");
urlConnection.setReadTimeout(10000 /* milliseconds */);
urlConnection.setConnectTimeout(15000 /* milliseconds */);
urlConnection.connect();

GET(Read):Requests data from a specified resource
POST(Write):Submits data to be processed to a specified resource
https://www.w3schools.com/tags/ref_httpmethods.asp

HTTP request method
https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Request_methods

Why are we using a GET instead of a POST?
1.You want to retrieve data from the server
2.You’re not posting new information to the server

url connection
https://developer.android.com/reference/java/net/URLConnection.html?utm_source=udacity&utm_medium=course&utm_campaign=android_basics#connect()

HTTP request and response

Android client
1. form http request, send request to USGS

working with URL
https://docs.oracle.com/javase/tutorial/networking/urls/

Web API Endpoint Reference

Web API Endpoint Reference

HTTPConection
https://developer.android.com/reference/java/net/HttpURLConnection.html

   URL url = new URL("http://www.android.com/");
   HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
   try {
     InputStream in = new BufferedInputStream(urlConnection.getInputStream());
     readStream(in);
   } finally {
     urlConnection.disconnect();
   }

Soonami

package com.example.android.soonami;

import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.widget.TextView;

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.text.SimpleDateFormat;

public class MainActivity extends AppCompatActivity {
	public static final String LOG_TAG = MainActivity.class.getSimpleName();

	private static final String USGS_REQUEST_URL =
		"http://earthquake.usgs.gov/fdsnws/event/1/query?format=geojson&starttime=2012-01-01&endtime=2012-12-01&minmagnitude=6";

	@Override
	protected void onCreate(Bundle savedInstanceState){
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		TsunamiAsyncTask task = new TsunamiAsyncTask();
		task.execute();
	}

	private void updateUi(Event earthquake){
		TextView titleTextView = (TextView) findViewById(R.id.title);
		titleTextView.setText(earthquake.title);

		TextView dateTextView = (TextView) findViewById(R.id.date);
		dateTextView.setText(getDateString(earthquake.time));

		TextView tsunamiTextView = (TextView) findViewById(R.id.tsunami_alert);
		titleTextView.setText(earthquake.title);
	}

	private String getDateString(long timeInMilliseconds){
		SimpleDateFormat formatter = new SimpleDateFormat("EEE, d MMM yyy 'at' HH:mm:ss z");
		return formatter.format(timeInMilliseconds);
	}

	private String getTsunamiAlertString(int tsunamiAlert){
		switch (tsunamiAlert){
			case 0:
				return getString(R.string.alert_no);
			case 1:
				return getString(R.string.alert_yes);
			default:
				return getString(R.string.alert_no_available);
		}
	}

	private class TsunamiAsyncTask extends AsyncTask<URL, Void, Event>{

		@Override
		protected Event doInBackground(URL... urls){
			// Create URL object
			URL url = createUrl(USGS_REQUEST_URL);
		} catch (IOException e){
			// todo handle the IOException
		}

		Event earthquake = extractFeatureFromJson(jsonResponse);

		return earthquake;
	}

	@Override
	protected void onPostExecute(Event earthquake){
		if (earthquake == null){
			return;
		}

		updateUi(earthquake);
	}

	private URL createUrl(String stringUrl){
		URL url = null;
		try {
			url = new URL(stringUrl);
		} catch (MalformedURLException exception){
			Log.e(LOG_TAG, "Error with creating URL", exception);
			return null;
		}
		return url;
	}

	private String makeHttpRequest(URL url) throws IOException {
		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){
			// todo
		} finally {
			if (urlConnection != null){
				urlConnection.disconnect();
			}
			if (inputStream != null){
				inputStream.close();
			}
		}
		return jsonResponse;
	}

	private String readFromStream(InputStream inputStream) throws IOException {
		StringBuilder output = new StringBuilder();
		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();
			}
		}
		return output.toString();
	}

	private Event extractFeatureFromJson(String earthquakeJSON){
		try {
			JSONObject baseJsonResponse = new JSONObject(earthquakeJSON);
			JSONArray featureArray = baseJsonResponse.getJSONArray("features");

			if (featureArray.length() > 0){
				JSONObject firstFeature = featureArray.getJSONObject(0);
				JSONObject properties = firstFeature.getJSONObject("properties");

				String title = properties.getString("title");
				long time = properties.getLong("time");
				int tsunamiAlert = properties.getInt("tsunami");

				return new Event(title, time, tsunamiAlert);
			}
		} catch (JSONException e){
			Log.e(LOG_TAG, "Problem parsing the earthquake JSON results", e);
		}
		return null;
	}

}

Access to the internet

By default, an Android app does not have access to the Internet

Android Client -> USGS Web Server

Request permission to access certain functions of device
-use internet, use camer, send sms message, call phone number
-record microphone audio, get current location, network connectivity status …and more!

https://developer.android.com/training/permissions/declaring.html

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.example.snazzyapp">

    <uses-permission android:name="android.permission.SEND_SMS"/>
    

    <application ...>
        ...
    </application>

</manifest>

levels of permissions in android
-normal permissions
access the internet, vibrate the device, set the timezone, network connectivity status
automatically granted by the system
-dangerous permissions
use camera, access call log, access contacts, record audio
requested at runtime when app needs the permission pop up a dialog to ask for permission

prompt to accept all permissions at install time
prompt at runtime when user accesses feature that requires permission(no prompt at install time)

Hypertext transfer protocol
android client -> USGS web server
Client(GET,POST,PUT,DELETE)

Intro to Networking

Your phone -> REQUEST “I want earthquake data!” -> Computers at USGS
Response: “Here’s a list of earthquakes from our earthquake data set…”

protocol/scheme
host/domain/authority
resource path
query (param)

HTTP Connection
1.Form HTTP Request
2.Send the Request
3.Receive the Response and makes sense of it
4.Update the UI

Visual Polish

search fit APIs
https://www.programmableweb.com/apis/directory
https://developers.google.com/apis-explorer/#p/

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
	xmlns:tools="http://schemas.android.com/tools"
	android:layout_width="match_parent"
	android:layout_height="?android:attr/listPreferredItemHeight"
	android:orientation="horizontal"
	android:paddingEnd="16dp"
	android:paddingLeft="16dp"
	android:paddingRight="16dp"
	android:paddingStart="16dp">

	<TextView
		android:id="@+id/magnitude"
		android:layout_width="36dp"
		android:layout_height="36dp"
		android:layout_gravity="central_vertical"
		android:background="@drawable/magnitude_circle"
		android:gravity="center"
		android:textColor="@android:color/white"
		android:textSize="16sp"
		tools:text="8.9" />

	<LinearLayout
		android:layout_width="0dp"
		android:layout_height="wrap_content"
		android:layout_gravity="center_vertical"
		android:layout_marginLeft="16dp"
		android:layout_marginStart="16dp"
		android:layout_weight="1"
		android:orientation="vertical">

		<TextView
			android:id="@+id/location_offset"
			android:layout_width="wrap_content"
			android:layout_height="wrap_content"
			android:ellipsize="end"
			android:fontFamily="sans-serif-medium"
			android:maxLines="1"
			android:textAllCaps="true"
			android:textColor="@color/textColorEarthquakeDetails"
			android:textSize="12sp"
			tools:text="30km S of" />

		<TextView
			android:id="@+id/primary_location"
			android:layout_width="wrap_content"
			android:layout_height="wrap_content"
			android:ellipsize="end"
			android:maxLines="2"
			android:textColor="@color/textColorEarthquakeLocation"
			android:textSize="16sp"
			tools:text="Long placeholder location that should wrap to more than 2 lines of text" />

		</LinearLayout>

		<LinearLayout
			android:layout_width="wrap_content"
			android:layout_height="wrap_content"
			android:layout_gravity="center_vertical"
			android:layout_marginLeft="16dp"
			android:layout_marginStart="16dp"
			android:orientation="vertical">

			<TextView
				android:id="@+id/date"
				android:layout_width="wrap_content"
				android:layout_height="wrap_content"
				android:layout_gravity="end"
				andorid:textColor="@color/textColorEarthquakeDetails"
				android:textSize="12sp"
				tools:text="Mar 6, 2010"/>

			<TextView
				android:id="@+id/time"
				adoroid:layout_width="wrap_content"
				android:layout_height="wrap_content"
				android:layout_gravity="end"
				android:textColor="@color/textColorEarthquakeDetails"
				andorid:textSize="12sp"
				tools:text="3:00 PM" />

		</LinearLayout>
	</LinearLayout>

EarthquakeAdapter.java

import android.support.v4.content.ContextCompact;

private int getMagnitudeColor(double magnitude){
	int magnitudeColorResourceId;
	int magnitudeFloor = (int) Math.floor(magnitude);
	switch(magnitudeFloor){
		case 0:
		case 1:
			magnitudeColorResourceId = R.color.magnitude1;
			break;
		case 2:
			magnitudeColorResourceId = R.color.magnitude2;
			break;
		case 3:
			magnitudeColorResourceId = R.color.magnitude3;
			break;
		case 4:
			magnitudeColorResourceId = R.color.magnitude4;
			break;
		case 5:
			magnitudeColorResourceId = R.color.magnitude5;
			break;
		case 6:
			magnitudeColorResourceId = R.color.magnitude6;
			break;
		case 7:
			magnitudeColorResourceId = R.color.magnitude7;
			break;
		case 8:
			magnitudeColorResourceId = R.color.magnitude8;
			break;
		case 9:
			magnitudeColorResourceId = R.color.magnitude9;
			break;
		default:
			magnitudeColorResourceId = R.color.magnitude10plus;
			break;
	}
	return ContextCompact.getColor(getContext(), magnitudeColorResourceID);
	}
}
<color name="textColorEarthquakeDetails">#B4BAC0</color>
<color name="textColorEarthquakeDetails">#2B3D4D</color>

set up magnitude color

<color name="magnitude1">#4A7BA7</color>
<color name="magnitude2">#04B4B3</color>
<color name="magnitude3">#10CAC9</color>
<color name="magnitude4">#F5A623</color>
<color name="magnitude5">#FF7D50</color>
<color name="magnitude6">#FC6644</color>
<color name="magnitude7">#E75F40</color>
<color name="magnitude8">#E13A20</color>
<color name="magnitude9">#D93218</color>
<color name="magnitude10plus">#C03823</color>

magnitude_circle.xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmln:android="http://schemas.android.com/apk/res/android" android:shape="oval">
	<solid android:color="@color/magnitude1" />
	<size
		android:width="36dp"
		android:height="36dp" />
	<corners android:radius="18dp" />
</shape>

TextView

<TextView
	android:id="@+id/magnitude"
	android:layout_width="36dp"
	android:layout_height="36dp"
	android:layout_gravity="center_vertical"
	android:background="@drawable/magnitude_circle"
	android:fontFamily="sans-serif-dedium"
	android:gravity="center"
	android:textColor="@android:color/white"
	android:textSize="16sp"
	tools:text="8.9" />
<TextView
	android:id="@+id/location_offset"
	android:layout_marginLeft="16dp"
	android:layout_width="0dp"
	android:layout_height="wrap_content"
	android:layout_weight="1"
	tools:text="30km S of" />

IF / ELSE Statement

if(points == 0){
	textView.setText("Loser");
	imageView.setImageResource(R.id.sad);
} else {
	textView.setText("Winner!");
	imageView.setImageResource(R.id.happy);
}

switch statement

switch (numberOfStarts){
	case 1:
		rating = "Bad restaurant";
		break;
	case 2:
		rating = "Okay restaurant";
		break;
	case 3:
		rating = "Great restaurant";
		break;
	default:
		rating = "No rating available";
		break;
}

switch statement

switch (grade){
	case 'A':
		message = "Superb work";
		break;
	case 'B':
		message = "Great job";
		break;
	case 'C':
		message = "You did OK";
		break;
	case 'D':
	case 'F':
		message = "Needs improvement";
		break;
	default:
		message = "No grade available";
		break;
}

Earthquake.java

public Earthquake(double magnitude, String location, long timeInMilliseconds){
	mMagnitude = magnitude;
	mLocation = location;
	mTimeInMilliseconds = timeInMilliseconds;
}

public double getMagnitude(){
	return mMagnitude;
}
import java.text.DecimalFormat;

@Override
public View getView(int postion, View convertView, ViewGroup parent){
	TextView magnitudeView = (TextView) listItemView.findViewById(R.id.magnitude);
	String formattedMagnitude = formatMagnitude(currentEarthquake.getMagnitude());
	magnitudeView.setText(formattedMagnitude);

	private String formatMagnitude(double magnitude){
		DecimalFormat magnitudeFormat = new DecimalFormat("0.0");
		return magnitudeFormat.format(magnitude);
	}
}