First try...

This commit is contained in:
2013-02-28 09:45:24 +01:00
parent 586570a897
commit 5eda993d7a
59 changed files with 3 additions and 86 deletions

21
src/se/hv/dindag/AboutUs.java Executable file
View File

@@ -0,0 +1,21 @@
package se.hv.dindag;
import android.app.Activity;
import android.os.Bundle;
/**
* Fires up the AboutUs Activity
*
* @author imcoh
*
*/
public class AboutUs extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.menu_about);
}
}

View File

@@ -0,0 +1,18 @@
package se.hv.dindag;
import android.app.Activity;
import android.os.Bundle;
/**
* Fires up the DinDagMenu
*
* @author imcoh
*
*/
public class DinDagMenu extends Activity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.menu.menu_start);
}
}

147
src/se/hv/dindag/Login.java Executable file
View File

@@ -0,0 +1,147 @@
package se.hv.dindag;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
/**
* Handles the Login-functionality to the University West resources
*
* @author imcoh
*
*/
public class Login extends Activity {
// Login URL to server. if login correct the full user name is returned -
// else the string "Ingen anvŠndare":
private static final String loginURL = "http://mittkonto.hv.se/public/appfeed/login_response.php?app_key=";
// Login to min sida returns XML
private static final String loginXML_URL = "https://mittkonto.hv.se/public/appfeed/app_rss.php?app_key=";
/*
* Starts up the username & password boxes
*/
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
Button loginButton = (Button) findViewById(R.id.btnTryLogin);
loginButton.setOnClickListener(new OnClickListener() {
/*
* The button has been clicked and someone wants to login Get the
* information from the textboxes and create a String with theese
* two, whicjh is sent to the Hash-maker
*/
public void onClick(View v) {
Toast.makeText(getApplicationContext(),
"Kollar dina uppgifter...", Toast.LENGTH_LONG).show();
// Loginknappen har klickats. Kolla uppgifterna
EditText username = (EditText) findViewById(R.id.tfUsername);
EditText password = (EditText) findViewById(R.id.tfPassword);
String uname = username.getText().toString();
String pword = password.getText().toString();
// Concaternate the username with the password
String userAndPass = uname + pword;
MessageDigest digest = null;
String hash;
try {
// Select the appropriate Hash-function
digest = MessageDigest.getInstance("SHA-256");
digest.update(userAndPass.getBytes());
// Get the hash-value for the user
hash = bytesToHexString(digest.digest());
LoginData loginUser = new LoginData();
// Appends the hash to the URL
String loginString = loginURL + hash;
String[] urlHash = { loginString };
// call thread trŒden and execute doinBackground in
// Logindata;
loginUser.execute(urlHash);
// Get "answer" from LoginData doInBackground with get()
ArrayList<String> arrayList = loginUser.get();
// Checks the string returned from loginServer. Displays
// info to user
if (arrayList.get(0).contains("Ingen anv")) {
showWrongLoginPopup();
} else {
// loginResult.setText("VŠlkommen "+arrayList.get(0));
LoginData loginData = new LoginData();
// Appends the hash to the URL
String loginDataStr = loginXML_URL + hash;
String[] urlDataHash = { loginDataStr };
// PAss the URL to the data and the users realname to
// the new Activity
Intent myIntent = new Intent(Login.this, MyDay.class);
myIntent.putExtra("URL", urlDataHash[0]);
myIntent.putExtra("REALNAME", arrayList.get(0));
startActivity(myIntent);
}
} catch (NoSuchAlgorithmException e1) {
e1.printStackTrace();
}
// Malin: tillagt fšr att fŒnga ev ytterligare exceptions
catch (Exception e1) {
e1.printStackTrace();
}
}
});
}
/**
* Creates a hash of the input String
*
* @param Username
* and Password
* @return The hash-value
*/
private static String bytesToHexString(byte[] bytes) {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < bytes.length; i++) {
String hex = Integer.toHexString(0xFF & bytes[i]);
if (hex.length() == 1) {
sb.append('0');
}
sb.append(hex);
}
return sb.toString();
}
/**
* Displays a popup-windows sayin that the credentials were wrong
*/
private void showWrongLoginPopup() {
AlertDialog.Builder myBuild = new AlertDialog.Builder(this);
myBuild.setTitle("Fel inloggning");
myBuild.setMessage("De uppgifter som du skrev in stŠmmer inte. Logga in med de uppgifter som du fŒtt av IT-enheten vid Hšgskolan VŠst.");
myBuild.setNeutralButton("OK", null);
myBuild.show();
}
}

48
src/se/hv/dindag/LoginData.java Executable file
View File

@@ -0,0 +1,48 @@
package se.hv.dindag;
import java.util.ArrayList;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
import android.os.AsyncTask;
import android.util.Log;
/**
* Sets up an ASynkTask to the credentials-server asking if the
* Username/password combination was correct.
*
* @author immp
*
*/
public class LoginData extends AsyncTask<String, Void, ArrayList<String>> {
@Override
protected ArrayList<String> doInBackground(String... urlHash) {
String answer = null;
try {
// defaultHttpClient
DefaultHttpClient httpClient = new DefaultHttpClient();
HttpPost httpPost = new HttpPost(urlHash[0]);
HttpResponse httpResponse = httpClient.execute(httpPost);
HttpEntity httpEntity = httpResponse.getEntity();
answer = EntityUtils.toString(httpEntity);
} catch (Exception e) {
e.printStackTrace();
}
ArrayList<String> loginList = new ArrayList<String>();
loginList.add(answer);
return loginList;
}
// Dummy method
protected void onPostExecute(Integer result) {
Log.d("TestP", "AsyncTask done and returned: " + result);
}
}

148
src/se/hv/dindag/MyDay.java Executable file
View File

@@ -0,0 +1,148 @@
package se.hv.dindag;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.concurrent.ExecutionException;
import android.app.AlertDialog;
import android.app.ListActivity;
import android.content.Intent;
import android.os.Bundle;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import android.widget.TextView;
/**
* Start-Up activity giving the user a Login-button plus a feed of News
*
* @author imcoh
*/
public class MyDay extends ListActivity {
/**
* Define the keys in the XML-feed we're interested in
*/
static final String KEY_ITEM = "item"; // parent node
static final String KEY_LINK = "link";
static final String KEY_TITLE = "title";
static final String KEY_DESC = "description";
static final String KEY_DATE = "pubDate";
/*
* Fires up the activity_myday and waits for the Login-button to be pressed.
* Then it starts the ASynkTask to gather the XML-feed in the background.
* When this is done we can populate the ListAdapter with the stuff from the
* feed.
*/
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent in = getIntent();
// Den personliga URL innehŒllande URL samt app_key=HEMLIG_HASH
String url = in.getExtras().getString("URL");
// Riktiga namnet pŒ den inloggade anvŠndaren
String realName = in.getExtras().getString("REALNAME");
try {
// Initiate the ASynkTask
MyDayHandler myDayNews = new MyDayHandler();
// Start the task and give it the URL as input
myDayNews.execute(url);
// Create a local ArrayList
ArrayList<HashMap<String, String>> myDayItems = new ArrayList<HashMap<String, String>>();
// Fill the ArrayList with the items we got from the ASynkTask
myDayItems = myDayNews.get();
// Add the menuItems to our ListView
ListAdapter adapter = new SimpleAdapter(this, myDayItems,
R.layout.activity_myday_list, new String[] { KEY_TITLE,
KEY_LINK, KEY_DESC, KEY_DATE }, new int[] {
R.id.mydayTitle, R.id.mydayLink,
R.id.mydayDescription, R.id.mydayDate });
setListAdapter(adapter);
ListView lv = (ListView) findViewById(R.id.myDayList);
// Wait for an item in the list to be clicked
lv.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
// getting values from selected ListItem
String link = ((TextView) view.findViewById(R.id.mydayLink))
.getText().toString();
// Starting new intent
Intent in = new Intent(getApplicationContext(),
WebReader.class);
// Pass the URL to the new Activity
in.putExtra("KEY_LINK", link);
startActivity(in);
}
});
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
} catch (Exception e) {
System.out
.println("============= MOTHER OF ALL ERRORS IN MYDAY ================");
e.printStackTrace();
}
}
/**
* Displays the menu for the startup screen
*/
@Override
public boolean onCreateOptionsMenu(android.view.Menu menu) {
super.onCreateOptionsMenu(menu);
MenuInflater blowUp = getMenuInflater();
blowUp.inflate(R.menu.menu_loggedin, menu);
return true;
}
/**
* Handles the different kinds of buttons wich can be pressed in the current
* Activitys menu
*/
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menuSave:
AlertDialog.Builder savePopup = new AlertDialog.Builder(this);
savePopup.setTitle("Spara dina loginuppgifter");
savePopup
.setMessage("HŠr kan vi implementera en SQLlite-databas fšr att spara uppgifterna man matade in.");
savePopup.setNeutralButton("OK", null);
savePopup.show();
break;
case R.id.menuMail:
AlertDialog.Builder mailPopup = new AlertDialog.Builder(this);
mailPopup.setTitle("Kolla mail");
mailPopup
.setMessage("…ppnar helt enkelt en WebView till studenternas Live-mail sida. Vi behšver inte ta med nŒgon login eller sŒ, bara šppna en WebView.");
mailPopup.setNeutralButton("OK", null);
mailPopup.show();
break;
}
return false;
}
}

View File

@@ -0,0 +1,142 @@
package se.hv.dindag;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Locale;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import android.os.AsyncTask;
import android.text.Html;
import android.text.Spanned;
import android.util.Log;
/**
* This class manages the loading of external data. It uses the ASynkTask class
* for this, wich in this case takes 3 arguments. Theese are (in order): String,
* which is the input (URL of the feed), Void, which is the datatype of the
* progress report (but I dont use any progress report, and finally an
* ArrayList, which is what is being returned from the class.
*
* This is a good place to mention why the app is using this ASynkTask: since
* Android version 3, the only Thread allowed to draw GUI-stuff is the
* main-thread and secondly, the main thread cannot use the network. Since
* getting an XML-feed is very much networking this has to be done someplace
* else than in the main thread. ASynkTask accomplishes this by setting aside a
* separate thread doing networking stuff.
*
* This class needs to have a method called doInBackground, which is responsible
* for doing the legwork of the class.
*
* @author imcoh
*
*/
public class MyDayHandler extends AsyncTask<String, Void, ArrayList> {
/**
* Define the keys in the XML-feed we're interested in
*/
static final String KEY_ITEM = "item"; // parent node
static final String KEY_LINK = "link";
static final String KEY_TITLE = "title";
static final String KEY_DESC = "description";
static final String KEY_DATE = "pubDate";
static final String KEY_TAG = "tag";
/**
* Since the desciption-element in the XML-feed look pretty shitty since
* teachers are allowed to use HTML-formatting in systems like Kronox, this
* method uses the fromHtml-method to strip tags and convert HTML-encoded
* characters to UTF-8, eg. #244 => Œ
*
* @param description
* @return A nice and clean string without HTML
*/
private String deUglify(String description) {
Spanned temp;
temp = Html.fromHtml(description);
return temp.toString();
}
/**
* Preserves the important part of the publishing time of an element in the
* feed. Counting the days since the notice has been published.
*
* @param theDate
* @return Polished date
*/
private String prettyfyDate(String theDate) {
String temp = theDate.substring(0, 10);
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd",
Locale.getDefault());
// TODO: Fixa till datumet i denna
// Förra versionen nvänder dc:date som ser ut som:
// 2013-02-08T10:49:00+01:00
//
// medan vi nu använder pubDate, som ser ut som:
// Thu, 24 Jan 2013 18:04:25 +0100
SimpleDateFormat sdf = new SimpleDateFormat(
"EEE, dd MMM yyyy HH:mm:ss z", Locale.getDefault());
Date date = null;
try {
date = sdf.parse(theDate);
theDate = new SimpleDateFormat("dd MMM @ HH:mm").format(date);
} catch (Exception e) {
e.printStackTrace();
}
return theDate;
}
/**
* Does all the magic in getting an XML-file from the network, parses it, an
* filling an ArrayList containing an HashMap of KEY-VALUE-pairs
*
* @param URL
* of the feed
* @return The ArrayList called menuItems containing the feed
*/
protected ArrayList<HashMap<String, String>> doInBackground(
String... theURL) {
String theFeed = theURL[0];
ArrayList<HashMap<String, String>> menuItems = new ArrayList<HashMap<String, String>>();
XMLParser parser = new XMLParser();
String xml = parser.getXmlFromUrl(theFeed); // getting XML
Document doc = parser.getDomElement(xml); // getting DOM element
NodeList nl = doc.getElementsByTagName(KEY_ITEM);
// looping through all item nodes <item>
for (int i = 0; i < nl.getLength(); i++) {
// creating new HashMap
HashMap<String, String> map = new HashMap<String, String>();
Element e = (Element) nl.item(i);
// adding each child node to HashMap key => value
map.put(KEY_TITLE, parser.getValue(e, KEY_TITLE));
map.put(KEY_TAG, parser.getValue(e, KEY_TAG));
map.put(KEY_LINK, parser.getValue(e, KEY_LINK));
map.put(KEY_DESC, deUglify(parser.getValue(e, KEY_DESC)));
map.put(KEY_DATE, prettyfyDate(parser.getValue(e, KEY_DATE)));
// adding HashList to ArrayList
menuItems.add(map);
}
return menuItems;
}
/**
* Dummy-method just called after the ASynkTask is done
*
* @param result
*/
protected void onPostExecute(Integer result) {
Log.i("MyDayHandler", "AsyncTask done. Returned : " + result);
}
}

215
src/se/hv/dindag/Start.java Executable file
View File

@@ -0,0 +1,215 @@
package se.hv.dindag;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.concurrent.ExecutionException;
import android.app.AlertDialog;
import android.app.ListActivity;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Bundle;
import android.util.Log;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.Button;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import android.widget.TextView;
import android.widget.Toast;
/**
* Start-Up activity giving the user a Login-button plus a feed of News
*
* @author imcoh
*/
public class Start extends ListActivity {
/**
* Define the keys in the XML-feed we're interested in
*/
static final String KEY_ITEM = "item"; // parent node
static final String KEY_LINK = "link";
static final String KEY_TITLE = "title";
static final String KEY_DESC = "description";
static final String KEY_DATE = "dc:date";
// The feed we want to read
static final String URL = "http://www.hv.se/feeds/nyheter.xml";
/**
* Checks whether the device is connected to the Internet or not.
*
* @return true if connected, otherwise false
*/
public boolean isOnline() {
final ConnectivityManager conMgr = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
if (conMgr.getNetworkInfo(0).getState() == NetworkInfo.State.CONNECTED
|| conMgr.getNetworkInfo(1).getState() == NetworkInfo.State.CONNECTED) {
return true;
} else {
return false;
}
}
/**
* Shows a dialog and the exists the app
*/
public void graceFullyExit() {
Log.e("NET", "No network.");
final AlertDialog.Builder myBuild = new AlertDialog.Builder(Start.this);
myBuild.setTitle("Ingen anslutning");
myBuild.setMessage("Du Šr inte ansluten till Internet. Utan en Internetanslutning kan du vŠl inte begŠra att jag ska kunna hŠmta din information?");
myBuild.setNeutralButton("OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
Log.i("Start", "Kommit hit");
finish();
}
});
myBuild.show();
}
/**
* Fires up the activity_start and waits for the Login-button to be pressed.
* Then it starts the ASynkTask to gather the XML-feed in the background.
* When this is done we can populate the ListAdapter with the stuff from the
* feed.
*/
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_start);
if (!isOnline()) {
graceFullyExit();
} else {
Log.i("NET", "Vi har nŠtverk.");
Toast.makeText(getApplicationContext(), "Laddar data...",
Toast.LENGTH_LONG).show();
Button login = (Button) findViewById(R.id.btnLogin);
login.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
// Login-button pressed. Start the Login-activity
Intent myIntent = new Intent(Start.this, Login.class);
Start.this.startActivity(myIntent);
}
});
try {
// Initiate the ASynkTask
XMLDataHandler generalNews = new XMLDataHandler();
// Start the task and give it the URL as input
generalNews.execute(URL);
// Create a local ArrayList
ArrayList<HashMap<String, String>> menuItems = new ArrayList<HashMap<String, String>>();
// Fill the ArrayList with the items we got from the ASynkTask
menuItems = generalNews.get();
// Add the menuItems to our ListView
ListAdapter adapter = new SimpleAdapter(this, menuItems,
R.layout.activity_generic, new String[] { KEY_TITLE,
KEY_LINK, KEY_DESC, KEY_DATE }, new int[] {
R.id.generalTitle, R.id.generalLink,
R.id.generalDescription, R.id.generalDate });
setListAdapter(adapter);
// selecting single ListView item
ListView lv = getListView();
menuItems = null;
// Wait for an item in the list to be clicked
lv.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
Toast.makeText(getApplicationContext(),
"Laddar data...", Toast.LENGTH_LONG).show();
// getting values from selected ListItem
String link = ((TextView) view
.findViewById(R.id.generalLink)).getText()
.toString();
// Starting new intent
Intent in = new Intent(getApplicationContext(),
WebReader.class);
// Pass the URL to the new Activity
in.putExtra("KEY_LINK", link);
startActivity(in);
}
});
} catch (InterruptedException e) {
Log.e("IE", "Interupted");
e.printStackTrace();
} catch (ExecutionException e) {
Log.e("EXE", "Execution");
e.printStackTrace();
} catch (Exception e) {
System.out
.println("============= MOTHER OF ALL ERRORS IN START ================");
e.printStackTrace();
}
}
}
/**
* Displays the menu for the startup screen
*/
@Override
public boolean onCreateOptionsMenu(android.view.Menu menu) {
super.onCreateOptionsMenu(menu);
MenuInflater blowUp = getMenuInflater();
blowUp.inflate(R.menu.menu_start, menu);
return true;
}
/**
* Handles the different kinds of buttons wich can be pressed in the current
* Activitys menu
*/
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menuAbout:
Log.i("Menu", "About");
Intent showAbout = new Intent("se.hv.dindag.ABOUT");
startActivity(showAbout);
break;
case R.id.menuPrefs:
AlertDialog.Builder settingsPopup = new AlertDialog.Builder(this);
settingsPopup.setTitle("InstŠllningar");
settingsPopup
.setMessage("JŠttekul att du tryckte pŒ den dŠr knappen. Verkligen. Synd bara att den inte gšr nŒgot. Hade den gjort nŒgot hade det sŠkert varit nŒgot fantastiskt som hade hŠnt.");
settingsPopup.setNeutralButton("OK", null);
settingsPopup.show();
break;
case R.id.menuTwitter:
Intent showTwitter = new Intent("se.hv.dindag.TWITTER");
startActivity(showTwitter);
break;
}
return false;
}
}

7
src/se/hv/dindag/Tweet.java Executable file
View File

@@ -0,0 +1,7 @@
package se.hv.dindag;
public class Tweet {
String from;
String text;
String date;
}

130
src/se/hv/dindag/TwitterFeed.java Executable file
View File

@@ -0,0 +1,130 @@
package se.hv.dindag;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Locale;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
import org.json.JSONArray;
import org.json.JSONObject;
import android.app.ListActivity;
import android.app.ProgressDialog;
import android.content.Context;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;
public class TwitterFeed extends ListActivity {
private ArrayList<Tweet> tweets = new ArrayList<Tweet>();
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
new MyTask().execute();
}
private class MyTask extends AsyncTask<Void, Void, Void> {
private ProgressDialog progressDialog;
protected void onPreExecute() {
progressDialog = ProgressDialog.show(TwitterFeed.this, "",
"Laddar Tweets...", true);
}
@Override
protected Void doInBackground(Void... arg0) {
/* "http://search.twitter.com/search.json?q=from:University_West"); */
try {
HttpClient hc = new DefaultHttpClient();
HttpGet get = new HttpGet(
"http://search.twitter.com/search.json?q=hogskolan%20vast");
HttpResponse rp = hc.execute(get);
if (rp.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
String result = EntityUtils.toString(rp.getEntity());
JSONObject root = new JSONObject(result);
JSONArray sessions = root.getJSONArray("results");
for (int i = 0; i < sessions.length(); i++) {
JSONObject session = sessions.getJSONObject(i);
Tweet tweet = new Tweet();
tweet.text = session.getString("text");
tweet.from = session.getString("from_user");
tweet.date = prettyfyDate(session
.getString("created_at"));
tweets.add(tweet);
}
}
} catch (Exception e) {
Log.e("TwitterFeedActivity", "Error loading JSON", e);
}
return null;
}
@Override
protected void onPostExecute(Void result) {
progressDialog.dismiss();
setListAdapter(new TweetListAdaptor(TwitterFeed.this,
R.layout.activity_tweet_list, tweets));
}
}
/**
* Preserves the important part of the publishing time of an element in the
* feed. Counting the days since the notice has been published.
*
* @param theDate
* (Format: Thu, 21 Feb 2013 09:27:56 +0000)
* @return Polished date
*/
private String prettyfyDate(String theDate) {
SimpleDateFormat sdf = new SimpleDateFormat(
"EEE, dd MMM yyyy HH:mm:ss z", Locale.getDefault());
Date date = null;
try {
date = sdf.parse(theDate);
theDate = new SimpleDateFormat("dd MMM @ HH:mm").format(date);
} catch (Exception e) {
e.printStackTrace();
}
return theDate;
}
private class TweetListAdaptor extends ArrayAdapter<Tweet> {
private ArrayList<Tweet> tweets;
public TweetListAdaptor(Context context, int textViewResourceId,
ArrayList<Tweet> items) {
super(context, textViewResourceId, items);
this.tweets = items;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
if (v == null) {
LayoutInflater vi = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(R.layout.activity_tweet_list, null);
}
Tweet o = tweets.get(position);
TextView tvText = (TextView) v.findViewById(R.id.tweet_text);
TextView tvDate = (TextView) v.findViewById(R.id.tweet_date);
TextView tvFrom = (TextView) v.findViewById(R.id.tweet_from);
tvFrom.setText("@" + o.from);
tvDate.setText(o.date);
tvText.setText(o.text);
return v;
}
}
}

50
src/se/hv/dindag/WebReader.java Executable file
View File

@@ -0,0 +1,50 @@
package se.hv.dindag;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.webkit.WebView;
/**
* Opens up a new WebView and loads the URL of the chosen element from the feed
* in the activity_webreader
*
* @author imcoh
*
*/
public class WebReader extends Activity {
WebView webview;
/*
* Creates a WebView, gets the URL from previous activity and starts the
* WebView.
*/
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_webreader);
Intent in = getIntent();
String url = in.getExtras().getString("KEY_LINK");
try {
WebSinglePost gsn = new WebSinglePost();
gsn.execute(url);
WebView webview;
webview = (WebView) findViewById(R.id.webreader);
String html = gsn.get();
String mime = "text/html";
String encoding = "iso-8859-1";
webview.loadData(html, mime, encoding);
} catch (Exception e) {
System.out.println("======== JSOUP Error");
e.printStackTrace();
}
}
}

View File

@@ -0,0 +1,41 @@
package se.hv.dindag;
import java.io.IOException;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.select.Elements;
import android.os.AsyncTask;
/**
* Makes a connection the the URL of the HV-website and by using JSOUP we can
* point out wich DIV-tag we want to retrive. The result is stored in a String,
* wich is returned as a result.
*
* @param The
* URL of a certain website
* @return The String of text contained in a specific DIV-tag
* @author imcoh
*
*/
public class WebSinglePost extends AsyncTask<String, Void, String> {
@Override
protected String doInBackground(String... theURL) {
String url = theURL[0];
String html = null;
Document doc;
try {
doc = Jsoup.connect(url).get();
Elements ele = doc.select("div.twocolumns");
html = ele.toString();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return html;
}
}

View File

@@ -0,0 +1,153 @@
package se.hv.dindag;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Locale;
import java.util.concurrent.TimeUnit;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import android.net.ParseException;
import android.os.AsyncTask;
import android.text.Html;
import android.text.Spanned;
import android.util.Log;
/**
* This class manages the loading of external data. It uses the ASynkTask class
* for this, wich in this case takes 3 arguments. Theese are (in order): String,
* which is the input (URL of the feed), Void, which is the datatype of the
* progress report (but I dont use any progress report, and finally an
* ArrayList, which is what is being returned from the class.
*
* This is a good place to mention why the app is using this ASynkTask: since
* Android version 3, the only Thread allowed to draw GUI-stuff is the
* main-thread and secondly, the main thread cannot use the network. Since
* getting an XML-feed is very much networking this has to be done someplace
* else than in the main thread. ASynkTask accomplishes this by setting aside a
* separate thread doing networking stuff.
*
* This class needs to have a method called doInBackground, which is responsible
* for doing the legwork of the class.
*
* @author imcoh
*
*/
public class XMLDataHandler extends AsyncTask<String, Void, ArrayList> {
/**
* Define the keys in the XML-feed we're interested in
*/
static final String KEY_ITEM = "item"; // parent node
static final String KEY_LINK = "link";
static final String KEY_TITLE = "title";
static final String KEY_DESC = "description";
static final String KEY_DATE = "dc:date";
static final String KEY_COLOR = "color";
/**
* Since the desciption-element in the XML-feed look pretty shitty since
* teachers are allowed to use HTML-formatting in systems like Kronox, this
* method uses the fromHtml-method to strip tags and convert HTML-encoded
* characters to UTF-8, eg. #244 => Œ
*
* @param description
* @return A nice and clean string without HTML
*/
private String deUglify(String description) {
Spanned temp;
temp = Html.fromHtml(description);
return temp.toString();
}
/**
* Preserves the important part of the publishing time of an element in the
* feed. Counting the days since the notice has been published.
*
* @param theDate
* @return Polished date
*/
private String prettyfyDate(String theDate) {
String temp = theDate.substring(0, 10);
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd",
Locale.getDefault());
long days = 0;
try {
Date past = format.parse(temp);
Date now = new Date();
days = TimeUnit.MILLISECONDS.toDays(now.getTime() - past.getTime());
} catch (ParseException e) {
e.printStackTrace();
} catch (java.text.ParseException e) {
e.printStackTrace();
}
String returnString = ""; // = temp;
if (days == 1) {
returnString += Long.toString(days) + " dag sedan";
} else if (days > 1) {
returnString += Long.toString(days) + " dagar sedan";
}
return returnString;
}
/**
* Does all the magic in getting an XML-file from the network, parses it, an
* filling an ArrayList containing an HashMap of KEY-VALUE-pairs
*
* @param URL
* of the feed
* @return The ArrayList called menuItems containing the feed
*/
@Override
protected ArrayList<HashMap<String, String>> doInBackground(
String... theURL) {
String theFeed = theURL[0];
ArrayList<HashMap<String, String>> menuItems = new ArrayList<HashMap<String, String>>();
XMLParser parser = new XMLParser();
String xml = parser.getXmlFromUrl(theFeed); // getting XML
Document doc = parser.getDomElement(xml); // getting DOM element
NodeList nl = doc.getElementsByTagName(KEY_ITEM);
// looping through all item nodes <item>
for (int i = 0; i < nl.getLength(); i++) {
// creating new HashMap
HashMap<String, String> map = new HashMap<String, String>();
Element e = (Element) nl.item(i);
// adding each child node to HashMap key => value
map.put(KEY_TITLE, parser.getValue(e, KEY_TITLE));
map.put(KEY_COLOR, parser.getValue(e, KEY_COLOR));
map.put(KEY_LINK, parser.getValue(e, KEY_LINK));
map.put(KEY_DESC, deUglify(parser.getValue(e, KEY_DESC)));
map.put(KEY_DATE, prettyfyDate(parser.getValue(e, KEY_DATE)));
// adding HashList to ArrayList
menuItems.add(map);
}
return menuItems;
}
@Override
protected void onPreExecute() {
Log.i("XMLData", "onPRE");
}
/**
* Dummy-method just called after the ASynkTask is done
*
*/
@Override
protected void onPostExecute(ArrayList stuff) {
Log.i("XMLData", "onPOST");
}
}

