Warning: Outdated Content
This MP is from a previous version of CS 125. Click here to access the latest version.
MP1: Photos
As we have learned previously, computers are frequently used to transform and analyze data. And an increasing amount of that data is multi-dimensional: including both photo and video data. People are taking a huge amount of photos and video, and processing that data is almost entirely done on or by computers.
For MP1 you’ll be working with two-dimensional photo pixel data as you complete the image transformations for a simple Android photo editing app. While we will continue introducing you to Android, our focus is primarily on data transformation and strengthening your existing programming abilities.
MP1 is due Monday 2/18/2019 @ 5PM. To receive full credit, you must submit by this deadline. In addition, 10% of your grade on MP1 is for submitting code that earns at least 40 points by Monday 2/11/2019 @ 5PM.
As usual, late submissions will be subject to the MP late submission policy.
1. Learning Objectives
The purpose of MP1 is to introduce you to data transformation and 2D arrays while continuing introducing you to Android development. You’ll begin to learn how to:
-
implement various image transformations by performing transformations on 2D arrays
-
avoid writing repetitive code by identifying similarities between various transformations
-
work with existing object classes
We’ll also introduce you some new parts of your simple Android app, and you’ll get practice modifying its UI to reflect the results of your image transformations.
We’ll also continue to reinforce the learning objectives from MP0: imperative programming and Android development.
2. Assignment Structure
Like MP0, MP1 is a single Android app with its source code divided into two pieces:
-
/lib/
: a library that performs various image transformations. 60 / 100 points on the MP are for completing the library, which requires that you write multiple image transformation functions from scratch. -
/app/
: an Android app for you to use for your own interactive testing. The Android app is almost complete, but needs a few modifications from you. 20 / 100 points on the MP are for completing the app, which requires that you understand the code that we have provided and make minor changes. And, to work correctly, you need to finish the library inlib
.
Your primary job is to complete the required transformations in Transform.java
.
This file doesn’t even exist yet!
You’ll have to create it, and then declare, complete, and document the required
functions as listed in the
official online documentation.
These make use of a pixel class defined in RGBAPixel.java
.
These functions are called by the app and, once you complete them, your app will
be almost completely functional—and we’ll be happy to help you with the
rest.
As always, you may find our official MP1 online documentation helpful in understanding what each function and class is supposed to do.
The MP1 app is somewhat more complicated than the MP0 app.
It has an Android activity (MainActivity.java
), plus another code file (Tasks.java
)
that allows us to execute code in the background.
You don’t need to fully understand either file yet,
/
but you do need to explore and experiment with them to finish the app and earn full credit.
2.1. Obtaining MP1
Just as with MP0, use this GitHub Classroom invitation link to fork your copy of MP1. Once your repository has been created, import it into Android Studio following our assignment Git workflow guide. Please follow these instructions carefully. Failure to do so can result in costly mistakes.
2.2. Your Goal
Like MP0, your goal is to complete the helper functions so that the app works properly. And like MP0, there are a few bits of the UI left for you to complete. However, this time we’re also going to push you to learn more about Android user interface design—since one of the buttons is connected in the source code but doesn’t yet exist in the interface description. See the grading description below.
3. Approaching MP1
All of our previous advice about how to approach the CS 125 MPs still applies. But MP1 has some unique features that are designed to continue your development as computer scientists and software developers.
3.1. Package Declarations
Since you’re creating an entirely new Transform.java
file, you need to watch out for
a code organization concept that we haven’t discussed in lecture yet: Java packages.
Happily, this is not at all complicated.
Simply duplicate the package edu.illinois.cs.cs125.spring2019.mp1.lib;
line from
RGBAPixel.java
in Transform.java
once you create that file and everything
will work properly.
We’ll discuss this more soon.
3.2. Don’t Repeat Yourself (DRY)
Whenever you write software, you should try to adhere to the DRY principle: don’t repeat yourself.
What does this mean? It means that you should try to avoid writing duplicative code—multiple functions (or parts of the same function) that perform identical tasks.
Consider the fact that any computer program could be written as one giant function and with no subroutines at all 1. But the result would be awful, since any time the program needed to repeat a task it would have to repeat the code needed to accomplish that task. And any time you fixed a bug in one part of the code, you’d have to find every other identical part and fix the bug there as well. Code like this quickly becomes impossible to understand, test, debug, and improve—and will also make it hard to keep a job.
At first glance, MP1 may seem daunting. You have 13 functions to write! And yes, you can complete MP1 by writing 13 separate independent functions.
But there is a much smarter way to approach MP1. As a hint, the solution set consists of only 4 real functions—with the rest just calling into this much smaller set of helper functions. The reason is that many of the transformations perform similar operations. For example, a shift down is similar to a shift up, as well as a shift left and a shift right. So rather than writing four separate extremely-similar functions, I can write a slightly more complicate generic shift function and have it called by all of the others.
There is a balance here that requires practice to get right. Trying to reduce the needs of 12 different functions to one single method produces overly-complicate and brittle code. But writing them all separately misses opportunities to harness common subroutines. You’ll get better at this with practice, and MP1 is a good chance to get some. So do not implement 12 separate transformation functions, but also do not attempt to implement one function that does everything. There are some natural groupings that you will probably be able to identify.
3.3. Understand Your Coordinate System
If you are used to working with the coordinate plane in mathematics, the canvas coordinate system can take some getting used to. In particular:
-
(0, 0)
is at the top left, not the bottom left. -
Increasing Y values move the image down, not up—keep this in mind when implementing
shiftUp
andshiftDown
. -
Increasing X values move the image to the right, which matches the mathematical coordinate system.
Another important pitfall is that the that way that two-dimensional arrays in Java are initialized does not match up with this coordinate system. So, for example, this static array:
int[][] myArray = {
{ 1, 2 },
{ 3, 4 }
};
corresponds to this image array:
|
|
|
|
We suggest that you do not try to interpret the statically initialized arrays in
the test suite directly.
Instead, use the output from RGBAPixel
helper methods, which is correctly
formatted.
3.3.1. Shrinking and expanding
As an additional note about coordinates, please consider carefully how to implement the shrink and expand transformations. Specifically, if I start with this 2x6 array (with pixel values shown):
|
|
|
|
|
|
|
|
|
|
|
|
and expand it horizontally by a factor of 3, this is the correct result:
|
|
|
|
|
|
|
|
|
|
|
|
But it is easy to get this instead:
|
|
|
|
|
|
|
|
|
|
|
|
You will want to think about this carefully.
As a hint, instead of starting with the original array and trying to figure out
where each pixel goes in the transformed array, you may want to start with the
transformed array and calculate where each pixel should come from.
Also keep in mind that simply casting a double to an integer does not round the
value properly.
So (int) doubleValue != Math.round(doubleValue)
.
Finally, note that shrinking is not tested by the test suite. You can feel free to implement it to get your app to work like the solution, but it will not affect your score.
3.4. Getting Help
The course staff is ready and willing to help you every step of the way! Please come to office hours, or post on the forum when you need help. You should also feel free to help each other, as long as you do not violate the academic integrity requirements.
4. More About Android
MP1 will continue introducing you to Android development. You have a bit more work to do to get your app to work, and we’ll introduce a few new ideas below.
4.1. UI Design
Smartphone apps communicate with the user through a graphical user interface, or UI. The aesthetic aspects of UI design are beyond the scope of this class—although there are other courses in the department that touch on this topic.
We do encourage you to consider app UI design as you interact with the apps that you use daily. What UI features of those apps do you like or dislike? Are there parts of the app that feel intuitive—or counter-intuitive? Do you find yourself fumbling around trying to accomplish things that seem like they should be simple?
But that’s as far as we’ll go on the design aspects. What we will focus on is the functional aspects—how we add elements to our UI and connect them with our app.
For example, the MP0 app has three buttons.
Two of them were toggle switches which could be turned either on or off.
The third was a simple button that could only be clicked.
We’ve already seen the Java code that provides the functionality for the two
toggle switches, from MP0 MainActivity.java
:
((ToggleButton) findViewById(R.id.enableLocation)).setOnCheckedChangeListener((v, setEnabled) -> {
enableOrDisableLocation(setEnabled);
});
((Switch) findViewById(R.id.wander)).setOnCheckedChangeListener((v, shouldWander) -> {
enableOrDisableLocation(locationEnabled);
});
But what is actually going on here? This is a topic that is hard to explain without using Android Studio, so please continue by viewing the screencast above. We’ll walk you through starting to use the UI designer in Android to examine and modify the MP1 user interface.
Do you need to know this to complete MP1? Yes! There is a small change to the UI that you need to make to pass the test suites.
4.2. Asynchronous Tasks
One of the core goals of every application, including smartphone apps, is to maintain a responsive user interface. If your app freezes for long periods of time, or even short ones, users will quickly stop using it.
Android accomplishes this by delegating certain slow operations to so-called background tasks. They then run independently of the user interface. So your app can be simultaneously responding to new user input and, for example, downloading a large file.
This is an advanced topic and not one that we expect you to master on this MP or
even on future ones.
But you will need to make small changes to Tasks.java
to produce a
fully-functional MP1 app, so learn more by watching the screencast above.
Our MP1 app uses two background tasks: one to download files and save them to
local storage, the second to run your image transformation functions.
The screencast above walks you through some of the task-related code in MP1 and
describes how tasks help maintain a responsive user interface.
Do you need to know this to complete MP1? Yes! There are some missing pieces in waiting for you to complete to get the app to work properly, although they aren’t tested by the test suite.
5. Troubleshooting
When building apps with Android Studio any one of a number of things can go wrong. We’ll try to keep an updated list here of troubleshooting strategies.
5.1. General Advice
If your app won’t build, try the following steps:
-
Restart Android Studio. Yes, this does in fact sometimes do the trick.
-
Invalidate Caches / Restart. You’ll find this under the "File" menu. Again, sometimes it seems to help.
-
Rebuild Project. You’ll find this under the "Build" menu. Sometimes rebuilding will help you pinpoint errors that are preventing your app from starting or the test suites from running.
6. Grading
MP1 is worth 100 points total, broken down as follows:
-
60 points:
Transform.java
-
10 points for completing the green screen transformation
-
15 points for completing the position shift transformations
-
15 points for completing the expand transformations
-
20 points for completing the rotation and flip transformations
-
-
20 points: the
app
module-
5 points for adding the missing button icon
-
15 points for fixing the broken buttons
-
-
10 points for no
checkstyle
violations -
10 points for submitting code that earns at least 40 points before Monday 2/11/2019 @ 5PM.
6.1. Test Cases
As in MP0, we have provided exhaustive test cases for each part of MP1. Please review the MP0 testing instructions.
6.2. Autograding
Like MP0 we have provided you with an autograding script that you can use to estimate your current grade as often as you want. Please use this script before you submit your code for official grading. That will reduce the load on our grading server and result in shorter waits for everyone—including you. Please review the MP0 autograding instructions.
7. Submitting Your Work
Follow the instructions from the submitting portion of the CS 125 workflow instructions.
And remember, you must submit something that earns 40 points before Monday 2/11/2019 @ 5PM to earn 10 points on the assignment.
7.1. Academic Integrity
Please review the MP0 academic integrity guidelines.
Here’s an example of the training that the CS 125 course staff undertakes to make sure we catch cheaters: