teaching machines

SENG 440: Lecture 15 – Camera

Dear students,

We are back from a break. I hope you grew as a human being. I did, and I’m hoping to change things up a bit in this second half of the semester. The first half was largely me leading you on code adventures in lecture. I really don’t enjoy teaching in this tutorial style. You are not active participants, and we take on too much. Sometimes I wish I was a literature professor and knew how to carry on critical discussions.

Alas, this is a technical course. We must start with low-level mechanics. The one thing I can do to enrich the discussion is flip things around so you are more involved. So, for the second half of the semester, our lectures will have a different format. For the first fifteen minutes or so, you will team up in small groups. Each group will be given a problem to solve—most likely a method to implement. Then we will take combine and discuss your solutions to complete the overall task of the lecture.

Probably I will struggle to get the timing right. But let’s try.

The theme of term 1 was the Android software platform. The theme of term 2 is the Android physical platform. We start with the camera. Today we will continue our Backlog app that we started before term 1 ended. Recall that the purpose of the app is to prompt the user to take a photo memory each day of their life. When they open the app, they will see pictures for the current day from 2019, 2018, 2017, and so on.

We have two options for working with the camera. If our app needs to be directly involved in the picture-taking process, perhaps providing our own camera widgets atop the visual field, or visualizing a couch in an augmented reality interior decorating app, then we must create a custom view that displays the camera feed live. If we just need access to the taken photos, we can use an implicit intent to fire off an existing camera app. Today we just need access to the taken photos.

If we need to create our own camera activity, we have two APIs to choose from. An older, deprecated one that is well-documented. Or a newer poorly-documented one.

Before we dive into the exercises, here’s your TODO for next time:

  • Read the Sensors Overview.
  • On a quarter sheet of paper to be turned in at the beginning of the next class, write down three questions or observations inspired by the reading. Is there a sensor you wish we had available?
  • Share a plan for your term 2 project on Slack, complete with sketches or wireframes of the user interface. Be sure to declare ownership of tasks. Don’t let collaborative development run afoul by not communicating.

Okay, let’s get going.

Activity

The user-interface and skeletal structure of the app has already been written. You will collaborate to complete this missing pieces to take pictures. Assume the following are already available in the activity:

  • Properties for the current year and the selected, 1-based month and day. All are Ints.
  • A property photoDirectory that yields a File pointing to a public directory on external storage named backlog. The directory might not exist yet. The directory, once it does exist, will have subdirectories for various years:
    backlog/
      2019/
        04_30.jpg
        04_29.jpg
        04_28.jpg
      2018/
        04_29.jpg
        04_28.jpg
  • A model for a day’s photo with the constructor Photo(val file: File).
  • An adapter to show a list of photos with the constructor PhotoAdapter(photos: List<Photo>).
  • A RecyclerView named photoList.

Also, you can and should make use of other teams’ methods.

Exercises

I recommend writing the code outside of Android Studio.

  1. Write method loadDayPhotos, which sets the list’s adapter to hold the photos from all years that have a photo for the current month and day. If the current date is 29 April and the directory is as shown above, then after this method runs, the photo list will have a new adapter holding the photos backlog/2019/04_29.jpg and backlog/2018/04_29.jpg. Keep this short with higher-order functions and lambdas. No loops are necessary. (< 10 lines of Kotlin)
  2. Write method dayFile, which accepts a year, a month, and a day, each an Int, and does two things: it returns a File pointing to the photo in the directory structure described above for the specified date, and it creates any missing parent directories that contain the file. (< 5 lines of Kotlin)
  3. Declare a FileProvider for the app, which we need because we want the camera activity to save our photo to our photo directory. Historically, we just sent a file:///-prefixed URI as an extra to specify the write location. But recent versions of Android outlaw sending raw URIs because they are a security risk. Provide files in the backlog directory in external storage. (< 10 lines of unwrapped XML)
  4. Write method dayUri, which accepts a year, a month, and a day, each an Int, and does two things: it returns a Uri pointing to the photo in the directory structured described above for the specified date, and it creates any missing parent directories that contain the file. The URI that you create must be shareable with the camera activity. Uri.fromFile does not create shareable URIs. Use a FileProvider to generate the URI. (< 5 lines of Kotlin)
  5. Write method takePictureFromCamera, which fires off an intent for the capturing an image—but only if there is an activity that can handle it. Pass along the URI pointing to the current day’s photo location. Use REQUEST_CAMERA for the request code. (< 10 lines of Kotlin)
  6. Write method takePictureFromGallery, which fires off an intent for choosing an image from the gallery. Use REQUEST_GALLERY for the request code. (< 10 lines of Kotlin)
  7. Write method copyUriToUri, which accepts a source Uri and a destination Uri. It copies the content of the source Uri to the destination Uri. Use ContentResolver to deal with the Uris. Kotlinisms like use and its java.io extension functions can make this short. (< 5 lines of Kotlin)
  8. Override method onActivityResult. If the camera activity succeeds, reload the current day’s photos. If the gallery activity succeeds, copy the Uri it returns to the current day’s Uri and reload the current day’s photos. Otherwise, defer to the superclass. (< 20 lines of Kotlin, many of which are curly braces)

Spend fifteen minutes on this. If you are able to share your code on Slack #general in a preformatted style, that’d be nice. Paper is okay too.

Sincerely,

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *