diff --git a/OsmAnd-java/src/net/osmand/router/RouteResultPreparation.java b/OsmAnd-java/src/net/osmand/router/RouteResultPreparation.java index ea1e7d1180..bb2617b2d6 100644 --- a/OsmAnd-java/src/net/osmand/router/RouteResultPreparation.java +++ b/OsmAnd-java/src/net/osmand/router/RouteResultPreparation.java @@ -533,10 +533,7 @@ public class RouteResultPreparation { } private void assignLanesInfo(RouteSegmentResult prevSegm, TurnType t, boolean leftSide) { - int lanes = prevSegm.getObject().getLanes(); - if (prevSegm.getObject().getOneway() == 0) { - lanes = countLanes(prevSegm, lanes); - } + int lanes = countLanes(prevSegm); if (lanes <= 0) { return; } @@ -645,10 +642,7 @@ public class RouteResultPreparation { if (rsSpeakPriority != MAX_SPEAK_PRIORITY || speakPriority == MAX_SPEAK_PRIORITY) { if ((ex < TURN_DEGREE_MIN || mpi < TURN_DEGREE_MIN) && ex >= 0) { kl = true; - int lns = attached.getObject().getLanes(); - if(attached.getObject().getOneway() == 0) { - lns = countLanes(attached, lns); - } + int lns = countLanes(attached); if (lns <= 0) { right += 1; } else { @@ -657,10 +651,7 @@ public class RouteResultPreparation { speak = speak || rsSpeakPriority <= speakPriority; } else if ((ex > -TURN_DEGREE_MIN || mpi < TURN_DEGREE_MIN) && ex <= 0) { kr = true; - int lns = attached.getObject().getLanes(); - if(attached.getObject().getOneway() == 0) { - lns = countLanes(attached, lns); - } + int lns = countLanes(attached); if (lns <= 0) { left += 1; } else { @@ -679,11 +670,8 @@ public class RouteResultPreparation { } else if(kl && right == 0) { right = 1; } - int current = currentSegm.getObject().getLanes(); + int current = countLanes(currentSegm); // attachedRoutes covers all allowed outbound routes at that point except currentSegm. - if (currentSegm.getObject().getOneway() == 0) { - current = countLanes(currentSegm, current); - } if (current <= 0) { current = 1; } @@ -748,17 +736,23 @@ public class RouteResultPreparation { return t; } - protected int countLanes(RouteSegmentResult attached, int lns) { - try { - if (attached.isForwardDirection() && attached.getObject().getValue("lanes:forward") != null) { - return Integer.parseInt(attached.getObject().getValue("lanes:forward")); - } else if (!attached.isForwardDirection() && attached.getObject().getValue("lanes:backward") != null) { - return Integer.parseInt(attached.getObject().getValue("lanes:backward")); + protected int countLanes(RouteSegmentResult attached) { + if (attached.getObject().getOneway() == 0) { + try { + if (attached.isForwardDirection() && attached.getObject().getValue("lanes:forward") != null) { + return Integer.parseInt(attached.getObject().getValue("lanes:forward")); + } else if (!attached.isForwardDirection() && attached.getObject().getValue("lanes:backward") != null) { + return Integer.parseInt(attached.getObject().getValue("lanes:backward")); + } else { + return -1; + } + } catch (NumberFormatException e) { + e.printStackTrace(); + return -1; } - } catch (NumberFormatException e) { - e.printStackTrace(); + } else { + return attached.getObject().getLanes(); } - return (lns + 1) / 2; } protected String getTurnLanesString(RouteSegmentResult segment) { @@ -774,10 +768,7 @@ public class RouteResultPreparation { } private TurnType attachTurnLanesData(boolean leftSide, RouteSegmentResult prevSegm, TurnType t) { - int lanes = prevSegm.getObject().getLanes(); - if (prevSegm.getObject().getOneway() == 0) { - lanes = countLanes(prevSegm, lanes); - } + int lanes = countLanes(prevSegm); String turnLanes = getTurnLanesString(prevSegm); if (turnLanes == null) { @@ -785,19 +776,42 @@ public class RouteResultPreparation { } String[] splitLaneOptions = turnLanes.split("\\|", -1); + if (splitLaneOptions.length != lanes) { - // Error in data or missing data - return t; + log.warn("Number of lanes in lanes key (" + lanes + ") does not match number of lanes from turn:lanes key (" + splitLaneOptions.length + "). Errors may occur."); + + int leftLanes = 0; + int rightLanes = 0; + boolean processingLeft = true; + for (int i = 0; i < t.getLanes().length; i++) { + if (t.getLanes()[i] == 0) { + if (processingLeft) { + leftLanes++; + } else { + rightLanes++; + } + } else { + processingLeft = false; + } + } + + int[] adjustedLanes = new int[lanes + leftLanes + rightLanes]; + + for (int i = leftLanes; i < leftLanes + lanes; i++) { + adjustedLanes[i] = 1; + } + + t.setLanes(adjustedLanes); } if (t.getLanes().length != lanes) { - // The turn:lanes don't easily match up to the target road. + // The lanes from prevSegm don't easily match up to the target roads (it's not one-to-one). List sourceLanes = new ArrayList(); int outgoingLanesIndex = 0; int sourceLanesIndex = 0; - while (outgoingLanesIndex < t.getLanes().length && sourceLanesIndex < lanes) { + while (outgoingLanesIndex < t.getLanes().length && sourceLanesIndex < splitLaneOptions.length) { if (splitLaneOptions[sourceLanesIndex].contains(";")) { // Two or more allowed turns for this lane int options = countOccurrences(splitLaneOptions[sourceLanesIndex], ';'); diff --git a/OsmAnd/res/layout-v14/osmo_groups_list_header.xml b/OsmAnd/res/layout-v14/osmo_groups_list_header.xml index 824415d276..abf588770a 100644 --- a/OsmAnd/res/layout-v14/osmo_groups_list_header.xml +++ b/OsmAnd/res/layout-v14/osmo_groups_list_header.xml @@ -84,6 +84,7 @@ android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_marginBottom="8dip" + android:autoLink="web" android:gravity="center" android:textSize="18sp" /> diff --git a/OsmAnd/res/layout/osmo_groups_list_header.xml b/OsmAnd/res/layout/osmo_groups_list_header.xml index ae386cfa46..fef215e96b 100644 --- a/OsmAnd/res/layout/osmo_groups_list_header.xml +++ b/OsmAnd/res/layout/osmo_groups_list_header.xml @@ -84,6 +84,7 @@ android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_marginBottom="8dip" + android:autoLink="web" android:gravity="center" android:textSize="18sp" /> diff --git a/OsmAnd/res/values-ca/strings.xml b/OsmAnd/res/values-ca/strings.xml index ee919fea90..ecd64d34e3 100644 --- a/OsmAnd/res/values-ca/strings.xml +++ b/OsmAnd/res/values-ca/strings.xml @@ -1934,4 +1934,6 @@ La llista de països inclosos (bàsicament tot el món!): Afganistan, Albània, "%1$s necessita aquest permís per la funcionalitat de posar la pantalla en mode d\'estalvi d\'energia." Mai Avançat + Utilitzeu una connexió segura amb el servidor + Utilitzeu https diff --git a/OsmAnd/res/values-cs/bidforfix.xml b/OsmAnd/res/values-cs/bidforfix.xml index 73aafbb86a..66e1368382 100644 --- a/OsmAnd/res/values-cs/bidforfix.xml +++ b/OsmAnd/res/values-cs/bidforfix.xml @@ -1,6 +1,6 @@ - + Nahrávám - %1$d sponzorů + %1$d Příznivců sponzorováno: %d%% - \ No newline at end of file + diff --git a/OsmAnd/res/values-cs/phrases.xml b/OsmAnd/res/values-cs/phrases.xml index 8632366dcb..4750b73d87 100644 --- a/OsmAnd/res/values-cs/phrases.xml +++ b/OsmAnd/res/values-cs/phrases.xml @@ -5,10 +5,10 @@ Obchodní dům Obchod s nápoji Masna - - - - + Delikatesy + Farmářský obchod + Zelinářství + Obchod mořskými plody Supermarket Knihkupectví @@ -23,7 +23,7 @@ Drogerie - + Dětské oblečení Obuv @@ -47,7 +47,7 @@ Hydrant Hasicí přístroj Ambulance - Ford + Brod Horské sedlo Brána Mýtné @@ -128,7 +128,7 @@ Pevnost Fontána Vrak lodi - Monument + Památník Zoo Hotel Motel @@ -194,4 +194,22 @@ Kotviště Suchý dok Přístav + Kasárna + Nebezpečná oblast + Cukrárna + Obchod čajem + Mlékárna + Prodejní automat + + Květinářství + Nábytek + Zahradní centrum + Sklenářství + Sluchové pomůcky + Obchod bylinkami + Domácí potřeby + Dekorace interiéru + Zpravodajská agentura + Kancelářské potřeby + Obchodní místo diff --git a/OsmAnd/res/values-da/phrases.xml b/OsmAnd/res/values-da/phrases.xml index 4cfde22ffc..f604fb3779 100644 --- a/OsmAnd/res/values-da/phrases.xml +++ b/OsmAnd/res/values-da/phrases.xml @@ -6,14 +6,14 @@ Butikscenter Drikkevarebutik Kødmarked - Delikatesser + Delikatesse Gårdbutik Grønthandler Fiskehandler Konfektureforretning Isbar Supermarked - Tebutik + Tehandel Mejeriudsalg Automat @@ -53,7 +53,7 @@ Høreapparater Urter HiFi - Isenkræmmer + Husholdningsartikler Jagtudstyr Boligindretning Smykkeforretning @@ -62,7 +62,7 @@ Mobiltelefoner Motorcykler Musikinstrumenter - Kiosk + Nyhedsbureau Optiker Økologiske fødevarer Fritidsbeklædning @@ -81,7 +81,7 @@ Støvsuger Fastpris butik Video - Gardinforretning + Persienner Stormagasin Elektronik Autohandel @@ -100,7 +100,7 @@ Brandslange Branddam Grusbeholder - Ambulance station + Ambulancestation SES station Nødstilfælde punkt @@ -118,7 +118,7 @@ Rumlestriber Trafikdæmpning, bord Indsnævring - Trafiksignaler + Trafiksignal Autoværksted Dækservice @@ -136,15 +136,15 @@ Offentlig transport stoppested Busstoppested Trolley busstoppested - Busstoppested + Busstoppested (forældet) Sporvognsstoppested - Sporvognsstoppestedet + Sporvognsstoppestedet (forældet) Offentlig transport station - Busstation + Busstation (forældet) Banegård (forældet) Perron (forældet) - Trinbrædt - Metro indgang + Trinbrædt (forældet) + Metroindgang Metrostation Taxaholdeplads @@ -167,7 +167,7 @@ Stolelift T-bar lift J-bar lift - Tallerken lift + Tallerkenlift Blandet lift Træklift Reblift @@ -189,7 +189,7 @@ Sluseport Vendepunkt på vandet Stemmeværk - Dam + Dæmning Vandmølle Transformerstation @@ -200,7 +200,7 @@ Posthus Postkasse Telefon - Kommunikation tårn + Kommunikationstårn Telefoncentral Genbrugsplads @@ -214,7 +214,7 @@ Mineskakt Stoll Oliebrønd - Undersøgelses punkt + Trianguleringspunkt Vindmølle Stenbrud Vingård @@ -235,7 +235,7 @@ Ambassade Regering Foged - Anklagemyndighed + Anklager Pensionskasse Migration Skattekontrol @@ -309,7 +309,7 @@ Kroket Cykling Dykning - Dykning + Scuba dykning Hundevæddeløb Hestesport Golf @@ -329,10 +329,10 @@ Ketsjer Rulleskøjteløb Roning - Rugby - Rugby + Rugby union + Rugby league Skydning - Skøjteløb + Skating Skateboard Skiløb Fodbold @@ -346,7 +346,7 @@ Turistattraktion Mindesmærke Kunstværk - Arkæologiske område + Arkæologisk område Slagmark Grænsesten Slot @@ -387,7 +387,7 @@ Rejsebureau Udsigtspunkt Campingplads - campingvognsplads + Campingvognsplads Skovtur/rasteplads Kilde Kirkegård @@ -408,7 +408,7 @@ Filmklub Fanklub Lystfiskerklub - Veteranklub + Veteranforening Linux klub Teaterklub Historieklub @@ -417,7 +417,7 @@ Naturklub Fotoklub Jagtklub - Skytteforeningen + Skytteforening Turistklub Velgørenhedsklub @@ -493,10 +493,10 @@ Skomager Udstillingsbygger Stenhugger - Solbeskyttelse håndværk + Solafskærmning håndværk Skorstensfejer Skrædder - Tagdækker + Fliselægger Blikkenslager Møbelpolstrer Urmager @@ -598,4 +598,27 @@ Militærsøvelsesområde Militærflådebase Nuklear eksplosion område - +Storby + By + Landsby + Lille landsby + Bebyggelse + Forstad + Kvarter + Lokalitet + + Alternativ medicin + Audiolog + Blodbank + Medicinskcenter + Jordemoder + Ergoterapeut + Optiker + Fysioterapeut + Ortopæd + Psykoterapeut + Rehabilitering + Talepædagog + Medicinsk facilitet + + diff --git a/OsmAnd/res/values-de/strings.xml b/OsmAnd/res/values-de/strings.xml index 1d93086acc..639fee967c 100644 --- a/OsmAnd/res/values-de/strings.xml +++ b/OsmAnd/res/values-de/strings.xml @@ -2013,4 +2013,5 @@ Afghanistan, Ägypten, Albanien, Algerien, Andorra, Angola, Anguilla, Antigua an Buslinien Ausblenden %1$s benötigt diese Berechtigung, um den Bildschirm auszuschalten (Energiesparfunktion). + Erweitert diff --git a/OsmAnd/res/values-fr/strings.xml b/OsmAnd/res/values-fr/strings.xml index a3ad68e2a3..6e72ca3260 100644 --- a/OsmAnd/res/values-fr/strings.xml +++ b/OsmAnd/res/values-fr/strings.xml @@ -1861,4 +1861,6 @@ Afghanistan, Albanie, Algérie, Allemagne, Andorre, Angola, Anguilla, Antigua-et %1$s a besoin de cette permission pour éteindre l\'écran en mode économie d\'énergie. Jamais Avancé + Utiliser une connexion sécurisée avec le serveur + Utiliser https diff --git a/OsmAnd/res/values-it/phrases.xml b/OsmAnd/res/values-it/phrases.xml new file mode 100644 index 0000000000..a6b3daec93 --- /dev/null +++ b/OsmAnd/res/values-it/phrases.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/OsmAnd/res/values-nl/strings.xml b/OsmAnd/res/values-nl/strings.xml index 831f676c08..1444ba37ef 100644 --- a/OsmAnd/res/values-nl/strings.xml +++ b/OsmAnd/res/values-nl/strings.xml @@ -1953,7 +1953,7 @@ Afghanistan, Albanie, Algerije, Andorra, Angola, Anguilla, Antigua en Barbuda, A Track maken in GPX-bestand Het registreren van de afgelegde weg in een GPX-bestand kan worden aan- en uitgeschakeld met een knop op het kaartscherm Interval tussen geregistreerde punten - Bus-, trolleybus- en minibuslijnen + Bus-, trolleybus- en pendelbuslijnen Altijd vragen Selecteer de loggings-interval voor de standaard track opname (te starten via de GPX opname widget in het scherm) Standaard loggings-interval @@ -1994,7 +1994,7 @@ Afghanistan, Albanie, Algerije, Andorra, Angola, Anguilla, Antigua en Barbuda, A "Aanpassingen in 1.9: * Verbeterde kaart stijlen met weg-weergave, vervoerslaag en wandelsymbolen * Zoek bezienswaardigheden langs de route * Markeer per route, een weg als onbegaanbaar * Eenvoudiger downloaden en updaten van kaarten * Krijg visuele- en geluidsmelding bij het naderen van een Routepunt * Print reisroute en routebeschrijving * Ondersteuning van voorsorteervakken * Ondersteuning van Android Wear * Veel gebruikersinterface-verbeteringen * Aparte zoomfunctie voor de tekstgrootte op de kaart * Speciale audio meldingen in het geval dat u afwijkt van de route * OsMo inlog functionaliteit * Oplossing van OsMo versie incompatibiliteit " Routes Details - Trein en lightrail lijnen + Trein verbindingen Tramlijnen Deeltaxi routes Trolleybus lijnen @@ -2006,5 +2006,6 @@ Afghanistan, Albanie, Algerije, Andorra, Angola, Anguilla, Antigua en Barbuda, A Vermijd wegen… Verberg Nooit - %1$s heeft deze permissie nodig om het scherm uit te kunnen schakelen (stroombesparing). - + %1$s heeft toestemming nodig om het scherm uit te kunnen schakelen (als onderdeel van de stroombesparende functie). + Geavanceerd + diff --git a/OsmAnd/res/values-ru/phrases.xml b/OsmAnd/res/values-ru/phrases.xml index 44ee30092d..56dbae8e37 100644 --- a/OsmAnd/res/values-ru/phrases.xml +++ b/OsmAnd/res/values-ru/phrases.xml @@ -1,4 +1,4 @@ - + Булочная Винно-водочный магазин @@ -253,19 +253,19 @@ Бэби-бокс Ветеринарная лечебница Санаторий - Альтернативная медицина - Отоларинголог - Банк крови - Медицинский центр - Акушерка - Профессиональный врач - Оптометрист - Физиотерапевт - Ортопед - Психотерапевт - Реабилитация - Логопед - Медицинское учреждение + Альтернативная медицина + Отоларинголог + Банк крови + Медицинский центр + Акушерка + Профессиональный врач + Оптометрист + Физиотерапевт + Ортопед + Психотерапевт + Реабилитация + Логопед + Медицинское учреждение Фирма Страховая компания @@ -341,7 +341,7 @@ Плавание Пинг-понг Теннис - + Санный спорт Воллейбол Музей @@ -389,7 +389,7 @@ Турагенство Место с хорошим видом Место для лагеря - + Место для пикника Родник Кладбище @@ -551,47 +551,47 @@ Остров Остров (небольшой) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + Якорная стоянка + + Бакен + + + + + + + + + + + + + Специальный буй + + + + + + Сигнал при тумане + + Гавань + + + + + + + Причал + + + + + + + + + + Военный аэродром Военный бункер @@ -600,4 +600,11 @@ Военное стрельбище Военно-морская база Место ядерного взрыва - \ No newline at end of file +Город + Город + Деревня + Деревня + Хутор + Урочище + + diff --git a/OsmAnd/res/values-ru/strings.xml b/OsmAnd/res/values-ru/strings.xml index 566b825675..189b48ac9f 100644 --- a/OsmAnd/res/values-ru/strings.xml +++ b/OsmAnd/res/values-ru/strings.xml @@ -1,5 +1,8 @@ -Плагин позволяет загружать контурные линии и затемнение высот для использования оффлайн (\"Настройки\" → \"Управление файлами карт\" → \"Загрузить\"). + + Использовать безопасное соединение с сервером + Использовать https + Плагин позволяет загружать контурные линии и затемнение высот для использования оффлайн (\"Настройки\" → \"Управление файлами карт\" → \"Загрузить\"). Рассмотрите, пожалуйста, покупку плагина \"Линии высот\" в Google Play, чтобы поддержать последующую разработку. Линии высот Запись видео diff --git a/OsmAnd/res/values-sc/strings.xml b/OsmAnd/res/values-sc/strings.xml index e7822205ef..2a2d346abb 100644 --- a/OsmAnd/res/values-sc/strings.xml +++ b/OsmAnd/res/values-sc/strings.xml @@ -834,7 +834,7 @@ Si cussigiat de annànghere unu o prus puntos intermedios pro megiorare sas pres Ammustra sas impostaduras pro funtzionalidades ispetziales pro s\'atzessibilidade. Impostaduras avantzadas Plugins - Issèbera unu plugin pro l\'ativare o lu deativare. (Diat pòdere serbire su reaviu de OsmAnd.) + Issèbera unu plugin pro l\'ativare o lu disativare. (Diat pòdere serbire su reaviu de OsmAnd.) Sos plugins abìlitana funtzionalidades azuntivas e impostaduras avantzadas Plugins Isvilupu de OsmAnd @@ -1737,7 +1737,7 @@ Si cussigiat de annànghere unu o prus puntos intermedios pro megiorare sas pres Moderatzione de su tràficu Autovelox Avisu de tràficu - Ischerta unu elementu esistente pro bìere prus detallios, carca e mantène carcau pro lu deativare o burrare. Datos como in su dispositivu (%1$s lìberos): + Ischerta unu elementu esistente pro bìere prus detallios, carca e mantène carcau pro lu disativare o burrare. Datos como in su dispositivu (%1$s lìberos): Issèbera sa mannària de su testu in sa mapa. Mannària de su testu Amus cambiau su nùmene de su prefèrridu tuo a %1$s pro evitare nùmenes dòpios. diff --git a/OsmAnd/res/values/phrases.xml b/OsmAnd/res/values/phrases.xml index c386f0b8de..e635954968 100644 --- a/OsmAnd/res/values/phrases.xml +++ b/OsmAnd/res/values/phrases.xml @@ -241,6 +241,14 @@ Tax inspection Administrative office Customs + City + Town + Village + Hamlet + Isolated dwelling + Suburb + Neighbourhood + Locality Pharmacy Hospital @@ -252,19 +260,19 @@ Baby hatch Veterinary Sanatorium - - Audiologist - Blood bank - - Midwife - Occupational therapist - Optometrist - Physiotherapist - Podiatrist - Psychotherapist - Rehabilitation - Speech therapist - + Alternative medicine + Audiologist + Blood bank + Medical center + Midwife + Occupational therapist + Optometrist + Physiotherapist + Podiatrist + Psychotherapist + Rehabilitation + Speech therapist + Medical facility Company Insurance diff --git a/OsmAnd/res/values/strings.xml b/OsmAnd/res/values/strings.xml index d21474157e..47fee71aaf 100644 --- a/OsmAnd/res/values/strings.xml +++ b/OsmAnd/res/values/strings.xml @@ -9,6 +9,8 @@ 3. All your modified/created strings are in the top of the file (to make easier find what\'s translated). PLEASE: Have a look at http://code.google.com/p/osmand/wiki/UIConsistency, it may really improve your and our work :-) Thx - Hardy --> + Use secure connection with server + Use https Advanced Bus, trolleybus, shuttle routes Tram and train routes diff --git a/OsmAnd/src/net/osmand/core/android/GLActivity.java b/OsmAnd/src/net/osmand/core/android/GLActivity.java index fd588dd5fb..2f1bb121d1 100644 --- a/OsmAnd/src/net/osmand/core/android/GLActivity.java +++ b/OsmAnd/src/net/osmand/core/android/GLActivity.java @@ -158,7 +158,7 @@ public class GLActivity extends Activity { // Get device display density factor DisplayMetrics displayMetrics = new DisplayMetrics(); getWindowManager().getDefaultDisplay().getMetrics(displayMetrics); - _displayDensityFactor = displayMetrics.densityDpi / 160.0f; + _displayDensityFactor = displayMetrics.density; _referenceTileSize = (int)(256 * _displayDensityFactor); _rasterTileSize = Integer.highestOneBit(_referenceTileSize - 1) * 2; Log.i(TAG, "displayDensityFactor = " + _displayDensityFactor); diff --git a/OsmAnd/src/net/osmand/plus/OsmandSettings.java b/OsmAnd/src/net/osmand/plus/OsmandSettings.java index adc197559e..9c3a093c19 100644 --- a/OsmAnd/src/net/osmand/plus/OsmandSettings.java +++ b/OsmAnd/src/net/osmand/plus/OsmandSettings.java @@ -57,6 +57,8 @@ public class OsmandSettings { void addListener(StateChangedListener listener); void removeListener(StateChangedListener listener); + + boolean isSet(); } private abstract class PreferenceWithListener implements OsmandPreference { @@ -168,6 +170,11 @@ public class OsmandSettings { set(ApplicationMode.DEFAULT); }; + @Override + public boolean isSet() { + return true; + }; + @Override public boolean set(ApplicationMode val) { ApplicationMode oldMode = currentMode; @@ -875,6 +882,9 @@ public class OsmandSettings { public final OsmandPreference OSMO_AUTO_CONNECT = new BooleanPreference("osmo_automatically_connect", false).makeGlobal(); + public final CommonPreference OSMO_USE_HTTPS = new BooleanPreference("osmo_use_https", + Build.VERSION.SDK_INT < 14/*Build.VERSION_CODES.ICE_CREAM_SANDWICH*/? false : true).makeGlobal(); + public final OsmandPreference OSMO_LAST_PING = new LongPreference("osmo_last_ping", 0).makeGlobal().cache(); public final OsmandPreference OSMO_AUTO_SEND_LOCATIONS = new BooleanPreference("osmo_automatically_send_locations", false).makeGlobal(); diff --git a/OsmAnd/src/net/osmand/plus/download/LocalIndexesFragment.java b/OsmAnd/src/net/osmand/plus/download/LocalIndexesFragment.java index 3c2577d861..2921f99cc9 100644 --- a/OsmAnd/src/net/osmand/plus/download/LocalIndexesFragment.java +++ b/OsmAnd/src/net/osmand/plus/download/LocalIndexesFragment.java @@ -477,6 +477,7 @@ public class LocalIndexesFragment extends OsmandExpandableListFragment { listAdapter.addLocalIndexInfo(info); } listAdapter.sortData(); + getExpandableListView().setAdapter(listAdapter); } ActionBar actionBar = getDownloadActivity().getSupportActionBar(); //hide action bar from downloadindexfragment diff --git a/OsmAnd/src/net/osmand/plus/osmo/OsMoControlDevice.java b/OsmAnd/src/net/osmand/plus/osmo/OsMoControlDevice.java index 882a55cd21..3d2b6215db 100644 --- a/OsmAnd/src/net/osmand/plus/osmo/OsMoControlDevice.java +++ b/OsmAnd/src/net/osmand/plus/osmo/OsMoControlDevice.java @@ -33,7 +33,6 @@ public class OsMoControlDevice implements OsMoReactor { this.plugin = plugin; this.service = service; this.tracker = tracker; - service.registerReactor(this); } public JSONObject getBatteryLevel() throws JSONException { diff --git a/OsmAnd/src/net/osmand/plus/osmo/OsMoGroups.java b/OsmAnd/src/net/osmand/plus/osmo/OsMoGroups.java index 878e9a7dd5..986807c434 100644 --- a/OsmAnd/src/net/osmand/plus/osmo/OsMoGroups.java +++ b/OsmAnd/src/net/osmand/plus/osmo/OsMoGroups.java @@ -26,6 +26,7 @@ import android.text.TextUtils; public class OsMoGroups implements OsMoReactor, OsmoTrackerListener { private static final String GROUP_NAME = "name"; + private static final String ACTIVE = "active"; private static final String GROUP_ID = "group_id"; private static final String EXPIRE_TIME = "expireTime"; private static final String DESCRIPTION = "description"; @@ -250,14 +251,14 @@ public class OsMoGroups implements OsMoReactor, OsmoTrackerListener { JSONArray arr = new JSONArray(data); int arrLength = arr.length(); if (arrLength > 0) { - Map resivedGroups = new HashMap(); + Map receivedGroups = new HashMap(); for (int i = 0; i < arrLength; i++) { JSONObject o = arr.getJSONObject(i); OsMoGroup parsedGroup = parseGroup(o); - resivedGroups.put(parsedGroup.getGroupId(), parsedGroup); + receivedGroups.put(parsedGroup.getGroupId(), parsedGroup); } - storage.mergeGroups(resivedGroups); + storage.mergeGroups(receivedGroups); storage.save(); } processed = true; @@ -287,6 +288,9 @@ public class OsMoGroups implements OsMoReactor, OsmoTrackerListener { if (!mid.equals(trackerId)) { if (toDelete.contains(trackerId)) { toDelete.remove(trackerId); + OsMoDevice dv = mainGroup.users.get(trackerId); + dv.serverColor = device.userColor; + dv.serverName = device.userName; } else { mainGroup.users.put(trackerId, device); } @@ -357,7 +361,8 @@ public class OsMoGroups implements OsMoReactor, OsmoTrackerListener { private OsMoGroup parseGroup(JSONObject obj) throws JSONException { OsMoGroup groupe = new OsMoGroup(); - groupe.enabled = true; + groupe.enabled = !(obj.has(ACTIVE) && ("0".equals(obj.getString(ACTIVE)) || + "false".equals(obj.getString(ACTIVE)))); groupe.name = obj.optString(GROUP_NAME); groupe.groupId = obj.getString(GROUP_ID); groupe.description = obj.optString(DESCRIPTION); @@ -478,7 +483,9 @@ public class OsMoGroups implements OsMoReactor, OsmoTrackerListener { } points.add(pt); } - plugin.getSaveGpxTask(gr.groupId + "_points", modify).execute(points.toArray(new WptPt[points.size()])); + if(points.size() > 0) { + plugin.getSaveGpxTask(gr.name + " points", modify, false).execute(points.toArray(new WptPt[points.size()])); + } } if(deleteUsers) { for(OsMoDevice s : toDelete.values()) { diff --git a/OsmAnd/src/net/osmand/plus/osmo/OsMoGroupsActivity.java b/OsmAnd/src/net/osmand/plus/osmo/OsMoGroupsActivity.java index b4beb259bb..c6bfa0e484 100644 --- a/OsmAnd/src/net/osmand/plus/osmo/OsMoGroupsActivity.java +++ b/OsmAnd/src/net/osmand/plus/osmo/OsMoGroupsActivity.java @@ -241,8 +241,11 @@ public class OsMoGroupsActivity extends OsmandExpandableListActivity implements mtd.setVisibility(visible? View.VISIBLE:View.GONE); if(visible) { mtd.setText(si.motd); + mtd.setLinksClickable(true); + mtd.setMovementMethod(LinkMovementMethod.getInstance()); } + CompoundButton login = (CompoundButton) header.findViewById(R.id.osmo_login_logoff); login.setChecked(osMoPlugin.getService().isLoggedIn()); login.setOnCheckedChangeListener(new LoginOnCheckedChangeListener()); diff --git a/OsmAnd/src/net/osmand/plus/osmo/OsMoGroupsStorage.java b/OsmAnd/src/net/osmand/plus/osmo/OsMoGroupsStorage.java index 891b76a5c9..1262bd3f6f 100644 --- a/OsmAnd/src/net/osmand/plus/osmo/OsMoGroupsStorage.java +++ b/OsmAnd/src/net/osmand/plus/osmo/OsMoGroupsStorage.java @@ -1,10 +1,8 @@ package net.osmand.plus.osmo; -import java.security.acl.Group; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; -import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; diff --git a/OsmAnd/src/net/osmand/plus/osmo/OsMoPlugin.java b/OsmAnd/src/net/osmand/plus/osmo/OsMoPlugin.java index f43f1fe9e0..7d86e32d1d 100644 --- a/OsmAnd/src/net/osmand/plus/osmo/OsMoPlugin.java +++ b/OsmAnd/src/net/osmand/plus/osmo/OsMoPlugin.java @@ -62,17 +62,18 @@ public class OsMoPlugin extends OsmandPlugin implements MonitoringInfoControlSer private OsMoPositionLayer olayer; protected MapActivity mapActivity; protected OsMoGroupsActivity groupsActivity; + protected OsMoControlDevice deviceControl; private final static Log log = PlatformUtil.getLog(OsMoPlugin.class); public OsMoPlugin(final OsmandApplication app) { + this.app = app; service = new OsMoService(app, this); tracker = new OsMoTracker(service, app.getSettings().OSMO_SAVE_TRACK_INTERVAL, app.getSettings().OSMO_AUTO_SEND_LOCATIONS); - new OsMoControlDevice(app, this, service, tracker); + deviceControl = new OsMoControlDevice(app, this, service, tracker); groups = new OsMoGroups(this, service, tracker, app); - this.app = app; ApplicationMode.regWidget("osmo_control", (ApplicationMode[])null); } @@ -85,6 +86,7 @@ public class OsMoPlugin extends OsmandPlugin implements MonitoringInfoControlSer return true; } + public OsMoGroupsActivity getGroupsActivity() { return groupsActivity; } @@ -229,8 +231,17 @@ public class OsMoPlugin extends OsmandPlugin implements MonitoringInfoControlSer if (si != null) { String uname = si.username; if (uname != null && uname.length() > 0) { - if (uname.length() > 7 && uname.indexOf(' ') != -1) { - uname = uname.substring(0, uname.indexOf(' ')); + if (uname.length() > 7) { + for(int k = 4; k < uname.length(); k++) { + if(!Character.isLetterOrDigit(uname.charAt(k)) && + uname.charAt(k) != '.' && uname.charAt(k) != '-') { + uname = uname.substring(0, k); + break; + } + } + if(uname.length() > 12) { + uname = uname.substring(0, 12); + } } if (uname.length() > 4) { txt = ""; @@ -350,11 +361,11 @@ public class OsMoPlugin extends OsmandPlugin implements MonitoringInfoControlSer return service; } - public AsyncTask getSaveGpxTask(final String name, final long timestamp) { + public AsyncTask getSaveGpxTask(final String name, final long timestamp, final boolean generateToast) { return new AsyncTask() { protected void onProgressUpdate(String... values) { - if (values != null) { + if (values != null && generateToast) { String t = ""; for (String s : values) { t += s + "\n"; @@ -381,7 +392,9 @@ public class OsMoPlugin extends OsmandPlugin implements MonitoringInfoControlSer if (errors == null) { errors = ""; } - publishProgress(app.getString(R.string.osmo_gpx_points_downloaded, name)); + if(generateToast) { + publishProgress(app.getString(R.string.osmo_gpx_points_downloaded, name)); + } } SelectedGpxFile byPath = app.getSelectedGpxHelper().getSelectedFileByPath(ps.getAbsolutePath()); if (byPath == null || changed) { @@ -396,7 +409,7 @@ public class OsMoPlugin extends OsmandPlugin implements MonitoringInfoControlSer @Override protected void onPostExecute(String result) { - if (result.length() > 0) { + if (result.length() > 0 && generateToast) { app.showToastMessage(app.getString(R.string.osmo_io_error) + result); } } @@ -525,4 +538,8 @@ public class OsMoPlugin extends OsmandPlugin implements MonitoringInfoControlSer } } + public boolean useHttps() { + return app.getSettings().OSMO_USE_HTTPS.get(); + } + } diff --git a/OsmAnd/src/net/osmand/plus/osmo/OsMoPositionLayer.java b/OsmAnd/src/net/osmand/plus/osmo/OsMoPositionLayer.java index e905d252af..da6be7c06c 100644 --- a/OsmAnd/src/net/osmand/plus/osmo/OsMoPositionLayer.java +++ b/OsmAnd/src/net/osmand/plus/osmo/OsMoPositionLayer.java @@ -8,7 +8,6 @@ import java.util.concurrent.ConcurrentLinkedQueue; import net.osmand.Location; import net.osmand.access.AccessibleToast; -import net.osmand.core.jni.ColorARGB; import net.osmand.data.LatLon; import net.osmand.data.RotatedTileBox; import net.osmand.plus.OsmAndFormatter; @@ -294,6 +293,7 @@ public class OsMoPositionLayer extends OsmandMapLayer implements ContextMenuLaye private static String followTrackerId; private static LatLon followMapLocation; private static String followDestinationId; + private static LatLon followTargetLocation; public static void setFollowTrackerId(OsMoDevice d) { if(d != null) { @@ -322,17 +322,29 @@ public class OsMoPositionLayer extends OsmandMapLayer implements ContextMenuLaye Location l = device.getLastLocation(); if(sameDestId && l != null) { TargetPointsHelper targets = map.getMyApplication().getTargetPointsHelper(); - RoutingHelper rh = map.getMyApplication().getRoutingHelper(); - double dist = 1; - if(rh.isRouteBeingCalculated()) { - dist = 100; - } else if(rh.isRouteCalculated()) { - dist = 30; - } - LatLon lt = new LatLon(l.getLatitude(), l.getLongitude()); final TargetPoint pn = targets.getPointToNavigate(); - if(pn == null || MapUtils.getDistance(pn.point, lt) > dist) { - targets.navigateToPoint(lt, true, -1); + LatLon lt = new LatLon(l.getLatitude(), l.getLongitude()); + boolean cancelDestinationId = false; + if(followTargetLocation != null ) { + if(pn == null || pn.point == null || !pn.point.equals(lt) ) { + cancelDestinationId = true; + } + } + if(cancelDestinationId) { + followTargetLocation = null; + followDestinationId = null; + } else { + RoutingHelper rh = map.getMyApplication().getRoutingHelper(); + double dist = 1; + if (rh.isRouteBeingCalculated()) { + dist = 100; + } else if (rh.isRouteCalculated()) { + dist = 30; + } + if (pn == null || MapUtils.getDistance(pn.point, lt) > dist) { + followTargetLocation = lt; + targets.navigateToPoint(lt, true, -1); + } } } diff --git a/OsmAnd/src/net/osmand/plus/osmo/OsMoService.java b/OsmAnd/src/net/osmand/plus/osmo/OsMoService.java index d94a3d65b3..245b66c7ff 100644 --- a/OsmAnd/src/net/osmand/plus/osmo/OsMoService.java +++ b/OsmAnd/src/net/osmand/plus/osmo/OsMoService.java @@ -4,11 +4,20 @@ import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; +import java.math.BigInteger; +import java.security.KeyFactory; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.PublicKey; +import java.security.interfaces.RSAPublicKey; +import java.security.spec.RSAPublicKeySpec; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.concurrent.ConcurrentLinkedQueue; +import javax.crypto.Cipher; + import net.osmand.PlatformUtil; import net.osmand.plus.OsmandApplication; import net.osmand.plus.R; @@ -45,6 +54,12 @@ import android.support.v4.app.NotificationCompat; import android.text.TextUtils; public class OsMoService implements OsMoReactor { + private static final String HTTP_API_PREPARE = "http://api.osmo.mobi/prepare"; + private static final String HTTPS_API_PREPARE = "https://api.osmo.mobi/prepare"; + private static final String HTTP_AUTH = "http://api.osmo.mobi/auth"; + private static final String HTTPS_AUTH = "https://api.osmo.mobi/auth"; + private static final boolean USE_RSA_ENCRYPTION = true; + public static final String REGENERATE_CMD = "TRACKER_REGENERATE_ID"; public static final String SIGN_IN_URL = "http://osmo.mobi/signin?key="; private OsMoThread thread; @@ -61,6 +76,7 @@ public class OsMoService implements OsMoReactor { private boolean enabled = false; private BroadcastReceiver broadcastReceiver; private Notification notification; + public final static String OSMO_REGISTER_AGAIN = "OSMO_REGISTER_AGAIN"; //$NON-NLS-1$ private final static int SIMPLE_NOTFICATION_ID = 5; @@ -170,7 +186,7 @@ public class OsMoService implements OsMoReactor { public String registerOsmoDeviceKey() throws IOException { HttpClient httpclient = new DefaultHttpClient(); - HttpPost httppost = new HttpPost("http://api.osmo.mobi/auth"); + HttpPost httppost = new HttpPost(plugin.useHttps()? HTTPS_AUTH : HTTP_AUTH); try { // Add your data List nameValuePairs = new ArrayList(2); @@ -209,6 +225,7 @@ public class OsMoService implements OsMoReactor { public String token; public String uid; public String username; + // after auth public String protocol = ""; public String groupTrackerId; @@ -217,6 +234,8 @@ public class OsMoService implements OsMoReactor { public long motdTimestamp; public String motd = ""; + public Cipher clientEncCypher; + public Cipher clientDecCypher; } public SessionInfo getCurrentSessionInfo() { @@ -258,12 +277,33 @@ public class OsMoService implements OsMoReactor { deviceKey = registerOsmoDeviceKey(); } HttpClient httpclient = new DefaultHttpClient(); - HttpPost httppost = new HttpPost("http://api.osmo.mobi/prepare"); + KeyPair getMsgPair = null; + if (plugin.useHttps() && USE_RSA_ENCRYPTION) { + try { + KeyPairGenerator rsaGen = KeyPairGenerator.getInstance("RSA"); + getMsgPair = rsaGen.generateKeyPair(); + } catch (Exception e1) { + if (thread != null) { + thread.exc("Private key can't be generated", e1); + } else { + e1.printStackTrace(); + } + } + } + HttpPost httppost = new HttpPost(plugin.useHttps()? HTTPS_API_PREPARE : HTTP_API_PREPARE); try { // Add your data List nameValuePairs = new ArrayList(2); nameValuePairs.add(new BasicNameValuePair("app", Version.getFullVersion(app))); nameValuePairs.add(new BasicNameValuePair("key", deviceKey)); + if(getMsgPair != null && getMsgPair.getPublic() instanceof RSAPublicKey) { + nameValuePairs.add(new BasicNameValuePair("encAlgorithm", "RSA")); + BigInteger modulus = ((RSAPublicKey) getMsgPair.getPublic()).getModulus(); + BigInteger pe = ((RSAPublicKey) getMsgPair.getPublic()).getPublicExponent(); + nameValuePairs.add(new BasicNameValuePair("encClientPublicKey1", modulus.toString())); + nameValuePairs.add(new BasicNameValuePair("encClientPublicKey2", pe.toString())); + } + if(app.getSettings().OSMO_USER_PWD.get() != null) { nameValuePairs.add(new BasicNameValuePair("auth", app.getSettings().OSMO_USER_PWD.get())); } @@ -304,6 +344,23 @@ public class OsMoService implements OsMoReactor { si.hostName = a.substring(0, i); si.port = a.substring(i + 1); si.token = obj.getString("token"); + try { + if(getMsgPair != null && obj.has("encServerPublicKey1")) { + si.clientEncCypher = Cipher.getInstance("RSA"); + PublicKey pk = KeyFactory.getInstance("RSA").generatePublic(new RSAPublicKeySpec(new BigInteger(obj.getString("encServerPublicKey1")), + new BigInteger(obj.getString("encServerPublicKey2")))); + si.clientEncCypher.init(Cipher.ENCRYPT_MODE, pk); + + si.clientDecCypher = Cipher.getInstance("RSA"); + si.clientDecCypher.init(Cipher.DECRYPT_MODE, getMsgPair.getPrivate()); + } + } catch (Exception e) { + if (thread != null) { + thread.exc("Error exchanging private keys", e); + } else { + e.printStackTrace(); + } + } return si; } catch (ClientProtocolException e) { throw new IOException(e); diff --git a/OsmAnd/src/net/osmand/plus/osmo/OsMoThread.java b/OsmAnd/src/net/osmand/plus/osmo/OsMoThread.java index 62dab6bd3f..b7357b3c95 100644 --- a/OsmAnd/src/net/osmand/plus/osmo/OsMoThread.java +++ b/OsmAnd/src/net/osmand/plus/osmo/OsMoThread.java @@ -17,7 +17,11 @@ import java.util.Map.Entry; import java.util.Set; import java.util.concurrent.ConcurrentLinkedQueue; +import javax.crypto.BadPaddingException; +import javax.crypto.IllegalBlockSizeException; + import net.osmand.PlatformUtil; +import net.osmand.osm.io.Base64; import net.osmand.plus.osmo.OsMoService.SessionInfo; import org.apache.commons.logging.Log; @@ -261,6 +265,15 @@ public class OsMoThread { while ((i = readCommand.indexOf('\n')) != -1) { String cmd = readCommand.substring(0, i); readCommand = readCommand.substring(i + 1); + if(sessionInfo != null && sessionInfo.clientDecCypher != null) { + try { + final byte[] inMsg = android.util.Base64.decode(cmd.getBytes(), android.util.Base64.DEFAULT); + final byte[] byts = sessionInfo.clientDecCypher.doFinal(inMsg); + cmd = new String(byts); + } catch (Exception e) { + exc("Error decrypting", e); + } + } queueOfMessages.add(cmd.replace("\\n", "\n")); } } @@ -449,15 +462,23 @@ public class OsMoThread { private String prepareCommand(String l) { StringBuilder res = new StringBuilder(l.length()); - for(int i = 0; i < l.length(); i++) { + for (int i = 0; i < l.length(); i++) { char c = l.charAt(i); - if(c == '\n' || c == '=' || c == '\\') { - res.append('\\'); + if (c == '\n' || c == '=' || c == '\\') { + res.append('\\'); } res.append(c); } - return res.toString().trim() + "=\n"; + String finalCmd = res.toString().trim(); + if(sessionInfo != null && sessionInfo.clientEncCypher != null) { + try { + finalCmd = Base64.encode(sessionInfo.clientEncCypher.doFinal(finalCmd.getBytes())); + } catch (Exception e) { + exc("Error encrypting", e); + } + } + return finalCmd + "=\n"; } public long getLastCommandTime() { diff --git a/OsmAnd/src/net/osmand/plus/osmo/SettingsOsMoActivity.java b/OsmAnd/src/net/osmand/plus/osmo/SettingsOsMoActivity.java index 9f468f6992..8db22c0dd7 100644 --- a/OsmAnd/src/net/osmand/plus/osmo/SettingsOsMoActivity.java +++ b/OsmAnd/src/net/osmand/plus/osmo/SettingsOsMoActivity.java @@ -68,6 +68,11 @@ public class SettingsOsMoActivity extends SettingsBaseActivity { showGroupNotifiations.setSummary(R.string.osmo_show_group_notifications_descr); grp.addPreference(showGroupNotifiations); + CheckBoxPreference useHttps = createCheckBoxPreference(settings.OSMO_USE_HTTPS); + useHttps.setTitle(R.string.osmo_use_https); + useHttps.setSummary(R.string.osmo_use_https_descr); + grp.addPreference(useHttps); + if (OsmandPlugin.isDevelopment()) { debugPref = new Preference(this); debugPref.setTitle(R.string.osmo_settings_debug); diff --git a/OsmAnd/src/net/osmand/plus/render/MapVectorLayer.java b/OsmAnd/src/net/osmand/plus/render/MapVectorLayer.java index 551e9d8a12..187251e86e 100644 --- a/OsmAnd/src/net/osmand/plus/render/MapVectorLayer.java +++ b/OsmAnd/src/net/osmand/plus/render/MapVectorLayer.java @@ -93,8 +93,8 @@ public class MapVectorLayer extends BaseMapLayer { if (mapRenderer != null) { // opengl renderer mapRenderer.setTarget(new PointI(tilesRect.getCenter31X(), tilesRect.getCenter31Y())); - mapRenderer.setAzimuth(tilesRect.getRotate()); - mapRenderer.setZoom((float) (tilesRect.getZoom() + tilesRect.getZoomScale() + tilesRect.getZoomAnimation())); + mapRenderer.setAzimuth(-tilesRect.getRotate()); + mapRenderer.setZoom((float) (tilesRect.getZoom() /*+ tilesRect.getZoomScale() */+ tilesRect.getZoomAnimation())); } else { if (!view.isZooming()) { if (resourceManager.updateRenderedMapNeeded(tilesRect, drawSettings)) { diff --git a/OsmAnd/src/net/osmand/plus/views/OsmandMapTileView.java b/OsmAnd/src/net/osmand/plus/views/OsmandMapTileView.java index 615e79dee6..1198067212 100644 --- a/OsmAnd/src/net/osmand/plus/views/OsmandMapTileView.java +++ b/OsmAnd/src/net/osmand/plus/views/OsmandMapTileView.java @@ -54,7 +54,6 @@ import android.view.SurfaceView; import android.view.View; import android.view.ViewParent; import android.view.WindowManager; -import android.widget.FrameLayout; import android.widget.Toast; public class OsmandMapTileView implements IMapDownloaderCallback { diff --git a/OsmAnd/src/net/osmand/plus/views/corenative/NativeQtLibrary.java b/OsmAnd/src/net/osmand/plus/views/corenative/NativeQtLibrary.java index 1fbfb61893..384e83d55b 100644 --- a/OsmAnd/src/net/osmand/plus/views/corenative/NativeQtLibrary.java +++ b/OsmAnd/src/net/osmand/plus/views/corenative/NativeQtLibrary.java @@ -117,7 +117,13 @@ public class NativeQtLibrary { // DisplayMetrics displayMetrics = new DisplayMetrics(); // act.getWindowManager().getDefaultDisplay().getMetrics(displayMetrics); DisplayMetrics displayMetrics = app.getResources().getDisplayMetrics(); - float displayDensityFactor = displayMetrics.densityDpi / 160.0f; + // TODO getSettings().getSettingsZoomScale() + Math.sqrt(Math.max(0, getDensity() - 1)) + float scaleCoefficient = displayMetrics.density; + if (Math.min(dm.widthPixels / (dm.density * 160), dm.heightPixels / (dm.density * 160)) > 2.5f) { + // large screen + scaleCoefficient *= 1.5f; + } + float displayDensityFactor = scaleCoefficient; int referenceTileSize = (int)(256 * displayDensityFactor); int rasterTileSize = Integer.highestOneBit(referenceTileSize - 1) * 2; Log.i(NATIVE_TAG, "displayDensityFactor = " + displayDensityFactor +