Hello, dear friend, you can consult us at any time if you have any questions, add WeChat: daixieit

CS 301

Project Assignment 7

November 21, 2022


To Deliver: In the same Gitlab repo as for Project 6

1. Several tags + 1 release

Tags:    MazePanel7 . 1, MazeGeneration7 .2, PlayManually7 .3,   PlayAnimation7 .4 ,

FileIO7 .5, CompleteApp7 .6

Release: CompleteApp7 .6

2. GitLab issue tracker board with issues tracked for this assignment

Learning Objectives :

-  Time management and project organization with an issue tracker

-   Porting code across platforms

-   Benets of encapsulation, (targeted reimplementation of MazePanel)

-   Understanding the differences between the general Java environment and the specic

Android Java environment .

-  Working with threads (the maze generation operates in a separate thread to keep the UI responsive) and understanding how Android handles graphics and screen updates in its UI thread with a message queue

-  Working with graphics in Android

-  Working with persistent storage in Android

Topic: Android App for the Maze game

Motivation/Background information

We want to port our maze java application to Android. This requires us to redesign the user interface and to port the GUI and generation packages into the new Android project.

Preparation steps we have done so far :

•      Project 6: new Android UI design . The newly created Android UI provides you with activities and navigation between them . This is a great start . Since the new UI from Project 6 handles the different screens with activities, we do not need certain classes from the GUI package anymore, for example, Control .java is not used anymore . It is obsolete as our activities represent and track the state of the game.

Still to do:

  Title / Starting Activity: we need to store some parameters in persistent storage to support the revisit functionality. Android shared preferences are a prime suspect for an easy solution here . This does not need code from Project 4, check the Android websitehere . We will also look into this in Module 5, persistent storage with Preferences .

•  Generating Activity: we need to generate a maze . So the plan is to recycle code from Project 4 for this . The prime suspect is the generation package . We need to import the code from there as needed and may need to make adjustments for the new Android environment (this means to port the code to a new environment, to the new software architecture) .

•  PlayManually Activity: same as for generating, but for this one, we need to adjust the drawing on the screen for the visualization of the maze . Prime suspects are StatePlaying and the classes it depends on.

•  PlayAnimation Activity: same as for PlayManually. Once we get PlayManually to work, we could benefit a lot from that and also recycle the RobotDriver, Robot, DistanceSensor interfaces and corresponding classes for the automated mode .

We will not use all code from Project 4, we rather consider it a scrapyard of existing functionality

that we import / copy / recycle for our new Android app as we see t.

GitLab Project management, issue tracker: Use the issue tracker and board in your repo.

•  Create one issue per challenge, assign the P7 due date as its milestone, assign it to yourself as assignee .

  Break down the overall assignment into a number of smaller tasks and create an issue for each task . This is not just about coding, testing, debugging, e .g . “find a tutorial on implementing a custom view and work through it” is also a task . Link each issue for a task with the issue for its corresponding challenge (the tracker has a feature to link one issue with another) . Decide on a timeline for all issues and estimate the time you need for each issue, set a milestone for your project submission date . Provide each issue with a time estimate, sources of supporting information that you may need for it, and a risk estimate that corresponds to your level of familiarity or expectation on the difficulty for this issue (low, medium, high risk) .

  The issue tracker must use at least the default columns open and closed to track your issues (more columns are optional) .

  Objective: learn how to work with an issue tracker for time management and as a project management tool . Get better at estimating your time from one project to the next! Become more professional!

•  Warning: meaningful use of the issue tracker is graded . If you put it to good use to your advantage, you should be fine.

1st Challenge: Implementing a custom view for MazePanel

We need to extend the new MazePanel.java class such that it can act as a collaborator and adapter for classes such as FirstPersonView, Map, and CompassRose to draw their content on the Android custom view implemented in MazePanel .java which in turn draws on a squared area in our new Android app .

Reference: https://developer.android.com/training/custom-views/custom-drawing

Suggested   strategy:

1.    Create a custom view for PlayManually: You have already done this in P6 . If that works, great . Otherwise, you need to do this, please read the rest fi rst to see where this gets us .

2.    Clarify the role of the MazePanel for the Maze game: The new MazePanel class assumes the responsibility to draw anything necessary on the screen in your PlayManually activity in the little square area where you see that maze from a fi rst-person view and as a map . A useful point of view is to consider the MazePanel class being a “notetaker” or an “editor” . Some client classes want to draw something, so they call the MazePanel to add a line, add an oval and the MazePanel takes notes for this using its private notepad (use a private Canvas and Bitmap to draw notes on) . At some point, the StatePlaying object thinks the current scene is all set and calls the MazePanel (the notetaker) that it can report the complete set of notes to the next level, i .e . , it commits the drawing which has the effect that the screen gets updated . The MazePanel can’t do this itself so it lets the UI know that its view is invalid and needs an update, so the UI triggers that views on the activity redraw themselves and calls the MazePanel onDraw method with a reference to the real UI Canvas to draw on. The MazePanel being a good notetaker can then draw its private bitmap on the given UI Canvas to make everything show up on the screen. So how does the MazePanel internally represents the graphical information?

1.    Variant 1: It keeps a list (a to-do list) of what to draw and in which order and then performs the corresponding method calls on the UI Canvas .

2.    Variant 2: It immediately performs the drawing on an internal bitmap with its own internal canvas and paint . In this sense, the MazePanel takes notes on what to draw over time by adding graphic elements to a little private memo image on its bitmap, and when the time comes it is ready to draw the full scene on the Canvas that is handed to it . Variant 2 is recommended here . It is the common solution for the problem that a user should not see how the graphics actually draws bits and pieces for an image, so the code draws till it is complete on a buffer image and then one switches the display from the current image to the complete buffer image at once .

3.    Implement the MazePanel drawing capability for client classes:

1.    Import the P7PanelF22 interface into your project and make MazePanel implement the P7PanelF22 interface . The interface is available on the BB assignment .

2.    In MazePanel .java, add necessary elds/instance variables for what the MazePanel needs to store to be a “notetaker” as discussed above . P6 instructed you to have a private Canvas, Bitmap and Paint, these are really needed now.

3.    Implement the color setting and drawing capabilities that public/protected MazePanel methods offer to client classes (such as Map or FirstPersonView) .

4.    For testing purposes: write a little private method (void myTestImage(Canvas c)) that exercises your color setting and drawing capabilities you implemented in step 3 to draw a hardcoded image, e .g . , 1 red ball, 1 green ball, 1 yellow rectangle, 1 blue polygon, plus a few lines for good measure on the parameter canvas c . Make sure your test code uses the public/protected methods of MazePanel for drawing .

1.    Hint: First try: Call this method in onDraw(Canvas) and use the given UI canvas for drawing . The image should show on the screen, use this to convince you the drawing works and your selection of what to draw is good for testing .

2.    Hint: Second try: Call this method then in your constructor and use your internal canvas for the parameter setting . The hardcoded figure should show up when you run the app and reach PlayManually.

3.    Hint: Third try: Expand and vary the test method to use all interface methods for drawing to convince you that they are working .

4.    Hint: For this purpose, you could temporarily make the PlayManually the starting activity in the Android Manifest such that testing this aspect is faster, once the drawing works, you change the Manifest le back to what it should be for the AMaze app.

5.   As a nal step, check how the MazePanel can inform the UI thread that the panel needs to be redrawn/updated . Check back on your StatePlaying .draw() method code and implement this with the MazePanel .update() resp . commit() method .

4.    Use custom view also for PlayAnimation: Adjust the layout and Java code for your PlayAnimation activity to work with your new MazePanel.

When you nish this challenge, make sure you tag this version on GitLab with the tag

MazePanel7 . 1”, as this will matter for grading . By the way, you can work and nish challenges out of order, that is ok.

2nd Challenge: Generating a maze in the Generating Activity

Generating the maze takes place in a separate thread to retain a UI that responds to user input. This was the case in the Maze code already and we need to keep it this way. Now, this takes place in the Generating activity which receives its parameter settings with its starting intent being sent by the Starting activity.

You need to consider the P4 codebase and identify classes you can use for this step, most likely you will select the whole generation package plus possibly some extras from the GUI package .

Copy these classes over from the maze codebase into the Android project as needed . For compiler errors: I would initially just comment out existing code that the compiler complains about, put the corresponding lines on a to-do list and make the compiler stop complaining that way. I would then work on making the GeneratingActivity use the MazeFactory to produce a MazeConfiguration for it.

In the end, the new maze conguration needs to be made accessible to the PlayManually and PlayAnimation activities .

      There are different design options on how the MazeFactory may deliver the maze configuration to the PlayManually activity. The recommendation is to use a simple shared variable, e .g . a static variable or a static field . See also the discussion of options here http:// stackoverflow.com/questions/4878159/android-whats-the-best-way-to-share-data-between- activities .

1.    One can dene a static variable, use the singleton pattern (application singleton), or some other way of using a global variable to share data across activities that reside in the same application . This is recommended here .

2.    One can serialize the data and communicate it within an intent (serializable or parcelable) . This is an interesting learning experience for message passing, but it creates a substantial amount of work and the solution does not scale well . Not recommended for this particular assignment .

3.    One can transfer the data into the applications preferences . A solution based on le i/o, not recommended either.

     The MazeBuilder thread reports progress that it makes and this should be visible in the progress bar on the screen for the user to see . Make sure you show the progress as it is reported by the factory, do not fake it with your solution from P6 .

      Finally, either the generating activity or the MazeFactory needs to start a playing activity when the maze generation is done . It makes sense to let the GeneratingActivity finish() such that the activity stack does not contain it and the back button leads back to the starting activity.

As a result of this challenge, you have an app with a working title screen to collect user input and a subsequent generating screen that generates the maze to play and switches to the PlayManually or PlayAnimation activity, where your code has access to the generated MazeConfiguration.

When you nish this challenge, make sure you tag this version on GitLab with the tag “MazeGeneration7.2”, as this will matter for grading.

3rd Challenge: Getting the manual operation of the maze game to work

The PlayManually activity collaborates with StatePlaying provided in the P4 codebase.

PlayManually acts very much like the UI and Control for StatePlaying.  So the user input for buttons (forward, left, right, jump) on the UI need to connect to the corresponding method calls for the handleUserInput method on the StatePlaying side . For this challenge, we need to


1.    Connect user input for rotate, move, and jump operations with corresponding methods

2.    Connect the user input for the map (former m, s, and z key inputs for walls and solution) with corresponding methods

3.    Connecting the user input for zoom in/out functionality, i .e . scaling the maze . Note: the size of the square for the MazePanel remains the same in your layout regardless of the zoom setting for the map .

4.    Recognize how StatePlaying .draw() interacts with MazePanel to make sure that method calls for FirstPerson and Map drawing take place plus the final trigger to update the Android view leads to drawing the maze on the activity. Drawing the graphics is implemented in an OnDraw method in MazePanel and one can cause the Android environment to call OnDraw by a call to the invalidate method . The main UI thread has a so-called looper and handles requests for redrawing a view in a queue .

For the manual operation of the maze, where the user clicks buttons, the integration of the maze graphics and controlling when an update is necessary is reasonably straightforward .

5.    Recognize termination of the game and switch to the winning activity. Make sure you count the forward steps so you can report the path length as well as the minimum distance to the exit.

As a result of challenges 1-3, you have an app that you can play by generating a new maze each round and playing the game manually. Finally: make sure you can play the game for more than one round!

When you nish this challenge, make sure you tag this version on GitLab with the tag

PlayManually7.3”, as this will matter for grading.

4th Challenge: Getting the animation to work

We want to complete our maze application on Android by integrating the automated maze exploration algorithms, i.e., the various implementations of the RobotDriver.java interfaces.

The key difference to the manual operation is that the automated maze exploration does not produce a sequence of events (user input, screen update, user input, screen update, …) but a sequence of screen updates as an effect of a single user input . So, our robot driver produces a sequence of images much like an animation, a movie . The challenge is to get them on display and a reasonable delay into the animation.

PlayAnimation activity :

      What does not work I: feeding a sequence of screen update requests (method: invalidate) to the UI thread is noticed by the UI thread . It optimizes its performance by skipping intermediate updates and simply goes to the last screen . The visual effect is that the maze exploration starts and it appears to reach the exit immediately. Fast, but unacceptable .

•      What does not work II: as a x to the UI thread optimization, one may think that slowing down the UI thread with sleep commands may yield the desired effect . This is a very bad idea because Android expects the UI thread to be responsive. Android may decide to bring up a user dialog (ANR: Application Not Responding) and offer to kill the app as it does not seem to respond (assuming it hangs and thus better be killed) .


      What works I: recognize that you can of course have code sleep when executed on a background thread . So much like what you did in P6 with the progress bar, you could have the robot driver execute on the background thread and sleep between each step it makes towards the exit . This would require some communication from the driver to the UI when it is done with one step to communicate that the MazePanel image is ready to be put on display for the user to see . For this communication, consider using a Handler for the UI thread and send messages to the handler for the UI thread to execute . Since a background thread can’t be revived once terminated, you need to think about how to establish the pause/continue feature . You can make a thread wait for an event (wait-notify mechanism) or reconsider how the concept of a lock works for threads .

      What works II: For the automated exploration with the RobotDriver, the Handler is a very powerful and useful concept . What exactly do we really need the background thread for? Right, sleeping between steps, because otherwise, we could simply post a Runnable on the handler with code where the driver drives 1 step towards the exit . There is one cool feature when posting Runnables on a handler, this is the method postdelayed . So if you put the puzzle pieces together, then you can make the animation work without a background thread and just post a runnable on the handler, that drives 1 step to the exit and posts itself with some delay till it reaches the exit . Think of it as an unorthodox way to establish a loop .

      Perform an internet search for "Android postdelayed UI update", see e .g . the section http://android-developers.blogspot.com/2007/11/stitch-in-time.html and http://stackoverow.com/questions/3765161/updating-ui-with-runnable-postdelayed-not- working-with-timer-app

      A Handler handles messages being sent to the thread it belongs to (here the main thread) . For communication between threads in Android with a so-called Handler, follow this link to a Handler; here is another example with a handler and a discussion on possible issues with a handler.

      What also works: the previous solutions are not necessarily the only one . Feel free to come up with something else, your solution is graded simply by checking if it works or not.

For the working version, keep in mind that the user must be able to adjust the animation speed, this naturally translates into adjusting the length of the delay between individual steps.

Including sensor failure & repair operations

As the user may have picked an unreliable robot, make sure your wall follower is able to handle these issues and tries its best to get to the exit by using the mitigation strategies you developed in Project 4. The status of each sensor is visualized and updated according to the sensor’s state during the animation.

When you nish this challenge, make sure you tag this version on GitLab with a release tag “PlayAnimation7.4”, as this will matter for grading.

5th Challenge: Loading and storing mazes

The revisitoption on the starting screen allows the user to replay a maze that was played before . We need to reproduce the same maze that was generated last time for the chosen selection of size (skill level) and builder algorithm . This feature can be implemented in different ways, for example,

a)   one can store a completely generated maze with the help of the MazeFileWriter to a le and then read it upon request with the MazeFileReader, or

b)   one can store all the parameter settings necessary to calculate the same maze again but from scratch . Since the user picks size, builder algorithm, and rooms (yes or no), the missing piece of information is the seed value for the random number generator. To do so, one needs to store and retrieve the seed value for the random number generator, the size, the builder algorithm, and if the maze should come with rooms or not can serve as a key for a (key, value) pair to store .

You will use variant b) and it is recommended to store the information in the app preferences le when you generate a maze for the fi rst time (explore button) . The storage space needed for this variant is limited .  With n sizes, m builder algorithms, and rooms y/n we would store at most n x m x 2 variants. The app preferences file should be ok to store this information.

When you nish this challenge, make sure you tag this version on GitLab with a release tag “FileIO7 .5”, as this will matter for grading . If you finish this before the animation works, this is ok, the tag clarifies which version got the file i/o to work.

Options for Bonus Points: Make the maze game more appealing

There are plenty of ways to make this game more appealing . Some of the following options have been successfully explored by students in previous classes :

      Background pictures in general and more attractive graphics for the walls in the FirstPersonView to create a theme such as the “Corn Maze”, “Zelda”, “James Bond”… (hint: check the documentation for BitmapShader)

      Sounds, vibrations

•      Music (make sure music starts and stops with activities, beware of the lifecycle of an activity)

•      Swipe gestures

•     Voice control

If you do something in this direction, please make sure you let the grader know to get bonus points for your efforts and achievements . For example, write a few notes into GitLab and the BB submission page.

Other options for Bonus points:

  Explore technical aspects of Android development that are of interest to you

  Other UI concepts such as animated transitions

•  Provide Junit test code for other classes outside of the current assignments, e .g . the BSPnodes . The tests must be not trivial and rigidly check correctness .

  Provide test code for testing the graphics part of an app (we did not cover this in class) .

  Track down the culprit for the CardinalDirection confusion in the Map drawing, describe and implement a way to fix this.