135
src/se/hv/dindag/XMLParser.java Executable file
View File

@@ -0,0 +1,135 @@
package se.hv.dindag;
import java.io.IOException;
import java.io.StringReader;
import java.io.UnsupportedEncodingException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import android.util.Log;
/**
* Parses an XML-feed using the DOM
*
* @author imcoh
*
*/
public class XMLParser {
/**
* Just an empty constructor
*/
public XMLParser() {
}
/**
* Getting XML from URL making HTTP request
*
* @param url
* string
*/
public String getXmlFromUrl(String url) {
String xml = null;
try {
// defaultHttpClient
DefaultHttpClient httpClient = new DefaultHttpClient();
HttpPost httpPost = new HttpPost(url);
HttpResponse httpResponse = httpClient.execute(httpPost);
HttpEntity httpEntity = httpResponse.getEntity();
xml = EntityUtils.toString(httpEntity);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
// return XML
return xml;
}
/**
* Getting XML DOM element
*
* @param XML
* string
* @return The DOM-object
*/
public Document getDomElement(String xml) {
Document doc = null;
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
try {
DocumentBuilder db = dbf.newDocumentBuilder();
InputSource is = new InputSource();
is.setCharacterStream(new StringReader(xml));
doc = db.parse(is);
} catch (ParserConfigurationException e) {
Log.e("Error: ", e.getMessage());
return null;
} catch (SAXException e) {
Log.e("Error: ", e.getMessage());
return null;
} catch (IOException e) {
Log.e("Error: ", e.getMessage());
return null;
}
return doc;
}
/**
* Gets the value of the chosen node
*
* @param elem
* element
* @return The value of the Node
*/
public final String getElementValue(Node elem) {
Node child;
if (elem != null) {
if (elem.hasChildNodes()) {
for (child = elem.getFirstChild(); child != null; child = child
.getNextSibling()) {
if (child.getNodeType() == Node.TEXT_NODE) {
return child.getNodeValue();
}
}
}
}
return "";
}
/**
* Getting node value
*
* @param Element
* node
* @param key
* string
* */
public String getValue(Element item, String str) {
NodeList n = item.getElementsByTagName(str);
return this.getElementValue(n.item(0));
}
}