===================[ Google Maps ]=================== Google maps are complex objects with a rich API (https://developers.google.com/maps/documentation/android-api/map) The best way to understand this API is by going through examples of its use. You will find Google's tutorials at: https://developers.google.com/maps/documentation/android-api/map-with-marker -------[ Our code examples from class ]------- Basic map functionality: requesting the map, reacting to the map being retrieved and loaded, reacting to clicks on the map: examples/MereMapJava/ and examples/MereMapKt/ (same thing in Kotlin) Note that the code that gets the map is fully asynchronous: every action is implemented in callbacks, as loading the map tiles is likely to take a while. Also note that clicks on the map give you the GPS coordinates of the clicked point as the argument to your callback. Adding your location to the map and centering the map on it is also easy: you only need to implement another interface, LocationListener: examples/MapTracker Note the Factory design pattern for camera transactions. Design patterns are ways of organizing code to manage complexity, keep the code maintainable, or manage resources such as the memory footprint. The term was introduced in the famous book 1994 https://en.wikipedia.org/wiki/Design_Patterns (the four authors of this book, Gamma et al., are occasionally called "The Gang of Four"; you can see the book created lively debate). Since then, many elements of standard libraries in Java, Javascript, C++ etc. got the names of these design patterns. Factory is one of them, Model-View-Controller is another. The idea of a Factory is very simple (as are the ideas behind most of these design patterns; the point was to give these ideas well-known names)---you never call _new_ to make a new object. Instead, you ask for new instances from a single objects that is called a "factory". That object keeps track of all new objects being allocated, and can also help de-allocate them efficiently when no longer needed. With a bunch of objects created by calling "new", all these objects go on the Java heap; the garbage collector does not have any special new of them or knowledge of their intended use and lifetime. The Factory keeps track of all objects allocated through it and can provide such knowledge. Make a note to read about design patterns, e.g., the Visitor pattern, which is very useful when working with tree-like structures like XML DOM documents. -----------[ Location Tracking Demo ]----------- The location tracking demo from class is in http://www.cs.dartmouth.edu/~sergey/cs65/examples/LiveLocationDemo/ This demo has two tasks, one for continually uploading locations to the server, the other for receiving and showing them. Only one of these tasks is meant to run at any given time; you can think of how you could improve the design of this program to make both functions available. --------------------[ Kotlin ]-------------------- Some of the class examples are in Kotlin. Kotlin is a new language officially supported for Android programming (compare with Swift for the Apple ecosystem), and is both strictly typed and more concise than Java. Kotlin is designed to be entirely compatible with Java. Any Java object or library can be accessed from Kotlin. This was a necessity for Android, because Android programming depends on thousands of Java classes and libraries. Kotlin must interact with all of them seamlessly, and does. However, Kotlin makes its type-checking stricter than Java's. Strict typing helps catch programming errors and bugs at compile time rather than crashing on them at runtime. One of Kotlin's specific goals in language design is prevention of null pointer exceptions. By now you probably encountered enough of these to see why people care! Java's initial design was to allow "null" to pass type checking as a value of any type; an Object could be null, a View could be null, an Array could be null or could contain nulls mixed with other values. The Java type checker would complain if you tried to assign an Integer to a String variable or a View, but it would not complain if you assigned null to a variable of either of these types. In other words, null was a member of any type. The inventor of this convention, Sir C.A.R. Hoare (https://en.wikipedia.org/wiki/Tony_Hoare), called it his "billion dollar mistake". You may have felt its bite. Android's dialect of Java tries to cure this by annotating variables as @Nullable and @NotNull, to make programmer expectations explicit. Kotlin takes a different approach. In Kotlin, null is _not_ a member of any class. To assign null to a variable of a type String, or Bundle, or View, is a type error. If the programmer _wants_ null to be that variable's legitimate value, then its type should be respectively String?, Bundle?, or View?, and assigning that variable to one of the type String, etc., would not type-check. >>> var s : String = "" >>> var t : String? = "" >>> t = null >>> s = null error: null can not be a value of a non-null type String s = null ^ >>> t = s >>> s = t error: type mismatch: inferred type is String? but String was expected s = t ^ So, s.length will _never_ cause a NullPointerException, whereas in Java it might. Moreover, for t.length you get: >>> t.length error: only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver of type String? t.length ^ That is, if your type allows nulls (such as String? or Bundle?), you must use a special "safe" form of dereferencing it that knows what to do when it hits a null. Just "." won't be allowed by the type-checker. >>> t?.length // safe, gets you a null if t is null, no exception null If you are dead-set on betting the value will _not_ be null, then you can use !!. Then and only then you will pass the type-checking; your code will compile---and then and only then you will get a NullPointerException at runtime. >>> t!!.length kotlin.KotlinNullPointerException So String and String?, Bundle and Bundle?, etc., are different types, generally not compatible. But Kotlin also specifies that inside expressions that exclude null these types are fully compatible. So, if you have val t : String? = you only need to, e.g., put the illegal "s = t" or "t.length" inside if( t != null ){ .. }, and they become legal. This is called a "smart cast": String? becomes String inside such expressions. Note "val", not "var" above for the declaration of t. If t were declared as a variable, you 'd get a different kind of error: if( t != null ) t.length else -1 error: smart cast to 'String' is impossible, because 't' is a mutable property that could have been changed by this time Read further: https://kotlinlang.org/docs/reference/null-safety.html ===================[ Notifications ]=================== Notifications are an important part of Android's user experience. They underwent recent changes in Android 8.0 (API version 26). Applications send notifications to the system, to be displayed in the topmost notification bar. Notifications can include both icons and text, and can be presented in either short or expanded form (once the notification bar is pulled down). Generally speaking, a notification can be a fairly complex object, View-wise. For this reason, notifications are built with a Builder class, which creates their representations with some auto-formatting rules. Clicking on a notification typically launches an activity; the click may happen well after the original activity or app that posted the notification has quit. For this reason, Notifications wrap the intent to start the activity into a PendingIntent object, which saves the default permissions of the sending app, and delegates these permissions to the code that will be handling the notification. This is a subtle scheme, described in https://developer.android.com/reference/android/app/PendingIntent.html See examples/Notify/ and examples/NotiRemove The former had me scratching my head for a couple of hours, because of a subtle bug, where I was just not seeing what was literally written in the code. The NotificationActivity just wouldn't launch! This happened because I was sending an implicit intent rather than an explicit one, but did not notice that. NotiRemove shows how a SQLite database could be used to keep track of a series of IDs assigned to objects created by the app (Notifications, in this case). It's excessive for its use (see comments) but is very handy for storing a series of data objects of the same kind (e.g., locations visited, requests sent or received, etc.) Study these examples to get some finer points of writing Kotlin.