From b21d948ecb1b29d96ed29f0282b312578409bd69 Mon Sep 17 00:00:00 2001 From: Sam Whited Date: Sun, 11 Mar 2018 13:09:35 -0500 Subject: [PATCH] Merge Open Street Map plugin --- art/marker.svg | 110 ++++++ art/render.rb | 1 + build.gradle | 1 + src/main/AndroidManifest.xml | 29 +- .../java/eu/siacs/conversations/Config.java | 16 +- .../conversations/ui/ActionBarActivity.java | 13 + .../conversations/ui/LocationActivity.java | 316 ++++++++++++++++++ .../ui/ShareLocationActivity.java | 247 ++++++++++++++ .../ui/ShowLocationActivity.java | 234 +++++++++++++ .../conversations/ui/UriHandlerActivity.java | 2 +- .../siacs/conversations/ui/XmppActivity.java | 15 +- .../conversations/ui/util/LocationHelper.java | 72 ++++ .../conversations/ui/util/UriHelper.java | 30 ++ .../siacs/conversations/ui/widget/Marker.java | 52 +++ .../conversations/ui/widget/MyLocation.java | 65 ++++ .../ic_directions_black_24dp.png | Bin 0 -> 233 bytes .../ic_directions_white_24dp.png | Bin 0 -> 252 bytes .../drawable-hdpi/ic_gps_fixed_black_24dp.png | Bin 0 -> 549 bytes .../drawable-hdpi/ic_gps_fixed_white_24dp.png | Bin 0 -> 546 bytes .../ic_gps_not_fixed_black_24dp.png | Bin 0 -> 472 bytes .../ic_gps_not_fixed_white_24dp.png | Bin 0 -> 468 bytes src/main/res/drawable-hdpi/marker.png | Bin 0 -> 3591 bytes .../ic_directions_black_24dp.png | Bin 0 -> 181 bytes .../ic_directions_white_24dp.png | Bin 0 -> 191 bytes .../drawable-mdpi/ic_gps_fixed_black_24dp.png | Bin 0 -> 341 bytes .../drawable-mdpi/ic_gps_fixed_white_24dp.png | Bin 0 -> 350 bytes .../ic_gps_not_fixed_black_24dp.png | Bin 0 -> 295 bytes .../ic_gps_not_fixed_white_24dp.png | Bin 0 -> 298 bytes src/main/res/drawable-mdpi/marker.png | Bin 0 -> 2211 bytes .../ic_directions_black_24dp.png | Bin 0 -> 274 bytes .../ic_directions_white_24dp.png | Bin 0 -> 307 bytes .../ic_gps_fixed_black_24dp.png | Bin 0 -> 660 bytes .../ic_gps_fixed_white_24dp.png | Bin 0 -> 687 bytes .../ic_gps_not_fixed_black_24dp.png | Bin 0 -> 561 bytes .../ic_gps_not_fixed_white_24dp.png | Bin 0 -> 577 bytes src/main/res/drawable-xhdpi/marker.png | Bin 0 -> 4815 bytes .../ic_directions_black_24dp.png | Bin 0 -> 393 bytes .../ic_directions_white_24dp.png | Bin 0 -> 444 bytes .../ic_gps_fixed_black_24dp.png | Bin 0 -> 976 bytes .../ic_gps_fixed_white_24dp.png | Bin 0 -> 1012 bytes .../ic_gps_not_fixed_black_24dp.png | Bin 0 -> 803 bytes .../ic_gps_not_fixed_white_24dp.png | Bin 0 -> 830 bytes src/main/res/drawable-xxhdpi/marker.png | Bin 0 -> 7462 bytes .../ic_directions_black_24dp.png | Bin 0 -> 491 bytes .../ic_directions_white_24dp.png | Bin 0 -> 554 bytes .../ic_gps_fixed_black_24dp.png | Bin 0 -> 1334 bytes .../ic_gps_fixed_white_24dp.png | Bin 0 -> 1379 bytes .../ic_gps_not_fixed_black_24dp.png | Bin 0 -> 1102 bytes .../ic_gps_not_fixed_white_24dp.png | Bin 0 -> 1139 bytes src/main/res/drawable-xxxhdpi/marker.png | Bin 0 -> 9950 bytes .../res/drawable/ic_directions_black_24dp.xml | 9 + .../res/drawable/ic_gps_fixed_black_24dp.xml | 9 + .../drawable/ic_gps_not_fixed_black_24dp.xml | 9 + src/main/res/drawable/ic_place_black_24dp.xml | 9 + .../res/layout/activity_share_location.xml | 99 ++++++ .../res/layout/activity_show_location.xml | 25 ++ src/main/res/menu/menu_show_location.xml | 14 + src/main/res/values/about.xml | 3 + src/main/res/values/attrs.xml | 5 + src/main/res/values/strings.xml | 8 + src/main/res/values/themes.xml | 10 + 61 files changed, 1386 insertions(+), 17 deletions(-) create mode 100644 art/marker.svg create mode 100644 src/main/java/eu/siacs/conversations/ui/ActionBarActivity.java create mode 100644 src/main/java/eu/siacs/conversations/ui/LocationActivity.java create mode 100644 src/main/java/eu/siacs/conversations/ui/ShareLocationActivity.java create mode 100644 src/main/java/eu/siacs/conversations/ui/ShowLocationActivity.java create mode 100644 src/main/java/eu/siacs/conversations/ui/util/LocationHelper.java create mode 100644 src/main/java/eu/siacs/conversations/ui/util/UriHelper.java create mode 100644 src/main/java/eu/siacs/conversations/ui/widget/Marker.java create mode 100644 src/main/java/eu/siacs/conversations/ui/widget/MyLocation.java create mode 100644 src/main/res/drawable-hdpi/ic_directions_black_24dp.png create mode 100644 src/main/res/drawable-hdpi/ic_directions_white_24dp.png create mode 100644 src/main/res/drawable-hdpi/ic_gps_fixed_black_24dp.png create mode 100644 src/main/res/drawable-hdpi/ic_gps_fixed_white_24dp.png create mode 100644 src/main/res/drawable-hdpi/ic_gps_not_fixed_black_24dp.png create mode 100644 src/main/res/drawable-hdpi/ic_gps_not_fixed_white_24dp.png create mode 100644 src/main/res/drawable-hdpi/marker.png create mode 100644 src/main/res/drawable-mdpi/ic_directions_black_24dp.png create mode 100644 src/main/res/drawable-mdpi/ic_directions_white_24dp.png create mode 100644 src/main/res/drawable-mdpi/ic_gps_fixed_black_24dp.png create mode 100644 src/main/res/drawable-mdpi/ic_gps_fixed_white_24dp.png create mode 100644 src/main/res/drawable-mdpi/ic_gps_not_fixed_black_24dp.png create mode 100644 src/main/res/drawable-mdpi/ic_gps_not_fixed_white_24dp.png create mode 100644 src/main/res/drawable-mdpi/marker.png create mode 100644 src/main/res/drawable-xhdpi/ic_directions_black_24dp.png create mode 100644 src/main/res/drawable-xhdpi/ic_directions_white_24dp.png create mode 100644 src/main/res/drawable-xhdpi/ic_gps_fixed_black_24dp.png create mode 100644 src/main/res/drawable-xhdpi/ic_gps_fixed_white_24dp.png create mode 100644 src/main/res/drawable-xhdpi/ic_gps_not_fixed_black_24dp.png create mode 100644 src/main/res/drawable-xhdpi/ic_gps_not_fixed_white_24dp.png create mode 100644 src/main/res/drawable-xhdpi/marker.png create mode 100644 src/main/res/drawable-xxhdpi/ic_directions_black_24dp.png create mode 100644 src/main/res/drawable-xxhdpi/ic_directions_white_24dp.png create mode 100644 src/main/res/drawable-xxhdpi/ic_gps_fixed_black_24dp.png create mode 100644 src/main/res/drawable-xxhdpi/ic_gps_fixed_white_24dp.png create mode 100644 src/main/res/drawable-xxhdpi/ic_gps_not_fixed_black_24dp.png create mode 100644 src/main/res/drawable-xxhdpi/ic_gps_not_fixed_white_24dp.png create mode 100644 src/main/res/drawable-xxhdpi/marker.png create mode 100644 src/main/res/drawable-xxxhdpi/ic_directions_black_24dp.png create mode 100644 src/main/res/drawable-xxxhdpi/ic_directions_white_24dp.png create mode 100644 src/main/res/drawable-xxxhdpi/ic_gps_fixed_black_24dp.png create mode 100644 src/main/res/drawable-xxxhdpi/ic_gps_fixed_white_24dp.png create mode 100644 src/main/res/drawable-xxxhdpi/ic_gps_not_fixed_black_24dp.png create mode 100644 src/main/res/drawable-xxxhdpi/ic_gps_not_fixed_white_24dp.png create mode 100644 src/main/res/drawable-xxxhdpi/marker.png create mode 100644 src/main/res/drawable/ic_directions_black_24dp.xml create mode 100644 src/main/res/drawable/ic_gps_fixed_black_24dp.xml create mode 100644 src/main/res/drawable/ic_gps_not_fixed_black_24dp.xml create mode 100644 src/main/res/drawable/ic_place_black_24dp.xml create mode 100644 src/main/res/layout/activity_share_location.xml create mode 100644 src/main/res/layout/activity_show_location.xml create mode 100644 src/main/res/menu/menu_show_location.xml diff --git a/art/marker.svg b/art/marker.svg new file mode 100644 index 000000000..f73c1537b --- /dev/null +++ b/art/marker.svg @@ -0,0 +1,110 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + diff --git a/art/render.rb b/art/render.rb index 326311895..9513e5584 100755 --- a/art/render.rb +++ b/art/render.rb @@ -68,6 +68,7 @@ images = { 'message_bubble_sent_grey.svg' => ['message_bubble_sent_grey.9', 0], 'date_bubble_white.svg' => ['date_bubble_white.9', 0], 'date_bubble_grey.svg' => ['date_bubble_grey.9', 0], + 'marker.svg' => ['marker', 0] } # Executable paths for Mac OSX diff --git a/build.gradle b/build.gradle index aabb8f255..4a6348fa3 100644 --- a/build.gradle +++ b/build.gradle @@ -52,6 +52,7 @@ dependencies { implementation "com.wefika:flowlayout:0.4.1" implementation 'net.ypresto.androidtranscoder:android-transcoder:0.2.0' implementation 'rocks.xmpp:xmpp-addr:0.8.0-SNAPSHOT' + implementation 'org.osmdroid:osmdroid-android:6.0.1' } ext { diff --git a/src/main/AndroidManifest.xml b/src/main/AndroidManifest.xml index a191042a2..a7eaad0bc 100644 --- a/src/main/AndroidManifest.xml +++ b/src/main/AndroidManifest.xml @@ -13,6 +13,13 @@ + + + + + + + @@ -49,7 +56,27 @@ - + + + + + + + + + + + + + + + + + diff --git a/src/main/java/eu/siacs/conversations/Config.java b/src/main/java/eu/siacs/conversations/Config.java index 1a5ccef7c..e128ef358 100644 --- a/src/main/java/eu/siacs/conversations/Config.java +++ b/src/main/java/eu/siacs/conversations/Config.java @@ -2,7 +2,8 @@ package eu.siacs.conversations; import android.graphics.Bitmap; -import java.util.Arrays; +import org.osmdroid.util.GeoPoint; + import java.util.Collections; import java.util.List; @@ -10,8 +11,6 @@ import eu.siacs.conversations.xmpp.chatstate.ChatState; import rocks.xmpp.addr.Jid; public final class Config { - - private static final int UNENCRYPTED = 1; private static final int OPENPGP = 2; private static final int OTR = 4; @@ -160,4 +159,15 @@ public final class Config { private Config() { } + + public static final class Map { + public final static double INITIAL_ZOOM_LEVEL = 4; + public final static double FINAL_ZOOM_LEVEL = 15; + public final static GeoPoint INITIAL_POS = new GeoPoint(33.805278, -84.171389); + public final static int MY_LOCATION_INDICATOR_SIZE = 10; + public final static int MY_LOCATION_INDICATOR_OUTLINE_SIZE = 3; + public final static long LOCATION_FIX_TIME_DELTA = 1000 * 10; // ms + public final static float LOCATION_FIX_SPACE_DELTA = 10; // m + public final static int LOCATION_FIX_SIGNIFICANT_TIME_DELTA = 1000 * 60 * 2; // ms + } } diff --git a/src/main/java/eu/siacs/conversations/ui/ActionBarActivity.java b/src/main/java/eu/siacs/conversations/ui/ActionBarActivity.java new file mode 100644 index 000000000..72a89ab2c --- /dev/null +++ b/src/main/java/eu/siacs/conversations/ui/ActionBarActivity.java @@ -0,0 +1,13 @@ +package eu.siacs.conversations.ui; + +import android.support.v7.app.ActionBar; +import android.support.v7.app.AppCompatActivity; + +public abstract class ActionBarActivity extends AppCompatActivity { + public static void configureActionBar(ActionBar actionBar) { + if (actionBar != null) { + actionBar.setHomeButtonEnabled(true); + actionBar.setDisplayHomeAsUpEnabled(true); + } + } +} \ No newline at end of file diff --git a/src/main/java/eu/siacs/conversations/ui/LocationActivity.java b/src/main/java/eu/siacs/conversations/ui/LocationActivity.java new file mode 100644 index 000000000..cc089c00d --- /dev/null +++ b/src/main/java/eu/siacs/conversations/ui/LocationActivity.java @@ -0,0 +1,316 @@ +package eu.siacs.conversations.ui; + +import android.Manifest; +import android.annotation.TargetApi; +import android.content.Context; +import android.content.SharedPreferences; +import android.content.pm.PackageManager; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.location.Location; +import android.location.LocationListener; +import android.location.LocationManager; +import android.os.Build; +import android.os.Bundle; +import android.preference.PreferenceManager; +import android.provider.Settings; +import android.support.annotation.NonNull; +import android.text.TextUtils; +import android.util.Log; +import android.view.MenuItem; + +import org.osmdroid.api.IGeoPoint; +import org.osmdroid.api.IMapController; +import org.osmdroid.config.Configuration; +import org.osmdroid.config.IConfigurationProvider; +import org.osmdroid.tileprovider.tilesource.XYTileSource; +import org.osmdroid.util.GeoPoint; +import org.osmdroid.views.MapView; +import org.osmdroid.views.overlay.Overlay; + +import java.io.File; + +import eu.siacs.conversations.BuildConfig; +import eu.siacs.conversations.Config; +import eu.siacs.conversations.R; +import eu.siacs.conversations.ui.util.LocationHelper; +import eu.siacs.conversations.ui.widget.Marker; +import eu.siacs.conversations.ui.widget.MyLocation; + +public abstract class LocationActivity extends ActionBarActivity implements LocationListener { + protected LocationManager locationManager; + protected boolean hasLocationFeature; + + public static final int REQUEST_CODE_CREATE = 0; + public static final int REQUEST_CODE_FAB_PRESSED = 1; + public static final int REQUEST_CODE_SNACKBAR_PRESSED = 2; + + protected static final String KEY_LOCATION = "loc"; + protected static final String KEY_ZOOM_LEVEL = "zoom"; + + protected Location myLoc = null; + protected MapView map = null; + protected IMapController mapController = null; + + protected Bitmap marker_icon; + + protected void clearMarkers() { + synchronized (this.map.getOverlays()) { + for (final Overlay overlay : this.map.getOverlays()) { + if (overlay instanceof Marker || overlay instanceof MyLocation) { + this.map.getOverlays().remove(overlay); + } + } + } + } + + protected void updateLocationMarkers() { + clearMarkers(); + } + + protected XYTileSource tileSource() { + return new XYTileSource("OpenStreetMap", + 0, 19, 256, ".png", new String[] { + "https://a.tile.openstreetmap.org/", + "https://b.tile.openstreetmap.org/", + "https://c.tile.openstreetmap.org/" },"© OpenStreetMap contributors"); + } + + @Override + protected void onCreate(final Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + final Context ctx = getApplicationContext(); + + final PackageManager packageManager = ctx.getPackageManager(); + hasLocationFeature = packageManager.hasSystemFeature(PackageManager.FEATURE_LOCATION) || + packageManager.hasSystemFeature(PackageManager.FEATURE_LOCATION_GPS) || + packageManager.hasSystemFeature(PackageManager.FEATURE_LOCATION_NETWORK); + this.locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE); + this.marker_icon = BitmapFactory.decodeResource(ctx.getResources(), R.drawable.marker); + final Boolean dark = PreferenceManager.getDefaultSharedPreferences(ctx) + .getString("theme", "light").equals("dark"); + final int mTheme = dark ? R.style.ConversationsTheme_Dark : R.style.ConversationsTheme; + setTheme(mTheme); + + // Ask for location permissions if location services are enabled and we're + // just starting the activity (we don't want to keep pestering them on every + // screen rotation or if there's no point because it's disabled anyways). + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && savedInstanceState == null) { + requestPermissions(REQUEST_CODE_CREATE); + } + + final IConfigurationProvider config = Configuration.getInstance(); + config.load(ctx, getPreferences()); + config.setUserAgentValue(BuildConfig.APPLICATION_ID + "_" + BuildConfig.VERSION_CODE); + + final File f = new File(ctx.getCacheDir() + "/tiles"); + try { + //noinspection ResultOfMethodCallIgnored + f.mkdirs(); + } catch (final SecurityException ignored) { + } + if (f.exists() && f.isDirectory() && f.canRead() && f.canWrite()) { + Log.d(Config.LOGTAG, "Using tile cache at: " + f.getAbsolutePath()); + config.setOsmdroidTileCache(f.getAbsoluteFile()); + } + } + + @Override + protected void onSaveInstanceState(@NonNull final Bundle outState) { + super.onSaveInstanceState(outState); + + final IGeoPoint center = map.getMapCenter(); + outState.putParcelable(KEY_LOCATION, new GeoPoint( + center.getLatitude(), + center.getLongitude() + )); + outState.putDouble(KEY_ZOOM_LEVEL, map.getZoomLevelDouble()); + } + + @Override + protected void onRestoreInstanceState(@NonNull final Bundle savedInstanceState) { + super.onRestoreInstanceState(savedInstanceState); + + if (savedInstanceState.containsKey(KEY_LOCATION)) { + mapController.setCenter(savedInstanceState.getParcelable(KEY_LOCATION)); + } + if (savedInstanceState.containsKey(KEY_ZOOM_LEVEL)) { + mapController.setZoom(savedInstanceState.getDouble(KEY_ZOOM_LEVEL)); + } + } + + protected void setupMapView(final GeoPoint pos) { + // Get map view and configure it. + map = findViewById(R.id.map); + map.setTileSource(tileSource()); + map.setBuiltInZoomControls(false); + map.setMultiTouchControls(true); + map.setTilesScaledToDpi(getPreferences().getBoolean("scale_tiles_for_high_dpi", false)); + mapController = map.getController(); + mapController.setZoom(Config.Map.INITIAL_ZOOM_LEVEL); + mapController.setCenter(pos); + } + + protected void gotoLoc() { + gotoLoc(map.getZoomLevelDouble() == Config.Map.INITIAL_ZOOM_LEVEL); + } + + protected abstract void gotoLoc(final boolean setZoomLevel); + + protected abstract void setMyLoc(final Location location); + + protected void requestLocationUpdates() { + if (!hasLocationFeature || locationManager == null) { + return; + } + + Log.d(Config.LOGTAG, "Requesting location updates..."); + final Location lastKnownLocationGps; + final Location lastKnownLocationNetwork; + + try { + if (locationManager.getAllProviders().contains(LocationManager.GPS_PROVIDER)) { + lastKnownLocationGps = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER); + + if (lastKnownLocationGps != null) { + setMyLoc(lastKnownLocationGps); + } + locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, Config.Map.LOCATION_FIX_TIME_DELTA, + Config.Map.LOCATION_FIX_SPACE_DELTA, this); + } else { + lastKnownLocationGps = null; + } + + if (locationManager.getAllProviders().contains(LocationManager.NETWORK_PROVIDER)) { + lastKnownLocationNetwork = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER); + if (lastKnownLocationNetwork != null && LocationHelper.isBetterLocation(lastKnownLocationNetwork, + lastKnownLocationGps)) { + setMyLoc(lastKnownLocationNetwork); + } + locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, Config.Map.LOCATION_FIX_TIME_DELTA, + Config.Map.LOCATION_FIX_SPACE_DELTA, this); + } + + // If something else is also querying for location more frequently than we are, the battery is already being + // drained. Go ahead and use the existing locations as often as we can get them. + if (locationManager.getAllProviders().contains(LocationManager.PASSIVE_PROVIDER)) { + locationManager.requestLocationUpdates(LocationManager.PASSIVE_PROVIDER, 0, 0, this); + } + } catch (final SecurityException ignored) { + // Do nothing if the users device has no location providers. + } + } + + protected void pauseLocationUpdates() throws SecurityException { + if (locationManager != null) { + locationManager.removeUpdates(this); + } + } + + @Override + public boolean onOptionsItemSelected(final MenuItem item) { + switch (item.getItemId()) { + case android.R.id.home: + finish(); + return true; + } + return super.onOptionsItemSelected(item); + } + + @Override + protected void onPause() { + super.onPause(); + Configuration.getInstance().save(this, getPreferences()); + map.onPause(); + try { + pauseLocationUpdates(); + } catch (final SecurityException ignored) { + } + } + + protected abstract void updateUi(); + + protected boolean mapAtInitialLoc() { + return map.getZoomLevelDouble() == Config.Map.INITIAL_ZOOM_LEVEL; + } + + @Override + protected void onResume() { + super.onResume(); + Configuration.getInstance().load(this, getPreferences()); + map.onResume(); + this.setMyLoc(null); + requestLocationUpdates(); + updateLocationMarkers(); + updateUi(); + map.setTileSource(tileSource()); + map.setTilesScaledToDpi(getPreferences().getBoolean("scale_tiles_for_high_dpi", false)); + + if (mapAtInitialLoc()) { + gotoLoc(); + } + } + + @TargetApi(Build.VERSION_CODES.M) + protected boolean hasLocationPermissions() { + return (checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED || + checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED); + } + + @TargetApi(Build.VERSION_CODES.M) + protected void requestPermissions(final int request_code) { + if (!hasLocationPermissions()) { + requestPermissions( + new String[]{ + Manifest.permission.ACCESS_FINE_LOCATION, + Manifest.permission.ACCESS_COARSE_LOCATION, + }, + request_code + ); + } + } + + @Override + public void onRequestPermissionsResult(final int requestCode, + @NonNull final String[] permissions, + @NonNull final int[] grantResults) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + for (int i = 0; i < grantResults.length; i++) { + if (Manifest.permission.ACCESS_FINE_LOCATION.equals(permissions[i]) || + Manifest.permission.ACCESS_COARSE_LOCATION.equals(permissions[i])) { + if (grantResults[i] == PackageManager.PERMISSION_GRANTED) { + requestLocationUpdates(); + } + } + } + } + + protected SharedPreferences getPreferences() { + return PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); + } + + @TargetApi(Build.VERSION_CODES.KITKAT) + private boolean isLocationEnabledKitkat() { + try { + final int locationMode = Settings.Secure.getInt(getContentResolver(), Settings.Secure.LOCATION_MODE); + return locationMode != Settings.Secure.LOCATION_MODE_OFF; + } catch( final Settings.SettingNotFoundException e ){ + return false; + } + } + + @SuppressWarnings("deprecation") + private boolean isLocationEnabledLegacy() { + final String locationProviders = Settings.Secure.getString(getContentResolver(), + Settings.Secure.LOCATION_PROVIDERS_ALLOWED); + return !TextUtils.isEmpty(locationProviders); + } + + protected boolean isLocationEnabled() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + return isLocationEnabledKitkat(); + } else { + return isLocationEnabledLegacy(); + } + } +} diff --git a/src/main/java/eu/siacs/conversations/ui/ShareLocationActivity.java b/src/main/java/eu/siacs/conversations/ui/ShareLocationActivity.java new file mode 100644 index 000000000..7f970a2a0 --- /dev/null +++ b/src/main/java/eu/siacs/conversations/ui/ShareLocationActivity.java @@ -0,0 +1,247 @@ +package eu.siacs.conversations.ui; + +import android.Manifest; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.location.Location; +import android.location.LocationListener; +import android.os.Build; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.design.widget.FloatingActionButton; +import android.view.View; +import android.widget.Button; +import android.widget.RelativeLayout; +import android.widget.TextView; + +import org.osmdroid.api.IGeoPoint; +import org.osmdroid.util.GeoPoint; + +import eu.siacs.conversations.Config; +import eu.siacs.conversations.R; +import eu.siacs.conversations.ui.util.LocationHelper; +import eu.siacs.conversations.ui.widget.Marker; +import eu.siacs.conversations.ui.widget.MyLocation; + +public class ShareLocationActivity extends LocationActivity implements LocationListener { + + private RelativeLayout snackBar; + private boolean marker_fixed_to_loc = false; + private static final String KEY_FIXED_TO_LOC = "fixed_to_loc"; + private Boolean noAskAgain = false; + + @Override + protected void onSaveInstanceState(@NonNull final Bundle outState) { + super.onSaveInstanceState(outState); + + outState.putBoolean(KEY_FIXED_TO_LOC, marker_fixed_to_loc); + } + + @Override + protected void onRestoreInstanceState(@NonNull final Bundle savedInstanceState) { + super.onRestoreInstanceState(savedInstanceState); + + if (savedInstanceState.containsKey(KEY_FIXED_TO_LOC)) { + this.marker_fixed_to_loc = savedInstanceState.getBoolean(KEY_FIXED_TO_LOC); + } + } + + @Override + protected void onCreate(final Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + setContentView(R.layout.activity_share_location); + setSupportActionBar(findViewById(R.id.toolbar)); + configureActionBar(getSupportActionBar()); + setupMapView(Config.Map.INITIAL_POS); + + // Setup the cancel button + final Button cancelButton = findViewById(R.id.cancel_button); + cancelButton.setOnClickListener(view -> { + setResult(RESULT_CANCELED); + finish(); + }); + + // Setup the snackbar + this.snackBar = findViewById(R.id.snackbar); + final TextView snackbarAction = findViewById(R.id.snackbar_action); + snackbarAction.setOnClickListener(view -> { + if (isLocationEnabledAndAllowed()) { + updateUi(); + } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !hasLocationPermissions()) { + requestPermissions(REQUEST_CODE_SNACKBAR_PRESSED); + } else if (!isLocationEnabled()) { + startActivity(new Intent(android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS)); + } + }); + + // Setup the share button + final Button shareButton = findViewById(R.id.share_button); + if (shareButton != null) { + shareButton.setOnClickListener(view -> { + final Intent result = new Intent(); + + if (marker_fixed_to_loc && myLoc != null) { + result.putExtra("latitude", myLoc.getLatitude()); + result.putExtra("longitude", myLoc.getLongitude()); + result.putExtra("altitude", myLoc.getAltitude()); + result.putExtra("accuracy", (int) myLoc.getAccuracy()); + } else { + final IGeoPoint markerPoint = map.getMapCenter(); + result.putExtra("latitude", markerPoint.getLatitude()); + result.putExtra("longitude", markerPoint.getLongitude()); + } + + setResult(RESULT_OK, result); + finish(); + }); + } + + this.marker_fixed_to_loc = isLocationEnabledAndAllowed(); + + // Setup the fab button + final FloatingActionButton toggleFixedMarkerButton = findViewById(R.id.fab); + toggleFixedMarkerButton.setOnClickListener(view -> { + if (!marker_fixed_to_loc) { + if (!isLocationEnabled()) { + startActivity(new Intent(android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS)); + } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + requestPermissions(REQUEST_CODE_FAB_PRESSED); + } + } + toggleFixedLocation(); + }); + } + + @Override + public void onRequestPermissionsResult(final int requestCode, + @NonNull final String[] permissions, + @NonNull final int[] grantResults) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + + if (grantResults.length > 0 && + grantResults[0] != PackageManager.PERMISSION_GRANTED && + Build.VERSION.SDK_INT >= 23 && + permissions.length > 0 && + ( + Manifest.permission.LOCATION_HARDWARE.equals(permissions[0]) || + Manifest.permission.ACCESS_FINE_LOCATION.equals(permissions[0]) || + Manifest.permission.ACCESS_COARSE_LOCATION.equals(permissions[0]) + ) && + !shouldShowRequestPermissionRationale(permissions[0])) { + noAskAgain = true; + } + + if (!noAskAgain && requestCode == REQUEST_CODE_SNACKBAR_PRESSED && !isLocationEnabled() && hasLocationPermissions()) { + startActivity(new Intent(android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS)); + } + updateUi(); + } + + @Override + protected void gotoLoc(final boolean setZoomLevel) { + if (this.myLoc != null && mapController != null) { + if (setZoomLevel) { + mapController.setZoom(Config.Map.FINAL_ZOOM_LEVEL); + } + mapController.animateTo(new GeoPoint(this.myLoc)); + } + } + + @Override + protected void setMyLoc(final Location location) { + this.myLoc = location; + } + + @Override + protected void onPause() { + super.onPause(); + } + + @Override + protected void updateLocationMarkers() { + super.updateLocationMarkers(); + if (this.myLoc != null) { + this.map.getOverlays().add(new MyLocation(this, null, this.myLoc)); + if (this.marker_fixed_to_loc) { + map.getOverlays().add(new Marker(marker_icon, new GeoPoint(this.myLoc))); + } else { + map.getOverlays().add(new Marker(marker_icon)); + } + } else { + map.getOverlays().add(new Marker(marker_icon)); + } + } + + @Override + public void onLocationChanged(final Location location) { + if (this.myLoc == null) { + this.marker_fixed_to_loc = true; + } + updateUi(); + if (LocationHelper.isBetterLocation(location, this.myLoc)) { + final Location oldLoc = this.myLoc; + this.myLoc = location; + + // Don't jump back to the users location if they're not moving (more or less). + if (oldLoc == null || (this.marker_fixed_to_loc && this.myLoc.distanceTo(oldLoc) > 1)) { + gotoLoc(); + } + + updateLocationMarkers(); + } + } + + @Override + public void onStatusChanged(final String provider, final int status, final Bundle extras) { + + } + + @Override + public void onProviderEnabled(final String provider) { + + } + + @Override + public void onProviderDisabled(final String provider) { + + } + + private boolean isLocationEnabledAndAllowed() { + return this.hasLocationFeature && (Build.VERSION.SDK_INT < Build.VERSION_CODES.M || this.hasLocationPermissions()) && this.isLocationEnabled(); + } + + private void toggleFixedLocation() { + this.marker_fixed_to_loc = isLocationEnabledAndAllowed() && !this.marker_fixed_to_loc; + if (this.marker_fixed_to_loc) { + gotoLoc(false); + } + updateLocationMarkers(); + updateUi(); + } + + @Override + protected void updateUi() { + if (!hasLocationFeature || noAskAgain || isLocationEnabledAndAllowed()) { + this.snackBar.setVisibility(View.GONE); + } else { + this.snackBar.setVisibility(View.VISIBLE); + } + + // Setup the fab button + final FloatingActionButton fab = findViewById(R.id.fab); + if (isLocationEnabledAndAllowed()) { + fab.setVisibility(View.VISIBLE); + runOnUiThread(() -> { + fab.setImageResource(marker_fixed_to_loc ? R.drawable.ic_gps_fixed_white_24dp : + R.drawable.ic_gps_not_fixed_white_24dp); + fab.setContentDescription(getResources().getString( + marker_fixed_to_loc ? R.string.action_unfix_from_location : R.string.action_fix_to_location + )); + fab.invalidate(); + }); + } else { + fab.setVisibility(View.GONE); + } + } +} \ No newline at end of file diff --git a/src/main/java/eu/siacs/conversations/ui/ShowLocationActivity.java b/src/main/java/eu/siacs/conversations/ui/ShowLocationActivity.java new file mode 100644 index 000000000..7e697f053 --- /dev/null +++ b/src/main/java/eu/siacs/conversations/ui/ShowLocationActivity.java @@ -0,0 +1,234 @@ +package eu.siacs.conversations.ui; + +import android.app.ActionBar; +import android.content.ActivityNotFoundException; +import android.content.ClipData; +import android.content.ClipboardManager; +import android.content.ComponentName; +import android.content.Intent; +import android.location.Location; +import android.location.LocationListener; +import android.net.Uri; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.design.widget.FloatingActionButton; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.widget.Toast; + +import org.osmdroid.util.GeoPoint; + +import java.util.HashMap; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import eu.siacs.conversations.Config; +import eu.siacs.conversations.R; +import eu.siacs.conversations.ui.util.LocationHelper; +import eu.siacs.conversations.ui.util.UriHelper; +import eu.siacs.conversations.ui.widget.Marker; +import eu.siacs.conversations.ui.widget.MyLocation; + + +public class ShowLocationActivity extends LocationActivity implements LocationListener { + + private GeoPoint loc = Config.Map.INITIAL_POS; + private FloatingActionButton navigationButton; + + + private Uri createGeoUri() { + return Uri.parse("geo:" + this.loc.getLatitude() + "," + this.loc.getLongitude()); + } + + @Override + protected void onCreate(final Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + final ActionBar actionBar = getActionBar(); + if (actionBar != null) { + actionBar.setDisplayHomeAsUpEnabled(true); + } + + setContentView(R.layout.activity_show_location); + setSupportActionBar(findViewById(R.id.toolbar)); + configureActionBar(getSupportActionBar()); + setupMapView(this.loc); + + // Setup the fab button + this.navigationButton = findViewById(R.id.fab); + this.navigationButton.setOnClickListener(view -> startNavigation()); + + final Intent intent = getIntent(); + if (intent != null) { + final String action = intent.getAction(); + if (action == null) { + return; + } + switch (action) { + case "eu.siacs.conversations.location.show": + if (intent.hasExtra("longitude") && intent.hasExtra("latitude")) { + final double longitude = intent.getDoubleExtra("longitude", 0); + final double latitude = intent.getDoubleExtra("latitude", 0); + this.loc = new GeoPoint(latitude, longitude); + } + break; + case Intent.ACTION_VIEW: + final Uri geoUri = intent.getData(); + + // Attempt to set zoom level if the geo URI specifies it + if (geoUri != null) { + final HashMap query = UriHelper.parseQueryString(geoUri.getQuery()); + + // Check for zoom level. + final String z = query.get("z"); + if (z != null) { + try { + mapController.setZoom(Double.valueOf(z)); + } catch (final Exception ignored) { + } + } + + // Check for the actual geo query. + boolean posInQuery = false; + final String q = query.get("q"); + if (q != null) { + final Pattern latlng = Pattern.compile("/^([-+]?[0-9]+(\\.[0-9]+)?),([-+]?[0-9]+(\\.[0-9]+)?)(\\(.*\\))?/"); + final Matcher m = latlng.matcher(q); + if (m.matches()) { + try { + this.loc = new GeoPoint(Double.valueOf(m.group(1)), Double.valueOf(m.group(3))); + posInQuery = true; + } catch (final Exception ignored) { + } + } + } + + final String schemeSpecificPart = geoUri.getSchemeSpecificPart(); + if (schemeSpecificPart != null && !schemeSpecificPart.isEmpty()) { + try { + final GeoPoint latlong = LocationHelper.parseLatLong(schemeSpecificPart); + if (latlong != null && !posInQuery) { + this.loc = latlong; + } + } catch (final NumberFormatException ignored) { + } + } + } + + break; + } + updateLocationMarkers(); + } + } + + @Override + protected void gotoLoc(final boolean setZoomLevel) { + if (this.loc != null && mapController != null) { + if (setZoomLevel) { + mapController.setZoom(Config.Map.FINAL_ZOOM_LEVEL); + } + mapController.animateTo(new GeoPoint(this.loc)); + } + } + + @Override + public void onRequestPermissionsResult(final int requestCode, + @NonNull final String[] permissions, + @NonNull final int[] grantResults) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + updateUi(); + } + + @Override + protected void setMyLoc(final Location location) { + this.myLoc = location; + } + + @Override + public boolean onCreateOptionsMenu(final Menu menu) { + // Inflate the menu; this adds items to the action bar if it is present. + getMenuInflater().inflate(R.menu.menu_show_location, menu); + updateUi(); + return true; + } + + @Override + protected void updateLocationMarkers() { + super.updateLocationMarkers(); + if (this.myLoc != null) { + this.map.getOverlays().add(new MyLocation(this, null, this.myLoc)); + } + this.map.getOverlays().add(new Marker(this.marker_icon, this.loc)); + } + + @Override + protected void onPause() { + super.onPause(); + } + + @Override + public boolean onOptionsItemSelected(final MenuItem item) { + switch (item.getItemId()) { + case R.id.action_copy_location: + final ClipboardManager clipboard = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE); + if (clipboard != null) { + final ClipData clip = ClipData.newPlainText("location", createGeoUri().toString()); + clipboard.setPrimaryClip(clip); + } + return true; + case R.id.action_share_location: + final Intent shareIntent = new Intent(); + shareIntent.setAction(Intent.ACTION_SEND); + shareIntent.putExtra(Intent.EXTRA_TEXT, createGeoUri().toString()); + shareIntent.setType("text/plain"); + try { + startActivity(Intent.createChooser(shareIntent, getText(R.string.share_with))); + } catch (final ActivityNotFoundException e) { + //This should happen only on faulty androids because normally chooser is always available + Toast.makeText(this, R.string.no_application_found_to_open_file, Toast.LENGTH_SHORT).show(); + } + return true; + } + return super.onOptionsItemSelected(item); + } + + private void startNavigation() { + startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse( + "google.navigation:q=" + + String.valueOf(this.loc.getLatitude()) + "," + String.valueOf(this.loc.getLongitude()) + ))); + } + + @Override + protected void updateUi() { + final Intent i = new Intent(Intent.ACTION_VIEW, Uri.parse("google.navigation:q=0,0")); + final ComponentName component = i.resolveActivity(getPackageManager()); + if (this.navigationButton != null) { + this.navigationButton.setVisibility(component == null ? View.GONE : View.VISIBLE); + } + } + + @Override + public void onLocationChanged(final Location location) { + if (LocationHelper.isBetterLocation(location, this.myLoc)) { + this.myLoc = location; + updateLocationMarkers(); + } + } + + @Override + public void onStatusChanged(final String provider, final int status, final Bundle extras) { + + } + + @Override + public void onProviderEnabled(final String provider) { + + } + + @Override + public void onProviderDisabled(final String provider) { + + } +} diff --git a/src/main/java/eu/siacs/conversations/ui/UriHandlerActivity.java b/src/main/java/eu/siacs/conversations/ui/UriHandlerActivity.java index 3e0b389a8..28755c316 100644 --- a/src/main/java/eu/siacs/conversations/ui/UriHandlerActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/UriHandlerActivity.java @@ -165,4 +165,4 @@ public class UriHandlerActivity extends AppCompatActivity { } finish(); } -} +} \ No newline at end of file diff --git a/src/main/java/eu/siacs/conversations/ui/XmppActivity.java b/src/main/java/eu/siacs/conversations/ui/XmppActivity.java index ec5eaead5..8684d8580 100644 --- a/src/main/java/eu/siacs/conversations/ui/XmppActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/XmppActivity.java @@ -3,9 +3,6 @@ package eu.siacs.conversations.ui; import android.Manifest; import android.annotation.SuppressLint; import android.annotation.TargetApi; -import android.support.v7.app.ActionBar; -import android.support.v7.app.AlertDialog; -import android.support.v7.app.AlertDialog.Builder; import android.app.PendingIntent; import android.content.ActivityNotFoundException; import android.content.ClipData; @@ -37,7 +34,8 @@ import android.os.PowerManager; import android.os.SystemClock; import android.preference.PreferenceManager; import android.support.v4.content.ContextCompat; -import android.support.v7.app.AppCompatActivity; +import android.support.v7.app.AlertDialog; +import android.support.v7.app.AlertDialog.Builder; import android.support.v7.app.AppCompatDelegate; import android.text.InputType; import android.util.DisplayMetrics; @@ -76,7 +74,7 @@ import eu.siacs.conversations.xmpp.OnKeyStatusUpdated; import eu.siacs.conversations.xmpp.OnUpdateBlocklist; import rocks.xmpp.addr.Jid; -public abstract class XmppActivity extends AppCompatActivity { +public abstract class XmppActivity extends ActionBarActivity { public static final String EXTRA_ACCOUNT = "account"; protected static final int REQUEST_ANNOUNCE_PGP = 0x0101; @@ -610,13 +608,6 @@ public abstract class XmppActivity extends AppCompatActivity { } } - public static void configureActionBar(ActionBar actionBar) { - if (actionBar != null) { - actionBar.setHomeButtonEnabled(true); - actionBar.setDisplayHomeAsUpEnabled(true); - } - } - protected boolean noAccountUsesPgp() { if (!hasPgp()) { return true; diff --git a/src/main/java/eu/siacs/conversations/ui/util/LocationHelper.java b/src/main/java/eu/siacs/conversations/ui/util/LocationHelper.java new file mode 100644 index 000000000..27a6c0837 --- /dev/null +++ b/src/main/java/eu/siacs/conversations/ui/util/LocationHelper.java @@ -0,0 +1,72 @@ +package eu.siacs.conversations.ui.util; + +import android.location.Location; + +import org.osmdroid.util.GeoPoint; + +import eu.siacs.conversations.Config; + +public final class LocationHelper { + /** + * Parses a lat long string in the form "lat,long". + * + * @param latlong A string in the form "lat,long" + * @return A GeoPoint representing the lat,long string. + * @throws NumberFormatException If an invalid lat or long is specified. + */ + public static GeoPoint parseLatLong(final String latlong) throws NumberFormatException { + if (latlong == null || latlong.isEmpty()) { + return null; + } + + final String[] parts = latlong.split(","); + if (parts[1].contains("?")) { + parts[1] = parts[1].substring(0, parts[1].indexOf("?")); + } + return new GeoPoint(Double.valueOf(parts[0]), Double.valueOf(parts[1])); + } + + private static boolean isSameProvider(final String provider1, final String provider2) { + if (provider1 == null) { + return provider2 == null; + } + return provider1.equals(provider2); + } + + public static boolean isBetterLocation(final Location location, final Location prevLoc) { + if (prevLoc == null) { + return true; + } + + // Check whether the new location fix is newer or older + final long timeDelta = location.getTime() - prevLoc.getTime(); + final boolean isSignificantlyNewer = timeDelta > Config.Map.LOCATION_FIX_SIGNIFICANT_TIME_DELTA; + final boolean isSignificantlyOlder = timeDelta < -Config.Map.LOCATION_FIX_SIGNIFICANT_TIME_DELTA; + final boolean isNewer = timeDelta > 0; + + if (isSignificantlyNewer) { + return true; + } else if (isSignificantlyOlder) { + return false; + } + + // Check whether the new location fix is more or less accurate + final int accuracyDelta = (int) (location.getAccuracy() - prevLoc.getAccuracy()); + final boolean isLessAccurate = accuracyDelta > 0; + final boolean isMoreAccurate = accuracyDelta < 0; + final boolean isSignificantlyLessAccurate = accuracyDelta > 200; + + // Check if the old and new location are from the same provider + final boolean isFromSameProvider = isSameProvider(location.getProvider(), prevLoc.getProvider()); + + // Determine location quality using a combination of timeliness and accuracy + if (isMoreAccurate) { + return true; + } else if (isNewer && !isLessAccurate) { + return true; + } else if (isNewer && !isSignificantlyLessAccurate && isFromSameProvider) { + return true; + } + return false; + } +} \ No newline at end of file diff --git a/src/main/java/eu/siacs/conversations/ui/util/UriHelper.java b/src/main/java/eu/siacs/conversations/ui/util/UriHelper.java new file mode 100644 index 000000000..e91012ad1 --- /dev/null +++ b/src/main/java/eu/siacs/conversations/ui/util/UriHelper.java @@ -0,0 +1,30 @@ +package eu.siacs.conversations.ui.util; + +import java.util.HashMap; + +/** + * Helper methods for parsing URI's. + */ +public final class UriHelper { + /** + * Parses a query string into a hashmap. + * + * @param q The query string to split. + * @return A hashmap containing the key-value pairs from the query string. + */ + public static HashMap parseQueryString(final String q) { + if (q == null || q.isEmpty()) { + return null; + } + + final String[] query = q.split("&"); + // TODO: Look up the HashMap implementation and figure out what the load factor is and make sure we're not reallocating here. + final HashMap queryMap = new HashMap<>(query.length); + for (final String param : query) { + final String[] pair = param.split("="); + queryMap.put(pair[0], pair.length == 2 && !pair[1].isEmpty() ? pair[1] : null); + } + + return queryMap; + } +} \ No newline at end of file diff --git a/src/main/java/eu/siacs/conversations/ui/widget/Marker.java b/src/main/java/eu/siacs/conversations/ui/widget/Marker.java new file mode 100644 index 000000000..0e2822270 --- /dev/null +++ b/src/main/java/eu/siacs/conversations/ui/widget/Marker.java @@ -0,0 +1,52 @@ +package eu.siacs.conversations.ui.widget; + +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Point; + +import org.osmdroid.util.GeoPoint; +import org.osmdroid.views.MapView; +import org.osmdroid.views.overlay.mylocation.SimpleLocationOverlay; + +/** + * An immutable marker overlay. + */ +public class Marker extends SimpleLocationOverlay { + private final GeoPoint position; + private final Bitmap icon; + private final Point mapPoint; + + /** + * Create a marker overlay which will be drawn at the current Geographical position. + * @param icon A bitmap icon for the marker + * @param position The geographic position where the marker will be drawn (if it is inside the view) + */ + public Marker(final Bitmap icon, final GeoPoint position) { + super(icon); + this.icon = icon; + this.position = position; + this.mapPoint = new Point(); + } + + /** + * Create a marker overlay which will be drawn centered in the view. + * @param icon A bitmap icon for the marker + */ + public Marker(final Bitmap icon) { + this(icon, null); + } + + @Override + public void draw(final Canvas c, final MapView view, final boolean shadow) { + super.draw(c, view, shadow); + + // If no position was set for the marker, draw it centered in the view. + view.getProjection().toPixels(this.position == null ? view.getMapCenter() : position, mapPoint); + + c.drawBitmap(icon, + mapPoint.x - icon.getWidth() / 2, + mapPoint.y - icon.getHeight(), + null); + + } +} \ No newline at end of file diff --git a/src/main/java/eu/siacs/conversations/ui/widget/MyLocation.java b/src/main/java/eu/siacs/conversations/ui/widget/MyLocation.java new file mode 100644 index 000000000..5dc771b44 --- /dev/null +++ b/src/main/java/eu/siacs/conversations/ui/widget/MyLocation.java @@ -0,0 +1,65 @@ +package eu.siacs.conversations.ui.widget; + +import android.annotation.TargetApi; +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Point; +import android.location.Location; +import android.os.Build; + +import org.osmdroid.util.GeoPoint; +import org.osmdroid.views.MapView; +import org.osmdroid.views.overlay.mylocation.SimpleLocationOverlay; + +import eu.siacs.conversations.Config; +import eu.siacs.conversations.R; +import microsoft.mappoint.TileSystem; + +public class MyLocation extends SimpleLocationOverlay { + private final GeoPoint position; + private final float accuracy; + private final Point mapCenterPoint; + private final Paint fill; + private final Paint outline; + + @TargetApi(Build.VERSION_CODES.LOLLIPOP) + private int getColor(final Context ctx) { + final int accent; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + accent = ctx.getResources().getColor(R.color.accent, ctx.getTheme()); + } else { + //noinspection deprecation + accent = ctx.getResources().getColor(R.color.accent); + } + return accent; + } + + public MyLocation(final Context ctx, final Bitmap icon, final Location position) { + super(icon); + this.mapCenterPoint = new Point(); + this.fill = new Paint(Paint.ANTI_ALIAS_FLAG); + final int accent = this.getColor(ctx); + fill.setColor(accent); + fill.setStyle(Paint.Style.FILL); + this.outline = new Paint(Paint.ANTI_ALIAS_FLAG); + outline.setColor(accent); + outline.setAlpha(50); + outline.setStyle(Paint.Style.FILL); + this.position = new GeoPoint(position); + this.accuracy = position.getAccuracy(); + } + + @Override + public void draw(final Canvas c, final MapView view, final boolean shadow) { + super.draw(c, view, shadow); + + view.getProjection().toPixels(position, mapCenterPoint); + c.drawCircle(mapCenterPoint.x, mapCenterPoint.y, + Math.max(Config.Map.MY_LOCATION_INDICATOR_SIZE + Config.Map.MY_LOCATION_INDICATOR_OUTLINE_SIZE, + accuracy / (float) TileSystem.GroundResolution(position.getLatitude(), view.getZoomLevel()) + ), this.outline); + c.drawCircle(mapCenterPoint.x, mapCenterPoint.y, Config.Map.MY_LOCATION_INDICATOR_SIZE, this.fill); + } +} diff --git a/src/main/res/drawable-hdpi/ic_directions_black_24dp.png b/src/main/res/drawable-hdpi/ic_directions_black_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..1d429c8f7e7f8eac89ffd52eff1e59c210adadcf GIT binary patch literal 233 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k0wldT1B8Lp22U5qkP6197Yw-$IY_uXWR&*K zpQL8~nMv;SW{pK1WsMch8hRY3ldm^w8n6HVqkQYL-l|s%4b#(f=chFrNdQp*BePbb z$4?)RiHcJV-2=o9Z(E?##yRDfDxzzpBsnKP;=-y3$&%>EWVFzE{`ruK4c0 z)SH)g7Ei~SC62Fx8*JJ{6ecs4{@Av_j=Ae6&x!^{QG*3cZ6Y&!K1qU%PjHazah+SL dw0Y59M!}YahATU(KLg#);OXk;vd$@?2>=QgR&@XX literal 0 HcmV?d00001 diff --git a/src/main/res/drawable-hdpi/ic_directions_white_24dp.png b/src/main/res/drawable-hdpi/ic_directions_white_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..e33ea5612331936eb03e91877c14203d61d03e94 GIT binary patch literal 252 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k0wldT1B8LpVNVyw5Rczopr0HL5` Aq5uE@ literal 0 HcmV?d00001 diff --git a/src/main/res/drawable-hdpi/ic_gps_fixed_black_24dp.png b/src/main/res/drawable-hdpi/ic_gps_fixed_black_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..85e38726dd4240d78e9f802db94a6987b027d0ef GIT binary patch literal 549 zcmV+=0^0qFP)q+FWCCT}XAvHG*iR93pm_1S5Hp zGX{g3?7{FW1~WTE1v&0B)$aWAV|TJUEMI4Vh=>I~Eg~f)`bUbsvBa4vI%APZJ|NE; zS0tp?c;%8+^1MTZHfhFaF~^AZ80bfR8dQmisnWF0?lOWOivMAs61I>7o-}(5etQc3 zW(t=Q*GlZ*QPJi9WQ;5UCnl3HONKmcUCkIi0XHVsB!|$`+Jp$PIdkEDiW5@$l+e}KHK>XL2GeFWdrUB7$wV6n8>Ei0iSS^K z=Z7{5y;D_$J7-ZHp=ORx?M)`Kf-yqJS=6;x2@N7&(Tl%`L%Ya#YYk`7z30|sQ4g80 z*Lne78Wk85Q(Xo|0QUIf@zkeKuOA|f-32DEnDS;fBGv_$1n#m_CUSyLx zUAo+}P64FMv&k;wl-GS<6W|kYt7j@lhB^8sazfy#`K4`S29I5>#|uP4vFFe9;gv>NR1ZS{7KkmM6)zWGe(^m-XX^d7xb_zdYrRNjt`h% no>RS36~_OkuMzu0>#O_)RZ4aRmaPDG00000NkvXXu0mjf7M<-G literal 0 HcmV?d00001 diff --git a/src/main/res/drawable-hdpi/ic_gps_fixed_white_24dp.png b/src/main/res/drawable-hdpi/ic_gps_fixed_white_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..745db489be6ad7efd37d8adb82999954a2a0574c GIT binary patch literal 546 zcmV+-0^R+IP)6vy!>N1}qhz<7BH3lSoMwqhYZhqp!>35e0=G#1l|)j_5aL@Px^>@*2Rd=ibK z81p$z*lfm~iz$ZT{8shfYw?BkUzfcz|C!9l%bSsDZ5iz>5Ay#L(6Bit;KZzN1$f18K~DIxQsDL)HNvUNrRTaQ z(x3~l9fd!L^=LHs3g9dS8dk$+s8lv!VpO)_9aG1Pzv8GQd$lEdoUe=8jIot z9E8AIDHVhN5FBePnK0jgLI|u%={5dKLHSmow>F^N7}P4Yl9cXRq}H%mP!8W~Qd$oF z3dnt}+K>;_L$CBFR>?ys|9GSP1F42Q2Rl(i#wZ@5ZLkMU)1AEto}=)7tBPK|y0a`B z&d0rg`DQ~~0ayCk4DAglHXGWEDWBj-Ukl7Xpk|`gV%r2<8%<)y-2m3xt=fG+Rl(T5 zAbVZ_KRa3e8)|^Mdxr{k9jd4UYSufwjwY2gQ_;kCF327W&b*8D?$o@VZm#S>(~iNh koPj^-HImWoL#uoH4L`+AbSP*|CjbBd07*qoM6N<$g7`7{Bme*a literal 0 HcmV?d00001 diff --git a/src/main/res/drawable-hdpi/ic_gps_not_fixed_black_24dp.png b/src/main/res/drawable-hdpi/ic_gps_not_fixed_black_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..7c5a19d133e4bbf072f9e1319bbc2092537c4e66 GIT binary patch literal 472 zcmV;}0Vn>6P)NklvrSCqiF0&wIBJz>PsfCJOG7MMde@lM+R+I2mR%(2@BEa zOErjm&nsh|lwNeDm=ectM2*w9#+DR2kvÇO3S3F~=??2=k-v2W)xG|OB@?n+C8 zS;QvJ~SEPnt3-vx)ZyLc4< O0000w%%*lIA~llZ3y zPUhPtMc8DLiz~~r=hxlhV=luv=Z3#l)+7>Z!sGfRp4m}o13UZ5;c&O36oDCVmiJu{C literal 0 HcmV?d00001 diff --git a/src/main/res/drawable-hdpi/marker.png b/src/main/res/drawable-hdpi/marker.png new file mode 100644 index 0000000000000000000000000000000000000000..e41741b9dc21fd7a2206267ff83c687ad0c68386 GIT binary patch literal 3591 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 N002ovPDHLkV1fo_(5V0b literal 0 HcmV?d00001 diff --git a/src/main/res/drawable-mdpi/ic_directions_black_24dp.png b/src/main/res/drawable-mdpi/ic_directions_black_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..7be13ecd1ffa651804804591ccfc1a3f28734a23 GIT binary patch literal 181 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM0wlfaz7_+i8c!F;kP615=XCj64Fp^t?rxtR zvYF#s{!hUafv;~^v^Y%EmDfEwyY+eYD*M=r>jFN0UbT6x)RNP@O)^JLIL`Saz*(H5 zka&($<*d8S)JZSm&pO^-_B@QC=H}e>~x$U gopP<^&*t3>4e~pFovc4U1?Ub2Pgg&ebxsLQ0P0an8vpcUJnrSX3l#(o-na~O5re0zpUXO@geCwr4@{x} literal 0 HcmV?d00001 diff --git a/src/main/res/drawable-mdpi/ic_gps_fixed_black_24dp.png b/src/main/res/drawable-mdpi/ic_gps_fixed_black_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..5684aa7dc5d4dd20ffac6d3191a20b810fa3b56c GIT binary patch literal 341 zcmV-b0jmCqP)o5F%8?4(H_dnxq%Qyb}~aDd}9xyNb>mzvH~ zSjR9mwRQ@xnyM5!-ef|pox+QzDus?Wsky^i3KyErQrN&SP5RhRp=+e}*K!JnI7*XU zJep6T>s+OBW;umL&)Cj1HyCJThL%%YWtOfn1{Ts_(J4lj@}4bYJUOtgqhrINXN+v- wV^&<7b!91^vE$g##L$uLe2pUCp~%np4=Q+%K$TBvZvX%Q07*qoM6N<$f;{4*-2eap literal 0 HcmV?d00001 diff --git a/src/main/res/drawable-mdpi/ic_gps_not_fixed_black_24dp.png b/src/main/res/drawable-mdpi/ic_gps_not_fixed_black_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..ffd6cd40374408c53cc66338f9579d7e67405999 GIT binary patch literal 295 zcmV+?0oeYDP)AP^J>)`Aq>i%xn7t-^sIZsAUJkmxXM0VnwlqWjMviauxf z&bi#j7E@5vZY1FfOo_z6WWxo=`iJpxX@3YZuMuXd{tv* zlV*JPoz+W3Pi(Rw@MxE*l2Ye{7~v@p6LMyVC7uJKO->i#_#`Zp$*CYLKO2}mqC-v( z;o_H`k~2pv@Qe{hYNXt8MhppT5v$~fdqJ#;w7A%$?w@Y;HyR}LZE|8pm&!Fg=A5nm tKt_`d3bLlbO(T{#t2!18|No!<)(5*PbP`oOf{FkD002ovPDHLkV1k&zez^bu literal 0 HcmV?d00001 diff --git a/src/main/res/drawable-mdpi/ic_gps_not_fixed_white_24dp.png b/src/main/res/drawable-mdpi/ic_gps_not_fixed_white_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..35404467a0df39cf5246341409d8814f29261c0e GIT binary patch literal 298 zcmV+_0oDGAP)!@Dvt;c!h1WP_&fw0AENI_GOaQfs=k>ka>Fvv^~74e@Xv-6 zxpoLDj##Vsx2qKU5d6eNT~d;!8^%Sj!Bi5-9IGNYqZb7OWPbrbH416~Z-PHLp&tcb z$b?OsMZp5gBADQ+QTqIwJ4WH84@gS~x5Z8pf{q-iX7Keb9$IC~H-%fcNG w-(&0Dwinh;>-EKrtz;mxGYAGKWp~O18qG%8^>NoP%I)Rb z3M>W1*~|&)p({P3J-^$xc;7Ar=2YxYiNF&dJ+Yv&pz^R=bI(e(nWjm1q?`U|KO^xG z09>jIuhmPry&NH~nLKpi(7)OS+J402oWJP=HXPsZ&|QwZnlwdo00iSfT6$Y(A82PN zHZddEu)UFigXb!NWB0_nStb;aJ1EIqo@cN+G3bnjGsp#?kJh zL=(}h=35mj9@RtNXdeJl$e5IJmHuP>AGu=5nZV<%kJnZ^sy|Yt>d+0H!<~ouH1KJz zYSLm678I$VNi9%UQTP2LE03JcWqwWs8qG!-Ym1$8YwlU5X>#bop-I6PSPGc!n$2`= zIsgN)0XjxH2qc;ay7L@wJ1W#=u4Oh+Wc)acQq5zLs%7Sddz*r_fhGn1i16-e}4Tl;P=^L zlGzSyG#h1wy<#gQH|){wqZ$2W_A)ll-ONJo!U^C36rr%lyNE4ww=mN&6IH0lt50ih zD`7p1Kro|V#`bJ6p$0N@|>x1AX|^Jx2Edtv)v zd*PXpGmrX5{igwntVJ|bH{ehm2q6$c5Hn*O?>i2F!{R93*t&6bwz#qmA(!e}2gy9& zKG2@gx4Lq58hqzS=c_L-eRF)yXZvJHRYgNvw28pE9R!V26GdktC^CuiV* zgg(n2SC;Zv)ni}ZGwmJ#{84{KEokm)rp8@^NAob#IdkLIlUo<~qyC+`sy738gy)A| ztM}<5t>|8WXd+6_Xivu7pvF^^&Sqgf{I|RlK<9vN=r38M#XfKPybJ;%J;eUA`)Qcd zfJgICWGk9qR#5h~RbKN{D(4Tyhd6ltAQ3&1Q3vLF<{}Wpjd(PwMBmC5R@NcZw6bZ` zAM<|#Fn8KqT&gRhzcR>_90)!BZ#78bo^G$pCJ0}3p6X|IL&=igOvib@AsmqE$Oz^;1FD&scNs>iyIdu7# zxm+cuL|}j2{x=7r17`r1mMo>*UVcrXkf>7406yLWsj9ocy8wW}*kH%*#k=?42$mZn z0B|{cd6Quph7^(qXFZ4%NmYta(&3WgjzjZZpp>oKHnT1p>jP@TEWRS-j`SO(y^lFatjg>tR1!yH-kM z=Bkg|%pT3diqaJb1Q9(l9Eb&eG8GI{BJj@QcZM&9FK&fo=6U4KN7A8`UimTJP=vyo z$~9pxn* z`fktNe^I2O2m}Yt9Uy8%CuAc)H!yzi*#n=o6ZRz|0jlNQ01y(aq(hm+%@SNTq2S9@bd>ge=eUk^ArExb>F)_-{9dpAONs$#lDtrg5UhyFb&hdFgwB>&%Ctkr5pMS>6XflQ#GY@e-hc5H3vz8d4y)A9#wK0TkUA$^1CLHR#d^*Bd{wSO2AI?Wz@o+{9AKKu}a-h2M3 w&sZlux5bJQKhNs`qZ6O%Y>kCwulsE^XaDy!!X9?p00i_>zopr07U9~H~;_u literal 0 HcmV?d00001 diff --git a/src/main/res/drawable-xhdpi/ic_directions_white_24dp.png b/src/main/res/drawable-xhdpi/ic_directions_white_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..8b29cb4a61c7155838599fcbbf870361334e4777 GIT binary patch literal 307 zcmV-30nGl1P)B83SG9@0z-N?YPVJBaW?4noMV{Il;CaNhm@#Et*D>ojZErb$s>sJ^=n zeeTd~1Dx+AjC>zqoFo z<^e#0^H1Fr?GZtFQ67jdU~c@J=mJh+%)l-o!1?pm3~T_vBmdlzfk{Uv(9XX!WFWr+ z0qy*hA2|~MP(A^P0D$rdNCW_oPXNC~J&ynroCkmj&I3RM=K%nM^8f(Bc>sXmJODs& z9snRX4*(FH2LK4p0{{f)0RRH>0PsewS~Mtpz~2S9djnPV2eoQM9kBoa002ovPDHLk FV1lcmc258R literal 0 HcmV?d00001 diff --git a/src/main/res/drawable-xhdpi/ic_gps_fixed_black_24dp.png b/src/main/res/drawable-xhdpi/ic_gps_fixed_black_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..7faa3455f60127e423ab3cd481745bfa47eb121f GIT binary patch literal 660 zcmV;F0&D$=P)%+^Dn#{hi&+J@;JCoEaj|OrYZL7kDW!#0DpPlLFTqv(5ld zAjt|ff|$5qnIwEe*UG7d=7p)6Mf5+2YK8}7}aF5bzPJQLg7;+9r@&{7z|1J zU}*a)K}1wSB}VX7?ptDQsMOEs$JcXc0 zV2FJLGxFJJ)tW{hf?H#O8w9!5yYU4a1oy@Q4Fv9gR3M9>ZY*UlM_nxwYhB(^tOj)t-4}Irl~@CEvS9>iDv{ft<02T9Penfl z7b>}gE={qeQ9gUP=*sff8!fA4O(qD-v(F6;8hGq7M%bhrU=gDvo?2KZgRNKG$#1>{ zZ7fI|PDx?I;Y=DghlK;JM8@LuXZl-VBh96x)S19!k~>-Z6$eYbc#_uSkP)JcQr2ec zCvUJv54F%xR@r8T94;<7X4z4%m7Jc}bjYPZU==>QI6TNaKiY18%^Z)AV2LVz%*iV( ulHduvV~rziwk|2NO8>wAC-9}f^Y90NP?&Wf5nE#b00005_dO{AfRR*eT+@b9gN#p1y~2!aQ%;zc~_NpA}JJya4TNWADLCzuWFR`;6~QoL%q#f;ygiJlyjth)6$c9C1aR3Wu!H z`y7H+mMCH4f<;=NBADYBaa5UooS>b3T-hVptRT%L7!;?hGfo#iK4~V{pn$?ana*Ye zX=>E@!ybJNs|Lt%FIv^%Dro0Y4Eu~1kx?;~5(y`P=>1pT;Kd}xF?BL7f;sW{Hav&4 z3B^pDpw(>5YW(a?Ql?SgX^9prnWY^G-5DXv4R;TzkzqJ=_lsHXg=j&^?CjvO=Ln+6 zl5Dtg#VA3)8QvFoe33>J0*XNtdh7?gU=7W;z||Z!0=vdcW5q5wLbD#|y&V-;i%m2K zcEJ^zad9n66uY8w5>1(~fG}O6;hj5yCaHQQJHu_g0vV`BZ{h1i%cqL zCd9Q2QEZFKDeEGe9HQ9}*M?EpP<#@VTWIoj!77>pp3_F%3DljTS+)y$&CCYG)g%QP zaT+*ahRnZ;9=pKf0!LV*0h`m)N&oVu)Uzz`+z~lu9{sKIN V8gkk7uaf`(002ovPDHLkV1fY7Hg5m` literal 0 HcmV?d00001 diff --git a/src/main/res/drawable-xhdpi/ic_gps_not_fixed_black_24dp.png b/src/main/res/drawable-xhdpi/ic_gps_not_fixed_black_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..14282267ed620ba1b69930d0f6c0014af3cf1a79 GIT binary patch literal 561 zcmV-10?z%3P)S+Z*}^w6rw!4~}0drL|W{y-2s^eSG&qn`App#O&lA&A6_{sjd=XhRB> z5Rmi-!Qj8r?Dq0_%%QV8GXz@D&pZ0wzR8=(WaW{`Btktk2sg(*SA5q7JucZ}h7pL^ zrbA|lTegTG+(+)o3ZlbU**o&ojiq!*aH6y46XO)AaIN{LZYM_{PZ<|wqs1BpBJOoK zd7CL2(hA@Y;`FqhlDtm z>LylulF}l?SE=5?YDTY$d3?Rmt74iQx6iGDeuK*k5is(z?fC{dj z^Pum1B?_$TDZZwRi1r;P)Dsgf)k~oi&jk*w%}LyEfyDkAP6qpiW_mME8QvReYg;Ugt*Zw5Cox>2uc`` z*p|WIt(fz4@$y2jJ(+XHETr}Kzkp|S0_TkRzo3l&3;}x$xHrx=r`(~MoUp}cF9Lbi zY2b3h8u{l0mboWQ!cw-t09AZd=noB)xJ7~G8#~M}OhiP9S$4U^0xD)GBv7J-dZfY_ z<}aJzh&C!=&^Iu^Eh^y)2KT0Dp&AtY0#(!*Z!jqcHJm9><_UKo$`mNPpg^hD{~}!zF`Fqc?|#X; z6U1(&z&@hp4s0PVGX<^?8}7g;!ZLvg+$SsmmJxTraDzAs4%9mTdUs$A(Pj!0uxTt} zCGEgT5G{%r&%NaV(R3d;x+T=P=aCt4fv_z29Qu`xMA75vFHi>_~CF7)zS;1EBS1EOr# z_eFk^rpdx{K0tD;QpY-;{E`)Nz4(Os$R@|csF)fXjQoRNnXdueiwgV(Q6*ArGL;|@ P00000NkvXXu0mjfx~2M# literal 0 HcmV?d00001 diff --git a/src/main/res/drawable-xhdpi/marker.png b/src/main/res/drawable-xhdpi/marker.png new file mode 100644 index 0000000000000000000000000000000000000000..a3413b8e44313cf7f1fa6eb433407c5c476249e2 GIT binary patch literal 4815 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 literal 0 HcmV?d00001 diff --git a/src/main/res/drawable-xxhdpi/ic_directions_white_24dp.png b/src/main/res/drawable-xxhdpi/ic_directions_white_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..ee364ee81e1a1fefb703b9ae25aa806456753267 GIT binary patch literal 444 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 literal 0 HcmV?d00001 diff --git a/src/main/res/drawable-xxhdpi/ic_gps_not_fixed_white_24dp.png b/src/main/res/drawable-xxhdpi/ic_gps_not_fixed_white_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..eac72e8dc17324cede3e3b6cc78b63defb6af575 GIT binary patch literal 830 zcmV-E1Ht@>P)zJPd;AX4xJT9JU@!5EPRi+4rZgLvpI2v)3zehHx= z8ll)yQ~M?*6%jquix-vD*n>}do5`BU?9L?EHoyNDcwlySk{PSze+ZeSI~MxW3i^)( zwSod9aMKobjrXxU&HyE+Bpd-2p6h<6vfOUD-qS)!OoG*_&IFIBRi%; zBtI|HF>r0G56@WW772HOE)?E+NY~A_hl(A@#=z^Mqc2B$Z&?LUr7^c#+~ah zTio!P8?p>F`&PP-3|Vr>a%5Q`{+6%FTS2X$R!~!?6{J6Z0}qHv5BtUvU;qFB07*qo IM6N<$f}Ff|3jhEB literal 0 HcmV?d00001 diff --git a/src/main/res/drawable-xxhdpi/marker.png b/src/main/res/drawable-xxhdpi/marker.png new file mode 100644 index 0000000000000000000000000000000000000000..70456d49df92d59b58c37c8c35ab3e61aaf64c9c GIT binary patch literal 7462 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 literal 0 HcmV?d00001 diff --git a/src/main/res/drawable-xxxhdpi/ic_directions_black_24dp.png b/src/main/res/drawable-xxxhdpi/ic_directions_black_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..0ad2fbbc7d9205c58b09fe6719a1393e8dce5ff6 GIT binary patch literal 491 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD0wg^q?%&M7z_`iN#WAFU@$J=vXM-FWS}*Qa z+sNBu>m_KC>Z%oWDxSl?)pS?F^Q2FY4oXkjdHF#32?PCNFz~-+cfa_wY5bhGFxe0s{M z5F&q$!RhN=euWVGXvUUT;pQ_KKHV=mrS>|VL*akyv1FF|N@G4A`I7_%RijXz)_2;hdIe!NXg1Nv? Lu6{1-oD!M<8A|Sq literal 0 HcmV?d00001 diff --git a/src/main/res/drawable-xxxhdpi/ic_directions_white_24dp.png b/src/main/res/drawable-xxxhdpi/ic_directions_white_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..3e3302fbd9af071006fa2d40ad260cf1b8cf5edf GIT binary patch literal 554 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD0wg^q?%&M7!1&SA#WAFU@$L1EzK0WJTnevy ztPz}KH$iceh%jSgpu`cjNxv2>tn2#27g+N>{=r`r?XqPX&m9ASO{b&vET3D>_E|go z(k|y|fAY@lV|(%JJLl6sb_?g+SD*6vcS}*-{D5=sg-`vgb+X*=ukoCC$^GZ+OE}By z@{2gD?3iPk=ACDlzTmm>0o5NrISM%I?3iMj=Jzv9fACxxD&+RBx^L&sN41NDdj3S8 zSS_S6zr1COQDSc0gNG}HHRhZDWKdv8C=acBQ=^b0@nP2LWzRm(lPI{zP*?ZqWW#4K z2A)ru@;nx$j1%;2oNnvH9_ad`I{V*wja=Vd_W_A?!IY4KR4R`njxgN@xNA3x52_ literal 0 HcmV?d00001 diff --git a/src/main/res/drawable-xxxhdpi/ic_gps_fixed_black_24dp.png b/src/main/res/drawable-xxxhdpi/ic_gps_fixed_black_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..0812b0e31d6c2a5633024cc3a86aa5e0329d34e7 GIT binary patch literal 1334 zcmV-61fgpj}7bM_akU$+7b}+y-C4p-Uu!9VB)Tm|b;uim6*~EKpvXiCMkT6}` z=QEarC~}YOgsHkXhk1+TGXCZu4OC5py-Z+vjB$1orV845fn_M3v!04tz&XBP8H~@I zAxed`@C3_;ctnZ{_?~}k=9dQy(oH)l5=4lQAVoVpoaQ0LvcH|81E1x{Ypc(5g)EJf z)5vD7qAz2HEI#Vi&i0cWBEeiOrk^S89sCiW{9A_ zOAJpA3-i9cINKOvlqm`nm}Hb8wi3tQO{Kp5co0_l<$t!1tyNs&BbE@;Tx131H7if& z*MxAbOKHRbo9D$Kvsn6|z)9v)PQUV-Ex2~Sq^JpE=&j^;Ec@Uot>`uIuH^c=xU@`J zyd6d_xoHq21lw3Va!pxkICxOmNwfQzFw4#%wP;zw-uH2gQ{1db9JVHmBkA|{F zy^ITW$}U?Lok1)YF@R2|^19?gM(K%hWUH8Ul|X@3WDAwiw;IQGloas*ol96QV+ftc zC0BOg*g#1UgUA~B=sJN9G$1=$a^*3cQZ~rDk!{2B5IJPMCD#pO%d&}fWJ8`3IFD?j z-7lRdkU}=A;DB6!+n}Za__y)bB%ByDrm+mPCKlSLf@^p@!CyicQIn26)YulB|4^hs1 z25e@eJjaQGgKaH~EUtx>)2nHkD6f?vK4>0W7igipwDN}iiVz+gRGM)edky3`&j{n> z$urIf=jo&#d$*PP_Tfof7@EJ}mpw{dZ;0X1Zs8a@gCEujN9jFy7UsF|cWK777RH4A z(+~!%7rv2r$r4Oj%Adk9>skysgC(TUj43Tb^DRzbOq9o1LPuJI3Ewg%zHCM?C?)Ry z%&-fu_K07>Ot2ioI+(!{;sz<)N^@H*^Aj8JL6)NC__Ut}oQiWqv#(ub6F&J#lY+%N zj*w)ok{s23Iyg%gKFTtqKXKtYoh+oBMdY}tKhfb6oA6nO&30~)N1UaXjigBuB}$Ss z8|mXLzuJ5vKEVbmpovi|A7X^%R7jLl6pc2%$O$4;)OS2H*8Hcer3&WJ$6L>he?t!; zswT#MUb}AmEA|ni>OyScuEWFb0(Zy~qJ}KyXD-_xcQC;)-6W_{U$L4ljxnq>e3)Z& su^MB7e}oGX2oeYq2oeYq2m}KE19wYc%&+VoivR!s07*qoM6N<$g8N!-_W%F@ literal 0 HcmV?d00001 diff --git a/src/main/res/drawable-xxxhdpi/ic_gps_fixed_white_24dp.png b/src/main/res/drawable-xxxhdpi/ic_gps_fixed_white_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..c55220a5fe5552f886fb309160080630acb8492f GIT binary patch literal 1379 zcmV-p1)TbcP)_+pOT_1^ zKs6(T;Te_lQD7IJ09lSF^wLH>m6Q=9Mj4gVbC8QXB?rh-G=yECnKY6#w`gPq3OOs- z!)?+?W@!wwK%02CpX4NEs64ZpE>hwd{57ls&BC8Q#c_&JK2yR;riBW>gi&CZaN=*V z9%Yyc289c$!FGWvKH)Y)J1SrfF^gM@3Y!I%F@oC%YEc%lg)!WQiQ6l11-E~wKv~KL z-r#n@R)KoH;r{c#M_J4o+!b3G>BMQA;$Q_%;dCpn*PQ+IF-(dK873K~kA0M)JaZSPV?hcOF^=v(&&Spe z+~6zVHqCW5dj1lo(Y>e8yg&<1$331Gy<`DdhVv{%A*Tzcz2*fTqf1hZ60?byt*Na9BV`7D%^L3hxsz`eZh zKgGPnuTkXR!XUbvCIt%kf=+%{>cvD4N=OsBNs|I~=(3cGH_j|3GU8>lk~wsn{TFCO z_XH*62B!K@LY|{*@n4_^U9ULU_=>41aboc@x-u!0(oCTli^=N z(T{j>-$tbjM-WZIQ9ID}2OmmY6kp({F*QX=cteR+bWc%2u4C$2n1i`GbUAVD zWg{6(q^TB;xXQ+Gx`5B<_Mn8E$HZCWr4(HfCB@Gq({1GGl)v$71bO=W4!VA`0*BD0 zS&b4>Ljpf0sPger-)2@|Eje^uC^5A@DopSrO3Z0=8PjPM#UpenN>E~I7$qMgRH4L_ z@(JAolxcwjIGscxXDK~o09l%|9!p2vI5h^D+#N$V?YXp3LmyMZW9u5#o{NcJ(Y*^Y zxvMyV(;&(-%W38+LnKI(CczL_X`%$>nfo{$MFlBPN&=@pP$A_{oW_DKa3~JrG)o;S zglr=X(h$>a;llYX_Ug?1r*zv!|4rcP!_Y6w>ah4YHOkU61Xc^JPXyl z#qAu*R)ILraT{X`%0hl(0=FSz_6jH}N#Qn2r-eID8n-0tZEv?}U>0z@LnX>ERon;M zX4nzNhNnhy!t!aC!S>Zsx`lb|9J|BXa`u~00Y1`AIV#VTb6VUwn58AmO@EEdBFQjF z6Dv{3Sw%B<$s(Cyci7u58%P1N9M8B+J3FbOoH%jHsbVJ`T;?z409le9^Re-@f?>ii z#QOQ#dK~8hIc&;tj@bNe{{ER4*fPr2h1h<-gbv0DYK(&vF5CwY#T?^3rrvRs;)VYN zrI5WmB#R#z9?(ePV)_VZHNSI{NxUTKr;W13`We=DY^H@X^yAde8CuvJeFzs7hzi(E lR3Iu462 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 Wu5P5nfD7_&03a)+Bv~zP6!d>2XX@1e literal 0 HcmV?d00001 diff --git a/src/main/res/drawable/ic_directions_black_24dp.xml b/src/main/res/drawable/ic_directions_black_24dp.xml new file mode 100644 index 000000000..739dd20ee --- /dev/null +++ b/src/main/res/drawable/ic_directions_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/src/main/res/drawable/ic_gps_fixed_black_24dp.xml b/src/main/res/drawable/ic_gps_fixed_black_24dp.xml new file mode 100644 index 000000000..07d6e4694 --- /dev/null +++ b/src/main/res/drawable/ic_gps_fixed_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/src/main/res/drawable/ic_gps_not_fixed_black_24dp.xml b/src/main/res/drawable/ic_gps_not_fixed_black_24dp.xml new file mode 100644 index 000000000..a1e7c4a27 --- /dev/null +++ b/src/main/res/drawable/ic_gps_not_fixed_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/src/main/res/drawable/ic_place_black_24dp.xml b/src/main/res/drawable/ic_place_black_24dp.xml new file mode 100644 index 000000000..e3291a943 --- /dev/null +++ b/src/main/res/drawable/ic_place_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/src/main/res/layout/activity_share_location.xml b/src/main/res/layout/activity_share_location.xml new file mode 100644 index 000000000..96e605aa7 --- /dev/null +++ b/src/main/res/layout/activity_share_location.xml @@ -0,0 +1,99 @@ + + + + + + + + + + + + + + +