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);
}
}
EarthquakeAdapter
public View getView(int position, View convertView, ViewGroup parent){
View listItemView = convertView;
if (listItemView == null){
listItemView = LayoutInflater.from(getContext()).inflate(
R.layout.earthquake_list_item, parent, false);
}
Earthquake currentEarthquake = getItem(position);
TextView magnitudeView = (TextView) listItemView.findViewById(R.id.magnitude);
magnitudeView.setText(currentEarthquake.getMagnitude());
TextView locaionView = (TextView) listItemView.findViewById(R.id.location);
locationView.setText(currentEarthquake.getLocation());
Date dateObject = new Date(currentEarthquake.getTimeInMilliseconds());
TextView dateView = (TextView) listItemView.findViewById(R.id.date);
String formattedDate = formatDate(dateObject);
dateView.setText(formattedDate);
TextView timeView = (TextView) listItemView.findViewById(R.id.time);
String formattedTime = formatTime(dateObject);
timeView.setText(formattedTime);
return listItemView;
}
private String formatDate(Date dateObject){
SimpleDateFormat dateFormat = new SimpleDateFormat("LLL dd, yyyy");
return dateFormat.format(dateObject);
}
private String formatTime(Date deteObject){
SimpleDateFormat timeFormat = new SimpleDateFormat("h:mm a");
return timeFormat.format(dateObject);
}
Extract the value for the key
long time = properties.getLong("time");
private long mTimeInMilliseconds;
public Earthquake(String magnitude, String location, long timeInMilliseconds){
mMagnitude = magnitude;
mLocation = location;
mTimeInMilliseconds = timeInMilliseconds;
}
in earthquake_list_item.xml;
<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="match_parent" android:orientation="horizontal" android:padding="16dp"> <TextView android:id="@+id/magnitude" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" tools:text="8.9" /> <TextView android:id="@+id/location" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" tools:text="San Francisco, CA" /> <TextView android:id="@+id/date" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" tools:text="Mar 6, 2010" /> <TextView android:id="@+id/time" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" tools:text="3.00 PM" /> </LinearLayout>