diff --git a/assignments/week-2-assignment-1/src/edu/vuum/mocca/SimpleAtomicLong.java b/assignments/week-2-assignment-1/src/edu/vuum/mocca/SimpleAtomicLong.java index b8851333a..f57064f95 100644 --- a/assignments/week-2-assignment-1/src/edu/vuum/mocca/SimpleAtomicLong.java +++ b/assignments/week-2-assignment-1/src/edu/vuum/mocca/SimpleAtomicLong.java @@ -1,3 +1,5 @@ +// Import the necessary Java synchronization and scheduling classes. + package edu.vuum.mocca; import java.util.concurrent.locks.ReentrantReadWriteLock; @@ -16,35 +18,27 @@ class SimpleAtomicLong * The value that's manipulated atomically via the methods. */ private long mValue; - + + /** * The ReentrantReadWriteLock used to serialize access to mValue. */ - - // TODO -- you fill in here by replacing the null with an - // initialization of ReentrantReadWriteLock. - private ReentrantReadWriteLock mRWLock = null; + // TODO - add the implementation /** * Creates a new SimpleAtomicLong with the given initial value. */ - public SimpleAtomicLong(long initialValue) - { - // TODO -- you fill in here + public SimpleAtomicLong(long initialValue) { + // TODO - you fill in here } /** - * @brief Gets the current value. + * @brief Gets the current value * * @returns The current value */ - public long get() - { - long value; - - // TODO -- you fill in here - - return value; + public long get() { + // TODO - you fill in here } /** @@ -52,13 +46,8 @@ public long get() * * @returns the updated value */ - public long decrementAndGet() - { - long value = 0; - - // TODO -- you fill in here - - return value; + public long decrementAndGet() { + // TODO - you fill in here } /** @@ -66,13 +55,8 @@ public long decrementAndGet() * * @returns the previous value */ - public long getAndIncrement() - { - long value = 0; - - // TODO -- you fill in here - - return value; + public long getAndIncrement() { + // TODO - you fill in here } /** @@ -80,13 +64,8 @@ public long getAndIncrement() * * @returns the previous value */ - public long getAndDecrement() - { - long value = 0; - - // TODO -- you fill in here - - return value; + public long getAndDecrement() { + // TODO - you fill in here } /** @@ -94,13 +73,8 @@ public long getAndDecrement() * * @returns the updated value */ - public long incrementAndGet() - { - long value = 0; - - // TODO -- you fill in here - - return value; + public long incrementAndGet() { + // TODO - you fill in here } } diff --git a/assignments/week-2-assignment-1/src/edu/vuum/mocca/SimpleAtomicLongMultithreadedTest.java b/assignments/week-2-assignment-1/src/edu/vuum/mocca/SimpleAtomicLongMultithreadedTest.java index 401bcd63f..afde62c6f 100644 --- a/assignments/week-2-assignment-1/src/edu/vuum/mocca/SimpleAtomicLongMultithreadedTest.java +++ b/assignments/week-2-assignment-1/src/edu/vuum/mocca/SimpleAtomicLongMultithreadedTest.java @@ -41,9 +41,11 @@ public class SimpleAtomicLongMultithreadedTest { static CountDownLatch mStopLatch; /** - * An instance of our implementation of SimpleAtomicLong. + * An instance of our implementation of SimpleAtomicLong, which is + * defined as "volatile" to ensure proper visibility of its fields + * after construction. */ - static SimpleAtomicLong mCounter; + static volatile SimpleAtomicLong mCounter; /** * Runnable commands that use the mCounter methods diff --git a/assignments/week-3-assignment-2/Assignment-Description.txt b/assignments/week-3-assignment-2/Assignment-Description.txt index 43ffd7ae4..57c2ddf42 100644 --- a/assignments/week-3-assignment-2/Assignment-Description.txt +++ b/assignments/week-3-assignment-2/Assignment-Description.txt @@ -4,9 +4,9 @@ Released Monday, May 26th, 2014 Due Monday, June 9th, 2014 In this assignment, you will use a Java ReentrantLock and Java -ConditionObject to implement a subset of the Java +Condition to implement a subset of the Java java.util.concurrent.Semaphore class, which we call SimpleSemaphore. -This assignment also reuses the SimpleAtomicLock you implemented for +This assignment also reuses the SimpleAtomicLong you implemented for week-2-assignment-1, so make sure it's compiling and running properly before attempting this assignment! @@ -19,28 +19,31 @@ Palantirs if you're not yet a fan of Tolkein's Lord of the Ring's. The PalantirManagerUnitTest.java program creates three Palantiri and five Threads (one for each Palantir user) that concurrently attempt to acquire a Palantir and gaze into it for a certain amount of time. If -the SimpleSemaphore and SimpleAtomicLock are implemented properly the +the SimpleSemaphore and SimpleAtomicLong are implemented properly the test should succeed without throwing any exceptions, as described further below. In this directory you'll find a number of files, all of which you should read. However, the only two files you need to modify are -SimpleAtomicLong.java and SimpleSemaphore.java, which contains the -skeleton Java code that you'll implement by completing the "TODO - You -fill in here" comments to provide a working solution. DO NOT CHANGE -THE OVERALL STRUCTURE OF THE SKELETON - just fill in the "TODO - You -fill in here" portions!!! +SimpleAtomicLong.java and SimpleSemaphore.java in the +src/edu/vuum/mocca directory, which contains the skeleton Java code +that you'll implement by completing the "TODO - You fill in here" +comments to provide a working solution. DO NOT CHANGE THE OVERALL +STRUCTURE OF THE SKELETON - just fill in the "TODO - You fill in here" +portions!!! In particular, you'll need to do the following: . Implement the SimpleAtomicLong class, which you should replace with your solution to week-2-assignment-1, after applying any fixes - suggested by peer graders. This class is only used by the - PalantirManagerUnitTest.java and should not be used by the - SimpleSemaphore implementation. - -. Implement the SimpleSemaphore class using a Java ConditionObject and - Java ReentrantLock, which are covered in these videos: + motivated by watching the Virtual Office Hours video of the + instructor's solution(s). This class is only used by the + PalantirManagerUnitTest.java and should not be used in the + SimpleSemaphore implementation itself. + +. Implement the SimpleSemaphore class using a Java ConditionObject + (accessed via a Condition) and Java ReentrantLock, which are covered + in these videos: Section 1: Module 2: Part 5: Java ReentrantLock Section 1: Module 2: Part 8: Java ConditionObject @@ -88,7 +91,7 @@ should disappear! Right click on the test suite (AllTests.java) or an individual *_UnitTest.java file in Eclipse and select 'Run As' -> 'JUnit -Test'. When the assignment is complete, 12 of 12 tests should complete +Test'. When the assignment is complete, all the tests should complete successfully. If a test passes a green-check mark will appear next to the test in the JUnit view. As long as this JUnit test "passes" successfully your program will be be consider "correct" for the diff --git a/assignments/week-3-assignment-2/src/edu/vuum/mocca/SimpleAtomicLong.java b/assignments/week-3-assignment-2/src/edu/vuum/mocca/SimpleAtomicLong.java index 37f4d7fb4..f57064f95 100644 --- a/assignments/week-3-assignment-2/src/edu/vuum/mocca/SimpleAtomicLong.java +++ b/assignments/week-3-assignment-2/src/edu/vuum/mocca/SimpleAtomicLong.java @@ -18,32 +18,27 @@ class SimpleAtomicLong * The value that's manipulated atomically via the methods. */ private long mValue; - + + /** * The ReentrantReadWriteLock used to serialize access to mValue. */ - // TODO - replace the null with the appropriate initialization: - private ReentrantReadWriteLock mRWLock = null; + // TODO - add the implementation /** * Creates a new SimpleAtomicLong with the given initial value. */ - public SimpleAtomicLong(long initialValue) - { - long value = 0; + public SimpleAtomicLong(long initialValue) { // TODO - you fill in here } /** - * @brief Gets the current value. + * @brief Gets the current value * * @returns The current value */ - public long get() - { - long value = 0; - // TODO - you fill in here, using a readLock() - return value; + public long get() { + // TODO - you fill in here } /** @@ -51,11 +46,8 @@ public long get() * * @returns the updated value */ - public long decrementAndGet() - { - long value = 0; - // TODO - you fill in here, using a writeLock() - return value; + public long decrementAndGet() { + // TODO - you fill in here } /** @@ -63,11 +55,8 @@ public long decrementAndGet() * * @returns the previous value */ - public long getAndIncrement() - { - long value = 0; - // TODO - you fill in here, using a writeLock() - return value; + public long getAndIncrement() { + // TODO - you fill in here } /** @@ -75,11 +64,8 @@ public long getAndIncrement() * * @returns the previous value */ - public long getAndDecrement() - { - long value = 0; - // TODO - you fill in here, using a writeLock() - return value; + public long getAndDecrement() { + // TODO - you fill in here } /** @@ -87,11 +73,8 @@ public long getAndDecrement() * * @returns the updated value */ - public long incrementAndGet() - { - long value = 0; - // TODO - you fill in here, using a writeLock() - return value; + public long incrementAndGet() { + // TODO - you fill in here } } diff --git a/assignments/week-3-assignment-2/src/edu/vuum/mocca/SimpleSemaphore.java b/assignments/week-3-assignment-2/src/edu/vuum/mocca/SimpleSemaphore.java index a7a6e8df6..a867818ed 100644 --- a/assignments/week-3-assignment-2/src/edu/vuum/mocca/SimpleSemaphore.java +++ b/assignments/week-3-assignment-2/src/edu/vuum/mocca/SimpleSemaphore.java @@ -6,21 +6,21 @@ /** * @class SimpleSemaphore - * + * * @brief This class provides a simple counting semaphore * implementation using Java a ReentrantLock and a - * ConditionObject. It must implement both "Fair" and - * "NonFair" semaphore semantics, just liked Java Semaphores. + * ConditionObject (which is accessed via a Condition). It must + * implement both "Fair" and "NonFair" semaphore semantics, + * just liked Java Semaphores. */ public class SimpleSemaphore { /** - * Define a ReentrantLock to protect the critical section. + * Define a Lock to protect the critical section. */ // TODO - you fill in here /** - * Define a ConditionObject to wait while the number of - * permits is 0. + * Define a Condition that waits while the number of permits is 0. */ // TODO - you fill in here @@ -30,44 +30,41 @@ public class SimpleSemaphore { // TODO - you fill in here. Make sure that this data member will // ensure its values aren't cached by multiple Threads.. - /** - * Constructor initialize the data members. - */ - public SimpleSemaphore (int permits, - boolean fair) - { - // TODO - you fill in here + public SimpleSemaphore(int permits, boolean fair) { + // TODO - you fill in here to initialize the SimpleSemaphore, + // making sure to allow both fair and non-fair Semaphore + // semantics. } /** - * Acquire one permit from the semaphore in a manner that can - * be interrupted. + * Acquire one permit from the semaphore in a manner that can be + * interrupted. */ public void acquire() throws InterruptedException { - // TODO - you fill in here + // TODO - you fill in here. } /** - * Acquire one permit from the semaphore in a manner that - * cannot be interrupted. + * Acquire one permit from the semaphore in a manner that cannot be + * interrupted. */ public void acquireUninterruptibly() { - // TODO - you fill in here + // TODO - you fill in here. } /** * Return one permit to the semaphore. */ - void release() { - // TODO - you fill in here + public void release() { + // TODO - you fill in here. } - + /** * Return the number of permits available. */ - public int availablePermits(){ - // TODO - you fill in here - return 0; // You will change this value. + public int availablePermits() { + // TODO - you fill in here by changing null to the appropriate + // return value. + return null; } } - diff --git a/assignments/week-3-assignment-2/test/edu/vuum/mocca/FairnessChecker.java b/assignments/week-3-assignment-2/test/edu/vuum/mocca/FairnessChecker.java index 264c857e3..2d8e1ff6a 100644 --- a/assignments/week-3-assignment-2/test/edu/vuum/mocca/FairnessChecker.java +++ b/assignments/week-3-assignment-2/test/edu/vuum/mocca/FairnessChecker.java @@ -7,7 +7,10 @@ * @class FairnessChecker * * @brief Class that attempts to check whether the SimpleSemaphore - * implementation is "fair". + * implementation is "fair". It has inherent limitations, but + * to fix these limitations would require obtrusive + * instrumentation within the SimpleSemaphore implementation + * itself. */ public class FairnessChecker { /** @@ -19,7 +22,7 @@ public class FairnessChecker { /** * Initialize the FairnessChecker */ - public FairnessChecker(int totalEntries) { + public FairnessChecker(final int totalEntries) { mEntryList = new ArrayList(totalEntries); } @@ -27,7 +30,7 @@ public FairnessChecker(int totalEntries) { * Add the name of a Thread that's about to acquire the @code * SimpleSemaphore. Assumes that Thread name are unique. */ - public synchronized void addNewThread(String entry) { + public synchronized void addNewThread(final String entry) { mEntryList.add(entry); } @@ -35,7 +38,7 @@ public synchronized void addNewThread(String entry) { * Returns true if the calling Thread's name is the same as the * first item in the list, else false. */ - public synchronized boolean checkOrder(String entry) { + public synchronized boolean checkOrder(final String entry) { String currentEntry = mEntryList.remove(0); return currentEntry.equals(entry); diff --git a/assignments/week-3-assignment-2/test/edu/vuum/mocca/PalantirManager.java b/assignments/week-3-assignment-2/test/edu/vuum/mocca/PalantirManager.java index e74f2eb11..dedf2454a 100644 --- a/assignments/week-3-assignment-2/test/edu/vuum/mocca/PalantirManager.java +++ b/assignments/week-3-assignment-2/test/edu/vuum/mocca/PalantirManager.java @@ -36,7 +36,7 @@ public class PalantirManager { * Create a resource manager for the palantiri passed as a * parameter. */ - PalantirManager(List palantiri) { + PalantirManager(final List palantiri) { mMaxPalantiri = palantiri.size(); mPalantiri = palantiri; used = new boolean[palantiri.size()]; @@ -60,7 +60,7 @@ public Palantir acquirePalantir() { * Returns the designated @code palantir so that it's * available for others to use. */ - public void releasePalantir(Palantir palantir) { + public void releasePalantir(final Palantir palantir) { if (markAsUnused(palantir)) mAvailable.release(); } @@ -83,7 +83,7 @@ protected synchronized Palantir getNextAvailablePalantir() { /** * Return the @code palantir back to the resource pool. */ - protected synchronized boolean markAsUnused(Palantir palantir) { + protected synchronized boolean markAsUnused(final Palantir palantir) { // Linear search is fine for this simple demo. for (int i = 0; i < mMaxPalantiri; ++i) { if (palantir == mPalantiri.get(i)) { diff --git a/assignments/week-3-assignment-2/test/edu/vuum/mocca/PalantirManagerUnitTest.java b/assignments/week-3-assignment-2/test/edu/vuum/mocca/PalantirManagerUnitTest.java index 3a43eac3e..90edc858f 100644 --- a/assignments/week-3-assignment-2/test/edu/vuum/mocca/PalantirManagerUnitTest.java +++ b/assignments/week-3-assignment-2/test/edu/vuum/mocca/PalantirManagerUnitTest.java @@ -1,6 +1,7 @@ package edu.vuum.mocca; import static org.junit.Assert.fail; +import static org.junit.Assert.assertFalse; import java.util.ArrayList; import java.util.List; @@ -8,7 +9,6 @@ import org.junit.Test; - /** * @class PalantirManagerUnitTest * @@ -22,8 +22,8 @@ */ public class PalantirManagerUnitTest { /** - * If this is set to true in SynchronizedQueueImpl.java then lots - * of debugging output will be generated. + * If this is set to true in then lots of debugging output will be + * generated. */ public static boolean diagnosticsEnabled = false; @@ -38,6 +38,11 @@ public class PalantirManagerUnitTest { */ static volatile long mMaxActiveThreads = 0; + /** + * Keep track of whether a runtime exception occurs. + */ + boolean mFailed = false; + /** * Count of the number of Active Threads. */ @@ -131,7 +136,7 @@ public void run() { if (diagnosticsEnabled) System.out.println(Thread.currentThread().getName() - + " is releasing the " + + " has released the " + palantir.name() + " palantir"); } @@ -222,21 +227,44 @@ public void testPalantirManager() { // Start all the Threads that Middle-Earth Beings use to // gaze into the Palantir. for (ListIterator iterator = palantirUsers.listIterator(); - iterator.hasNext();) - iterator.next().start(); + iterator.hasNext(); + ) { + Thread t = iterator.next(); + // Catch runtime exceptions and induce a JUnit test + // failure. + t.setUncaughtExceptionHandler + (new Thread.UncaughtExceptionHandler() { + public void uncaughtException(Thread t, + Throwable e) { + System.out.println(t + + " throws exception: " + + e); + mFailed = true; + } + }); + t.start(); + } // Barrier synchronization that waits for all the Threads // to exit. - for (ListIterator iterator = palantirUsers.listIterator(); iterator - .hasNext();) + for (ListIterator iterator = palantirUsers.listIterator(); + iterator.hasNext(); + ) iterator.next().join(); + // Make sure we haven't failed. + assertFalse(mFailed); + if (diagnosticsEnabled) System.out.println("Finishing PalantirManagerTest"); } catch (Exception e) { - fail("The Exception " + if (diagnosticsEnabled) + System.out.println("A " + + e.getMessage() + + " Exception was thrown"); + fail("A " + e.getMessage() - + " was thrown"); + + " Exception was thrown"); } } diff --git a/assignments/week-3-assignment-2/test/edu/vuum/mocca/SimpleAtomicLongUnitTest.java b/assignments/week-3-assignment-2/test/edu/vuum/mocca/SimpleAtomicLongUnitTest.java index 66d01c104..69895b8ac 100644 --- a/assignments/week-3-assignment-2/test/edu/vuum/mocca/SimpleAtomicLongUnitTest.java +++ b/assignments/week-3-assignment-2/test/edu/vuum/mocca/SimpleAtomicLongUnitTest.java @@ -9,7 +9,7 @@ * @class SimpleAtomicLongUnitTest * * @brief Simple unit test for the SimpleAtomicLong clas that ensures - * the version submitted for this assignment works properly. + * the version submitted for this assignment works correctly. */ public class SimpleAtomicLongUnitTest { @Test diff --git a/assignments/week-4-assignment-3/.classpath b/assignments/week-4-assignment-3/.classpath index 18d70f02c..b0e3db7ba 100644 --- a/assignments/week-4-assignment-3/.classpath +++ b/assignments/week-4-assignment-3/.classpath @@ -1,6 +1,8 @@ + + diff --git a/assignments/week-4-assignment-3/Assignment-Description.txt b/assignments/week-4-assignment-3/Assignment-Description.txt index c6452c2ed..66cb926d8 100644 --- a/assignments/week-4-assignment-3/Assignment-Description.txt +++ b/assignments/week-4-assignment-3/Assignment-Description.txt @@ -1,11 +1,15 @@ -Programming Assignment 1 +Week 4: Programming Assignment 3 + +Released Monday, June 2nd, 2014 +Due Monday, June 16th, 2014 In this assignment, you will implement a Java program that creates two instances of the PlayPingPongThread and then starts these thread instances to correctly alternate printing "Ping" and "Pong", respectively, on the console display. This assignment also reuses the -SimpleSemaphore you implemented for the previous assignment, so make -sure it's working properly before attempting this assignment! +SimpleSemaphore you implemented for the previous assignment, so please +apply any fixes motivated by watching the Virtual Office Hours video +of the instructor's solution(s). In this directory you'll find the PingPongRight.java class, which contains the skeleton Java code that you'll implement by completing @@ -16,7 +20,9 @@ DO NOT CHANGE THE OVERALL STRUCTURE OF THE SKELETON - just fill in the In particular, you'll need to do the following: . Implement the SimpleSemaphore class, which you should replace with - your working solution from the previous assignment. + your working solution from the previous assignment, after applying + any fixes motivated by watching the Virtual Office Hours video of + the instructor's solution(s). . Use your SimpleSemaphore to implement the PlayPingPongThread class and fix the problems with the earlier PingPongWrong solution, which @@ -43,13 +49,19 @@ In particular, you'll need to do the following: Section 1: Module 2: Part 1: Overview of Java Threads (Part 1) Section 1: Module 2: Part 2: Overview of Java Threads (Part 2) -Note, at the moment, all these videos are available in the YouTube -playlist at - -https://www.youtube.com/playlist?list=PLZ9NgFYEMxp4tbiFYip6tDNIEBRUDyPQK +. A more sophisticated example of a concurrent ping-pong program is + is shown in these videos: -When the 2014 POSA MOOC officially starts these videos will be -available at + Section 1: Module 2: Part 10: Java Synchronization and Scheduling Example (Part 1) + Section 1: Module 2: Part 11: Java Synchronization and Scheduling Example (Part 2) + + This programming assignment isn't as sophisticated (e.g., it doesn't + implement a framework and doesn't use as many GoF patterns), but I + suggest you watch these videos to learn more about how binary + semaphores can be used to correctly alternate printing "ping" and + "pong" from two Java Threads. + +These videos are available at https://class.coursera.org/posa-002/lecture @@ -60,7 +72,7 @@ in item #38 at the POSA MOOC FAQ available from http://www.courera.org/course/posa To compile this code you can either use the provided Eclipse project -or go into the src directory and simply type +or go into the src/edu/vuum/mooca directory and simply type % javac PingPongRight.java SimpleSemaphore.java @@ -68,33 +80,45 @@ and to run the resulting class file simply type % java PingPongRight -The correct solution should look exactly like this: +The correct solution when you run PingPongRight should look exactly +like this: Ready...Set...Go! -Ping!(1) -Pong!(1) -Ping!(2) -Pong!(2) -Ping!(3) -Pong!(3) -Ping!(4) -Pong!(4) -Ping!(5) -Pong!(5) -Ping!(6) -Pong!(6) -Ping!(7) -Pong!(7) -Ping!(8) -Pong!(8) -Ping!(9) -Pong!(9) -Ping!(10) -Pong!(10) +Ping! (1) + Pong! (1) +Ping! (2) + Pong! (2) +Ping! (3) + Pong! (3) +Ping! (4) + Pong! (4) +Ping! (5) + Pong! (5) +Ping! (6) + Pong! (6) +Ping! (7) + Pong! (7) +Ping! (8) + Pong! (8) +Ping! (9) + Pong! (9) +Ping! (10) + Pong! (10) Done! - - - - +There is also a Unit Test Suite that will run the PingPongRightTest +file included in the test/edu/vuum/mooca directory for you at. When +you first open the project in Eclipse, you might see compile errors if +JUnit is not included in your build path. To fix these errors, open +SynchronizedQueueTest.java, hover over "org.junit," and click "Fix +project setup." Make sure "Add JUnit 4 library to the build path" is +selected and then click "OK." At this point, the compile errors +should disappear! + +Right click on the PingPongRightTest.java file in Eclipse and select +'Run As' -> 'JUnit Test'. When the assignment is complete, the test +should complete successfully. If the test passes a green-check mark +will appear next to the test in the JUnit view. As long as this JUnit +test "passes" successfully your program will be be consider "correct" +for the purposes of assessing this assignment. diff --git a/assignments/week-4-assignment-3/src/PingPongRight.java b/assignments/week-4-assignment-3/src/PingPongRight.java deleted file mode 100644 index 53b8411d4..000000000 --- a/assignments/week-4-assignment-3/src/PingPongRight.java +++ /dev/null @@ -1,100 +0,0 @@ -// Import the necessary Java synchronization and scheduling classes. - -import java.util.concurrent.CountDownLatch; - -/** - * @class PingPongRight - * - * @brief This class implements a Java program that creates two - * instances of the PlayPingPongThread and start these thread - * instances to correctly alternate printing "Ping" and "Pong", - * respectively, on the console display. - */ -public class PingPongRight { - /** - * Number of iterations to run the test program. - */ - public static int mMaxIterations = 10; - - /** - * Latch that will be decremented each time a thread exits. - */ - public static CountDownLatch latch = null; // TODO - You fill in here - - /** - * @class PlayPingPongThread - * - * @brief This class implements the ping/pong processing algorithm - * using the SimpleSemaphore to alternate printing "ping" - * and "pong" to the console display. - */ - public static class PlayPingPongThread extends Thread - { - /** - * Constructor initializes the data member. - */ - public PlayPingPongThread (/* TODO - You fill in here */) - { - // TODO - You fill in here. - } - - /** - * Main event loop that runs in a separate thread of control - * and performs the ping/pong algorithm using the - * SimpleSemaphores. - */ - public void run () - { - // TODO - You fill in here. - } - - /** - * String to print (either "ping!" or "pong"!) for each - * iteration. - */ - // TODO - You fill in here. - - /** - * The two SimpleSemaphores use to alternate pings and pongs. - */ - // TODO - You fill in here. - } - - /** - * The main() entry point method into PingPongRight program. - */ - public static void main(String[] args) { - try { - // Create the ping and pong SimpleSemaphores that control - // alternation between threads. - - // TODO - You fill in here. - - System.out.println("Ready...Set...Go!"); - - // Create the ping and pong threads, passing in the string - // to print and the appropriate SimpleSemaphores. - PlayPingPongThread ping = - new PlayPingPongThread(/* TODO - You fill in here */); - PlayPingPongThread pong = - new PlayPingPongThread(/* TODO - You fill in here */); - - // Initiate the ping and pong threads, which will call the - // run() hook method. - ping.start(); - pong.start(); - - // Use barrier synchronization to wait for both threads to - // finish. - - // TODO - replace replace the following line with a - // CountDownLatch barrier synchronizer call that waits for - // both threads to finish. - throw new java.lang.InterruptedException(); - } - catch (java.lang.InterruptedException e) - {} - - System.out.println("Done!"); - } -} diff --git a/assignments/week-4-assignment-3/src/SimpleSemaphore.java b/assignments/week-4-assignment-3/src/SimpleSemaphore.java deleted file mode 100644 index d3c534373..000000000 --- a/assignments/week-4-assignment-3/src/SimpleSemaphore.java +++ /dev/null @@ -1,61 +0,0 @@ -import java.util.concurrent.locks.ReentrantLock; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.Condition; - -/** - * @class SimpleSemaphore - * - * @brief This class provides a simple counting semaphore - * implementation using Java a ReentrantLock and a - * ConditionObject. It must implement both "Fair" and - * "NonFair" semaphore semantics, just liked Java Semaphores. - */ -public class SimpleSemaphore { - /** - * Constructor initialize the data members. - */ - public SimpleSemaphore (int permits, - boolean fair) - { - // TODO - you fill in here - } - - /** - * Acquire one permit from the semaphore in a manner that can - * be interrupted. - */ - public void acquire() throws InterruptedException { - // TODO - you fill in here - } - - /** - * Acquire one permit from the semaphore in a manner that - * cannot be interrupted. - */ - public void acquireUninterruptibly() { - // TODO - you fill in here - } - - /** - * Return one permit to the semaphore. - */ - void release() { - // TODO - you fill in here - } - - /** - * Define a ReentrantLock to protect the critical section. - */ - // TODO - you fill in here - - /** - * Define a ConditionObject to wait while the number of - * permits is 0. - */ - // TODO - you fill in here - - /** - * Define a count of the number of available permits. - */ - // TODO - you fill in here -} diff --git a/assignments/week-4-assignment-3/src/edu/vuum/mocca/PingPongRight.java b/assignments/week-4-assignment-3/src/edu/vuum/mocca/PingPongRight.java new file mode 100644 index 000000000..4fd24024f --- /dev/null +++ b/assignments/week-4-assignment-3/src/edu/vuum/mocca/PingPongRight.java @@ -0,0 +1,157 @@ +package edu.vuum.mocca; + +// Import the necessary Java synchronization and scheduling classes. +import java.util.concurrent.CountDownLatch; + +/** + * @class PingPongRight + * + * @brief This class implements a Java program that creates two + * instances of the PlayPingPongThread and start these thread + * instances to correctly alternate printing "Ping" and "Pong", + * respectively, on the console display. + */ +public class PingPongRight { + /** + * Number of iterations to run the test program. + */ + public final static int mMaxIterations = 10; + + /** + * Latch that will be decremented each time a thread exits. + */ + public static CountDownLatch mLatch = null; + + /** + * @class PlayPingPongThread + * + * @brief This class implements the ping/pong processing algorithm + * using the SimpleSemaphore to alternate printing "ping" + * and "pong" to the console display. + */ + public static class PlayPingPongThread extends Thread { + /** + * Constants to distinguish between ping and pong + * SimpleSemaphores, if you choose to use an array of + * SimpleSemaphores. If you don't use this implementation + * feel free to remove these constants. + */ + private final static int FIRST_SEMA = 0; + private final static int SECOND_SEMA = 1; + + /** + * Maximum number of loop iterations. + */ + private int mMaxLoopIterations = 0; + + /** + * String to print (either "ping!" or "pong"!) for each + * iteration. + */ + // TODO - You fill in here. + + /** + * Two SimpleSemaphores use to alternate pings and pongs. You + * can use an array of SimpleSemaphores or just define them as + * two data members. + */ + // TODO - You fill in here. + + /** + * Constructor initializes the data member(s). + */ + public PlayPingPongThread(String stringToPrint, + SimpleSemaphore semaphoreOne, + SimpleSemaphore semaphoreTwo, + int maxIterations) { + // TODO - You fill in here. + } + + /** + * Main event loop that runs in a separate thread of control + * and performs the ping/pong algorithm using the + * SimpleSemaphores. + */ + public void run() { + /** + * This method runs in a separate thread of control and + * implements the core ping/pong algorithm. + */ + + // TODO - You fill in here. + } + + /** + * Method for acquiring the appropriate SimpleSemaphore. + */ + private void acquire() { + // TODO fill in here + } + + /** + * Method for releasing the appropriate SimpleSemaphore. + */ + private void release() { + // TODO fill in here + } + } + + /** + * The method that actually runs the ping/pong program. + */ + public static void process(String startString, + String pingString, + String pongString, + String finishString, + int maxIterations) throws InterruptedException { + + // TODO initialize this by replacing null with the appropriate + // constructor call. + mLatch = null; + + // Create the ping and pong SimpleSemaphores that control + // alternation between threads. + + // TODO - You fill in here, make pingSema start out unlocked. + SimpleSemaphore pingSema = null; + // TODO - You fill in here, make pongSema start out locked. + SimpleSemaphore pongSema = null; + + System.out.println(startString); + + // Create the ping and pong threads, passing in the string to + // print and the appropriate SimpleSemaphores. + PlayPingPongThread ping = new PlayPingPongThread(/* + * TODO - You fill in + * here + */); + PlayPingPongThread pong = new PlayPingPongThread(/* + * TODO - You fill in + * here + */); + + // TODO - Initiate the ping and pong threads, which will call + // the run() hook method. + + // TODO - replace the following line with a barrier + // synchronizer call to mLatch that waits for both threads to + // finish. + throw new java.lang.InterruptedException(); + + System.out.println(finishString); + } + + /** + * The main() entry point method into PingPongRight program. + * + * @throws InterruptedException + */ + public static void main(String[] args) throws InterruptedException { + process("Ready...Set...Go!", + "Ping! ", + " Pong! ", + "Done!", + mMaxIterations); + } +} + diff --git a/assignments/week-4-assignment-3/src/edu/vuum/mocca/SimpleSemaphore.java b/assignments/week-4-assignment-3/src/edu/vuum/mocca/SimpleSemaphore.java new file mode 100644 index 000000000..5e473adf6 --- /dev/null +++ b/assignments/week-4-assignment-3/src/edu/vuum/mocca/SimpleSemaphore.java @@ -0,0 +1,66 @@ +package edu.vuum.mocca; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.ReentrantLock; + +/** + * @class SimpleSemaphore + * + * @brief This class provides a simple counting semaphore implementation using + * Java a ReentrantLock and a ConditionObject (which is accessed via a + * Condition). It must implement both "Fair" and "NonFair" semaphore + * semantics, just liked Java Semaphores. + */ +public class SimpleSemaphore { + /** + * Define a ReentrantLock to protect the critical section. + */ + // TODO - you fill in here + + /** + * Define a Condition that waits while the number of permits is 0. + */ + // TODO - you fill in here + + /** + * Define a count of the number of available permits. + */ + // TODO - you fill in here. Make sure that this data member will + // ensure its values aren't cached by multiple Threads.. + + public SimpleSemaphore(int permits, boolean fair) { + // TODO - you fill in here to initialize the SimpleSemaphore, + // making sure to allow both fair and non-fair Semaphore + // semantics. + } + + /** + * Acquire one permit from the semaphore in a manner that can be + * interrupted. + */ + public void acquire() throws InterruptedException { + // TODO - you fill in here. + } + + /** + * Acquire one permit from the semaphore in a manner that cannot be + * interrupted. + */ + public void acquireUninterruptibly() { + // TODO - you fill in here. + } + + /** + * Return one permit to the semaphore. + */ + void release() { + // TODO - you fill in here. + } + + /** + * Return the number of permits available. + */ + public int availablePermits() { + // TODO - you fill in here to return the correct result + return 0; + } +} diff --git a/assignments/week-4-assignment-3/test/edu/vuum/mocca/PingPongRightTest.java b/assignments/week-4-assignment-3/test/edu/vuum/mocca/PingPongRightTest.java new file mode 100644 index 000000000..5148fba59 --- /dev/null +++ b/assignments/week-4-assignment-3/test/edu/vuum/mocca/PingPongRightTest.java @@ -0,0 +1,100 @@ +package edu.vuum.mocca; + +import static org.junit.Assert.fail; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +/** + * @class PingPongRightTest + * + * @brief This JUnit test checks the PingPong program to make sure it's working + * properly. + */ +public class PingPongRightTest { + /* + * These data members are used to capture [ + * System.out.println() ] for testing. + */ + private final ByteArrayOutputStream outContent = + new ByteArrayOutputStream(); + private final ByteArrayOutputStream errContent = + new ByteArrayOutputStream(); + + /* + * Setup the output Capturing. + */ + @Before + public void setUpStreams() { + System.setOut(new PrintStream(outContent)); + System.setErr(new PrintStream(errContent)); + } + + /* + * Tear-down the output Capturing. + */ + @After + public void cleanUpStreams() { + System.setOut(null); + System.setErr(null); + } + + /* + * Test the process(...) logic/accuracy + * + * Gives some helpful error outputs for some simple error states. + */ + @Test(timeout = 3000) + // This test will only run for 3000ms => 3 seconds, otherwise if fails + public void test() throws InterruptedException, IOException { + for (int i = 0; i < 10; i++) { + PingPongRight.process("start", "a", "b", "end", 10); + String outResults = outContent.toString(); + + if (outResults == null || outResults.length() == 0) { + fail("No output at all."); + } + + //We need to split things up for Windows and UNIX due to + //differences in the way that newlines are handled. + boolean windowsTrue = outResults.equals(testResultWindows); + boolean unixTrue = outResults.equals(testResultUnix); + boolean pingAllFirstTrue = outResults.equals(pingAllFirst); + boolean pongAllFirstTrue = outResults.equals(pongAllFirst); + + if (errContent.toString().length() != 0) + fail("There was error text."); + + if (pingAllFirstTrue) + fail("Ping Thread completed before Pong started."); + + if (pongAllFirstTrue) + fail("Pong Thread completed before Ping started."); + + if (!(windowsTrue || unixTrue)) + fail("Output was wrong.\n" + + "--- Received output ---\n" + + outResults + + "--- Expected output ---\n" + + testResultWindows); + + outContent.reset(); + } + } + + // This is what should be output \n was replaced for visible + // endlines for inclusion into single line. + String testResultUnix = + "start\na(1)\nb(1)\na(2)\nb(2)\na(3)\nb(3)\na(4)\nb(4)\na(5)\nb(5)\na(6)\nb(6)\na(7)\nb(7)\na(8)\nb(8)\na(9)\nb(9)\na(10)\nb(10)\nend\n"; + String testResultWindows = + "start\r\na(1)\r\nb(1)\r\na(2)\r\nb(2)\r\na(3)\r\nb(3)\r\na(4)\r\nb(4)\r\na(5)\r\nb(5)\r\na(6)\r\nb(6)\r\na(7)\r\nb(7)\r\na(8)\r\nb(8)\r\na(9)\r\nb(9)\r\na(10)\r\nb(10)\r\nend\r\n"; + String pingAllFirst = + "start\r\na(1)\r\nb(1)\r\na(2)\r\na(3)\r\na(4)\r\na(5)\r\na(6)\r\na(7)\r\na(8)\r\na(9)\r\na(10)\r\nb(2)\r\nb(3)\r\nb(4)\r\nb(5)\r\nb(6)\r\nb(8)\r\nb(7)\r\nb(9)\r\nb(10)\r\nend\r\n"; + String pongAllFirst = + "start\r\nb(1)\r\nb(2)\r\nb(3)\r\nb(4)\r\nb(5)\r\nb(6)\r\nb(8)\r\nb(7)\r\nb(9)\r\nb(10)\r\na(1)\r\na(2)\r\na(3)\r\na(4)\r\na(5)\r\na(6)\r\na(7)\r\na(8)\r\na(9)\r\na(10)\r\nend\r\n"; +} diff --git a/assignments/week-5-assignment-4/Assignment-Description.txt b/assignments/week-5-assignment-4/Assignment-Description.txt index cad036f73..066243159 100644 --- a/assignments/week-5-assignment-4/Assignment-Description.txt +++ b/assignments/week-5-assignment-4/Assignment-Description.txt @@ -1,21 +1,28 @@ -Programming Assignment 4 +Week 5: Programming Assignment 4 + +Released Monday, June 9th, 2014 +Due Monday, June 23rd, 2014 In this assignment, you will implement a program that uses a -pattern-oriented framework to spawn threads that correctly alternate -printing "Ping" and "Pong", respectively on either the command-line -display (of the Eclipse IDE) or in an Android TextView (in either the -AVD emulator or on an actual Android device). In this directory -you'll find Java source code, AndroidManifest.xml, and associated XML -metadata files. The src/edu/vuum/mocca/ directory contains the -skeleton Java code that you'll implement by completing the "TODO - You -fill in here" comments to provide a working solution. DO NOT CHANGE -THE OVERALL STRUCTURE OF THE SKELETON - just fill in the "TODO - You -fill in here" portions!!! - -In particular, you'll need to do the following: - -. Read & understand the PingPongThreadSema PingPongThreadCond classes, - which are covered in these videos: +pattern-oriented ping-pong framework to spawn threads that correctly +alternate printing "Ping" and "Pong", respectively on either the +command-line display (of the Eclipse IDE) or in an Android TextView +(in either the AVD emulator or on an actual Android device). + +In this directory you'll find Java source code, AndroidManifest.xml, +and associated XML metadata files. The directory +W5-A4-Android/src/edu/vuum/mocca/ contains the skeleton Java code that +you'll implement by completing the "TODO - You fill in here" comments +to provide a working solution. DO NOT CHANGE THE OVERALL STRUCTURE OF +THE SKELETON - just fill in the "TODO - You fill in here" portions!!! + +Although there are a lot of files, the actual amount of code you need +to write is small - the main goal is to understand the +pattern-oriented ping-pong framework and how to apply the Android +HaMeR framework. In particular, you'll need to do the following: + +. Read & understand the PingPongThreadSema and PingPongThreadCond + classes, which are covered in these videos: Section 1: Module 2: Part 10: Java Synchronization and Schedule Example @@ -29,8 +36,8 @@ In particular, you'll need to do the following: . Implement the hook methods in the AndroidPlatformStrategy.java class that use a Java CountDownLatch and Activity's runOnUiThread() method - to post a Runnable command to the UI Thread, which are covered - in these videos: + to post a Runnable command to the UI Thread, which are covered in + these videos: Section 1: Module 2: Part 9: Java CountDownLatch Section 1: Module 2: Part 10: Java Synchronization and Scheduling Example @@ -44,13 +51,7 @@ In particular, you'll need to do the following: Section 1: Module 3: Part 3: Overview of Android Handler Section 1: Module 3: Part 4: Posting and Processing Runnables to Android Handler -Note, at the moment, all these videos are available in the YouTube -playlist at - -https://www.youtube.com/playlist?list=PLZ9NgFYEMxp4tbiFYip6tDNIEBRUDyPQK - -When the 2014 POSA MOOC officially starts these videos will be -available at +These videos are available at https://class.coursera.org/posa-002/lecture @@ -61,32 +62,43 @@ in item #38 at the POSA MOOC FAQ available from http://www.courera.org/course/posa You'll need to build this Android application in the Eclipse ADT -environment. The correct solution should look like this (for both the -Eclipse command-line and Android versions): +environment. By default, the output for the correct solution should +look similar to this (for both the Eclipse command-line and Android +versions): Ready...Set...Go! -Ping!(1) -Pong!(1) -Ping!(2) -Pong!(2) -Ping!(3) -Pong!(3) -Ping!(4) -Pong!(4) -Ping!(5) -Pong!(5) -Ping!(6) -Pong!(6) -Ping!(7) -Pong!(7) -Ping!(8) -Pong!(8) -Ping!(9) -Pong!(9) -Ping!(10) -Pong!(10) +ping (1) +_pong (1) +ping (2) +_pong (2) +ping (3) +_pong (3) +ping (4) +_pong (4) +ping (5) +_pong (5) +ping (6) +_pong (6) +ping (7) +_pong (7) +ping (8) +_pong (8) +ping (9) +_pong (9) +ping (10) +_pong (10) Done! +However, this assignment only requires you to create and test the +Android version. BTW, the test assumes that each line of text is +formatted: + '\n' + +To Run the Android Application, right click on the 'W5-A4-Android' +project and select [Run As] -> [Android Application] + +To Run the Android Unit Test, right click on the 'W5-A4-Android-Test' +project and select [Run As] -> [Android Unit Test] + diff --git a/assignments/week-5-assignment-4/W5-A4-Android-Test/.classpath b/assignments/week-5-assignment-4/W5-A4-Android-Test/.classpath new file mode 100644 index 000000000..2bf50ad70 --- /dev/null +++ b/assignments/week-5-assignment-4/W5-A4-Android-Test/.classpath @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/assignments/week-5-assignment-4/W5-A4-Android-Test/.project b/assignments/week-5-assignment-4/W5-A4-Android-Test/.project new file mode 100644 index 000000000..3f10b9d9c --- /dev/null +++ b/assignments/week-5-assignment-4/W5-A4-Android-Test/.project @@ -0,0 +1,33 @@ + + + W5-A4-Android-Test + + + + + + com.android.ide.eclipse.adt.ResourceManagerBuilder + + + + + com.android.ide.eclipse.adt.PreCompilerBuilder + + + + + org.eclipse.jdt.core.javabuilder + + + + + com.android.ide.eclipse.adt.ApkBuilder + + + + + + com.android.ide.eclipse.adt.AndroidNature + org.eclipse.jdt.core.javanature + + diff --git a/assignments/week-5-assignment-4/W5-A4-Android-Test/AndroidManifest.xml b/assignments/week-5-assignment-4/W5-A4-Android-Test/AndroidManifest.xml new file mode 100644 index 000000000..a226ce2e0 --- /dev/null +++ b/assignments/week-5-assignment-4/W5-A4-Android-Test/AndroidManifest.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + diff --git a/assignments/week-5-assignment-4/libs/android-support-v4.jar b/assignments/week-5-assignment-4/W5-A4-Android-Test/libs/android-support-v4.jar similarity index 63% rename from assignments/week-5-assignment-4/libs/android-support-v4.jar rename to assignments/week-5-assignment-4/W5-A4-Android-Test/libs/android-support-v4.jar index 96644edbe..9056828a0 100644 Binary files a/assignments/week-5-assignment-4/libs/android-support-v4.jar and b/assignments/week-5-assignment-4/W5-A4-Android-Test/libs/android-support-v4.jar differ diff --git a/assignments/week-5-assignment-4/W5-A4-Android-Test/libs/robotium-solo-5.1.jar b/assignments/week-5-assignment-4/W5-A4-Android-Test/libs/robotium-solo-5.1.jar new file mode 100644 index 000000000..1931dd97f Binary files /dev/null and b/assignments/week-5-assignment-4/W5-A4-Android-Test/libs/robotium-solo-5.1.jar differ diff --git a/assignments/week-5-assignment-4/proguard-project.txt b/assignments/week-5-assignment-4/W5-A4-Android-Test/proguard-project.txt similarity index 100% rename from assignments/week-5-assignment-4/proguard-project.txt rename to assignments/week-5-assignment-4/W5-A4-Android-Test/proguard-project.txt diff --git a/assignments/week-5-assignment-4/project.properties b/assignments/week-5-assignment-4/W5-A4-Android-Test/project.properties similarity index 96% rename from assignments/week-5-assignment-4/project.properties rename to assignments/week-5-assignment-4/W5-A4-Android-Test/project.properties index 4ab125693..a3ee5ab64 100644 --- a/assignments/week-5-assignment-4/project.properties +++ b/assignments/week-5-assignment-4/W5-A4-Android-Test/project.properties @@ -11,4 +11,4 @@ #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt # Project target. -target=android-19 +target=android-17 diff --git a/assignments/week-5-assignment-4/W5-A4-Android-Test/res/drawable-hdpi/ic_launcher.png b/assignments/week-5-assignment-4/W5-A4-Android-Test/res/drawable-hdpi/ic_launcher.png new file mode 100644 index 000000000..96a442e5b Binary files /dev/null and b/assignments/week-5-assignment-4/W5-A4-Android-Test/res/drawable-hdpi/ic_launcher.png differ diff --git a/assignments/week-5-assignment-4/W5-A4-Android-Test/res/drawable-mdpi/ic_launcher.png b/assignments/week-5-assignment-4/W5-A4-Android-Test/res/drawable-mdpi/ic_launcher.png new file mode 100644 index 000000000..359047dfa Binary files /dev/null and b/assignments/week-5-assignment-4/W5-A4-Android-Test/res/drawable-mdpi/ic_launcher.png differ diff --git a/assignments/week-5-assignment-4/W5-A4-Android-Test/res/drawable-xhdpi/ic_launcher.png b/assignments/week-5-assignment-4/W5-A4-Android-Test/res/drawable-xhdpi/ic_launcher.png new file mode 100644 index 000000000..71c6d760f Binary files /dev/null and b/assignments/week-5-assignment-4/W5-A4-Android-Test/res/drawable-xhdpi/ic_launcher.png differ diff --git a/assignments/week-5-assignment-4/res/values-v11/styles.xml b/assignments/week-5-assignment-4/W5-A4-Android-Test/res/values-v11/styles.xml similarity index 100% rename from assignments/week-5-assignment-4/res/values-v11/styles.xml rename to assignments/week-5-assignment-4/W5-A4-Android-Test/res/values-v11/styles.xml diff --git a/assignments/week-5-assignment-4/res/values-v14/styles.xml b/assignments/week-5-assignment-4/W5-A4-Android-Test/res/values-v14/styles.xml similarity index 100% rename from assignments/week-5-assignment-4/res/values-v14/styles.xml rename to assignments/week-5-assignment-4/W5-A4-Android-Test/res/values-v14/styles.xml diff --git a/assignments/week-5-assignment-4/W5-A4-Android-Test/res/values/strings.xml b/assignments/week-5-assignment-4/W5-A4-Android-Test/res/values/strings.xml new file mode 100644 index 000000000..1711cecf9 --- /dev/null +++ b/assignments/week-5-assignment-4/W5-A4-Android-Test/res/values/strings.xml @@ -0,0 +1,5 @@ + + + W5-A4-Android-Test + + diff --git a/assignments/week-5-assignment-4/res/values/styles.xml b/assignments/week-5-assignment-4/W5-A4-Android-Test/res/values/styles.xml similarity index 100% rename from assignments/week-5-assignment-4/res/values/styles.xml rename to assignments/week-5-assignment-4/W5-A4-Android-Test/res/values/styles.xml diff --git a/assignments/week-5-assignment-4/W5-A4-Android-Test/src/edu/vuum/mocca/test/PingPongActivityTest.java b/assignments/week-5-assignment-4/W5-A4-Android-Test/src/edu/vuum/mocca/test/PingPongActivityTest.java new file mode 100644 index 000000000..1107c3cd7 --- /dev/null +++ b/assignments/week-5-assignment-4/W5-A4-Android-Test/src/edu/vuum/mocca/test/PingPongActivityTest.java @@ -0,0 +1,81 @@ +package edu.vuum.mocca.test; + +import android.content.Context; +import android.test.ActivityInstrumentationTestCase2; +import android.widget.Button; +import android.widget.TextView; + +import com.robotium.solo.Solo; + +import edu.vuum.mocca.PingPongActivity; + +/** + * @class PingPongActivityTest + * + * @brief Implements a Robotium test for the PingPongActivity. + */ +public class PingPongActivityTest + extends ActivityInstrumentationTestCase2 { + /** + * Constructor initializes the superclass. + */ + public PingPongActivityTest() { + super(PingPongActivity.class); + } + + /** + * This is the handle for Robotium, which allows us to interact + * with the UI. + */ + Solo mSolo; + + /** + * The context of this project, not the target project. + */ + Context mContext; + + Button playButton_; + TextView outputTextView_; + + /** + * Called before each test is run to perform the initialization. + */ + public void setUp() throws Exception { + super.setUp(); + + // Setup Robotium and get the EditText View. + mSolo = new Solo(getInstrumentation(), getActivity()); + + mContext = getInstrumentation().getContext(); + + playButton_ = (Button) mSolo.getView(edu.vuum.mocca.R.id.play_button); + + outputTextView_ = (TextView) mSolo + .getView(edu.vuum.mocca.R.id.pingpong_output); + + getInstrumentation().callActivityOnStart(getActivity()); + getInstrumentation().callActivityOnResume(getActivity()); + } + + /** + * No need for @Test because of use of + * ActivityInstrumentationTestCase2 which makes each method in + * this class a @Test method TODO find better explanation, 100% + * proper. + */ + public void testPlayPingPongButtonPress() throws Exception { + Thread.sleep(TestOptions.ACCEPTABLE_STARTUP_LENGTH); + + // Asserttrue(outputTextView_.isAttachedToWindow() == true); + assertTrue(outputTextView_.getText().length() == 0); + + // Click on the 'play' button + mSolo.clickOnView(mSolo.getView(edu.vuum.mocca.R.id.play_button)); + + // wait for the threads to execute + Thread.sleep(TestOptions.ACCEPTABLE_RUNTIME_LENGTH); + + assertTrue(outputTextView_.getText().toString() + .equals(TestOptions.ANDROID_TEXTVIEW)); + } +} diff --git a/assignments/week-5-assignment-4/W5-A4-Android-Test/src/edu/vuum/mocca/test/TestOptions.java b/assignments/week-5-assignment-4/W5-A4-Android-Test/src/edu/vuum/mocca/test/TestOptions.java new file mode 100644 index 000000000..fb1fb4c55 --- /dev/null +++ b/assignments/week-5-assignment-4/W5-A4-Android-Test/src/edu/vuum/mocca/test/TestOptions.java @@ -0,0 +1,38 @@ +package edu.vuum.mocca.test; + +/** + * @class Options + * + * @brief Holds global constants for the testing suite. More convenient than + * grabbing resources from /res and trying to finagle a working Context + * out of the test classes every time we want to use TEST_URI. + * + */ +public class TestOptions { + /** + * Time we should wait for things to run. + */ + static final long ACCEPTABLE_STARTUP_LENGTH = 1000; + + /** + * Time we should wait for things to run. + */ + static final long ACCEPTABLE_RUNTIME_LENGTH = 2000; + + /** + * Time we should wait for things to download. + */ + static final long LONG_WAIT_TIME = 5000; + + /** + * Various test strings. + */ + static final String JAVA_CONSOLE_UNIX = "Ready...Set...Go!\nping (1)\n_pong (1)\nping (2)\n_pong (2)\nping (3)\n_pong (3)\nping (4)\n_pong (4)\nping (5)\n_pong (5)\nping (6)\n_pong (6)\nping (7)\n_pong (7)\nping (8)\n_pong (8)\nping (9)\n_pong (9)\nping (10)\n_pong (10)\nDone!\n"; + static final String PING_ALL_FIRST_UNIX = "Ready...Set...Go!\nping (1)\nping (2)\nping (3)\nping (4)\nping (5)\nping (6)\nping (7)\nping (8)\nping (9)\nping (10)\n_pong (1)\n_pong (2)\n_pong (3)\n_pong (4)\n_pong (5)\n_pong (6)\n_pong (7)\n_pong (8)\n_pong (9)\n_pong (10)\nDone!\n"; + static final String PING_ALL_FIRST_WINDOWS = "Ready...Set...Go!\r\nping (1)\r\nping (2)\r\nping (3)\r\nping (4)\r\nping (5)\r\nping (6)\r\nping (7)\r\nping (8)\r\nping (9)\r\nping (10)\r\n_pong (1)\r\n_pong (2)\r\n_pong (3)\r\n_pong (4)\r\n_pong (5)\r\n_pong (6)\r\n_pong (7)\r\n_pong (8)\r\n_pong (9)\r\n_pong (10)\r\nDone!\r\n"; + static final String PONG_ALL_FIRST_WINDOWS = "Ready...Set...Go!\r\n_pong (1)\r\n_pong (2)\r\n_pong (3)\r\n_pong (4)\r\n_pong (5)\r\n_pong (6)\r\n_pong (7)\r\n_pong (8)\r\n_pong (9)\r\n_pong (10)\r\nping (1)\r\nping (2)\r\nping (3)\r\nping (4)\r\nping (5)\r\nping (6)\r\nping (7)\r\nping (8)\r\nping (9)\r\nping (10)\r\nDone!"; + static final String PONG_ALL_FIRST_UNIX = "Ready...Set...Go!\n_pong (1)\n_pong (2)\n_pong (3)\n_pong (4)\n_pong (5)\n_pong (6)\n_pong (7)\n_pong (8)\n_pong (9)\n_pong (10)\nping (1)\nping (2)\nping (3)\nping (4)\nping (5)\nping (6)\nping (7)\nping (8)\nping (9)\nping (10)\nDone!"; + static final String JAVA_CONSOLE_WINDOWS = "Ready...Set...Go!\r\nping (1)\r\n_pong (1)\r\nping (2)\r\n_pong (2)\r\nping (3)\r\n_pong (3)\r\nping (4)\r\n_pong (4)\r\nping (5)\r\n_pong (5)\r\nping (6)\r\n_pong (6)\r\nping (7)\r\n_pong (7)\r\nping (8)\r\n_pong (8)\r\nping (9)\r\n_pong (9)\r\nping (10)\r\n_pong (10)\r\nDone!"; + static final String ANDROID_TEXTVIEW = "Ready...Set...Go!\nping (1)\n_pong (1)\nping (2)\n_pong (2)\nping (3)\n_pong (3)\nping (4)\n_pong (4)\nping (5)\n_pong (5)\nping (6)\n_pong (6)\nping (7)\n_pong (7)\nping (8)\n_pong (8)\nping (9)\n_pong (9)\nping (10)\n_pong (10)\nDone!\n"; + +} diff --git a/assignments/week-5-assignment-4/W5-A4-Android/.classpath b/assignments/week-5-assignment-4/W5-A4-Android/.classpath new file mode 100644 index 000000000..51769745b --- /dev/null +++ b/assignments/week-5-assignment-4/W5-A4-Android/.classpath @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/assignments/week-5-assignment-4/W5-A4-Android/.project b/assignments/week-5-assignment-4/W5-A4-Android/.project new file mode 100644 index 000000000..5aad4ab5c --- /dev/null +++ b/assignments/week-5-assignment-4/W5-A4-Android/.project @@ -0,0 +1,33 @@ + + + W5-A4-Android + + + + + + com.android.ide.eclipse.adt.ResourceManagerBuilder + + + + + com.android.ide.eclipse.adt.PreCompilerBuilder + + + + + org.eclipse.jdt.core.javabuilder + + + + + com.android.ide.eclipse.adt.ApkBuilder + + + + + + com.android.ide.eclipse.adt.AndroidNature + org.eclipse.jdt.core.javanature + + diff --git a/assignments/week-5-assignment-4/AndroidManifest.xml b/assignments/week-5-assignment-4/W5-A4-Android/AndroidManifest.xml similarity index 86% rename from assignments/week-5-assignment-4/AndroidManifest.xml rename to assignments/week-5-assignment-4/W5-A4-Android/AndroidManifest.xml index b7a50564e..949fedabf 100644 --- a/assignments/week-5-assignment-4/AndroidManifest.xml +++ b/assignments/week-5-assignment-4/W5-A4-Android/AndroidManifest.xml @@ -1,12 +1,11 @@ - + android:minSdkVersion="14" + android:targetSdkVersion="19" /> + + + + + diff --git a/assignments/week-5-assignment-4/W5-A4-Android/res/values-v14/styles.xml b/assignments/week-5-assignment-4/W5-A4-Android/res/values-v14/styles.xml new file mode 100644 index 000000000..a91fd0372 --- /dev/null +++ b/assignments/week-5-assignment-4/W5-A4-Android/res/values-v14/styles.xml @@ -0,0 +1,12 @@ + + + + + + diff --git a/assignments/week-5-assignment-4/res/values/dimens.xml b/assignments/week-5-assignment-4/W5-A4-Android/res/values/dimens.xml similarity index 100% rename from assignments/week-5-assignment-4/res/values/dimens.xml rename to assignments/week-5-assignment-4/W5-A4-Android/res/values/dimens.xml diff --git a/assignments/week-5-assignment-4/res/values/strings.xml b/assignments/week-5-assignment-4/W5-A4-Android/res/values/strings.xml similarity index 71% rename from assignments/week-5-assignment-4/res/values/strings.xml rename to assignments/week-5-assignment-4/W5-A4-Android/res/values/strings.xml index 0beb6a933..cd5196b9a 100644 --- a/assignments/week-5-assignment-4/res/values/strings.xml +++ b/assignments/week-5-assignment-4/W5-A4-Android/res/values/strings.xml @@ -1,8 +1,9 @@ - - PingPongFinal + + PlayPingPong Settings Play PingPong! Reset Game + diff --git a/assignments/week-5-assignment-4/W5-A4-Android/res/values/styles.xml b/assignments/week-5-assignment-4/W5-A4-Android/res/values/styles.xml new file mode 100644 index 000000000..6ce89c7ba --- /dev/null +++ b/assignments/week-5-assignment-4/W5-A4-Android/res/values/styles.xml @@ -0,0 +1,20 @@ + + + + + + + + + diff --git a/assignments/week-5-assignment-4/src/edu/vuum/mocca/AndroidPlatformStrategy.java b/assignments/week-5-assignment-4/W5-A4-Android/src/edu/vuum/mocca/AndroidPlatformStrategy.java similarity index 91% rename from assignments/week-5-assignment-4/src/edu/vuum/mocca/AndroidPlatformStrategy.java rename to assignments/week-5-assignment-4/W5-A4-Android/src/edu/vuum/mocca/AndroidPlatformStrategy.java index 83dc2a05d..bc684b5ce 100644 --- a/assignments/week-5-assignment-4/src/edu/vuum/mocca/AndroidPlatformStrategy.java +++ b/assignments/week-5-assignment-4/W5-A4-Android/src/edu/vuum/mocca/AndroidPlatformStrategy.java @@ -45,7 +45,7 @@ public AndroidPlatformStrategy(Object output, /** Do any initialization needed to start a new game. */ public void begin() { - /** Reset the CountDownLatch. */ + /** (Re)initialize the CountDownLatch. */ // TODO - You fill in here. } @@ -71,12 +71,6 @@ public void awaitDone() // TODO - You fill in here. } - /** Returns the platform name in a String. */ - public String platformName() - { - return System.getProperty("java.specification.vendor"); - } - /** * Error log formats the message and displays it for the * debugging purposes. @@ -86,4 +80,3 @@ public void errorLog(String javaFile, String errorMessage) Log.e(javaFile, errorMessage); } } - diff --git a/assignments/week-5-assignment-4/src/edu/vuum/mocca/ConsolePlatformStrategy.java b/assignments/week-5-assignment-4/W5-A4-Android/src/edu/vuum/mocca/ConsolePlatformStrategy.java similarity index 78% rename from assignments/week-5-assignment-4/src/edu/vuum/mocca/ConsolePlatformStrategy.java rename to assignments/week-5-assignment-4/W5-A4-Android/src/edu/vuum/mocca/ConsolePlatformStrategy.java index c67f981ca..c83233f16 100644 --- a/assignments/week-5-assignment-4/src/edu/vuum/mocca/ConsolePlatformStrategy.java +++ b/assignments/week-5-assignment-4/W5-A4-Android/src/edu/vuum/mocca/ConsolePlatformStrategy.java @@ -17,13 +17,13 @@ public class ConsolePlatformStrategy extends PlatformStrategy * Latch to decrement each time a thread exits to control when the * play() method returns. */ - private static CountDownLatch mLatch = new CountDownLatch(2); + private static CountDownLatch mLatch = null; /** Contains information for outputting to console window. */ PrintStream mOutput; /** Ctor. */ - ConsolePlatformStrategy(Object output) + public ConsolePlatformStrategy(Object output) { mOutput = (PrintStream) output; } @@ -31,14 +31,14 @@ public class ConsolePlatformStrategy extends PlatformStrategy /** Do any initialization needed to start a new game. */ public void begin() { - mLatch = new CountDownLatch(2); + mLatch = new CountDownLatch(NUMBER_OF_THREADS); } /** Print the outputString to the display. */ public void print(String outputString) { /** Print to the console window. */ - System.out.println(outputString); + mOutput.println(outputString); } /** Indicate that a game thread has finished running. */ @@ -56,18 +56,13 @@ public void awaitDone() } } - /** Returns a string revealing the platform in use. */ - public String platformName() - { - return System.getProperty("java.specification.vendor"); - } - /** * Error log formats the message and displays it for the debugging * purposes. */ public void errorLog(String javaFile, String errorMessage) { - System.out.println(javaFile + " " + errorMessage); + mOutput.println(javaFile + " " + errorMessage); } } + diff --git a/assignments/week-5-assignment-4/src/edu/vuum/mocca/Main.java b/assignments/week-5-assignment-4/W5-A4-Android/src/edu/vuum/mocca/Main.java similarity index 100% rename from assignments/week-5-assignment-4/src/edu/vuum/mocca/Main.java rename to assignments/week-5-assignment-4/W5-A4-Android/src/edu/vuum/mocca/Main.java diff --git a/assignments/week-5-assignment-4/src/edu/vuum/mocca/Options.java b/assignments/week-5-assignment-4/W5-A4-Android/src/edu/vuum/mocca/Options.java similarity index 79% rename from assignments/week-5-assignment-4/src/edu/vuum/mocca/Options.java rename to assignments/week-5-assignment-4/W5-A4-Android/src/edu/vuum/mocca/Options.java index 11d85015f..f07a88350 100644 --- a/assignments/week-5-assignment-4/src/edu/vuum/mocca/Options.java +++ b/assignments/week-5-assignment-4/W5-A4-Android/src/edu/vuum/mocca/Options.java @@ -1,9 +1,5 @@ package edu.vuum.mocca; -import java.io.File; -import java.nio.*; -import java.util.*; - /** * @class Options * @@ -62,18 +58,20 @@ public String syncMechanism() */ public boolean parseArgs(String argv[]) { - for (int argc = 0; argc < argv.length; argc += 2) - if (argv[argc].equals("-i")) - mMaxIterations = Integer.parseInt(argv[argc + 1]); - else if (argv[argc].equals("-s")) - mSyncMechanism = argv[argc + 1]; - else if (argv[argc].equals("-t")) - mMaxTurns = Integer.parseInt(argv[argc + 1]); - else - { - printUsage(); - return false; - } + if (argv != null) { + for (int argc = 0; argc < argv.length; argc += 2) + if (argv[argc].equals("-i")) + mMaxIterations = Integer.parseInt(argv[argc + 1]); + else if (argv[argc].equals("-s")) + mSyncMechanism = argv[argc + 1]; + else if (argv[argc].equals("-t")) + mMaxTurns = Integer.parseInt(argv[argc + 1]); + else + { + printUsage(); + return false; + } + } return true; } diff --git a/assignments/week-5-assignment-4/W5-A4-Android/src/edu/vuum/mocca/PingPongActivity.java b/assignments/week-5-assignment-4/W5-A4-Android/src/edu/vuum/mocca/PingPongActivity.java new file mode 100644 index 000000000..3d283d399 --- /dev/null +++ b/assignments/week-5-assignment-4/W5-A4-Android/src/edu/vuum/mocca/PingPongActivity.java @@ -0,0 +1,76 @@ +package edu.vuum.mocca; + +import android.app.Activity; +import android.os.Bundle; +import android.view.View; +import android.widget.Button; +import android.widget.TextView; + +/** + * @class MainActivity + * + * @brief Initial start up screen for the android GUI. + */ +public class PingPongActivity extends Activity { + /** TextView that PingPong will be "played" upon */ + private TextView mAndroidPingPongOutput; + + /** Button that allows playing and resetting of the game */ + private Button mPlayButton; + + /** Variables to track state of the game */ + private static int PLAY = 0; + private static int RESET = 1; + private int mGameState = PLAY; + + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + // Sets the content view to the xml file, activity_ping_pong. + setContentView(R.layout.activity_ping_pong); + mAndroidPingPongOutput = + (TextView) findViewById(R.id.pingpong_output); + mPlayButton = (Button) findViewById(R.id.play_button); + + // Initializes the Platform singleton with the appropriate + // Platform strategy, which in this case will be the + // AndroidPlatform. + PlatformStrategy.instance + (new PlatformStrategyFactory + (mAndroidPingPongOutput, + this).makePlatformStrategy()); + + // Initializes the Options singleton. + Options.instance().parseArgs(null); + } + + /** Sets the action of the button on click state. */ + public void playButtonClicked(View view) { + if (mGameState == PLAY) { + // Use a factory method to create the appropriate type of + // OutputStrategy. + PlayPingPong pingPong = + new PlayPingPong(PlatformStrategy.instance(), + Options.instance().maxIterations(), + Options.instance().maxTurns(), + Options.instance().syncMechanism()); + + // Play ping-pong with the designated number of + // iterations. + new Thread(pingPong).start(); + mPlayButton.setText(R.string.reset_button); + mGameState = RESET; + } else if (mGameState == RESET) { + + // Empty TextView and prepare the UI to play another game. + mAndroidPingPongOutput.setText(R.string.empty_string); + mPlayButton.setText(R.string.play_button); + mGameState = PLAY; + } else { + // Notify the player that something has gone wrong and + // reset. + mAndroidPingPongOutput.setText("Unknown State entered!"); + mGameState = RESET; + } + } +} diff --git a/assignments/week-5-assignment-4/src/edu/vuum/mocca/PlatformStrategy.java b/assignments/week-5-assignment-4/W5-A4-Android/src/edu/vuum/mocca/PlatformStrategy.java similarity index 87% rename from assignments/week-5-assignment-4/src/edu/vuum/mocca/PlatformStrategy.java rename to assignments/week-5-assignment-4/W5-A4-Android/src/edu/vuum/mocca/PlatformStrategy.java index 1280920f2..8ae0fadef 100644 --- a/assignments/week-5-assignment-4/src/edu/vuum/mocca/PlatformStrategy.java +++ b/assignments/week-5-assignment-4/W5-A4-Android/src/edu/vuum/mocca/PlatformStrategy.java @@ -12,6 +12,9 @@ */ public abstract class PlatformStrategy { + /** Number of threads used to play ping-pong. */ + protected static final int NUMBER_OF_THREADS = 2; + /** The singleton @a PlatformStrategy instance. */ private static PlatformStrategy mUniqueInstance = null; @@ -42,11 +45,13 @@ public static PlatformStrategy instance(PlatformStrategy platform) /** Barrier that waits for all the game threads to finish. */ public abstract void awaitDone(); - /** + /** * Returns the name of the platform in a string. e.g., Android or * a JVM. + * @deprecated This method is just here for backwards + * compatibility with the skeletons. */ - public abstract String platformName(); + public String platformName() { return ""; } /** * Error log formats the message and displays it for the debugging diff --git a/assignments/week-5-assignment-4/src/edu/vuum/mocca/PlatformStrategyFactory.java b/assignments/week-5-assignment-4/W5-A4-Android/src/edu/vuum/mocca/PlatformStrategyFactory.java similarity index 68% rename from assignments/week-5-assignment-4/src/edu/vuum/mocca/PlatformStrategyFactory.java rename to assignments/week-5-assignment-4/W5-A4-Android/src/edu/vuum/mocca/PlatformStrategyFactory.java index a655f6a18..95d6bb962 100644 --- a/assignments/week-5-assignment-4/src/edu/vuum/mocca/PlatformStrategyFactory.java +++ b/assignments/week-5-assignment-4/W5-A4-Android/src/edu/vuum/mocca/PlatformStrategyFactory.java @@ -11,21 +11,29 @@ public class PlatformStrategyFactory { /** - * This interface uses the Strategy pattern to create @a PlatformStrategy - * implementations at runtime. + * This interface uses the Strategy pattern to create @a + * PlatformStrategy implementations at runtime. */ private static interface IPlatformStrategyFactoryStrategy { public PlatformStrategy execute(); } + /** + * Enumeration distinguishing platforms Android from plain ol' Java. + */ + public enum PlatformType { + ANDROID, + PLAIN_JAVA + } + /** * HashMap used to map strings containing the Java platform names * and dispatch the execute() method of the associated @a PlatformStrategy * implementation. */ - private HashMap mPlatformStrategyMap = - new HashMap(); + private HashMap mPlatformStrategyMap = + new HashMap(); /** * Ctor that stores the objects that perform output for a @@ -39,7 +47,7 @@ public PlatformStrategyFactory(final Object output, * The "The Android Project" string maps to a command object * that creates an @a AndroidPlatformStrategy implementation. */ - mPlatformStrategyMap.put("The Android Project", + mPlatformStrategyMap.put(PlatformType.ANDROID, new IPlatformStrategyFactoryStrategy() { /** @@ -58,7 +66,7 @@ public PlatformStrategy execute() * The "Sun Microsystems Inc." string maps to a command object * that creates an @a ConsolePlatformStrategy implementation. */ - mPlatformStrategyMap.put("Sun Microsystems Inc.", + mPlatformStrategyMap.put(PlatformType.PLAIN_JAVA, new IPlatformStrategyFactoryStrategy() { public PlatformStrategy execute() @@ -66,19 +74,26 @@ public PlatformStrategy execute() return new ConsolePlatformStrategy(output); } }); + } - /** - * The "Oracle Corporation" string maps to a command object - * that creates an @a ConsolePlatformStrategy implementation. - */ - mPlatformStrategyMap.put("Oracle Corporation", - new IPlatformStrategyFactoryStrategy() - { - public PlatformStrategy execute() - { - return new ConsolePlatformStrategy(output); - } - }); + /** + * Returns the name of the platform in a string. e.g., Android or + * a JVM. + */ + public static String platformName() + { + return System.getProperty("java.specification.vendor"); + } + + /** + * Returns the type of the platformm e.g. Android or + * a JVM. + */ + public static PlatformType platformType() { + if(platformName().indexOf("Android") >= 0) + return PlatformType.ANDROID; + else + return PlatformType.PLAIN_JAVA; } /** @@ -87,8 +102,8 @@ public PlatformStrategy execute() */ public PlatformStrategy makePlatformStrategy() { - String name = System.getProperty("java.specification.vendor"); + PlatformType type = platformType(); - return mPlatformStrategyMap.get(name).execute(); + return mPlatformStrategyMap.get(type).execute(); } } diff --git a/assignments/week-5-assignment-4/src/edu/vuum/mocca/PlayPingPong.java b/assignments/week-5-assignment-4/W5-A4-Android/src/edu/vuum/mocca/PlayPingPong.java similarity index 61% rename from assignments/week-5-assignment-4/src/edu/vuum/mocca/PlayPingPong.java rename to assignments/week-5-assignment-4/W5-A4-Android/src/edu/vuum/mocca/PlayPingPong.java index a72d8246a..aa8cc4b4e 100644 --- a/assignments/week-5-assignment-4/src/edu/vuum/mocca/PlayPingPong.java +++ b/assignments/week-5-assignment-4/W5-A4-Android/src/edu/vuum/mocca/PlayPingPong.java @@ -1,21 +1,18 @@ package edu.vuum.mocca; +import java.util.concurrent.Semaphore; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.ReentrantLock; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.Semaphore; /** * @class PlayPingPong - * - * @brief This class implements a Java program that creates two - * threads, Ping and Pong, to alternately print "Ping" and - * "Pong", respectively, on the display. It uses the Template - * Method, Strategy, and Factory Method patterns to factor out - * common code and simplify the program design. + * + * @brief This class implements a Java program that creates two threads, Ping + * and Pong, to alternately print "Ping" and "Pong", respectively, on the + * display. It uses the Template Method, Strategy, and Factory Method + * patterns to factor out common code and simplify the program design. */ -public class PlayPingPong implements Runnable -{ +public class PlayPingPong implements Runnable { /** * Number of iterations to ping/pong. */ @@ -25,44 +22,42 @@ public class PlayPingPong implements Runnable private static int mMaxTurns = 1; /** - * Keeps track of the platform that we're running on, e.g., - * Android vs. Console. + * Keeps track of the platform that we're running on, e.g., Android vs. + * Console. */ private static volatile PlatformStrategy mPlatformStrategy; /** - * Which synchronization to use, e.g., "SEMA" vs. "COND". - * Defaults to "SEMA". + * Which synchronization to use, e.g., "SEMA" vs. "COND". Defaults to + * "SEMA". */ private static String mSyncMechanism = "SEMA"; - + /** - * Constants used to distinguish between ping and pong threads. + * Constants used to distinguish between ping and pong threads. */ private final static int PING_THREAD = 0; private final static int PONG_THREAD = 1; /** * @Brief PingPongThread - * + * * @class This class implements the core ping/pong algorithm, but - * defers the scheduling aspect to subclasses. It plays - * the role of the "Abstract Class" in the Template Method + * defers the scheduling aspect to subclasses. It plays the + * role of the "Abstract Class" in the Template Method * pattern. */ - static abstract class PingPongThread extends Thread - { - /** + static abstract class PingPongThread extends Thread { + /** * Constructor initializes the various fields. */ - PingPongThread(String stringToPrint) - { + PingPongThread(String stringToPrint) { mStringToPrint = stringToPrint; } /** - * Abstract hook methods that determine the ping/pong - * scheduling protocol in the run() template method. + * Abstract hook methods that determine the ping/pong scheduling + * protocol in the run() template method. */ abstract void acquire(); abstract void release(); @@ -70,28 +65,25 @@ static abstract class PingPongThread extends Thread /** * Sets the id of the other thread. */ - void setOtherThreadId(long id) {} - + void setOtherThreadId(long id) { + } + /** * This method runs in a separate thread of control and - * implements the core ping/pong algorithm. It plays the role + * implements the core ping/pong algorithm. It plays the role * of the "template method" in the Template Method pattern. */ - public void run() - { - for (int loopsDone = 1; - loopsDone <= mMaxIterations; - ++loopsDone) { + public void run() { + for (int loopsDone = 1; loopsDone <= mMaxIterations; ++loopsDone) { // Perform the template method protocol for printing a - // "ping" or a "pong" on the display. Note that the + // "ping" or a "pong" on the display. Note that the // acquire() and release() hook methods that control // the scheduling of the threads are deferred to // subclasses. acquire(); - mPlatformStrategy.print - (mStringToPrint + "(" + loopsDone + ")"); + mPlatformStrategy.print(mStringToPrint + "(" + loopsDone + ")"); release(); } @@ -109,14 +101,13 @@ public void run() /** * @class PingPongThreadSema - * - * @brief This class uses semaphores to implement the acquire() - * and release() hook methods that schedule the ping/pong - * algorithm. It plays the role of the "Concrete Class" in - * the Template Method pattern. + * + * @brief This class uses semaphores to implement the acquire() and + * release() hook methods that schedule the ping/pong algorithm. It + * plays the role of the "Concrete Class" in the Template Method + * pattern. */ - static class PingPongThreadSema extends PingPongThread - { + static class PingPongThreadSema extends PingPongThread { /** * Semaphores that schedule the ping/pong algorithm */ @@ -128,10 +119,8 @@ static class PingPongThreadSema extends PingPongThread private final static int FIRST_SEMA = 0; private final static int SECOND_SEMA = 1; - PingPongThreadSema(String stringToPrint, - Semaphore firstSema, - Semaphore secondSema) - { + PingPongThreadSema(String stringToPrint, Semaphore firstSema, + Semaphore secondSema) { super(stringToPrint); mSemas[FIRST_SEMA] = firstSema; mSemas[SECOND_SEMA] = secondSema; @@ -140,16 +129,14 @@ static class PingPongThreadSema extends PingPongThread /** * Hook method for ping/pong acquire. */ - void acquire() - { + void acquire() { mSemas[FIRST_SEMA].acquireUninterruptibly(); } /** * Hook method for ping/pong release. */ - void release() - { + void release() { mSemas[SECOND_SEMA].release(); } @@ -163,10 +150,9 @@ void release() * plays the role of the "Concrete Class" in the Template Method * pattern. */ - static class PingPongThreadCond extends PingPongThread - { + static class PingPongThreadCond extends PingPongThread { /** - * Conditions that schedule the ping/pong algorithm. + * Semaphores that schedule the ping/pong algorithm. */ private Condition mConds[] = new Condition[2]; @@ -179,7 +165,7 @@ static class PingPongThreadCond extends PingPongThread * Number of times we've iterated thus far in our "turn". */ private int mIterationCount = 0; - + /** * Id for the other thread. */ @@ -189,9 +175,8 @@ static class PingPongThreadCond extends PingPongThread * Thread whose turn it currently is. */ private static long mThreadOwner; - - public void setOtherThreadId(long otherThreadId) - { + + public void setOtherThreadId(long otherThreadId) { this.mOtherThreadId = otherThreadId; } @@ -201,18 +186,14 @@ public void setOtherThreadId(long otherThreadId) private final static int FIRST_COND = 0; private final static int SECOND_COND = 1; - PingPongThreadCond(String stringToPrint, - ReentrantLock lock, - Condition firstCond, - Condition secondCond, - boolean isOwner) - { + PingPongThreadCond(String stringToPrint, ReentrantLock lock, + Condition firstCond, Condition secondCond, boolean isOwner) { super(stringToPrint); mIterationCount = mMaxTurns; mLock = lock; mConds[FIRST_COND] = firstCond; mConds[SECOND_COND] = secondCond; - if (isOwner) + if (isOwner) mThreadOwner = this.getId(); } @@ -247,14 +228,11 @@ void release() { } /** - * Constructor stores the PlatformStrategy and the number of - * iterations to play ping/pong. + * Constructor stores the PlatformStrategy and the number of iterations to + * play ping/pong. */ - public PlayPingPong (PlatformStrategy platformStrategy, - int maxIterations, - int maxTurns, - String syncMechanism) - { + public PlayPingPong(PlatformStrategy platformStrategy, int maxIterations, + int maxTurns, String syncMechanism) { // The PlatformStrategy being used. mPlatformStrategy = platformStrategy; @@ -263,57 +241,62 @@ public PlayPingPong (PlatformStrategy platformStrategy, // Number of iterations to perform pings and pongs per "turn". mMaxTurns = maxTurns; - + // Which synchronization to use (e.g., "SEMA" vs. "COND"). mSyncMechanism = syncMechanism; } - private void makePingPongThreads(String schedMechanism, - PingPongThread[] pingPongThreads) - { + static String pingString = "ping "; + static String pongString = "_pong "; + + static boolean checkedStringFormatting = false; + + private void formatStrings() { + if (!checkedStringFormatting) { + PlatformStrategyFactory.PlatformType type = + PlatformStrategyFactory.PlatformType.ANDROID; + + if (PlatformStrategyFactory.platformType().equals(type)) + pingString += " "; + checkedStringFormatting = true; + } + } + + private void makePingPongThreads(String schedMechanism, + PingPongThread[] pingPongThreads) { + formatStrings(); if (schedMechanism.equals("SEMA")) { // Create the semaphores that schedule threads - // printing "ping" and "pong" in the correct + // printing "ping " and "_pong" in the correct // alternating order. Semaphore pingSema = new Semaphore(1); // Starts out unlocked. Semaphore pongSema = new Semaphore(0); - - pingPongThreads[PING_THREAD] = - new PingPongThreadSema("ping", pingSema, pongSema); - pingPongThreads[PONG_THREAD] = - new PingPongThreadSema("pong", pongSema, pingSema); - } - else if (schedMechanism.equals("COND")) { + + pingPongThreads[PING_THREAD] = new PingPongThreadSema(pingString, + pingSema, pongSema); + pingPongThreads[PONG_THREAD] = new PingPongThreadSema(pongString, + pongSema, pingSema); + } else if (schedMechanism.equals("COND")) { ReentrantLock lock = new ReentrantLock(); Condition pingCond = lock.newCondition(); Condition pongCond = lock.newCondition(); - int numberOfTurnsEach = 2; - - pingPongThreads[PING_THREAD] = - new PingPongThreadCond("ping", - lock, - pingCond, - pongCond, - true); - pingPongThreads[PONG_THREAD] = - new PingPongThreadCond("pong", - lock, - pongCond, - pingCond, - false); + + pingPongThreads[PING_THREAD] = new PingPongThreadCond(pingString, + lock, pingCond, pongCond, true); + pingPongThreads[PONG_THREAD] = new PingPongThreadCond(pongString, + lock, pongCond, pingCond, false); pingPongThreads[PING_THREAD] .setOtherThreadId(pingPongThreads[PONG_THREAD].getId()); pingPongThreads[PONG_THREAD] .setOtherThreadId(pingPongThreads[PING_THREAD].getId()); } } - + /** - * Start running the ping/pong code, which can be called from a - * main() function in a Java class, an Android Activity, etc. - */ - public void run() - { + * Start running the ping/pong code, which can be called from a main() + * function in a Java class, an Android Activity, etc. + */ + public void run() { // Indicate a new game is beginning. mPlatformStrategy.begin(); @@ -325,24 +308,22 @@ public void run() pingPongThreads[PING_THREAD] = null; pingPongThreads[PONG_THREAD] = null; - /** - * Create the appropriate type of threads with the designated - * scheduling mechanism (e.g., "SEMA" for Semaphores, "COND" - * for ConditionObjects, etc.). + /** + * Create the appropriate type of threads with the designated scheduling + * mechanism (e.g., "SEMA" for Semaphores, "COND" for ConditionObjects, + * etc.). */ - makePingPongThreads(mSyncMechanism, - pingPongThreads); + makePingPongThreads(mSyncMechanism, pingPongThreads); /** - * Start ping and pong threads, which calls their run() - * methods. + * Start ping and pong threads, which calls their run() methods. */ pingPongThreads[PING_THREAD].start(); pingPongThreads[PONG_THREAD].start(); /** - * Barrier synchronization to wait for all work to be done - * before exiting play(). + * Barrier synchronization to wait for all work to be done before + * exiting play(). */ mPlatformStrategy.awaitDone(); diff --git a/assignments/week-5-assignment-4/ic_launcher-web.png b/assignments/week-5-assignment-4/ic_launcher-web.png deleted file mode 100644 index a18cbb48c..000000000 Binary files a/assignments/week-5-assignment-4/ic_launcher-web.png and /dev/null differ diff --git a/assignments/week-5-assignment-4/res/drawable-hdpi/ic_launcher.png b/assignments/week-5-assignment-4/res/drawable-hdpi/ic_launcher.png deleted file mode 100644 index 288b66551..000000000 Binary files a/assignments/week-5-assignment-4/res/drawable-hdpi/ic_launcher.png and /dev/null differ diff --git a/assignments/week-5-assignment-4/res/drawable-mdpi/ic_launcher.png b/assignments/week-5-assignment-4/res/drawable-mdpi/ic_launcher.png deleted file mode 100644 index 6ae570b4d..000000000 Binary files a/assignments/week-5-assignment-4/res/drawable-mdpi/ic_launcher.png and /dev/null differ diff --git a/assignments/week-5-assignment-4/res/drawable-xhdpi/ic_launcher.png b/assignments/week-5-assignment-4/res/drawable-xhdpi/ic_launcher.png deleted file mode 100644 index d4fb7cd9d..000000000 Binary files a/assignments/week-5-assignment-4/res/drawable-xhdpi/ic_launcher.png and /dev/null differ diff --git a/assignments/week-5-assignment-4/res/drawable-xxhdpi/ic_launcher.png b/assignments/week-5-assignment-4/res/drawable-xxhdpi/ic_launcher.png deleted file mode 100644 index 85a608158..000000000 Binary files a/assignments/week-5-assignment-4/res/drawable-xxhdpi/ic_launcher.png and /dev/null differ diff --git a/assignments/week-5-assignment-4/res/menu/ping_pong.xml b/assignments/week-5-assignment-4/res/menu/ping_pong.xml deleted file mode 100644 index c00202823..000000000 --- a/assignments/week-5-assignment-4/res/menu/ping_pong.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - diff --git a/assignments/week-5-assignment-4/res/values-sw600dp/dimens.xml b/assignments/week-5-assignment-4/res/values-sw600dp/dimens.xml deleted file mode 100644 index 44f01db75..000000000 --- a/assignments/week-5-assignment-4/res/values-sw600dp/dimens.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - diff --git a/assignments/week-5-assignment-4/res/values-sw720dp-land/dimens.xml b/assignments/week-5-assignment-4/res/values-sw720dp-land/dimens.xml deleted file mode 100644 index 61e3fa8fb..000000000 --- a/assignments/week-5-assignment-4/res/values-sw720dp-land/dimens.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - 128dp - - diff --git a/assignments/week-5-assignment-4/src/edu/vuum/mocca/PingPongActivity.java b/assignments/week-5-assignment-4/src/edu/vuum/mocca/PingPongActivity.java deleted file mode 100644 index 4296cd074..000000000 --- a/assignments/week-5-assignment-4/src/edu/vuum/mocca/PingPongActivity.java +++ /dev/null @@ -1,85 +0,0 @@ -package edu.vuum.mocca; - -import android.app.Activity; -import android.os.Bundle; -import android.view.View; -import android.widget.Button; -import android.widget.TextView; - -/** - * @class MainActivity - * - * @brief Initial start up screen for the android GUI. - */ -public class PingPongActivity extends Activity -{ - /** TextView that PingPong will be "played" upon */ - private TextView mAndroidPingPongOutput; - - /** Button that allows playing and resetting of the game */ - private Button mPlayButton; - - /** Variables to track state of the game */ - private static int PLAY = 0; - private static int RESET = 1; - private int mGameState = PLAY; - - protected void onCreate(Bundle savedInstanceState) - { - super.onCreate(savedInstanceState); - - /** Sets the content view to the xml file, activity_ping_pong. */ - setContentView(R.layout.activity_ping_pong); - mAndroidPingPongOutput = (TextView) findViewById(R.id.pingpong_output); - mPlayButton = (Button) findViewById(R.id.play_button); - - /** - * Initializes the Platform singleton with the appropriate - * Platform strategy, which in this case will be the - * AndroidPlatform. - */ - PlatformStrategy.instance - (new PlatformStrategyFactory - (mAndroidPingPongOutput, this).makePlatformStrategy()); - - /** Initializes the Options singleton. */ - String args[] = new String[] { "PlayPingPongGUI" }; - Options.instance().parseArgs(args); - } - - /** Sets the action of the button on click state. */ - public void playButtonClicked(View view) - { - if(mGameState == PLAY) { - /** - * Use a factory method to create the appropriate type of - * OutputStrategy. - */ - PlayPingPong pingPong = - new PlayPingPong(PlatformStrategy.instance(), - Options.instance().maxIterations(), - Options.instance().maxTurns(), - Options.instance().syncMechanism()); - - /** - * Play ping-pong with the designated number of - * iterations. - */ - new Thread (pingPong).start(); - mPlayButton.setText(R.string.reset_button); - mGameState = RESET; - } - else if(mGameState == RESET) { - - /** Empty TextView and prepare the UI to play another game */ - mAndroidPingPongOutput.setText(R.string.empty_string); - mPlayButton.setText(R.string.play_button); - mGameState = PLAY; - } - else { - /** Notify the player that something has gone wrong and reset */ - mAndroidPingPongOutput.setText("Unknown State entered!"); - mGameState = RESET; - } - } -} diff --git a/assignments/week-6-assignment-5/Assignment-Description.txt b/assignments/week-6-assignment-5/Assignment-Description.txt new file mode 100644 index 000000000..acc0a2dee --- /dev/null +++ b/assignments/week-6-assignment-5/Assignment-Description.txt @@ -0,0 +1,109 @@ +Week 6: Programming Assignment 5 + +Released Monday, June 16th, 2014 +Due Monday, June 30th, 2014 + +In this assignment, you will implement a program that downloads images +using started services and then displays them in the context of the UI +Thread. The user can optionally select one of two different Started +Services whose implementations you will complete: + +. A simple DownloadIntentService that uses on the Android + IntentService framework to download files in a single background + Thread and + +. A more scalable ThreadPoolDownloadService that uses a + ThreadPoolExecutor to download several files concurrently within a + fixed pool of Threads. + +In this directory you'll find Java source code, AndroidManifest.xml, +and associated XML metadata files. The directory +W6-A5-ThreadedDownloads-StartedServices/src/edu/vuum/mocca/ contains +the skeleton Java code that you'll implement by completing the "TODO - +You fill in here" comments to provide a working solution. DO NOT +CHANGE THE OVERALL STRUCTURE OF THE SKELETON - just fill in the "TODO +- You fill in here" portions!!! + +The main goal of this project is to understand the pattern-oriented +threaded download application and how to start and interact with +Services using the IntentService and Messenger IPC mechanisms. In +particular, you'll need to do the following: + +. Understand how to launch Started Services using Intents and receive + replies from Services using the Messenger IPC mechanism in the + DownloadActivity class, which are covered in these videos: + + Section 1: Module 3: Part 5: Sending and Handling Messages with Android Handler + Section 2: Module 1: Part 2: Programming Started Services (Part 1) + Section 2: Module 1: Part 3: Programming Started Services (Part 2) + +. Understand how to implement the DownloadIntentService and + ThreadPoolDownloadService by handling Intents, doing work in the + background, and sending results the Messenger IPC mechanism covered + in these videos: + + Section 2: Module 1: Part 4: Android IntentService + Section 2: Module 1: Part 6: Service to Activity Communication via Android Messenger + +. Understand factory methods and implement the makeIntent() factory + methods in each service, which are similar to the + DownloadService.makeIntent() factory method covered in this video: + + Section 2: Module 1: Part 3: Programming Started Services (Part 2) + +. Understand the ThreadPoolExecutor class and utilize a factory method + in the Executors class to create a new thread pool, which is + (briefly) outlined in this video + + Section 1: Module 3: Part 7: The AsyncTask Framework (Part 2) + + and described further in the documentation at: + + http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Executors.html + +. Understand the methods provided in the DownloadUtils class, which + contains functionality that is common to both the + DownloadIntentService and ThreadPoolDownloadService. + +These videos are available at + +https://class.coursera.org/posa-002/lecture + +We'll also discuss this assignment specification (and later its +solution) in the POSA MOOC "Virtual Office Hours", which are described +in item #38 at the POSA MOOC FAQ available from + +http://www.courera.org/course/posa + +You'll need to build this Android application in the Eclipse ADT +environment. Unlike previous assignments, this program is +user-driven, so output will vary depending on which URL is provided. +In addition to using the default URL (which is available from +https://d396qusza40orc.cloudfront.net/posa/ka.png) you should also +test this application by finding an Internet URL to an image (ending +in .jpg, .gif, .png etc.) and see if your application correctly +displays the image. + +We provide several JUnit tests that should test your program's +functionality. The unit tests test the Service classes independently +of the DownloadActivity, and then test the overall functionality of +the program. By default, the unit tests try to download the default +URL and then check if the proper image was downloaded using Bitmap +comparison. + +To Run the Android Application, right click on the 'W6-A5-Android' +project and select [Run As] -> [Android Application] + +To Run the Android Unit Test, right click on the 'W6-A5-Android-Test' +project and select [Run As] -> [Android Unit Test] + +By default, the application and test program do an "offline" download +since students often run this code an emulator or some other +environment with slow/no Internet connectivity. If you'd like to +run/test it in the Internet please change the DOWNLOAD_OFFLINE boolean +in + +W6-A5-ThreadedDownloads-StartedServices/src/edu/vuum/mocca/DownloadUtils.java + +to false. + diff --git a/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices-Tests/.classpath b/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices-Tests/.classpath new file mode 100644 index 000000000..de7aa1845 --- /dev/null +++ b/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices-Tests/.classpath @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices-Tests/.project b/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices-Tests/.project new file mode 100644 index 000000000..04245676b --- /dev/null +++ b/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices-Tests/.project @@ -0,0 +1,34 @@ + + + W6-A5-ThreadedDownloads-StartedServices-Tests + + + week-6-assignment-5 + + + + com.android.ide.eclipse.adt.ResourceManagerBuilder + + + + + com.android.ide.eclipse.adt.PreCompilerBuilder + + + + + org.eclipse.jdt.core.javabuilder + + + + + com.android.ide.eclipse.adt.ApkBuilder + + + + + + com.android.ide.eclipse.adt.AndroidNature + org.eclipse.jdt.core.javanature + + diff --git a/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices-Tests/AndroidManifest.xml b/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices-Tests/AndroidManifest.xml new file mode 100644 index 000000000..2d80b1796 --- /dev/null +++ b/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices-Tests/AndroidManifest.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices-Tests/project.properties b/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices-Tests/project.properties new file mode 100644 index 000000000..a3ee5ab64 --- /dev/null +++ b/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices-Tests/project.properties @@ -0,0 +1,14 @@ +# This file is automatically generated by Android Tools. +# Do not modify this file -- YOUR CHANGES WILL BE ERASED! +# +# This file must be checked in Version Control Systems. +# +# To customize properties used by the Ant build system edit +# "ant.properties", and override values to adapt the script to your +# project structure. +# +# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): +#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt + +# Project target. +target=android-17 diff --git a/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices-Tests/res/drawable-hdpi/ic_launcher.png b/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices-Tests/res/drawable-hdpi/ic_launcher.png new file mode 100644 index 000000000..96a442e5b Binary files /dev/null and b/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices-Tests/res/drawable-hdpi/ic_launcher.png differ diff --git a/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices-Tests/res/drawable-ldpi/ic_launcher.png b/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices-Tests/res/drawable-ldpi/ic_launcher.png new file mode 100644 index 000000000..99238729d Binary files /dev/null and b/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices-Tests/res/drawable-ldpi/ic_launcher.png differ diff --git a/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices-Tests/res/drawable-mdpi/ic_launcher.png b/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices-Tests/res/drawable-mdpi/ic_launcher.png new file mode 100644 index 000000000..359047dfa Binary files /dev/null and b/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices-Tests/res/drawable-mdpi/ic_launcher.png differ diff --git a/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices-Tests/res/drawable-nodpi/dougs.jpg b/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices-Tests/res/drawable-nodpi/dougs.jpg new file mode 100644 index 000000000..e31e8b98b Binary files /dev/null and b/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices-Tests/res/drawable-nodpi/dougs.jpg differ diff --git a/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices-Tests/res/drawable-xhdpi/ic_launcher.png b/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices-Tests/res/drawable-xhdpi/ic_launcher.png new file mode 100644 index 000000000..71c6d760f Binary files /dev/null and b/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices-Tests/res/drawable-xhdpi/ic_launcher.png differ diff --git a/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices-Tests/res/values/strings.xml b/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices-Tests/res/values/strings.xml new file mode 100644 index 000000000..111dfea6e --- /dev/null +++ b/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices-Tests/res/values/strings.xml @@ -0,0 +1,5 @@ + + + + W6-A5-ThreadedDownloads-StartedServices-Tests + diff --git a/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices-Tests/src/edu/vuum/mocca/test/AllTests.java b/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices-Tests/src/edu/vuum/mocca/test/AllTests.java new file mode 100644 index 000000000..0d878f947 --- /dev/null +++ b/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices-Tests/src/edu/vuum/mocca/test/AllTests.java @@ -0,0 +1,22 @@ +package edu.vuum.mocca.test; + +import junit.framework.Test; +import junit.framework.TestSuite; + +/** + * @class AllTests + * + * @brief Combine all the unit tests into one suite, so that you can run them together with one click. + */ +public class AllTests { + public static Test suite() { + TestSuite suite = new TestSuite(AllTests.class.getName()); + //$JUnit-BEGIN$ + suite.addTestSuite(DownloadIntentServiceTests.class); + suite.addTestSuite(DownloadUtilsTests.class); + suite.addTestSuite(ThreadPoolDownloadServiceTests.class); + suite.addTestSuite(DownloadActivityTests.class); + //$JUnit-END$ + return suite; + } +} diff --git a/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices-Tests/src/edu/vuum/mocca/test/DownloadActivityTests.java b/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices-Tests/src/edu/vuum/mocca/test/DownloadActivityTests.java new file mode 100644 index 000000000..9b301e359 --- /dev/null +++ b/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices-Tests/src/edu/vuum/mocca/test/DownloadActivityTests.java @@ -0,0 +1,113 @@ +package edu.vuum.mocca.test; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.test.ActivityInstrumentationTestCase2; +import android.widget.EditText; + +import com.robotium.solo.Solo; + +import edu.vuum.mocca.DownloadActivity; + +/** + * @class DownloadActivityTests + * + * @brief Tests the functionality of DownloadActivity. Current tests + * only press buttons and check that the correct image was downloaded. + */ +public class DownloadActivityTests + extends + ActivityInstrumentationTestCase2 { + /** + * Constructor initializes the superclass + */ + public DownloadActivityTests() { + super(DownloadActivity.class); + } + + /** + * This is the handle for Robotium, which allows us to interact + * with the UI. + */ + Solo mSolo; + + /** + * The context of this project, not the target project. + */ + Context mContext; + + /** + * The activity we're testing + */ + DownloadActivity mActivity; + + /** + * Store the bitmap that we expect to be downloaded. + */ + Bitmap mExpected; + + /** + * Called before each test is run to perform the initialization. + */ + public void setUp() throws Exception{ + super.setUp(); + + mActivity = getActivity(); + + // Setup Robotium and get the EditText View. + mSolo = new Solo(getInstrumentation(), mActivity); + + mContext = getInstrumentation().getContext(); + + EditText edit_ = (EditText) mSolo.getView(edu.vuum.mocca.R.id.url); + mSolo.clearEditText(edit_); + mSolo.enterText(edit_, Options.TEST_URI); + + mExpected = BitmapFactory.decodeResource(mContext.getResources(), + R.drawable.dougs); + + getInstrumentation().callActivityOnStart(mActivity); + getInstrumentation().callActivityOnResume(mActivity); + + // Wait for things to settle + Thread.sleep(Options.SHORT_WAIT_TIME); + + } + + /** + * Push the button and see if the correct image is displayed. + */ + public void testThreadPoolButton() throws Exception { + + // Make sure the current image isn't the one we're looking for + assertFalse(mExpected.sameAs(mActivity.mCurrentBitmap)); + + // Click on the "Start ThreadPool Button" + mSolo.clickOnView(mSolo.getView(edu.vuum.mocca.R.id.thread_pool_button)); + + // Wait for the image to download + Thread.sleep(Options.LONG_WAIT_TIME); + + // Check if we displayed the correct image + assertTrue(mExpected.sameAs(mActivity.mCurrentBitmap)); + } + + /** + * Push the button and see if the correct image is displayed. + */ + public void testIntentServiceButton() throws Exception { + + // Make sure the current image isn't the one we're looking for + assertFalse(mExpected.sameAs(mActivity.mCurrentBitmap)); + + // Click on the "Start ThreadPool Button" + mSolo.clickOnView(mSolo.getView(edu.vuum.mocca.R.id.intent_service_button)); + + // Wait for the image to download + Thread.sleep(Options.LONG_WAIT_TIME); + + // Check if we displayed the correct image + assertTrue(mExpected.sameAs(mActivity.mCurrentBitmap)); + } +} diff --git a/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices-Tests/src/edu/vuum/mocca/test/DownloadIntentServiceTests.java b/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices-Tests/src/edu/vuum/mocca/test/DownloadIntentServiceTests.java new file mode 100644 index 000000000..8148d4dac --- /dev/null +++ b/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices-Tests/src/edu/vuum/mocca/test/DownloadIntentServiceTests.java @@ -0,0 +1,162 @@ +package edu.vuum.mocca.test; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import android.app.Service; +import android.content.Context; +import android.content.Intent; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.test.ServiceTestCase; +import edu.vuum.mocca.DownloadIntentService; +import edu.vuum.mocca.DownloadUtils; + +/** + * @class DownloadIntentServiceTests + * + * @brief Tests the functionality of the DownloadIntentService. + */ +public class DownloadIntentServiceTests + extends + ServiceTestCase { + /** + * Use this latch to wait for messages to be received by the + * Handler's thread. + */ + static CountDownLatch mLatch; + + /** + * Stores the Uri received by the Handler. + */ + static String mReceivedUri = null; + + /** + * The Handler that receives a Message reply from the + * IntentService. + */ + static MessageHandler mHandler; + + /** + * Store the intent from makeIntent() to test proper creations. + */ + Intent mIntent; + + /** + * The context of THIS project, not the target project + */ + Context mContext; + + /** + * Constructor initializes the superclass. + */ + public DownloadIntentServiceTests() { + super(DownloadIntentService.class); + } + + /** + * @class MessageHandler + * + * @brief Make a handler to catch Messages sent from the service. + */ + static class MessageHandler extends Handler { + /** + * Allows us to explicitly specify which thread's Looper to use. + */ + public MessageHandler(Looper myLooper) { + super(myLooper); + } + + /** + * Handle return messages from the IntentService. Store the + * received Uri and notify the JUnit thread. + */ + public void handleMessage(Message msg) { + // We don't know what tag they'll use for the path, so we + // have to search for it. + mReceivedUri = Utilities.searchForPath(msg); + + // Let the unit test thread know we've gotten a message. + mLatch.countDown(); + } + } + + /** + * This method is called before each test is called to perform + * initialization activities. + */ + public void setUp() throws Exception{ + super.setUp(); + + // Make an intent with the handler using the factory method. + mIntent = DownloadIntentService.makeIntent(getContext(), + new Handler(), + Options.TEST_URI); + + // Get the context for THIS project, not the target project. + mContext = getContext().createPackageContext(this.getClass().getPackage().getName(), + Context.CONTEXT_IGNORE_SECURITY); + + } + + /** + * Check that the intent starts the correct service. + */ + public void test_makeIntent_Class () { + assertTrue(Utilities.checkClass(mIntent, DownloadIntentService.class)); + } + + /** + * Check that the intent has the correct Uri. + */ + public void test_makeIntent_Uri () { + assertTrue(Utilities.checkUri(mIntent)); + } + + /** + * Check that the intent has a Messenger attached. + */ + public void test_makeIntent_Messenger () { + assertTrue(Utilities.checkMessenger(mIntent)); + } + + /** + * Try starting the service + */ + public void test_startService () throws Exception { + + mLatch = new CountDownLatch(1); + + // Start a thread to handle the message when it's sent. + new Thread(new Runnable() { + public void run() { + Looper.prepare(); + mHandler = new MessageHandler(Looper.myLooper()); + Looper.loop(); + } + }).start(); + + // Wait for the handler to get instantiated + Thread.sleep(Options.SHORT_WAIT_TIME); + + //Create an Intent to start the service + mIntent = DownloadIntentService.makeIntent(getContext(), + mHandler, + Options.TEST_URI); + + // Start the service + startService(mIntent); + + assertNotNull(getService()); + + // Wait for it to send us a Message (or time out) + mLatch.await(Options.LONG_WAIT_TIME, TimeUnit.MILLISECONDS); + + // Check if we got a Message or timed out + assertNotNull(mReceivedUri); + + // Check that the image actually downloaded. + assertTrue(Utilities.checkDownloadedImage(mContext, mReceivedUri)); + } +} diff --git a/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices-Tests/src/edu/vuum/mocca/test/DownloadUtilsTests.java b/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices-Tests/src/edu/vuum/mocca/test/DownloadUtilsTests.java new file mode 100644 index 000000000..d82d0087b --- /dev/null +++ b/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices-Tests/src/edu/vuum/mocca/test/DownloadUtilsTests.java @@ -0,0 +1,202 @@ +package edu.vuum.mocca.test; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import android.content.Context; +import android.content.Intent; +import android.net.Uri; +import android.os.Bundle; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.os.Messenger; +import android.test.ActivityInstrumentationTestCase2; +import edu.vuum.mocca.DownloadActivity; +import edu.vuum.mocca.DownloadUtils; + +/** + * @class DownloadUtilsTests + * + * @brief Test the functionality of the DownloadUtils class + */ +public class DownloadUtilsTests + extends + ActivityInstrumentationTestCase2 { + /** + * Constructor initializes the superclass. + */ + public DownloadUtilsTests () { + super (DownloadActivity.class); + } + + // The intent returned by makeMessengerIntent() + Intent mIntent; + + // The bundle that is part of the intent + Bundle mExtras; + + /** + * Use this latch to wait for messages to be received by the + * Handler's thread. + */ + static CountDownLatch mLatch; + + /** + * Stores the Uri received by the Handler. + */ + static String mReceivedUri = null; + + /** + * The Handler that receives a Message reply from the + * IntentService. + */ + static MessageHandler mHandler; + + /** + * @class MessageHandler + * + * @brief Define a handler to catch messages from sendPath() + */ + static class MessageHandler extends Handler { + /** + * Constructor initializes the superclass + */ + public MessageHandler(Looper myLooper) { + super(myLooper); + } + + /** + * Handle return messages from the IntentService. Store the + * received Uri and notify the JUnit thread. + */ + public void handleMessage(Message msg) { + + // We don't know what tag they'll use for the path, so we + // have to search for it. + mReceivedUri = Utilities.searchForPath(msg); + + // Let the unit test thread know we've gotten a message. + mLatch.countDown(); + } + } + + /** + * This method is called before each test is run to perform + * initialization activities. + */ + @Override + protected void setUp() throws Exception { + super.setUp(); + + // Make an arbitrary Messenger intent. + mIntent = DownloadUtils.makeMessengerIntent(getActivity(), + DownloadUtilsTests.class, + new MessageHandler(Looper.myLooper()), + Options.TEST_URI); + mExtras = mIntent.getExtras(); + } + + /** + * Try downloading a file. + */ + public void test_downloadFile () { + Context context = getInstrumentation().getContext(); + String result = DownloadUtils.downloadFile(getActivity(), + Uri.parse(Options.TEST_URI)); + + assertTrue(Utilities.checkDownloadedImage(context, result)); + } + + /** + * Check that the intent has a Messenger attached. + */ + public void test_makeMessengerIntent_Messenger_Extra () { + assertTrue(Utilities.checkMessenger(mIntent)); + } + + /** + * Check that the intent has the proper Uri attached + */ + public void test_makeMessengerIntent_Uri_Extra () { + assertTrue(Utilities.checkUri(mIntent)); + } + + /** + * Check that the intent will start the class we told it to + */ + public void test_makeMessengerIntent_Class () { + assertTrue(Utilities.checkClass(mIntent, DownloadUtilsTests.class)); + } + + /** + * Try sending a message using sendPath(). + */ + public void test_sendPath () throws Exception { + mLatch = new CountDownLatch(1); + + // Start a thread to catch the message from sendPath() + new Thread ( new Runnable () { + public void run() { + Looper.prepare(); + mHandler = new MessageHandler(Looper.myLooper()); + Looper.loop(); + } + }).start(); + + // Wait for the handler to instantiate + Thread.sleep(Options.SHORT_WAIT_TIME); + + // Send a message to ourselves + DownloadUtils.sendPath(Options.TEST_URI, new Messenger(mHandler)); + + // Wait for it to get here + mLatch.await(Options.LONG_WAIT_TIME, TimeUnit.MILLISECONDS); + + // See if we got the message or timed out. + assertNotNull(mReceivedUri); + + // Check that the Uri is correct + assertTrue(mReceivedUri.equals(Options.TEST_URI)); + + // Other tests use this + mReceivedUri = null; + } + + /** + * Test that the downloadAndRespond method properly uses the other + * two methods in DownloadUtils. + */ + public void test_downloadAndRespond() throws Exception { + mLatch = new CountDownLatch(1); + + // Start a thread to handle messages we send to ourselves + new Thread ( new Runnable () { + public void run() { + Looper.prepare(); + mHandler = new MessageHandler(Looper.myLooper()); + Looper.loop(); + } + }).start(); + + // Wait for mHandler to instantiate + Thread.sleep(Options.SHORT_WAIT_TIME); + + // Download the image and send a message to ourselves + DownloadUtils.downloadAndRespond(getActivity(), + Uri.parse(Options.TEST_URI), + new Messenger(mHandler)); + + // Wait for it to get here. + mLatch.await(Options.LONG_WAIT_TIME, TimeUnit.MILLISECONDS); + + // Check if we timed out or got the message + assertNotNull(mReceivedUri); + + // Make sure the image downloaded correctly. + assertTrue(Utilities.checkDownloadedImage(getInstrumentation().getContext(), mReceivedUri)); + + // Other tests use this + mReceivedUri = null; + } +} diff --git a/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices-Tests/src/edu/vuum/mocca/test/Options.java b/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices-Tests/src/edu/vuum/mocca/test/Options.java new file mode 100644 index 000000000..042f8f648 --- /dev/null +++ b/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices-Tests/src/edu/vuum/mocca/test/Options.java @@ -0,0 +1,34 @@ +package edu.vuum.mocca.test; + +/** + * @class Options + * + * @brief Holds global constants for the testing suite. More + * convenient than grabbing resources from /res and trying to + * finagle a working Context out of the test classes every time + * we want to use TEST_URI. + * + */ +public class Options { + + /** + * The online URL of the image we're using for testing. + */ + static final String TEST_URI = "https://d396qusza40orc.cloudfront.net/posa/dougs-xsmall.jpg"; + + /** + * Whatever image we're testing, store it in res/drawable-nodpi so + * we can compare it to what's downloaded. + */ + static final int TEST_IMAGE = R.drawable.dougs; + + /** + * Time we should wait for things to instantiate. + */ + static final long SHORT_WAIT_TIME = 10000; + + /** + * Time we should wait for things to download. + */ + static final long LONG_WAIT_TIME = 25000; +} diff --git a/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices-Tests/src/edu/vuum/mocca/test/ThreadPoolDownloadServiceTests.java b/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices-Tests/src/edu/vuum/mocca/test/ThreadPoolDownloadServiceTests.java new file mode 100644 index 000000000..43ec67721 --- /dev/null +++ b/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices-Tests/src/edu/vuum/mocca/test/ThreadPoolDownloadServiceTests.java @@ -0,0 +1,169 @@ +package edu.vuum.mocca.test; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import android.app.Service; +import android.content.Context; +import android.content.Intent; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.test.ServiceTestCase; +import edu.vuum.mocca.DownloadIntentService; +import edu.vuum.mocca.DownloadUtils; +import edu.vuum.mocca.ThreadPoolDownloadService; + +/** + * @class ThreadPoolDownloadServiceTests + * + * @brief Tests the functionality of the ThreadPoolDownloadService. + */ +public class ThreadPoolDownloadServiceTests + extends + ServiceTestCase { + /** + * Use this latch to wait for messages to be received by the + * Handler's thread. + */ + static CountDownLatch mLatch; + + /** + * Stores the Uri received by the Handler. + */ + static String mReceivedUri = null; + + /** + * The Handler that receives a Message reply from the + * IntentService. + */ + static MessageHandler mHandler; + + /** + * Store the intent from makeIntent() to test proper creations. + */ + Intent mIntent; + + /** + * The context of THIS project, not the target project + */ + Context mContext; + + /** + * Constructor initializes the superclass. + */ + public ThreadPoolDownloadServiceTests() { + super(ThreadPoolDownloadService.class); + } + + /** + * @class MessageHandler + * + * @brief Define a private handler to catch messages from the service. + */ + static class MessageHandler extends Handler { + /** + * Constructor initializes the superclass + */ + public MessageHandler(Looper myLooper) { + super(myLooper); + } + + /** + * Handle return messages from the IntentService. Store the + * received Uri and notify the JUnit thread. + */ + public void handleMessage(Message msg) { + // We don't know what tag they'll use for the path, so we + // have to search for it. + mReceivedUri = Utilities.searchForPath(msg); + + // Let the unit test thread know we've gotten a message. + mLatch.countDown(); + } + } + + /** + * This is called once before each test is run. + */ + public void setUp() throws Exception{ + super.setUp(); + + // Make an intent using the factory method + mIntent = ThreadPoolDownloadService.makeIntent(getContext(), + new Handler(), + Options.TEST_URI); + + // Get the context for THIS project, not the target project. + mContext = getContext().createPackageContext(this.getClass().getPackage().getName(), + Context.CONTEXT_IGNORE_SECURITY); + + } + + /** + * Check that the intent will start the correct service. + */ + public void test_makeIntent_Class () { + assertTrue(Utilities.checkClass(mIntent, ThreadPoolDownloadService.class)); + } + + /** + * Check that the intent has the correct uri. + */ + public void test_makeIntent_Uri () { + assertTrue(Utilities.checkUri(mIntent)); + } + + /** + * Check that the intent has a Messenger attached. + */ + public void test_makeIntent_Messenger () { + assertTrue(Utilities.checkMessenger(mIntent)); + } + + /** + * Test starting the service. + */ + public void test_startService () throws Exception{ + + mLatch = new CountDownLatch(1); + + // Start a thread to handle the message when it's sent. + new Thread(new Runnable() { + public void run() { + Looper.prepare(); + mHandler = new MessageHandler(Looper.myLooper()); + Looper.loop(); + } + }).start(); + + // Wait for the handler to get instantiated + Thread.sleep(Options.SHORT_WAIT_TIME); + + //Create an Intent to start the service + mIntent = DownloadIntentService.makeIntent(getContext(), + mHandler, + Options.TEST_URI); + + // Start the service + startService(mIntent); + + // Check if the service actually started + assertNotNull(getService()); + + // Wait for the service to download and send us a message + mLatch.await(Options.LONG_WAIT_TIME, TimeUnit.MILLISECONDS); + + // See if we timed out or actually got a message + assertNotNull(mReceivedUri); + + // Get the context for THIS project, not the target project + Context context = getContext().createPackageContext(this.getClass().getPackage().getName(), + Context.CONTEXT_IGNORE_SECURITY); + + // Check that the file downloaded correctly + assertTrue(Utilities.checkDownloadedImage(context, mReceivedUri)); + } +} + + diff --git a/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices-Tests/src/edu/vuum/mocca/test/Utilities.java b/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices-Tests/src/edu/vuum/mocca/test/Utilities.java new file mode 100644 index 000000000..107d69d8e --- /dev/null +++ b/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices-Tests/src/edu/vuum/mocca/test/Utilities.java @@ -0,0 +1,86 @@ +package edu.vuum.mocca.test; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; + +import android.content.Context; +import android.content.Intent; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.os.Bundle; +import android.os.Message; +import android.os.Messenger; +import edu.vuum.mocca.DownloadUtils; + +/** + * @class Utilities + * + * @brief A few checks are repeated several times, such as checking + * whether a Messenger is present in an Intent, or if the proper + * Uri is set. + */ +public class Utilities { + /** + * Check that the proper Uri is set for the provided Intent. + */ + static boolean checkUri(Intent intent) { + return Options.TEST_URI.equals(intent.getData().toString()); + } + + /** + * Check that the provided Intent contains a Messenger extra. + */ + static boolean checkMessenger(Intent intent) { + Bundle extras = intent.getExtras(); + + // We don't know what tag they'll use for the Messenger, so we + // have to search for it. + Messenger messenger = null; + + for (String key : extras.keySet()) { + if (extras.get(key) instanceof Messenger) + messenger = (Messenger) extras.get(key); + } + + return (messenger != null); + } + + /** + * Check that the provided Intent will start the expected class. + */ + static boolean checkClass(Intent intent, Class class_) { + return intent.getComponent().getClassName().equals(class_.getName()); + } + + + /** + * Check if the downloaded Bitmap is equivalent to the expected + * bitmap. + */ + static boolean checkDownloadedImage(Context test_context, String result) { + Bitmap downloaded = BitmapFactory.decodeFile(result); + + Bitmap expected = BitmapFactory.decodeResource(test_context.getResources(), + Options.TEST_IMAGE); + return downloaded.sameAs(expected); + } + + /** + * Search for the pathname that should be bundled in the provided + * Message. (Returns the last String extra found). + */ + static String searchForPath (Message msg) { + Bundle msg_extras = msg.getData(); + + String path = null; + for (String key : msg_extras.keySet()) { + if (msg_extras.get(key) instanceof String) + path = (String) msg_extras.get(key); + } + + return path; + } + +} diff --git a/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices/.classpath b/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices/.classpath new file mode 100644 index 000000000..980bef1db --- /dev/null +++ b/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices/.classpath @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices/.gitignore b/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices/.gitignore new file mode 100644 index 000000000..102b6fc94 --- /dev/null +++ b/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices/.gitignore @@ -0,0 +1 @@ +*.properties \ No newline at end of file diff --git a/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices/.project b/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices/.project new file mode 100644 index 000000000..7ec10d267 --- /dev/null +++ b/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices/.project @@ -0,0 +1,33 @@ + + + W6-A5-ThreadedDownloads-StartedServices + + + + + + com.android.ide.eclipse.adt.ResourceManagerBuilder + + + + + com.android.ide.eclipse.adt.PreCompilerBuilder + + + + + org.eclipse.jdt.core.javabuilder + + + + + com.android.ide.eclipse.adt.ApkBuilder + + + + + + com.android.ide.eclipse.adt.AndroidNature + org.eclipse.jdt.core.javanature + + diff --git a/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices/AndroidManifest.xml b/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices/AndroidManifest.xml new file mode 100644 index 000000000..33958ae4e --- /dev/null +++ b/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices/AndroidManifest.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices/libs/robotium-solo-5.1.jar b/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices/libs/robotium-solo-5.1.jar new file mode 100644 index 000000000..1931dd97f Binary files /dev/null and b/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices/libs/robotium-solo-5.1.jar differ diff --git a/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices/project.properties b/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices/project.properties new file mode 100644 index 000000000..a3ee5ab64 --- /dev/null +++ b/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices/project.properties @@ -0,0 +1,14 @@ +# This file is automatically generated by Android Tools. +# Do not modify this file -- YOUR CHANGES WILL BE ERASED! +# +# This file must be checked in Version Control Systems. +# +# To customize properties used by the Ant build system edit +# "ant.properties", and override values to adapt the script to your +# project structure. +# +# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): +#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt + +# Project target. +target=android-17 diff --git a/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices/res/drawable-hdpi/ic_launcher.png b/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices/res/drawable-hdpi/ic_launcher.png new file mode 100644 index 000000000..96a442e5b Binary files /dev/null and b/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices/res/drawable-hdpi/ic_launcher.png differ diff --git a/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices/res/drawable-mdpi/ic_launcher.png b/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices/res/drawable-mdpi/ic_launcher.png new file mode 100644 index 000000000..359047dfa Binary files /dev/null and b/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices/res/drawable-mdpi/ic_launcher.png differ diff --git a/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices/res/drawable-xhdpi/ic_launcher.png b/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices/res/drawable-xhdpi/ic_launcher.png new file mode 100644 index 000000000..71c6d760f Binary files /dev/null and b/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices/res/drawable-xhdpi/ic_launcher.png differ diff --git a/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices/res/drawable/ka.png b/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices/res/drawable/ka.png new file mode 100644 index 000000000..3a751e9cd Binary files /dev/null and b/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices/res/drawable/ka.png differ diff --git a/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices/res/layout/activity_download.xml b/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices/res/layout/activity_download.xml new file mode 100644 index 000000000..0ae335689 --- /dev/null +++ b/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices/res/layout/activity_download.xml @@ -0,0 +1,64 @@ + + + + + + + + + + + +