Custom place picker to replace places SDK.
This commit is contained in:
parent
83479d11b7
commit
cfcb9a8cdb
19 changed files with 579 additions and 30 deletions
|
@ -457,6 +457,11 @@
|
|||
android:exported="true"
|
||||
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
|
||||
|
||||
<activity
|
||||
android:name=".maps.PlacePickerActivity"
|
||||
android:label="@string/PlacePickerActivity_title"
|
||||
android:theme="@style/TextSecure.LightNoActionBar" />
|
||||
|
||||
<service android:enabled="true" android:name="org.thoughtcrime.securesms.service.WebRtcCallService"/>
|
||||
<service android:enabled="true" android:name=".service.ApplicationMigrationService"/>
|
||||
<service android:enabled="true" android:exported="false" android:name=".service.KeyCachingService"/>
|
||||
|
|
|
@ -76,8 +76,8 @@ dependencies {
|
|||
exclude group: 'com.google.firebase', module: 'firebase-measurement-connector'
|
||||
}
|
||||
|
||||
implementation 'com.google.android.gms:play-services-maps:16.0.0'
|
||||
implementation 'com.google.android.gms:play-services-places:16.0.0'
|
||||
implementation 'com.google.android.gms:play-services-maps:16.1.0'
|
||||
implementation 'com.google.android.gms:play-services-location:16.0.0'
|
||||
implementation 'com.google.android.gms:play-services-auth:16.0.1'
|
||||
|
||||
implementation 'com.google.android.exoplayer:exoplayer-core:2.9.1'
|
||||
|
@ -189,8 +189,8 @@ dependencyVerification {
|
|||
'androidx.lifecycle:lifecycle-extensions:8d4072201b6231d67e4192d608d46b1f5c920845106c9831632c2e3ffe706117',
|
||||
'androidx.lifecycle:lifecycle-common-java8:9edc2d4f589656d470ef03b9c6ece62d335971294b033ec7d9ceb6e361e9aafa',
|
||||
'com.google.firebase:firebase-messaging:e42288e7950d7d3b033d3395a5ac9365d230da3e439a2794ec13e2ef0fbaf078',
|
||||
'com.google.android.gms:play-services-places:2d5c4e4ac3ee5be21b4ec544411bc51d11457b5ae2fa2a5d4539019f87c233c6',
|
||||
'com.google.android.gms:play-services-maps:07f59c5955b759ce7b80ceaeb8261643c5b79acc9f180df2b7c3987658eed2e8',
|
||||
'com.google.android.gms:play-services-maps:ff50cae9e4059416202375597d99cdc8ddefd9cea3f1dc2ff53779a3a12eb480',
|
||||
'com.google.android.gms:play-services-location:240a0fcb9e8e58586e38ea43b69c09ed6e89ea9a0c69770b7634d81dabf5f3a0',
|
||||
'com.google.android.gms:play-services-auth:aec9e1c584d442cb9f59481a50b2c66dc191872607c04d97ecb82dd0eb5149ec',
|
||||
'com.google.android.exoplayer:exoplayer-ui:7a942afcc402ff01e9bf48e8d3942850986710f06562d50a1408aaf04a683151',
|
||||
'com.google.android.exoplayer:exoplayer-core:b6ab34abac36bc2bc6934b7a50008162feca2c0fde91aaf1e8c1c22f2c16e2c0',
|
||||
|
|
BIN
res/drawable-hdpi/marker_shadow.webp
Normal file
BIN
res/drawable-hdpi/marker_shadow.webp
Normal file
Binary file not shown.
After Width: | Height: | Size: 360 B |
BIN
res/drawable-mdpi/marker_shadow.webp
Normal file
BIN
res/drawable-mdpi/marker_shadow.webp
Normal file
Binary file not shown.
After Width: | Height: | Size: 244 B |
BIN
res/drawable-xhdpi/marker_shadow.webp
Normal file
BIN
res/drawable-xhdpi/marker_shadow.webp
Normal file
Binary file not shown.
After Width: | Height: | Size: 506 B |
BIN
res/drawable-xxhdpi/marker_shadow.webp
Normal file
BIN
res/drawable-xxhdpi/marker_shadow.webp
Normal file
Binary file not shown.
After Width: | Height: | Size: 844 B |
BIN
res/drawable-xxxhdpi/marker_shadow.webp
Normal file
BIN
res/drawable-xxxhdpi/marker_shadow.webp
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.4 KiB |
5
res/drawable/ic_check.xml
Normal file
5
res/drawable/ic_check.xml
Normal file
|
@ -0,0 +1,5 @@
|
|||
<vector android:height="24dp" android:tint="#FFFFFF"
|
||||
android:viewportHeight="24.0" android:viewportWidth="24.0"
|
||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="#FF000000" android:pathData="M9,16.17L4.83,12l-1.42,1.41L9,19 21,7l-1.41,-1.41z"/>
|
||||
</vector>
|
9
res/drawable/ic_map_marker.xml
Normal file
9
res/drawable/ic_map_marker.xml
Normal file
|
@ -0,0 +1,9 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="512dp"
|
||||
android:height="512dp"
|
||||
android:viewportWidth="438.536"
|
||||
android:viewportHeight="438.536">
|
||||
<path
|
||||
android:pathData="M322.621,42.825C294.073,14.272 259.619,0 219.268,0c-40.353,0 -74.803,14.275 -103.353,42.825c-28.549,28.549 -42.825,63 -42.825,103.353c0,20.749 3.14,37.782 9.419,51.106l104.21,220.986c2.856,6.276 7.283,11.225 13.278,14.838c5.996,3.617 12.419,5.428 19.273,5.428c6.852,0 13.278,-1.811 19.273,-5.428c5.996,-3.613 10.513,-8.562 13.559,-14.838l103.918,-220.986c6.282,-13.324 9.424,-30.358 9.424,-51.106C365.449,105.825 351.176,71.378 322.621,42.825zM270.942,197.855c-14.273,14.272 -31.497,21.411 -51.674,21.411s-37.401,-7.139 -51.678,-21.411c-14.275,-14.277 -21.414,-31.501 -21.414,-51.678c0,-20.175 7.139,-37.402 21.414,-51.675c14.277,-14.275 31.504,-21.414 51.678,-21.414c20.177,0 37.401,7.139 51.674,21.414c14.274,14.272 21.413,31.5 21.413,51.675C292.355,166.352 285.217,183.575 270.942,197.855z"
|
||||
android:fillColor="#2090ea"/>
|
||||
</vector>
|
91
res/layout/activity_map_bottom_sheet_view.xml
Executable file
91
res/layout/activity_map_bottom_sheet_view.xml
Executable file
|
@ -0,0 +1,91 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="bottom">
|
||||
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/place_chosen_button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="16dp"
|
||||
android:contentDescription="@string/PlacePickerActivity_accept_address"
|
||||
android:scaleType="center"
|
||||
android:tint="@color/white"
|
||||
app:backgroundTint="?attr/colorPrimary"
|
||||
app:elevation="3dp"
|
||||
app:fabSize="normal"
|
||||
app:layout_anchor="@id/root_bottom_sheet"
|
||||
app:layout_anchorGravity="top|end"
|
||||
app:srcCompat="@drawable/ic_check" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/root_bottom_sheet"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="3dp"
|
||||
android:scaleType="fitXY"
|
||||
android:background="@drawable/compose_divider_background"/>
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@color/white">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginBottom="12dp"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text_view_place_name"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="18dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
style="@style/Signal.Text.Body"
|
||||
android:fontFamily="sans-serif-medium"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:textColor="?conversation_item_sent_text_primary_color"
|
||||
tools:text="Short address" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text_view_place_address"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
style="@style/Signal.Text.Preview"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:textColor="?conversation_item_sent_text_secondary_color"
|
||||
tools:text="Precise address" />
|
||||
</LinearLayout>
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/progress_bar_place"
|
||||
style="?android:attr/progressBarStyle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:indeterminate="true"
|
||||
android:visibility="invisible"
|
||||
tools:visibility="visible" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
56
res/layout/activity_place_picker.xml
Normal file
56
res/layout/activity_place_picker.xml
Normal file
|
@ -0,0 +1,56 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context="org.thoughtcrime.securesms.maps.PlacePickerActivity">
|
||||
|
||||
<fragment
|
||||
android:id="@+id/map"
|
||||
android:name="com.google.android.gms.maps.SupportMapFragment"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintVertical_bias="0.0" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/marker_shadow_image_view"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:importantForAccessibility="no"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/map"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:srcCompat="@drawable/marker_shadow" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/marker_image_view"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="47dp"
|
||||
android:adjustViewBounds="true"
|
||||
android:contentDescription="@string/PlacePickerActivity_drop_pin"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@id/marker_shadow_image_view"
|
||||
app:layout_constraintVertical_bias="0.0"
|
||||
app:srcCompat="@drawable/ic_map_marker" />
|
||||
|
||||
<org.thoughtcrime.securesms.maps.SingleAddressBottomSheet
|
||||
android:id="@+id/bottom_sheet"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -547,6 +547,13 @@
|
|||
<string name="PassphrasePromptActivity_ok_button_content_description">Submit passphrase</string>
|
||||
<string name="PassphrasePromptActivity_invalid_passphrase_exclamation">Invalid passphrase!</string>
|
||||
|
||||
<!-- PlacePickerActivity -->
|
||||
<string name="PlacePickerActivity_title">Map</string>
|
||||
|
||||
<string name="PlacePickerActivity_not_a_valid_address">Not a valid Address</string>
|
||||
<string name="PlacePickerActivity_drop_pin">Drop pin</string>
|
||||
<string name="PlacePickerActivity_accept_address">Accept address</string>
|
||||
|
||||
<!-- PlayServicesProblemFragment -->
|
||||
<string name="PlayServicesProblemFragment_the_version_of_google_play_services_you_have_installed_is_not_functioning">The version of Google Play Services you have installed is not functioning correctly. Please reinstall Google Play Services and try again.</string>
|
||||
|
||||
|
|
|
@ -7,12 +7,10 @@ import android.os.Build;
|
|||
import android.util.AttributeSet;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.google.android.gms.location.places.Place;
|
||||
import com.google.android.gms.maps.CameraUpdateFactory;
|
||||
import com.google.android.gms.maps.GoogleMap;
|
||||
import com.google.android.gms.maps.MapView;
|
||||
|
|
|
@ -1,16 +1,18 @@
|
|||
package org.thoughtcrime.securesms.components.location;
|
||||
|
||||
import android.location.Address;
|
||||
import android.net.Uri;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.google.android.gms.location.places.Place;
|
||||
import com.google.android.gms.maps.model.LatLng;
|
||||
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
import org.thoughtcrime.securesms.maps.AddressData;
|
||||
import org.thoughtcrime.securesms.util.JsonUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
|
@ -32,13 +34,17 @@ public class SignalPlace {
|
|||
@JsonProperty
|
||||
private double longitude;
|
||||
|
||||
public SignalPlace(Place place) {
|
||||
this.name = place.getName();
|
||||
this.address = place.getAddress();
|
||||
this.latitude = place.getLatLng().latitude;
|
||||
this.longitude = place.getLatLng().longitude;
|
||||
public SignalPlace(@NonNull AddressData place) {
|
||||
Address address = place.getAddress();
|
||||
|
||||
this.name = "";
|
||||
this.address = address!= null ? address.getAddressLine(0) : "";
|
||||
this.latitude = place.getLatitude();
|
||||
this.longitude = place.getLongitude();
|
||||
}
|
||||
|
||||
@JsonCreator
|
||||
@SuppressWarnings("unused")
|
||||
public SignalPlace() {}
|
||||
|
||||
@JsonIgnore
|
||||
|
|
|
@ -72,7 +72,6 @@ import android.widget.TextView;
|
|||
import android.widget.Toast;
|
||||
|
||||
import com.annimon.stream.Stream;
|
||||
import com.google.android.gms.location.places.ui.PlacePicker;
|
||||
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
import org.greenrobot.eventbus.Subscribe;
|
||||
|
@ -153,6 +152,7 @@ import org.thoughtcrime.securesms.linkpreview.LinkPreview;
|
|||
import org.thoughtcrime.securesms.linkpreview.LinkPreviewRepository;
|
||||
import org.thoughtcrime.securesms.linkpreview.LinkPreviewViewModel;
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
import org.thoughtcrime.securesms.maps.PlacePickerActivity;
|
||||
import org.thoughtcrime.securesms.mediasend.Media;
|
||||
import org.thoughtcrime.securesms.mediasend.MediaSendActivity;
|
||||
import org.thoughtcrime.securesms.mms.AttachmentManager;
|
||||
|
@ -521,7 +521,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||
fragment.reloadList();
|
||||
break;
|
||||
case PICK_LOCATION:
|
||||
SignalPlace place = new SignalPlace(PlacePicker.getPlace(data, this));
|
||||
SignalPlace place = new SignalPlace(PlacePickerActivity.addressFromData(data));
|
||||
attachmentManager.setLocation(place, getCurrentMediaConstraints());
|
||||
break;
|
||||
case PICK_GIF:
|
||||
|
|
57
src/org/thoughtcrime/securesms/maps/AddressData.java
Normal file
57
src/org/thoughtcrime/securesms/maps/AddressData.java
Normal file
|
@ -0,0 +1,57 @@
|
|||
package org.thoughtcrime.securesms.maps;
|
||||
|
||||
import android.location.Address;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
public final class AddressData implements Parcelable {
|
||||
|
||||
private final double latitude;
|
||||
private final double longitude;
|
||||
private final @Nullable Address address;
|
||||
|
||||
AddressData(double latitude, double longitude, @Nullable Address address) {
|
||||
this.latitude = latitude;
|
||||
this.longitude = longitude;
|
||||
this.address = address;
|
||||
}
|
||||
|
||||
public @Nullable Address getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
public double getLongitude() {
|
||||
return longitude;
|
||||
}
|
||||
|
||||
public double getLatitude() {
|
||||
return latitude;
|
||||
}
|
||||
|
||||
public static final Creator<AddressData> CREATOR = new Creator<AddressData>() {
|
||||
@Override
|
||||
public AddressData createFromParcel(Parcel in) {
|
||||
return new AddressData(in.readDouble(),
|
||||
in.readDouble(),
|
||||
Address.CREATOR.createFromParcel(in));
|
||||
}
|
||||
|
||||
@Override
|
||||
public AddressData[] newArray(int size) {
|
||||
return new AddressData[size];
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeDouble(latitude);
|
||||
dest.writeDouble(longitude);
|
||||
dest.writeParcelable(address, flags);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
}
|
243
src/org/thoughtcrime/securesms/maps/PlacePickerActivity.java
Normal file
243
src/org/thoughtcrime/securesms/maps/PlacePickerActivity.java
Normal file
|
@ -0,0 +1,243 @@
|
|||
package org.thoughtcrime.securesms.maps;
|
||||
|
||||
import android.Manifest;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.location.Address;
|
||||
import android.location.Geocoder;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import android.view.animation.OvershootInterpolator;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
import com.google.android.gms.location.FusedLocationProviderClient;
|
||||
import com.google.android.gms.location.LocationServices;
|
||||
import com.google.android.gms.maps.CameraUpdateFactory;
|
||||
import com.google.android.gms.maps.GoogleMap;
|
||||
import com.google.android.gms.maps.SupportMapFragment;
|
||||
import com.google.android.gms.maps.model.LatLng;
|
||||
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* Allows selection of an address from a google map.
|
||||
* <p>
|
||||
* Based on https://github.com/suchoX/PlacePicker
|
||||
*/
|
||||
public final class PlacePickerActivity extends AppCompatActivity {
|
||||
|
||||
private static final String TAG = Log.tag(PlacePickerActivity.class);
|
||||
|
||||
// If it cannot load location for any reason, it defaults to the prime meridian.
|
||||
private static final LatLng PRIME_MERIDIAN = new LatLng(51.4779, -0.0015);
|
||||
private static final String ADDRESS_INTENT = "ADDRESS";
|
||||
private static final float ZOOM = 17.0f;
|
||||
|
||||
private static final int ANIMATION_DURATION = 250;
|
||||
private static final OvershootInterpolator OVERSHOOT_INTERPOLATOR = new OvershootInterpolator();
|
||||
|
||||
private SingleAddressBottomSheet bottomSheet;
|
||||
private Address currentAddress;
|
||||
private LatLng initialLocation;
|
||||
private LatLng currentLocation = new LatLng(0, 0);
|
||||
private AddressLookup addressLookup;
|
||||
private GoogleMap googleMap;
|
||||
|
||||
public static void startActivityForResultAtCurrentLocation(@NonNull Activity activity, int requestCode) {
|
||||
activity.startActivityForResult(new Intent(activity, PlacePickerActivity.class), requestCode);
|
||||
}
|
||||
|
||||
public static AddressData addressFromData(@NonNull Intent data) {
|
||||
return data.getParcelableExtra(ADDRESS_INTENT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_place_picker);
|
||||
|
||||
bottomSheet = findViewById(R.id.bottom_sheet);
|
||||
View markerImage = findViewById(R.id.marker_image_view);
|
||||
View fab = findViewById(R.id.place_chosen_button);
|
||||
|
||||
fab.setOnClickListener(v -> finishWithAddress());
|
||||
|
||||
FusedLocationProviderClient fusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
|
||||
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M ||
|
||||
checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED ||
|
||||
checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED
|
||||
) {
|
||||
fusedLocationClient.getLastLocation()
|
||||
.addOnFailureListener(e -> {
|
||||
Log.e(TAG, "Failed to get location", e);
|
||||
setInitialLocation(PRIME_MERIDIAN);
|
||||
})
|
||||
.addOnSuccessListener(location -> {
|
||||
if (location == null) {
|
||||
Log.w(TAG, "Failed to get location");
|
||||
setInitialLocation(PRIME_MERIDIAN);
|
||||
} else {
|
||||
setInitialLocation(new LatLng(location.getLatitude(), location.getLongitude()));
|
||||
}
|
||||
});
|
||||
} else {
|
||||
Log.w(TAG, "No location permissions");
|
||||
setInitialLocation(PRIME_MERIDIAN);
|
||||
}
|
||||
|
||||
SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map);
|
||||
if (mapFragment == null) throw new AssertionError("No map fragment");
|
||||
|
||||
mapFragment.getMapAsync(googleMap -> {
|
||||
|
||||
setMap(googleMap);
|
||||
|
||||
enableMyLocationButtonIfHaveThePermission(googleMap);
|
||||
|
||||
googleMap.setOnCameraMoveStartedListener(i -> {
|
||||
markerImage.animate()
|
||||
.translationY(-75f)
|
||||
.setInterpolator(OVERSHOOT_INTERPOLATOR)
|
||||
.setDuration(ANIMATION_DURATION)
|
||||
.start();
|
||||
|
||||
bottomSheet.hide();
|
||||
});
|
||||
|
||||
googleMap.setOnCameraIdleListener(() -> {
|
||||
markerImage.animate()
|
||||
.translationY(0f)
|
||||
.setInterpolator(OVERSHOOT_INTERPOLATOR)
|
||||
.setDuration(ANIMATION_DURATION)
|
||||
.start();
|
||||
|
||||
setCurrentLocation(googleMap.getCameraPosition().target);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private void setInitialLocation(@NonNull LatLng latLng) {
|
||||
initialLocation = latLng;
|
||||
|
||||
moveMapToInitialIfPossible();
|
||||
}
|
||||
|
||||
private void setMap(GoogleMap googleMap) {
|
||||
this.googleMap = googleMap;
|
||||
|
||||
moveMapToInitialIfPossible();
|
||||
}
|
||||
|
||||
private void moveMapToInitialIfPossible() {
|
||||
if (initialLocation != null && googleMap != null) {
|
||||
Log.d(TAG, "Moving map to initial location");
|
||||
googleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(initialLocation, ZOOM));
|
||||
setCurrentLocation(initialLocation);
|
||||
}
|
||||
}
|
||||
|
||||
private void setCurrentLocation(LatLng location) {
|
||||
currentLocation = location;
|
||||
bottomSheet.showLoading();
|
||||
lookupAddress(location);
|
||||
}
|
||||
|
||||
private void finishWithAddress() {
|
||||
Intent returnIntent = new Intent();
|
||||
AddressData addressData = new AddressData(currentLocation.latitude, currentLocation.longitude, currentAddress);
|
||||
returnIntent.putExtra(ADDRESS_INTENT, addressData);
|
||||
setResult(RESULT_OK, returnIntent);
|
||||
finish();
|
||||
}
|
||||
|
||||
private void enableMyLocationButtonIfHaveThePermission(GoogleMap googleMap) {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M ||
|
||||
checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED ||
|
||||
checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED)
|
||||
{
|
||||
googleMap.setMyLocationEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
private void lookupAddress(@Nullable LatLng target) {
|
||||
if (addressLookup != null) {
|
||||
addressLookup.cancel(true);
|
||||
}
|
||||
addressLookup = new AddressLookup();
|
||||
addressLookup.execute(target);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
super.onPause();
|
||||
if (addressLookup != null) {
|
||||
addressLookup.cancel(true);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
private class AddressLookup extends AsyncTask<LatLng, Void, Address> {
|
||||
|
||||
private final String TAG = Log.tag(AddressLookup.class);
|
||||
private final Geocoder geocoder;
|
||||
|
||||
AddressLookup() {
|
||||
geocoder = new Geocoder(getApplicationContext(), Locale.getDefault());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Address doInBackground(LatLng... latLngs) {
|
||||
if (latLngs.length == 0) return null;
|
||||
LatLng latLng = latLngs[0];
|
||||
if (latLng == null) return null;
|
||||
try {
|
||||
List<Address> result = geocoder.getFromLocation(latLng.latitude, latLng.longitude, 1);
|
||||
return !result.isEmpty() ? result.get(0) : null;
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "Failed to get address from location", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(@Nullable Address address) {
|
||||
Log.d(TAG, String.format("%s", addressToString(address)));
|
||||
currentAddress = address;
|
||||
if (address != null) {
|
||||
bottomSheet.showResult(address.getLatitude(), address.getLongitude(), addressToShortString(address), addressToString(address));
|
||||
} else {
|
||||
bottomSheet.hide();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static @NonNull String addressToString(@Nullable Address address) {
|
||||
return address != null ? address.getAddressLine(0) : "";
|
||||
}
|
||||
|
||||
private static @NonNull String addressToShortString(@Nullable Address address) {
|
||||
if (address == null) return "";
|
||||
|
||||
String addressLine = address.getAddressLine(0);
|
||||
String[] split = addressLine.split(",");
|
||||
|
||||
if (split.length >= 3) {
|
||||
return split[1].trim() + ", " + split[2].trim();
|
||||
} else if (split.length == 2) {
|
||||
return split[1].trim();
|
||||
} else return split[0].trim();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
package org.thoughtcrime.securesms.maps;
|
||||
|
||||
import android.content.Context;
|
||||
import android.location.Location;
|
||||
import android.text.TextUtils;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.TextView;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.coordinatorlayout.widget.CoordinatorLayout;
|
||||
import com.google.android.material.bottomsheet.BottomSheetBehavior;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
final class SingleAddressBottomSheet extends CoordinatorLayout {
|
||||
|
||||
private TextView placeNameTextView;
|
||||
private TextView placeAddressTextView;
|
||||
private ProgressBar placeProgressBar;
|
||||
private BottomSheetBehavior<View> bottomSheetBehavior;
|
||||
|
||||
public SingleAddressBottomSheet(@NonNull Context context) {
|
||||
super(context);
|
||||
init();
|
||||
}
|
||||
|
||||
public SingleAddressBottomSheet(@NonNull Context context, @Nullable AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
init();
|
||||
}
|
||||
|
||||
public SingleAddressBottomSheet(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
init();
|
||||
}
|
||||
|
||||
private void init() {
|
||||
CoordinatorLayout rootView = (CoordinatorLayout) inflate(getContext(), R.layout.activity_map_bottom_sheet_view, this);
|
||||
|
||||
bottomSheetBehavior = BottomSheetBehavior.from(rootView.findViewById(R.id.root_bottom_sheet));
|
||||
bottomSheetBehavior.setHideable(true);
|
||||
bottomSheetBehavior.setState(BottomSheetBehavior.STATE_HIDDEN);
|
||||
|
||||
bindViews();
|
||||
}
|
||||
|
||||
private void bindViews() {
|
||||
placeNameTextView = findViewById(R.id.text_view_place_name);
|
||||
placeAddressTextView = findViewById(R.id.text_view_place_address);
|
||||
placeProgressBar = findViewById(R.id.progress_bar_place);
|
||||
}
|
||||
|
||||
public void showLoading() {
|
||||
bottomSheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED);
|
||||
placeNameTextView.setText("");
|
||||
placeAddressTextView.setText("");
|
||||
placeProgressBar.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
public void showResult(double latitude, double longitude, String addressToShortString, String addressToString) {
|
||||
bottomSheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED);
|
||||
placeProgressBar.setVisibility(View.GONE);
|
||||
|
||||
if (TextUtils.isEmpty(addressToString)) {
|
||||
String longString = Location.convert(longitude, Location.FORMAT_DEGREES);
|
||||
String latString = Location.convert(latitude, Location.FORMAT_DEGREES);
|
||||
|
||||
placeNameTextView.setText(String.format(Locale.getDefault(), "%s %s", latString, longString));
|
||||
} else {
|
||||
placeNameTextView.setText(addressToShortString);
|
||||
placeAddressTextView.setText(addressToString);
|
||||
}
|
||||
}
|
||||
|
||||
public void hide() {
|
||||
bottomSheetBehavior.setState(BottomSheetBehavior.STATE_HIDDEN);
|
||||
}
|
||||
}
|
|
@ -30,23 +30,17 @@ import android.os.AsyncTask;
|
|||
import android.provider.ContactsContract;
|
||||
import android.provider.MediaStore;
|
||||
import android.provider.OpenableColumns;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import org.thoughtcrime.securesms.TransportOption;
|
||||
import org.thoughtcrime.securesms.mediasend.MediaSendActivity;
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
import android.util.Pair;
|
||||
import android.view.View;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.google.android.gms.common.GooglePlayServicesNotAvailableException;
|
||||
import com.google.android.gms.common.GooglePlayServicesRepairableException;
|
||||
import com.google.android.gms.location.places.ui.PlacePicker;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import org.thoughtcrime.securesms.MediaPreviewActivity;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.TransportOption;
|
||||
import org.thoughtcrime.securesms.attachments.Attachment;
|
||||
import org.thoughtcrime.securesms.components.AudioView;
|
||||
import org.thoughtcrime.securesms.components.DocumentView;
|
||||
|
@ -55,6 +49,9 @@ import org.thoughtcrime.securesms.components.ThumbnailView;
|
|||
import org.thoughtcrime.securesms.components.location.SignalMapView;
|
||||
import org.thoughtcrime.securesms.components.location.SignalPlace;
|
||||
import org.thoughtcrime.securesms.giph.ui.GiphyActivity;
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
import org.thoughtcrime.securesms.maps.PlacePickerActivity;
|
||||
import org.thoughtcrime.securesms.mediasend.MediaSendActivity;
|
||||
import org.thoughtcrime.securesms.permissions.Permissions;
|
||||
import org.thoughtcrime.securesms.providers.BlobProvider;
|
||||
import org.thoughtcrime.securesms.providers.DeprecatedPersistentBlobProvider;
|
||||
|
@ -414,13 +411,7 @@ public class AttachmentManager {
|
|||
.request(Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION)
|
||||
.ifNecessary()
|
||||
.withPermanentDenialDialog(activity.getString(R.string.AttachmentManager_signal_requires_location_information_in_order_to_attach_a_location))
|
||||
.onAllGranted(() -> {
|
||||
try {
|
||||
activity.startActivityForResult(new PlacePicker.IntentBuilder().build(activity), requestCode);
|
||||
} catch (GooglePlayServicesRepairableException | GooglePlayServicesNotAvailableException e) {
|
||||
Log.w(TAG, e);
|
||||
}
|
||||
})
|
||||
.onAllGranted(() -> PlacePickerActivity.startActivityForResultAtCurrentLocation(activity, requestCode))
|
||||
.execute();
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue