diff --git a/labs/Lab11_LocationLab/.gitignore b/labs/Lab11_LocationLab/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..ceff37eff0e621e8f96607f26a6bced4727fb5a5 --- /dev/null +++ b/labs/Lab11_LocationLab/.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/Lab11_LocationLab/LocationLab.pdf b/labs/Lab11_LocationLab/LocationLab.pdf new file mode 100644 index 0000000000000000000000000000000000000000..d42f5b58f4068dd54f64b31bbee1a4d691de969d Binary files /dev/null and b/labs/Lab11_LocationLab/LocationLab.pdf differ diff --git a/labs/Lab11_LocationLab/app/build.gradle b/labs/Lab11_LocationLab/app/build.gradle new file mode 100644 index 0000000000000000000000000000000000000000..0ce26a38291b1235eae24dcf5c8a7da1d39946fc --- /dev/null +++ b/labs/Lab11_LocationLab/app/build.gradle @@ -0,0 +1,43 @@ +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply plugin: 'kotlin-android-extensions' + +android { + compileSdkVersion 26 + buildToolsVersion '27.0.3' + + defaultConfig { + applicationId "course.labs.locationlab" + minSdkVersion 21 + targetSdkVersion 26 + + testApplicationId "course.labs.locationlab.test" + testInstrumentationRunner "android.test.InstrumentationTestRunner" + testInstrumentationRunner 'android.support.test.runner.AndroidJUnitRunner' + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt' + } + } +} + +dependencies { + androidTestImplementation 'com.jayway.android.robotium:robotium-solo:5.6.3' + androidTestImplementation 'com.android.support.test:rules:1.0.2' + androidTestImplementation 'com.android.support.test.uiautomator:uiautomator-v18:2.1.3' + implementation 'com.android.support:support-annotations:28.0.0' + implementation 'com.android.support:support-v4:26.1.0' + implementation 'com.android.support:support-core-utils:26.1.0' + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} + +configurations.all { + resolutionStrategy.force 'com.android.support:support-annotations:26.0.0' +} +repositories { + mavenCentral() +} + diff --git a/labs/Lab11_LocationLab/app/gradle/wrapper/gradle-wrapper.jar b/labs/Lab11_LocationLab/app/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..f6b961fd5a86aa5fbfe90f707c3138408be7c718 Binary files /dev/null and b/labs/Lab11_LocationLab/app/gradle/wrapper/gradle-wrapper.jar differ diff --git a/labs/Lab11_LocationLab/app/gradle/wrapper/gradle-wrapper.properties b/labs/Lab11_LocationLab/app/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000000000000000000000000000000000000..2254882d6a9c8f8986af6daff6d59a5a9aea3fc7 --- /dev/null +++ b/labs/Lab11_LocationLab/app/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +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 \ No newline at end of file diff --git a/labs/Lab11_LocationLab/app/gradlew b/labs/Lab11_LocationLab/app/gradlew new file mode 100644 index 0000000000000000000000000000000000000000..cccdd3d517fc5249beaefa600691cf150f2fa3e6 --- /dev/null +++ b/labs/Lab11_LocationLab/app/gradlew @@ -0,0 +1,172 @@ +#!/usr/bin/env sh + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# 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 + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +# 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 +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +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" -a "$nonstop" = "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 + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi + +exec "$JAVACMD" "$@" diff --git a/labs/Lab11_LocationLab/app/gradlew.bat b/labs/Lab11_LocationLab/app/gradlew.bat new file mode 100644 index 0000000000000000000000000000000000000000..f9553162f122c71b34635112e717c3e733b5b212 --- /dev/null +++ b/labs/Lab11_LocationLab/app/gradlew.bat @@ -0,0 +1,84 @@ +@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 + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@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= + +@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 Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_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=%* + +: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/Lab11_LocationLab/app/libs/robotium-solo-5.2.1.jar b/labs/Lab11_LocationLab/app/libs/robotium-solo-5.2.1.jar new file mode 100644 index 0000000000000000000000000000000000000000..2875fc4de9de5172a9d0f9f6faa7da1a11fcce79 Binary files /dev/null and b/labs/Lab11_LocationLab/app/libs/robotium-solo-5.2.1.jar differ diff --git a/labs/Lab11_LocationLab/app/src/androidTest/java/course/labs/locationlab/tests/PermGrantedTest.kt b/labs/Lab11_LocationLab/app/src/androidTest/java/course/labs/locationlab/tests/PermGrantedTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..9e238246541d2bf98e52a03adadf7728b3b3f564 --- /dev/null +++ b/labs/Lab11_LocationLab/app/src/androidTest/java/course/labs/locationlab/tests/PermGrantedTest.kt @@ -0,0 +1,64 @@ +package course.labs.locationlab.tests + +import android.content.Intent +import android.support.test.InstrumentationRegistry +import android.support.test.filters.SdkSuppress +import android.support.test.runner.AndroidJUnit4 +import android.support.test.uiautomator.By +import android.support.test.uiautomator.UiDevice +import android.support.test.uiautomator.Until +import org.hamcrest.CoreMatchers +import org.junit.Assert +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +@SdkSuppress(minSdkVersion = 21) +class PermGrantedTest { + private var mDevice: UiDevice? = null + @Before + fun startMainActivityFromHomeScreen() { + // Initialize UiDevice instance + mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) + + // Start from the home screen + mDevice?.pressHome() + + // Wait for launcher + val launcherPackage = mDevice?.launcherPackageName + Assert.assertThat(launcherPackage, CoreMatchers.`is`(CoreMatchers.notNullValue())) + mDevice?.wait(Until.hasObject(By.pkg(launcherPackage).depth(0)), + LAUNCH_TIMEOUT.toLong()) + + // Launch the app + val context = InstrumentationRegistry.getContext() + val intent = context.packageManager + .getLaunchIntentForPackage(BASIC_SAMPLE_PACKAGE) + if (null == intent) Assert.fail() + + // Clear out any previous instances + intent!!.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK) + context.startActivity(intent) + + // Wait for the app to appear + mDevice?.wait(Until.hasObject(By.pkg(BASIC_SAMPLE_PACKAGE).depth(0)), + LAUNCH_TIMEOUT.toLong()) + //Give permission if it is not given already + // + val permissionDialog = mDevice?.wait(Until.findObject(By.text("Allow only while using the app")), 2000) + permissionDialog?.click() + } + + @Test + fun testPermissionRequested() { + val getNewPlace = mDevice!!.wait(Until.findObject(By.text("Get New Place")), 2000) + Assert.assertNotNull("Permission wasn't granted", getNewPlace) + getNewPlace.click() + } + + companion object { + private const val LAUNCH_TIMEOUT = 10000 + private const val BASIC_SAMPLE_PACKAGE = "course.labs.locationlab" + } +} \ No newline at end of file diff --git a/labs/Lab11_LocationLab/app/src/androidTest/java/course/labs/locationlab/tests/TestNoCountryLocation.kt b/labs/Lab11_LocationLab/app/src/androidTest/java/course/labs/locationlab/tests/TestNoCountryLocation.kt new file mode 100644 index 0000000000000000000000000000000000000000..7f05a303a0532dc61d83f6dbeb41b45a78eb0b7a --- /dev/null +++ b/labs/Lab11_LocationLab/app/src/androidTest/java/course/labs/locationlab/tests/TestNoCountryLocation.kt @@ -0,0 +1,41 @@ +package course.labs.locationlab.tests + +import android.test.ActivityInstrumentationTestCase2 +import com.robotium.solo.Solo +import course.labs.locationlab.PlaceViewActivity +import course.labs.locationlab.R + +class TestNoCountryLocation : ActivityInstrumentationTestCase2<PlaceViewActivity>(PlaceViewActivity::class.java) { + private var solo: Solo? = null + @Throws(Exception::class) + public override fun setUp() { + solo = Solo(instrumentation, activity) + PlaceViewActivity.sHasNetwork = false + } + + @Throws(Exception::class) + public override fun tearDown() { + solo!!.finishOpenedActivities() + } + + fun testRun() { + val delay = 2000 + val longDelay = 5000 + + // Wait for activity: 'course.labs.locationlab.PlaceViewActivity' + solo!!.waitForActivity(PlaceViewActivity::class.java, + delay) + + // Click on action bar item + solo!!.clickOnActionBarItem(R.id.place_no_country) + solo!!.sleep(delay) + + // Click on Get New Place + solo!!.clickOnView(solo!!.getView(R.id.footer)) + val noCountryString = solo!!.getString(R.string.no_country_string) + + // Assert that no country toast is shown + assertTrue("$noCountryString is not shown!", + solo!!.waitForText(noCountryString, 1, longDelay.toLong())) + } +} \ No newline at end of file diff --git a/labs/Lab11_LocationLab/app/src/androidTest/java/course/labs/locationlab/tests/TestOneValidLocation.kt b/labs/Lab11_LocationLab/app/src/androidTest/java/course/labs/locationlab/tests/TestOneValidLocation.kt new file mode 100644 index 0000000000000000000000000000000000000000..d35297528ddebe0450257307d7b88a4c19249e9d --- /dev/null +++ b/labs/Lab11_LocationLab/app/src/androidTest/java/course/labs/locationlab/tests/TestOneValidLocation.kt @@ -0,0 +1,45 @@ +package course.labs.locationlab.tests + +import android.test.ActivityInstrumentationTestCase2 +import com.robotium.solo.Solo +import course.labs.locationlab.PlaceViewActivity +import course.labs.locationlab.R + +class TestOneValidLocation : ActivityInstrumentationTestCase2<PlaceViewActivity>(PlaceViewActivity::class.java) { + private var solo: Solo? = null + @Throws(Exception::class) + public override fun setUp() { + solo = Solo(instrumentation, activity) + PlaceViewActivity.sHasNetwork = false + } + + @Throws(Exception::class) + public override fun tearDown() { + solo!!.finishOpenedActivities() + } + + fun testRun() { + val delay = 5000 + val longDelay = 8000 + + // Wait for activity: 'course.labs.locationlab.PlaceViewActivity' + solo!!.waitForActivity(PlaceViewActivity::class.java, + 2000) + + // Click on action bar item + solo!!.clickOnActionBarItem(R.id.place_one) + solo!!.sleep(delay) + + // Click on Get New Place + solo!!.clickOnView(solo!!.getView(R.id.footer)) + + // Assert that PlaceBadge is shown + assertTrue("PlaceBadge is not shown!", solo!!.waitForText( + solo!!.getString(R.string.the_greenhouse_string), 1, longDelay.toLong())) + // Click on PlaceBadge + + solo!!.clickOnText(solo!!.getString(R.string.the_greenhouse_string)) + solo!!.sleep(10000) + assertTrue("Detail view not shown!", solo!!.waitForText("Date")) + } +} \ No newline at end of file diff --git a/labs/Lab11_LocationLab/app/src/androidTest/java/course/labs/locationlab/tests/TestSameLocation.kt b/labs/Lab11_LocationLab/app/src/androidTest/java/course/labs/locationlab/tests/TestSameLocation.kt new file mode 100644 index 0000000000000000000000000000000000000000..ab42c0d81f259f1db438a2fbbe4c6a77dcffa1bc --- /dev/null +++ b/labs/Lab11_LocationLab/app/src/androidTest/java/course/labs/locationlab/tests/TestSameLocation.kt @@ -0,0 +1,53 @@ +package course.labs.locationlab.tests + +import android.test.ActivityInstrumentationTestCase2 +import com.robotium.solo.Solo +import course.labs.locationlab.PlaceViewActivity +import course.labs.locationlab.R + +class TestSameLocation : ActivityInstrumentationTestCase2<PlaceViewActivity>(PlaceViewActivity::class.java) { + private var solo: Solo? = null + @Throws(Exception::class) + public override fun setUp() { + solo = Solo(instrumentation, activity) + PlaceViewActivity.sHasNetwork = false + } + + @Throws(Exception::class) + public override fun tearDown() { + solo!!.finishOpenedActivities() + } + + fun testRun() { + val delay = 2000 + val longDelay = 5000 + + // Wait for activity: 'course.labs.locationlab.PlaceViewActivity' + solo!!.waitForActivity(PlaceViewActivity::class.java, delay) + + // Click on action bar item + solo!!.clickOnActionBarItem(R.id.place_one) + solo!!.sleep(delay) + + // Click on Get New Place + solo!!.clickOnView(solo!!.getView(R.id.footer)) + solo!!.sleep(2000) + + // Assert that PlaceBadge is shown + assertTrue("PlaceBadge is not shown!", solo!!.waitForText( + solo!!.getString(R.string.the_greenhouse_string), 1, longDelay.toLong())) + + // Click on action bar item + solo!!.clickOnActionBarItem(R.id.place_one) + solo!!.sleep(delay) + + // Click on Get New Place + solo!!.clickOnView(solo!!.getView(R.id.footer)) + val samePlaceString = solo!! + .getString(R.string.duplicate_location_string) + + // Assert that duplicate location Toast is shown + assertTrue("$samePlaceString is not shown!", + solo!!.waitForText(samePlaceString, 1, longDelay.toLong())) + } +} \ No newline at end of file diff --git a/labs/Lab11_LocationLab/app/src/androidTest/java/course/labs/locationlab/tests/TestTwoValidLocations.kt b/labs/Lab11_LocationLab/app/src/androidTest/java/course/labs/locationlab/tests/TestTwoValidLocations.kt new file mode 100644 index 0000000000000000000000000000000000000000..05df91042c6cb999971c4b1c59d36cce0e801b14 --- /dev/null +++ b/labs/Lab11_LocationLab/app/src/androidTest/java/course/labs/locationlab/tests/TestTwoValidLocations.kt @@ -0,0 +1,60 @@ +package course.labs.locationlab.tests + +import android.test.ActivityInstrumentationTestCase2 +import com.robotium.solo.Solo +import course.labs.locationlab.PlaceViewActivity +import course.labs.locationlab.R +import org.junit.Test + +class TestTwoValidLocations : ActivityInstrumentationTestCase2<PlaceViewActivity>(PlaceViewActivity::class.java) { + private var solo: Solo? = null + @Throws(Exception::class) + public override fun setUp() { + solo = Solo(instrumentation, activity) + PlaceViewActivity.sHasNetwork = false + } + + @Throws(Exception::class) + public override fun tearDown() { + solo!!.finishOpenedActivities() + } + + @Test + fun testRun() { + val delay = 2000 + val longDelay = 5000 + + // Wait for activity: 'course.labs.locationlab.PlaceViewActivity' + solo!!.waitForActivity(PlaceViewActivity::class.java, + 2000) + + // Click on action bar item + solo!!.clickOnActionBarItem(R.id.place_one) + solo!!.sleep(delay) + + // Click on Get New Place + solo!!.clickOnView(solo!!.getView(R.id.footer)) + solo!!.sleep(delay) + + // Assert that PlaceBadge is shown + assertTrue("PlaceBadge is not shown!", solo!!.waitForText( + solo!!.getString(R.string.the_greenhouse_string), 1, longDelay.toLong())) + + // Click on action bar item + solo!!.clickOnActionBarItem(R.id.place_two) + solo!!.sleep(delay) + + // Click on Get New Place + solo!!.clickOnView(solo!!.getView(R.id.footer)) + solo!!.sleep(delay) + + // Assert that PlaceBadge is shown + assertTrue("PlaceBadge is not shown!", solo!!.waitForText( + solo!!.getString(R.string.berwyn_string), 1, longDelay.toLong())) + + // Click on PlaceBadge + solo!!.clickOnText(solo!!.getString(R.string.berwyn_string)) + solo!!.sleep(delay) + assertTrue("Detail view not shown!", solo!!.waitForText("Date")) + } +} \ No newline at end of file diff --git a/labs/Lab11_LocationLab/app/src/androidTest/res/drawable/.gitignore b/labs/Lab11_LocationLab/app/src/androidTest/res/drawable/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/labs/Lab11_LocationLab/app/src/main/AndroidManifest.xml b/labs/Lab11_LocationLab/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000000000000000000000000000000000000..6de5d0e769760cd1471aff9aa5b782febb94853f --- /dev/null +++ b/labs/Lab11_LocationLab/app/src/main/AndroidManifest.xml @@ -0,0 +1,40 @@ +<?xml version="1.0" encoding="utf-8"?> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + package="course.labs.locationlab" + android:versionCode="1" + android:versionName="1.0" > + + <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> + <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> + <uses-permission android:name="android.permission.INTERNET" /> + <uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION" + tools:ignore="MockLocation,ProtectedPermissions"></uses-permission> + + + <uses-sdk + android:minSdkVersion="21" + android:targetSdkVersion="26" /> + + <application + android:allowBackup="true" + android:icon="@drawable/ic_launcher" + android:label="@string/app_name" + android:theme="@style/AppTheme" > + <activity + android:name="course.labs.locationlab.PlaceViewActivity" + android:label="@string/app_name" > + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + <activity + android:name="course.labs.locationlab.PlaceBadgeDetailActivity" + android:label="@string/badge_detail" > + </activity> + + </application> + +</manifest> \ No newline at end of file diff --git a/labs/Lab11_LocationLab/app/src/main/java/course/labs/locationlab/MockLocationProvider.kt b/labs/Lab11_LocationLab/app/src/main/java/course/labs/locationlab/MockLocationProvider.kt new file mode 100644 index 0000000000000000000000000000000000000000..8cad8e4af16c865223d699edd30736e90c42095e --- /dev/null +++ b/labs/Lab11_LocationLab/app/src/main/java/course/labs/locationlab/MockLocationProvider.kt @@ -0,0 +1,41 @@ +package course.labs.locationlab + +import android.os.SystemClock +import android.content.Context +import android.location.Location +import android.location.LocationManager +import android.util.Log + +// Adapted from code found at: +// http://mobiarch.wordpress.com/2012/07/17/testing-with-mock-location-data-in-android/ + +class MockLocationProvider(private val mProviderName: String, ctx: Context) { + + private val mLocationManager: LocationManager = ctx + .getSystemService(Context.LOCATION_SERVICE) as LocationManager + + fun pushLocation(lat: Double, lon: Double) { + val mockLocation = Location(mProviderName) + mockLocation.latitude = lat + mockLocation.longitude = lon + mockLocation.altitude = 0.0 + mockLocation.time = System.currentTimeMillis() + mockLocation.elapsedRealtimeNanos = SystemClock.elapsedRealtimeNanos() + mockLocation.accuracy = 5f + mLocationManager.setTestProviderLocation(mProviderName, mockLocation) + } + + fun shutdown() { + mLocationManager.removeTestProvider(mProviderName) + } + + init { + try { + mLocationManager.addTestProvider(mProviderName, false, false, false, + false, true, true, true, 0, 5) + } catch (e: IllegalArgumentException) { + // ignore + } + mLocationManager.setTestProviderEnabled(mProviderName, true) + } +} \ No newline at end of file diff --git a/labs/Lab11_LocationLab/app/src/main/java/course/labs/locationlab/PlaceBadgeDetailActivity.kt b/labs/Lab11_LocationLab/app/src/main/java/course/labs/locationlab/PlaceBadgeDetailActivity.kt new file mode 100644 index 0000000000000000000000000000000000000000..aabf099a9f70eea2ea2e3b081fc72a48a2bfd67a --- /dev/null +++ b/labs/Lab11_LocationLab/app/src/main/java/course/labs/locationlab/PlaceBadgeDetailActivity.kt @@ -0,0 +1,16 @@ +package course.labs.locationlab + +import android.app.Activity +import android.content.Intent +import android.os.Bundle +import android.view.View +import android.widget.ImageView +import android.widget.TextView + +class PlaceBadgeDetailActivity : Activity() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + // TODO - implement the Activity + + } +} \ No newline at end of file diff --git a/labs/Lab11_LocationLab/app/src/main/java/course/labs/locationlab/PlaceDownloaderTask.kt b/labs/Lab11_LocationLab/app/src/main/java/course/labs/locationlab/PlaceDownloaderTask.kt new file mode 100644 index 0000000000000000000000000000000000000000..c45fb5be85b9216fc5aa541b51d9ddac7f364a85 --- /dev/null +++ b/labs/Lab11_LocationLab/app/src/main/java/course/labs/locationlab/PlaceDownloaderTask.kt @@ -0,0 +1,208 @@ +package course.labs.locationlab + +import android.graphics.Bitmap +import android.graphics.BitmapFactory +import android.location.Location +import android.location.LocationManager +import android.os.AsyncTask +import android.util.Log +import org.w3c.dom.DOMException +import org.xml.sax.InputSource +import org.xml.sax.SAXException +import java.io.* +import java.lang.ref.WeakReference +import java.net.HttpURLConnection +import java.net.MalformedURLException +import java.net.URL +import java.util.* +import javax.xml.parsers.DocumentBuilder +import javax.xml.parsers.DocumentBuilderFactory +import javax.xml.parsers.ParserConfigurationException + +class PlaceDownloaderTask(parent: PlaceViewActivity?, hasNetwork: Boolean) : AsyncTask<Location?, Void?, PlaceRecord?>() { + // False if you don't have network access + private var mHasNetwork = false + private val mParent: WeakReference<PlaceViewActivity?> + + override fun doInBackground(vararg location: Location?): PlaceRecord? { + var place: PlaceRecord? + if (mHasNetwork) { + + // Get the PlaceBadge information + place = getPlaceFromURL(generateURL(USERNAME, location[0]!!)) + place.location = location[0] + if ("" !== place.countryName) { + place.flagBitmap = getFlagFromURL(place.flagUrl) + } else { + place.flagBitmap = sStubBitmap + } + } else { + place = PlaceRecord() + place.location = location[0] + place.flagBitmap = sStubBitmap + if (place.intersects(sMockLoc1)) { + place.countryName = sMockCountryName1 + place.place = sMockPlaceName1 + } else if (place.intersects(sMockLoc2)) { + place.countryName = sMockCountryName1 + place.place = sMockPlaceName2 + } else { + place.countryName = sMockCountryNameInvalid + place.place = sMockPlaceNameInvalid + } + } + return place + } + + override fun onPostExecute(result: PlaceRecord?) { + if (null != result && null != mParent.get()) { + mParent.get()!!.addNewPlace(result) + } + } + + private fun getPlaceFromURL(vararg params: String): PlaceRecord { + var result: String? = null + var bufferedReader: BufferedReader? = null + try { + val url = URL(params[0]) + mHttpUrl = url.openConnection() as HttpURLConnection + bufferedReader = BufferedReader(InputStreamReader( + mHttpUrl!!.inputStream)) + val sb = StringBuffer("") + var line = bufferedReader.readLine() + + while (line != null) { + sb.append(""" $line""".trimIndent() + "\n") + line = bufferedReader.readLine() + } + result = sb.toString() + } catch (e: MalformedURLException) { + } catch (e: IOException) { + } finally { + try { + bufferedReader?.close() + } catch (e: IOException) { + e.printStackTrace() + } + mHttpUrl!!.disconnect() + } + return placeDataFromXml(result) + } + + companion object { + // TODO - set your www.geonames.org account name as USERNAME. + private const val USERNAME = "YOUR_USER_NAME" + private val sMockLoc1 = Location( + LocationManager.NETWORK_PROVIDER) + private val sMockLoc2 = Location( + LocationManager.NETWORK_PROVIDER) + private val sMockLoc3 = Location( + LocationManager.NETWORK_PROVIDER) + private var sMockCountryName1: String? = null + private var sMockCountryNameInvalid: String? = null + private var sMockPlaceName1: String? = null + private var sMockPlaceName2: String? = null + private var sMockPlaceNameInvalid: String? = null + private var sStubBitmap: Bitmap? = null + private var mHttpUrl: HttpURLConnection? = null + + private fun placeDataFromXml(xmlString: String?): PlaceRecord { + val builder: DocumentBuilder + var countryName = "" + var countryCode = "" + var placeName = "" + val factory = DocumentBuilderFactory.newInstance() + try { + builder = factory.newDocumentBuilder() + val document = builder.parse(InputSource(StringReader( + xmlString))) + val list = document.documentElement.childNodes + for (i in 0 until list.length) { + val curr = list.item(i) + val list2 = curr.childNodes + for (j in 0 until list2.length) { + val curr2 = list2.item(j) + if (curr2.nodeName != null) { + if (curr2.nodeName == "countryName") { + countryName = curr2.textContent + } else if (curr2.nodeName == "countryCode") { + countryCode = curr2.textContent + } else if (curr2.nodeName == "name") { + placeName = curr2.textContent + } + } + } + } + } catch (e: DOMException) { + e.printStackTrace() + } catch (e: ParserConfigurationException) { + e.printStackTrace() + } catch (e: SAXException) { + e.printStackTrace() + } catch (e: IOException) { + e.printStackTrace() + } + return PlaceRecord(generateFlagURL(countryCode.toLowerCase(Locale.US)), + countryName, placeName) + } + + private fun generateURL(username: String, location: Location): String { + return ("http://www.geonames.org/findNearbyPlaceName?username=" + + username + "&style=full&lat=" + location.latitude + + "&lng=" + location.longitude) + } + + private fun generateFlagURL(countryCode: String): String { + return "https://flagpedia.net/data/flags/small/${countryCode.toLowerCase(Locale.ROOT)}.png" + } + + fun getFlagFromURL(flagUrl: String?): Bitmap? { + + if (flagUrl == null){ + return null + } + var `in`: InputStream? = null + Log.i("temp", flagUrl) + try { + val url = URL(flagUrl) + mHttpUrl = url.openConnection() as HttpURLConnection + `in` = mHttpUrl!!.inputStream + return BitmapFactory.decodeStream(`in`) + } catch (e: MalformedURLException) { + Log.e("DEBUG", e.toString()) + } catch (e: IOException) { + Log.e("DEBUG", e.toString()) + } finally { + try { + `in`?.close() + } catch (e: IOException) { + e.printStackTrace() + } + mHttpUrl!!.disconnect() + } + return null + } + + } + + init { + mParent = WeakReference(parent) + mHasNetwork = hasNetwork + if (null != parent) { + sStubBitmap = BitmapFactory.decodeResource(parent.resources, + R.drawable.stub) + sMockLoc1.latitude = 37.422 + sMockLoc1.longitude = -122.084 + sMockCountryName1 = parent + .getString(R.string.mock_name_united_states_string) + sMockPlaceName1 = parent.getString(R.string.the_greenhouse_string) + sMockLoc2.latitude = 38.996667 + sMockLoc2.longitude = -76.9275 + sMockPlaceName2 = parent.getString(R.string.berwyn_string) + sMockLoc3.latitude = 0.0 + sMockLoc3.longitude = 0.0 + sMockCountryNameInvalid = "" + sMockPlaceNameInvalid = "" + } + } +} \ No newline at end of file diff --git a/labs/Lab11_LocationLab/app/src/main/java/course/labs/locationlab/PlaceRecord.kt b/labs/Lab11_LocationLab/app/src/main/java/course/labs/locationlab/PlaceRecord.kt new file mode 100644 index 0000000000000000000000000000000000000000..076dd4741ef6f02f01ae9cd43be8fd0811f1fefb --- /dev/null +++ b/labs/Lab11_LocationLab/app/src/main/java/course/labs/locationlab/PlaceRecord.kt @@ -0,0 +1,50 @@ +package course.labs.locationlab + +import android.content.Intent +import android.graphics.Bitmap +import android.location.Location +import java.util.* + +class PlaceRecord { + var flagUrl: String? = null + var countryName: String? = null + var place: String? = null + var flagBitmap: Bitmap? = null + var location: Location? = null + var dateVisited: Date? = null + + constructor(flagUrl: String?, country: String?, place: String?) { + this.flagUrl = flagUrl + this.countryName = country + this.place = place + } + constructor(){} + constructor(intent: Intent) { + flagUrl = intent.getStringExtra("mFlagUrl") + countryName = intent.getStringExtra("mCountryName") + place = intent.getStringExtra("mPlaceName") + location = intent.getParcelableExtra("mLocation") as? Location + dateVisited = intent.getSerializableExtra("mDateVisited") as? Date + flagBitmap = intent.getParcelableExtra("mFlagBitmap") as? Bitmap + } + + fun packageToIntent(): Intent { + val intent = Intent() + intent.putExtra("mFlagUrl", flagUrl) + intent.putExtra("mCountryName", countryName) + intent.putExtra("mPlaceName", place) + intent.putExtra("mLocation", location) + intent.putExtra("mDateVisited", dateVisited) + intent.putExtra("mFlagBitmap", flagBitmap) + return intent + } + + fun intersects(newLocation: Location?): Boolean { + val tolerance = 1000.0 + return location!!.distanceTo(newLocation) <= tolerance + } + + override fun toString(): String { + return "Place: $place Country: $countryName" + } +} \ No newline at end of file diff --git a/labs/Lab11_LocationLab/app/src/main/java/course/labs/locationlab/PlaceViewActivity.kt b/labs/Lab11_LocationLab/app/src/main/java/course/labs/locationlab/PlaceViewActivity.kt new file mode 100644 index 0000000000000000000000000000000000000000..6ff83c8059e1caa8e978c5fc3e9685020b9cd57e --- /dev/null +++ b/labs/Lab11_LocationLab/app/src/main/java/course/labs/locationlab/PlaceViewActivity.kt @@ -0,0 +1,228 @@ +package course.labs.locationlab + +import android.app.ListActivity +import android.content.Intent +import android.content.pm.PackageManager +import android.location.Location +import android.location.LocationListener +import android.location.LocationManager +import android.os.Build +import android.os.Bundle +import android.support.v4.app.ActivityCompat +import android.support.v4.content.ContextCompat +import android.util.Log +import android.view.Menu +import android.view.MenuItem +import android.widget.AdapterView.OnItemClickListener +import android.widget.Toast +import java.util.* + +class PlaceViewActivity : ListActivity(), LocationListener { + private var mLastLocationReading: Location? = null + private var mAdapter: PlaceViewAdapter? = null + + // default minimum time between new readings + private val mMinTime: Long = 5000 + + // default minimum distance between old and new readings. + private val mMinDistance = 1000.0f + private var mLocationManager: LocationManager? = null + + // A fake location provider used for testing + private var mMockLocationProvider: MockLocationProvider? = null + private var mockLocationOn = false + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + // Set up the app's user interface + // This class is a ListActivity, so it has its own ListView + // ListView's adapter should be a PlaceViewAdapter + + // TODO - acquire reference to the LocationManager + + val placesListView = listView + + // TODO - Set an OnItemClickListener on the ListView placesListView to open a detail view when the user + // clicks on a Place Badge. + + + val footerView = layoutInflater.inflate(R.layout.footer_view, + placesListView, false) + ?: return + + + // TODO - When the footerView's onClick() method is called, it must + // issue the + // following log call + // Log.i(TAG,"Entered footerView.OnClickListener.onClick()"); + + // footerView must respond to user clicks. + // Must handle 3 cases: + // 1) The current location is new - download new Place Badge. Issue the + // following log call: + // Log.i(TAG,"Starting Place Download"); + + // 2) The current location has been seen before - issue Toast message. + // Issue the following log call: + // Log.i(TAG,"You already have this location badge"); + + // 3) There is no current location - response is up to you. The best + // solution is to disable the footerView until you have a location. + // Issue the following log call: + // Log.i(TAG,"Location data is not available"); + + placesListView.addFooterView(footerView) + mAdapter = PlaceViewAdapter(applicationContext) + listAdapter = mAdapter + } + + override fun onResume() { + super.onResume() + if (Build.VERSION.SDK_INT >= 23 && + ContextCompat.checkSelfPermission(applicationContext, "android.permission.ACCESS_FINE_LOCATION") != PackageManager.PERMISSION_GRANTED + || ContextCompat.checkSelfPermission(applicationContext, "android.permission.ACCESS_COARSE_LOCATION") != PackageManager.PERMISSION_GRANTED) { + ActivityCompat.requestPermissions(this@PlaceViewActivity, arrayOf("android.permission.ACCESS_FINE_LOCATION", + "android.permission.ACCESS_COARSE_LOCATION"), + MY_PERMISSIONS_LOCATION) + } else getLocationUpdates() + } + + private fun getLocationUpdates(){ + try { + startMockLocationManager() + + // TODO - Check NETWORK_PROVIDER and GPS_PROVIDER for an existing + // location reading. + // Only keep this last reading if it is fresh - less than 5 minutes old. + + + // TODO - register to receive location updates from NETWORK_PROVIDER + + } catch (e: SecurityException) { + Log.d(TAG, e.localizedMessage) + } + } + + override fun onPause() { + shutdownMockLocationManager() + // TODO - unregister for location updates + + super.onPause() + } + + // Callback method used by PlaceDownloaderTask + fun addNewPlace(place: PlaceRecord) { + Log.i(TAG, "Entered addNewPlace()") + if (place.countryName.isNullOrEmpty()) { + showToast(getString(R.string.no_country_string)) + } else if (!mAdapter!!.intersects(place.location)) { + place.dateVisited = Date() + mAdapter!!.add(place) + mAdapter!!.notifyDataSetChanged() + } else { + showToast(getString(R.string.duplicate_location_string)) + } + } + + override fun onLocationChanged(currentLocation: Location) { + + // TODO - Handle location updates + // Cases to consider + // 1) If there is no last location, keep the current location. + // 2) If the current location is older than the last location, ignore + // the current location + // 3) If the current location is newer than the last locations, keep the + // current location. + + } + + override fun onProviderDisabled(provider: String) { + // not implemented + } + + override fun onProviderEnabled(provider: String) { + // not implemented + } + + override fun onStatusChanged(provider: String, status: Int, extras: Bundle) { + // not implemented + } + + override fun onCreateOptionsMenu(menu: Menu): Boolean { + val inflater = menuInflater + inflater.inflate(R.menu.main, menu) + return true + } + + override fun onOptionsItemSelected(item: MenuItem): Boolean { + return when (item.itemId) { + R.id.delete_badges -> { + mAdapter!!.removeAllViews() + true + } + R.id.place_one -> { + mMockLocationProvider!!.pushLocation(37.422, -122.084) + true + } + R.id.place_no_country -> { + mMockLocationProvider!!.pushLocation(0.0, 0.0) + true + } + R.id.place_two -> { + mMockLocationProvider!!.pushLocation(38.996667, -76.9275) + true + } + else -> super.onOptionsItemSelected(item) + } + } + + private fun showToast(toast: String) { + Toast.makeText(this@PlaceViewActivity, toast, Toast.LENGTH_LONG) + .show() + } + + private fun shutdownMockLocationManager() { + Log.i(TAG, "shut: shutcalled"); + if (mockLocationOn) { + Log.i(TAG, "shut: shutcalled in side if"); + mMockLocationProvider!!.shutdown() + mockLocationOn = false + } + } + + private fun startMockLocationManager() { + if (!mockLocationOn) { + mMockLocationProvider = MockLocationProvider( + LocationManager.NETWORK_PROVIDER, this) + mockLocationOn = true + } + } + + override fun onRequestPermissionsResult(requestCode: Int, + permissions: Array<String>, grantResults: IntArray) { + when (requestCode) { + MY_PERMISSIONS_LOCATION -> { + var g = 0 + Log.d(TAG, "Perm?: " + permissions.size + " -? " + grantResults.size) + for (perm in permissions) Log.d(TAG, "Perm: " + perm + " --> " + grantResults[g++]) + if (grantResults.isNotEmpty() + && grantResults[0] == PackageManager.PERMISSION_GRANTED) getLocationUpdates() else { + Log.i(TAG, "Permission was not granted to access location") + finish() + } + } + } + } + + companion object { + private const val FIVE_MINS = 5 * 60 * 1000.toLong() + private const val TAG = "Lab-Location" + var INTENT_DATA = "course.labs.locationlab.placerecord.IntentData" + + // False if you don't have network access + @JvmField + var sHasNetwork = true + const val MY_PERMISSIONS_LOCATION = 4 + } +} \ No newline at end of file diff --git a/labs/Lab11_LocationLab/app/src/main/java/course/labs/locationlab/PlaceViewAdapter.kt b/labs/Lab11_LocationLab/app/src/main/java/course/labs/locationlab/PlaceViewAdapter.kt new file mode 100644 index 0000000000000000000000000000000000000000..6d7695f71407a6e4e75bee13a5cd512942b29ca7 --- /dev/null +++ b/labs/Lab11_LocationLab/app/src/main/java/course/labs/locationlab/PlaceViewAdapter.kt @@ -0,0 +1,81 @@ +package course.labs.locationlab + +import android.content.Context +import android.location.Location +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.BaseAdapter +import android.widget.ImageView +import android.widget.TextView +import java.util.* + +class PlaceViewAdapter(mContext: Context) : BaseAdapter() { + + private val list = ArrayList<PlaceRecord>() + + override fun getCount(): Int { + return list.size + } + + override fun getItem(position: Int): Any { + return list[position] + } + + override fun getItemId(position: Int): Long { + return position.toLong() + } + + override fun getView(position: Int, convertView: View?, parent: ViewGroup): View? { + var newView = convertView + val holder: ViewHolder + val curr = list[position] + if (null == convertView) { + holder = ViewHolder() + newView = inflater!!.inflate(R.layout.place_badge_view, parent, false) + holder.flag = newView.findViewById<View>(R.id.flag) as ImageView + holder.country = newView.findViewById<View>(R.id.country_name) as TextView + holder.place = newView.findViewById<View>(R.id.place_name) as TextView + newView.tag = holder + } else { + holder = newView?.tag as ViewHolder + } + holder.flag!!.setImageBitmap(curr.flagBitmap) + holder.country?.text = curr.countryName + holder.place?.text = curr.place + return newView + } + + internal class ViewHolder { + var flag: ImageView? = null + var country: TextView? = null + var place: TextView? = null + } + + fun intersects(location: Location?): Boolean { + for (item in list) { + if (item.intersects(location)) { + return true + } + } + return false + } + + fun add(listItem: PlaceRecord) { + list.add(listItem) + notifyDataSetChanged() + } + + fun removeAllViews() { + list.clear() + notifyDataSetChanged() + } + + companion object { + private var inflater: LayoutInflater? = null + } + + init { + inflater = LayoutInflater.from(mContext) + } +} \ No newline at end of file diff --git a/labs/Lab11_LocationLab/app/src/main/res/drawable-hdpi/ic_launcher.png b/labs/Lab11_LocationLab/app/src/main/res/drawable-hdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..288b66551d1efd1f13dd06f20a67534d2df57946 Binary files /dev/null and b/labs/Lab11_LocationLab/app/src/main/res/drawable-hdpi/ic_launcher.png differ diff --git a/labs/Lab11_LocationLab/app/src/main/res/drawable-hdpi/stub.jpg b/labs/Lab11_LocationLab/app/src/main/res/drawable-hdpi/stub.jpg new file mode 100644 index 0000000000000000000000000000000000000000..cb3556ecadf21bbc4ac1d420901bb2956ee969ef Binary files /dev/null and b/labs/Lab11_LocationLab/app/src/main/res/drawable-hdpi/stub.jpg differ diff --git a/labs/Lab11_LocationLab/app/src/main/res/drawable-hdpi/stubt.jpg b/labs/Lab11_LocationLab/app/src/main/res/drawable-hdpi/stubt.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b82ead519ea0d11528c10797883cbf5d9e97e1ad Binary files /dev/null and b/labs/Lab11_LocationLab/app/src/main/res/drawable-hdpi/stubt.jpg differ diff --git a/labs/Lab11_LocationLab/app/src/main/res/drawable-mdpi/ic_launcher.png b/labs/Lab11_LocationLab/app/src/main/res/drawable-mdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..6ae570b4db4da165fada0650079061cb56aa8793 Binary files /dev/null and b/labs/Lab11_LocationLab/app/src/main/res/drawable-mdpi/ic_launcher.png differ diff --git a/labs/Lab11_LocationLab/app/src/main/res/drawable-xhdpi/ic_launcher.png b/labs/Lab11_LocationLab/app/src/main/res/drawable-xhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..d4fb7cd9d868f1d7d9964f1686dcbc018ef9495a Binary files /dev/null and b/labs/Lab11_LocationLab/app/src/main/res/drawable-xhdpi/ic_launcher.png differ diff --git a/labs/Lab11_LocationLab/app/src/main/res/drawable-xxhdpi/ic_launcher.png b/labs/Lab11_LocationLab/app/src/main/res/drawable-xxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..85a6081587e2c2b9793d796ee7b07e12fdf860db Binary files /dev/null and b/labs/Lab11_LocationLab/app/src/main/res/drawable-xxhdpi/ic_launcher.png differ diff --git a/labs/Lab11_LocationLab/app/src/main/res/layout/footer_view.xml b/labs/Lab11_LocationLab/app/src/main/res/layout/footer_view.xml new file mode 100644 index 0000000000000000000000000000000000000000..bf95517b9b36b2efe441430c69ed7e4d0a4d15f6 --- /dev/null +++ b/labs/Lab11_LocationLab/app/src/main/res/layout/footer_view.xml @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="utf-8"?> +<TextView xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/footer" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:gravity="center_horizontal" + android:text="@string/footer_text" + android:textColor="@color/black_text_87" + android:textSize="20sp" /> diff --git a/labs/Lab11_LocationLab/app/src/main/res/layout/place_badge_detail.xml b/labs/Lab11_LocationLab/app/src/main/res/layout/place_badge_detail.xml new file mode 100644 index 0000000000000000000000000000000000000000..b2a5237ac7770a6564c8704429059913d625c83b --- /dev/null +++ b/labs/Lab11_LocationLab/app/src/main/res/layout/place_badge_detail.xml @@ -0,0 +1,110 @@ +<?xml version="1.0" encoding="utf-8"?> +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:layout_margin="8dp" > + + <ImageView + android:id="@+id/flag" + android:layout_width="300dp" + android:layout_height="158dp" + android:padding="8dp" + android:layout_alignParentTop="true" + android:layout_centerHorizontal="true" + android:contentDescription="@string/image_descriptor_string" /> + + <RelativeLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_below="@+id/flag" + android:layout_margin="8dp" > + + <TextView + android:id="@+id/place_string" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/place_name_string" + android:textAppearance="?android:attr/textAppearanceSmall" + android:textColor="@color/black_text_87" /> + + <TextView + android:id="@+id/place_name" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_alignBaseline="@+id/place_string" + android:layout_toRightOf="@+id/place_string" + android:ellipsize="end" + android:singleLine="true" + android:textAppearance="?android:attr/textAppearanceSmall" + android:textColor="@color/black_text_87" /> + + <TextView + android:id="@+id/country_string" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_below="@+id/place_name" + android:ellipsize="end" + android:singleLine="true" + android:text="@string/country_name_string" + android:textAppearance="?android:attr/textAppearanceSmall" + android:textColor="@color/black_text_87" /> + + <TextView + android:id="@+id/country_name" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_alignBaseline="@+id/country_string" + android:layout_below="@+id/place_name" + android:layout_toRightOf="@+id/country_string" + android:ellipsize="end" + android:singleLine="true" + android:textAppearance="?android:attr/textAppearanceSmall" + android:textColor="@color/black_text_87" /> + + <TextView + android:id="@+id/date_visited_string" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_below="@+id/country_name" + android:ellipsize="end" + android:singleLine="true" + android:text="@string/date_visited_string" + android:textAppearance="?android:attr/textAppearanceSmall" + android:textColor="@color/black_text_87" /> + + <TextView + android:id="@+id/date_visited" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_alignBaseline="@+id/date_visited_string" + android:layout_below="@+id/country_name" + android:layout_toRightOf="@+id/date_visited_string" + android:ellipsize="end" + android:singleLine="true" + android:textAppearance="?android:attr/textAppearanceSmall" + android:textColor="@color/black_text_87" /> + + <TextView + android:id="@+id/gps_coordinates_string" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_below="@+id/date_visited_string" + android:ellipsize="end" + android:singleLine="true" + android:text="@string/gps_coordinates_string" + android:textAppearance="?android:attr/textAppearanceSmall" + android:textColor="@color/black_text_87" /> + + <TextView + android:id="@+id/gps_coordinates" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_alignBaseline="@+id/gps_coordinates_string" + android:layout_toRightOf="@+id/gps_coordinates_string" + android:ellipsize="end" + android:singleLine="true" + android:textAppearance="?android:attr/textAppearanceSmall" + android:textColor="@color/black_text_87" /> + </RelativeLayout> + +</RelativeLayout> \ No newline at end of file diff --git a/labs/Lab11_LocationLab/app/src/main/res/layout/place_badge_view.xml b/labs/Lab11_LocationLab/app/src/main/res/layout/place_badge_view.xml new file mode 100644 index 0000000000000000000000000000000000000000..e6958a6b23ed97955a861c0a59c46582333b0e69 --- /dev/null +++ b/labs/Lab11_LocationLab/app/src/main/res/layout/place_badge_view.xml @@ -0,0 +1,57 @@ +<?xml version="1.0" encoding="utf-8"?> +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="wrap_content" > + + <ImageView + android:id="@+id/flag" + android:layout_width="160dp" + android:layout_height="85dp" + android:contentDescription="@string/image_descriptor_string" + android:padding="8dp" + android:scaleType="fitXY" /> + + <RelativeLayout + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_centerVertical="true" + android:layout_toRightOf="@+id/flag" > + + <TextView + android:id="@+id/place_string" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/place_name_string" + android:textAppearance="?android:attr/textAppearanceSmall" + android:textColor="@color/black_text_87" /> + + <TextView + android:id="@+id/place_name" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_alignBaseline="@+id/place_string" + android:layout_toRightOf="@+id/place_string" + android:textAppearance="?android:attr/textAppearanceSmall" + android:textColor="@color/black_text_87" /> + + <TextView + android:id="@+id/country_string" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_below="@+id/place_string" + android:text="@string/country_name_string" + android:textAppearance="?android:attr/textAppearanceSmall" + android:textColor="@color/black_text_87" /> + + <TextView + android:id="@+id/country_name" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_alignBaseline="@+id/country_string" + android:layout_toRightOf="@+id/country_string" + android:ellipsize="end" + android:textAppearance="?android:attr/textAppearanceSmall" + android:textColor="@color/black_text_87" /> + </RelativeLayout> + +</RelativeLayout> \ No newline at end of file diff --git a/labs/Lab11_LocationLab/app/src/main/res/menu/main.xml b/labs/Lab11_LocationLab/app/src/main/res/menu/main.xml new file mode 100644 index 0000000000000000000000000000000000000000..4451357749531faad6707bc2cbafa9f827e23a88 --- /dev/null +++ b/labs/Lab11_LocationLab/app/src/main/res/menu/main.xml @@ -0,0 +1,18 @@ +<menu xmlns:android="http://schemas.android.com/apk/res/android" > + + <item + android:id="@+id/delete_badges" + android:title="@string/delete"/> + + <item + android:id="@+id/place_one" + android:title="@string/place_one"/> + + <item + android:id="@+id/place_no_country" + android:title="@string/place_no_country"/> + + <item + android:id="@+id/place_two" + android:title="@string/place_two"/> +</menu> diff --git a/labs/Lab11_LocationLab/app/src/main/res/values-sw600dp/dimens.xml b/labs/Lab11_LocationLab/app/src/main/res/values-sw600dp/dimens.xml new file mode 100644 index 0000000000000000000000000000000000000000..44f01db75f0fef18081132a9e86517f8d5efa8f6 --- /dev/null +++ b/labs/Lab11_LocationLab/app/src/main/res/values-sw600dp/dimens.xml @@ -0,0 +1,8 @@ +<resources> + + <!-- + Customize dimensions originally defined in res/values/dimens.xml (such as + screen margins) for sw600dp devices (e.g. 7" tablets) here. + --> + +</resources> diff --git a/labs/Lab11_LocationLab/app/src/main/res/values-sw720dp-land/dimens.xml b/labs/Lab11_LocationLab/app/src/main/res/values-sw720dp-land/dimens.xml new file mode 100644 index 0000000000000000000000000000000000000000..ee04b4b85d54927ab542aea48d06295a230e2197 --- /dev/null +++ b/labs/Lab11_LocationLab/app/src/main/res/values-sw720dp-land/dimens.xml @@ -0,0 +1,8 @@ +<resources> + + <!-- + Customize dimensions originally defined in res/values/dimens.xml (such as + screen margins) for sw720dp devices (e.g. 10" tablets) in landscape here. + --> + +</resources> diff --git a/labs/Lab11_LocationLab/app/src/main/res/values-v11/styles.xml b/labs/Lab11_LocationLab/app/src/main/res/values-v11/styles.xml new file mode 100644 index 0000000000000000000000000000000000000000..3c02242ad044be9b8c7c09e7c90c5d427763fe97 --- /dev/null +++ b/labs/Lab11_LocationLab/app/src/main/res/values-v11/styles.xml @@ -0,0 +1,11 @@ +<resources> + + <!-- + Base application theme for API 11+. This theme completely replaces + AppBaseTheme from res/values/styles.xml on API 11+ devices. + --> + <style name="AppBaseTheme" parent="android:Theme.Holo.Light"> + <!-- API 11 theme customizations can go here. --> + </style> + +</resources> diff --git a/labs/Lab11_LocationLab/app/src/main/res/values-v14/styles.xml b/labs/Lab11_LocationLab/app/src/main/res/values-v14/styles.xml new file mode 100644 index 0000000000000000000000000000000000000000..a91fd0372b20f85e284fc2fa2ce949176dfdf6e5 --- /dev/null +++ b/labs/Lab11_LocationLab/app/src/main/res/values-v14/styles.xml @@ -0,0 +1,12 @@ +<resources> + + <!-- + Base application theme for API 14+. This theme completely replaces + AppBaseTheme from BOTH res/values/styles.xml and + res/values-v11/styles.xml on API 14+ devices. + --> + <style name="AppBaseTheme" parent="android:Theme.Holo.Light.DarkActionBar"> + <!-- API 14 theme customizations can go here. --> + </style> + +</resources> diff --git a/labs/Lab11_LocationLab/app/src/main/res/values/color.xml b/labs/Lab11_LocationLab/app/src/main/res/values/color.xml new file mode 100644 index 0000000000000000000000000000000000000000..e4aaf650d571c86360e616b4872c7c071f19ba5d --- /dev/null +++ b/labs/Lab11_LocationLab/app/src/main/res/values/color.xml @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <color name="black_text_87">#DE000000</color> +</resources> diff --git a/labs/Lab11_LocationLab/app/src/main/res/values/dimens.xml b/labs/Lab11_LocationLab/app/src/main/res/values/dimens.xml new file mode 100644 index 0000000000000000000000000000000000000000..0e9ce62a515ae5d1c761ff9bbad6b8291a65da36 --- /dev/null +++ b/labs/Lab11_LocationLab/app/src/main/res/values/dimens.xml @@ -0,0 +1,5 @@ +<resources> + + <!-- Default screen margins, per the Android Design guidelines. --> + +</resources> diff --git a/labs/Lab11_LocationLab/app/src/main/res/values/strings.xml b/labs/Lab11_LocationLab/app/src/main/res/values/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..52e02ba5ce742b32611b750c73820b878a0f8bd4 --- /dev/null +++ b/labs/Lab11_LocationLab/app/src/main/res/values/strings.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + + <string name="app_name">LocationLab</string> + <string name="footer_text">Get New Place</string> + <string name="delete">Delete</string> + <string name="badge_detail">Badge Details</string> + <string name="place_name_string">Place: </string> + <string name="country_name_string">Country: </string> + <string name="date_visited_string">Date Visited: </string> + <string name="gps_coordinates_string">Location: </string> + <string name="image_descriptor_string">Flag of visited country</string> + <string name="place_one">Place One</string> + <string name="place_no_country">Place No Country</string> + <string name="place_two">Place Two</string> + <string name="no_country_string">There is no country at this location</string> + <string name="mock_name_united_states_string">United States</string> + <string name="the_greenhouse_string">The Greenhouse</string> + <string name="berwyn_string">Berwyn</string> + <string name="duplicate_location_string">You already have this location badge</string> + +</resources> \ No newline at end of file diff --git a/labs/Lab11_LocationLab/app/src/main/res/values/styles.xml b/labs/Lab11_LocationLab/app/src/main/res/values/styles.xml new file mode 100644 index 0000000000000000000000000000000000000000..5cf0386a144ff6248609832f751aa29c590c6454 --- /dev/null +++ b/labs/Lab11_LocationLab/app/src/main/res/values/styles.xml @@ -0,0 +1,21 @@ +<resources> + + <!-- + Base application theme, dependent on API level. This theme is replaced + by AppBaseTheme from res/values-vXX/styles.xml on newer devices. + --> + <style name="AppBaseTheme" parent="android:Theme.Light"> + <!-- + Theme customizations available in newer API levels can go in + res/values-vXX/styles.xml, while customizations related to + backward-compatibility can go here. + --> + </style> + + <!-- Application theme. --> + <style name="AppTheme" parent="AppBaseTheme"> + <!-- All customizations that are NOT specific to a particular API-level can go here. --> + <item name="android:textColor">@color/black_text_87</item> + </style> + +</resources> diff --git a/labs/Lab11_LocationLab/build.gradle b/labs/Lab11_LocationLab/build.gradle new file mode 100644 index 0000000000000000000000000000000000000000..0eb88a241bad749148d079d6937fb0585592a026 --- /dev/null +++ b/labs/Lab11_LocationLab/build.gradle @@ -0,0 +1,21 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + jcenter() + google() + } + dependencies { + classpath 'com.android.tools.build:gradle:3.1.4' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + jcenter() + maven { + url "https://maven.google.com" + } + } +} diff --git a/labs/Lab11_LocationLab/demo_location_lab.mp4 b/labs/Lab11_LocationLab/demo_location_lab.mp4 new file mode 100644 index 0000000000000000000000000000000000000000..c063a0ddf6eb33629b5f361f3d253d487eb4a167 Binary files /dev/null and b/labs/Lab11_LocationLab/demo_location_lab.mp4 differ diff --git a/labs/Lab11_LocationLab/gradle/wrapper/gradle-wrapper.jar b/labs/Lab11_LocationLab/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..13372aef5e24af05341d49695ee84e5f9b594659 Binary files /dev/null and b/labs/Lab11_LocationLab/gradle/wrapper/gradle-wrapper.jar differ diff --git a/labs/Lab11_LocationLab/gradle/wrapper/gradle-wrapper.properties b/labs/Lab11_LocationLab/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000000000000000000000000000000000000..4898ad075689995ec88d7c971ad112ac814340b7 --- /dev/null +++ b/labs/Lab11_LocationLab/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Mon Oct 19 10:04:54 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/Lab11_LocationLab/gradlew b/labs/Lab11_LocationLab/gradlew new file mode 100644 index 0000000000000000000000000000000000000000..9d82f78915133e1c35a6ea51252590fb38efac2f --- /dev/null +++ b/labs/Lab11_LocationLab/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/Lab11_LocationLab/gradlew.bat b/labs/Lab11_LocationLab/gradlew.bat new file mode 100644 index 0000000000000000000000000000000000000000..8a0b282aa6885fb573c106b3551f7275c5f17e8e --- /dev/null +++ b/labs/Lab11_LocationLab/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/Lab11_LocationLab/settings.gradle b/labs/Lab11_LocationLab/settings.gradle new file mode 100644 index 0000000000000000000000000000000000000000..e7b4def49cb53d9aa04228dd3edb14c9e635e003 --- /dev/null +++ b/labs/Lab11_LocationLab/settings.gradle @@ -0,0 +1 @@ +include ':app'