Notes: Also required :

     Runtime feedback on what the program is doing : Use the Log.v(), Log.e()… methods, and LogCat to obtain output from the Maze program .

      Regular commits & pushes into your GitLab project repository : Do this for your benet but also to be able to make the case that this code is code of your own making . You are expected to regularly commit and push your versions into GitLab and use meaningful comments to document your progress.

     As general advice: do not attempt a big bang integration, identify individual steps, e.g., the integration of the maze generation, and make this one work before integrating the graphics part or vice versa . For the reimplementation of the MazePanel code: reimplement the individual functions and test them with your MazePanel .myTestImage(Canvas c) method before you attempt to port FirstPersonView, Map, and CompassRose to the Android project.

When you nish this assignment, make sure you tag your nal version on GitLab with the tag

CompleteApp7 .6”, as this will matter for grading .

AND: create a dedicated release CompleteApp7.6 for the grader to download.

Grading

     GitLab

      Issue tracker: You will receive points for organizing and tracking your work with the issue tracker, at least 3 issues per challenge are expected . They should have the P7 due date as a milestone, a time estimate . Consider using the Gitlab tracker feature of link issues such that one can see which issue belongs to which challenge .

      Tags & Final release: You will receive points for a GitLab project with 6 tagged versions named in the assignment that each includes a complete Android project that can be checked out by the grader. The 6 tagged versions need to demonstrate that you solved individual challenges over time . Just uploading essentially a nal version with 6 fake tagged versions is not acceptable . Tags need not be in chronological order. It’s ok if you decide to finish FileIO7 .5 fi rst or PlayManually7 .3 .

      Revisions: You are expected to regularly commit and push your versions into GitLab and use meaningful comments to document your progress .

      You will receive points if your Android app can be executed on an AVD Pixel 6 API level 32 in portrait mode (if it only works on a different architecture, it is your responsibility to clearly communicate this to the graders) . You get points specifically if

      One can select options for the maze generation (size, algorithm, rooms y/n) and can either create a new maze or replay the last maze generated for that parameter setting

      One can move from the initial activity to the generating activity and a random maze gets generated with the MazeFactory in the generating activity while a user can pick the driver (manual, wizard, wall follower) and a robot (premium, mediocre, so-so, shaky) .

      A maze is generated outside of the UI thread (e .g . , with a separate thread in the MazeFactory or an asynctask) and the progress bar shows progress values that originate from the maze generation code .

      Parameters (size, builder, rooms y/n, seed) of a newly generated maze are automatically stored in persistent storage (app preferences) such that one can revisit (i .e . , recompute the same maze) and play it again at a later point in time

      If the user wants to revisit a previously generated maze, a maze is generated according to the stored parameter settings that are loaded from le (preference le)

      The game switches automatically from the generating screen to the corresponding playing screen once the maze is generated and the user picked a driver. The switch goes to PlayManually if the user selected the manual operation, otherwise, it goes to

PlayAnimation .

      On the PlayManually screen,

      The maze is visualized in the rst-person perspective and one can move left, right, forward, and jump, and the screen updates accordingly.

     One can manually play the game and get to the exit

      One can select if one also sees the maze from the top, its walls, and its solution, and the visualization corresponds to the selection .

      If the map is not selected, one sees hints such as the compass rose or the map, the map only when facing a dead-end (this is already so in the original codebase) .

      One can zoom in/out of the map, i .e . , change the scale of the map . Pick an initial setting for the Pixel 6 such that one can clearly see the map .

      One can select automated drivers (WallFollower, Wizard) during the maze generation to get to the PlayAnimation screen, and there

•      One can observe how the driver tries to nd the exit within the rst-person perspective and on the map .

      The map should be turned on by default and be scaled to a reasonable size by default . One can switch the map on and off and zoom in and out .

•      One can see the remaining energy shrinking during operation

•      Depending on the robot chosen during maze generation, there are failure & repair events during the exploration and each sensor’s state is visualized during animation .

      While the driver explores the game, one can pause and subsequently continue the animation with button clicks

      One can adjust the animation speed with a seekbar. This essentially slows down the animation by changing the time delay between steps .

      One gets to the winning screen if one reaches the exit in the manual mode, it shows the path length performed as well as the initial distance to&