Mobile App Dev 2021W: Tutorial 9: Difference between revisions

From Soma-notes
Created page with "'''This tutorial is still in developoment.''' ==Tasks== ==Code== ===MainActivity.kt=== <syntaxhighlight lang="kotlin" line> package carleton.comp1601.intentdemo import and..."
 
No edit summary
 
(14 intermediate revisions by the same user not shown)
Line 1: Line 1:
'''This tutorial is still in developoment.'''
This tutorial is due on <b>April 8, 2021</b> via cuLearn.  Please use [https://homeostasis.scs.carleton.ca/~soma/mad-2021w/templates/tut9-template.txt this template] for your solutions.  Be sure to download the code for [https://homeostasis.scs.carleton.ca/~soma/mad-2021w/code/IntentDemo.zip IntentDemo].


==Tasks==
==Questions==
 
<ol>
<li>Where in the application is the following behaviour specified?
<ol style="list-style-type:lower-alpha">
<li>The size of the red circle</li>
<li>The colour of the red circle.</li>
<li>No application title on the screens.</li>
<li>The application should start with showing the splash screen.</li>
<li>The splash screen layout in splashscreen.xml is associated with the code in SplashScreen.kt</li>
<li>Clicking on continue on the splash screen should cause MainActivity to be run.</li>
</ol>
</li>
<li>The layout of the application changes when you switch the device to dark/night mode, beyond different colors.  Why?</li>
<li>Where does the application send an explicit intent?  Where does it receive an explicit intent?</li>
<li>Where does the application send an implicit intent?  Where does it receive an implicit intent?</li>
<li>What touch events does MainActivity respond to?  What code implements the response for them?</li>
<li>Why are the constants added to circle.x and circle.y in TrackCircle's onTouch handler (lines 40 and 41)?  How does the behavior of the app change if these constants are removed?  Why?</li>
<li>TrackCircle's onTouch method does the same thing in response to an ACTION_MOVE and an ACTION_UP event.  Are both of these needed?  What happens if either is removed?</li>
</ol>


==Code==
==Code==
[https://homeostasis.scs.carleton.ca/~soma/mad-2021w/code/IntentDemo.zip IntentDemo.zip]


===MainActivity.kt===
===MainActivity.kt===
Line 14: Line 35:
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.app.AppCompatActivity
import android.content.Intent
import android.content.Intent
import android.graphics.drawable.ShapeDrawable
import android.net.Uri
import android.net.Uri
import android.os.Build
import android.view.MotionEvent
import android.view.MotionEvent
import android.view.Window
import android.view.WindowManager
import androidx.annotation.RequiresApi
import java.lang.Math.abs


val appName = "IntentDemo"
val appName = "IntentDemo"
Line 28: Line 42:
class MainActivity : AppCompatActivity() {
class MainActivity : AppCompatActivity() {
     private lateinit var circle: View
     private lateinit var circle: View
    private lateinit var root: View


     override fun onCreate(savedInstanceState: Bundle?) {
     override fun onCreate(savedInstanceState: Bundle?) {
Line 34: Line 47:
         setContentView(R.layout.activity_main)
         setContentView(R.layout.activity_main)


        this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                WindowManager.LayoutParams.FLAG_FULLSCREEN);
         circle = findViewById(R.id.circle)
         circle = findViewById(R.id.circle)
         circle.setOnTouchListener(trackCircle)
         circle.setOnTouchListener(trackCircle)
Line 119: Line 130:


import android.content.Intent
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.os.Bundle
import android.util.Log
import android.util.Log
Line 140: Line 150:
}
}
</syntaxhighlight>
</syntaxhighlight>


===splashscreen.xml===
===splashscreen.xml===
Line 223: Line 232:
</shape>
</shape>
</syntaxhighlight>
</syntaxhighlight>
===theme.xml===
<syntaxhighlight lang="xml" line>
<resources xmlns:tools="http://schemas.android.com/tools">
    <!-- Base application theme. -->
    <style name="Theme.IntentDemo" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
        <!-- Primary brand color. -->
        <item name="colorPrimary">@color/purple_500</item>
        <item name="colorPrimaryVariant">@color/purple_700</item>
        <item name="colorOnPrimary">@color/white</item>
        <!-- Secondary brand color. -->
        <item name="colorSecondary">@color/teal_200</item>
        <item name="colorSecondaryVariant">@color/teal_700</item>
        <item name="colorOnSecondary">@color/black</item>
        <!-- Status bar color. -->
        <item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item>
        <!-- Customize your theme here. -->
        <item name="windowActionBar">false</item>
        <item name="windowNoTitle">true</item>
    </style>
</resources>
</syntaxhighlight>
==Solutions==
[https://homeostasis.scs.carleton.ca/~soma/mad-2021w/solutions/tut9-solutions.txt Tutorial 9 Solutions]

Latest revision as of 18:15, 9 April 2021

This tutorial is due on April 8, 2021 via cuLearn. Please use this template for your solutions. Be sure to download the code for IntentDemo.

Questions

  1. Where in the application is the following behaviour specified?
    1. The size of the red circle
    2. The colour of the red circle.
    3. No application title on the screens.
    4. The application should start with showing the splash screen.
    5. The splash screen layout in splashscreen.xml is associated with the code in SplashScreen.kt
    6. Clicking on continue on the splash screen should cause MainActivity to be run.
  2. The layout of the application changes when you switch the device to dark/night mode, beyond different colors. Why?
  3. Where does the application send an explicit intent? Where does it receive an explicit intent?
  4. Where does the application send an implicit intent? Where does it receive an implicit intent?
  5. What touch events does MainActivity respond to? What code implements the response for them?
  6. Why are the constants added to circle.x and circle.y in TrackCircle's onTouch handler (lines 40 and 41)? How does the behavior of the app change if these constants are removed? Why?
  7. TrackCircle's onTouch method does the same thing in response to an ACTION_MOVE and an ACTION_UP event. Are both of these needed? What happens if either is removed?

Code

IntentDemo.zip

MainActivity.kt

package carleton.comp1601.intentdemo

import android.os.Bundle
import android.util.Log
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import android.content.Intent
import android.net.Uri
import android.view.MotionEvent

val appName = "IntentDemo"

class MainActivity : AppCompatActivity() {
    private lateinit var circle: View

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        circle = findViewById(R.id.circle)
        circle.setOnTouchListener(trackCircle)

        Log.d(appName, "Main screen created")
    }

    fun openPage(v: View) {
        Log.d(appName, "Opening URL")
        val intent = Intent(Intent.ACTION_VIEW, Uri.parse("https://homeostasis.scs.carleton.ca/wiki"))
        startActivity(intent)
        Log.d(appName, "URL intent sent")
    }

    val trackCircle = object: View.OnTouchListener {
        override fun onTouch(v: View?, event: MotionEvent?): Boolean {
            if (event == null || v == null) {
                return false
            }

            val action = event.getAction()
            val x = event.rawX - 128F
            val y = event.rawY - 128F

            if (action == MotionEvent.ACTION_DOWN) {
                Log.d(appName, "Circle touched at ${x}, ${y}")
            } else if (action == MotionEvent.ACTION_UP) {
                circle.x = x
                circle.y = y
                Log.d(appName, "Circle released at ${x}, ${y}")
            } else if (action == MotionEvent.ACTION_MOVE) {
                circle.x = x
                circle.y = y
                Log.d(appName, "Circle repositioned to ${x}, ${y}")
            }
            return true;
        }
    }
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <ImageView
        android:id="@+id/circle"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:src="@drawable/circle"
        android:visibility="visible"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="openPage"
        android:text="Open Page"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.501"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.944" />

</androidx.constraintlayout.widget.ConstraintLayout>


SplashScreen.kt

package carleton.comp1601.intentdemo

import android.content.Intent
import android.os.Bundle
import android.util.Log
import android.view.View
import androidx.appcompat.app.AppCompatActivity

class SplashScreen : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.splashscreen)
        Log.d(appName, "Splash screen created")
    }

    fun startMain(v: View) {
        Log.d(appName, "Starting Main button pressed")
        intent = Intent(this, MainActivity::class.java)
        startActivity(intent)
        Log.d(appName, "Starting Main intent sent")
    }
}

splashscreen.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:onClick="startMain"
    tools:context=".SplashScreen">

    <TextView
        android:id="@+id/title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Intent &amp; Drag Demo"
        android:textAlignment="center"
        android:textAppearance="@style/TextAppearance.AppCompat.Display3"
        android:textStyle="bold"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/textView2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="COMP 1601"
        android:textAppearance="@style/TextAppearance.AppCompat.Display2"
        app:layout_constraintBottom_toTopOf="@+id/continueButton"
        app:layout_constraintTop_toBottomOf="@+id/title"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent" />

    <Button
        android:id="@+id/continueButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="16dp"
        android:onClick="startMain"
        android:text="Continue"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="carleton.comp1601.intentdemo">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.IntentDemo">
        <activity android:name=".SplashScreen">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity android:name=".MainActivity" android:exported="true">
        </activity>
    </application>

</manifest>

circle.xml

<?xml version="1.0" encoding="utf-8"?>
<shape android:shape="oval" xmlns:android="http://schemas.android.com/apk/res/android">
    <solid android:color="#ff0000"/>
</shape>

theme.xml

<resources xmlns:tools="http://schemas.android.com/tools">
    <!-- Base application theme. -->
    <style name="Theme.IntentDemo" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
        <!-- Primary brand color. -->
        <item name="colorPrimary">@color/purple_500</item>
        <item name="colorPrimaryVariant">@color/purple_700</item>
        <item name="colorOnPrimary">@color/white</item>
        <!-- Secondary brand color. -->
        <item name="colorSecondary">@color/teal_200</item>
        <item name="colorSecondaryVariant">@color/teal_700</item>
        <item name="colorOnSecondary">@color/black</item>
        <!-- Status bar color. -->
        <item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item>
        <!-- Customize your theme here. -->
        <item name="windowActionBar">false</item>
        <item name="windowNoTitle">true</item>
    </style>
</resources>

Solutions

Tutorial 9 Solutions