diff --git a/labs/Lab9_GraphicsLab/.gitignore b/labs/Lab9_GraphicsLab/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..ceff37eff0e621e8f96607f26a6bced4727fb5a5 --- /dev/null +++ b/labs/Lab9_GraphicsLab/.gitignore @@ -0,0 +1,39 @@ +# built application files +*.apk +*.ap_ + +# files for the dex VM +*.dex + +# Java class files +*.class + +# generated files +bin/ +gen/ + +# Local configuration file (sdk path, etc) +local.properties + +# Eclipse project files +.classpath +.settings + +# Proguard folder generated by Eclipse +proguard/ + +# Intellij project files +*.iml +*.ipr +*.iws +.idea +.idea/workspace.xml +.gradle +build/ +captures/ + +# Mac files +.DS_Store + +# Windows thumbnail db +Thumbs.db diff --git a/labs/Lab9_GraphicsLab/GraphicsLabVideo.mp4 b/labs/Lab9_GraphicsLab/GraphicsLabVideo.mp4 new file mode 100644 index 0000000000000000000000000000000000000000..a26b994f2230840e9e0cc021b6977f01fc76b9ef Binary files /dev/null and b/labs/Lab9_GraphicsLab/GraphicsLabVideo.mp4 differ diff --git a/labs/Lab9_GraphicsLab/Lab9-GraphicsLab.pdf b/labs/Lab9_GraphicsLab/Lab9-GraphicsLab.pdf new file mode 100644 index 0000000000000000000000000000000000000000..f4aa796267993339457cc48cc68ede2ac683d9e2 Binary files /dev/null and b/labs/Lab9_GraphicsLab/Lab9-GraphicsLab.pdf differ diff --git a/labs/Lab9_GraphicsLab/app/build.gradle b/labs/Lab9_GraphicsLab/app/build.gradle new file mode 100644 index 0000000000000000000000000000000000000000..c6294a10110afb209dadc9536d8b6c0c5f410181 --- /dev/null +++ b/labs/Lab9_GraphicsLab/app/build.gradle @@ -0,0 +1,32 @@ +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply plugin: 'kotlin-android-extensions' + +android { + compileSdkVersion 26 + buildToolsVersion '29.0.3' + + defaultConfig { + applicationId "course.labs.graphicslab" + minSdkVersion 21 + targetSdkVersion 26 + + testApplicationId "course.labs.graphicslab.tests" + testInstrumentationRunner "android.test.InstrumentationTestRunner" + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt' + } + } +} + +dependencies { + androidTestImplementation 'com.jayway.android.robotium:robotium-solo:5.6.3' + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} +repositories { + mavenCentral() +} diff --git a/labs/Lab9_GraphicsLab/app/src/androidTest/java/course/labs/graphicslab/tests/BubbleActivityFloatOffScreen.kt b/labs/Lab9_GraphicsLab/app/src/androidTest/java/course/labs/graphicslab/tests/BubbleActivityFloatOffScreen.kt new file mode 100644 index 0000000000000000000000000000000000000000..af7cef58fa2e0a0f9984bf00c8b719e7e6d0d86d --- /dev/null +++ b/labs/Lab9_GraphicsLab/app/src/androidTest/java/course/labs/graphicslab/tests/BubbleActivityFloatOffScreen.kt @@ -0,0 +1,64 @@ +package course.labs.graphicslab.tests + +import course.labs.graphicslab.BubbleActivity + +import com.robotium.solo.* +import android.test.ActivityInstrumentationTestCase2 +import junit.framework.Assert +import kotlin.jvm.Throws + +class BubbleActivityFloatOffScreen : ActivityInstrumentationTestCase2<BubbleActivity>(BubbleActivity::class.java) { + private var solo: Solo? = null + + @Throws(Exception::class) + public override fun setUp() { + solo = Solo(instrumentation, activity) + } + + @Throws(Exception::class) + public override fun tearDown() { + solo!!.finishOpenedActivities() + } + + fun testRun() { + + val shortDelay = 250 + val delay = 2000 + + // Wait for activity: 'course.labs.TouchLab.BubbleActivity' + solo!!.waitForActivity(course.labs.graphicslab.BubbleActivity::class.java, + delay) + + // Click on action bar item + solo!!.clickOnMenuItem("Single Speed Mode") + + // Click on action bar item + solo!!.clickOnMenuItem("Add a Bubble") + + // Check whether bubble appears + var bubbleAppeared = solo!!.getCurrentViews<course.labs.graphicslab.BubbleActivity.BubbleView>( + course.labs.graphicslab.BubbleActivity.BubbleView::class.java).size > 0 + var i = 0 + while (i < 8 && !bubbleAppeared) { + solo!!.sleep(shortDelay) + bubbleAppeared = solo!!.getCurrentViews<course.labs.graphicslab.BubbleActivity.BubbleView>( + course.labs.graphicslab.BubbleActivity.BubbleView::class.java) + .size > 0 + i++ + } + + // Assert that a bubble was displayed + Assert.assertTrue("Bubble hasn't appeared", bubbleAppeared) + + solo!!.sleep(delay) + + // Assert that the bubble has left the screen + Assert.assertEquals( + "Bubble hasn't left the screen", + 0, + solo!!.getCurrentViews<course.labs.graphicslab.BubbleActivity.BubbleView>( + course.labs.graphicslab.BubbleActivity.BubbleView::class.java) + .size) + + } +} diff --git a/labs/Lab9_GraphicsLab/app/src/androidTest/java/course/labs/graphicslab/tests/BubbleActivityMultiple.kt b/labs/Lab9_GraphicsLab/app/src/androidTest/java/course/labs/graphicslab/tests/BubbleActivityMultiple.kt new file mode 100644 index 0000000000000000000000000000000000000000..02933a269018b657ed620ec77f0110171c6fa449 --- /dev/null +++ b/labs/Lab9_GraphicsLab/app/src/androidTest/java/course/labs/graphicslab/tests/BubbleActivityMultiple.kt @@ -0,0 +1,61 @@ +package course.labs.graphicslab.tests + +import course.labs.graphicslab.BubbleActivity + +import com.robotium.solo.* +import android.test.ActivityInstrumentationTestCase2 +import junit.framework.Assert +import kotlin.jvm.Throws + +class BubbleActivityMultiple : ActivityInstrumentationTestCase2<BubbleActivity>(BubbleActivity::class.java) { + private var solo: Solo? = null + + @Throws(Exception::class) + public override fun setUp() { + solo = Solo(instrumentation, activity) + } + + @Throws(Exception::class) + public override fun tearDown() { + solo!!.finishOpenedActivities() + } + + fun testRun() { + + val delay = 2000 + + // Wait for activity: 'course.labs.TouchLab.BubbleActivity' + solo!!.waitForActivity(course.labs.graphicslab.BubbleActivity::class.java, delay) + + // Set Still Mode + solo!!.clickOnMenuItem("Still Mode") + + // Click on action bar item + solo!!.clickOnMenuItem("Add a Bubble") + + solo!!.sleep(delay) + + // Assert that a bubble was displayed + Assert.assertEquals("Bubble hasn't appeared", 1, solo!!.getCurrentViews<course.labs.graphicslab.BubbleActivity.BubbleView>(course.labs.graphicslab.BubbleActivity.BubbleView::class.java).size) + + // Click on action bar item + solo!!.clickOnMenuItem("Add a Bubble") + + solo!!.sleep(delay) + + // Assert that a bubble was displayed + Assert.assertEquals("Second bubble hasn't appeared", 2, solo!!.getCurrentViews<course.labs.graphicslab.BubbleActivity.BubbleView>(course.labs.graphicslab.BubbleActivity.BubbleView::class.java).size) + + solo!!.sleep(delay) + + // Give misbehaving bubbles a chance to move off screen + // Assert that there are two bubbles on the screen + Assert.assertEquals( + "There should be two bubbles on the screen", + 2, + solo!!.getCurrentViews<course.labs.graphicslab.BubbleActivity.BubbleView>( + course.labs.graphicslab.BubbleActivity.BubbleView::class.java) + .size) + + } +} diff --git a/labs/Lab9_GraphicsLab/app/src/androidTest/java/course/labs/graphicslab/tests/BubbleActivityPop.kt b/labs/Lab9_GraphicsLab/app/src/androidTest/java/course/labs/graphicslab/tests/BubbleActivityPop.kt new file mode 100644 index 0000000000000000000000000000000000000000..e149c1371a6cb83e9c4e324140c53100a8af7b2b --- /dev/null +++ b/labs/Lab9_GraphicsLab/app/src/androidTest/java/course/labs/graphicslab/tests/BubbleActivityPop.kt @@ -0,0 +1,61 @@ +package course.labs.graphicslab.tests + +import course.labs.graphicslab.BubbleActivity + +import com.robotium.solo.* +import android.test.ActivityInstrumentationTestCase2 +import junit.framework.Assert +import kotlin.jvm.Throws + +class BubbleActivityPop : ActivityInstrumentationTestCase2<BubbleActivity>(BubbleActivity::class.java) { + private var solo: Solo? = null + + @Throws(Exception::class) + public override fun setUp() { + solo = Solo(instrumentation, activity) + } + + @Throws(Exception::class) + public override fun tearDown() { + solo!!.finishOpenedActivities() + } + + fun testRun() { + + val delay = 2000 + + // Wait for activity: 'course.labs.TouchLab.BubbleActivity' + solo!!.waitForActivity(course.labs.graphicslab.BubbleActivity::class.java, + delay) + + // Set Still Mode + solo!!.clickOnMenuItem("Still Mode") + + // Click on action bar item + solo!!.clickOnMenuItem("Add a Bubble") + + solo!!.sleep(delay) + + // Assert that a bubble was displayed + Assert.assertEquals( + "Bubble hasn't appeared", + 1, + solo!!.getCurrentViews<course.labs.graphicslab.BubbleActivity.BubbleView>( + course.labs.graphicslab.BubbleActivity.BubbleView::class.java) + .size) + + // Click on action bar item + solo!!.clickOnMenuItem("Delete a Bubble") + + solo!!.sleep(delay) + + // Assert that there are no more bubbles + Assert.assertEquals( + "The bubble was not popped", + 0, + solo!!.getCurrentViews<course.labs.graphicslab.BubbleActivity.BubbleView>( + course.labs.graphicslab.BubbleActivity.BubbleView::class.java) + .size) + + } +} diff --git a/labs/Lab9_GraphicsLab/app/src/androidTest/res/.gitignore b/labs/Lab9_GraphicsLab/app/src/androidTest/res/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/labs/Lab9_GraphicsLab/app/src/main/AndroidManifest.xml b/labs/Lab9_GraphicsLab/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000000000000000000000000000000000000..896fe6c02f37c131ab6edafdbc115ca1369e868d --- /dev/null +++ b/labs/Lab9_GraphicsLab/app/src/main/AndroidManifest.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="course.labs.graphicslab" + android:versionCode="1" + android:versionName="1.0" > + + + <application + android:allowBackup="false" + android:icon="@mipmap/icon" + android:label="@string/app_name" > + + <activity + android:name=".BubbleActivity" + android:label="@string/app_name" + android:theme="@android:style/Theme.NoTitleBar.Fullscreen" > + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + </application> + +</manifest> \ No newline at end of file diff --git a/labs/Lab9_GraphicsLab/app/src/main/java/course/labs/graphicslab/BubbleActivity.kt b/labs/Lab9_GraphicsLab/app/src/main/java/course/labs/graphicslab/BubbleActivity.kt new file mode 100644 index 0000000000000000000000000000000000000000..e864ca428f06b7b5e0d4582a048024df151bb596 --- /dev/null +++ b/labs/Lab9_GraphicsLab/app/src/main/java/course/labs/graphicslab/BubbleActivity.kt @@ -0,0 +1,353 @@ +package course.labs.graphicslab + +import java.util.Random +import java.util.concurrent.Executors +import java.util.concurrent.ScheduledExecutorService +import java.util.concurrent.ScheduledFuture +import java.util.concurrent.TimeUnit + +import android.app.Activity +import android.content.Context +import android.graphics.Bitmap +import android.graphics.BitmapFactory +import android.graphics.Canvas +import android.graphics.Paint +import android.media.AudioAttributes +import android.media.AudioManager +import android.media.SoundPool +import android.media.SoundPool.OnLoadCompleteListener +import android.os.Bundle +import android.util.Log +import android.view.GestureDetector +import android.view.Menu +import android.view.MenuItem +import android.view.MotionEvent +import android.view.View +import android.widget.RelativeLayout + +class BubbleActivity : Activity() { + + // The Main view + private var mFrame: RelativeLayout? = null + + // Bubble image's bitmap + private var mBitmap: Bitmap? = null + + // Display dimensions + private var mDisplayWidth: Int = 0 + private var mDisplayHeight: Int = 0 + + // Sound variables + + // AudioManager + private var mAudioManager: AudioManager? = null + // SoundPool + private var mSoundPool: SoundPool? = null + // ID for the bubble popping sound + private var mSoundID: Int = 0 + // Audio volume + private var mStreamVolume: Float = 0.toFloat() + + public override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + setContentView(R.layout.main) + + // Set up user interface + mFrame = findViewById<View>(R.id.frame) as RelativeLayout + + // Load basic bubble Bitmap + mBitmap = BitmapFactory.decodeResource(resources, R.drawable.b64) + + } + + override fun onResume() { + super.onResume() + + // Manage bubble popping sound + // Use AudioManager.STREAM_MUSIC as stream type + + mAudioManager = getSystemService(Context.AUDIO_SERVICE) as AudioManager + + mStreamVolume = mAudioManager!! + .getStreamVolume(AudioManager.STREAM_MUSIC).toFloat() / mAudioManager!!.getStreamMaxVolume(AudioManager.STREAM_MUSIC) + + val musicAttribute = AudioAttributes.Builder() + .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC) + .build() + + mSoundPool = SoundPool.Builder() + .setMaxStreams(10) + .setAudioAttributes(musicAttribute) + .build() + + mSoundID = mSoundPool!!.load(this, R.raw.bubble_pop, 1) + + } + + override fun onWindowFocusChanged(hasFocus: Boolean) { + super.onWindowFocusChanged(hasFocus) + if (hasFocus) { + + // Get the size of the display so this View knows where borders are + mDisplayWidth = mFrame!!.width + mDisplayHeight = mFrame!!.height + + } + } + + override fun onPause() { + mSoundPool!!.unload(mSoundID) + mSoundPool!!.release() + mSoundPool = null + super.onPause() + } + + // BubbleView is a View that displays a bubble. + // This class handles animating, drawing, and popping amongst other actions. + // A new BubbleView is created for each bubble on the display + + inner class BubbleView internal constructor(context: Context, x: Float, y: Float) : View(context) { + private val mPainter = Paint() + private var mMoverFuture: ScheduledFuture<*>? = null + private var mScaledBitmapWidth: Int = 0 + private val mScaledBitmap: Bitmap? = null + + // location, speed and direction of the bubble + private val mXPos: Float + private val mYPos: Float + private var mDx: Float = 0.toFloat() + private var mDy: Float = 0.toFloat() + private val mRadius: Float + private val mRadiusSquared: Float + private val mRotate: Long = 0 + private var mDRotate: Long = 0 + + // Return true if the BubbleView is still on the screen after the move + // operation + private// TODO - Return true if the BubbleView is still on the screen after + // the move operation + val isOutOfView: Boolean + get() = false + + init { + Log.i(TAG, "Creating Bubble at: x:$x y:$y") + + // Create a new random number generator to + // randomize size, rotation, speed and direction + val r = Random() + + // Creates the bubble bitmap for this BubbleView + createScaledBitmap(r) + + // Radius of the Bitmap + mRadius = (mScaledBitmapWidth / 2).toFloat() + mRadiusSquared = mRadius * mRadius + + // Adjust position to center the bubble under user's finger + mXPos = x - mRadius + mYPos = y - mRadius + + // Set the BubbleView's speed and direction + setSpeedAndDirection(r) + + // Set the BubbleView's rotation + setRotation(r) + + mPainter.isAntiAlias = true + + } + + private fun setRotation(r: Random) { + + if (speedMode == RANDOM) { + + // TODO - set rotation in range [1..3] + mDRotate = 0 + + } else { + + mDRotate = 0 + + } + } + + private fun setSpeedAndDirection(r: Random) { + + // Used by test cases + when (speedMode) { + + SINGLE -> { + + mDx = 40f + mDy = 40f + } + + STILL -> { + + // No speed + mDx = 0f + mDy = 0f + } + }// TODO - Set movement direction and speed + // Limit movement speed in the x and y + // direction to [-3..3] pixels per movement. + } + + private fun createScaledBitmap(r: Random) { + + if (speedMode != RANDOM) { + mScaledBitmapWidth = BITMAP_SIZE * 3 + } else { + + // TODO - set scaled bitmap size in range [1..3] * BITMAP_SIZE + + } + + // TODO - create the scaled bitmap using size set above + + } + + // Start moving the BubbleView & updating the display + private fun start() { + + // Creates a WorkerThread + val executor = Executors + .newScheduledThreadPool(1) + + // Execute the run() in Worker Thread every REFRESH_RATE + // milliseconds + // Save reference to this job in mMoverFuture + mMoverFuture = executor.scheduleWithFixedDelay({ + // TODO - implement movement logic. + // Each time this method is run the BubbleView should + // move one step. If the BubbleView exits the display, + // stop the BubbleView's Worker Thread. + // Otherwise, request that the BubbleView be redrawn. + }, 0, REFRESH_RATE.toLong(), TimeUnit.MILLISECONDS) + } + + // Cancel the Bubble's movement + // Remove Bubble from mFrame + // Play pop sound if the BubbleView was popped + + private fun stop(wasPopped: Boolean) { + + if (null != mMoverFuture) { + + if (!mMoverFuture!!.isDone) { + mMoverFuture!!.cancel(true) + } + + // This work will be performed on the UI Thread + mFrame!!.post { + // TODO - Remove the BubbleView from mFrame + + + // If the bubble was popped by user, + // play the popping sound and Log that pop was performed + if (wasPopped) { + Log.i(TAG, "Pop!") + mSoundPool!!.play(mSoundID, mStreamVolume, + mStreamVolume, 1, 0, 1.0f) + } + Log.i(TAG, "Bubble removed from view!") + } + } + } + + // Draw the Bubble at its current location + @Synchronized + override fun onDraw(canvas: Canvas) { + + // TODO - save the canvas + + // TODO - increase the rotation of the original image by mDRotate + + // TODO Rotate the canvas by current rotation + // Hint - Rotate around the bubble's center, not its position + + + // TODO - draw the bitmap at it's new location + + // TODO - restore the canvas + + } + + // Returns true if the BubbleView is still on the screen after the move + // operation + @Synchronized + private fun moveWhileOnScreen(): Boolean { + + // TODO - Move the BubbleView + + + return isOutOfView + + } + + } + + override fun onBackPressed() { + openOptionsMenu() + } + + override fun onCreateOptionsMenu(menu: Menu): Boolean { + super.onCreateOptionsMenu(menu) + + menuInflater.inflate(R.menu.menu, menu) + + return true + } + + override fun onOptionsItemSelected(item: MenuItem): Boolean { + // TODO- Handle addition and deletion of bubbles from options menu + // Added bubbles should be given random locations. + // The bubble to delete is the most recently added bubble + // that is still in the frame. + + // Hint: You can get all Views in mFrame using the + // ViewGroup.getChildCount() method + when (item.itemId) { + R.id.menu_add_bubble -> + + return true + R.id.menu_delete_bubble -> + + return true + R.id.menu_still_mode -> { + speedMode = STILL + return true + } + R.id.menu_single_speed -> { + speedMode = SINGLE + return true + } + R.id.menu_random_mode -> { + speedMode = RANDOM + return true + } + R.id.quit -> { + exitRequested() + return true + } + else -> return super.onOptionsItemSelected(item) + } + } + + private fun exitRequested() { + super.onBackPressed() + } + + companion object { + + // These variables are for testing purposes, do not modify + private val RANDOM = 0 + private val SINGLE = 1 + private val STILL = 2 + private var speedMode = RANDOM + private val BITMAP_SIZE = 64 + private val REFRESH_RATE = 40 + private val TAG = "Lab-Graphics" + } +} \ No newline at end of file diff --git a/labs/Lab9_GraphicsLab/app/src/main/res/drawable/b128.png b/labs/Lab9_GraphicsLab/app/src/main/res/drawable/b128.png new file mode 100644 index 0000000000000000000000000000000000000000..7845514160501a2c864bf1386154b2280e1332cd Binary files /dev/null and b/labs/Lab9_GraphicsLab/app/src/main/res/drawable/b128.png differ diff --git a/labs/Lab9_GraphicsLab/app/src/main/res/drawable/b64.png b/labs/Lab9_GraphicsLab/app/src/main/res/drawable/b64.png new file mode 100644 index 0000000000000000000000000000000000000000..7101a2580a251dde3fce5fbd6867a3fc5cf48222 Binary files /dev/null and b/labs/Lab9_GraphicsLab/app/src/main/res/drawable/b64.png differ diff --git a/labs/Lab9_GraphicsLab/app/src/main/res/layout/main.xml b/labs/Lab9_GraphicsLab/app/src/main/res/layout/main.xml new file mode 100644 index 0000000000000000000000000000000000000000..363f5813cfa28da30cb1b227c305602362ff4962 --- /dev/null +++ b/labs/Lab9_GraphicsLab/app/src/main/res/layout/main.xml @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="utf-8"?> +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="fill_parent" + android:layout_height="fill_parent" + android:background="#FF444444" + android:id="@+id/frame"> + +</RelativeLayout> \ No newline at end of file diff --git a/labs/Lab9_GraphicsLab/app/src/main/res/menu/menu.xml b/labs/Lab9_GraphicsLab/app/src/main/res/menu/menu.xml new file mode 100644 index 0000000000000000000000000000000000000000..23678d87e061c2123bfac2bc3136a3770f456154 --- /dev/null +++ b/labs/Lab9_GraphicsLab/app/src/main/res/menu/menu.xml @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="utf-8"?> +<menu xmlns:android="http://schemas.android.com/apk/res/android" > + <item android:id="@+id/menu_add_bubble" android:title="@string/add_bubble_string"></item> + <item android:id="@+id/menu_delete_bubble" android:title="@string/delete_bubble_string"></item> + <item android:id="@+id/menu_still_mode" android:title="@string/still_mode_string"></item> + <item android:id="@+id/menu_single_speed" android:title="@string/single_speed_mode_string"></item> + <item android:id="@+id/menu_random_mode" android:title="@string/random_speed_mode_string"></item> + <item android:id="@+id/quit" android:title="@string/quit_string"></item> +</menu> diff --git a/labs/Lab9_GraphicsLab/app/src/main/res/mipmap-hdpi/icon.png b/labs/Lab9_GraphicsLab/app/src/main/res/mipmap-hdpi/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..8074c4c571b8cd19e27f4ee5545df367420686d7 Binary files /dev/null and b/labs/Lab9_GraphicsLab/app/src/main/res/mipmap-hdpi/icon.png differ diff --git a/labs/Lab9_GraphicsLab/app/src/main/res/mipmap-ldpi/icon.png b/labs/Lab9_GraphicsLab/app/src/main/res/mipmap-ldpi/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..1095584ec21f71cd0afc9e0993aa2209671b590c Binary files /dev/null and b/labs/Lab9_GraphicsLab/app/src/main/res/mipmap-ldpi/icon.png differ diff --git a/labs/Lab9_GraphicsLab/app/src/main/res/mipmap-mdpi/icon.png b/labs/Lab9_GraphicsLab/app/src/main/res/mipmap-mdpi/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..a07c69fa5a0f4da5d5efe96eea12a543154dbab6 Binary files /dev/null and b/labs/Lab9_GraphicsLab/app/src/main/res/mipmap-mdpi/icon.png differ diff --git a/labs/Lab9_GraphicsLab/app/src/main/res/raw/bubble_pop.wav b/labs/Lab9_GraphicsLab/app/src/main/res/raw/bubble_pop.wav new file mode 100644 index 0000000000000000000000000000000000000000..50886e247e01f246e57f388ee4b15f66c47979fb Binary files /dev/null and b/labs/Lab9_GraphicsLab/app/src/main/res/raw/bubble_pop.wav differ diff --git a/labs/Lab9_GraphicsLab/app/src/main/res/values/strings.xml b/labs/Lab9_GraphicsLab/app/src/main/res/values/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..e5534cfe6c420bc4cebd5e34c05324f2164e0395 --- /dev/null +++ b/labs/Lab9_GraphicsLab/app/src/main/res/values/strings.xml @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <string name="app_name">GraphicsLab</string> + <string name="still_mode_string">Still Mode</string> + <string name="single_speed_mode_string">Single Speed Mode</string> + <string name="random_speed_mode_string">Random Speed Mode</string> + <string name="quit_string">Quit</string> + <string name="add_bubble_string">Add a Bubble</string> + <string name="delete_bubble_string">Delete a Bubble</string> +</resources> diff --git a/labs/Lab9_GraphicsLab/build.gradle b/labs/Lab9_GraphicsLab/build.gradle new file mode 100644 index 0000000000000000000000000000000000000000..7fd901d0cff7f2f011618e0c8521c0cf4d551109 --- /dev/null +++ b/labs/Lab9_GraphicsLab/build.gradle @@ -0,0 +1,19 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. +buildscript { + ext.kotlin_version = '1.4.10' + repositories { + jcenter() + google() + } + dependencies { + classpath 'com.android.tools.build:gradle:4.0.1' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + jcenter() + google() + } +} diff --git a/labs/Lab9_GraphicsLab/gradle/wrapper/gradle-wrapper.jar b/labs/Lab9_GraphicsLab/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..13372aef5e24af05341d49695ee84e5f9b594659 Binary files /dev/null and b/labs/Lab9_GraphicsLab/gradle/wrapper/gradle-wrapper.jar differ diff --git a/labs/Lab9_GraphicsLab/gradle/wrapper/gradle-wrapper.properties b/labs/Lab9_GraphicsLab/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000000000000000000000000000000000000..715fda21a5a5c67504364d677ad5fc87b7c61721 --- /dev/null +++ b/labs/Lab9_GraphicsLab/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Wed Oct 21 03:07:10 EDT 2020 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip diff --git a/labs/Lab9_GraphicsLab/gradlew b/labs/Lab9_GraphicsLab/gradlew new file mode 100755 index 0000000000000000000000000000000000000000..9d82f78915133e1c35a6ea51252590fb38efac2f --- /dev/null +++ b/labs/Lab9_GraphicsLab/gradlew @@ -0,0 +1,160 @@ +#!/usr/bin/env bash + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn ( ) { + echo "$*" +} + +die ( ) { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; +esac + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules +function splitJvmOpts() { + JVM_OPTS=("$@") +} +eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS +JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" + +exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/labs/Lab9_GraphicsLab/gradlew.bat b/labs/Lab9_GraphicsLab/gradlew.bat new file mode 100644 index 0000000000000000000000000000000000000000..8a0b282aa6885fb573c106b3551f7275c5f17e8e --- /dev/null +++ b/labs/Lab9_GraphicsLab/gradlew.bat @@ -0,0 +1,90 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windowz variants + +if not "%OS%" == "Windows_NT" goto win9xME_args +if "%@eval[2+2]" == "4" goto 4NT_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* +goto execute + +:4NT_args +@rem Get arguments from the 4NT Shell from JP Software +set CMD_LINE_ARGS=%$ + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/labs/Lab9_GraphicsLab/settings.gradle b/labs/Lab9_GraphicsLab/settings.gradle new file mode 100644 index 0000000000000000000000000000000000000000..e7b4def49cb53d9aa04228dd3edb14c9e635e003 --- /dev/null +++ b/labs/Lab9_GraphicsLab/settings.gradle @@ -0,0 +1 @@ +include ':app'