summaryrefslogtreecommitdiffstats
path: root/Android/06-Notifications/Notifications/src/course/labs/notificationslab
diff options
context:
space:
mode:
Diffstat (limited to 'Android/06-Notifications/Notifications/src/course/labs/notificationslab')
-rw-r--r--Android/06-Notifications/Notifications/src/course/labs/notificationslab/DownloaderTask.java217
-rw-r--r--Android/06-Notifications/Notifications/src/course/labs/notificationslab/FeedFragment.java35
-rw-r--r--Android/06-Notifications/Notifications/src/course/labs/notificationslab/FriendsFragment.java44
-rw-r--r--Android/06-Notifications/Notifications/src/course/labs/notificationslab/MainActivity.java235
-rw-r--r--Android/06-Notifications/Notifications/src/course/labs/notificationslab/SelectionListener.java5
-rw-r--r--Android/06-Notifications/Notifications/src/course/labs/notificationslab/TestFrontEndActivity.java114
6 files changed, 650 insertions, 0 deletions
diff --git a/Android/06-Notifications/Notifications/src/course/labs/notificationslab/DownloaderTask.java b/Android/06-Notifications/Notifications/src/course/labs/notificationslab/DownloaderTask.java
new file mode 100644
index 0000000..b792b38
--- /dev/null
+++ b/Android/06-Notifications/Notifications/src/course/labs/notificationslab/DownloaderTask.java
@@ -0,0 +1,217 @@
+package course.labs.notificationslab;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.net.URL;
+
+import android.app.Activity;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.os.AsyncTask;
+import android.util.Log;
+import android.widget.RemoteViews;
+
+public class DownloaderTask extends AsyncTask<String, Void, String[]> {
+
+ private static final int SIM_NETWORK_DELAY = 5000;
+ private static final String TAG = "Lab-Notifications";
+ private final int MY_NOTIFICATION_ID = 11151990;
+ private String mFeeds[] = new String[3];
+ private MainActivity mParentActivity;
+ private Context mApplicationContext;
+
+ // Change this variable to false if you do not have a stable network
+ // connection
+ private static final boolean HAS_NETWORK_CONNECTION = true;
+
+ // Raw feed file IDs used if you do not have a stable connection
+ public static final int txtFeeds[] = { R.raw.tswift, R.raw.rblack, R.raw.lgaga };
+
+ // Constructor
+ public DownloaderTask(MainActivity parentActivity) {
+ super();
+ mParentActivity = parentActivity;
+ mApplicationContext = parentActivity.getApplicationContext();
+ }
+
+ @Override
+ protected String[] doInBackground(String... urlParameters) {
+ log("Entered doInBackground()");
+ return download(urlParameters);
+ }
+
+ private String[] download(String urlParameters[]) {
+
+ boolean downloadCompleted = false;
+
+ try {
+
+ for (int idx = 0; idx < urlParameters.length; idx++) {
+
+ URL url = new URL(urlParameters[idx]);
+ try {
+ Thread.sleep(SIM_NETWORK_DELAY);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+
+ InputStream inputStream;
+ BufferedReader in;
+
+ // Alternative for students without
+ // a network connection
+ if (HAS_NETWORK_CONNECTION) {
+ inputStream = url.openStream();
+ in = new BufferedReader(new InputStreamReader(inputStream));
+ } else {
+ inputStream = mApplicationContext.getResources().openRawResource(txtFeeds[idx]);
+ in = new BufferedReader(new InputStreamReader(inputStream));
+ }
+
+ String readLine;
+ StringBuffer buf = new StringBuffer();
+
+ while ((readLine = in.readLine()) != null) {
+ buf.append(readLine);
+ }
+
+ mFeeds[idx] = buf.toString();
+
+ if (null != in) {
+ in.close();
+ }
+ }
+
+ downloadCompleted = true;
+
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ log("Tweet Download Completed:" + downloadCompleted);
+
+ notify(downloadCompleted);
+
+ return mFeeds;
+ }
+
+ // Call back to the MainActivity to update the feed display
+ @Override
+ protected void onPostExecute(String[] result) {
+ super.onPostExecute(result);
+
+ if (mParentActivity != null) {
+ mParentActivity.setRefreshed(result);
+ }
+
+ }
+
+ // If necessary, notifies the user that the tweet downloads are complete.
+ // Sends an ordered broadcast back to the BroadcastReceiver in MainActivity
+ // to determine whether the notification is necessary.
+ private void notify(final boolean success) {
+ log("Entered notify()");
+ final Intent restartMainActivtyIntent = new Intent(mApplicationContext, MainActivity.class);
+ restartMainActivtyIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
+ if (success) {
+ // Save tweets to a file
+ saveTweetsToFile();
+ }
+
+ // Sends an ordered broadcast to determine whether MainActivity is
+ // active and in the foreground. Creates a new BroadcastReceiver
+ // to receive a result indicating the state of MainActivity
+
+ // The Action for this broadcast Intent is MainActivity.DATA_REFRESHED_ACTION
+ // The result Activity.RESULT_OK, indicates that MainActivity is active and
+ // in the foreground.
+ mApplicationContext.sendOrderedBroadcast(
+ new Intent(MainActivity.DATA_REFRESHED_ACTION), null, new BroadcastReceiver() {
+
+ final String failMsg = "Download has failed. Please retry Later.";
+ final String successMsg = "Download completed successfully.";
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+
+ log("Entered result receiver's onReceive() method");
+
+ // TODO: Check whether the result code is RESULT_OK
+
+ if (/*change this*/ true) {
+
+ // TODO: If so, create a PendingIntent using the
+ // restartMainActivityIntent and set its flags
+ // to FLAG_UPDATE_CURRENT
+
+ final PendingIntent pendingIntent = null;
+
+ // Uses R.layout.custom_notification for the
+ // layout of the notification View. The xml
+ // file is in res/layout/custom_notification.xml
+ RemoteViews mContentView = new RemoteViews(
+ mApplicationContext.getPackageName(),
+ R.layout.custom_notification);
+
+ // TODO: Set the notification View's text to
+ // reflect whether or the download completed
+ // successfully
+
+ // TODO: Use the Notification.Builder class to
+ // create the Notification. You will have to set
+ // several pieces of information. You can use
+ // android.R.drawable.stat_sys_warning
+ // for the small icon. You should also setAutoCancel(true).
+
+ Notification.Builder notificationBuilder = null;
+
+ // TODO: Send the notification
+
+ log("Notification Area Notification sent");
+ }
+ }
+ }, null, 0, null, null);
+ }
+
+ // Saves the tweets to a file
+ private void saveTweetsToFile() {
+ PrintWriter writer = null;
+ try {
+ FileOutputStream fos = mApplicationContext.openFileOutput(
+ MainActivity.TWEET_FILENAME, Context.MODE_PRIVATE);
+ writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(
+ fos)));
+
+ for (String s : mFeeds) {
+ writer.println(s);
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ } finally {
+ if (null != writer) {
+ writer.close();
+ }
+ }
+ }
+
+ // Simplified log output method
+ private void log(String msg) {
+ try {
+ Thread.sleep(500);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ Log.i(TAG, msg);
+ }
+}
diff --git a/Android/06-Notifications/Notifications/src/course/labs/notificationslab/FeedFragment.java b/Android/06-Notifications/Notifications/src/course/labs/notificationslab/FeedFragment.java
new file mode 100644
index 0000000..549524a
--- /dev/null
+++ b/Android/06-Notifications/Notifications/src/course/labs/notificationslab/FeedFragment.java
@@ -0,0 +1,35 @@
+package course.labs.notificationslab;
+
+import android.app.Fragment;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+public class FeedFragment extends Fragment {
+
+ private TextView mTextView;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ return inflater.inflate(R.layout.feed, container, false);
+ }
+
+ @Override
+ public void onActivityCreated(Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+ mTextView = (TextView) getView().findViewById(R.id.feed_view);
+ }
+
+ void update(String feed) {
+ if (null != mTextView) {
+ mTextView.setText(feed);
+ }
+ }
+}
diff --git a/Android/06-Notifications/Notifications/src/course/labs/notificationslab/FriendsFragment.java b/Android/06-Notifications/Notifications/src/course/labs/notificationslab/FriendsFragment.java
new file mode 100644
index 0000000..b90f8d3
--- /dev/null
+++ b/Android/06-Notifications/Notifications/src/course/labs/notificationslab/FriendsFragment.java
@@ -0,0 +1,44 @@
+package course.labs.notificationslab;
+
+import android.app.Activity;
+import android.app.ListFragment;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.ArrayAdapter;
+import android.widget.ListView;
+
+public class FriendsFragment extends ListFragment {
+
+ private SelectionListener mCallback;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setListAdapter(new ArrayAdapter<String>(getActivity(), android.R.layout.simple_list_item_1, MainActivity.FRIENDS));
+ }
+
+ @Override
+ public void onAttach(Activity activity) {
+ super.onAttach(activity);
+
+ // This makes sure that the container activity has implemented
+ // the callback interface. If not, it throws an exception
+ try {
+ mCallback = (SelectionListener) activity;
+ } catch (ClassCastException e) {
+ throw new ClassCastException(activity.toString() + " must implement SelectionListener");
+ }
+ }
+
+ @Override
+ public void onActivityCreated(Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+ getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);
+ }
+
+ @Override
+ public void onListItemClick(ListView l, View view, int position, long id) {
+ // Send the event to the host activity
+ mCallback.onItemSelected(position);
+ }
+}
diff --git a/Android/06-Notifications/Notifications/src/course/labs/notificationslab/MainActivity.java b/Android/06-Notifications/Notifications/src/course/labs/notificationslab/MainActivity.java
new file mode 100644
index 0000000..eebf924
--- /dev/null
+++ b/Android/06-Notifications/Notifications/src/course/labs/notificationslab/MainActivity.java
@@ -0,0 +1,235 @@
+package course.labs.notificationslab;
+
+import java.io.BufferedReader;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStreamReader;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import android.app.Activity;
+import android.app.FragmentManager;
+import android.app.FragmentTransaction;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Bundle;
+import android.util.Log;
+
+public class MainActivity extends Activity implements SelectionListener {
+
+ public static final String TWEET_FILENAME = "tweets.txt";
+ public static final String[] FRIENDS = { "taylorswift13", "msrebeccablack", "ladygaga" };
+ public static final String DATA_REFRESHED_ACTION = "course.labs.notificationslab.DATA_REFRESHED";
+
+ private static final int NUM_FRIENDS = 3;
+ private static final String URL_LGAGA = "https://d396qusza40orc.cloudfront.net/android%2FLabs%2FUserNotifications%2Fladygaga.txt";
+ private static final String URL_RBLACK = "https://d396qusza40orc.cloudfront.net/android%2FLabs%2FUserNotifications%2Frebeccablack.txt";
+ private static final String URL_TSWIFT = "https://d396qusza40orc.cloudfront.net/android%2FLabs%2FUserNotifications%2Ftaylorswift.txt";
+ private static final String TAG = "Lab-Notifications";
+ private static final long TWO_MIN = 2 * 60 * 1000;
+ private static final int UNSELECTED = -1;
+
+ private FragmentManager mFragmentManager;
+ private FriendsFragment mFriendsFragment;
+ private boolean mIsFresh;
+ private BroadcastReceiver mRefreshReceiver;
+ private int mFeedSelected = UNSELECTED;
+ private FeedFragment mFeedFragment;
+ private String[] mRawFeeds = new String[3];
+ private String[] mProcessedFeeds = new String[3];
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+ mFragmentManager = getFragmentManager();
+ addFriendsFragment();
+ // The feed is fresh if it was downloaded less than 2 minutes ago
+ mIsFresh = (System.currentTimeMillis() - getFileStreamPath( TWEET_FILENAME).lastModified()) < TWO_MIN;
+ ensureData();
+ }
+
+ // Add Friends Fragment to Activity
+ private void addFriendsFragment() {
+ mFriendsFragment = new FriendsFragment();
+ mFriendsFragment.setArguments(getIntent().getExtras());
+ FragmentTransaction transaction = mFragmentManager.beginTransaction();
+ transaction.add(R.id.fragment_container, mFriendsFragment);
+ transaction.commit();
+ }
+
+ // If stored Tweets are not fresh, reload them from network
+ // Otherwise, load them from file
+ private void ensureData() {
+
+ log("In ensureData(), mIsFresh:" + mIsFresh);
+
+ if (!mIsFresh) {
+ // TODO:
+ // Show a Toast Notification to inform user that
+ // the app is "Downloading Tweets from Network"
+ log ("Issuing Toast Message");
+
+ // TODO:
+ // Start new AsyncTask to download Tweets from network
+
+ // Set up a BroadcastReceiver to receive an Intent when download
+ // finishes.
+ mRefreshReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ log("BroadcastIntent received in MainActivity");
+ // TODO:
+ // Check to make sure this is an ordered broadcast
+ // Let sender know that the Intent was received
+ // by setting result code to RESULT_OK
+ }
+ };
+ } else {
+ loadTweetsFromFile();
+ parseJSON();
+ updateFeed();
+ }
+ }
+
+ // Called when new Tweets have been downloaded
+ public void setRefreshed(String[] feeds) {
+ mRawFeeds[0] = feeds[0];
+ mRawFeeds[1] = feeds[1];
+ mRawFeeds[2] = feeds[2];
+
+ parseJSON();
+ updateFeed();
+ mIsFresh = true;
+ };
+
+ // Called when a Friend is clicked on
+ @Override
+ public void onItemSelected(int position) {
+ mFeedSelected = position;
+ mFeedFragment = addFeedFragment();
+
+ if (mIsFresh) {
+ updateFeed();
+ }
+ }
+
+ // Calls FeedFragement.update, passing in the
+ // the tweets for the currently selected friend
+ void updateFeed() {
+ if (null != mFeedFragment)
+ mFeedFragment.update(mProcessedFeeds[mFeedSelected]);
+ }
+
+ // Add FeedFragment to Activity
+ private FeedFragment addFeedFragment() {
+ FeedFragment feedFragment;
+ feedFragment = new FeedFragment();
+
+ FragmentTransaction transaction = mFragmentManager.beginTransaction();
+
+ transaction.replace(R.id.fragment_container, feedFragment);
+ transaction.addToBackStack(null);
+
+ transaction.commit();
+ mFragmentManager.executePendingTransactions();
+ return feedFragment;
+ }
+
+ // Register the BroadcastReceiver
+ @Override
+ protected void onResume() {
+ super.onResume();
+ // TODO:
+ // Register the BroadcastReceiver to receive a
+ // DATA_REFRESHED_ACTION broadcast
+ }
+
+ @Override
+ protected void onPause() {
+ // TODO:
+ // Unregister the BroadcastReceiver
+ super.onPause();
+ }
+
+ // Convert raw Tweet data (in JSON format) into text for display
+ public void parseJSON() {
+
+ JSONArray[] JSONFeeds = new JSONArray[NUM_FRIENDS];
+
+ for (int i = 0; i < NUM_FRIENDS; i++) {
+ try {
+ JSONFeeds[i] = new JSONArray(mRawFeeds[i]);
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+
+ String name = "";
+ String tweet = "";
+
+ JSONArray tmp = JSONFeeds[i];
+
+ // string buffer for twitter feeds
+ StringBuffer tweetRec = new StringBuffer("");
+
+ for (int j = 0; j < tmp.length(); j++) {
+ try {
+ tweet = tmp.getJSONObject(j).getString("text");
+ JSONObject user = (JSONObject) tmp.getJSONObject(j).get(
+ "user");
+ name = user.getString("name");
+
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+
+ tweetRec.append(name + " - " + tweet + "\n\n");
+ }
+ mProcessedFeeds[i] = tweetRec.toString();
+ }
+ }
+
+ // Retrieve feeds text from a file
+ // Store them in mRawTextFeed[]
+ private void loadTweetsFromFile() {
+ BufferedReader reader = null;
+
+ try {
+ FileInputStream fis = openFileInput(TWEET_FILENAME);
+ reader = new BufferedReader(new InputStreamReader(fis));
+ String s = null;
+ int i = 0;
+ while (null != (s = reader.readLine()) && i < NUM_FRIENDS) {
+ mRawFeeds[i] = s;
+ i++;
+ }
+ } catch (FileNotFoundException e) {
+ e.printStackTrace();
+ } catch (IOException e) {
+ e.printStackTrace();
+ } finally {
+ if (null != reader) {
+ try {
+ reader.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+
+ // Simplified log output method
+ private void log(String msg) {
+ try {
+ Thread.sleep(500);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ Log.i(TAG, msg);
+ }
+}
diff --git a/Android/06-Notifications/Notifications/src/course/labs/notificationslab/SelectionListener.java b/Android/06-Notifications/Notifications/src/course/labs/notificationslab/SelectionListener.java
new file mode 100644
index 0000000..87c9dbe
--- /dev/null
+++ b/Android/06-Notifications/Notifications/src/course/labs/notificationslab/SelectionListener.java
@@ -0,0 +1,5 @@
+package course.labs.notificationslab;
+
+public interface SelectionListener {
+ public void onItemSelected(int position);
+}
diff --git a/Android/06-Notifications/Notifications/src/course/labs/notificationslab/TestFrontEndActivity.java b/Android/06-Notifications/Notifications/src/course/labs/notificationslab/TestFrontEndActivity.java
new file mode 100644
index 0000000..72b1a6f
--- /dev/null
+++ b/Android/06-Notifications/Notifications/src/course/labs/notificationslab/TestFrontEndActivity.java
@@ -0,0 +1,114 @@
+package course.labs.notificationslab;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.os.Bundle;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.Button;
+
+public class TestFrontEndActivity extends Activity {
+
+ private final static long DAWN_OF_TIME = 0;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_test_front_end);
+
+ Button ageTweetsButton = (Button) findViewById(R.id.age_tweets_button);
+ ageTweetsButton.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ setFileAge(DAWN_OF_TIME);
+ }
+ });
+
+ Button rejuvTweetsButton = (Button) findViewById(R.id.rejuv_tweets_button);
+ rejuvTweetsButton.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ setFileAge(System.currentTimeMillis());
+ }
+ });
+
+ Button startMainActivityButton = (Button) findViewById(R.id.start_main_button);
+ startMainActivityButton.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ startActivity(new Intent(TestFrontEndActivity.this,
+ MainActivity.class));
+ }
+ });
+ createTweetFileIfMissing();
+ }
+
+ private void createTweetFileIfMissing() {
+
+ String fname = TestFrontEndActivity.this.getFilesDir() + "/" + MainActivity.TWEET_FILENAME;
+
+ File file = new File(fname);
+ if (!file.exists()) {
+
+ PrintWriter out = null;
+ BufferedReader in = null;
+
+ try {
+ out = new PrintWriter(new BufferedWriter(
+ new OutputStreamWriter(openFileOutput(
+ MainActivity.TWEET_FILENAME,
+ Context.MODE_PRIVATE))));
+
+ for (int resId : DownloaderTask.txtFeeds) {
+ in = new BufferedReader(new InputStreamReader(
+ getResources().openRawResource(resId)));
+
+ String line;
+ StringBuffer buffer = new StringBuffer();
+
+ while ((line = in.readLine()) != null) {
+ buffer.append(line);
+ }
+ out.println(buffer);
+ }
+ } catch (FileNotFoundException e) {
+ e.printStackTrace();
+ } catch (Resources.NotFoundException e) {
+ e.printStackTrace();
+ } catch (IOException e) {
+ e.printStackTrace();
+ } finally {
+ try {
+ if (null != in) {
+ in.close();
+ }
+ if (null != out) {
+ out.close();
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+
+ private void setFileAge(long timestamp) {
+ String fname = TestFrontEndActivity.this.getFilesDir() + "/" + MainActivity.TWEET_FILENAME;
+ File file = new File(fname);
+ if (file.exists()) {
+ file.setLastModified(timestamp);
+ }
+ }
+
+}