Skip to content

Commit

Permalink
Use Firebase for settings
Browse files Browse the repository at this point in the history
- Commute home and work address, travel mode
- Compact UI configuration

Also upgrading dependencies and using Java 8 features
  • Loading branch information
maxbbraun committed Dec 16, 2018
1 parent 7ba09b4 commit 46b8a77
Show file tree
Hide file tree
Showing 16 changed files with 374 additions and 129 deletions.
37 changes: 30 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,35 @@
# Smart Mirror

This is the source code for the prototype UI of my smart mirror projects outlined in [this article](https://medium.com/@maxbraun/my-bathroom-mirror-is-smarter-than-yours-94b21c6671ba) and its [follow-up](https://medium.com/@maxbraun/smarter-mirrors-and-how-theyre-made-327997b9eff7).

[!["Smart Mirror"](mirror.jpg)](https://medium.com/@maxbraun/my-bathroom-mirror-is-smarter-than-yours-94b21c6671ba#.4exmyxt0w)

Simply import the whole project into [Android Studio](http://developer.android.com/tools/studio/index.html), then build and run the apk. The first prototype uses [`HomeActivity.java`](app/src/main/java/net/maxbraun/mirror/HomeActivity.java) and the second one uses [`CompactHomeActivity.java`](app/src/main/java/net/maxbraun/mirror/CompactHomeActivity.java).

While the time, date, and news show up without any additional changes, you need to first enable the respective APIs in order to see the weather, commute, and body measures. Edit [`keys.xml`](app/src/main/res/values/keys.xml) and enter the key for the [Dark Sky API](https://darksky.net/dev/), the key for the [Google Maps Directions API](https://developers.google.com/maps/documentation/directions/start), and multiple keys for the [Nokia Health API](https://developer.health.nokia.com/oauth2/). The home and work addresses for the commute need to be entered in [`commute.xml`](app/src/main/res/values/commute.xml).
This is the source code for the prototype UI of my smart mirror projects outlined in
[this article](https://medium.com/@maxbraun/my-bathroom-mirror-is-smarter-than-yours-94b21c6671ba)
and its [follow-up](https://medium.com/@maxbraun/smarter-mirrors-and-how-theyre-made-327997b9eff7).

[![Smart Mirror 1](mirror-1.jpg)](https://medium.com/@maxbraun/my-bathroom-mirror-is-smarter-than-yours-94b21c6671ba)

[![Smart Mirror 2](mirror-2.jpg)](https://medium.com/@maxbraun/smarter-mirrors-and-how-theyre-made-327997b9eff7)

To get started, import the whole project into
[Android Studio](http://developer.android.com/tools/studio/index.html), then build and run the apk.
The first prototype uses
[`HomeActivity.java`](app/src/main/java/net/maxbraun/mirror/HomeActivity.java) and the second one
uses [`CompactHomeActivity.java`](app/src/main/java/net/maxbraun/mirror/CompactHomeActivity.java).

While the time, date, and news show up without any additional changes, you need to first enable the
respective APIs in order to see the weather, commute, and body measures. Edit
[`keys.xml`](app/src/main/res/values/keys.xml) and enter the key for the
[Dark Sky API](https://darksky.net/dev/), the key for the
[Google Maps Directions API](https://developers.google.com/maps/documentation/directions/start), and
multiple keys for the [Nokia Health API](https://developer.health.nokia.com/oauth2/).

The home and work addresses and the travel mode for the commute are pulled from a
[Firebase Realtime Database](https://firebase.google.com/docs/database/) and can be edited in the
[Firebase Console](https://console.firebase.google.com/) after
[adding Firebase to your Android Studio project](https://firebase.google.com/docs/android/setup).
The client expects a `commute_settings` path with string children `home`, `work`, and `travel_mode`.
The composition of the [compact UI](app/src/main/java/net/maxbraun/mirror/CompactHomeActivity.java)
is also configured via the Firebase Database: The `compact_ui_settings` path has boolean children
for `body`, `commute`, `time`, and `weather` that determine which ones are shown. See
[`database-example.json`](database-example.json) for a sample layout.

## License

Expand Down
52 changes: 36 additions & 16 deletions app/app.iml
Original file line number Diff line number Diff line change
Expand Up @@ -22,20 +22,21 @@
</configuration>
</facet>
</component>
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_7">
<output url="file://$MODULE_DIR$/build/intermediates/classes/debug" />
<output-test url="file://$MODULE_DIR$/build/intermediates/classes/test/debug" />
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_8">
<output url="file://$MODULE_DIR$/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes" />
<output-test url="file://$MODULE_DIR$/build/intermediates/javac/debugUnitTest/compileDebugUnitTestJavaWithJavac/classes" />
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/apt/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/r/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/not_namespaced_r_class_sources/debug/processDebugResources/r" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/aidl/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/google-services/debug" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/debug" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/resValues/debug" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/apt/androidTest/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/r/androidTest/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/not_namespaced_r_class_sources/debugAndroidTest/processDebugAndroidTestResources/r" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/aidl/androidTest/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/androidTest/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/androidTest/debug" isTestSource="true" generated="true" />
Expand Down Expand Up @@ -84,43 +85,62 @@
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/rs" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/shaders" isTestSource="true" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/assets" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/annotation_processor_list" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/apk_list" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/blame" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/build-info" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/builds" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/check-libraries" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/check-manifest" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/classes" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/checkDebugClasspath" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/compatible_screen_manifest" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental-classes" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental-runtime-classes" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental-verifier" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/instant-run-apk" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/instant-run-resources" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/javaPrecompile" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/instant_run_merged_manifests" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/instant_run_split_apk_resources" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/javac" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/jniLibs" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/lint" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/manifest-checker" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/manifests" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/merged_assets" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/merged_manifests" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/prebuild" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/processed_res" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/reload-dex" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/res" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/resources" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/rs" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/shader_assets" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/shaders" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/split-apk" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/splits-support" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/split_list" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/symbols" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/transforms" />
<excludeFolder url="file://$MODULE_DIR$/build/outputs" />
<excludeFolder url="file://$MODULE_DIR$/build/tmp" />
</content>
<orderEntry type="jdk" jdkName="Android API 23 Platform" jdkType="Android SDK" />
<orderEntry type="jdk" jdkName="Android API 26 Platform" jdkType="Android SDK" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="Gradle: com.android.support:support-v4-23.4.0" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:support-annotations:23.4.0@jar" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:recyclerview-v7-23.4.0" level="project" />
<orderEntry type="library" name="Gradle: com.google.android.gms:play-services-base-16.0.1" level="project" />
<orderEntry type="library" name="Gradle: com.google.firebase:firebase-database-collection-16.0.1" level="project" />
<orderEntry type="library" name="Gradle: com.google.android.gms:play-services-tasks-16.0.1" level="project" />
<orderEntry type="library" name="Gradle: android.arch.lifecycle:common:1.0.0@jar" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:support-core-ui-26.1.0" level="project" />
<orderEntry type="library" name="Gradle: com.google.firebase:firebase-common-16.0.4" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:support-core-utils-26.1.0" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:support-fragment-26.1.0" level="project" />
<orderEntry type="library" name="Gradle: android.arch.core:common:1.0.0@jar" level="project" />
<orderEntry type="library" name="Gradle: com.google.android.gms:play-services-basement-16.0.1" level="project" />
<orderEntry type="library" name="Gradle: com.github.scribejava:scribejava-apis:5.5.0@jar" level="project" />
<orderEntry type="library" name="Gradle: com.github.scribejava:scribejava-core:5.5.0@jar" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:leanback-v17-23.4.0" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:support-media-compat-26.1.0" level="project" />
<orderEntry type="library" name="Gradle: com.google.firebase:firebase-database-16.0.5" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:support-annotations:26.1.0@jar" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:support-compat-26.1.0" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:support-v4-26.1.0" level="project" />
<orderEntry type="library" name="Gradle: android.arch.lifecycle:runtime-1.0.0" level="project" />
</component>
</module>
12 changes: 9 additions & 3 deletions app/build.gradle
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
apply plugin: 'com.android.application'

android {
compileSdkVersion 23
compileSdkVersion 26
defaultConfig {
applicationId "net.maxbraun.mirror"
minSdkVersion 22
targetSdkVersion 22
targetSdkVersion 26
versionCode 1
versionName "1.0"
}
Expand All @@ -15,10 +15,16 @@ android {
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility = '1.8'
targetCompatibility = '1.8'
}
}

dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:leanback-v17:23.4.0'
implementation 'com.github.scribejava:scribejava-apis:5.5.0'
implementation 'com.google.firebase:firebase-database:16.0.5'
}

apply plugin: 'com.google.gms.google-services'
5 changes: 0 additions & 5 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,6 @@
package="net.maxbraun.mirror"
xmlns:android="http://schemas.android.com/apk/res/android">

<uses-feature
android:name="android.software.leanback"
android:required="true"/>
<uses-feature
android:name="android.hardware.touchscreen"
android:required="false"/>
Expand Down Expand Up @@ -34,7 +31,6 @@
<intent-filter android:priority="11">
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
<category android:name="android.intent.category.LEANBACK_LAUNCHER"/>
<category android:name="android.intent.category.HOME"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
Expand All @@ -52,7 +48,6 @@
<intent-filter android:priority="11">
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
<category android:name="android.intent.category.LEANBACK_LAUNCHER"/>
<category android:name="android.intent.category.HOME"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
Expand Down
10 changes: 2 additions & 8 deletions app/src/main/java/net/maxbraun/mirror/Body.java
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
package net.maxbraun.mirror;

import android.app.Activity;
import android.content.Context;
import android.util.Log;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.TimeUnit;
Expand Down Expand Up @@ -146,12 +144,8 @@ private static BodyMeasure[] parseBodyMeasures(JSONObject response) throws JSONE
}

// Make sure the measures are sorted by ascending timestamp.
Collections.sort(bodyMeasures, new Comparator<BodyMeasure>() {
@Override
public int compare(BodyMeasure lhs, BodyMeasure rhs) {
return Long.compare(lhs.timestamp, rhs.timestamp);
}
});
Collections.sort(bodyMeasures,
(BodyMeasure lhs, BodyMeasure rhs) -> Long.compare(lhs.timestamp, rhs.timestamp));

return bodyMeasures.toArray(new BodyMeasure[bodyMeasures.size()]);
}
Expand Down
Loading

0 comments on commit 46b8a77

Please sign in to comment.