First Commit
@ -0,0 +1,13 @@
|
||||
package haus.nightmare.GlassTesla;
|
||||
|
||||
import android.app.Application;
|
||||
import android.test.ApplicationTestCase;
|
||||
|
||||
/**
|
||||
* <a href="http://d.android.com/tools/testing/testing_android.html">Testing Fundamentals</a>
|
||||
*/
|
||||
public class ApplicationTest extends ApplicationTestCase<Application> {
|
||||
public ApplicationTest() {
|
||||
super(Application.class);
|
||||
}
|
||||
}
|
||||
33
app/src/main/AndroidManifest.xml
Normal file
@ -0,0 +1,33 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
package="haus.nightmare.GlassTesla">
|
||||
|
||||
<uses-permission android:name="com.google.android.glass.permission.DEVELOPMENT" />
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:supportsRtl="true"
|
||||
tools:ignore="GoogleAppIndexingWarning">
|
||||
<activity
|
||||
android:name="haus.nightmare.GlassTesla.MainActivity"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/title_activity_main">
|
||||
<intent-filter>
|
||||
<action android:name="com.google.android.glass.action.VOICE_TRIGGER" />
|
||||
</intent-filter>
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
|
||||
<meta-data
|
||||
android:name="com.google.android.glass.VoiceTrigger"
|
||||
android:resource="@xml/voice_trigger" />
|
||||
</activity>
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
47
app/src/main/java/haus/nightmare/GlassTesla/ChargeState.java
Normal file
@ -0,0 +1,47 @@
|
||||
package haus.nightmare.GlassTesla;
|
||||
|
||||
public class ChargeState {
|
||||
public boolean battery_heater_on;
|
||||
public int battery_level;
|
||||
public double battery_range;
|
||||
public int charge_current_request;
|
||||
public int charge_current_request_max;
|
||||
public boolean charge_enable_request;
|
||||
public double charge_energy_added;
|
||||
public int charge_limit_soc;
|
||||
public int charge_limit_soc_max;
|
||||
public int charge_limit_soc_min;
|
||||
public int charge_limit_soc_std;
|
||||
public double charge_miles_added_ideal;
|
||||
public double charge_miles_added_rated;
|
||||
public Object charge_port_cold_weather_mode;
|
||||
public boolean charge_port_door_open;
|
||||
public String charge_port_latch;
|
||||
public double charge_rate;
|
||||
public boolean charge_to_max_range;
|
||||
public int charger_actual_current;
|
||||
public int charger_phases;
|
||||
public int charger_pilot_current;
|
||||
public int charger_power;
|
||||
public int charger_voltage;
|
||||
public String charging_state;
|
||||
public String conn_charge_cable;
|
||||
public double est_battery_range;
|
||||
public String fast_charger_brand;
|
||||
public boolean fast_charger_present;
|
||||
public String fast_charger_type;
|
||||
public double ideal_battery_range;
|
||||
public boolean managed_charging_active;
|
||||
public Object managed_charging_start_time;
|
||||
public boolean managed_charging_user_canceled;
|
||||
public int max_range_charge_counter;
|
||||
public int minutes_to_full_charge;
|
||||
public boolean not_enough_power_to_heat;
|
||||
public boolean scheduled_charging_pending;
|
||||
public Object scheduled_charging_start_time;
|
||||
public double time_to_full_charge;
|
||||
public long timestamp;
|
||||
public boolean trip_charging;
|
||||
public int usable_battery_level;
|
||||
public Object user_charge_enable_request;
|
||||
}
|
||||
@ -0,0 +1,28 @@
|
||||
package haus.nightmare.GlassTesla;
|
||||
|
||||
public class ClimateState {
|
||||
public boolean battery_heater;
|
||||
public boolean battery_heater_no_power;
|
||||
public String climate_keeper_mode;
|
||||
public int defrost_mode;
|
||||
public double driver_temp_setting;
|
||||
public int fan_status;
|
||||
public double inside_temp;
|
||||
public boolean is_auto_conditioning_on;
|
||||
public boolean is_climate_on;
|
||||
public boolean is_front_defroster_on;
|
||||
public boolean is_preconditioning;
|
||||
public boolean is_rear_defroster_on;
|
||||
public int left_temp_direction;
|
||||
public double max_avail_temp;
|
||||
public double min_avail_temp;
|
||||
public double outside_temp;
|
||||
public double passenger_temp_setting;
|
||||
public boolean remote_heater_control_enabled;
|
||||
public int right_temp_direction;
|
||||
public int seat_heater_left;
|
||||
public int seat_heater_right;
|
||||
public boolean side_mirror_heaters;
|
||||
public long timestamp;
|
||||
public boolean wiper_blade_heater;
|
||||
}
|
||||
20
app/src/main/java/haus/nightmare/GlassTesla/DriveState.java
Normal file
@ -0,0 +1,20 @@
|
||||
package haus.nightmare.GlassTesla;
|
||||
|
||||
// import com.fasterxml.jackson.databind.ObjectMapper; // version 2.11.1
|
||||
// import com.fasterxml.jackson.annotation.JsonProperty; // version 2.11.1
|
||||
/* ObjectMapper om = new ObjectMapper();
|
||||
Root root = om.readValue(myJsonString, Root.class); */
|
||||
public class DriveState {
|
||||
public int gps_as_of;
|
||||
public int heading;
|
||||
public double latitude;
|
||||
public double longitude;
|
||||
public double native_latitude;
|
||||
public int native_location_supported;
|
||||
public double native_longitude;
|
||||
public String native_type;
|
||||
public int power;
|
||||
public Object shift_state;
|
||||
public Object speed;
|
||||
public long timestamp;
|
||||
}
|
||||
11
app/src/main/java/haus/nightmare/GlassTesla/GuiSettings.java
Normal file
@ -0,0 +1,11 @@
|
||||
package haus.nightmare.GlassTesla;
|
||||
|
||||
public class GuiSettings {
|
||||
public boolean gui_24_hour_time;
|
||||
public String gui_charge_rate_units;
|
||||
public String gui_distance_units;
|
||||
public String gui_range_display;
|
||||
public String gui_temperature_units;
|
||||
public boolean show_range_units;
|
||||
public long timestamp;
|
||||
}
|
||||
190
app/src/main/java/haus/nightmare/GlassTesla/MainActivity.java
Normal file
@ -0,0 +1,190 @@
|
||||
package haus.nightmare.GlassTesla;
|
||||
|
||||
import com.google.android.glass.media.Sounds;
|
||||
import com.google.android.glass.widget.CardBuilder;
|
||||
import com.google.android.glass.widget.CardScrollAdapter;
|
||||
import com.google.android.glass.widget.CardScrollView;
|
||||
import com.google.gson.Gson;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.media.AudioManager;
|
||||
import android.os.Bundle;
|
||||
import android.os.StrictMode;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.AdapterView;
|
||||
|
||||
import org.conscrypt.Conscrypt;
|
||||
|
||||
import java.net.URL;
|
||||
import java.security.Security;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Calendar;
|
||||
|
||||
import javax.net.ssl.SSLException;
|
||||
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
|
||||
|
||||
public class MainActivity extends Activity {
|
||||
|
||||
private CardScrollView cardScroller;
|
||||
|
||||
private View view;
|
||||
private TeslaResponse vehicleData;
|
||||
private SharedPreferences prefs;
|
||||
@Override
|
||||
protected void onCreate(Bundle bundle) {
|
||||
super.onCreate(bundle);
|
||||
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
|
||||
StrictMode.setThreadPolicy(policy);
|
||||
prefs = getPreferences(MODE_PRIVATE);
|
||||
view = buildStatusView();
|
||||
view.setKeepScreenOn(true);
|
||||
cardScroller = new CardScrollView(this);
|
||||
cardScroller.setAdapter(new CardScrollAdapter() {
|
||||
@Override
|
||||
public int getCount() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getItem(int position) {
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPosition(Object item) {
|
||||
if (view.equals(item)) {
|
||||
return 0;
|
||||
}
|
||||
return AdapterView.INVALID_POSITION;
|
||||
}
|
||||
});
|
||||
|
||||
cardScroller.setOnItemClickListener(new AdapterView.OnItemClickListener() {
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
||||
AudioManager am = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
|
||||
am.playSoundEffect(Sounds.TAP);
|
||||
|
||||
}
|
||||
});
|
||||
setContentView(cardScroller);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
cardScroller.activate();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
cardScroller.deactivate();
|
||||
super.onPause();
|
||||
}
|
||||
|
||||
private View buildStatusView() {
|
||||
if (vehicleData == null) {
|
||||
try {
|
||||
getVehicleData();
|
||||
} catch(Exception e) {
|
||||
Log.v("Tesla API Setup", "Unable to get Tesla data", e);
|
||||
this.finishAffinity();
|
||||
System.exit(0); // Shouldn't be reached, but just in case let's kill it dead
|
||||
}
|
||||
}
|
||||
|
||||
CardBuilder card = new CardBuilder(this, CardBuilder.Layout.TEXT);
|
||||
String chargeDuration = "";
|
||||
int totalSecs = (int) (vehicleData.charge_state.time_to_full_charge * 3600);
|
||||
int hours = totalSecs / 3600;
|
||||
int minutes = (totalSecs % 3600) / 60;
|
||||
if (hours > 0) {
|
||||
chargeDuration += hours + "h";
|
||||
}
|
||||
if (minutes > 0) {
|
||||
chargeDuration += minutes + "m";
|
||||
}
|
||||
Calendar cal = Calendar.getInstance();
|
||||
cal.add(Calendar.HOUR_OF_DAY, hours);
|
||||
cal.add(Calendar.MINUTE, minutes);
|
||||
card.setText(
|
||||
String.format(getString(R.string.StatusFormat),
|
||||
vehicleData.charge_state.battery_level,
|
||||
(int) vehicleData.charge_state.battery_range,
|
||||
vehicleData.vehicle_state.sentry_mode ? "Enabled" : "Disabled",
|
||||
vehicleData.charge_state.charging_state,
|
||||
vehicleData.charge_state.charger_power,
|
||||
chargeDuration,
|
||||
new SimpleDateFormat("hh:mm").format(cal.getTime())
|
||||
)
|
||||
);
|
||||
card.setFootnote(String.format("%s last updated: %s",
|
||||
vehicleData.display_name,
|
||||
new SimpleDateFormat("hh:mm").format(vehicleData.charge_state.timestamp)
|
||||
));
|
||||
|
||||
return card.getView();
|
||||
}
|
||||
|
||||
// /api/1/vehicles/{id}/vehicle_data
|
||||
public void getVehicleData() {
|
||||
String vehicleId = prefs.getString("vehicle_id", "");
|
||||
String json = getResponseFromJsonURL("https://owner-api.teslamotors.com/api/1/vehicles/" + vehicleId +"/vehicle_data");
|
||||
Gson gson = new Gson();
|
||||
ResponseRoot root = gson.fromJson(json, ResponseRoot.class);
|
||||
vehicleData = root.response;
|
||||
}
|
||||
public String getResponseFromJsonURL(String url) {
|
||||
String token = prefs.getString("bearer_token", "");
|
||||
|
||||
String jsonResponse = null;
|
||||
if (url.length() > 0) {
|
||||
try {
|
||||
Security.insertProviderAt(Conscrypt.newProvider(), 1);
|
||||
|
||||
|
||||
|
||||
/************** For getting response from HTTP URL start ***************/
|
||||
URL object = new URL(url);
|
||||
|
||||
OkHttpClient client = new OkHttpClient();
|
||||
Request request = new Request.Builder()
|
||||
.url(object)
|
||||
.addHeader("Authorization", "Bearer " + token)
|
||||
.addHeader("User-Agent", "Tesla-GLASS")
|
||||
.addHeader("Content-Type", "application/json")
|
||||
.build();
|
||||
|
||||
Response response = client.newCall(request).execute();
|
||||
|
||||
int responseCode = response.code();
|
||||
|
||||
if (responseCode == 200) {
|
||||
return response.body().string();
|
||||
|
||||
}
|
||||
} catch (SSLException e) {
|
||||
Log.e("DataSSL", "SSL Exception getting json:", e);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return jsonResponse;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,5 @@
|
||||
package haus.nightmare.GlassTesla;
|
||||
|
||||
public class MediaState {
|
||||
public boolean remote_control_enabled;
|
||||
}
|
||||
@ -0,0 +1,5 @@
|
||||
package haus.nightmare.GlassTesla;
|
||||
|
||||
public class ResponseRoot {
|
||||
public TeslaResponse response;
|
||||
}
|
||||
@ -0,0 +1,9 @@
|
||||
package haus.nightmare.GlassTesla;
|
||||
|
||||
public class SoftwareUpdate {
|
||||
public int download_perc;
|
||||
public int expected_duration_sec;
|
||||
public int install_perc;
|
||||
public String status;
|
||||
public String version;
|
||||
}
|
||||
@ -0,0 +1,9 @@
|
||||
package haus.nightmare.GlassTesla;
|
||||
|
||||
public class SpeedLimitMode {
|
||||
public boolean active;
|
||||
public double current_limit_mph;
|
||||
public int max_limit_mph;
|
||||
public int min_limit_mph;
|
||||
public boolean pin_code_set;
|
||||
}
|
||||
@ -0,0 +1,30 @@
|
||||
package haus.nightmare.GlassTesla;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
|
||||
public class TeslaResponse{
|
||||
public long id;
|
||||
public long user_id;
|
||||
public long vehicle_id;
|
||||
public String vin;
|
||||
public String display_name;
|
||||
public String option_codes;
|
||||
public Object color;
|
||||
public String access_type;
|
||||
public ArrayList<String> tokens;
|
||||
public String state;
|
||||
public boolean in_service;
|
||||
public String id_s;
|
||||
public boolean calendar_enabled;
|
||||
public int api_version;
|
||||
public Object backseat_token;
|
||||
public Object backseat_token_updated_at;
|
||||
public DriveState drive_state;
|
||||
public ClimateState climate_state;
|
||||
public ChargeState charge_state;
|
||||
public GuiSettings gui_settings;
|
||||
public VehicleState vehicle_state;
|
||||
public VehicleConfig vehicle_config;
|
||||
}
|
||||
|
||||
@ -0,0 +1,29 @@
|
||||
package haus.nightmare.GlassTesla;
|
||||
|
||||
public class VehicleConfig {
|
||||
public boolean can_accept_navigation_requests;
|
||||
public boolean can_actuate_trunks;
|
||||
public String car_special_type;
|
||||
public String car_type;
|
||||
public String charge_port_type;
|
||||
public boolean default_charge_to_max;
|
||||
public boolean ece_restrictions;
|
||||
public boolean eu_vehicle;
|
||||
public String exterior_color;
|
||||
public boolean has_air_suspension;
|
||||
public boolean has_ludicrous_mode;
|
||||
public boolean motorized_charge_port;
|
||||
public boolean plg;
|
||||
public int rear_seat_heaters;
|
||||
public int rear_seat_type;
|
||||
public boolean rhd;
|
||||
public String roof_color;
|
||||
public int seat_type;
|
||||
public String spoiler_type;
|
||||
public int sun_roof_installed;
|
||||
public String third_row_seats;
|
||||
public long timestamp;
|
||||
public String trim_badging;
|
||||
public boolean use_range_badging;
|
||||
public String wheel_type;
|
||||
}
|
||||
@ -0,0 +1,44 @@
|
||||
package haus.nightmare.GlassTesla;
|
||||
|
||||
public class VehicleState {
|
||||
public int api_version;
|
||||
public String autopark_state_v2;
|
||||
public String autopark_style;
|
||||
public boolean calendar_supported;
|
||||
public String car_version;
|
||||
public int center_display_state;
|
||||
public int df;
|
||||
public int dr;
|
||||
public int fd_window;
|
||||
public int fp_window;
|
||||
public int ft;
|
||||
public int homelink_device_count;
|
||||
public boolean homelink_nearby;
|
||||
public boolean is_user_present;
|
||||
public String last_autopark_error;
|
||||
public boolean locked;
|
||||
public MediaState media_state;
|
||||
public boolean notifications_supported;
|
||||
public double odometer;
|
||||
public boolean parsed_calendar_supported;
|
||||
public int pf;
|
||||
public int pr;
|
||||
public int rd_window;
|
||||
public boolean remote_start;
|
||||
public boolean remote_start_enabled;
|
||||
public boolean remote_start_supported;
|
||||
public int rp_window;
|
||||
public int rt;
|
||||
public boolean sentry_mode;
|
||||
public boolean sentry_mode_available;
|
||||
public boolean smart_summon_available;
|
||||
public SoftwareUpdate software_update;
|
||||
public SpeedLimitMode speed_limit_mode;
|
||||
public boolean summon_standby_mode_enabled;
|
||||
public int sun_roof_percent_open;
|
||||
public String sun_roof_state;
|
||||
public long timestamp;
|
||||
public boolean valet_mode;
|
||||
public boolean valet_pin_needed;
|
||||
public Object vehicle_name;
|
||||
}
|
||||
BIN
app/src/main/res/drawable-hdpi/ic_glass_logo.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
app/src/main/res/drawable-hdpi/ic_stop.png
Normal file
|
After Width: | Height: | Size: 633 B |
BIN
app/src/main/res/mipmap-hdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 5.0 KiB |
BIN
app/src/main/res/mipmap-hdpi/ic_launcher_adaptive_back.png
Normal file
|
After Width: | Height: | Size: 5.0 KiB |
BIN
app/src/main/res/mipmap-hdpi/ic_launcher_adaptive_fore.png
Normal file
|
After Width: | Height: | Size: 4.4 KiB |
BIN
app/src/main/res/mipmap-mdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 3.2 KiB |
BIN
app/src/main/res/mipmap-mdpi/ic_launcher_adaptive_back.png
Normal file
|
After Width: | Height: | Size: 2.8 KiB |
BIN
app/src/main/res/mipmap-mdpi/ic_launcher_adaptive_fore.png
Normal file
|
After Width: | Height: | Size: 2.4 KiB |
BIN
app/src/main/res/mipmap-xhdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 7.8 KiB |
BIN
app/src/main/res/mipmap-xhdpi/ic_launcher_adaptive_back.png
Normal file
|
After Width: | Height: | Size: 7.9 KiB |
BIN
app/src/main/res/mipmap-xhdpi/ic_launcher_adaptive_fore.png
Normal file
|
After Width: | Height: | Size: 5.5 KiB |
BIN
app/src/main/res/mipmap-xxhdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
app/src/main/res/mipmap-xxhdpi/ic_launcher_adaptive_back.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
app/src/main/res/mipmap-xxhdpi/ic_launcher_adaptive_fore.png
Normal file
|
After Width: | Height: | Size: 10 KiB |
BIN
app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
app/src/main/res/mipmap-xxxhdpi/ic_launcher_adaptive_back.png
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
app/src/main/res/mipmap-xxxhdpi/ic_launcher_adaptive_fore.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
7
app/src/main/res/values/strings.xml
Normal file
@ -0,0 +1,7 @@
|
||||
<resources>
|
||||
<string name="app_name">GlassTesla</string>
|
||||
<string name="title_activity_main">Glass Tesla</string>
|
||||
<string name="hello_world">Hello, world!</string>
|
||||
<string name="voice_trigger">glass tesla</string>
|
||||
<string name="StatusFormat">Battery: %d%% (%d mi)\nSentry Mode: %s \n%s: %dkW \nTime to Full: %s (%s)</string>
|
||||
</resources>
|
||||
5
app/src/main/res/values/styles.xml
Normal file
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<style name="AppTheme" parent="android:Theme.Holo.Light"></style>
|
||||
</resources>
|
||||
2
app/src/main/res/xml/voice_trigger.xml
Normal file
@ -0,0 +1,2 @@
|
||||
<!-- For more information about voice trigger, check out: https://developers.google.com/glass/develop/gdk/starting-glassware -->
|
||||
<trigger keyword="@string/voice_trigger" />
|
||||