Milestone 3 Rubric

Personal Android Project

What's included in the third sprint, and how is it graded?

Overview

This is the third set of deliverables in the personal Android project, due at the end of the third sprint. In general, deliverables are cumulative: They include elements delivered in earlier sprints, but these should be updated as necessary, and they won’t be weighted as heavily in the grading. Thus, the content for this milestone is expected to include project summary and design elements, as well as the data model documentation included in the first milestone—all updated as necessary—along with new elements for this milestone.

Note: If elements that were previously delivered for the first or second milestone are also included in this milestone, but do not correspond to the project in its current state—or if you have not addressed issues that were raised in the grading and feedback for the first or second milestone—you will not get full credit for those elements.

The nominal total value of this deliverable is 50 points; in addition, up to 10 points of extra credit can be earned for exemplary execution of any or all of the required elements.

Elements

Project description: 1 point

See “Milestone 1: Project description” for this element’s requirements.

Intended users and user stories: 1 point

See “Milestone 1: Intended users and user stories” for this element’s requirements.

Wireframe diagram: 2 points

See “Milestone 1: Wireframe diagram” for this element’s requirements. Please note that even though the navigation features of your app are incomplete at this point, you must update the wireframe if—while working on the navigation—you have changed your planned flow through the different screens.

UML class diagram: 2 points

See “Milestone 1: UML class diagram” for this element’s requirements. Also, please note that any updates to the acessible attributes (properties) and operations (constructor and method declarations) in the domain classes must be reflected in corresponding changes to the UML, and vice versa.

Cloud- or device-based services or data: 1 point

See “Milestone 1: Cloud- or device-based services or data” for this element’s requirements. Please note that if you are using any service that requires you to register for a account, you should do so ASAP (if you haven’t done already).

Entity-relationship diagram (ERD): 4 points

See “Milestone 2: Entity-relationship diagram (ERD)” for this element’s requirements. Also, please note that any updates to the persistent elements of the entity classes must be reflected in corresponding changes to the ERD, and vice versa.

Entity classes: 4 points

See “Milestone 2: Entity classes” for this element’s requirements.

DAO interfaces: 4 points

See “Milestone 2: DAO interfaces for this element’s requirements.

Database class: 3 points

See “Milestone 2: Database class for this element’s requirements. Don’t forget to update the entities element of the @Database annotation if you added, removed, or renamed any of your entity classes; also, make sure the abstract getters for DAOs in this class are consistent with your current DAOs.

DDL: 3 points

See “Milestone 2: DDL for this element’s requirements. Please remember to update the DDL as necessary, along with the ERD, as the entity classes are modified.

Hilt module for database and DAOs: 4 points

  1. Your code must include a class (in a package named hilt, created as a subpackage of the project base package) annotated with @InstallIn(SingletonComponent.class) and @Module.

  2. This class must either have no constructors explicitly declared (i.e., only the compiler-generated default constructor, with no parameters), or—if there is at least one constructor explicitly declared, there must be one constructor without any parameter. If a no-parameter constructor is explicitly declared, it should have the package-private access level. The body of the constructor can be empty—privoded, of course, there are no fields of the class (typically not needed in a Hilt module of this kind) requiring initialization in the constructor.

  3. This class must have one public method to provide an instance of the database, and another public method for each DAO interface, to provide an instance for the given DAO. All of these methods must be annotated with both @Provides and @Singleton.

    1. The method to provide an instance of the database must declare a parameter of the type Context, annotated with @AppContext. This method must use the Room.databaseBuilder method (passing the received context, along with the database class and database name, as arguments) to create an instance of RoomDatabase.Builder; after any required configuration method invocations, the build() method must be invoked on the RoomDatabase.Builder, to create an instance of your database class. This last instance is the one that must be returned by this method.

    2. Each of the methods that returns a DAO instance must do so by taking an instance of your database as a parameter, then (in the body of the method) invoking the corresponding DAO getter method on the database instance to get the DAO instance, and finally returning the DAO instance.

    You should use the edu.cnm.deepdive.codebreaker.hilt.CodebreakerDatabaseModule class from your codebreaker-android project as an example of this kind of Hilt module.

Repository classes: 7 points

  1. For at least every entity type that will need to be written to or read from the database directly, as an instance or collection of that entity type (rather than simply being written to the database as a companion operation to reading, writing, or updating a parent entity instance), you must create a repository class:

  2. Repository classes must be located in a service package, which itself must be a subpackage of your application base package.

  3. Each repository class must have a package-private constructor with the @Inject annotation, and with parameters that Hilt will be able to satisfy (e.g., one or more DAOs provided by the Hilt database module, an @ApplicationContext-annotated Context instance). These parameters make up the main part of the repository class’s dependencies, and they should either be used in the code of the constructor alone, or saved into instance fields of the repository.

  4. Each repository must have methods that—taken together—invoke all of the methods in the DAOs that the repositories depend upon. For any of those DAO methods that return ReactiveX types (e.g. Single, Completable), the repository methods must also use subscribeOn (or, in some cases, observeOn) to specify a Scheduler that will manage the aynchronous processing of the reactive stream. (For database persistence operations, this will typically be a Scheduler returned from the Schedulers.io() method. Alternatively, if the order of asynchronous operations is preserved, we might use a Scheduler returned from Schedulers.single(), and assigned to a field in repository initialization. Or, if we simply want to limit the number of threads consumed by our asynchronous operations—e.g., for constraining the number of simultanous requests to a web service—we might use Schedulers.from(Executors.newFixedThreadPool(int)) in the constructor, assign the Scheduler returned to a field, and then specify that scheduler in subscribeOn.)

    You should use the edu.cnm.deepdive.codebreaker.service.GameResultRepository class from the codebreaker-android project as an example of this kind of repository class.

  1. For each screen (including settings and dialog screens) that your app will display, after completion of the sign-in process (that is, don’t include the sign-in screen), your project must include a Fragment subclass. (Settings screens typically extend PreferenceFragmentCompat, dialog screens extend DialogFragment or BottomSheetDialogFragment; other fragments usually extend Fragment itself.)

  2. All of these fragment classes must be referenced in <fragment> or <dialog> elements of a navigation graph resource. This is a resource file with <navigation> as a root element, located in res/navigation.

  3. Your navigation graph must include <action> elements that are not inconsistent with your wireframe (and vice versa). So, if your wireframe shows a button in one of your screens, and includes a line indicating that clicking that button will lead the user to a specific second screen, then the <fragment> (in the navigation graph) corresponding to the fragment implementing the first screen should include an <action> with an app:destination attribute referring to the fragment implementing the second screen. (The main reason you might not include such an <action> in the first <fragment> would be that the app will have several navigational paths—originating in multiple screens—leading to that second screen, in which case a top-level <action>, defined directly in the root <navigation> element, might be more appropriate.)

Build, launch, and initial navigation: 7 points

  1. For full credit on this item, your app must build and launch.

  2. After completing the Google Sign In, there must be at least two reachable navigation destinations (fragments): the first is the starting destination in your navigation graph; when that fragment is visible, there must be a means provided (button, navigation menu item, etc.) to navigate to at least one of the other fragments in the navigation graph. In other words, while your navigation graph is expected to include all of your planned fragments that will be hosted in the main activity, and any necessary <action> elements to navigate between them, you don’t (yet) need to have all of that navigation capability implemented in your UI.