From 3af45ac6a74deffc593a021f89683f05b37fc463 Mon Sep 17 00:00:00 2001 From: BarbeRouge Date: Mon, 16 Jun 2014 22:39:01 +0300 Subject: [PATCH 1/9] Assignment done --- .../src/edu/vuum/mocca/PingPongRight.java | 336 ++++++++++-------- .../src/edu/vuum/mocca/SimpleSemaphore.java | 168 +++++---- 2 files changed, 280 insertions(+), 224 deletions(-) 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 index db6e66605..dd1d5dcd2 100644 --- a/assignments/week-4-assignment-3/src/edu/vuum/mocca/PingPongRight.java +++ b/assignments/week-4-assignment-3/src/edu/vuum/mocca/PingPongRight.java @@ -1,158 +1,178 @@ -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); - } -} - +package edu.vuum.mocca; + +// Import the necessary Java synchronization and scheduling classes. +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Semaphore; + +/** + * @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. + private String stringToPrint = null; + + /** + * 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. + private SimpleSemaphore[] arraySema = new SimpleSemaphore[2]; + + /** + * Constructor initializes the data member(s). + */ + public PlayPingPongThread(String stringToPrint, + SimpleSemaphore semaphoreOne, + SimpleSemaphore semaphoreTwo, + int maxIterations) { + // TODO - You fill in here. + this.stringToPrint = stringToPrint; + this.arraySema[FIRST_SEMA] = semaphoreOne; + this.arraySema[SECOND_SEMA] = semaphoreTwo; + this.mMaxLoopIterations = maxIterations; + } + + /** + * 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. + for (int i = 1; i <= mMaxIterations; i++){ + acquire(); + System.out.println(stringToPrint + "(" + i + ")"); + release(); + } + mLatch.countDown(); + } + + /** + * Method for acquiring the appropriate SimpleSemaphore. + */ + private void acquire() { + // TODO fill in here + arraySema[FIRST_SEMA].acquireUninterruptibly(); + } + + /** + * Method for releasing the appropriate SimpleSemaphore. + */ + private void release() { + // TODO fill in here + arraySema[SECOND_SEMA].release(); + } + } + + /** + * 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 = new CountDownLatch(2); + + // Create the ping and pong SimpleSemaphores that control + // alternation between threads. + + // TODO - You fill in here, make pingSema start out unlocked. + SimpleSemaphore pingSema = new SimpleSemaphore(1, true); + // TODO - You fill in here, make pongSema start out locked. + SimpleSemaphore pongSema = new SimpleSemaphore(0, true); + + 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 + */ + pingString, pingSema, pongSema, maxIterations); + PlayPingPongThread pong = new PlayPingPongThread(/* + * TODO - You fill in + * here + */ + pongString, pongSema, pingSema, maxIterations); + + // TODO - Initiate the ping and pong threads, which will call + // the run() hook method. + ping.start(); + pong.start(); + + // TODO - replace the following line with a barrier + // synchronizer call to mLatch that waits for both threads to + // finish. + mLatch.await(); + //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 index 5e473adf6..ca6b9d121 100644 --- a/assignments/week-4-assignment-3/src/edu/vuum/mocca/SimpleSemaphore.java +++ b/assignments/week-4-assignment-3/src/edu/vuum/mocca/SimpleSemaphore.java @@ -1,66 +1,102 @@ -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; - } -} +package edu.vuum.mocca; + +import java.util.concurrent.locks.ReentrantLock; +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 { + /** + * Define a ReentrantLock to protect the critical section. + */ + // TODO - you fill in here + private final ReentrantLock mReentrantLock; + + /** + * Define a ConditionObject to wait while the number of + * permits is 0. + */ + // TODO - you fill in here + private final Condition mCondition;// = mReentrantLock.newCondition(); + + /** + * 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.. + private volatile int permits; + + 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. + this.permits = permits; + mReentrantLock = new ReentrantLock(fair); + mCondition = mReentrantLock.newCondition(); + } + + /** + * Acquire one permit from the semaphore in a manner that can be + * interrupted. + */ + public void acquire() throws InterruptedException { + // TODO - you fill in here. + mReentrantLock.lockInterruptibly(); + try{ + while (permits <= 0){ + mCondition.await(); + } + --permits; + } + finally{ + mReentrantLock.unlock(); + } + } + + /** + * Acquire one permit from the semaphore in a manner that cannot be + * interrupted. + */ + public void acquireUninterruptibly() { + // TODO - you fill in here. + mReentrantLock.lock(); + try{ + while (permits <= 0){ + mCondition.awaitUninterruptibly(); + } + --permits; + } + finally{ + mReentrantLock.unlock(); + } + } + + /** + * Return one permit to the semaphore. + */ + void release() { + // TODO - you fill in here. + mReentrantLock.lock(); + try{ + permits++; + mCondition.signal(); + } + finally{ + mReentrantLock.unlock(); + } + } + + /** + * Return the number of permits available. + */ + public int availablePermits() { + // TODO - you fill in here by changing null to the appropriate + // return value. + return permits; + } +} From 8fbf53888dae0b27c300f69e46a8a1d02e52fe6c Mon Sep 17 00:00:00 2001 From: BarbeRouge Date: Thu, 26 Jun 2014 21:55:37 +0300 Subject: [PATCH 2/9] Assignment done! --- .../src/edu/vuum/mocca/PingPongRight.java | 356 +++++++++--------- .../src/edu/vuum/mocca/SimpleSemaphore.java | 204 +++++----- .../W5-A4-Android/.classpath | 2 +- .../W5-A4-Android/project.properties | 2 +- .../vuum/mocca/AndroidPlatformStrategy.java | 14 + .../src/edu/vuum/mocca/Main.java | 4 +- .../src/edu/vuum/mocca/PlayPingPong.java | 6 +- ex/DownloadApplication/.classpath | 2 +- ex/ThreadedDownload/.classpath | 2 +- .../src/edu/vuum/mocca/PingPongRight.java | 34 +- .../src/edu/vuum/mocca/SimpleSemaphore.java | 52 ++- 11 files changed, 371 insertions(+), 307 deletions(-) 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 index dd1d5dcd2..a20589158 100644 --- a/assignments/week-4-assignment-3/src/edu/vuum/mocca/PingPongRight.java +++ b/assignments/week-4-assignment-3/src/edu/vuum/mocca/PingPongRight.java @@ -1,178 +1,178 @@ -package edu.vuum.mocca; - -// Import the necessary Java synchronization and scheduling classes. -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.Semaphore; - -/** - * @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. - private String stringToPrint = null; - - /** - * 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. - private SimpleSemaphore[] arraySema = new SimpleSemaphore[2]; - - /** - * Constructor initializes the data member(s). - */ - public PlayPingPongThread(String stringToPrint, - SimpleSemaphore semaphoreOne, - SimpleSemaphore semaphoreTwo, - int maxIterations) { - // TODO - You fill in here. - this.stringToPrint = stringToPrint; - this.arraySema[FIRST_SEMA] = semaphoreOne; - this.arraySema[SECOND_SEMA] = semaphoreTwo; - this.mMaxLoopIterations = maxIterations; - } - - /** - * 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. - for (int i = 1; i <= mMaxIterations; i++){ - acquire(); - System.out.println(stringToPrint + "(" + i + ")"); - release(); - } - mLatch.countDown(); - } - - /** - * Method for acquiring the appropriate SimpleSemaphore. - */ - private void acquire() { - // TODO fill in here - arraySema[FIRST_SEMA].acquireUninterruptibly(); - } - - /** - * Method for releasing the appropriate SimpleSemaphore. - */ - private void release() { - // TODO fill in here - arraySema[SECOND_SEMA].release(); - } - } - - /** - * 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 = new CountDownLatch(2); - - // Create the ping and pong SimpleSemaphores that control - // alternation between threads. - - // TODO - You fill in here, make pingSema start out unlocked. - SimpleSemaphore pingSema = new SimpleSemaphore(1, true); - // TODO - You fill in here, make pongSema start out locked. - SimpleSemaphore pongSema = new SimpleSemaphore(0, true); - - 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 - */ - pingString, pingSema, pongSema, maxIterations); - PlayPingPongThread pong = new PlayPingPongThread(/* - * TODO - You fill in - * here - */ - pongString, pongSema, pingSema, maxIterations); - - // TODO - Initiate the ping and pong threads, which will call - // the run() hook method. - ping.start(); - pong.start(); - - // TODO - replace the following line with a barrier - // synchronizer call to mLatch that waits for both threads to - // finish. - mLatch.await(); - //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); - } -} - +package edu.vuum.mocca; + +// Import the necessary Java synchronization and scheduling classes. +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Semaphore; + +/** + * @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. + private String stringToPrint = null; + + /** + * 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. + private SimpleSemaphore[] arraySema = new SimpleSemaphore[2]; + + /** + * Constructor initializes the data member(s). + */ + public PlayPingPongThread(String stringToPrint, + SimpleSemaphore semaphoreOne, + SimpleSemaphore semaphoreTwo, + int maxIterations) { + // TODO - You fill in here. + this.stringToPrint = stringToPrint; + this.arraySema[FIRST_SEMA] = semaphoreOne; + this.arraySema[SECOND_SEMA] = semaphoreTwo; + this.mMaxLoopIterations = maxIterations; + } + + /** + * 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. + for (int i = 1; i <= mMaxIterations; i++){ + acquire(); + System.out.println(stringToPrint + "(" + i + ")"); + release(); + } + mLatch.countDown(); + } + + /** + * Method for acquiring the appropriate SimpleSemaphore. + */ + private void acquire() { + // TODO fill in here + arraySema[FIRST_SEMA].acquireUninterruptibly(); + } + + /** + * Method for releasing the appropriate SimpleSemaphore. + */ + private void release() { + // TODO fill in here + arraySema[SECOND_SEMA].release(); + } + } + + /** + * 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 = new CountDownLatch(2); + + // Create the ping and pong SimpleSemaphores that control + // alternation between threads. + + // TODO - You fill in here, make pingSema start out unlocked. + SimpleSemaphore pingSema = new SimpleSemaphore(1, true); + // TODO - You fill in here, make pongSema start out locked. + SimpleSemaphore pongSema = new SimpleSemaphore(0, true); + + 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 + */ + pingString, pingSema, pongSema, maxIterations); + PlayPingPongThread pong = new PlayPingPongThread(/* + * TODO - You fill in + * here + */ + pongString, pongSema, pingSema, maxIterations); + + // TODO - Initiate the ping and pong threads, which will call + // the run() hook method. + ping.start(); + pong.start(); + + // TODO - replace the following line with a barrier + // synchronizer call to mLatch that waits for both threads to + // finish. + mLatch.await(); + //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 index ca6b9d121..bfc06fde0 100644 --- a/assignments/week-4-assignment-3/src/edu/vuum/mocca/SimpleSemaphore.java +++ b/assignments/week-4-assignment-3/src/edu/vuum/mocca/SimpleSemaphore.java @@ -1,102 +1,102 @@ -package edu.vuum.mocca; - -import java.util.concurrent.locks.ReentrantLock; -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 { - /** - * Define a ReentrantLock to protect the critical section. - */ - // TODO - you fill in here - private final ReentrantLock mReentrantLock; - - /** - * Define a ConditionObject to wait while the number of - * permits is 0. - */ - // TODO - you fill in here - private final Condition mCondition;// = mReentrantLock.newCondition(); - - /** - * 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.. - private volatile int permits; - - 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. - this.permits = permits; - mReentrantLock = new ReentrantLock(fair); - mCondition = mReentrantLock.newCondition(); - } - - /** - * Acquire one permit from the semaphore in a manner that can be - * interrupted. - */ - public void acquire() throws InterruptedException { - // TODO - you fill in here. - mReentrantLock.lockInterruptibly(); - try{ - while (permits <= 0){ - mCondition.await(); - } - --permits; - } - finally{ - mReentrantLock.unlock(); - } - } - - /** - * Acquire one permit from the semaphore in a manner that cannot be - * interrupted. - */ - public void acquireUninterruptibly() { - // TODO - you fill in here. - mReentrantLock.lock(); - try{ - while (permits <= 0){ - mCondition.awaitUninterruptibly(); - } - --permits; - } - finally{ - mReentrantLock.unlock(); - } - } - - /** - * Return one permit to the semaphore. - */ - void release() { - // TODO - you fill in here. - mReentrantLock.lock(); - try{ - permits++; - mCondition.signal(); - } - finally{ - mReentrantLock.unlock(); - } - } - - /** - * Return the number of permits available. - */ - public int availablePermits() { - // TODO - you fill in here by changing null to the appropriate - // return value. - return permits; - } -} +package edu.vuum.mocca; + +import java.util.concurrent.locks.ReentrantLock; +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 { + /** + * Define a ReentrantLock to protect the critical section. + */ + // TODO - you fill in here + private final ReentrantLock mReentrantLock; + + /** + * Define a ConditionObject to wait while the number of + * permits is 0. + */ + // TODO - you fill in here + private final Condition mCondition;// = mReentrantLock.newCondition(); + + /** + * 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.. + private volatile int permits; + + 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. + this.permits = permits; + mReentrantLock = new ReentrantLock(fair); + mCondition = mReentrantLock.newCondition(); + } + + /** + * Acquire one permit from the semaphore in a manner that can be + * interrupted. + */ + public void acquire() throws InterruptedException { + // TODO - you fill in here. + mReentrantLock.lockInterruptibly(); + try{ + while (permits <= 0){ + mCondition.await(); + } + --permits; + } + finally{ + mReentrantLock.unlock(); + } + } + + /** + * Acquire one permit from the semaphore in a manner that cannot be + * interrupted. + */ + public void acquireUninterruptibly() { + // TODO - you fill in here. + mReentrantLock.lock(); + try{ + while (permits <= 0){ + mCondition.awaitUninterruptibly(); + } + --permits; + } + finally{ + mReentrantLock.unlock(); + } + } + + /** + * Return one permit to the semaphore. + */ + void release() { + // TODO - you fill in here. + mReentrantLock.lock(); + try{ + permits++; + mCondition.signal(); + } + finally{ + mReentrantLock.unlock(); + } + } + + /** + * Return the number of permits available. + */ + public int availablePermits() { + // TODO - you fill in here by changing null to the appropriate + // return value. + return permits; + } +} diff --git a/assignments/week-5-assignment-4/W5-A4-Android/.classpath b/assignments/week-5-assignment-4/W5-A4-Android/.classpath index 51769745b..1bf51fee7 100644 --- a/assignments/week-5-assignment-4/W5-A4-Android/.classpath +++ b/assignments/week-5-assignment-4/W5-A4-Android/.classpath @@ -6,4 +6,4 @@ - + \ No newline at end of file diff --git a/assignments/week-5-assignment-4/W5-A4-Android/project.properties b/assignments/week-5-assignment-4/W5-A4-Android/project.properties index a3ee5ab64..4ab125693 100644 --- a/assignments/week-5-assignment-4/W5-A4-Android/project.properties +++ b/assignments/week-5-assignment-4/W5-A4-Android/project.properties @@ -11,4 +11,4 @@ #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt # Project target. -target=android-17 +target=android-19 diff --git a/assignments/week-5-assignment-4/W5-A4-Android/src/edu/vuum/mocca/AndroidPlatformStrategy.java b/assignments/week-5-assignment-4/W5-A4-Android/src/edu/vuum/mocca/AndroidPlatformStrategy.java index bc684b5ce..2fd7994a1 100644 --- a/assignments/week-5-assignment-4/W5-A4-Android/src/edu/vuum/mocca/AndroidPlatformStrategy.java +++ b/assignments/week-5-assignment-4/W5-A4-Android/src/edu/vuum/mocca/AndroidPlatformStrategy.java @@ -47,6 +47,7 @@ public void begin() { /** (Re)initialize the CountDownLatch. */ // TODO - You fill in here. + mLatch = new CountDownLatch(NUMBER_OF_THREADS); } /** Print the outputString to the display. */ @@ -57,18 +58,31 @@ public void print(final String outputString) * and appends the outputString to a TextView. */ // TODO - You fill in here. + mActivity.get().runOnUiThread(new Runnable() { + + @Override + public void run() { + // TODO Auto-generated method stub + mTextViewOutput.append(outputString + '\n'); + } + }); } /** Indicate that a game thread has finished running. */ public void done() { // TODO - You fill in here. + mLatch.countDown(); } /** Barrier that waits for all the game threads to finish. */ public void awaitDone() { // TODO - You fill in here. + try{ + mLatch.await(); + }catch(InterruptedException e){ + } } /** diff --git a/assignments/week-5-assignment-4/W5-A4-Android/src/edu/vuum/mocca/Main.java b/assignments/week-5-assignment-4/W5-A4-Android/src/edu/vuum/mocca/Main.java index 9026c80e6..b52682b13 100644 --- a/assignments/week-5-assignment-4/W5-A4-Android/src/edu/vuum/mocca/Main.java +++ b/assignments/week-5-assignment-4/W5-A4-Android/src/edu/vuum/mocca/Main.java @@ -12,7 +12,7 @@ public class Main * The Java virtual machine requires the instantiation of a main * method to run the console version of the PlayPingPong app. */ - public static void main(String[] args) + public static void main(String[] args) { /** * Initializes the Platform singleton with the appropriate @@ -41,4 +41,4 @@ public static void main(String[] args) */ new Thread (pingPong).start(); } -} +} \ No newline at end of file diff --git a/assignments/week-5-assignment-4/W5-A4-Android/src/edu/vuum/mocca/PlayPingPong.java b/assignments/week-5-assignment-4/W5-A4-Android/src/edu/vuum/mocca/PlayPingPong.java index aa8cc4b4e..a5c506355 100644 --- a/assignments/week-5-assignment-4/W5-A4-Android/src/edu/vuum/mocca/PlayPingPong.java +++ b/assignments/week-5-assignment-4/W5-A4-Android/src/edu/vuum/mocca/PlayPingPong.java @@ -96,7 +96,7 @@ public void run() { // Data member that indicates the string to print (typically a // "ping" or a "pong"). - protected String mStringToPrint; + protected final String mStringToPrint; } /** @@ -263,7 +263,7 @@ private void formatStrings() { } private void makePingPongThreads(String schedMechanism, - PingPongThread[] pingPongThreads) { + PingPongThread[] pingPongThreads) { formatStrings(); if (schedMechanism.equals("SEMA")) { // Create the semaphores that schedule threads @@ -330,4 +330,4 @@ public void run() { /** Let the user know we're done. */ mPlatformStrategy.print("Done!"); } -} +} \ No newline at end of file diff --git a/ex/DownloadApplication/.classpath b/ex/DownloadApplication/.classpath index c06dfcb8e..51769745b 100644 --- a/ex/DownloadApplication/.classpath +++ b/ex/DownloadApplication/.classpath @@ -1,7 +1,7 @@ - + diff --git a/ex/ThreadedDownload/.classpath b/ex/ThreadedDownload/.classpath index 0b0840834..d57ec0251 100644 --- a/ex/ThreadedDownload/.classpath +++ b/ex/ThreadedDownload/.classpath @@ -1,7 +1,7 @@ - + diff --git a/grading-drivers/week-4-assignment-3/src/edu/vuum/mocca/PingPongRight.java b/grading-drivers/week-4-assignment-3/src/edu/vuum/mocca/PingPongRight.java index b2845e4e2..348559c21 100644 --- a/grading-drivers/week-4-assignment-3/src/edu/vuum/mocca/PingPongRight.java +++ b/grading-drivers/week-4-assignment-3/src/edu/vuum/mocca/PingPongRight.java @@ -37,8 +37,6 @@ public static class PlayPingPongThread extends Thread { * 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. @@ -50,6 +48,7 @@ public static class PlayPingPongThread extends Thread { * iteration. */ // TODO - You fill in here. + private String mString = null; /** * Two SimpleSemaphores use to alternate pings and pongs. You @@ -57,6 +56,8 @@ public static class PlayPingPongThread extends Thread { * two data members. */ // TODO - You fill in here. + private SimpleSemaphore mPingSemaphore = null; + private SimpleSemaphore mPongSemaphore = null; /** * Constructor initializes the data member(s). @@ -66,6 +67,10 @@ public PlayPingPongThread(String stringToPrint, SimpleSemaphore semaphoreTwo, int maxIterations) { // TODO - You fill in here. + mString = stringToPrint; + mPingSemaphore = semaphoreOne; + mPongSemaphore = semaphoreTwo; + mMaxLoopIterations = maxIterations; } /** @@ -80,6 +85,12 @@ public void run() { */ // TODO - You fill in here. + for (int i = 0; i < mMaxLoopIterations;) { + acquire(); + System.out.println(mString + "(" + ++i + ")"); + mLatch.countDown(); + release(); + } } /** @@ -87,6 +98,7 @@ public void run() { */ private void acquire() { // TODO fill in here + mPingSemaphore.acquireUninterruptibly(); } /** @@ -94,6 +106,7 @@ private void acquire() { */ private void release() { // TODO fill in here + mPongSemaphore.release(); } } @@ -108,15 +121,15 @@ public static void process(String startString, // TODO initialize this by replacing null with the appropriate // constructor call. - mLatch = null; + mLatch = new CountDownLatch(2*maxIterations); // Create the ping and pong SimpleSemaphores that control // alternation between threads. // TODO - You fill in here, make pingSema start out unlocked. - SimpleSemaphore pingSema = null; + SimpleSemaphore pingSema = new SimpleSemaphore(1, true); // TODO - You fill in here, make pongSema start out locked. - SimpleSemaphore pongSema = null; + SimpleSemaphore pongSema = new SimpleSemaphore(0, true); System.out.println(startString); @@ -125,19 +138,23 @@ public static void process(String startString, PlayPingPongThread ping = new PlayPingPongThread(/* * TODO - You fill in * here - */); + */ + "a", pingSema, pongSema, mMaxIterations); PlayPingPongThread pong = new PlayPingPongThread(/* * TODO - You fill in * here - */); + */ + "b", pongSema, pingSema, mMaxIterations); // TODO - Initiate the ping and pong threads, which will call // the run() hook method. + ping.start(); + pong.start(); // TODO - replace the following line with a barrier // synchronizer call to mLatch that waits for both threads to // finish. - throw new java.lang.InterruptedException(); + mLatch.await(); System.out.println(finishString); } @@ -155,3 +172,4 @@ public static void main(String[] args) throws InterruptedException { mMaxIterations); } } + diff --git a/grading-drivers/week-4-assignment-3/src/edu/vuum/mocca/SimpleSemaphore.java b/grading-drivers/week-4-assignment-3/src/edu/vuum/mocca/SimpleSemaphore.java index 5e473adf6..7db4fa2df 100644 --- a/grading-drivers/week-4-assignment-3/src/edu/vuum/mocca/SimpleSemaphore.java +++ b/grading-drivers/week-4-assignment-3/src/edu/vuum/mocca/SimpleSemaphore.java @@ -1,36 +1,43 @@ package edu.vuum.mocca; -import java.util.concurrent.locks.Condition; + import java.util.concurrent.locks.ReentrantLock; +import java.util.concurrent.locks.Condition; /** * @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. + * Java a ReentrantLock and a ConditionObject. 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 + private ReentrantLock mLock = null; /** - * Define a Condition that waits while the number of permits is 0. + * Define a ConditionObject to wait while the number of + * permits is 0. */ // TODO - you fill in here + private Condition mCondition = null; /** * Define a count of the number of available permits. */ - // TODO - you fill in here. Make sure that this data member will + // TODO - you fill in here. Make sure that this data member will // ensure its values aren't cached by multiple Threads.. + private volatile int mPermits; 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. + mPermits = permits; + mLock = new ReentrantLock(fair); + mCondition = mLock.newCondition(); } /** @@ -39,6 +46,15 @@ public SimpleSemaphore(int permits, boolean fair) { */ public void acquire() throws InterruptedException { // TODO - you fill in here. + mLock.lockInterruptibly(); + try { + while (mPermits == 0) { + mCondition.await(); + } + mPermits--; + } finally { + mLock.unlock(); + } } /** @@ -47,20 +63,36 @@ public void acquire() throws InterruptedException { */ public void acquireUninterruptibly() { // TODO - you fill in here. + mLock.lock(); + try { + while (mPermits == 0) { + mCondition.awaitUninterruptibly(); + } + mPermits--; + } finally { + mLock.unlock(); + } } /** * Return one permit to the semaphore. */ void release() { - // TODO - you fill in here. + mLock.lock(); + try { + mPermits++; + mCondition.signal(); + } finally { + mLock.unlock(); + } } /** * Return the number of permits available. */ public int availablePermits() { - // TODO - you fill in here to return the correct result - return 0; + // TODO - you fill in here by changing null to the appropriate + // return value. + return mPermits; } -} +} \ No newline at end of file From dc5a780099c541419c90b796bf0bcec09d372bb3 Mon Sep 17 00:00:00 2001 From: BarbeRouge Date: Sat, 5 Jul 2014 22:22:10 +0300 Subject: [PATCH 3/9] =?UTF-8?q?Copi=C3=A9=20coller=20depuis=20Doug's=20rep?= =?UTF-8?q?o=20+=20assignement?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mocca/test/DownloadActivityTests.java | 82 ++++++------ .../test/DownloadIntentServiceTests.java | 51 +++++--- .../vuum/mocca/test/DownloadUtilsTests.java | 56 ++++---- .../src/edu/vuum/mocca/test/Options.java | 13 +- .../test/ThreadPoolDownloadServiceTests.java | 57 +++++---- .../src/edu/vuum/mocca/test/Utilities.java | 19 ++- .../project.properties | 2 +- .../res/raw/dougs.jpg | Bin 0 -> 85825 bytes .../src/edu/vuum/mocca/DownloadActivity.java | 64 ++++------ .../src/edu/vuum/mocca/DownloadBase.java | 10 +- .../edu/vuum/mocca/DownloadIntentService.java | 8 +- .../src/edu/vuum/mocca/DownloadUtils.java | 120 +++++++++++++----- .../vuum/mocca/ThreadPoolDownloadService.java | 32 +++-- 13 files changed, 304 insertions(+), 210 deletions(-) create mode 100644 assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices/res/raw/dougs.jpg 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 index 036c1a155..9fbc17b86 100644 --- 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 @@ -5,6 +5,7 @@ import android.graphics.BitmapFactory; import android.test.ActivityInstrumentationTestCase2; import android.widget.EditText; +import android.view.WindowManager; import com.robotium.solo.Solo; @@ -25,7 +26,7 @@ public class DownloadActivityTests public DownloadActivityTests() { super(DownloadActivity.class); } - + /** * This is the handle for Robotium, which allows us to interact * with the UI. @@ -36,78 +37,85 @@ public DownloadActivityTests() { * 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(), getActivity()); - + 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(getActivity()); - getInstrumentation().callActivityOnResume(getActivity()); - } - - /** - * Called after each test finishes running to cleanup. - */ - public void tearDown() { - getActivity().finish(); + + getInstrumentation().callActivityOnStart(mActivity); + getInstrumentation().callActivityOnResume(mActivity); + + // Let us dismiss the lockscreen + getInstrumentation().runOnMainSync(new Runnable() { + @Override + public void run() { + getActivity().getWindow().addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD); + } + }); + + // 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 { - // Wait for things to settle - Thread.sleep(Options.SHORT_WAIT_TIME); - + // Make sure the current image isn't the one we're looking for - assertFalse(mExpected.sameAs(getActivity().mCurrentBitmap)); - + 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(getActivity().mCurrentBitmap)); + assertTrue(mExpected.sameAs(mActivity.mCurrentBitmap)); } - + /** * Push the button and see if the correct image is displayed. */ public void testIntentServiceButton() throws Exception { - - // Wait for things to settle - Thread.sleep(Options.SHORT_WAIT_TIME); - + // Make sure the current image isn't the one we're looking for - assertFalse(mExpected.sameAs(getActivity().mCurrentBitmap)); - + 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(getActivity().mCurrentBitmap)); + assertTrue(mExpected.sameAs(mActivity.mCurrentBitmap)); } -} +} \ No newline at end of file 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 index f25295090..7a148354c 100644 --- 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 @@ -3,6 +3,7 @@ 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; @@ -10,6 +11,7 @@ import android.os.Message; import android.test.ServiceTestCase; import edu.vuum.mocca.DownloadIntentService; +import edu.vuum.mocca.DownloadUtils; /** * @class DownloadIntentServiceTests @@ -40,14 +42,19 @@ public class DownloadIntentServiceTests * 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 * @@ -69,7 +76,7 @@ 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(); } @@ -81,40 +88,46 @@ public void handleMessage(Message msg) { */ 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); - + + mLatch = new CountDownLatch(1); + // Start a thread to handle the message when it's sent. new Thread(new Runnable() { public void run() { @@ -123,7 +136,7 @@ public void run() { Looper.loop(); } }).start(); - + // Wait for the handler to get instantiated Thread.sleep(Options.SHORT_WAIT_TIME); @@ -134,20 +147,16 @@ public void run() { // 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); - - // 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 image actually downloaded. - assertTrue(Utilities.checkDownloadedImage(context, mReceivedUri)); + assertTrue(Utilities.checkDownloadedImage(mContext, mReceivedUri)); } -} +} \ No newline at end of file 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 index 34979a0d4..fcfd29da3 100644 --- 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 @@ -29,7 +29,7 @@ public class DownloadUtilsTests public DownloadUtilsTests () { super (DownloadActivity.class); } - + // The intent returned by makeMessengerIntent() Intent mIntent; @@ -52,7 +52,7 @@ public DownloadUtilsTests () { * IntentService. */ static MessageHandler mHandler; - + /** * @class MessageHandler * @@ -71,16 +71,16 @@ public MessageHandler(Looper myLooper) { * 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. @@ -88,17 +88,15 @@ public void handleMessage(Message msg) { @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. */ @@ -106,37 +104,37 @@ 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() { @@ -145,22 +143,22 @@ public void run() { 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; } @@ -171,7 +169,7 @@ public void run() { */ 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() { @@ -180,25 +178,25 @@ public void run() { 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; } -} +} \ No newline at end of file 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 index 4e46918d8..acd4a1dfa 100644 --- 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 @@ -10,8 +10,9 @@ * */ public class Options { + /** - * The URL of the image we're using for testing. + * The online URL of the image we're using for testing. */ static final String TEST_URI = "https://d396qusza40orc.cloudfront.net/posa/dougs-xsmall.jpg"; @@ -20,14 +21,14 @@ public class Options { * 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 = 1000; - + static final long SHORT_WAIT_TIME = 10000; + /** * Time we should wait for things to download. */ - static final long LONG_WAIT_TIME = 5000; -} + static final long LONG_WAIT_TIME = 25000; +} \ No newline at end of file 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 index c7a7d914f..a70d00c90 100644 --- 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 @@ -3,13 +3,14 @@ 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; /** @@ -41,14 +42,19 @@ public class ThreadPoolDownloadServiceTests * 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 * @@ -70,7 +76,7 @@ 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(); } @@ -81,41 +87,46 @@ public void handleMessage(Message msg) { */ public void setUp() throws Exception{ super.setUp(); - + // Make an intent using the factory method mIntent = ThreadPoolDownloadService.makeIntent(getContext(), new Handler(), Options.TEST_URI); - Thread.sleep(Options.SHORT_WAIT_TIME); + + // 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); - + + mLatch = new CountDownLatch(1); + // Start a thread to handle the message when it's sent. new Thread(new Runnable() { public void run() { @@ -124,34 +135,32 @@ public void run() { 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); + mIntent = ThreadPoolDownloadService.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.SHORT_WAIT_TIME, TimeUnit.MILLISECONDS); - + 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 index 870182172..049bd56e5 100644 --- 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 @@ -1,5 +1,10 @@ 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; @@ -7,6 +12,7 @@ import android.os.Bundle; import android.os.Message; import android.os.Messenger; +import edu.vuum.mocca.DownloadUtils; /** * @class Utilities @@ -22,13 +28,13 @@ public class Utilities { 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; @@ -37,7 +43,7 @@ static boolean checkMessenger(Intent intent) { if (extras.get(key) instanceof Messenger) messenger = (Messenger) extras.get(key); } - + return (messenger != null); } @@ -47,7 +53,7 @@ static boolean checkMessenger(Intent intent) { static boolean checkClass(Intent intent, Class class_) { return intent.getComponent().getClassName().equals(class_.getName()); } - + /** * Check if the downloaded Bitmap is equivalent to the expected @@ -55,7 +61,7 @@ static boolean checkClass(Intent intent, Class class_) { */ 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); @@ -76,4 +82,5 @@ static String searchForPath (Message msg) { return path; } -} + +} \ No newline at end of file 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 index a3ee5ab64..4ab125693 100644 --- a/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices/project.properties +++ b/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices/project.properties @@ -11,4 +11,4 @@ #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt # Project target. -target=android-17 +target=android-19 diff --git a/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices/res/raw/dougs.jpg b/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices/res/raw/dougs.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e31e8b98b2fb6daa9874800c6d80b05b08f5bfd4 GIT binary patch literal 85825 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
M}A;-lyqQ2kFB% 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 E*#lh3 outerClass; @@ -61,30 +61,33 @@ static class MessengerHandler extends Handler { * @see https://groups.google.com/forum/#!msg/android-developers/1aPZXZG6kWk/lIYDavGYn5UJ */ public MessengerHandler(DownloadActivity outer) { - outerClass = new WeakReference(outer); + outerClass = new WeakReference(outer); } // Handle any messages that get sent to this Handler - public void handleMessage(Message msg) { + @Override + public void handleMessage(Message msg) { - // Get an actual reference to the DownloadActivity - // from the WeakReference. - DownloadActivity activity = outerClass.get(); + // Get an actual reference to the DownloadActivity + // from the WeakReference. + final DownloadActivity activity = outerClass.get(); - // If DownloadActivity hasn't been garbage collected - // (closed by user), display the sent image. - if (activity != null) { - // TODO - You fill in here to display the image - // bitmap that's been downloaded and returned to - // the DownloadActivity as a pathname that's named - // "PATHNAME". - } + // If DownloadActivity hasn't been garbage collected + // (closed by user), display the sent image. + if (activity != null) { + // TODO - You fill in here to display the image + // bitmap that's been downloaded and returned to + // the DownloadActivity as a pathname who's Bundle + // key is defined by DownloadUtils.PATHNAME_KEY + String path = msg.getData().getString(DownloadUtils.PATHNAME_KEY); + activity.displayBitmap(path); + } } } /** * Instantiate the MessengerHandler, passing in the - * DownloadActivity to help with garbage collection. + * DownloadActivity to be stored as a WeakReference */ MessengerHandler handler = new MessengerHandler(this); @@ -107,15 +110,18 @@ public void runService(View view) { // TODO - You fill in here to start the // DownloadIntentService with the appropriate Intent // returned from the makeIntent() factory method. - - which = "Starting IntentService"; + //DownloadIntentService downloadIntentService = new DownloadIntentService(name); + Intent mIntentService = DownloadIntentService.makeIntent(DownloadActivity.this, handler, getUrlString()); + startService(mIntentService); + which = "Starting DownloadIntentService"; break; case R.id.thread_pool_button: // TODO - You fill in here to start the // ThreadPoolDownloadService with the appropriate Intent // returned from the makeIntent() factory method. - + Intent mIntentThread = ThreadPoolDownloadService.makeIntent(this, handler, getUrlString()); + startService(mIntentThread); which = "Starting ThreadPoolDownloadService"; break; @@ -127,22 +133,4 @@ public void runService(View view) { which, Toast.LENGTH_SHORT).show(); } - - /** Called when this activity becomes visible after onStart(). - * Also called when the activity is un-paused. - */ - @Override - public void onResume() { - // Attach handler to looper. - super.onResume(); - } - - /** - * Called when this activity becomes partially hidden. - */ - @Override - public void onPause() { - // Remove handler from looper. - super.onPause(); - } -} +} \ No newline at end of file diff --git a/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices/src/edu/vuum/mocca/DownloadBase.java b/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices/src/edu/vuum/mocca/DownloadBase.java index ee68c4156..6521163f4 100644 --- a/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices/src/edu/vuum/mocca/DownloadBase.java +++ b/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices/src/edu/vuum/mocca/DownloadBase.java @@ -46,7 +46,7 @@ public class DownloadBase extends Activity { private ImageView mImageView; /** - * The original bitmap (used for reseting the image). + * The original bitmap (used for resetting the image). */ private Bitmap mDefaultBitmap; @@ -74,11 +74,13 @@ String getUrlString () { } /** - * Resets image to the default image stored with the program. + * Resets image to the default image stored with the program and + * reset the image default URL. */ public void resetImage(View view) { mImageView.setImageBitmap(mDefaultBitmap); mCurrentBitmap = mDefaultBitmap; + mEditText.setText(getResources().getString(R.string.default_url)); Log.d(TAG, "reset Image"); } @@ -89,7 +91,7 @@ public void resetImage(View view) { * exists. */ @Override - public void onCreate(Bundle savedInstanceState) { + public void onCreate(Bundle savedInstanceState) { Log.d(getClass().getSimpleName(), "onCreate"); super.onCreate(savedInstanceState); @@ -111,4 +113,4 @@ public void onCreate(Bundle savedInstanceState) { ((BitmapDrawable)(mImageView.getDrawable())).getBitmap(); mDefaultBitmap = mCurrentBitmap; } -} +} \ No newline at end of file diff --git a/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices/src/edu/vuum/mocca/DownloadIntentService.java b/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices/src/edu/vuum/mocca/DownloadIntentService.java index fb2733706..8d5a3da43 100644 --- a/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices/src/edu/vuum/mocca/DownloadIntentService.java +++ b/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices/src/edu/vuum/mocca/DownloadIntentService.java @@ -63,7 +63,7 @@ public static Intent makeIntent(Context context, // factory method in DownloadUtils that makes a Messenger // Intent with the appropriate parameters. - return null; + return DownloadUtils.makeMessengerIntent(context, DownloadIntentService.class, handler, uri); } /** @@ -80,10 +80,12 @@ public static Intent makeIntent(Context context, * the creation and lifecycle of a started service, but allows a * user to define what happens when an Intent is actually handled. */ + @Override protected void onHandleIntent (Intent intent) { // TODO - You fill in here with a call the appropriate helper // method from the DownloadUtils class that downloads the uri // in the intent and returns the file's pathname using a - // Messenger that's named "MESSENGER". + // Messenger who's Bundle key is defined by DownloadUtils.MESSENGER_KEY + DownloadUtils.downloadAndRespond(this, intent.getData(), (Messenger)intent.getParcelableExtra(DownloadUtils.MESSENGER_KEY)); } -} +} \ No newline at end of file diff --git a/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices/src/edu/vuum/mocca/DownloadUtils.java b/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices/src/edu/vuum/mocca/DownloadUtils.java index dc96454fb..a821d1b6e 100644 --- a/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices/src/edu/vuum/mocca/DownloadUtils.java +++ b/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices/src/edu/vuum/mocca/DownloadUtils.java @@ -7,6 +7,8 @@ import java.io.OutputStream; import java.net.URL; +import edu.vuum.mocca.R; + import android.content.Context; import android.content.Intent; import android.net.Uri; @@ -30,7 +32,26 @@ public class DownloadUtils { * Used for debugging. */ static final String TAG = "DownloadActivity"; - + + /** + * The key used to store/retrieve a Messenger extra from a Bundle. + */ + public static final String MESSENGER_KEY = "MESSENGER"; + + /** + * The key used to store/retrieve a file's pathname from a Bundle. + */ + public static final String PATHNAME_KEY = "PATHNAME"; + + /** + * If you have access to a stable Internet connection for testing + * purposes, feel free to change this variable to false so it + * actually downloads the image from a remote server. + */ + // TODO - You can change this to the appropriate setting for your + // environment. + static final boolean DOWNLOAD_OFFLINE = true; + /** * Make an Intent which will start a service if provided as a * parameter to startService(). @@ -66,7 +87,7 @@ public static Intent makeMessengerIntent(Context context, Intent intent = new Intent(context, service); - intent.putExtra("MESSENGER", + intent.putExtra(MESSENGER_KEY, messenger); intent.setData(Uri.parse(uri)); @@ -84,7 +105,7 @@ public static void sendPath (String outputPath, Messenger messenger) { Message msg = Message.obtain(); Bundle data = new Bundle(); - data.putString("PATHNAME", + data.putString(PATHNAME_KEY, outputPath); // Make the Bundle the "data" of the Message. @@ -100,8 +121,7 @@ public static void sendPath (String outputPath, /** * Download a file to the Android file system, then respond with - * the file location using the provided Messenger. Hint: use the - * other methods in this class + * the file location using the provided Messenger. */ public static void downloadAndRespond(Context context, Uri uri, @@ -110,6 +130,19 @@ public static void downloadAndRespond(Context context, uri), messenger); } + + /** + * The resource that we write to the file system in offline + * mode. Note that this must be the same image that the testing + * project expects. (found in res/drawable-nodpi and Options.java) + */ + static final int OFFLINE_TEST_IMAGE = R.raw.dougs; + + /** + * The file name that we should use to store the image in offline mode + */ + static final String OFFLINE_FILENAME = "dougs.jpg"; + /** * Download the file located at the provided internet url using * the URL class, store it on the android file system using @@ -122,27 +155,54 @@ public static void downloadAndRespond(Context context, */ public static String downloadFile (Context context, Uri uri) { + try { - // Create a temp file. - final File file = getTemporaryFile(context, - uri.toString()); - Log.d(TAG, " downloading to " + file); - - // Download the contents at the URL, which should - // reference an image. - final InputStream in = (InputStream) - new URL(uri.toString()).getContent(); - final OutputStream os = - new FileOutputStream(file); - - // Copy the contents of the downloaded image to the temp - // file. - copy(in, os); - in.close(); - os.close(); - - // Return the pathname of the temp file. - return file.getAbsolutePath(); + + // If we're offline, write the image in our resources to + // disk, then return that pathname. + if (DOWNLOAD_OFFLINE) { + + // Store the image on the file system. We can store it + // as private since the test project runs in the same + // process as the target project + FileOutputStream out = + context.openFileOutput(OFFLINE_FILENAME, 0); + + // Get a stream from the image resource + InputStream in = + context.getResources().openRawResource(OFFLINE_TEST_IMAGE); + + // Write the resource to disk. + copy(in, out); + in.close(); + out.close(); + + return context.getFilesDir().toString() + File.separator + OFFLINE_FILENAME; + } + + // Otherwise, go ahead and download the file + else { + // Create a temp file. + final File file = getTemporaryFile(context, + uri.toString()); + Log.d(TAG, " downloading to " + file); + + // Download the contents at the URL, which should + // reference an image. + final InputStream in = (InputStream) + new URL(uri.toString()).getContent(); + final OutputStream os = + new FileOutputStream(file); + + // Copy the contents of the downloaded image to the + // temp file. + copy(in, os); + in.close(); + os.close(); + + // Return the pathname of the temp file. + return file.getAbsolutePath(); + } } catch (Exception e) { Log.e(TAG, "Exception while downloading. Returning null."); Log.e(TAG, e.toString()); @@ -160,7 +220,7 @@ public static String downloadFile (Context context, * @throws IOException */ static private File getTemporaryFile(final Context context, - final String url) throws IOException { + final String url) throws IOException { // This is what you'd normally call to get a unique temporary // file, but for testing purposes we always name the file the @@ -171,7 +231,7 @@ static private File getTemporaryFile(final Context context, // + System.currentTimeMillis()); return context.getFileStreamPath(Base64.encodeToString(url.getBytes(), - Base64.NO_WRAP)); + Base64.NO_WRAP)); } /** @@ -182,8 +242,8 @@ static private File getTemporaryFile(final Context context, * @return * @throws IOException */ - static private int copy(final InputStream in, - final OutputStream out) throws IOException { + static public int copy(final InputStream in, + final OutputStream out) throws IOException { final int BUFFER_LENGTH = 1024; final byte[] buffer = new byte[BUFFER_LENGTH]; int totalRead = 0; @@ -196,4 +256,4 @@ static private int copy(final InputStream in, return totalRead; } -} +} \ No newline at end of file diff --git a/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices/src/edu/vuum/mocca/ThreadPoolDownloadService.java b/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices/src/edu/vuum/mocca/ThreadPoolDownloadService.java index 84e96ef93..2198b8b74 100644 --- a/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices/src/edu/vuum/mocca/ThreadPoolDownloadService.java +++ b/assignments/week-6-assignment-5/W6-A5-ThreadedDownloads-StartedServices/src/edu/vuum/mocca/ThreadPoolDownloadService.java @@ -9,6 +9,7 @@ import android.os.Handler; import android.os.IBinder; import android.os.Messenger; +import android.widget.ListView.FixedViewInfo; /** * @class ThreadPoolDownloadService @@ -34,7 +35,7 @@ public class ThreadPoolDownloadService extends Service { * used to service download requests. */ static final int MAX_THREADS = 4; - + /** * The ExecutorService that references a ThreadPool. */ @@ -43,12 +44,13 @@ public class ThreadPoolDownloadService extends Service { /** * Hook method called when the Service is created. */ + @Override public void onCreate() { // TODO - You fill in here to replace null with a new // FixedThreadPool Executor that's configured to use // MAX_THREADS. Use a factory method in the Executors class. - mExecutor = null; + mExecutor = Executors.newFixedThreadPool(MAX_THREADS); } /** @@ -73,27 +75,33 @@ public static Intent makeIntent(Context context, // invocation of the appropriate factory method in // DownloadUtils that makes a MessengerIntent. - return null; + return DownloadUtils.makeMessengerIntent(context, ThreadPoolDownloadService.class, handler, uri); } /** * Hook method called when a component calls startService() with * the proper Intent. */ - public int onStartCommand(Intent intent, + @Override + public int onStartCommand(final Intent intent, int flags, int startId) { - final Intent i = intent; - // TODO - You fill in here to replace null with a new Runnable // that the ThreadPoolExecutor will execute to download the // image and respond to the client. The Runnable's run() // method implementation should forward to the appropriate // helper method from the DownloadUtils class that downloads // the uri in the intent and returns the file's pathname using - // a Messenger that's named "MESSENGER". + // a Messenger who's Bundle key is defined by DownloadUtils.MESSENGER_KEY. - Runnable downloadRunnable = null; + Runnable downloadRunnable = new Runnable() { + + @Override + public void run() { + // TODO Auto-generated method stub + DownloadUtils.downloadAndRespond(ThreadPoolDownloadService.this, intent.getData(), (Messenger)intent.getParcelableExtra(DownloadUtils.MESSENGER_KEY)); + } + }; mExecutor.execute(downloadRunnable); @@ -109,7 +117,8 @@ public int onStartCommand(Intent intent, * the Service receives informing it to clean up any resources it * holds. */ - public void onDestroy() { + @Override + public void onDestroy() { // Ensure that the threads used by the ThreadPoolExecutor // complete and are reclaimed by the system. @@ -120,7 +129,8 @@ public void onDestroy() { * Return null since this class does not implement a Bound * Service. */ - public IBinder onBind (Intent intent) { + @Override + public IBinder onBind (Intent intent) { return null; } -} +} \ No newline at end of file From d92c7076ca79d168ff18ac9e3c3cd628da5a579c Mon Sep 17 00:00:00 2001 From: BarbeRouge Date: Sun, 6 Jul 2014 20:56:01 +0300 Subject: [PATCH 4/9] old ones uptodate --- .../edu/vuum/mooca/SynchronizedQueueImpl.java | 12 ++- assignments/week-2-assignment-1/.classpath | 2 +- .../src/edu/vuum/mocca/SimpleAtomicLong.java | 78 ++++++++++++++----- .../SimpleAtomicLongMultithreadedTest.java | 6 +- .../Assignment-Description.txt | 16 ++-- .../src/edu/vuum/mocca/SimpleAtomicLong.java | 78 ++++++++++++++----- .../src/edu/vuum/mocca/SimpleSemaphore.java | 59 +++++++++++--- .../vuum/mocca/PalantirManagerUnitTest.java | 47 +++-------- 8 files changed, 197 insertions(+), 101 deletions(-) diff --git a/assignments/week-1-assignment-0-v2/src/edu/vuum/mooca/SynchronizedQueueImpl.java b/assignments/week-1-assignment-0-v2/src/edu/vuum/mooca/SynchronizedQueueImpl.java index c34c74bb7..4d4010cc2 100644 --- a/assignments/week-1-assignment-0-v2/src/edu/vuum/mooca/SynchronizedQueueImpl.java +++ b/assignments/week-1-assignment-0-v2/src/edu/vuum/mooca/SynchronizedQueueImpl.java @@ -17,29 +17,35 @@ public class SynchronizedQueueImpl extends SynchronizedQueue { // TODO - change this to true if you want to see diagnostic // output on the console as the test runs. static { - diagnosticsEnabled = false; + diagnosticsEnabled = true; } protected void createThreads() { // TODO - replace the "null" assignments below to create two // Java Threads, one that's passed the mProducerRunnable and // the other that's passed the mConsumerRunnable. - mConsumer = null; - mProducer = null; + mConsumer = new Thread(mConsumerRunnable); + mProducer = new Thread(mProducerRunnable); } protected void startThreads() { // TODO - you fill in here to start the threads. More // interesting results will occur if you start the // consumer first. + mConsumer.start(); + mProducer.start(); } protected void interruptThreads() { // TODO - you fill in here to interrupt the threads. + mConsumer.interrupt(); + mProducer.interrupt(); } protected void joinThreads() throws InterruptedException { // TODO - you fill in here to wait for the threads to // exit. + mConsumer.join(); + mProducer.join(); } } diff --git a/assignments/week-2-assignment-1/.classpath b/assignments/week-2-assignment-1/.classpath index 3e0fb272a..baf9687e8 100644 --- a/assignments/week-2-assignment-1/.classpath +++ b/assignments/week-2-assignment-1/.classpath @@ -2,6 +2,6 @@ - + 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 f57064f95..26caf464c 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,5 +1,3 @@ -// Import the necessary Java synchronization and scheduling classes. - package edu.vuum.mocca; import java.util.concurrent.locks.ReentrantReadWriteLock; @@ -18,27 +16,39 @@ class SimpleAtomicLong * The value that's manipulated atomically via the methods. */ private long mValue; - - + /** * The ReentrantReadWriteLock used to serialize access to mValue. */ - // TODO - add the implementation + + // TODO -- you fill in here by replacing the null with an + // initialization of ReentrantReadWriteLock. + private ReentrantReadWriteLock mRWLock = new ReentrantReadWriteLock(); /** * 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 + this.mValue = initialValue; } /** - * @brief Gets the current value + * @brief Gets the current value. * * @returns The current value */ - public long get() { - // TODO - you fill in here + public long get() + { + long value; + + // TODO -- you fill in here + mRWLock.readLock().lock(); + value = this.mValue; + mRWLock.readLock().unlock(); + + return value; } /** @@ -46,8 +56,16 @@ public long get() { * * @returns the updated value */ - public long decrementAndGet() { - // TODO - you fill in here + public long decrementAndGet() + { + long value = 0; + + // TODO -- you fill in here + mRWLock.writeLock().lock(); + value = --mValue; + mRWLock.writeLock().unlock(); + + return value; } /** @@ -55,8 +73,16 @@ public long decrementAndGet() { * * @returns the previous value */ - public long getAndIncrement() { - // TODO - you fill in here + public long getAndIncrement() + { + long value = 0; + + // TODO -- you fill in here + mRWLock.writeLock().lock(); + value = mValue++; + mRWLock.writeLock().unlock(); + + return value; } /** @@ -64,8 +90,16 @@ public long getAndIncrement() { * * @returns the previous value */ - public long getAndDecrement() { - // TODO - you fill in here + public long getAndDecrement() + { + long value = 0; + + // TODO -- you fill in here + mRWLock.writeLock().lock(); + value = mValue--; + mRWLock.writeLock().unlock(); + + return value; } /** @@ -73,8 +107,16 @@ public long getAndDecrement() { * * @returns the updated value */ - public long incrementAndGet() { - // TODO - you fill in here + public long incrementAndGet() + { + long value = 0; + + // TODO -- you fill in here + mRWLock.writeLock().lock(); + value = ++mValue; + mRWLock.writeLock().unlock(); + + return value; } } 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 afde62c6f..401bcd63f 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,11 +41,9 @@ public class SimpleAtomicLongMultithreadedTest { static CountDownLatch mStopLatch; /** - * An instance of our implementation of SimpleAtomicLong, which is - * defined as "volatile" to ensure proper visibility of its fields - * after construction. + * An instance of our implementation of SimpleAtomicLong. */ - static volatile SimpleAtomicLong mCounter; + static 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 57c2ddf42..f3fd926c6 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 -Condition to implement a subset of the Java +ConditionObject to implement a subset of the Java java.util.concurrent.Semaphore class, which we call SimpleSemaphore. -This assignment also reuses the SimpleAtomicLong you implemented for +This assignment also reuses the SimpleAtomicLock you implemented for week-2-assignment-1, so make sure it's compiling and running properly before attempting this assignment! @@ -19,7 +19,7 @@ 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 SimpleAtomicLong are implemented properly the +the SimpleSemaphore and SimpleAtomicLock are implemented properly the test should succeed without throwing any exceptions, as described further below. @@ -36,14 +36,12 @@ 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 - motivated by watching the Virtual Office Hours video of the - instructor's solution(s). This class is only used by the + suggested by peer graders. 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: +. Implement the SimpleSemaphore class using a Java ConditionObject 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 @@ -91,7 +89,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, all the tests should complete +Test'. When the assignment is complete, 12 of 12 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 f57064f95..26caf464c 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 @@ -1,5 +1,3 @@ -// Import the necessary Java synchronization and scheduling classes. - package edu.vuum.mocca; import java.util.concurrent.locks.ReentrantReadWriteLock; @@ -18,27 +16,39 @@ class SimpleAtomicLong * The value that's manipulated atomically via the methods. */ private long mValue; - - + /** * The ReentrantReadWriteLock used to serialize access to mValue. */ - // TODO - add the implementation + + // TODO -- you fill in here by replacing the null with an + // initialization of ReentrantReadWriteLock. + private ReentrantReadWriteLock mRWLock = new ReentrantReadWriteLock(); /** * 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 + this.mValue = initialValue; } /** - * @brief Gets the current value + * @brief Gets the current value. * * @returns The current value */ - public long get() { - // TODO - you fill in here + public long get() + { + long value; + + // TODO -- you fill in here + mRWLock.readLock().lock(); + value = this.mValue; + mRWLock.readLock().unlock(); + + return value; } /** @@ -46,8 +56,16 @@ public long get() { * * @returns the updated value */ - public long decrementAndGet() { - // TODO - you fill in here + public long decrementAndGet() + { + long value = 0; + + // TODO -- you fill in here + mRWLock.writeLock().lock(); + value = --mValue; + mRWLock.writeLock().unlock(); + + return value; } /** @@ -55,8 +73,16 @@ public long decrementAndGet() { * * @returns the previous value */ - public long getAndIncrement() { - // TODO - you fill in here + public long getAndIncrement() + { + long value = 0; + + // TODO -- you fill in here + mRWLock.writeLock().lock(); + value = mValue++; + mRWLock.writeLock().unlock(); + + return value; } /** @@ -64,8 +90,16 @@ public long getAndIncrement() { * * @returns the previous value */ - public long getAndDecrement() { - // TODO - you fill in here + public long getAndDecrement() + { + long value = 0; + + // TODO -- you fill in here + mRWLock.writeLock().lock(); + value = mValue--; + mRWLock.writeLock().unlock(); + + return value; } /** @@ -73,8 +107,16 @@ public long getAndDecrement() { * * @returns the updated value */ - public long incrementAndGet() { - // TODO - you fill in here + public long incrementAndGet() + { + long value = 0; + + // TODO -- you fill in here + mRWLock.writeLock().lock(); + value = ++mValue; + mRWLock.writeLock().unlock(); + + return value; } } 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 a867818ed..7cce199eb 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 @@ -1,39 +1,43 @@ package edu.vuum.mocca; 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 (which is accessed via a Condition). It must - * implement both "Fair" and "NonFair" semaphore semantics, - * just liked Java Semaphores. + * @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 { /** - * Define a Lock to protect the critical section. + * Define a ReentrantLock to protect the critical section. */ // TODO - you fill in here + private final ReentrantLock mReentrantLock; /** - * Define a Condition that waits while the number of permits is 0. + * Define a ConditionObject to wait while the number of + * permits is 0. */ // TODO - you fill in here + private final Condition mCondition;// = mReentrantLock.newCondition(); /** * 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.. + private volatile int permits; 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. + this.permits = permits; + mReentrantLock = new ReentrantLock(fair); + mCondition = mReentrantLock.newCondition(); } /** @@ -42,6 +46,18 @@ public SimpleSemaphore(int permits, boolean fair) { */ public void acquire() throws InterruptedException { // TODO - you fill in here. + mReentrantLock.lockInterruptibly(); + try{ + while (permits <= 0){ + mReentrantLock.wait(); + } + if (permits > 0){ + permits--; + } + } + finally{ + mReentrantLock.unlock(); + } } /** @@ -50,13 +66,36 @@ public void acquire() throws InterruptedException { */ public void acquireUninterruptibly() { // TODO - you fill in here. + mReentrantLock.lock(); + try{ + while (permits <= 0){ + mReentrantLock.wait(); + } + if (permits > 0){ + permits--; + } + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + finally{ + mReentrantLock.unlock(); + } } /** * Return one permit to the semaphore. */ - public void release() { + void release() { // TODO - you fill in here. + mReentrantLock.lock(); + try{ + permits++; + mCondition.signalAll(); + } + finally{ + mReentrantLock.unlock(); + } } /** @@ -65,6 +104,6 @@ public void release() { public int availablePermits() { // TODO - you fill in here by changing null to the appropriate // return value. - return null; + return permits; } } 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 90edc858f..cfc5853a3 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,7 +1,6 @@ package edu.vuum.mocca; import static org.junit.Assert.fail; -import static org.junit.Assert.assertFalse; import java.util.ArrayList; import java.util.List; @@ -22,8 +21,8 @@ */ public class PalantirManagerUnitTest { /** - * If this is set to true in then lots of debugging output will be - * generated. + * If this is set to true in SynchronizedQueueImpl.java then lots + * of debugging output will be generated. */ public static boolean diagnosticsEnabled = false; @@ -38,11 +37,6 @@ 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. */ @@ -136,7 +130,7 @@ public void run() { if (diagnosticsEnabled) System.out.println(Thread.currentThread().getName() - + " has released the " + + " is releasing the " + palantir.name() + " palantir"); } @@ -227,44 +221,21 @@ public void testPalantirManager() { // Start all the Threads that Middle-Earth Beings use to // gaze into the Palantir. for (ListIterator iterator = palantirUsers.listIterator(); - 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(); - } + iterator.hasNext();) + iterator.next().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) { - if (diagnosticsEnabled) - System.out.println("A " - + e.getMessage() - + " Exception was thrown"); - fail("A " + fail("The Exception " + e.getMessage() - + " Exception was thrown"); + + " was thrown"); } } From 3d978ee0879a2d85a5ae363030678310da008009 Mon Sep 17 00:00:00 2001 From: BarbeRouge81 Date: Mon, 7 Jul 2014 17:37:51 +0300 Subject: [PATCH 5/9] Update AndroidManifest.xml Fixing of security issue in AndroidManifest.xml --- .../week-7-assignment-6/iRemember/AndroidManifest.xml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/assignments/week-7-assignment-6/iRemember/AndroidManifest.xml b/assignments/week-7-assignment-6/iRemember/AndroidManifest.xml index 628dc6d57..b9563bff3 100644 --- a/assignments/week-7-assignment-6/iRemember/AndroidManifest.xml +++ b/assignments/week-7-assignment-6/iRemember/AndroidManifest.xml @@ -53,11 +53,8 @@ - - - - \ No newline at end of file + From 0b3b3d00ccb6249c0b1ad2b8a1cf1f52314595ce Mon Sep 17 00:00:00 2001 From: BarbeRouge81 Date: Mon, 7 Jul 2014 17:40:55 +0300 Subject: [PATCH 6/9] Update LoginActivity.java Correcting issue with Integer usage of security level --- .../iRemember/src/edu/vuum/mocca/ui/LoginActivity.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assignments/week-7-assignment-6/iRemember/src/edu/vuum/mocca/ui/LoginActivity.java b/assignments/week-7-assignment-6/iRemember/src/edu/vuum/mocca/ui/LoginActivity.java index 6f7e8fe09..01f53fd68 100644 --- a/assignments/week-7-assignment-6/iRemember/src/edu/vuum/mocca/ui/LoginActivity.java +++ b/assignments/week-7-assignment-6/iRemember/src/edu/vuum/mocca/ui/LoginActivity.java @@ -26,7 +26,7 @@ public class LoginActivity extends StoryActivityBase{ EditText mPassword; // Make sure we use maximum security to store login credentials - static final int MAX_SECURITY = Integer.MAX_VALUE; + static final int MAX_SECURITY = StorageUtilities.SECURITY_PRIVATE; @Override protected void onCreate(Bundle savedInstanceState) { From 9056d7a79e2201f9e1ec5cc635008413d7449224 Mon Sep 17 00:00:00 2001 From: BarbeRouge Date: Mon, 7 Jul 2014 19:23:07 +0300 Subject: [PATCH 7/9] 'blabla' --- ex/GeoNamesApplication/.classpath | 2 +- ex/ThreadedDownload/.classpath | 2 +- ex/UniqueIDGeneratorApplication/.classpath | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ex/GeoNamesApplication/.classpath b/ex/GeoNamesApplication/.classpath index c06dfcb8e..51769745b 100644 --- a/ex/GeoNamesApplication/.classpath +++ b/ex/GeoNamesApplication/.classpath @@ -1,7 +1,7 @@ - + diff --git a/ex/ThreadedDownload/.classpath b/ex/ThreadedDownload/.classpath index c06dfcb8e..51769745b 100644 --- a/ex/ThreadedDownload/.classpath +++ b/ex/ThreadedDownload/.classpath @@ -1,7 +1,7 @@ - + diff --git a/ex/UniqueIDGeneratorApplication/.classpath b/ex/UniqueIDGeneratorApplication/.classpath index c06dfcb8e..51769745b 100644 --- a/ex/UniqueIDGeneratorApplication/.classpath +++ b/ex/UniqueIDGeneratorApplication/.classpath @@ -1,7 +1,7 @@ - + From 9fdffd89866eb67a890b22d94100a6ef60b6e8b8 Mon Sep 17 00:00:00 2001 From: BarbeRouge Date: Tue, 8 Jul 2014 22:27:00 +0300 Subject: [PATCH 8/9] few changes --- assignments/week-7-assignment-6/iRemember/project.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assignments/week-7-assignment-6/iRemember/project.properties b/assignments/week-7-assignment-6/iRemember/project.properties index a3ee5ab64..3409f0811 100644 --- a/assignments/week-7-assignment-6/iRemember/project.properties +++ b/assignments/week-7-assignment-6/iRemember/project.properties @@ -11,4 +11,4 @@ #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt # Project target. -target=android-17 +target=android-20 From 4f3cdf35bfe813ace63a91245b2d9a85ce529a4a Mon Sep 17 00:00:00 2001 From: BarbeRouge Date: Sun, 13 Jul 2014 22:43:12 +0300 Subject: [PATCH 9/9] sthing --- .../W8-A7-ThreadedDownloads-BoundServices/.classpath | 2 +- .../W8-A7-ThreadedDownloads-BoundServices/.classpath | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/assignments/week-8-assignment-7/W8-A7-ThreadedDownloads-BoundServices/.classpath b/assignments/week-8-assignment-7/W8-A7-ThreadedDownloads-BoundServices/.classpath index ed9fc3580..7bc01d9a9 100644 --- a/assignments/week-8-assignment-7/W8-A7-ThreadedDownloads-BoundServices/.classpath +++ b/assignments/week-8-assignment-7/W8-A7-ThreadedDownloads-BoundServices/.classpath @@ -5,5 +5,5 @@ - + diff --git a/grading-drivers/week-8-assignment-7/W8-A7-ThreadedDownloads-BoundServices/.classpath b/grading-drivers/week-8-assignment-7/W8-A7-ThreadedDownloads-BoundServices/.classpath index ed9fc3580..7bc01d9a9 100644 --- a/grading-drivers/week-8-assignment-7/W8-A7-ThreadedDownloads-BoundServices/.classpath +++ b/grading-drivers/week-8-assignment-7/W8-A7-ThreadedDownloads-BoundServices/.classpath @@ -5,5 +5,5 @@ - +