diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..6332594 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,14 @@ +Copyright (C) 2018 Norbert Truchsess norbert.truchsess@t-online.de + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . diff --git a/README.md b/README.md new file mode 100644 index 0000000..f605938 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# send2Car +Android App to send location to BMW car + diff --git a/app/build.gradle b/app/build.gradle new file mode 100644 index 0000000..e888524 --- /dev/null +++ b/app/build.gradle @@ -0,0 +1,46 @@ +apply plugin: 'com.android.application' + +android { + compileSdkVersion 28 + defaultConfig { + applicationId "com.truchsess.send2car" + minSdkVersion 16 + targetSdkVersion 28 + versionCode 7 + versionName "7" + testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } +} + +dependencies { + implementation fileTree(include: ['*.jar'], dir: 'libs') + + androidTestImplementation('com.android.support.test.espresso:espresso-core:2.2.2', { + exclude group: 'com.android.support', module: 'support-annotations' + }) + + implementation 'com.android.support:appcompat-v7:28.0.0' + implementation 'com.android.support:design:28.0.0' + implementation 'com.android.support.constraint:constraint-layout:1.1.3' + implementation 'com.android.support:preference-v7:28.0.0' + + implementation 'com.google.code.gson:gson:2.8.2' + + implementation 'com.squareup.retrofit2:retrofit:2.5.0' + implementation 'com.squareup.retrofit2:converter-gson:2.5.0' + + androidTestImplementation group: 'ch.qos.logback', name: 'logback-classic', version: '1.2.3' + androidTestImplementation group: 'xpp3', name: 'xpp3_min', version: '1.1.4c' + androidTestImplementation group: 'xmlpull', name: 'xmlpull', version: '1.1.3.1' + androidTestImplementation 'junit:junit:4.12' + androidTestImplementation 'xpp3:xpp3_min:1.1.4c' + androidTestImplementation 'xmlpull:xmlpull:1.1.3.1' + androidTestImplementation 'org.mockito:mockito-core:1.10.19' +} + diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..b0df89a --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,456 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/assets/nominatim.properties b/app/src/main/assets/nominatim.properties new file mode 100644 index 0000000..a08f8e7 --- /dev/null +++ b/app/src/main/assets/nominatim.properties @@ -0,0 +1,168 @@ +airport Flughafen +arts_centre Kunstzentrum +atm Geldautomat +auditorium Auditorium +bank Bank +bar Bar +bench Sitzbank +bicycle_parking Fahrradabstellplatz +bicycle_rental Leihfahrräder +brothel Bordell +bureau_de_change Wechselstube +bus_station Busbahnhof +cafe Cafe +car_rental Autovermietung +car_wash Autowaschanlage +casino Spielkasino +cinema Kino +clinic Krankenhaus +club Klub +college Hochschule +community_centre Gemeindezentrum +courthouse Gericht +crematorium Krematorium +dentist Zahnarzt +doctors Ärzte +dormitory Wohnheim +drinking_water Trinkwasser +driving_school Fahrschule +embassy Botschaft +emergency_phone Notruf +fast_food Fast Food +ferry_terminal Fähranlegestelle +fire_hydrant Hydrant +fire_station Feuerwache +fountain Brunnen +fuel Tankstelle +grave_yard Friedhof +hall Halle +health_centre Gesundheitszentrum +hospital Krankenhaus +hotel Hotel +hunting_stand Jagd Stand +ice_cream Eiscafe +kindergarten Kindergarten +library Bibliotek +market Markt +marketplace Marktplatz +nightclub Nachtclub +nursery Kinderkrippe +nursing_home Pflegeheim +office Büro +park Park +parking Parkplatz +pharmacy Apotheke +place_of_worship Kirche +police Polizei +post_box Briefkasten +post_office Postamt +preschool Vorschule +prison Gefängnis +pub Kneipe +public_Öffendliches Gebäude +public_market Öffendlicher Markt +reception_area Pforte +restaurant Restaurant +retirement_home Altenheim +sauna Sauna +school Schule +shelter Schutzhütte +shop Geschäft +shopping Geschäft +social_club Privater Club +studio Studio +supermarket Supermarkt +taxi Taxistand +telephone Telefon +theatre Theater +toilets Toiletten +townhall Rathaus +university Universität +veterinary Tierarzt +waste_basket Abfalleimer +wifi Wireless LAN +youth_centre Jugendzentrum +apartments Wohnungen +block Wohnblock +bunker Bunker +chapel Kapelle +church Kirche +commercial Gewerbegebäude +dormitory Wohnheim +entrance Eingang +faculty Fakultät +farm Bauernhof +flats Wohnungen +garage Werkstatt +hospital Krankenhaus +hotel Hotel +house Haus +industrial Industriegebäude +office Büro +public Öffendliches Gebäude +residential Straße im Wohngebiet +living_street Verkehrsberuhigter Bereich +retail Einzelhandel +school Schule +shop Geschäft +stadium Stadion +store Geschäft +terrace Terasse +tower Turm +train_station Bahnhof +university Universität +bridleway Reitweg +bus_stop Bushaltestelle +construction Baustelle +cycleway Radweg +distance_marker Entfernungsangabe +emergency_access_point Anfahrtspunkt für Rettungsfahrzeuge +footway Fußweg +gate Gatter +motorway Autobahn +motorway_junction Abzweigung Autobahn +path Pfad +pedestrian Fußgängerzone +platform Bahnsteig +primary Hauptstraße +primary_link Abzeigung Hauptstraße +raceway Rennstrecke +road Straße +secondary Sekundärstraße +secondary_link Abzweigung Sekundärstraße +services Versorgungsstraße +steps Treppe +tertiary Nebenstraße +track Wirtschaftsweg +trail Pfad +trunk Ausfallstraße +trunk_link Abzweigung Ausfallstraße +unsurfaced Unbefestigte Straße +archaeological_site Archaelogische Stätte +battlefield Schlachtfeld +historisches Gebäude +castle Burg +church Kirche +house historisches Gebäude +icon Bildzeichen +manor Landgut +memorial Gedenkstätte +mine Bergwerk +monument Denkmal +museum Museum +ruins Ruinen +tower Turm +wayside_cross Kreuz +wayside_shrine Schrein +wreck Wrack +cemetery Friedhof +commercial Gewerbegebiet +construction Baustelle +farm Bauernhof +farmland Feld +farmyard Feld +forest Wald +grass Grass +industrial Industriegebiet +water Wasserfläche +camp_site Campingplatz \ No newline at end of file diff --git a/app/src/main/java/com/truchsess/send2car/GeoFragment.java b/app/src/main/java/com/truchsess/send2car/GeoFragment.java new file mode 100644 index 0000000..abf17d3 --- /dev/null +++ b/app/src/main/java/com/truchsess/send2car/GeoFragment.java @@ -0,0 +1,108 @@ +package com.truchsess.send2car; + +import android.net.Uri; +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Button; +import android.widget.EditText; +import android.widget.TextView; + +import com.truchsess.send2car.geo.GeoUrl; + +/********************************************************************************************** + Copyright (C) 2018 Norbert Truchsess norbert.truchsess@t-online.de + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + **********************************************************************************************/ +public class GeoFragment extends Fragment { + + private EditText mEditTextLat; + private EditText mEditTextLon; + private EditText mEditTextDescription; + + private Listener mListener; + + public void setListener(Listener listener) { + mListener = listener; + } + + public interface Listener { + void onLookupGeoDataClicked(); + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + + final View view = inflater.inflate(R.layout.fragment_geo, container, false); + + mEditTextLat = view.findViewById(R.id.editTextLat); + mEditTextLon = view.findViewById(R.id.editTextLon); + mEditTextDescription = view.findViewById(R.id.editTextDescription); + + view.findViewById(R.id.buttonClearLat).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + mEditTextLat.setText(""); + } + }); + + view.findViewById(R.id.buttonClearLon).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + mEditTextLon.setText(""); + } + }); + + view.findViewById(R.id.buttonClearDescription).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + mEditTextDescription.setText(""); + } + }); + + view.findViewById(R.id.buttonLookupGeodata).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (mListener != null) { + mListener.onLookupGeoDataClicked(); + } + } + }); + + return view; + } + + public void setGeoUrl(final GeoUrl geoUrl) { + mEditTextLat.setText(geoUrl != null && geoUrl.isValid() ? GeoUrl.degreeToString(geoUrl.getLat()) : " - "); + mEditTextLon.setText(geoUrl != null && geoUrl.isValid() ? GeoUrl.degreeToString(geoUrl.getLon()) : " - "); + mEditTextDescription.setText(geoUrl == null || geoUrl.getDescription() == null ? " - " : geoUrl.getDescription()); + } + + public GeoUrl getGeoUrl() { + double lat = Double.NaN; + double lon = Double.NaN; + + try { + lat = Double.parseDouble(mEditTextLat.getText().toString()); + lon = Double.parseDouble(mEditTextLon.getText().toString()); + } catch (NumberFormatException nfe) { + } + + return new GeoUrl(lat,lon,mEditTextDescription.getText().toString()); + } +} diff --git a/app/src/main/java/com/truchsess/send2car/GetVinsFragment.java b/app/src/main/java/com/truchsess/send2car/GetVinsFragment.java new file mode 100644 index 0000000..2d12cca --- /dev/null +++ b/app/src/main/java/com/truchsess/send2car/GetVinsFragment.java @@ -0,0 +1,59 @@ +package com.truchsess.send2car; + +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Button; +import android.widget.TextView; + +/********************************************************************************************** + Copyright (C) 2018 Norbert Truchsess norbert.truchsess@t-online.de + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + **********************************************************************************************/ +public class GetVinsFragment extends Fragment { + + private Button mButtonGetVins; + private Listener mListener; + + public interface Listener { + void onGetVinsClicked(); + } + + public void setmListener(Listener listener) { + mListener = listener; + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.fragment_vins, container, false); + + mButtonGetVins = view.findViewById(R.id.buttonGetVins); + + mButtonGetVins.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (mListener != null) { + mListener.onGetVinsClicked(); + } + } + }); + return view; + } + +} + diff --git a/app/src/main/java/com/truchsess/send2car/ListPlacesFragment.java b/app/src/main/java/com/truchsess/send2car/ListPlacesFragment.java new file mode 100644 index 0000000..9a254a1 --- /dev/null +++ b/app/src/main/java/com/truchsess/send2car/ListPlacesFragment.java @@ -0,0 +1,41 @@ +package com.truchsess.send2car; + +import android.support.v4.app.ListFragment; +import android.view.View; +import android.widget.ListView; + +/********************************************************************************************** + Copyright (C) 2018 Norbert Truchsess norbert.truchsess@t-online.de + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + **********************************************************************************************/ +public class ListPlacesFragment extends ListFragment { + + private Listener listener; + + public interface Listener { + void onListItemClick(int position); + } + + public void setListPlacesListener(Listener listener) { + this.listener = listener; + } + + @Override + public void onListItemClick(ListView l, View v, int position, long id) { + if (listener != null) { + listener.onListItemClick(position); + } + } +} diff --git a/app/src/main/java/com/truchsess/send2car/MainActivity.java b/app/src/main/java/com/truchsess/send2car/MainActivity.java new file mode 100644 index 0000000..4124946 --- /dev/null +++ b/app/src/main/java/com/truchsess/send2car/MainActivity.java @@ -0,0 +1,549 @@ +package com.truchsess.send2car; + +import android.content.Intent; +import android.content.SharedPreferences; +import android.database.DataSetObserver; +import android.net.Uri; +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentTransaction; +import android.support.v7.app.ActionBar; +import android.support.v7.app.AppCompatActivity; +import android.support.v7.preference.EditTextPreference; +import android.support.v7.preference.PreferenceManager; +import android.support.v7.widget.Toolbar; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.view.WindowManager; +import android.widget.ListAdapter; +import android.widget.TextView; + +import com.truchsess.send2car.cd.Token; +import com.truchsess.send2car.cd.api.ErrorResponse; +import com.truchsess.send2car.cd.entity.ServiceMessage; +import com.truchsess.send2car.cd.entity.Vehicle; +import com.truchsess.send2car.component.GetVehiclesController; +import com.truchsess.send2car.component.SendServiceMessageController; +import com.truchsess.send2car.geo.GeoUrl; + +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.PropertyResourceBundle; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/********************************************************************************************** + Copyright (C) 2018 Norbert Truchsess norbert.truchsess@t-online.de + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + **********************************************************************************************/ + +public class MainActivity extends AppCompatActivity implements View.OnClickListener { + + private enum Story { + ePreferences, + eArguments, + eCurrentMessage + } + + private Story currentStory; + + private PreferencesFragment mPreferencesFragment; + private GetVinsFragment mGetVinsFragment; + private GeoFragment mGeoFragment; + private ListPlacesFragment mListPlacesFragment; + private PlaceFragment mPlaceFragment; + private StatusFragment mStatusFragment; + private ActionBar mActionBar; + + private Token mToken; + private GetVehiclesController mGetVehiclesController; + private SendServiceMessageController mServiceMessageController; + private Set mServiceMessageDataSetObservers = new HashSet<>(); + //need to store a strong reference to OnSharedPreferenceChangeListener. For Details see: + //https://developer.android.com/reference/android/content/SharedPreferences.html#registerOnSharedPreferenceChangeListener(android.content.SharedPreferences.OnSharedPreferenceChangeListener) + private SharedPreferences.OnSharedPreferenceChangeListener mOnSharedPreferenceChangeListener; + + @Override + public void onAttachFragment(Fragment fragment) { + if (fragment instanceof PreferencesFragment) { + mPreferencesFragment = (PreferencesFragment) fragment; + return; + } + if (fragment instanceof GetVinsFragment) { + mGetVinsFragment = (GetVinsFragment) fragment; + return; + } + if (fragment instanceof GeoFragment) { + mGeoFragment = (GeoFragment) fragment; + return; + } + if (fragment instanceof ListPlacesFragment) { + mListPlacesFragment = (ListPlacesFragment) fragment; + return; + } + if (fragment instanceof PlaceFragment) { + mPlaceFragment = (PlaceFragment) fragment; + return; + } + if (fragment instanceof StatusFragment) { + mStatusFragment = (StatusFragment) fragment; + return; + } + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + setContentView(R.layout.activity_main); + Toolbar toolbar = findViewById(R.id.toolbar_main); + setSupportActionBar(toolbar); + mActionBar = getSupportActionBar(); + + getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); + + mToken = new Token(); + mGetVehiclesController = new GetVehiclesController(); + mServiceMessageController = new SendServiceMessageController(); + + try { + final InputStream in = getBaseContext().getAssets().open(SendServiceMessageController.NOMINATIM_PROPERTIES); + if (in != null) { + Reader reader = new InputStreamReader(in,"UTF-8"); + final PropertyResourceBundle nominatimCategories = new PropertyResourceBundle(reader); + mServiceMessageController.setCategories(nominatimCategories); + } + } catch (IOException e) { + e.printStackTrace(); + } + + mGetVinsFragment.setmListener(new GetVinsFragment.Listener() { + @Override + public void onGetVinsClicked() { + getVehicles(); + } + }); + + mListPlacesFragment.setListAdapter(new ListAdapter() { + + @Override + public boolean areAllItemsEnabled() { + return true; + } + + @Override + public boolean isEnabled(int position) { + return true; + } + + @Override + public void registerDataSetObserver(DataSetObserver observer) { + mServiceMessageDataSetObservers.add(observer); + } + + @Override + public void unregisterDataSetObserver(DataSetObserver observer) { + mServiceMessageDataSetObservers.remove(observer); + } + + @Override + public int getCount() { + return mServiceMessageController.getNumServiceMessages(); + } + + @Override + public Object getItem(int position) { + return mServiceMessageController.getServiceMessage(position); + } + + @Override + public long getItemId(int position) { + return position; + } + + @Override + public boolean hasStableIds() { + return false; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + final View view = convertView == null ? + getLayoutInflater().inflate(R.layout.list_place, null, true) : + convertView; + TextView textPlaceName = (TextView) view.findViewById(R.id.textListPlaceName); + textPlaceName.setText(((ServiceMessage)getItem(position)).getName()); + return view; + } + + @Override + public int getItemViewType(int position) { + return 0; + } + + @Override + public int getViewTypeCount() { + return 1; + } + + @Override + public boolean isEmpty() { + return mServiceMessageController.getNumServiceMessages() == 0; + } + }); + + mListPlacesFragment.setListPlacesListener(new ListPlacesFragment.Listener() { + @Override + public void onListItemClick(int position) { + mServiceMessageController.setServiceMessageIndex(position); + mStatusFragment.clear(); + currentStory = Story.eCurrentMessage; + updateView(); + } + }); + + mPlaceFragment.setPlaceFragmentListener(new PlaceFragment.Listener() { + @Override + public void onSend2CarClicked() { + + SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getBaseContext()); + final String vin = mPlaceFragment.getSelectedVin(); + + SharedPreferences.Editor editor = sp.edit(); + editor.putString(getString(R.string.key_preference_selected_vin),vin); + editor.commit(); + + if (vin == null) { + mStatusFragment.setStatus(getString(R.string.status_servicemessage),getString(R.string.status_novin)); + updateView(); + } else { + mStatusFragment.setStatus(getString(R.string.status_servicemessage),getString(R.string.status_authenticating)); + updateView(); + + setTokenCredentials(sp); + mToken.checkToken(new Token.AuthenticationListener() { + @Override + public void onAuthentication() { + mStatusFragment.setStatus(getString(R.string.status_servicemessage),getString(R.string.status_sending)); + updateView(); + + mServiceMessageController.setVin(vin); + mServiceMessageController.sendServiceMessage2Car(mToken, new SendServiceMessageController.ServiceMessageSendListener() { + @Override + public void onSent() { + mStatusFragment.setStatus(getString(R.string.status_servicemessage),getString(R.string.status_sent)); + updateView(); + } + + @Override + public void onError(String error) { + mStatusFragment.setStatus(getString(R.string.status_servicemessage_error), error); + updateView(); + } + }); + } + + @Override + public void onAuthenticationFailure(ErrorResponse errorResponse) { + mStatusFragment.setStatus(errorResponse.getError(), errorResponse.getError_description()); + updateView(); + } + }); + } + } + }); + + + mGeoFragment.setListener(new GeoFragment.Listener() { + @Override + public void onLookupGeoDataClicked() { + mServiceMessageController.setGeoUrl(mGeoFragment.getGeoUrl()); + getGeoData(); + } + }); + + final SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getBaseContext()); + mOnSharedPreferenceChangeListener = new SharedPreferences.OnSharedPreferenceChangeListener() { + @Override + public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { + if (key.equals(getString(R.string.key_preference_vins))) { + setVinsFromPreferences(sharedPreferences); + } + } + }; + sp.registerOnSharedPreferenceChangeListener(mOnSharedPreferenceChangeListener); + + setVinsFromPreferences(sp); + + currentStory = Story.eArguments; + + // Get intent, action and MIME type + Intent intent = getIntent(); + String action = intent.getAction(); + + if (Intent.ACTION_VIEW.equals(action)) { + final Uri uri = intent.getData(); + final String scheme = uri.getScheme(); + if (scheme.equals("geo") || scheme.equals("google.navigation")) { + mServiceMessageController.setGeoUrlFromUri(uri); + } + final GeoUrl geoUrl = mServiceMessageController.getGeoUrl(); + + if (mGeoFragment != null) { + mGeoFragment.setGeoUrl(geoUrl); + } + + getGeoData(); + } + } + + private void setVinsFromPreferences(SharedPreferences sharedPreferences) { + + final String keyPreferenceVins = getString(R.string.key_preference_vins); + final String vinsPreference = sharedPreferences.getString(keyPreferenceVins,""); + + final EditTextPreference editTextPreferenceVins = (EditTextPreference) mPreferencesFragment.findPreference(keyPreferenceVins); + if (editTextPreferenceVins != null) { + final String editTextPreferenceVinsText = editTextPreferenceVins.getText(); + if (editTextPreferenceVins != null && !editTextPreferenceVins.equals(vinsPreference)) { + editTextPreferenceVins.setText(vinsPreference); + } + } + + final Map vins = new HashMap(); + final Pattern pattern = Pattern.compile("([A-Z0-9]+)(\\(([^\\n]*)\\)){0,1}"); + Matcher matcher = pattern.matcher(vinsPreference); + while(matcher.find()) { + final int num = matcher.groupCount(); + final String vin = matcher.group(1); + final String description = matcher.group(3); + vins.put(vin,description == null ? vin : description); + } + mPlaceFragment.setVins(vins); + mPlaceFragment.setCurrentVin(sharedPreferences.getString(getString(R.string.key_preference_selected_vin),"")); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + MenuInflater inflater = getMenuInflater(); + inflater.inflate(R.menu.menu, menu); + return true; + } + + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch(item.getItemId()) + { + case R.id.help: + Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(getString(R.string.url_help))); + startActivity(browserIntent); + break; + case R.id.preferences: + mStatusFragment.clear(); + currentStory = Story.ePreferences; + updateView(); + break; + case android.R.id.home: + mStatusFragment.clear(); + currentStory = Story.eArguments; + updateView(); + break; + default: + return super.onOptionsItemSelected(item); + } + return true; + } + + @Override + public void onClick(View v) { + switch (v.getId()) { + } + } + + @Override + public void onStop() { + super.onStop(); + } + + @Override + public void onPause() { + super.onPause(); + } + + @Override + public void onResume() { + super.onResume(); // Always call the superclass method first + + updateView(true); + } + + private void getGeoData() { + + mStatusFragment.setStatus(getString(R.string.status_lookup_geo),getString(R.string.status_loading)); + updateView(); + + mServiceMessageController.lookupGeodata(new SendServiceMessageController.ServiceMessageUpdateListener() { + @Override + public void onUpdate() { + for (DataSetObserver observer : mServiceMessageDataSetObservers) { + observer.onChanged(); + } + mStatusFragment.setStatus(getString(R.string.status_lookup_geo),getString(R.string.status_success)); + updateView(); + } + + @Override + public void onError(String error) { + for (DataSetObserver observer : mServiceMessageDataSetObservers) { + observer.onInvalidated(); + } + mStatusFragment.setStatus(getString(R.string.status_lookup_geo_error), error); + updateView(); + } + }); + } + + private void getVehicles() { + + mStatusFragment.setStatus(getString(R.string.status_get_vehicles),getString(R.string.status_loading)); + updateView(); + + setTokenCredentials(PreferenceManager.getDefaultSharedPreferences(getBaseContext())); + + mToken.checkToken(new Token.AuthenticationListener() { + @Override + public void onAuthentication() { + mGetVehiclesController.getVehiclesResponse(mToken, new GetVehiclesController.GetVehiclesListener() { + @Override + public void onUpdate() { + List vins = new ArrayList<>(); + int num = mGetVehiclesController.getNumVehicles(); + boolean isNotFirst = false; + StringBuilder vinBuilder = new StringBuilder(); + for (int i = 0; i < num; i++) { + Vehicle vehicle = mGetVehiclesController.getVehicle(i); + if (isNotFirst) { + vinBuilder.append('\n'); + } else { + isNotFirst = true; + } + vinBuilder.append(vehicle.getVin()) + .append("(") + .append(vehicle.getModel()) + .append(")"); + } + SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getBaseContext()); + SharedPreferences.Editor editor = sp.edit(); + editor.putString(getString(R.string.key_preference_vins), vinBuilder.toString()); + editor.commit(); + mStatusFragment.setStatus(getString(R.string.status_get_vehicles),getString(R.string.status_success)); + updateView(); + } + + @Override + public void onError(String error) { + mStatusFragment.setStatus(getString(R.string.status_get_vehicles_error), error); + updateView(); + } + }); + } + + @Override + public void onAuthenticationFailure(ErrorResponse errorResponse) { + mStatusFragment.setStatus(errorResponse.getError(),errorResponse.getError_description()); + updateView(); + } + }); + } + + private void setTokenCredentials(SharedPreferences sharedPreferences) { + final String api_key = sharedPreferences.getString(getString(R.string.key_preference_apikey), ""); + final String api_secret = sharedPreferences.getString(getString(R.string.key_preference_apisecret), ""); + final String username = sharedPreferences.getString(getString(R.string.key_preference_username), ""); + final String password = sharedPreferences.getString(getString(R.string.key_preference_password), ""); + mToken.setCredentials(username, password, api_key, api_secret); + } + + private void updateView(boolean force) { + + FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); + + switch (currentStory) { + case ePreferences: + mActionBar.setDisplayHomeAsUpEnabled(true); + showFragment(ft,mPreferencesFragment,force); + showFragment(ft,mGetVinsFragment,force); + hideFragment(ft,mGeoFragment,force); + hideFragment(ft,mListPlacesFragment,force); + hideFragment(ft,mPlaceFragment,force); + break; + + case eArguments: + mActionBar.setDisplayHomeAsUpEnabled(false); + hideFragment(ft,mPreferencesFragment,force); + hideFragment(ft,mGetVinsFragment,force); + showFragment(ft,mGeoFragment,force); + showFragment(ft,mListPlacesFragment,force); + hideFragment(ft,mPlaceFragment,force); + break; + + case eCurrentMessage: + mActionBar.setDisplayHomeAsUpEnabled(true); + hideFragment(ft,mPreferencesFragment,force); + hideFragment(ft,mGetVinsFragment,force); + hideFragment(ft,mGeoFragment,force); + hideFragment(ft,mListPlacesFragment,force); + showFragment(ft,mPlaceFragment,force); + + final ServiceMessage serviceMessage = mServiceMessageController.getServiceMessage(); + mPlaceFragment.setServiceMessage(serviceMessage); + break; + } + if (mStatusFragment.isSet()) { + showFragment(ft,mStatusFragment,force); + } else { + hideFragment(ft,mStatusFragment,force); + } + ft.commit(); + } + + private void updateView() { + updateView(false); + } + + private void hideFragment(final FragmentTransaction ft, final Fragment f, final boolean force) { + if (f != null && (f.isVisible() || force)) { + ft.hide(f); + } + } + + private void showFragment(final FragmentTransaction ft, final Fragment f, final boolean force) { + if (f != null && (f.isHidden() || force)) { + ft.show(f); + } + } +} diff --git a/app/src/main/java/com/truchsess/send2car/PlaceFragment.java b/app/src/main/java/com/truchsess/send2car/PlaceFragment.java new file mode 100644 index 0000000..02a1af2 --- /dev/null +++ b/app/src/main/java/com/truchsess/send2car/PlaceFragment.java @@ -0,0 +1,207 @@ +package com.truchsess.send2car; + +import android.content.Context; +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Button; +import android.widget.EditText; +import android.widget.RadioButton; +import android.widget.RadioGroup; +import android.widget.TextView; + +import com.truchsess.send2car.cd.entity.ServiceMessage; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +/********************************************************************************************** + Copyright (C) 2018 Norbert Truchsess norbert.truchsess@t-online.de + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + **********************************************************************************************/ +public class PlaceFragment extends Fragment { + + private ServiceMessage mServiceMessage; + private TextView mTextViewPoiName; + private TextView mTextViewPoiLat; + private TextView mTextViewPoiLon; + private TextView mTextViewPoiCity; + private TextView mTextViewPoiStreet; + private TextView mTextViewPoiNumber; + private TextView mTextViewPoiPostalCode; + + private EditText mEditTextPhone; + private EditText mEditTextSubject; + private EditText mEditTextMessage; + + private RadioGroup mRadioGroupVins; + + private Button mButtonSend2Car; + + private Listener mListener; + + private Map mVins = new HashMap<>(); + private String mCurrentVin; + + public interface Listener { + void onSend2CarClicked(); + } + + public void setPlaceFragmentListener(Listener listener) { + mListener = listener; + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.fragment_place, container, false); + + mTextViewPoiName = view.findViewById(R.id.textViewPoiName); + mTextViewPoiLat = view.findViewById(R.id.textViewPoiLat); + mTextViewPoiLon = view.findViewById(R.id.textViewPoiLon); + mTextViewPoiCity = view.findViewById(R.id.textViewPoiCity); + mTextViewPoiPostalCode = view.findViewById(R.id.textViewPoiPostalCode); + mTextViewPoiStreet = view.findViewById(R.id.textViewPoiStreet); + mTextViewPoiNumber = view.findViewById(R.id.textViewPoiNumber); + + mEditTextPhone = view.findViewById(R.id.editTextPoiPhone); + mEditTextSubject = view.findViewById(R.id.editTextSubject); + mEditTextMessage = view.findViewById(R.id.editTextMessage); + + mRadioGroupVins = view.findViewById(R.id.radioGroupVins); + mRadioGroupVins.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(RadioGroup group, int checkedId) { + final View view = group.findViewById(checkedId); + mCurrentVin = view == null ? null : (String) view.getTag(); + } + }); + mButtonSend2Car = view.findViewById(R.id.buttonSend2Car); + + mButtonSend2Car.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + + mServiceMessage.setPhone1(mEditTextPhone.getText().toString()); + mServiceMessage.setSubject(mEditTextSubject.getText().toString()); + mServiceMessage.setMessage(mEditTextMessage.getText().toString()); + + if (mListener != null) { + mListener.onSend2CarClicked(); + } + } + }); + return view; + } + + public void setServiceMessage(final ServiceMessage serviceMessage) { + mServiceMessage = serviceMessage; + updateView(); + } + + public void setVins(Map vins) { + mVins.clear(); + mVins.putAll(vins); + updateView(); + } + + public void setCurrentVin(String vin) { + mCurrentVin = vin; + updateView(); + } + + public String getSelectedVin() { + final int id = mRadioGroupVins.getCheckedRadioButtonId(); + if (id != -1) { + final View view = mRadioGroupVins.findViewById(id); + if (view != null) { + return (String) view.getTag(); + } + } + return null; + } + + public void updateView() { + if (mServiceMessage != null) { + mTextViewPoiName.setText(mServiceMessage.getName()); + mTextViewPoiLat.setText(mServiceMessage.getLat()); + mTextViewPoiLon.setText(mServiceMessage.getLng()); + mTextViewPoiCity.setText(mServiceMessage.getCity()); + mTextViewPoiPostalCode.setText(mServiceMessage.getZip()); + mTextViewPoiStreet.setText(mServiceMessage.getStreet()); + mTextViewPoiNumber.setText(mServiceMessage.getNumber()); + mEditTextPhone.setText(mServiceMessage.getPhone1()); + mEditTextSubject.setText(mServiceMessage.getSubject()); + mEditTextMessage.setText(mServiceMessage.getMessage()); + + final int numButtons = mRadioGroupVins.getChildCount(); + final Set viewsToRemove = new HashSet<>(); + final Set tags = new HashSet<>(); + for (int i=0; i entry : mVins.entrySet()) { + final String vin = entry.getKey(); + if (!tags.contains(vin)) { + final RadioButton radioButton = new RadioButton(context); + radioButton.setText(entry.getValue()); + radioButton.setTag(vin); + mRadioGroupVins.addView(radioButton); + tags.add(vin); + } + } + final View view = mRadioGroupVins.findViewWithTag(mCurrentVin); + if (view == null) { + mRadioGroupVins.clearCheck(); + } else { + if (!((RadioButton)view).isChecked()) { + mRadioGroupVins.check(view.getId()); + } + } + mButtonSend2Car.setActivated(true); + } else { + mTextViewPoiName.setText(""); + mTextViewPoiLat.setText(""); + mTextViewPoiLon.setText(""); + mTextViewPoiCity.setText(""); + mTextViewPoiPostalCode.setText(""); + mTextViewPoiStreet.setText(""); + mTextViewPoiNumber.setText(""); + mEditTextPhone.setText(""); + mEditTextSubject.setText(""); + mEditTextMessage.setText(""); + mButtonSend2Car.setActivated(false); + } + } +} + diff --git a/app/src/main/java/com/truchsess/send2car/PreferencesFragment.java b/app/src/main/java/com/truchsess/send2car/PreferencesFragment.java new file mode 100644 index 0000000..85de324 --- /dev/null +++ b/app/src/main/java/com/truchsess/send2car/PreferencesFragment.java @@ -0,0 +1,38 @@ +package com.truchsess.send2car; + +import android.os.Bundle; +import android.support.v7.preference.Preference; +import android.support.v7.preference.PreferenceFragmentCompat; + +/********************************************************************************************** + Copyright (C) 2018 Norbert Truchsess norbert.truchsess@t-online.de + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + **********************************************************************************************/ +public class PreferencesFragment extends PreferenceFragmentCompat { + + @Override + public void onCreatePreferences(Bundle bundle, String rootKey) { + // Load the preferences from an XML resource + setPreferencesFromResource(R.xml.preferences, rootKey); + + + } + + @Override + public boolean onPreferenceTreeClick(Preference preference) { + + return false; + } +} diff --git a/app/src/main/java/com/truchsess/send2car/StatusFragment.java b/app/src/main/java/com/truchsess/send2car/StatusFragment.java new file mode 100644 index 0000000..c56e67e --- /dev/null +++ b/app/src/main/java/com/truchsess/send2car/StatusFragment.java @@ -0,0 +1,55 @@ +package com.truchsess.send2car; + +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +/********************************************************************************************** + Copyright (C) 2018 Norbert Truchsess norbert.truchsess@t-online.de + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + **********************************************************************************************/ +public class StatusFragment extends Fragment { + + private TextView mTextViewError; + private TextView mTextViewErrorDescription; + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.fragment_status, container, false); + + mTextViewError = view.findViewById(R.id.textViewError); + mTextViewErrorDescription = view.findViewById(R.id.textViewErrorDescription); + + return view; + } + + public void setStatus(final String status, final String description) { + mTextViewError.setText(status); + mTextViewErrorDescription.setText(description); + } + + public void clear() { + setStatus("",""); + } + + public boolean isSet() { + return mTextViewError.getText().length() > 0 || mTextViewErrorDescription.getText().length() > 0; + } +} + diff --git a/app/src/main/java/com/truchsess/send2car/cd/GetVehicles.java b/app/src/main/java/com/truchsess/send2car/cd/GetVehicles.java new file mode 100644 index 0000000..145c038 --- /dev/null +++ b/app/src/main/java/com/truchsess/send2car/cd/GetVehicles.java @@ -0,0 +1,107 @@ +package com.truchsess.send2car.cd; + +import com.google.gson.Gson; +import com.google.gson.JsonSyntaxException; +import com.truchsess.send2car.cd.api.CDApi; +import com.truchsess.send2car.cd.api.VehicleResponse; +import com.truchsess.send2car.cd.entity.CDApiJSONError; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.TimeUnit; + +import okhttp3.OkHttpClient; +import okhttp3.ResponseBody; +import retrofit2.Call; +import retrofit2.Callback; +import retrofit2.Response; +import retrofit2.Retrofit; +import retrofit2.converter.gson.GsonConverterFactory; + +/********************************************************************************************** + Copyright (C) 2018 Norbert Truchsess norbert.truchsess@t-online.de + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + **********************************************************************************************/ +public class GetVehicles { + + private final CDApi cdApi; + + public GetVehicles(final String baseUrl) { + final OkHttpClient okHttpClient = new OkHttpClient.Builder() + .connectTimeout(60, TimeUnit.SECONDS) + .writeTimeout(60, TimeUnit.SECONDS) + .readTimeout(60, TimeUnit.SECONDS) + .build(); + Retrofit retrofit = new Retrofit.Builder() + .baseUrl(baseUrl) + .client(okHttpClient) + .addConverterFactory(GsonConverterFactory.create()) + .build(); + cdApi = retrofit.create(CDApi.class); + } + + public interface GetVehiclesListener { + public void onSuccess(final VehicleResponse response); + public void onError(final CDApiJSONError error); + } + + public void getVehiclesResponse(final String authorization, final GetVehiclesListener listener) { + + cdApi.getVehicles(authorization).enqueue(new Callback() { + @Override + public void onResponse(Call call, Response response) { + if (response.isSuccessful()) { + listener.onSuccess(response.body()); + } else { + final ResponseBody responseBody = response.errorBody(); + CDApiJSONError error = null; + try { + error = new Gson().fromJson(responseBody.charStream(), CDApiJSONError.class); + } catch (JsonSyntaxException jse) { + error = new CDApiJSONError(); + } + if (error == null) { + error = new CDApiJSONError(); + } + if (error.getReasons() == null) { + error.setReasons(new ArrayList()); + } + try { + final String bodyContent = responseBody.string(); + if (bodyContent != null && !bodyContent.isEmpty()) { + error.getReasons().add(bodyContent); + } + } catch (IOException ioe) { + } + error.getReasons().add(0, Integer.toString(response.code())); + error.getReasons().add(1, response.message()); + listener.onError(error); + } + } + + @Override + public void onFailure(Call call, Throwable t) { + final CDApiJSONError error = new CDApiJSONError(); + final List reasons = new ArrayList<>(); + reasons.add("0"); + reasons.add("error getting vehicles"); + reasons.add(t.getLocalizedMessage()); + error.setReasons(reasons); + listener.onError(error); + } + }); + } +} diff --git a/app/src/main/java/com/truchsess/send2car/cd/SendServiceMessage.java b/app/src/main/java/com/truchsess/send2car/cd/SendServiceMessage.java new file mode 100644 index 0000000..42bdd4e --- /dev/null +++ b/app/src/main/java/com/truchsess/send2car/cd/SendServiceMessage.java @@ -0,0 +1,127 @@ +package com.truchsess.send2car.cd; + +import com.google.gson.Gson; +import com.google.gson.JsonSyntaxException; +import com.truchsess.send2car.cd.api.CDApi; +import com.truchsess.send2car.cd.entity.CDApiJSONError; +import com.truchsess.send2car.cd.entity.ServiceMessage; + +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.StringWriter; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.TimeUnit; + +import okhttp3.OkHttpClient; +import okhttp3.RequestBody; +import okhttp3.ResponseBody; +import okio.Buffer; +import retrofit2.Call; +import retrofit2.Callback; +import retrofit2.Response; +import retrofit2.Retrofit; +import retrofit2.converter.gson.GsonConverterFactory; + +/********************************************************************************************** + Copyright (C) 2018 Norbert Truchsess norbert.truchsess@t-online.de + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + **********************************************************************************************/ +public class SendServiceMessage { + + private final CDApi cdApi; + + public SendServiceMessage(final String baseUrl) { + final OkHttpClient okHttpClient = new OkHttpClient.Builder() + .connectTimeout(60, TimeUnit.SECONDS) + .writeTimeout(60, TimeUnit.SECONDS) + .readTimeout(60, TimeUnit.SECONDS) + .build(); + Retrofit retrofit = new Retrofit.Builder() + .baseUrl(baseUrl) + .client(okHttpClient) + .addConverterFactory(GsonConverterFactory.create()) + .build(); + cdApi = retrofit.create(CDApi.class); + } + + public interface SendServiceMessageListener { + public void onSuccess(); + public void onError(CDApiJSONError error); + } + + public void sendServiceMessage(final ServiceMessage serviceMessage, final String authorization, final SendServiceMessageListener listener) { + + cdApi.sendServiceMessage(serviceMessage, authorization).enqueue(new Callback() { + @Override + public void onResponse(Call call, Response response) { + if (response.isSuccessful()) { + listener.onSuccess(); + } else { + final RequestBody requestBody = call.request().body(); + final Buffer buffer = new Buffer(); + String requestBodyString = null; + try { + requestBody.writeTo(buffer); + InputStreamReader reader = new InputStreamReader(buffer.inputStream(), "UTF-8"); + StringWriter writer = new StringWriter(); + while (reader.ready()) { + writer.write(reader.read()); + } + requestBodyString = writer.toString(); + } catch (IOException e) { + e.printStackTrace(); + } + final ResponseBody responseBody = response.errorBody(); + CDApiJSONError error = null; + try { + error = new Gson().fromJson(responseBody.charStream(), CDApiJSONError.class); + } catch (JsonSyntaxException jse) { + } + if (error == null) { + error = new CDApiJSONError(); + } + if (error.getReasons() == null) { + error.setReasons(new ArrayList()); + } + try { + final String bodyContent = responseBody.string(); + if (bodyContent != null && !bodyContent.isEmpty()) { + error.getReasons().add(bodyContent); + } + } catch (IOException ioe) { + } + error.getReasons().add(0, Integer.toString(response.code())); + error.getReasons().add(1, response.message()); + if (requestBodyString != null && !requestBodyString.isEmpty()) { + error.getReasons().add(requestBodyString); + } + listener.onError(error); + } + } + + @Override + public void onFailure(Call call, Throwable t) { + final CDApiJSONError error = new CDApiJSONError(); + final List reasons = new ArrayList<>(); + reasons.add("0"); + reasons.add("error sending servicemessage"); + reasons.add(t.getLocalizedMessage()); + error.setReasons(reasons); + listener.onError(error); + } + }); + } +} diff --git a/app/src/main/java/com/truchsess/send2car/cd/Token.java b/app/src/main/java/com/truchsess/send2car/cd/Token.java new file mode 100644 index 0000000..bcebb6b --- /dev/null +++ b/app/src/main/java/com/truchsess/send2car/cd/Token.java @@ -0,0 +1,104 @@ +package com.truchsess.send2car.cd; + +import com.truchsess.send2car.cd.api.CDApiCall; +import com.truchsess.send2car.cd.api.ErrorResponse; +import com.truchsess.send2car.cd.api.TokenResponse; + +import java.util.Base64; + +import static com.truchsess.send2car.cd.api.CDApi.API_SERVER; + +/********************************************************************************************** + Copyright (C) 2018 Norbert Truchsess norbert.truchsess@t-online.de + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + **********************************************************************************************/ +public class Token extends CDApiCall { + + private static String GRANT_TYPE = "password"; + private static String SCOPE = "remote_services vehicle_data"; + private static long expireBefore = 60 * 1000L; //ms + + private String token = null; + private String tokenType; + private long tokenExpires = 0; + + public Token() {}; + + public void setCredentials(final String username, final String password, final String api_key, final String api_secret) { + + final String gcdm = api_key+":"+api_secret; + final String gcdm_key = android.util.Base64.encodeToString(gcdm.getBytes(), android.util.Base64.NO_WRAP); + apiCall = this.createApi(API_SERVER).getToken( + GRANT_TYPE, + username, + password, + SCOPE, + "Basic "+gcdm_key); + } + + public void clearToken() { + token = null; + tokenExpires = 0; + } + + public interface AuthenticationListener { + + public void onAuthentication(); + + public void onAuthenticationFailure(final ErrorResponse errorResponse); + } + + public void checkToken(final AuthenticationListener listener) { + if (System.currentTimeMillis() + expireBefore > tokenExpires || token == null) { + requestResult(new CDApiServiceListener() { + @Override + public void onSuccess(final TokenResponse tokenResponse) { + tokenType = tokenResponse.getToken_type(); + token = tokenResponse.getAccess_token(); + tokenExpires = System.currentTimeMillis() + 1000L * tokenResponse.getExpires_in(); + if (listener != null) { + listener.onAuthentication(); + } + } + + @Override + public void onError(final ErrorResponse errorResponse) { + clearToken(); + if (listener != null) { + listener.onAuthenticationFailure(errorResponse); + } + } + }); + } else if (listener != null) { + listener.onAuthentication(); + } + } + + public String getToken() { + return token; + } + + public String getTokenType() { + return tokenType; + } + + public boolean isAuthenticated() { + return token != null && tokenType != null; + } + + public String getAuthorization() { + return isAuthenticated() ? tokenType + " " + token : ""; + } +} diff --git a/app/src/main/java/com/truchsess/send2car/cd/api/CDApi.java b/app/src/main/java/com/truchsess/send2car/cd/api/CDApi.java new file mode 100644 index 0000000..de0c34b --- /dev/null +++ b/app/src/main/java/com/truchsess/send2car/cd/api/CDApi.java @@ -0,0 +1,59 @@ +package com.truchsess.send2car.cd.api; + +import com.truchsess.send2car.cd.entity.ServiceMessage; + +import retrofit2.Call; +import retrofit2.http.Body; +import retrofit2.http.Field; +import retrofit2.http.FormUrlEncoded; +import retrofit2.http.GET; +import retrofit2.http.Header; +import retrofit2.http.Headers; +import retrofit2.http.POST; +import retrofit2.http.Path; + +/********************************************************************************************** + Copyright (C) 2018 Norbert Truchsess norbert.truchsess@t-online.de + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + **********************************************************************************************/ +public interface CDApi { + + // API Gateway + public static String API_SERVER = "https://b2vapi.bmwgroup.com"; + + public static String CD_SERVER = "https://www.bmw-connecteddrive.de"; + + @FormUrlEncoded + @POST("webapi/oauth/token/") + Call getToken(@Field("grant_type") String grandType, + @Field("username") String username, + @Field("password") String password, + @Field("scope") String scope, + @Header("Authorization") String authorization); + + @GET("webapi/v1/user/vehicles") + Call getVehicles(@Header("Authorization") String authorization); + + @GET("webapi/v1/user/vehicles/{VIN}/status") + Call getVehicleStatus(@Path("VIN") String vin, @Header("Authorization") String authorization); + + @FormUrlEncoded + @POST("webapi/v1/user/vehicles/{VIN}/sendpoi") + Call sendPoi(@Path("VIN") String vin, @Field("data") String poiMessageData, @Header("Authorization") String authorization); + + @POST("api/vehicle/myinfo/v1") + //@Headers("Content-Type: application/json;charset=utf-8") + Call sendServiceMessage(@Body ServiceMessage serviceMessage, @Header("Authorization") String authorization); +} diff --git a/app/src/main/java/com/truchsess/send2car/cd/api/CDApiCall.java b/app/src/main/java/com/truchsess/send2car/cd/api/CDApiCall.java new file mode 100644 index 0000000..5897648 --- /dev/null +++ b/app/src/main/java/com/truchsess/send2car/cd/api/CDApiCall.java @@ -0,0 +1,101 @@ +package com.truchsess.send2car.cd.api; + +import com.google.gson.Gson; +import com.google.gson.JsonSyntaxException; + +import okhttp3.ResponseBody; +import retrofit2.Call; +import retrofit2.Callback; +import retrofit2.Response; +import retrofit2.Retrofit; +import retrofit2.converter.gson.GsonConverterFactory; + +/********************************************************************************************** + Copyright (C) 2018 Norbert Truchsess norbert.truchsess@t-online.de + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + **********************************************************************************************/ +public abstract class CDApiCall { + + protected Call apiCall; + private boolean callRunning = false; + + protected T value; + + protected CDApi createApi(String baseUrl) { + Retrofit retrofit = new Retrofit.Builder() + .baseUrl(baseUrl) + .addConverterFactory(GsonConverterFactory.create()) + .build(); + return retrofit.create(CDApi.class); + } + + public interface CDApiServiceListener { + + public void onSuccess(T result); + + public void onError(ErrorResponse error); + } + + public void requestResult(final CDApiServiceListener listener) { + + synchronized (apiCall) { + if (!callRunning) { + callRunning = true; + apiCall.clone().enqueue(new Callback() { + @Override + public void onResponse(Call call, Response response) { + synchronized (apiCall) { + callRunning = false; + } + T body = response.body(); + if (response.isSuccessful() && (body == null || body.getError() == null)) { + listener.onSuccess(body); + } else { + ErrorResponse errorResponse = null; + if (body != null) { + errorResponse = body; + } else { + ResponseBody errorBody = response.errorBody(); + if (errorBody != null) { + try { + errorResponse = new Gson().fromJson(errorBody.charStream(), ErrorResponse.class); + } catch (JsonSyntaxException jse) { + } + } + if (errorResponse == null) { + errorResponse = new ErrorResponse(); + errorResponse.setError(Integer.toString(response.code())); + errorResponse.setError_description(response.message()); + } + } + listener.onError(errorResponse); + } + } + + @Override + public void onFailure(Call call, Throwable t) { + synchronized (apiCall) { + callRunning = false; + } + ErrorResponse error = new ErrorResponse(); + error.setError("request error"); + error.setError_description(t.getLocalizedMessage()); + listener.onError(error); + } + }); + } + } + } +} diff --git a/app/src/main/java/com/truchsess/send2car/cd/api/CDApiService.java b/app/src/main/java/com/truchsess/send2car/cd/api/CDApiService.java new file mode 100644 index 0000000..f028551 --- /dev/null +++ b/app/src/main/java/com/truchsess/send2car/cd/api/CDApiService.java @@ -0,0 +1,62 @@ +package com.truchsess.send2car.cd.api; + +import com.truchsess.send2car.cd.Token; +import com.truchsess.send2car.cd.entity.VehicleStatus; + +import retrofit2.Call; + +import static com.truchsess.send2car.cd.api.CDApi.API_SERVER; + +/********************************************************************************************** + Copyright (C) 2018 Norbert Truchsess norbert.truchsess@t-online.de + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + **********************************************************************************************/ +public abstract class CDApiService extends CDApiCall { + + private Token token; + private String bearer; + private String tokenType; + private boolean requiresNewService = true; + + protected CDApiService(Token token) { + this.token = token; + } + + abstract protected Call createService(String authorization); + + protected void requestService(final CDApiServiceListener listener) { + String bearer = token.getToken(); + String tokenType = token.getTokenType(); + if (bearer == null || tokenType == null) { + apiCall = null; + } else { + if (!bearer.equals(this.bearer) + || !tokenType.equals(this.tokenType) + || requiresNewService) { + this.bearer = bearer; + this.tokenType = tokenType; + apiCall = createService(this.tokenType + " " + bearer); + this.requiresNewService = false; + } + if (apiCall != null) { + requestResult(listener); + } + } + } + + public void setRequiresNewService() { + this.requiresNewService = true; + } +} diff --git a/app/src/main/java/com/truchsess/send2car/cd/api/ErrorResponse.java b/app/src/main/java/com/truchsess/send2car/cd/api/ErrorResponse.java new file mode 100644 index 0000000..43ece81 --- /dev/null +++ b/app/src/main/java/com/truchsess/send2car/cd/api/ErrorResponse.java @@ -0,0 +1,40 @@ +package com.truchsess.send2car.cd.api; + +/********************************************************************************************** + Copyright (C) 2018 Norbert Truchsess norbert.truchsess@t-online.de + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + **********************************************************************************************/ +public class ErrorResponse { + + private String error; + + private String error_description; + + public String getError() { + return error; + } + + public void setError(String error) { + this.error = error; + } + + public String getError_description() { + return error_description; + } + + public void setError_description(String error_description) { + this.error_description = error_description; + } +} diff --git a/app/src/main/java/com/truchsess/send2car/cd/api/ExecutionStatusResponse.java b/app/src/main/java/com/truchsess/send2car/cd/api/ExecutionStatusResponse.java new file mode 100644 index 0000000..0e91574 --- /dev/null +++ b/app/src/main/java/com/truchsess/send2car/cd/api/ExecutionStatusResponse.java @@ -0,0 +1,28 @@ +package com.truchsess.send2car.cd.api; + +import com.truchsess.send2car.cd.entity.ExecutionStatus; + +/********************************************************************************************** + Copyright (C) 2018 Norbert Truchsess norbert.truchsess@t-online.de + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + **********************************************************************************************/ +public class ExecutionStatusResponse extends ErrorResponse { + + private ExecutionStatus executionStatus; + + public ExecutionStatus getExecutionStatus() { + return executionStatus; + } +} diff --git a/app/src/main/java/com/truchsess/send2car/cd/api/PoiMessage.java b/app/src/main/java/com/truchsess/send2car/cd/api/PoiMessage.java new file mode 100644 index 0000000..26d6631 --- /dev/null +++ b/app/src/main/java/com/truchsess/send2car/cd/api/PoiMessage.java @@ -0,0 +1,32 @@ +package com.truchsess.send2car.cd.api; + +import com.truchsess.send2car.cd.entity.Poi; + +/********************************************************************************************** + Copyright (C) 2018 Norbert Truchsess norbert.truchsess@t-online.de + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + **********************************************************************************************/ +public class PoiMessage { + + private Poi poi; + + public Poi getPoi() { + return poi; + } + + public void setPoi(Poi poi) { + this.poi = poi; + } +} diff --git a/app/src/main/java/com/truchsess/send2car/cd/api/TokenResponse.java b/app/src/main/java/com/truchsess/send2car/cd/api/TokenResponse.java new file mode 100644 index 0000000..b6b392d --- /dev/null +++ b/app/src/main/java/com/truchsess/send2car/cd/api/TokenResponse.java @@ -0,0 +1,50 @@ +package com.truchsess.send2car.cd.api; + +/********************************************************************************************** + Copyright (C) 2018 Norbert Truchsess norbert.truchsess@t-online.de + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + **********************************************************************************************/ +public class TokenResponse extends ErrorResponse { + + private String access_token; + + private String token_type; + + private long expires_in; + + private String refresh_token; + + private String scope; + + public String getAccess_token() { + return access_token; + } + + public String getToken_type() { + return token_type; + } + + public long getExpires_in() { + return expires_in; + } + + public String getRefresh_token() { + return refresh_token; + } + + public String getScope() { + return scope; + } +} diff --git a/app/src/main/java/com/truchsess/send2car/cd/api/VehicleResponse.java b/app/src/main/java/com/truchsess/send2car/cd/api/VehicleResponse.java new file mode 100644 index 0000000..3f85281 --- /dev/null +++ b/app/src/main/java/com/truchsess/send2car/cd/api/VehicleResponse.java @@ -0,0 +1,30 @@ +package com.truchsess.send2car.cd.api; + +import com.truchsess.send2car.cd.entity.Vehicle; + +import java.util.List; + +/********************************************************************************************** + Copyright (C) 2018 Norbert Truchsess norbert.truchsess@t-online.de + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + **********************************************************************************************/ +public class VehicleResponse extends ErrorResponse { + + private List vehicles; + + public List getVehicles() { + return vehicles; + } +} diff --git a/app/src/main/java/com/truchsess/send2car/cd/api/VehicleStatusResponse.java b/app/src/main/java/com/truchsess/send2car/cd/api/VehicleStatusResponse.java new file mode 100644 index 0000000..1e68953 --- /dev/null +++ b/app/src/main/java/com/truchsess/send2car/cd/api/VehicleStatusResponse.java @@ -0,0 +1,28 @@ +package com.truchsess.send2car.cd.api; + +import com.truchsess.send2car.cd.entity.VehicleStatus; + +/********************************************************************************************** + Copyright (C) 2018 Norbert Truchsess norbert.truchsess@t-online.de + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + **********************************************************************************************/ +public class VehicleStatusResponse extends ErrorResponse { + + private VehicleStatus vehicleStatus; + + public VehicleStatus getVehicleStatus() { + return vehicleStatus; + } +} diff --git a/app/src/main/java/com/truchsess/send2car/cd/entity/CDApiJSONError.java b/app/src/main/java/com/truchsess/send2car/cd/entity/CDApiJSONError.java new file mode 100644 index 0000000..7d2256a --- /dev/null +++ b/app/src/main/java/com/truchsess/send2car/cd/entity/CDApiJSONError.java @@ -0,0 +1,40 @@ +package com.truchsess.send2car.cd.entity; + +import java.util.List; + +/********************************************************************************************** + Copyright (C) 2018 Norbert Truchsess norbert.truchsess@t-online.de + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + **********************************************************************************************/ +public class CDApiJSONError { + private List reasons; + private ErrorDetails details; + + public List getReasons() { + return reasons; + } + + public void setReasons(List reasons) { + this.reasons = reasons; + } + + public ErrorDetails getDetails() { + return details; + } + + public void setDetails(ErrorDetails details) { + this.details = details; + } +} \ No newline at end of file diff --git a/app/src/main/java/com/truchsess/send2car/cd/entity/Dealer.java b/app/src/main/java/com/truchsess/send2car/cd/entity/Dealer.java new file mode 100644 index 0000000..8de7eaf --- /dev/null +++ b/app/src/main/java/com/truchsess/send2car/cd/entity/Dealer.java @@ -0,0 +1,50 @@ +package com.truchsess.send2car.cd.entity; + +/********************************************************************************************** + Copyright (C) 2018 Norbert Truchsess norbert.truchsess@t-online.de + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + **********************************************************************************************/ +public class Dealer { + + private String name; + + private String country; + + private String postalCode; + + private String city; + + private String street; + + public String getName() { + return name; + } + + public String getCountry() { + return country; + } + + public String getPostalCode() { + return postalCode; + } + + public String getCity() { + return city; + } + + public String getStreet() { + return street; + } +} diff --git a/app/src/main/java/com/truchsess/send2car/cd/entity/ErrorDetails.java b/app/src/main/java/com/truchsess/send2car/cd/entity/ErrorDetails.java new file mode 100644 index 0000000..366f394 --- /dev/null +++ b/app/src/main/java/com/truchsess/send2car/cd/entity/ErrorDetails.java @@ -0,0 +1,29 @@ +package com.truchsess.send2car.cd.entity; + +/********************************************************************************************** + Copyright (C) 2018 Norbert Truchsess norbert.truchsess@t-online.de + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + **********************************************************************************************/ +public class ErrorDetails { + private String msgId; // "Id-5fcd545ca540fe25b8536db7" + + public String getMsgId() { + return msgId; + } + + public void setMsgId(String msgId) { + this.msgId = msgId; + } +} diff --git a/app/src/main/java/com/truchsess/send2car/cd/entity/ExecutionStatus.java b/app/src/main/java/com/truchsess/send2car/cd/entity/ExecutionStatus.java new file mode 100644 index 0000000..5f1353e --- /dev/null +++ b/app/src/main/java/com/truchsess/send2car/cd/entity/ExecutionStatus.java @@ -0,0 +1,38 @@ +package com.truchsess.send2car.cd.entity; + +/********************************************************************************************** + Copyright (C) 2018 Norbert Truchsess norbert.truchsess@t-online.de + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + **********************************************************************************************/ +public class ExecutionStatus { + + private String serviceType; + + private String status; + + private String eventId; + + public String getServiceType() { + return serviceType; + } + + public String getStatus() { + return status; + } + + public String getEventId() { + return eventId; + } +} diff --git a/app/src/main/java/com/truchsess/send2car/cd/entity/Poi.java b/app/src/main/java/com/truchsess/send2car/cd/entity/Poi.java new file mode 100644 index 0000000..33d55c9 --- /dev/null +++ b/app/src/main/java/com/truchsess/send2car/cd/entity/Poi.java @@ -0,0 +1,107 @@ +package com.truchsess.send2car.cd.entity; + +/********************************************************************************************** + Copyright (C) 2018 Norbert Truchsess norbert.truchsess@t-online.de + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + **********************************************************************************************/ +public class Poi { + + private String city = ""; + + private double lat = 0.0; + + private double lon = 0.0; + + private String name = ""; + + private long rating = -1; + + private String postalCode = ""; + + private String street = ""; + + public String getCity() { + return city; + } + + public void setCity(String city) { + this.city = city; + } + + public double getLat() { + return lat; + } + + public void setLat(double lat) { + this.lat = lat; + } + + public double getLon() { + return lon; + } + + public void setLon(double lon) { + this.lon = lon; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public long getRating() { + return rating; + } + + public void setRating(long rating) { + this.rating = rating; + } + + public String getPostalCode() { + return postalCode; + } + + public void setPostalCode(String postalCode) { + this.postalCode = postalCode; + } + + public String getStreet() { + return street; + } + + public void setStreet(String street) { + this.street = street; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + Poi poi = (Poi) o; + + if (Double.compare(poi.lat, lat) != 0) return false; + if (Double.compare(poi.lon, lon) != 0) return false; + if (rating != poi.rating) return false; + if (city != null ? !city.equals(poi.city) : poi.city != null) return false; + if (name != null ? !name.equals(poi.name) : poi.name != null) return false; + if (postalCode != null ? !postalCode.equals(poi.postalCode) : poi.postalCode != null) + return false; + return street != null ? street.equals(poi.street) : poi.street == null; + } +} diff --git a/app/src/main/java/com/truchsess/send2car/cd/entity/Position.java b/app/src/main/java/com/truchsess/send2car/cd/entity/Position.java new file mode 100644 index 0000000..2211869 --- /dev/null +++ b/app/src/main/java/com/truchsess/send2car/cd/entity/Position.java @@ -0,0 +1,44 @@ +package com.truchsess.send2car.cd.entity; + +/********************************************************************************************** + Copyright (C) 2018 Norbert Truchsess norbert.truchsess@t-online.de + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + **********************************************************************************************/ +public class Position { + + private float lat; + + private float lon; + + private int heading; + + private String status; + + public float getLat() { + return lat; + } + + public float getLon() { + return lon; + } + + public int getHeading() { + return heading; + } + + public String getStatus() { + return status; + } +} diff --git a/app/src/main/java/com/truchsess/send2car/cd/entity/ServiceMessage.java b/app/src/main/java/com/truchsess/send2car/cd/entity/ServiceMessage.java new file mode 100644 index 0000000..38567e1 --- /dev/null +++ b/app/src/main/java/com/truchsess/send2car/cd/entity/ServiceMessage.java @@ -0,0 +1,221 @@ +package com.truchsess.send2car.cd.entity; + +import java.util.List; + +/********************************************************************************************** + Copyright (C) 2018 Norbert Truchsess norbert.truchsess@t-online.de + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + **********************************************************************************************/ +public class ServiceMessage { + + private List vins; // [ "ASDF1234567890123" ] + private String message; // "powered by Postman", + private String subject; // "AquariUSH - Familien", + private String number; // "2", + private String street; // "Hartmut-Hermann-Weg", + private String quarter; // "Lohhof", + private String city; // "Unterschleißheim", + private String district; // "München", + private String county; // "Oberbayern", + private String countyCode; // "Oberbayern", + private String region; // "Bayern", + private String regionCode; // "BY", + private String country; // " ", + private String countryCode; // "DE", + private String zip; // "85716", + private String lat; // "48.268322", + private String lng; // "11.583435000000009", + private String url; // "http://www.aquariush.de/", + private String name; // "AquariUSH - Familien und Thermalbad & Sauna Oase", + private String formattedPhoneNumber; // "+49 89 310094500", + private String phonetype1; // "UNKNOWN", + private String phone1; // "+49 89 310094500" + + public List getVins() { + return vins; + } + + public void setVins(List vins) { + this.vins = vins; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + public String getSubject() { + return subject; + } + + public void setSubject(String subject) { + this.subject = subject; + } + + public String getNumber() { + return number; + } + + public void setNumber(String number) { + this.number = number; + } + + public String getStreet() { + return street; + } + + public void setStreet(String street) { + this.street = street; + } + + public String getQuarter() { + return quarter; + } + + public void setQuarter(String quarter) { + this.quarter = quarter; + } + + public String getCity() { + return city; + } + + public void setCity(String city) { + this.city = city; + } + + public String getDistrict() { + return district; + } + + public void setDistrict(String district) { + this.district = district; + } + + public String getCounty() { + return county; + } + + public void setCounty(String county) { + this.county = county; + } + + public String getCountyCode() { + return countyCode; + } + + public void setCountyCode(String countyCode) { + this.countyCode = countyCode; + } + + public String getRegion() { + return region; + } + + public void setRegion(String region) { + this.region = region; + } + + public String getRegionCode() { + return regionCode; + } + + public void setRegionCode(String regionCode) { + this.regionCode = regionCode; + } + + public String getCountry() { + return country; + } + + public void setCountry(String country) { + this.country = country; + } + + public String getCountryCode() { + return countryCode; + } + + public void setCountryCode(String countryCode) { + this.countryCode = countryCode; + } + + public String getZip() { + return zip; + } + + public void setZip(String zip) { + this.zip = zip; + } + + public String getLat() { + return lat; + } + + public void setLat(String lat) { + this.lat = lat; + } + + public String getLng() { + return lng; + } + + public void setLng(String lng) { + this.lng = lng; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getFormattedPhoneNumber() { + return formattedPhoneNumber; + } + + public void setFormattedPhoneNumber(String formattedPhoneNumber) { + this.formattedPhoneNumber = formattedPhoneNumber; + } + + public String getPhonetype1() { + return phonetype1; + } + + public void setPhonetype1(String phonetype1) { + this.phonetype1 = phonetype1; + } + + public String getPhone1() { + return phone1; + } + + public void setPhone1(String phone1) { + this.phone1 = phone1; + } +} diff --git a/app/src/main/java/com/truchsess/send2car/cd/entity/Vehicle.java b/app/src/main/java/com/truchsess/send2car/cd/entity/Vehicle.java new file mode 100644 index 0000000..e5b5edb --- /dev/null +++ b/app/src/main/java/com/truchsess/send2car/cd/entity/Vehicle.java @@ -0,0 +1,297 @@ +package com.truchsess.send2car.cd.entity; + +import java.util.List; + +/********************************************************************************************** + Copyright (C) 2018 Norbert Truchsess norbert.truchsess@t-online.de + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + **********************************************************************************************/ +public class Vehicle { + private String vehicleFinderRestriction; + + private String doorUnlock; + + private String color; + + private String onlineSearchMode; + + private Dealer dealer; + + private String climateNowRES; + + private String breakdownNumber; + + private String smartSolution; + + private int yearOfConstruction; + + private String driveTrain; + + private String rangeMap; + + private String vehicleFinder; + + private String a4a; + + private String hornBlow; + + private String chargeNow; + + private String countryCode; + + private String bodytype; + + private String lightFlash; + + private String vin; + + private String model; + + private String ipa; + + private String brand; + + private String climateControl; + + private String climateControlRES; + + private String sendPoi; + + private String lastDestinations; + + private String remoteSoftwareUpgrade; + + private String doorLock; + + private String chargingControl; + + private String onlineSearchProvider; + + private String steering; + + private String intermodalRouting; + + private List supportedChargingModes; + + private String lscType; + + private boolean hasAlarmSystem; + + private boolean statisticsCommunityEnabled; + + private String climateNow; + + private String hub; + + private String remote360; + + private String hmiVersion; + + private String chargingUpdateMode; + + private String climateFunction; + + private String colorCode; + + private String carCloud; + + private boolean statisticsAvailable; + + private String licensePlate; + + public String getVehicleFinderRestriction() { + return vehicleFinderRestriction; + } + + public String getDoorUnlock() { + return doorUnlock; + } + + public String getColor() { + return color; + } + + public String getOnlineSearchMode() { + return onlineSearchMode; + } + + public Dealer getDealer() { + return dealer; + } + + public String getClimateNowRES() { + return climateNowRES; + } + + public String getBreakdownNumber() { + return breakdownNumber; + } + + public String getSmartSolution() { + return smartSolution; + } + + public int getYearOfConstruction() { + return yearOfConstruction; + } + + public String getDriveTrain() { + return driveTrain; + } + + public String getRangeMap() { + return rangeMap; + } + + public String getVehicleFinder() { + return vehicleFinder; + } + + public String getA4a() { + return a4a; + } + + public String getHornBlow() { + return hornBlow; + } + + public String getChargeNow() { + return chargeNow; + } + + public String getCountryCode() { + return countryCode; + } + + public String getBodytype() { + return bodytype; + } + + public String getLightFlash() { + return lightFlash; + } + + public String getVin() { + return vin; + } + + public String getModel() { + return model; + } + + public String getIpa() { + return ipa; + } + + public String getBrand() { + return brand; + } + + public String getClimateControl() { + return climateControl; + } + + public String getClimateControlRES() { + return climateControlRES; + } + + public String getSendPoi() { + return sendPoi; + } + + public String getLastDestinations() { + return lastDestinations; + } + + public String getRemoteSoftwareUpgrade() { + return remoteSoftwareUpgrade; + } + + public String getDoorLock() { + return doorLock; + } + + public String getChargingControl() { + return chargingControl; + } + + public String getOnlineSearchProvider() { + return onlineSearchProvider; + } + + public String getSteering() { + return steering; + } + + public String getIntermodalRouting() { + return intermodalRouting; + } + + public List getSupportedChargingModes() { + return supportedChargingModes; + } + + public String getLscType() { + return lscType; + } + + public boolean isHasAlarmSystem() { + return hasAlarmSystem; + } + + public boolean isStatisticsCommunityEnabled() { + return statisticsCommunityEnabled; + } + + public String getClimateNow() { + return climateNow; + } + + public String getHub() { + return hub; + } + + public String getRemote360() { + return remote360; + } + + public String getHmiVersion() { + return hmiVersion; + } + + public String getChargingUpdateMode() { + return chargingUpdateMode; + } + + public String getClimateFunction() { + return climateFunction; + } + + public String getColorCode() { + return colorCode; + } + + public String getCarCloud() { + return carCloud; + } + + public boolean isStatisticsAvailable() { + return statisticsAvailable; + } + + public String getLicensePlate() { + return licensePlate; + } +} diff --git a/app/src/main/java/com/truchsess/send2car/cd/entity/VehicleStatus.java b/app/src/main/java/com/truchsess/send2car/cd/entity/VehicleStatus.java new file mode 100644 index 0000000..7681627 --- /dev/null +++ b/app/src/main/java/com/truchsess/send2car/cd/entity/VehicleStatus.java @@ -0,0 +1,236 @@ +package com.truchsess.send2car.cd.entity; + +/********************************************************************************************** + Copyright (C) 2018 Norbert Truchsess norbert.truchsess@t-online.de + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + **********************************************************************************************/ +public class VehicleStatus { + + private String vin; + + private int mileage; + + private String updateReason; + + private String updateTime; + + private String doorDriverFront; + + private String doorDriverRear; + + private String doorPassengerFront; + + private String doorPassengerRear; + + private String windowDriverFront; + + private String windowDriverRear; + + private String windowPassengerFront; + + private String windowPassengerRear; + + private String trunk; + + private String rearWindow; + + private String convertibleRoofState; + + private String hood; + + private String doorLockState; + + private String parkingLight; + + private String positionLight; + + private float remainingFuel; + + private int remainingRangeElectric; + + private int remainingRangeElectricMls; + + private int remainingRangeFuel; + + private int remainingRangeFuelMls; + + private int maxRangeElectric; + + private int maxRangeElectricMls; + + private int fuelPercent; + + private float maxFuel; + + private String connectionStatus; + + private String chargingStatus; + + private int chargingLevelHv; + + private String lastChargingEndReason; + + private String lastChargingEndResult; + + private Position position; + + private int chargingTimeRemaining; + + private String internalDataTimeUTC; + + public String getVin() { + return vin; + } + + public int getMileage() { + return mileage; + } + + public String getUpdateReason() { + return updateReason; + } + + public String getUpdateTime() { + return updateTime; + } + + public String getDoorDriverFront() { + return doorDriverFront; + } + + public String getDoorDriverRear() { + return doorDriverRear; + } + + public String getDoorPassengerFront() { + return doorPassengerFront; + } + + public String getDoorPassengerRear() { + return doorPassengerRear; + } + + public String getWindowDriverFront() { + return windowDriverFront; + } + + public String getWindowDriverRear() { + return windowDriverRear; + } + + public String getWindowPassengerFront() { + return windowPassengerFront; + } + + public String getWindowPassengerRear() { + return windowPassengerRear; + } + + public String getTrunk() { + return trunk; + } + + public String getRearWindow() { + return rearWindow; + } + + public String getConvertibleRoofState() { + return convertibleRoofState; + } + + public String getHood() { + return hood; + } + + public String getDoorLockState() { + return doorLockState; + } + + public String getParkingLight() { + return parkingLight; + } + + public String getPositionLight() { + return positionLight; + } + + public float getRemainingFuel() { + return remainingFuel; + } + + public int getRemainingRangeElectric() { + return remainingRangeElectric; + } + + public int getRemainingRangeElectricMls() { + return remainingRangeElectricMls; + } + + public int getRemainingRangeFuel() { + return remainingRangeFuel; + } + + public int getRemainingRangeFuelMls() { + return remainingRangeFuelMls; + } + + public int getMaxRangeElectric() { + return maxRangeElectric; + } + + public int getMaxRangeElectricMls() { + return maxRangeElectricMls; + } + + public int getFuelPercent() { + return fuelPercent; + } + + public float getMaxFuel() { + return maxFuel; + } + + public String getConnectionStatus() { + return connectionStatus; + } + + public String getChargingStatus() { + return chargingStatus; + } + + public int getChargingLevelHv() { + return chargingLevelHv; + } + + public String getLastChargingEndReason() { + return lastChargingEndReason; + } + + public String getLastChargingEndResult() { + return lastChargingEndResult; + } + + public Position getPosition() { + return position; + } + + public int getChargingTimeRemaining() { + return chargingTimeRemaining; + } + + public String getInternalDataTimeUTC() { + return internalDataTimeUTC; + } +} diff --git a/app/src/main/java/com/truchsess/send2car/component/GetVehiclesController.java b/app/src/main/java/com/truchsess/send2car/component/GetVehiclesController.java new file mode 100644 index 0000000..d885d59 --- /dev/null +++ b/app/src/main/java/com/truchsess/send2car/component/GetVehiclesController.java @@ -0,0 +1,106 @@ +package com.truchsess.send2car.component; + +import com.truchsess.send2car.cd.GetVehicles; +import com.truchsess.send2car.cd.Token; +import com.truchsess.send2car.cd.api.CDApi; +import com.truchsess.send2car.cd.api.ErrorResponse; +import com.truchsess.send2car.cd.api.VehicleResponse; +import com.truchsess.send2car.cd.entity.CDApiJSONError; +import com.truchsess.send2car.cd.entity.Vehicle; + +import java.util.ArrayList; +import java.util.List; +import java.util.ResourceBundle; + +/********************************************************************************************** + Copyright (C) 2018 Norbert Truchsess norbert.truchsess@t-online.de + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + **********************************************************************************************/ +public class GetVehiclesController { + + private final GetVehicles getVehicles; + private final List vehiclesList; + + private int vehiclesIndex = -1; + + private ResourceBundle categories; + + public GetVehiclesController() { + getVehicles = new GetVehicles(CDApi.API_SERVER); + vehiclesList = new ArrayList<>(); + } + + public interface GetVehiclesListener { + void onUpdate(); + void onError(String error); + } + + public void getVehiclesResponse(final Token token, final GetVehiclesListener listener) { + token.checkToken(new Token.AuthenticationListener() { + @Override + public void onAuthentication() { + getVehicles.getVehiclesResponse(token.getAuthorization(), new GetVehicles.GetVehiclesListener() { + @Override + public void onSuccess(VehicleResponse response) { + vehiclesList.clear(); + vehiclesList.addAll(response.getVehicles()); + listener.onUpdate(); + } + + @Override + public void onError(CDApiJSONError error) { + final StringBuilder builder = new StringBuilder(); + boolean first = true; + for (String reason : error.getReasons()) { + if (first) { + first = false; + } else { + builder.append(", "); + first = false; + } + builder.append(reason); + } + listener.onError(builder.toString()); + } + }); + } + + @Override + public void onAuthenticationFailure(ErrorResponse errorResponse) { + listener.onError(errorResponse.getError()+": "+errorResponse.getError_description()); + } + }); + } + + public void setVehiclesIndex(final int index) { + vehiclesIndex = index; + } + + public int getNumVehicles() { + return vehiclesList.size(); + } + + public Vehicle getVehicle() { + return getVehicle(vehiclesIndex); + } + + public Vehicle getVehicle(int position) { + if (position >= 0 && position < vehiclesList.size()) { + return vehiclesList.get(position); + } else { + return null; + } + } +} diff --git a/app/src/main/java/com/truchsess/send2car/component/SendServiceMessageController.java b/app/src/main/java/com/truchsess/send2car/component/SendServiceMessageController.java new file mode 100644 index 0000000..a56eb1f --- /dev/null +++ b/app/src/main/java/com/truchsess/send2car/component/SendServiceMessageController.java @@ -0,0 +1,445 @@ +package com.truchsess.send2car.component; + +import android.net.Uri; + +import com.truchsess.send2car.cd.SendServiceMessage; +import com.truchsess.send2car.cd.Token; +import com.truchsess.send2car.cd.api.CDApi; +import com.truchsess.send2car.cd.entity.CDApiJSONError; +import com.truchsess.send2car.cd.entity.ServiceMessage; +import com.truchsess.send2car.geo.GeoUrl; +import com.truchsess.send2car.geo.api.NominatimCall; +import com.truchsess.send2car.geo.api.NominatimError; +import com.truchsess.send2car.geo.entity.Address; +import com.truchsess.send2car.geo.entity.ExtraTags; +import com.truchsess.send2car.geo.entity.NameDetails; +import com.truchsess.send2car.geo.entity.Place; + +import java.util.ArrayList; +import java.util.List; +import java.util.MissingResourceException; +import java.util.ResourceBundle; + +/********************************************************************************************** + Copyright (C) 2018 Norbert Truchsess norbert.truchsess@t-online.de + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + **********************************************************************************************/ +public class SendServiceMessageController { + + public static String NOMINATIM_PROPERTIES = "nominatim.properties"; + + private final SendServiceMessage sendServiceMessage; + private final NominatimCall nominatimCall; + private final List serviceMessageList; + private final List vinList; + + private GeoUrl geoUrl; + private int serviceMessageIndex = -1; + + private ResourceBundle categories; + + public SendServiceMessageController() { + sendServiceMessage = new SendServiceMessage(CDApi.CD_SERVER); + geoUrl = new GeoUrl(); + nominatimCall = new NominatimCall(); + serviceMessageList = new ArrayList<>(); + vinList = new ArrayList<>(); + } + + public void setGeoUrlFromUri(final Uri geoUri) { + geoUrl.fromUri(geoUri); + } + + public void setGeoUrl(final GeoUrl geoUrl) { + this.geoUrl = geoUrl; + } + + public interface ServiceMessageUpdateListener { + void onUpdate(); + void onError(String error); + } + + public interface ServiceMessageSendListener { + void onSent(); + void onError(String error); + } + + private ServiceMessage createServiceMessageFromPlace(final Place place) { + + final ServiceMessage serviceMessage = new ServiceMessage(); + + serviceMessage.setLat(GeoUrl.degreeToString(place.getLat())); + serviceMessage.setLng(GeoUrl.degreeToString(place.getLon())); + + final String description = geoUrl.getDescription(); + + createName(serviceMessage, place, description); + + createSubject(serviceMessage, description); + + createMessage(serviceMessage, place, description); + + createAddress(serviceMessage, place); + + return serviceMessage; + } + + private void createName(final ServiceMessage serviceMessage, final Place place, final String description) { + //https://github.com/openstreetmap/Nominatim/blob/master/settings/address-levels.json + final NameDetails nameDetails = place.getNamedetails(); + String name = null; + if (nameDetails != null) { + name = nameDetails.getName(); + } + if (name == null || name.isEmpty()) { + name = place.getName(); + } + if (name != null && !name.isEmpty()) { + // https://github.com/openstreetmap/Nominatim/blob/80df4d3b560f5b1fd550dcf8cdc09a992b69fee0/settings/partitionedtags.def + final String type = place.getType(); + if (type != null && !type.isEmpty() && !type.equals("yes")) { + if (categories != null) { + try { + serviceMessage.setName(name + " (" + categories.getString(type) + ")"); + } catch (MissingResourceException mre) { + serviceMessage.setName(name + " (" + type + ")"); + } + } else { + serviceMessage.setName(name + " (" + type + ")"); + } + } else { + serviceMessage.setName(name); + } + } else { + final String displayName = place.getDisplay_name(); + if (displayName != null && !displayName.isEmpty()) { + serviceMessage.setName(displayName); + } else { + serviceMessage.setName(description); + } + } + } + + private void createSubject(final ServiceMessage serviceMessage, final String description) { + final String subject = description == null || description.isEmpty() + ? serviceMessage.getName() + : description; + if (subject != null && !subject.isEmpty()) { + serviceMessage.setSubject(subject.length() > 20 ? subject.substring(0, 19) : subject); + } else { + serviceMessage.setSubject("neues Fahrziel"); + } + } + + private void createMessage(final ServiceMessage serviceMessage, final Place place, final String description) { + + boolean first = true; + final StringBuilder messageBuilder = new StringBuilder(); + + final String name = serviceMessage.getName(); + if (name != null && !name.isEmpty()) { + messageBuilder.append(name); + first = false; + } else { + if (description != null && !description.isEmpty()) { + messageBuilder.append(description); + first = false; + } + } + + final ExtraTags extraTags = place.getExtratags(); + if (extraTags != null) { + final String sport = extraTags.getSport(); + if (sport != null && !sport.isEmpty()) { + if (!first) { + messageBuilder.append(" ("); + } + messageBuilder.append(sport); + if (!first) { + messageBuilder.append(")"); + } + first = false; + } + } + + if (extraTags != null) { + + final String openingHours = extraTags.getOpening_hours(); + if (openingHours!=null && !openingHours.isEmpty()) { + if (!first) { + messageBuilder.append("\n"); + } + messageBuilder.append(openingHours.replaceAll("\\s*;\\s*","\n").replaceAll(" {2,}"," ")); + } + + final String phone = extraTags.getContactPhone(); + if (phone!=null && !phone.isEmpty()) { + serviceMessage.setFormattedPhoneNumber(phone); + serviceMessage.setPhone1(phone); + serviceMessage.setPhonetype1("UNKNOWN"); + } + + final String website = extraTags.getContactWebsite(); + if (website!=null && !website.isEmpty()) { + serviceMessage.setUrl(website); + } + } + + final int messageLength = messageBuilder.length(); + if (messageLength>255) { + serviceMessage.setMessage(messageBuilder.substring(0,255)); + } else if (messageLength > 0){ + serviceMessage.setMessage(messageBuilder.toString()); + } else { + serviceMessage.setMessage(null); + } + } + + private void createAddress(ServiceMessage serviceMessage, Place place) { + final Address address = place.getAddress(); + + if (address != null) { + + final String road = address.getRoad(); + if (road != null && !road.isEmpty()) { + serviceMessage.setStreet(road); + } else { + final String footway = address.getFootway(); + if (footway != null && !footway.isEmpty()) { + serviceMessage.setStreet(footway); + } else { + final String pedestrian = address.getPedestrian(); + if (pedestrian != null && !pedestrian.isEmpty()) { + serviceMessage.setStreet(pedestrian); + } else { + final String name = place.getName(); + if (name != null && !name.isEmpty() && !name.equals(serviceMessage.getName())) { + serviceMessage.setStreet(name); + } else { + serviceMessage.setStreet(null); + } + } + } + } + + final String houseNumber = address.getHouse_number(); + if (houseNumber != null && !houseNumber.isEmpty()) { + serviceMessage.setNumber(houseNumber); + } else { + serviceMessage.setNumber(null); + } + + final String city = address.getCity(); + if (city != null && !city.isEmpty()) { + serviceMessage.setCity(address.getCity()); + } else { + final String town = address.getTown(); + if (town != null && !town.isEmpty()) { + serviceMessage.setCity(town); + } else { + final String village = address.getVillage(); + if (village != null && !village.isEmpty()) { + serviceMessage.setCity(village); + } else { + serviceMessage.setCity(null); + } + } + } + + final String suburb = address.getSuburb(); + if (suburb != null && !suburb.isEmpty()) { + if (serviceMessage.getCity() == null) { + serviceMessage.setCity(suburb); + } else { + serviceMessage.setQuarter(suburb); + } + } else { + final String neighbourhood = address.getNeighbourhood(); + if (neighbourhood != null && !neighbourhood.isEmpty()) { + serviceMessage.setQuarter(neighbourhood); + } else { + serviceMessage.setQuarter(null); + } + } + + final String postcode = address.getPostcode(); + if (postcode != null && !postcode.isEmpty()) { + serviceMessage.setZip(postcode); + } else { + serviceMessage.setZip(null); + } + + final String country = address.getCountry(); + if (country != null && !country.isEmpty()) { + serviceMessage.setCountry(country); + } else { + serviceMessage.setCountry(null); + } + + final String cityDistrict = address.getCity_district(); + if (cityDistrict != null && !cityDistrict.isEmpty()) { + serviceMessage.setDistrict(cityDistrict); + } else { + serviceMessage.setDistrict(null); + } + + final String countryCode = address.getCountry_code(); + if (countryCode != null && !countryCode.isEmpty()) { + serviceMessage.setCountryCode(countryCode); + } else { + serviceMessage.setCountryCode(null); + } + + final String state = address.getState(); + if (state != null && !state.isEmpty()) { + serviceMessage.setRegion(state); + } else { + serviceMessage.setRegion(null); + } + + final String stateDistrict = address.getState_district(); + if (stateDistrict != null && !stateDistrict.isEmpty()) { + serviceMessage.setCounty(stateDistrict); + } else { + serviceMessage.setCounty(null); + } + } + } + + public void lookupGeodata(final ServiceMessageUpdateListener listener) { + + if (geoUrl != null) { + + final double lat = geoUrl.getLat(); + final double lon = geoUrl.getLon(); + final String description = geoUrl.getDescription(); + + if (Double.isNaN(lat) || Double.isNaN(lon) || (lat==0.0 && lon==0.0) && description != null && !description.isEmpty()) { + nominatimCall.requestSearch(description, new NominatimCall.NominatimCallListener>() { + @Override + public void onSuccess(final List places) { + serviceMessageList.clear(); + serviceMessageIndex = -1; + for(final Place place : places) { + serviceMessageList.add(createServiceMessageFromPlace(place)); + } + listener.onUpdate(); + } + + @Override + public void onError(NominatimError error) { + serviceMessageList.clear(); + serviceMessageIndex = -1; + listener.onError(Integer.toString(error.getCode())+": "+error.getMessage()); + } + }); + } else { + nominatimCall.requestReverse(geoUrl.getLat(), geoUrl.getLon(), new NominatimCall.NominatimCallListener() { + @Override + public void onSuccess(Place result) { + serviceMessageList.clear(); + serviceMessageIndex = -1; + final String error = result.getError(); + if (error!=null) { + listener.onError(error); + } else { + final ServiceMessage serviceMessage = createServiceMessageFromPlace(result); + serviceMessage.setLat(GeoUrl.degreeToString(lat)); + serviceMessage.setLng(GeoUrl.degreeToString(lon)); + serviceMessageList.add(serviceMessage); + listener.onUpdate(); + } + } + + @Override + public void onError(NominatimError error) { + serviceMessageList.clear(); + serviceMessageIndex = -1; + listener.onError(Integer.toString(error.getCode())+": "+error.getMessage()); + } + }); + } + } + } + + public void sendServiceMessage2Car(final Token token, final ServiceMessageSendListener listener) { + + final ServiceMessage serviceMessage = getServiceMessage(); + if (serviceMessage != null) { + serviceMessage.setVins(vinList); + sendServiceMessage.sendServiceMessage(serviceMessage, token.getAuthorization(), new SendServiceMessage.SendServiceMessageListener() { + @Override + public void onSuccess() { + listener.onSent(); + } + + @Override + public void onError(CDApiJSONError error) { + final StringBuilder builder = new StringBuilder(); + boolean first = true; + for (String reason : error.getReasons()) { + if (first) { + first = false; + } else { + builder.append(", "); + first = false; + } + builder.append(reason); + } + listener.onError(builder.toString()); + } + }); + } else { + listener.onError("serviceMessage is null"); + } + } + + public GeoUrl getGeoUrl() { + return geoUrl; + } + + public ResourceBundle getCategories() { + return categories; + } + + public void setCategories(ResourceBundle categories) { + this.categories = categories; + } + + public void setVin(String vin) { + vinList.clear(); + vinList.add(vin); + } + + public void setServiceMessageIndex(final int index) { + serviceMessageIndex = index; + } + + public int getNumServiceMessages() { + return serviceMessageList.size(); + } + + public ServiceMessage getServiceMessage() { + return getServiceMessage(serviceMessageIndex); + } + + public ServiceMessage getServiceMessage(int position) { + if (position >= 0 && position < serviceMessageList.size()) { + return serviceMessageList.get(position); + } else { + return null; + } + } +} diff --git a/app/src/main/java/com/truchsess/send2car/geo/GeoUrl.java b/app/src/main/java/com/truchsess/send2car/geo/GeoUrl.java new file mode 100644 index 0000000..ab377d8 --- /dev/null +++ b/app/src/main/java/com/truchsess/send2car/geo/GeoUrl.java @@ -0,0 +1,99 @@ +package com.truchsess.send2car.geo; + +import android.net.Uri; + +import java.util.Locale; +import java.util.StringTokenizer; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/********************************************************************************************** + Copyright (C) 2018 Norbert Truchsess norbert.truchsess@t-online.de + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + **********************************************************************************************/ +public class GeoUrl { + + private double lat = Double.NaN; + private double lon = Double.NaN; + private String description = null; + + public GeoUrl () {} + + public GeoUrl(final double lat, final double lon, final String description) { + this.lat = lat; + this.lon = lon; + this.description = description; + } + + public void fromUri(Uri uri) { + + String data = uri.getSchemeSpecificPart(); + + // format is: + // ,?z= + // 0,0?q=,(label) + + int qpos = data.indexOf("?"); + String resource = qpos < 0 ? data : data.substring(0, qpos); + String query = data.substring(qpos+1); + + Matcher resMatcher = Pattern.compile("^(\\d++\\.?\\d*),(\\d++\\.?\\d*)$").matcher(resource); + boolean resMatches = resMatcher.matches(); + + lat = resMatches ? Double.parseDouble(resMatcher.group(1)) : Double.NaN; + lon = resMatches ? Double.parseDouble(resMatcher.group(2)) : Double.NaN; + + description = null; + + StringTokenizer queryTokenizer = new StringTokenizer(query,"&"); + while (queryTokenizer.hasMoreTokens()) { + final String nextToken = queryTokenizer.nextToken(); + Matcher paramMatcher = Pattern.compile("^q=(.*)$",Pattern.DOTALL).matcher(nextToken); + if (paramMatcher.matches()) { + final String q0 = paramMatcher.group(1); + final String q1 = q0.replaceAll("[\\n\\r\\t\\f]",", "); + Matcher locationMatcher = Pattern.compile("^(\\d++\\.?\\d*),(\\d++\\.?\\d*)(\\((.*)\\)|)+$").matcher(q1); + if (locationMatcher.matches()) { + lat = Double.parseDouble(locationMatcher.group(1)); + lon = Double.parseDouble(locationMatcher.group(2)); + description = locationMatcher.group(4); + break; + } else { + description = q1; + } + } + } + } + + public boolean isValid() { + return !Double.isNaN(lat) && !Double.isNaN(lon); + } + + public double getLat() { + return lat; + } + + public double getLon() { + return lon; + } + + public static String degreeToString(final double degree) { + return String.format(Locale.US,"%1$.6f",degree); + } + + public String getDescription() { + return description; + } +} diff --git a/app/src/main/java/com/truchsess/send2car/geo/api/NominatimApi.java b/app/src/main/java/com/truchsess/send2car/geo/api/NominatimApi.java new file mode 100644 index 0000000..5808c41 --- /dev/null +++ b/app/src/main/java/com/truchsess/send2car/geo/api/NominatimApi.java @@ -0,0 +1,37 @@ +package com.truchsess.send2car.geo.api; + +import com.truchsess.send2car.geo.entity.Place; + +import java.util.List; + +import retrofit2.Call; +import retrofit2.http.GET; +import retrofit2.http.Query; + +/********************************************************************************************** + Copyright (C) 2018 Norbert Truchsess norbert.truchsess@t-online.de + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + **********************************************************************************************/ +public interface NominatimApi { + + public static final String NOMINATIM_URL = "https://nominatim.openstreetmap.org"; + + @GET("reverse?format=jsonv2&addressdetails=1&extratags=1&namedetails=1") + public Call reverse(@Query("lat") String lat, @Query("lon") String lon); + + @GET("search?format=jsonv2&addressdetails=1&extratags=1&namedetails=1") + public Call> search(@Query("q") String query); + +} diff --git a/app/src/main/java/com/truchsess/send2car/geo/api/NominatimCall.java b/app/src/main/java/com/truchsess/send2car/geo/api/NominatimCall.java new file mode 100644 index 0000000..d01e59c --- /dev/null +++ b/app/src/main/java/com/truchsess/send2car/geo/api/NominatimCall.java @@ -0,0 +1,129 @@ +package com.truchsess.send2car.geo.api; + +import com.google.gson.Gson; +import com.google.gson.JsonSyntaxException; +import com.truchsess.send2car.geo.GeoUrl; +import com.truchsess.send2car.geo.entity.Place; + +import java.util.List; +import java.util.Locale; + +import okhttp3.ResponseBody; +import retrofit2.Call; +import retrofit2.Callback; +import retrofit2.Response; +import retrofit2.Retrofit; +import retrofit2.converter.gson.GsonConverterFactory; + +/********************************************************************************************** + Copyright (C) 2018 Norbert Truchsess norbert.truchsess@t-online.de + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + **********************************************************************************************/ +public class NominatimCall { + + private final NominatimApi api; + private boolean callRunning = false; + + public NominatimCall() { + + Retrofit retrofit = new Retrofit.Builder() + .baseUrl(NominatimApi.NOMINATIM_URL) + .addConverterFactory(GsonConverterFactory.create()) + .build(); + api = retrofit.create(NominatimApi.class); + } + + public static interface NominatimCallListener { + + public void onSuccess(T result); + + public void onError(NominatimError error); + + } + + private class PlaceCallback implements Callback { + + private final NominatimCallListener listener; + + PlaceCallback(NominatimCallListener listener) { + this.listener = listener; + } + + @Override + public void onResponse(Call call, Response response) { + final T result = response.body(); + if (response.isSuccessful()) { + listener.onSuccess(result); + } else { + final ResponseBody errorBody = response.errorBody(); + NominatimErrorResponse errorResponse = null; + if (errorBody != null) { + try { + errorResponse = new Gson().fromJson(errorBody.charStream(), NominatimErrorResponse.class); + } catch (JsonSyntaxException jse) { + } + } + if (errorResponse != null && errorResponse.getError() != null) { + listener.onError(errorResponse.getError()); + } else { + final NominatimError error = new NominatimError(); + error.setCode(response.code()); + error.setMessage(response.message()); + listener.onError(error); + } + } + synchronized (api) { + callRunning = false; + } + } + + @Override + public void onFailure(Call call, Throwable t) { + final NominatimError error = new NominatimError(); + error.setCode(-1); + error.setMessage(t.getLocalizedMessage()); + listener.onError(error); + synchronized (api) { + callRunning = false; + } + } + } + + public void requestReverse(double lat, double lon, final NominatimCallListener listener) { + + synchronized (api) { + if (!callRunning) { + callRunning = true; + api.reverse(GeoUrl.degreeToString(lat),GeoUrl.degreeToString(lon)).enqueue(new PlaceCallback(listener)); + } + } + } + + public void requestSearch(String query, final NominatimCallListener> listener) { + + synchronized (api) { + if (!callRunning) { + callRunning = true; + api.search(query).enqueue(new PlaceCallback>(listener)); + } + } + } + + public boolean isCallRunning() { + synchronized (api) { + return callRunning; + } + } +} diff --git a/app/src/main/java/com/truchsess/send2car/geo/api/NominatimError.java b/app/src/main/java/com/truchsess/send2car/geo/api/NominatimError.java new file mode 100644 index 0000000..9226a28 --- /dev/null +++ b/app/src/main/java/com/truchsess/send2car/geo/api/NominatimError.java @@ -0,0 +1,40 @@ +package com.truchsess.send2car.geo.api; + +/********************************************************************************************** + Copyright (C) 2018 Norbert Truchsess norbert.truchsess@t-online.de + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + **********************************************************************************************/ +public class NominatimError { + + private int code; + + private String message; + + public int getCode() { + return code; + } + + public void setCode(int code) { + this.code = code; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } +} diff --git a/app/src/main/java/com/truchsess/send2car/geo/api/NominatimErrorResponse.java b/app/src/main/java/com/truchsess/send2car/geo/api/NominatimErrorResponse.java new file mode 100644 index 0000000..0e77680 --- /dev/null +++ b/app/src/main/java/com/truchsess/send2car/geo/api/NominatimErrorResponse.java @@ -0,0 +1,26 @@ +package com.truchsess.send2car.geo.api; + +/********************************************************************************************** + Copyright (C) 2018 Norbert Truchsess norbert.truchsess@t-online.de + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + **********************************************************************************************/ +public class NominatimErrorResponse { + + private NominatimError error; + + public NominatimError getError() { + return error; + } +} diff --git a/app/src/main/java/com/truchsess/send2car/geo/entity/Address.java b/app/src/main/java/com/truchsess/send2car/geo/entity/Address.java new file mode 100644 index 0000000..2ea7615 --- /dev/null +++ b/app/src/main/java/com/truchsess/send2car/geo/entity/Address.java @@ -0,0 +1,116 @@ +package com.truchsess.send2car.geo.entity; + +/********************************************************************************************** + Copyright (C) 2018 Norbert Truchsess norbert.truchsess@t-online.de + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + **********************************************************************************************/ +public class Address { + + private String house_number; + + private String pedestrian; + + private String footway; + + private String road; + + private String village; + + private String town; + + private String city; + + private String county; + + private String state_district; + + private String state; + + private String postcode; + + private String country; + + private String country_code; + + private String city_district; + + private String suburb; + + private String neighbourhood; + + public String getHouse_number() { + return house_number; + } + + public String getPedestrian() { + return pedestrian; + } + + public String getFootway() { + return footway; + } + + public String getRoad() { + return road; + } + + public String getVillage() { + return village; + } + + public String getTown() { + return town; + } + + public String getCity() { + return city; + } + + public String getCounty() { + return county; + } + + public String getState_district() { + return state_district; + } + + public String getState() { + return state; + } + + public String getPostcode() { + return postcode; + } + + public String getCountry() { + return country; + } + + public String getCountry_code() { + return country_code; + } + + public String getCity_district() { + return city_district; + } + + public String getSuburb() { + return suburb; + } + + public String getNeighbourhood() { + return neighbourhood; + } +} diff --git a/app/src/main/java/com/truchsess/send2car/geo/entity/ExtraTags.java b/app/src/main/java/com/truchsess/send2car/geo/entity/ExtraTags.java new file mode 100644 index 0000000..d09228f --- /dev/null +++ b/app/src/main/java/com/truchsess/send2car/geo/entity/ExtraTags.java @@ -0,0 +1,54 @@ +package com.truchsess.send2car.geo.entity; + +import com.google.gson.annotations.SerializedName; + +/********************************************************************************************** + Copyright (C) 2018 Norbert Truchsess norbert.truchsess@t-online.de + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + **********************************************************************************************/ +public class ExtraTags { + + private String sport; + private String opening_hours; + + @SerializedName("contact:fax") + private String contactFax; + + @SerializedName("contact:phone") + private String contactPhone; + + @SerializedName("contact:website") + private String contactWebsite; + + public String getSport() { + return sport; + } + + public String getOpening_hours() { + return opening_hours; + } + + public String getContactFax() { + return contactFax; + } + + public String getContactPhone() { + return contactPhone; + } + + public String getContactWebsite() { + return contactWebsite; + } +} diff --git a/app/src/main/java/com/truchsess/send2car/geo/entity/NameDetails.java b/app/src/main/java/com/truchsess/send2car/geo/entity/NameDetails.java new file mode 100644 index 0000000..3e44a0a --- /dev/null +++ b/app/src/main/java/com/truchsess/send2car/geo/entity/NameDetails.java @@ -0,0 +1,26 @@ +package com.truchsess.send2car.geo.entity; + +/********************************************************************************************** + Copyright (C) 2018 Norbert Truchsess norbert.truchsess@t-online.de + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + **********************************************************************************************/ +public class NameDetails { + + private String name; + + public String getName() { + return name; + } +} diff --git a/app/src/main/java/com/truchsess/send2car/geo/entity/Place.java b/app/src/main/java/com/truchsess/send2car/geo/entity/Place.java new file mode 100644 index 0000000..ddf12c2 --- /dev/null +++ b/app/src/main/java/com/truchsess/send2car/geo/entity/Place.java @@ -0,0 +1,130 @@ +package com.truchsess.send2car.geo.entity; + +import java.util.List; + +/********************************************************************************************** + Copyright (C) 2018 Norbert Truchsess norbert.truchsess@t-online.de + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + **********************************************************************************************/ +public class Place { + + private String error; + + private long place_id; + + private String licence; + + private String osm_type; + + private long osm_id; + + private double lat; + + private double lon; + + private int place_rank; + + private String category; + + private String type; + + private double importance; + + private String addresstype; + + private String name; + + private String display_name; + + private Address address; + + private List boundingbox; + + private NameDetails namedetails; + + private ExtraTags extratags; + + public String getError() { + return error; + } + + public long getPlace_id() { + return place_id; + } + + public String getLicence() { + return licence; + } + + public String getOsm_type() { + return osm_type; + } + + public long getOsm_id() { + return osm_id; + } + + public double getLat() { + return lat; + } + + public double getLon() { + return lon; + } + + public int getPlace_rank() { + return place_rank; + } + + public String getCategory() { + return category; + } + + public String getType() { + return type; + } + + public double getImportance() { + return importance; + } + + public String getAddresstype() { + return addresstype; + } + + public String getName() { + return name; + } + + public String getDisplay_name() { + return display_name; + } + + public Address getAddress() { + return address; + } + + public List getBoundingbox() { + return boundingbox; + } + + public NameDetails getNamedetails() { + return namedetails; + } + + public ExtraTags getExtratags() { + return extratags; + } +} diff --git a/app/src/main/res/drawable-hdpi/ic_action_help.png b/app/src/main/res/drawable-hdpi/ic_action_help.png new file mode 100644 index 0000000..7df3f00 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_action_help.png differ diff --git a/app/src/main/res/drawable-hdpi/ic_action_menu_light.png b/app/src/main/res/drawable-hdpi/ic_action_menu_light.png new file mode 100644 index 0000000..ddb4dcc Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_action_menu_light.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_action_help.png b/app/src/main/res/drawable-mdpi/ic_action_help.png new file mode 100644 index 0000000..687f5f8 Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_action_help.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_action_menu_light.png b/app/src/main/res/drawable-mdpi/ic_action_menu_light.png new file mode 100644 index 0000000..b07955b Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_action_menu_light.png differ diff --git a/app/src/main/res/drawable-v21/ic_launcher_background.xml b/app/src/main/res/drawable-v21/ic_launcher_background.xml new file mode 100644 index 0000000..d5fccc5 --- /dev/null +++ b/app/src/main/res/drawable-v21/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable-v21/ic_launcher_foreground.xml b/app/src/main/res/drawable-v21/ic_launcher_foreground.xml new file mode 100644 index 0000000..c7bd21d --- /dev/null +++ b/app/src/main/res/drawable-v21/ic_launcher_foreground.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + diff --git a/app/src/main/res/drawable-v21/ic_menu_camera.xml b/app/src/main/res/drawable-v21/ic_menu_camera.xml new file mode 100644 index 0000000..0d9ea10 --- /dev/null +++ b/app/src/main/res/drawable-v21/ic_menu_camera.xml @@ -0,0 +1,12 @@ + + + + diff --git a/app/src/main/res/drawable-v21/ic_menu_gallery.xml b/app/src/main/res/drawable-v21/ic_menu_gallery.xml new file mode 100644 index 0000000..f6872c4 --- /dev/null +++ b/app/src/main/res/drawable-v21/ic_menu_gallery.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable-v21/ic_menu_manage.xml b/app/src/main/res/drawable-v21/ic_menu_manage.xml new file mode 100644 index 0000000..c1be60b --- /dev/null +++ b/app/src/main/res/drawable-v21/ic_menu_manage.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/drawable-v21/ic_menu_send.xml b/app/src/main/res/drawable-v21/ic_menu_send.xml new file mode 100644 index 0000000..00c668c --- /dev/null +++ b/app/src/main/res/drawable-v21/ic_menu_send.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable-v21/ic_menu_share.xml b/app/src/main/res/drawable-v21/ic_menu_share.xml new file mode 100644 index 0000000..a28fb9e --- /dev/null +++ b/app/src/main/res/drawable-v21/ic_menu_share.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable-v21/ic_menu_slideshow.xml b/app/src/main/res/drawable-v21/ic_menu_slideshow.xml new file mode 100644 index 0000000..209aa64 --- /dev/null +++ b/app/src/main/res/drawable-v21/ic_menu_slideshow.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable-v21/side_nav_bar.xml b/app/src/main/res/drawable-v21/side_nav_bar.xml new file mode 100644 index 0000000..6d81870 --- /dev/null +++ b/app/src/main/res/drawable-v21/side_nav_bar.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/drawable-xhdpi/ic_action_help.png b/app/src/main/res/drawable-xhdpi/ic_action_help.png new file mode 100644 index 0000000..8b27e07 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_action_help.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_action_menu_light.png b/app/src/main/res/drawable-xhdpi/ic_action_menu_light.png new file mode 100644 index 0000000..276d9b8 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_action_menu_light.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_action_help.png b/app/src/main/res/drawable-xxhdpi/ic_action_help.png new file mode 100644 index 0000000..cd7b789 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_action_help.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_action_menu_light.png b/app/src/main/res/drawable-xxhdpi/ic_action_menu_light.png new file mode 100644 index 0000000..ec25f34 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_action_menu_light.png differ diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml new file mode 100644 index 0000000..454acf1 --- /dev/null +++ b/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_geo.xml b/app/src/main/res/layout/fragment_geo.xml new file mode 100644 index 0000000..465fae8 --- /dev/null +++ b/app/src/main/res/layout/fragment_geo.xml @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +