diff --git a/app/src/androidTest/java/com/mapbox/mapboxsdk/plugins/places/autocomplete/ui/PlaceAutocompleteFragmentTest.java b/app/src/androidTest/java/com/mapbox/mapboxsdk/plugins/places/autocomplete/ui/PlaceAutocompleteFragmentTest.java index 948e627d5..ae9990c52 100644 --- a/app/src/androidTest/java/com/mapbox/mapboxsdk/plugins/places/autocomplete/ui/PlaceAutocompleteFragmentTest.java +++ b/app/src/androidTest/java/com/mapbox/mapboxsdk/plugins/places/autocomplete/ui/PlaceAutocompleteFragmentTest.java @@ -4,6 +4,7 @@ import android.graphics.Color; import android.net.wifi.WifiManager; import android.support.test.espresso.action.ViewActions; +import android.support.test.espresso.assertion.ViewAssertions; import android.support.test.rule.ActivityTestRule; import android.support.test.runner.AndroidJUnit4; @@ -22,13 +23,14 @@ import static android.support.test.espresso.action.ViewActions.typeText; import static android.support.test.espresso.assertion.ViewAssertions.matches; import static android.support.test.espresso.matcher.ViewMatchers.hasBackground; +import static android.support.test.espresso.matcher.ViewMatchers.hasFocus; import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed; import static android.support.test.espresso.matcher.ViewMatchers.withHint; import static android.support.test.espresso.matcher.ViewMatchers.withId; +import static android.support.test.espresso.matcher.ViewMatchers.withText; import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.not; import static org.junit.Assert.assertThat; -import static org.mockito.ArgumentMatchers.isNull; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -100,6 +102,36 @@ public void onBackButtonPress_doesInvokeOnCancelCallback() throws Exception { verify(listener, times(1)).onCancel(); } + @Test + public void onClearSearchQueryTextButtonPress_doesClearEditText() throws Exception { + ClearButtonListener clearButtonListener = mock(ClearButtonListener.class); + placeAutocompleteFragment.setOnClearButtonListener(clearButtonListener); + onView(withId(R.id.edittext_search)).check(ViewAssertions.matches((withText("")))); + } + + @Test + public void onClearSearchQueryTextButtonPress_doesInvokeOnCancelCallback() throws Exception { + ClearButtonListener clearButtonListener = mock(ClearButtonListener.class); + placeAutocompleteFragment.setOnClearButtonListener(clearButtonListener); + verify(clearButtonListener, times(1)).onCancel(); + } + + @Test + public void onSearchQueryEditTextPress_doesAddFocusToEditText() throws Exception { + QueryFocusListener searchUiHasFocusListener = mock(QueryFocusListener.class); + placeAutocompleteFragment.setOnSearchUiHasFocusListener(searchUiHasFocusListener); + onView(withId(R.id.edittext_search)).perform(ViewActions.click()); + onView(withId(R.id.edittext_search)).check(matches(hasFocus())); + } + + @Test + public void onResultPress_doesRemoveFocus() throws Exception { + PlaceSelectionListener listener = mock(PlaceSelectionListener.class); + placeAutocompleteFragment.setOnPlaceSelectedListener(listener); + onView(withId(R.id.scroll_view_results)).perform(ViewActions.click()); + onView(withId(R.id.edittext_search)).check(matches(not(hasFocus()))); + } + // // Offline state test // diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 4b893a088..3a72cd5a5 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -32,6 +32,18 @@ android:name="android.support.PARENT_ACTIVITY" android:value=".activity.FeatureOverviewActivity"/> + + + + + reverseGeocodingSwitch.text = if (checked) + getString(R.string.reverse_geocoding_enabled) + else getString(R.string.reverse_geocoding_disabled) + } + + includeSearchUiSwitch.text = getString(R.string.search_ui_enabled) + includeSearchUiSwitch.setOnCheckedChangeListener { compoundButton, checked -> + includeSearchUiSwitch.text = if (checked) + getString(R.string.search_ui_enabled) + else getString(R.string.search_ui_disabled) + } + + userLocationSwitch.text = getString(R.string.user_location_button_enabled) + userLocationSwitch.setOnCheckedChangeListener { compoundButton, checked -> + userLocationSwitch.text = if (checked) + getString(R.string.user_location_button_enabled) + else getString(R.string.user_location_button_disabled) + } + + fabLocationPicker.setOnClickListener { _ -> + Mapbox.getAccessToken()?.let { + startActivityForResult( + PlacePicker.IntentBuilder() + .accessToken(it) + .placeOptions(PlacePickerOptions.builder() + .includeReverseGeocode(reverseGeocodingSwitch.isChecked) + .includeSearch(includeSearchUiSwitch.isChecked) + .includeDeviceLocationButton(userLocationSwitch.isChecked) + .statingCameraPosition(CameraPosition.Builder() + .target(LatLng(40.7544, -73.9862)) + .zoom(16.0) + .build()) + .build()) + .build(this), REQUEST_CODE) + } + } + } + + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + super.onActivityResult(requestCode, resultCode, data) + if (requestCode == REQUEST_CODE && resultCode == Activity.RESULT_OK) { + if (reverseGeocodingSwitch.isChecked) { + val carmenFeature = PlacePicker.getPlace(data) + Toast.makeText(this, carmenFeature?.placeName(), Toast.LENGTH_LONG).show() + } else { + val cameraPosition = PlacePicker.getLastCameraPosition(data) + Toast.makeText(this, cameraPosition.target.toString(), Toast.LENGTH_LONG).show() + } + } + } + + companion object { + private val REQUEST_CODE = 5678 + } +} diff --git a/app/src/main/java/com/mapbox/mapboxsdk/plugins/testapp/activity/places/PickerLauncherActivity.kt b/app/src/main/java/com/mapbox/mapboxsdk/plugins/testapp/activity/places/PickerLauncherActivity.kt index 51ec2d51a..805521961 100644 --- a/app/src/main/java/com/mapbox/mapboxsdk/plugins/testapp/activity/places/PickerLauncherActivity.kt +++ b/app/src/main/java/com/mapbox/mapboxsdk/plugins/testapp/activity/places/PickerLauncherActivity.kt @@ -25,7 +25,7 @@ class PickerLauncherActivity : AppCompatActivity() { else getString(R.string.reverse_geocoding_disabled) } - userLocationSwitch.text = getString(R.string.user_location_button_disabled) + userLocationSwitch.text = getString(R.string.user_location_button_enabled) userLocationSwitch.setOnCheckedChangeListener { compoundButton, checked -> userLocationSwitch.text = if (checked) getString(R.string.user_location_button_enabled) diff --git a/app/src/main/res/layout/activity_picker_autocomplete_combo_launcher.xml b/app/src/main/res/layout/activity_picker_autocomplete_combo_launcher.xml new file mode 100644 index 000000000..42e801c87 --- /dev/null +++ b/app/src/main/res/layout/activity_picker_autocomplete_combo_launcher.xml @@ -0,0 +1,84 @@ + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/activity_picker_launcher.xml b/app/src/main/res/layout/activity_picker_launcher.xml index e53dde63d..f9be9333b 100644 --- a/app/src/main/res/layout/activity_picker_launcher.xml +++ b/app/src/main/res/layout/activity_picker_launcher.xml @@ -33,6 +33,7 @@ app:layout_constraintBottom_toTopOf="@+id/reverseGeocodingSwitch" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.5" + android:checked="true" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/textView" /> diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 51893ab59..37b90241d 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -19,6 +19,7 @@ Building Plugin Places Autocomplete Places Autocomplete Fragment + Autocomplete and Place Picker Combination Create region List regions Place picker @@ -42,6 +43,7 @@ Add 3D Building layer to a Mapbox map. Launch the autocomplete activity. Launch the autocomplete fragment inside an activity + Show the Place Picker and autocomplete UI together. Use a form to create an offline region. List all offline regions. Launch the place picker activity and receive result @@ -62,10 +64,13 @@ Example shows how to launch the Place Picker using the Floating action button and receiving a result in onActivityResult. + PickerAutocompleteCombinedActivity: Example shows how to launch the Place Picker combined with the autocomplete geocoding search UI. Reverse geocoding enabled Reverse geocoding disabled User location button enabled User location button disabled + Search autocomplete UI enabled + Search autocomplete UI disabled Min zoom: %1$d diff --git a/plugin-places/src/main/java/com/mapbox/mapboxsdk/plugins/places/autocomplete/ui/BackButtonListener.java b/plugin-places/src/main/java/com/mapbox/mapboxsdk/plugins/places/autocomplete/ui/BackButtonListener.java new file mode 100644 index 000000000..11403d633 --- /dev/null +++ b/plugin-places/src/main/java/com/mapbox/mapboxsdk/plugins/places/autocomplete/ui/BackButtonListener.java @@ -0,0 +1,11 @@ +package com.mapbox.mapboxsdk.plugins.places.autocomplete.ui; + +/** + * This click interface notifies when the back arrow button is clicked + * in the {@link SearchView}. + */ +public interface BackButtonListener { + + void onBackButtonPress(); + +} diff --git a/plugin-places/src/main/java/com/mapbox/mapboxsdk/plugins/places/autocomplete/ui/ClearButtonListener.java b/plugin-places/src/main/java/com/mapbox/mapboxsdk/plugins/places/autocomplete/ui/ClearButtonListener.java new file mode 100644 index 000000000..55bc97bfe --- /dev/null +++ b/plugin-places/src/main/java/com/mapbox/mapboxsdk/plugins/places/autocomplete/ui/ClearButtonListener.java @@ -0,0 +1,13 @@ +package com.mapbox.mapboxsdk.plugins.places.autocomplete.ui; + +/** + * This click interface notifies when the clear button + * is clickedin the {@link SearchView} to clear the query text in the EditText. + */ +public interface ClearButtonListener { + + void onClearButtonPress(); + + void onCancel(); + +} \ No newline at end of file diff --git a/plugin-places/src/main/java/com/mapbox/mapboxsdk/plugins/places/autocomplete/ui/PlaceAutocompleteFragment.java b/plugin-places/src/main/java/com/mapbox/mapboxsdk/plugins/places/autocomplete/ui/PlaceAutocompleteFragment.java index af3edaa2e..7870f157c 100644 --- a/plugin-places/src/main/java/com/mapbox/mapboxsdk/plugins/places/autocomplete/ui/PlaceAutocompleteFragment.java +++ b/plugin-places/src/main/java/com/mapbox/mapboxsdk/plugins/places/autocomplete/ui/PlaceAutocompleteFragment.java @@ -3,15 +3,21 @@ import android.app.Activity; import android.arch.lifecycle.Observer; import android.arch.lifecycle.ViewModelProviders; +import android.graphics.Color; +import android.graphics.drawable.Drawable; import android.os.Build; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.annotation.Nullable; +import android.support.graphics.drawable.VectorDrawableCompat; import android.support.v4.app.Fragment; +import android.support.v4.graphics.drawable.DrawableCompat; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.ViewTreeObserver; +import android.widget.EditText; +import android.widget.ImageView; import android.widget.ScrollView; import android.widget.Toast; @@ -24,18 +30,23 @@ import com.mapbox.mapboxsdk.plugins.places.autocomplete.viewmodel.PlaceAutocompleteViewModel; import com.mapbox.mapboxsdk.plugins.places.common.PlaceConstants; import com.mapbox.mapboxsdk.plugins.places.common.utils.KeyboardUtils; +import com.mapbox.mapboxsdk.plugins.places.picker.ui.PlacePickerActivity; import java.util.List; import timber.log.Timber; public class PlaceAutocompleteFragment extends Fragment implements ResultClickCallback, - SearchView.QueryListener, SearchView.BackButtonListener, + QueryListener, QueryFocusListener, BackButtonListener, ClearButtonListener, ViewTreeObserver.OnScrollChangedListener { public static final String TAG = "PlaceAutocompleteFragment"; private PlaceSelectionListener placeSelectionListener; + private QueryFocusListener queryFocusListener; + private QueryListener searchQueryListener; + private ClearButtonListener clearButtonListener; + private SearchHistoryCountListener searchHistoryCountListener; private PlaceAutocompleteViewModel viewModel; private ResultView searchHistoryView; private ResultView searchResultView; @@ -48,7 +59,9 @@ public class PlaceAutocompleteFragment extends Fragment implements ResultClickCa private String accessToken; private Integer historyCount; private View rootView; + private Activity context; private int mode; + private EditText searchEditText; public static PlaceAutocompleteFragment newInstance(@NonNull String accessToken) { PlaceAutocompleteFragment fragment = new PlaceAutocompleteFragment(); @@ -81,6 +94,7 @@ public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, } mode = placeOptions.viewMode(); + placeOptions.toolbarColor(); rootView = inflater.inflate( mode == PlaceOptions.MODE_CARDS ? R.layout.mapbox_fragment_autocomplete_card : R.layout.mapbox_fragment_autocomplete_full, @@ -96,6 +110,8 @@ public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); resultScrollView.getViewTreeObserver().addOnScrollChangedListener(this); styleView(); + KeyboardUtils.showKeyboard(context.getWindow().getDecorView()); + searchEditText.requestFocus(); } private void styleView() { @@ -105,19 +121,30 @@ private void styleView() { View toolbar = rootView.findViewById(R.id.toolbar); if (toolbar != null) { toolbar.setBackgroundColor(placeOptions.toolbarColor()); + if (placeOptions.toolbarColor() != Color.WHITE) { + swapUiColor(); + } } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - Activity context = (Activity) rootView.getContext(); + context = (Activity) rootView.getContext(); context.getWindow().setStatusBarColor(placeOptions.statusbarColor()); } searchView = rootView.findViewById(R.id.searchView); searchView.setHint(placeOptions.hint() == null ? getString(R.string.mapbox_plugins_autocomplete_search_hint) : placeOptions.hint()); + + searchEditText = searchView.findViewById(R.id.edittext_search); } } + private void swapUiColor() { + changeBackButtonColorToWhite(); + changeClearSearchTextButtonColorToWhite(); + changeSearchTextColorToWhite(); + } + @Override public void onActivityCreated(@Nullable Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); @@ -153,6 +180,9 @@ public void onScrollChanged() { @Override public void onQueryChange(CharSequence charSequence) { viewModel.onQueryChange(charSequence); + if (searchQueryListener != null) { + searchQueryListener.onQueryChange(charSequence); + } if (charSequence.length() <= 0) { searchResultView.getResultsList().clear(); searchResultView.setVisibility( @@ -162,27 +192,132 @@ public void onQueryChange(CharSequence charSequence) { } } + @Override + public void onClearButtonPress() { + if (clearButtonListener != null) { + clearButtonListener.onClearButtonPress(); + } + } + @Override public void onClick(CarmenFeature carmenFeature) { + searchEditText.clearFocus(); viewModel.saveCarmenFeatureToDatabase(carmenFeature); if (placeSelectionListener != null) { placeSelectionListener.onPlaceSelected(carmenFeature); } } + private void changeBackButtonColorToWhite() { + ImageView clearButtonImageView = searchView.findViewById(R.id.button_search_clear); + Drawable clearButtonVectorDrawable = VectorDrawableCompat.create( + getResources(), + R.drawable.mapbox_ic_clear, + null); + Drawable clearButtonDrawable = DrawableCompat.wrap(clearButtonVectorDrawable); + DrawableCompat.setTint(clearButtonDrawable.mutate(), Color.WHITE); + clearButtonImageView.setImageDrawable(clearButtonDrawable); + } + + private void changeClearSearchTextButtonColorToWhite() { + ImageView backButtonImageView = searchView.findViewById(R.id.button_search_back); + Drawable backButtonVectorDrawable = VectorDrawableCompat.create( + getResources(), + R.drawable.mapbox_ic_arrow_back, + null); + Drawable backButtonDrawable = DrawableCompat.wrap(backButtonVectorDrawable); + DrawableCompat.setTint(backButtonDrawable.mutate(), Color.WHITE); + backButtonImageView.setImageDrawable(backButtonDrawable); + } + + private void changeSearchTextColorToWhite() { + EditText searchEditText = searchView.findViewById(R.id.edittext_search); + if (searchEditText != null) { + searchEditText.setTextColor(Color.WHITE); + searchEditText.setHintTextColor(Color.WHITE); + } + } + @Override public void onDestroyView() { if (resultScrollView != null) { resultScrollView.getViewTreeObserver().removeOnScrollChangedListener(this); } - placeSelectionListener = null; + if (placeSelectionListener != null) { + placeSelectionListener = null; + } + if (placeSelectionListener != null) { + placeSelectionListener = null; + } + if (searchQueryListener != null) { + searchQueryListener = null; + } + if (clearButtonListener != null) { + clearButtonListener = null; + } + if (searchHistoryCountListener != null) { + searchHistoryCountListener = null; + } super.onDestroyView(); } @Override public void onBackButtonPress() { - if (placeSelectionListener != null) { - placeSelectionListener.onCancel(); + if (searchEditText.hasFocus()) { + // Remove focus from the search UI EditText + searchEditText.clearFocus(); + + // Hide the keyboard + KeyboardUtils.hideKeyboard(rootView); + + // Shrink the results CardView if using PlacePickerActivity and search UI is enabled + if (context instanceof PlacePickerActivity) { + if (!((PlacePickerActivity) context).resultsCardViewListIsCollapsed) { + ((PlacePickerActivity) context).adjustResultsCardViewHeight(false); + } + } + } else { + if (placeSelectionListener != null) { + placeSelectionListener.onCancel(); + } + if (queryFocusListener != null) { + queryFocusListener.onCancel(); + } + if (searchQueryListener != null) { + searchQueryListener.onCancel(); + } + if (clearButtonListener != null) { + clearButtonListener.onCancel(); + } + if (searchHistoryCountListener != null) { + searchHistoryCountListener.onCancel(); + } + } + } + + @Override + public void onCancel() { + if (queryFocusListener != null) { + queryFocusListener.onCancel(); + } + if (searchQueryListener != null) { + searchQueryListener.onCancel(); + } + if (queryFocusListener != null) { + queryFocusListener.onCancel(); + } + if (searchQueryListener != null) { + searchQueryListener.onCancel(); + } + if (clearButtonListener != null) { + clearButtonListener.onCancel(); + } + } + + @Override + public void onSearchViewEditTextHasFocus() { + if (queryFocusListener != null) { + queryFocusListener.onSearchViewEditTextHasFocus(); } } @@ -190,12 +325,30 @@ public void setOnPlaceSelectedListener(PlaceSelectionListener listener) { placeSelectionListener = listener; } + public void setOnSearchUiHasFocusListener(QueryFocusListener listener) { + queryFocusListener = listener; + } + + public void setOnSearchQueryListener(QueryListener listener) { + searchQueryListener = listener; + } + + public void setOnClearButtonListener(ClearButtonListener listener) { + clearButtonListener = listener; + } + + public void setOnHistoryCountListener(SearchHistoryCountListener listener) { + searchHistoryCountListener = listener; + } + private void bindClickListeners() { searchHistoryView.setOnItemClickListener(this); searchResultView.setOnItemClickListener(this); starredView.setOnItemClickListener(this); searchView.setBackButtonListener(this); + searchView.setClearButtonListener(this); searchView.setQueryListener(this); + searchView.setQueryFocusListener(this); } private void bindViews() { @@ -212,6 +365,9 @@ private void bindViews() { void updateSearchHistoryView(@Nullable List searchHistoryEntities) { searchHistoryView.getResultsList().clear(); if (searchHistoryEntities != null) { + if (searchHistoryCountListener != null) { + searchHistoryCountListener.onNewHistoryCount(searchHistoryEntities.size()); + } if (placeOptions.historyCount() != null) { historyCount = placeOptions.historyCount(); for (int x = 0; x < historyCount; x++) { @@ -288,4 +444,11 @@ public String getAccessToken() { public Integer getHistoryCount() { return historyCount; } + + public interface SearchHistoryCountListener { + + void onNewHistoryCount(int count); + + void onCancel(); + } } diff --git a/plugin-places/src/main/java/com/mapbox/mapboxsdk/plugins/places/autocomplete/ui/QueryFocusListener.java b/plugin-places/src/main/java/com/mapbox/mapboxsdk/plugins/places/autocomplete/ui/QueryFocusListener.java new file mode 100644 index 000000000..69167ac2a --- /dev/null +++ b/plugin-places/src/main/java/com/mapbox/mapboxsdk/plugins/places/autocomplete/ui/QueryFocusListener.java @@ -0,0 +1,15 @@ +package com.mapbox.mapboxsdk.plugins.places.autocomplete.ui; + +/** + * This interface is used to notify when the search UI EditText is focused on + * in the {@link SearchView}. This is helpful for adjusting the cardview height in + * {@link com.mapbox.mapboxsdk.plugins.places.picker.ui.PlacePickerActivity} + * as a user interacts with the search UI in the toolbar. + */ +public interface QueryFocusListener { + + void onSearchViewEditTextHasFocus(); + + void onCancel(); + +} \ No newline at end of file diff --git a/plugin-places/src/main/java/com/mapbox/mapboxsdk/plugins/places/autocomplete/ui/QueryListener.java b/plugin-places/src/main/java/com/mapbox/mapboxsdk/plugins/places/autocomplete/ui/QueryListener.java new file mode 100644 index 000000000..0f1cca0de --- /dev/null +++ b/plugin-places/src/main/java/com/mapbox/mapboxsdk/plugins/places/autocomplete/ui/QueryListener.java @@ -0,0 +1,13 @@ +package com.mapbox.mapboxsdk.plugins.places.autocomplete.ui; + +/** + * This click interface notifies when the search query text in the + * {@link SearchView} EditText changes. + */ +public interface QueryListener { + + void onQueryChange(CharSequence charSequence); + + void onCancel(); + +} diff --git a/plugin-places/src/main/java/com/mapbox/mapboxsdk/plugins/places/autocomplete/ui/SearchView.java b/plugin-places/src/main/java/com/mapbox/mapboxsdk/plugins/places/autocomplete/ui/SearchView.java index 72f2772bb..5b9cc68d9 100644 --- a/plugin-places/src/main/java/com/mapbox/mapboxsdk/plugins/places/autocomplete/ui/SearchView.java +++ b/plugin-places/src/main/java/com/mapbox/mapboxsdk/plugins/places/autocomplete/ui/SearchView.java @@ -19,17 +19,21 @@ import com.mapbox.mapboxsdk.places.R; public class SearchView extends LinearLayout implements ImageButton.OnClickListener, TextWatcher, - LifecycleObserver { + LifecycleObserver, View.OnFocusChangeListener { @Nullable private BackButtonListener backButtonListener; @Nullable + private ClearButtonListener clearButtonListener; + @Nullable private QueryListener queryListener; + @Nullable + private QueryFocusListener focusListener; private final ImageView backButton; private final ImageView clearButton; private final EditText searchEditText; - + public SearchView(@NonNull Context context) { this(context, null); } @@ -51,6 +55,7 @@ private void initialize() { backButton.setOnClickListener(this); clearButton.setOnClickListener(this); searchEditText.addTextChangedListener(this); + searchEditText.setOnFocusChangeListener(this); ((LifecycleOwner) getContext()).getLifecycle().addObserver(this); } @@ -62,6 +67,18 @@ public void onClick(View view) { } } else { searchEditText.getText().clear(); + if (clearButtonListener != null) { + clearButtonListener.onClearButtonPress(); + } + } + } + + @Override + public void onFocusChange(View view, boolean hasFocus) { + if (view.getId() == searchEditText.getId()) { + if (focusListener != null) { + focusListener.onSearchViewEditTextHasFocus(); + } } } @@ -69,6 +86,8 @@ public void onClick(View view) { public void onDestroy() { backButtonListener = null; queryListener = null; + focusListener = null; + clearButtonListener = null; } public void setHint(String hint) { @@ -76,7 +95,7 @@ public void setHint(String hint) { } @Override - public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) { + public void onTextChanged(CharSequence charSequence, int start, int count, int after) { if (queryListener != null) { queryListener.onQueryChange(charSequence); } @@ -84,7 +103,7 @@ public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) { } @Override - public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) { + public void beforeTextChanged(CharSequence charSequence, int start, int count, int after) { // Not used } @@ -97,15 +116,15 @@ public void setBackButtonListener(@Nullable BackButtonListener backButtonListene this.backButtonListener = backButtonListener; } - public void setQueryListener(@Nullable QueryListener queryListener) { - this.queryListener = queryListener; + public void setClearButtonListener(@Nullable ClearButtonListener clearButtonListener) { + this.clearButtonListener = clearButtonListener; } - interface QueryListener { - void onQueryChange(CharSequence charSequence); + public void setQueryListener(@Nullable QueryListener queryListener) { + this.queryListener = queryListener; } - interface BackButtonListener { - void onBackButtonPress(); + public void setQueryFocusListener(@Nullable QueryFocusListener focusListener) { + this.focusListener = focusListener; } } \ No newline at end of file diff --git a/plugin-places/src/main/java/com/mapbox/mapboxsdk/plugins/places/common/model/BasePlaceOptions.java b/plugin-places/src/main/java/com/mapbox/mapboxsdk/plugins/places/common/model/BasePlaceOptions.java index 56d6c7128..4f9f4f692 100644 --- a/plugin-places/src/main/java/com/mapbox/mapboxsdk/plugins/places/common/model/BasePlaceOptions.java +++ b/plugin-places/src/main/java/com/mapbox/mapboxsdk/plugins/places/common/model/BasePlaceOptions.java @@ -16,4 +16,6 @@ public interface BasePlaceOptions { Integer toolbarColor(); + Integer statusBarColor(); + } \ No newline at end of file diff --git a/plugin-places/src/main/java/com/mapbox/mapboxsdk/plugins/places/picker/model/PlacePickerOptions.java b/plugin-places/src/main/java/com/mapbox/mapboxsdk/plugins/places/picker/model/PlacePickerOptions.java index 0090ac2bc..a5a256212 100644 --- a/plugin-places/src/main/java/com/mapbox/mapboxsdk/plugins/places/picker/model/PlacePickerOptions.java +++ b/plugin-places/src/main/java/com/mapbox/mapboxsdk/plugins/places/picker/model/PlacePickerOptions.java @@ -37,10 +37,20 @@ public abstract class PlacePickerOptions implements BasePlaceOptions, Parcelable public abstract boolean includeDeviceLocationButton(); + public abstract boolean includeSearch(); + + @Nullable + @Override + public abstract Integer statusBarColor(); + + @Nullable + public abstract String mapStyle(); + public static Builder builder() { return new AutoValue_PlacePickerOptions.Builder() .includeReverseGeocode(true) - .includeDeviceLocationButton(false); + .includeDeviceLocationButton(false) + .includeSearch(false); } @AutoValue.Builder @@ -66,7 +76,7 @@ public Builder geocodingTypes(@NonNull @GeocodingTypeCriteria String... geocodin * geocoding information associated with coordinates at the center of the map. A new * geocoding call is made every time the map is moved when true is passed through * includeReverseGeocode(). - * + * @param includeReverseGeocode whether or not to make a reverse geocoding call to * retrieve and display information associated with * the picked location's coordinates. Defaults to true. @@ -87,6 +97,33 @@ public Builder geocodingTypes(@NonNull @GeocodingTypeCriteria String... geocodin */ public abstract Builder includeDeviceLocationButton(boolean includeDeviceLocationButton); + /** + * @param includeSearch whether or not to include autocomplete geocoding search + * field with the Place Picker UI. Defaults to false. + * + * @return this builder instance for chaining options together + */ + public abstract Builder includeSearch(boolean includeSearch); + + /** + * Set the {@link com.mapbox.mapboxsdk.plugins.places.picker.ui.PlacePickerActivity}'s layout + * status bar color. Defaults to the app theme's primary color. + * + * @param statusBarColor the views status bar color as a ColorInt + * @return this builder instance for chaining options together + */ + public abstract Builder statusBarColor(@ColorInt Integer statusBarColor); + + /** + * Set the {@link com.mapbox.mapboxsdk.plugins.places.picker.ui.PlacePickerActivity}'s + * map style. Defaults to {@link com.mapbox.mapboxsdk.maps.Style#MAPBOX_STREETS} if + * this option isn't used when building this {@link PlacePickerOptions} class. + * + * @param customMapStyleUrl a map style URL to use in the Place Picker. + * @return this builder instance for chaining options together + */ + public abstract Builder mapStyle(String customMapStyleUrl); + public abstract PlacePickerOptions build(); } } diff --git a/plugin-places/src/main/java/com/mapbox/mapboxsdk/plugins/places/picker/ui/PlacePickerActivity.java b/plugin-places/src/main/java/com/mapbox/mapboxsdk/plugins/places/picker/ui/PlacePickerActivity.java index 5c5f2b03c..331fcfa2f 100644 --- a/plugin-places/src/main/java/com/mapbox/mapboxsdk/plugins/places/picker/ui/PlacePickerActivity.java +++ b/plugin-places/src/main/java/com/mapbox/mapboxsdk/plugins/places/picker/ui/PlacePickerActivity.java @@ -2,20 +2,33 @@ import android.arch.lifecycle.Observer; import android.arch.lifecycle.ViewModelProviders; +import android.content.Context; import android.content.Intent; +import android.content.res.TypedArray; import android.location.Location; +import android.os.Build; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.constraint.ConstraintLayout; +import android.support.design.widget.AppBarLayout; import android.support.design.widget.FloatingActionButton; import android.support.design.widget.Snackbar; +import android.support.v4.app.FragmentTransaction; import android.support.v7.app.ActionBar; import android.support.v7.app.AppCompatActivity; +import android.support.v7.widget.CardView; +import android.transition.ChangeBounds; +import android.transition.TransitionManager; +import android.transition.TransitionSet; +import android.util.TypedValue; import android.view.View; +import android.view.ViewGroup; import android.view.Window; import android.view.animation.OvershootInterpolator; +import android.widget.FrameLayout; import android.widget.ImageView; +import android.widget.LinearLayout; import android.widget.Toast; import com.google.gson.JsonObject; @@ -23,6 +36,7 @@ import com.mapbox.android.core.permissions.PermissionsManager; import com.mapbox.api.geocoding.v5.models.CarmenFeature; import com.mapbox.geojson.Point; +import com.mapbox.mapboxsdk.Mapbox; import com.mapbox.mapboxsdk.camera.CameraPosition; import com.mapbox.mapboxsdk.camera.CameraUpdateFactory; import com.mapbox.mapboxsdk.geometry.LatLng; @@ -35,8 +49,15 @@ import com.mapbox.mapboxsdk.maps.OnMapReadyCallback; import com.mapbox.mapboxsdk.maps.Style; import com.mapbox.mapboxsdk.places.R; +import com.mapbox.mapboxsdk.plugins.places.autocomplete.model.PlaceOptions; +import com.mapbox.mapboxsdk.plugins.places.autocomplete.ui.ClearButtonListener; +import com.mapbox.mapboxsdk.plugins.places.autocomplete.ui.PlaceAutocompleteFragment; +import com.mapbox.mapboxsdk.plugins.places.autocomplete.ui.PlaceSelectionListener; +import com.mapbox.mapboxsdk.plugins.places.autocomplete.ui.QueryFocusListener; +import com.mapbox.mapboxsdk.plugins.places.autocomplete.ui.QueryListener; import com.mapbox.mapboxsdk.plugins.places.common.PlaceConstants; import com.mapbox.mapboxsdk.plugins.places.common.utils.ColorUtils; +import com.mapbox.mapboxsdk.plugins.places.common.utils.KeyboardUtils; import com.mapbox.mapboxsdk.plugins.places.picker.PlacePicker; import com.mapbox.mapboxsdk.plugins.places.picker.PlacePicker.IntentBuilder; import com.mapbox.mapboxsdk.plugins.places.picker.model.PlacePickerOptions; @@ -56,12 +77,19 @@ * @since 0.2.0 */ public class PlacePickerActivity extends AppCompatActivity implements OnMapReadyCallback, - MapboxMap.OnCameraMoveStartedListener, MapboxMap.OnCameraIdleListener, Observer, + MapboxMap.OnCameraMoveStartedListener, MapboxMap.OnMapClickListener, + MapboxMap.OnCameraIdleListener, Observer, PermissionsListener { + public int COLLAPSED_SEARCH_CARDVIEW_HEIGHT; + public boolean includeReverseGeocode; + public boolean includeDeviceLocationButton; + public Boolean resultsCardViewListIsCollapsed = true; + private final int EXPANDED_SEARCH_CARDVIEW_HEIGHT = 555; + private final int SPACE_BETWEEN_RESULTS_LIST_AND_COMPASS = 3; private PermissionsManager permissionsManager; - CurrentPlaceSelectionBottomSheet bottomSheet; - CarmenFeature carmenFeature; + private CurrentPlaceSelectionBottomSheet bottomSheet; + private CarmenFeature carmenFeature; private PlacePickerViewModel viewModel; private PlacePickerOptions options; private ImageView markerImage; @@ -69,7 +97,12 @@ public class PlacePickerActivity extends AppCompatActivity implements OnMapReady private String accessToken; private MapView mapView; private FloatingActionButton userLocationButton; - private boolean includeReverseGeocode; + private CardView searchCardView; + private CardView searchResultsCardView; + private int searchHistoryCount; + private boolean includeSearch; + private Integer customToolbarColor; + private String customMapStyle; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { @@ -83,12 +116,19 @@ protected void onCreate(@Nullable Bundle savedInstanceState) { if (actionBar != null) { actionBar.hide(); } + + COLLAPSED_SEARCH_CARDVIEW_HEIGHT = getToolBarHeight(); + setContentView(R.layout.mapbox_activity_place_picker); if (savedInstanceState == null) { accessToken = getIntent().getStringExtra(PlaceConstants.ACCESS_TOKEN); options = getIntent().getParcelableExtra(PlaceConstants.PLACE_OPTIONS); includeReverseGeocode = options.includeReverseGeocode(); + includeDeviceLocationButton = options.includeDeviceLocationButton(); + includeSearch = options.includeSearch(); + customMapStyle = options.mapStyle(); + customToolbarColor = options.toolbarColor(); } // Initialize the view model. @@ -96,10 +136,14 @@ protected void onCreate(@Nullable Bundle savedInstanceState) { viewModel.getResults().observe(this, this); bindViews(); - addBackButtonListener(); + if (includeSearch) { + AppBarLayout appBarLayout = findViewById(R.id.place_picker_app_bar_layout); + appBarLayout.setVisibility(View.GONE); + } else { + addBackButtonListener(); + setToolbarColor(); + } addPlaceSelectedButton(); - customizeViews(); - mapView.onCreate(savedInstanceState); mapView.getMapAsync(this); } @@ -124,38 +168,187 @@ private void bindViews() { private void bindListeners() { PlacePickerActivity.this.mapboxMap.addOnCameraMoveStartedListener(PlacePickerActivity.this); PlacePickerActivity.this.mapboxMap.addOnCameraIdleListener(PlacePickerActivity.this); + searchResultsCardView = findViewById(R.id.optional_search_autocomplete_cardview); } - private void customizeViews() { + private void setToolbarColor() { ConstraintLayout toolbar = findViewById(R.id.place_picker_toolbar); - if (options != null && options.toolbarColor() != null) { - toolbar.setBackgroundColor(options.toolbarColor()); - } else { - int color = ColorUtils.getMaterialColor(this, R.attr.colorPrimary); - toolbar.setBackgroundColor(color); - } + toolbar.setBackgroundColor(customToolbarColor != null + ? customToolbarColor : ColorUtils.getMaterialColor( + this, R.attr.colorPrimary)); } @Override public void onMapReady(final MapboxMap mapboxMap) { this.mapboxMap = mapboxMap; - mapboxMap.setStyle(Style.MAPBOX_STREETS, new Style.OnStyleLoaded() { - @Override - public void onStyleLoaded(@NonNull Style style) { - adjustCameraBasedOnOptions(); - if (includeReverseGeocode) { - // Initialize with the marker's current coordinates. - makeReverseGeocodingSearch(); - } - bindListeners(); + mapboxMap.setStyle(new Style.Builder().fromUri(customMapStyle != null + ? customMapStyle : Style.MAPBOX_STREETS), new Style.OnStyleLoaded() { + @Override + public void onStyleLoaded(@NonNull Style style) { + adjustCameraBasedOnOptions(); + if (includeReverseGeocode) { + // Initialize with the marker's current coordinates. + makeReverseGeocodingSearch(); + if (includeDeviceLocationButton) { + adjustBottomMarginOfFabLinearLayout(135); + } else { + adjustBottomMarginOfFabLinearLayout(7); + } + } + + bindListeners(); + + if (options != null && includeDeviceLocationButton) { + enableLocationComponent(style); + addUserLocationButton(); + } else { + userLocationButton.hide(); + } + + if (options != null) { + if (options.startingBounds() != null) { + mapboxMap.moveCamera(CameraUpdateFactory.newLatLngBounds(options.startingBounds(), 0)); + } else if (options.statingCameraPosition() != null) { + mapboxMap.moveCamera(CameraUpdateFactory.newCameraPosition(options.statingCameraPosition())); + } + + if (includeSearch) { + searchCardView = findViewById(R.id.optional_search_autocomplete_cardview); + searchCardView.setVisibility(View.VISIBLE); + + adjustMapCompassTopPadding(false); + + PlaceAutocompleteFragment autocompleteFragment = PlaceAutocompleteFragment.newInstance( + Mapbox.getAccessToken(), initPlaceOptions()); + + FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); + transaction + .add(R.id.optional_search_autocomplete_cardview_fragment_container, + autocompleteFragment, PlaceAutocompleteFragment.TAG) + .commit(); + + autocompleteFragment.setOnClearButtonListener(new ClearButtonListener() { + @Override + public void onClearButtonPress() { + adjustResultsCardViewHeight(false); + } + + @Override + public void onCancel() { + finish(); + } + }); + + // Update the search history count to determine whether the search UI should + // be expanded when the EditText is focused on. + autocompleteFragment.setOnHistoryCountListener( + new PlaceAutocompleteFragment.SearchHistoryCountListener() { + @Override + public void onNewHistoryCount(int count) { + searchHistoryCount = count; + } + + @Override + public void onCancel() { + finish(); + } + }); + + // Set up what should happen when the search UI EditText is focused on + autocompleteFragment.setOnSearchUiHasFocusListener(new QueryFocusListener() { + @Override + public void onSearchViewEditTextHasFocus() { + if (searchHistoryCount > 0) { + adjustResultsCardViewHeight(true); + } + } + + @Override + public void onCancel() { + finish(); + } + }); + + // Expand the search UI cardview height when typing happens in the EditText. + autocompleteFragment.setOnSearchQueryListener(new QueryListener() { + @Override + public void onQueryChange(CharSequence charSequence) { + // charSequence not needed here in this activity. The cardview height + // will adjust once text query change has changed. + adjustResultsCardViewHeight(true); + } + + @Override + public void onCancel() { + finish(); + } + }); + + // Expand the search UI cardview height and move the map when a place is selected. + autocompleteFragment.setOnPlaceSelectedListener(new PlaceSelectionListener() { + @Override + public void onPlaceSelected(CarmenFeature carmenFeature) { + PlacePickerActivity.this.carmenFeature = carmenFeature; + + // Adjust the height of the cardview that has the list of search results + adjustResultsCardViewHeight(false); + + // Hide the keyboard once a place has been selected + KeyboardUtils.hideKeyboard(getWindow().getDecorView()); + + // Move camera to selected location + mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom( + new LatLng(carmenFeature.center().latitude(), + carmenFeature.center().longitude()), mapboxMap.getCameraPosition().zoom)); + } + + @Override + public void onCancel() { + finish(); + } + }); + } + } + + PlacePickerActivity.this.mapboxMap.addOnMapClickListener(PlacePickerActivity.this); + PlacePickerActivity.this.mapboxMap.addOnCameraMoveStartedListener(PlacePickerActivity.this); + PlacePickerActivity.this.mapboxMap.addOnCameraIdleListener(PlacePickerActivity.this); + } + }); + } - if (options != null && options.includeDeviceLocationButton()) { - enableLocationComponent(style); - } else { - userLocationButton.hide(); - } - } - }); + private void adjustBottomMarginOfFabLinearLayout(int newBottom) { + View placeChosenButton = findViewById(R.id.place_chosen_button); + LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) placeChosenButton.getLayoutParams(); + params.bottomMargin = newBottom; + placeChosenButton.setLayoutParams(params); + } + + /** + * Initialize {@link PlaceOptions} to use when creating an instance of {@link PlaceAutocompleteFragment} + * if search was enabled in the {@link PlacePickerOptions}. + * + * @return a fully built {@link PlaceOptions} object. + */ + private PlaceOptions initPlaceOptions() { + int toolbarColor = customToolbarColor != null ? customToolbarColor + : getThemePrimaryColor(PlacePickerActivity.this); + int statusBarColor = options.statusBarColor() != null ? options.statusBarColor() + : getThemePrimaryDarkColor(PlacePickerActivity.this); + return PlaceOptions.builder() + .toolbarColor(toolbarColor) + .statusbarColor(statusBarColor) + .hint(getString(R.string.mapbox_plugins_autocomplete_search_hint)) + .build(); + } + + @Override + public boolean onMapClick(@NonNull LatLng point) { + if (!resultsCardViewListIsCollapsed) { + adjustResultsCardViewHeight(false); + KeyboardUtils.hideKeyboard(getWindow().getDecorView()); + } + return true; } private void adjustCameraBasedOnOptions() { @@ -189,7 +382,6 @@ private void enableLocationComponent(@NonNull Style loadedMapStyle) { // Set the component's render mode locationComponent.setRenderMode(RenderMode.NORMAL); - addUserLocationButton(); } else { permissionsManager = new PermissionsManager(this); permissionsManager.requestLocationPermissions(this); @@ -213,7 +405,7 @@ public void onPermissionResult(boolean granted) { mapboxMap.getStyle(new Style.OnStyleLoaded() { @Override public void onStyleLoaded(@NonNull Style style) { - if (options != null && options.includeDeviceLocationButton()) { + if (options != null && includeDeviceLocationButton) { enableLocationComponent(style); } } @@ -221,6 +413,85 @@ public void onStyleLoaded(@NonNull Style style) { } } + /** + * Adjusts the height of the {@link PlaceAutocompleteFragment} CardView. + * + * @param expandCard whether or not the height should be lengthened. + */ + public void adjustResultsCardViewHeight(boolean expandCard) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + TransitionManager.beginDelayedTransition(searchResultsCardView, new TransitionSet() + .addTransition(new ChangeBounds())); + ViewGroup.LayoutParams params = searchResultsCardView.getLayoutParams(); + params.height = expandCard ? EXPANDED_SEARCH_CARDVIEW_HEIGHT : COLLAPSED_SEARCH_CARDVIEW_HEIGHT; + searchResultsCardView.setLayoutParams(params); + } else { + searchResultsCardView.setLayoutParams(new FrameLayout.LayoutParams( + searchResultsCardView.getMeasuredWidth(), expandCard ? EXPANDED_SEARCH_CARDVIEW_HEIGHT + : COLLAPSED_SEARCH_CARDVIEW_HEIGHT)); + } + adjustMapTopPadding(expandCard); + adjustMapCompassTopPadding(expandCard); + resultsCardViewListIsCollapsed = !expandCard; + } + + private void adjustMapTopPadding(boolean cardExpanded) { + int[] mapPadding = mapboxMap.getPadding(); + mapboxMap.setPadding(mapPadding[0], cardExpanded ? EXPANDED_SEARCH_CARDVIEW_HEIGHT + : COLLAPSED_SEARCH_CARDVIEW_HEIGHT, + mapPadding[2], mapPadding[3]); + } + + private void adjustMapCompassTopPadding(boolean cardExpanded) { + int[] mapPadding = mapboxMap.getPadding(); + int newTopPadding; + newTopPadding = cardExpanded + ? EXPANDED_SEARCH_CARDVIEW_HEIGHT + SPACE_BETWEEN_RESULTS_LIST_AND_COMPASS + : COLLAPSED_SEARCH_CARDVIEW_HEIGHT + SPACE_BETWEEN_RESULTS_LIST_AND_COMPASS; + mapboxMap.getUiSettings().setCompassMargins(mapPadding[0], + newTopPadding, mapPadding[2], mapPadding[3]); + } + + /** + * Get the primary color from the app's theming. + * + * @param context this activity's context. + * @return an int value representing the theme's primary color + */ + private static int getThemePrimaryColor(Context context) { + int colorAttr; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + colorAttr = android.R.attr.colorPrimary; + } else { + //Get colorAccent defined for AppCompat + colorAttr = context.getResources().getIdentifier("colorPrimary", "attr", + context.getPackageName()); + } + TypedValue outValue = new TypedValue(); + context.getTheme().resolveAttribute(colorAttr, outValue, true); + return outValue.data; + } + + /** + * Get the primary dark color from the app's theming. + * + * @param context this activity's context. + * @return an int value representing the theme's primary dark color + */ + private static int getThemePrimaryDarkColor(Context context) { + int colorAttr; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + colorAttr = android.R.attr.colorPrimaryDark; + } else { + //Get colorAccent defined for AppCompat + colorAttr = context.getResources().getIdentifier("colorPrimaryDark", + "attr", context.getPackageName()); + } + TypedValue outValue = new TypedValue(); + context.getTheme().resolveAttribute(colorAttr, outValue, true); + return outValue.data; + } + @Override public void onCameraMoveStarted(int reason) { Timber.v("Map camera has begun moving."); @@ -241,7 +512,13 @@ public void onCameraIdle() { markerImage.animate().translationY(0) .setInterpolator(new OvershootInterpolator()).setDuration(250).start(); if (includeReverseGeocode) { - bottomSheet.setPlaceDetails(null); + if (includeSearch) { + if (carmenFeature != null) { + bottomSheet.setPlaceDetails(carmenFeature); + } + } else { + bottomSheet.setPlaceDetails(null); + } // Initialize with the markers current location information. makeReverseGeocodingSearch(); } @@ -287,8 +564,8 @@ public void onClick(View view) { } /** - * Bind the device location Floating Action Button to this activity's UI and move the - * map camera if the button's clicked. + * Bind the device location Floating Action Button to this activity's UI and animate the + * map camera to the device's location if the button's clicked. */ private void addUserLocationButton() { userLocationButton.show(); @@ -300,10 +577,10 @@ public void onClick(View view) { mapboxMap.animateCamera(CameraUpdateFactory.newCameraPosition( new CameraPosition.Builder() .target(new LatLng(lastKnownLocation.getLatitude(), - lastKnownLocation.getLongitude())) + lastKnownLocation.getLongitude())) .zoom(17.5) .build() - ),1400); + ), 1400); } else { Toast.makeText(PlacePickerActivity.this, getString(R.string.mapbox_plugins_place_picker_user_location_not_found), Toast.LENGTH_SHORT).show(); @@ -323,6 +600,14 @@ void placeSelected() { finish(); } + public int getToolBarHeight() { + int[] attrs = new int[] {R.attr.actionBarSize}; + TypedArray ta = this.obtainStyledAttributes(attrs); + int toolBarHeight = ta.getDimensionPixelSize(0, -1); + ta.recycle(); + return toolBarHeight; + } + @Override protected void onStart() { super.onStart(); diff --git a/plugin-places/src/main/res/drawable/mapbox_ic_arrow_back.xml b/plugin-places/src/main/res/drawable/mapbox_ic_arrow_back.xml index beafea395..4933d7f7b 100644 --- a/plugin-places/src/main/res/drawable/mapbox_ic_arrow_back.xml +++ b/plugin-places/src/main/res/drawable/mapbox_ic_arrow_back.xml @@ -4,6 +4,6 @@ android:viewportWidth="24.0" android:viewportHeight="24.0"> diff --git a/plugin-places/src/main/res/drawable/mapbox_ic_clear.xml b/plugin-places/src/main/res/drawable/mapbox_ic_clear.xml index ede4b7108..3edee749b 100644 --- a/plugin-places/src/main/res/drawable/mapbox_ic_clear.xml +++ b/plugin-places/src/main/res/drawable/mapbox_ic_clear.xml @@ -4,6 +4,6 @@ android:viewportWidth="24.0" android:viewportHeight="24.0"> diff --git a/plugin-places/src/main/res/layout/mapbox_activity_place_picker.xml b/plugin-places/src/main/res/layout/mapbox_activity_place_picker.xml index ed0987f6c..cf242b5e3 100644 --- a/plugin-places/src/main/res/layout/mapbox_activity_place_picker.xml +++ b/plugin-places/src/main/res/layout/mapbox_activity_place_picker.xml @@ -1,20 +1,35 @@ - - - + android:layout_height="match_parent" + tools:context="com.mapbox.mapboxsdk.plugins.places.picker.ui.PlacePickerActivity"> - + - + - + - \ No newline at end of file + + + + + + + + + + + \ No newline at end of file diff --git a/plugin-places/src/main/res/layout/mapbox_content_place_picker.xml b/plugin-places/src/main/res/layout/mapbox_content_place_picker.xml index 802c0ea44..98f46fb69 100644 --- a/plugin-places/src/main/res/layout/mapbox_content_place_picker.xml +++ b/plugin-places/src/main/res/layout/mapbox_content_place_picker.xml @@ -34,7 +34,7 @@ android:id="@+id/map_view" android:layout_width="0dp" android:layout_height="0dp" - app:mapbox_uiLogo="false" + app:mapbox_uiLogo="true" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" diff --git a/plugin-places/src/main/res/layout/mapbox_view_bottom_sheet_container.xml b/plugin-places/src/main/res/layout/mapbox_view_bottom_sheet_container.xml index 345604a26..10b26004b 100644 --- a/plugin-places/src/main/res/layout/mapbox_view_bottom_sheet_container.xml +++ b/plugin-places/src/main/res/layout/mapbox_view_bottom_sheet_container.xml @@ -1,47 +1,20 @@ - - - - - + app:srcCompat="@drawable/mapbox_logo_icon" /> + + app:layout_anchorGravity="top" /> - + + + + + + + + + \ No newline at end of file diff --git a/plugin-places/src/main/res/layout/mapbox_view_search.xml b/plugin-places/src/main/res/layout/mapbox_view_search.xml index f6aea32f4..f194980ee 100644 --- a/plugin-places/src/main/res/layout/mapbox_view_search.xml +++ b/plugin-places/src/main/res/layout/mapbox_view_search.xml @@ -20,10 +20,10 @@ android:imeOptions="actionSearch|flagNoExtractUi" android:inputType="textNoSuggestions" android:singleLine="true" + android:textCursorDrawable="@null" android:textColor="@color/mapbox_plugins_navy" android:textColorHint="@color/mapbox_plugins_light_navy" android:textColorLink="@color/mapbox_plugins_navy" - android:textCursorDrawable="@drawable/mapbox_color_text_cursor" android:textSize="16sp" android:typeface="sans" app:layout_constraintBottom_toBottomOf="parent" @@ -41,7 +41,6 @@ android:contentDescription="@string/mapbox_plugins_cd_search_clear_button" android:focusable="true" android:scaleType="center" - android:tint="@color/mapbox_plugins_navy" android:visibility="invisible" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" @@ -63,7 +62,6 @@ android:paddingRight="20dp" android:paddingStart="0dp" android:scaleType="center" - android:tint="@color/mapbox_plugins_navy" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" diff --git a/plugin-places/src/test/java/com/mapbox/mapboxsdk/plugins/places/picker/PlacePickerTest.java b/plugin-places/src/test/java/com/mapbox/mapboxsdk/plugins/places/picker/PlacePickerTest.java index 08511c9dd..89fec1713 100644 --- a/plugin-places/src/test/java/com/mapbox/mapboxsdk/plugins/places/picker/PlacePickerTest.java +++ b/plugin-places/src/test/java/com/mapbox/mapboxsdk/plugins/places/picker/PlacePickerTest.java @@ -7,7 +7,9 @@ import com.mapbox.api.geocoding.v5.models.CarmenFeature; import com.mapbox.mapboxsdk.camera.CameraPosition; import com.mapbox.mapboxsdk.geometry.LatLng; +import com.mapbox.mapboxsdk.maps.Style; import com.mapbox.mapboxsdk.plugins.places.common.PlaceConstants; +import com.mapbox.mapboxsdk.plugins.places.picker.model.PlacePickerOptions; import org.junit.Ignore; import org.junit.Test; @@ -72,6 +74,25 @@ public void intentBuilder_initializesCorrectly() throws Exception { assertNotNull(builder); } + @Test + public void intentBuilder_initializesCorrectlyWithSearchIncluded() throws Exception { + PlacePicker.IntentBuilder builder = new PlacePicker.IntentBuilder(); + builder.placeOptions(PlacePickerOptions.builder() + .includeReverseGeocode(true) + .includeSearch(true) + .build()); + assertNotNull(builder); + } + + @Test + public void intentBuilder_initializesCorrectlyWithCustomMapStyleIncluded() throws Exception { + PlacePicker.IntentBuilder builder = new PlacePicker.IntentBuilder(); + builder.placeOptions(PlacePickerOptions.builder() + .mapStyle(Style.SATELLITE) + .build()); + assertNotNull(builder); + } + // TODO finish mocking this class @Test @Ignore diff --git a/scripts/exclude-activity-gen.json b/scripts/exclude-activity-gen.json index 1e2bc88eb..e3837c9d0 100644 --- a/scripts/exclude-activity-gen.json +++ b/scripts/exclude-activity-gen.json @@ -9,5 +9,6 @@ "LocationLayerFragmentActivity", "LocationLayerMapChangeActivity", "LocationLayerModesActivity", - "ManualLocationUpdatesActivity" + "ManualLocationUpdatesActivity", + "PickerAutocompleteCombinedActivity" ]