Skip to content
Snippets Groups Projects
Commit 6b940be7 authored by Andrej Rasevic's avatar Andrej Rasevic
Browse files

adding Graphics Lab

parent 0db90b14
No related branches found
No related tags found
No related merge requests found
Showing
with 681 additions and 0 deletions
# 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
File added
File added
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()
}
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)
}
}
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)
}
}
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)
}
}
<?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
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
labs/Lab9_GraphicsLab/app/src/main/res/drawable/b128.png

24.9 KiB

labs/Lab9_GraphicsLab/app/src/main/res/drawable/b64.png

7.99 KiB

<?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
<?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>
labs/Lab9_GraphicsLab/app/src/main/res/mipmap-hdpi/icon.png

4.05 KiB

labs/Lab9_GraphicsLab/app/src/main/res/mipmap-ldpi/icon.png

1.68 KiB

labs/Lab9_GraphicsLab/app/src/main/res/mipmap-mdpi/icon.png

2.51 KiB

File added
<?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>
// 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()
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment