3
import android.graphics.Typeface;
4
import android.os.Bundle;
5
import android.os.Handler;
6
import android.view.LayoutInflater;
7
import android.view.Menu;
8
import android.view.MenuItem;
9
import android.view.View;
10
import android.view.ViewGroup;
11
import android.widget.RelativeLayout;
12
import android.widget.TextView;
14
import java.lang.annotation.Retention;
15
import java.util.ArrayList;
18
import ai.nextbillion.gestures.AndroidGesturesManager;
19
import ai.nextbillion.gestures.MoveGestureDetector;
20
import ai.nextbillion.gestures.RotateGestureDetector;
21
import ai.nextbillion.gestures.ShoveGestureDetector;
22
import ai.nextbillion.gestures.StandardScaleGestureDetector;
23
import ai.nextbillion.maps.annotations.Marker;
24
import ai.nextbillion.maps.annotations.MarkerOptions;
25
import ai.nextbillion.maps.camera.CameraPosition;
26
import ai.nextbillion.maps.camera.CameraUpdateFactory;
27
import ai.nextbillion.maps.core.MapView;
28
import ai.nextbillion.maps.core.NextbillionMap;
29
import ai.nextbillion.maps.core.UiSettings;
30
import ai.nextbillion.maps.geometry.LatLng;
31
import ai.nextbillion.utils.FontCache;
32
import ai.nextbillion.utils.ResourceUtils;
33
import androidx.annotation.ColorInt;
34
import androidx.annotation.IntDef;
35
import androidx.annotation.NonNull;
36
import androidx.annotation.Nullable;
37
import androidx.appcompat.app.AppCompatActivity;
38
import androidx.core.content.ContextCompat;
39
import androidx.recyclerview.widget.LinearLayoutManager;
40
import androidx.recyclerview.widget.RecyclerView;
42
import static java.lang.annotation.RetentionPolicy.SOURCE;
45
* Test activity showcasing APIs around gestures implementation.
47
public class GestureDetectorActivity extends AppCompatActivity {
49
private static final int MAX_NUMBER_OF_ALERTS = 30;
51
private MapView mapView;
52
private NextbillionMap nextbillionMap;
53
private RecyclerView recyclerView;
54
private GestureAlertsAdapter gestureAlertsAdapter;
56
private AndroidGesturesManager gesturesManager;
59
private Marker marker;
61
private LatLng focalPointLatLng;
64
protected void onCreate(Bundle savedInstanceState) {
65
super.onCreate(savedInstanceState);
66
setContentView(R.layout.activity_gesture_detector);
68
mapView = findViewById(R.id.mapView);
69
mapView.onCreate(savedInstanceState);
70
mapView.getMapAsync(nextbillionMap -> {
71
GestureDetectorActivity.this.nextbillionMap = nextbillionMap;
72
nextbillionMap.setStyle(StyleConstants.NBMAP_STREETS);
73
CameraPosition cameraPosition = new CameraPosition.Builder()
74
.target(new LatLng(22.70418008712976, 78.66264025041812))
79
nextbillionMap.moveCamera(CameraUpdateFactory.newCameraPosition(cameraPosition));
83
recyclerView = findViewById(R.id.alerts_recycler);
84
recyclerView.setLayoutManager(new LinearLayoutManager(this));
86
gestureAlertsAdapter = new GestureAlertsAdapter();
87
recyclerView.setAdapter(gestureAlertsAdapter);
91
protected void onResume() {
97
protected void onPause() {
99
gestureAlertsAdapter.cancelUpdates();
104
protected void onStart() {
110
protected void onStop() {
116
public void onLowMemory() {
118
mapView.onLowMemory();
122
protected void onDestroy() {
128
protected void onSaveInstanceState(Bundle outState) {
129
super.onSaveInstanceState(outState);
130
mapView.onSaveInstanceState(outState);
133
private void initializeMap() {
134
gesturesManager = nextbillionMap.getGesturesManager();
136
RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) recyclerView.getLayoutParams();
137
layoutParams.height = (int) (mapView.getHeight() / 1.75);
138
layoutParams.width = (mapView.getWidth() / 3);
139
recyclerView.setLayoutParams(layoutParams);
143
fixedFocalPointEnabled(nextbillionMap.getUiSettings().getFocalPoint() != null);
146
public void attachListeners() {
147
nextbillionMap.addOnMoveListener(new NextbillionMap.OnMoveListener() {
149
public void onMoveBegin(@NonNull MoveGestureDetector detector) {
150
gestureAlertsAdapter.addAlert(new GestureAlert(GestureAlert.TYPE_START, "MOVE START"));
154
public void onMove(@NonNull MoveGestureDetector detector) {
155
gestureAlertsAdapter.addAlert(new GestureAlert(GestureAlert.TYPE_PROGRESS, "MOVE PROGRESS"));
159
public void onMoveEnd(@NonNull MoveGestureDetector detector) {
160
gestureAlertsAdapter.addAlert(new GestureAlert(GestureAlert.TYPE_END, "MOVE END"));
161
recalculateFocalPoint();
165
nextbillionMap.addOnRotateListener(new NextbillionMap.OnRotateListener() {
167
public void onRotateBegin(@NonNull RotateGestureDetector detector) {
168
gestureAlertsAdapter.addAlert(new GestureAlert(GestureAlert.TYPE_START, "ROTATE START"));
172
public void onRotate(@NonNull RotateGestureDetector detector) {
173
gestureAlertsAdapter.addAlert(new GestureAlert(GestureAlert.TYPE_PROGRESS, "ROTATE PROGRESS"));
174
recalculateFocalPoint();
178
public void onRotateEnd(@NonNull RotateGestureDetector detector) {
179
gestureAlertsAdapter.addAlert(new GestureAlert(GestureAlert.TYPE_END, "ROTATE END"));
183
nextbillionMap.addOnScaleListener(new NextbillionMap.OnScaleListener() {
185
public void onScaleBegin(@NonNull StandardScaleGestureDetector detector) {
186
gestureAlertsAdapter.addAlert(new GestureAlert(GestureAlert.TYPE_START, "SCALE START"));
187
if (focalPointLatLng != null) {
188
gestureAlertsAdapter.addAlert(new GestureAlert(GestureAlert.TYPE_OTHER, "INCREASING MOVE THRESHOLD"));
189
gesturesManager.getMoveGestureDetector().setMoveThreshold(
190
ResourceUtils.convertDpToPx(GestureDetectorActivity.this, 175));
192
gestureAlertsAdapter.addAlert(new GestureAlert(GestureAlert.TYPE_OTHER, "MANUALLY INTERRUPTING MOVE"));
193
gesturesManager.getMoveGestureDetector().interrupt();
195
recalculateFocalPoint();
199
public void onScale(@NonNull StandardScaleGestureDetector detector) {
200
gestureAlertsAdapter.addAlert(new GestureAlert(GestureAlert.TYPE_PROGRESS, "SCALE PROGRESS"));
204
public void onScaleEnd(@NonNull StandardScaleGestureDetector detector) {
205
gestureAlertsAdapter.addAlert(new GestureAlert(GestureAlert.TYPE_END, "SCALE END"));
207
if (focalPointLatLng != null) {
208
gestureAlertsAdapter.addAlert(new GestureAlert(GestureAlert.TYPE_OTHER, "REVERTING MOVE THRESHOLD"));
209
gesturesManager.getMoveGestureDetector().setMoveThreshold(0f);
214
nextbillionMap.addOnShoveListener(new NextbillionMap.OnShoveListener() {
216
public void onShoveBegin(@NonNull ShoveGestureDetector detector) {
217
gestureAlertsAdapter.addAlert(new GestureAlert(GestureAlert.TYPE_START, "SHOVE START"));
221
public void onShove(@NonNull ShoveGestureDetector detector) {
222
gestureAlertsAdapter.addAlert(new GestureAlert(GestureAlert.TYPE_PROGRESS, "SHOVE PROGRESS"));
226
public void onShoveEnd(@NonNull ShoveGestureDetector detector) {
227
gestureAlertsAdapter.addAlert(new GestureAlert(GestureAlert.TYPE_END, "SHOVE END"));
233
public boolean onCreateOptionsMenu(Menu menu) {
234
getMenuInflater().inflate(R.menu.menu_gestures, menu);
239
public boolean onOptionsItemSelected(MenuItem item) {
240
UiSettings uiSettings = nextbillionMap.getUiSettings();
241
switch (item.getItemId()) {
242
case R.id.menu_gesture_focus_point:
243
fixedFocalPointEnabled(focalPointLatLng == null);
245
case R.id.menu_gesture_animation:
246
uiSettings.setScaleVelocityAnimationEnabled(!uiSettings.isScaleVelocityAnimationEnabled());
247
uiSettings.setRotateVelocityAnimationEnabled(!uiSettings.isRotateVelocityAnimationEnabled());
248
uiSettings.setFlingVelocityAnimationEnabled(!uiSettings.isFlingVelocityAnimationEnabled());
250
case R.id.menu_gesture_rotate:
251
uiSettings.setRotateGesturesEnabled(!uiSettings.isRotateGesturesEnabled());
253
case R.id.menu_gesture_tilt:
254
uiSettings.setTiltGesturesEnabled(!uiSettings.isTiltGesturesEnabled());
256
case R.id.menu_gesture_zoom:
257
uiSettings.setZoomGesturesEnabled(!uiSettings.isZoomGesturesEnabled());
259
case R.id.menu_gesture_scroll:
260
uiSettings.setScrollGesturesEnabled(!uiSettings.isScrollGesturesEnabled());
262
case R.id.menu_gesture_double_tap:
263
uiSettings.setDoubleTapGesturesEnabled(!uiSettings.isDoubleTapGesturesEnabled());
265
case R.id.menu_gesture_quick_zoom:
266
uiSettings.setQuickZoomGesturesEnabled(!uiSettings.isQuickZoomGesturesEnabled());
268
case R.id.menu_gesture_scroll_horizontal:
269
uiSettings.setHorizontalScrollGesturesEnabled(!uiSettings.isHorizontalScrollGesturesEnabled());
272
return super.onOptionsItemSelected(item);
275
private void fixedFocalPointEnabled(boolean enabled) {
277
focalPointLatLng = new LatLng(51.50325, -0.12968);
278
marker = nextbillionMap.addMarker(new MarkerOptions().position(focalPointLatLng));
279
nextbillionMap.easeCamera(CameraUpdateFactory.newLatLngZoom(focalPointLatLng, 16),
280
new NextbillionMap.CancelableCallback() {
282
public void onCancel() {
283
recalculateFocalPoint();
287
public void onFinish() {
288
recalculateFocalPoint();
292
if (marker != null) {
293
nextbillionMap.removeMarker(marker);
296
focalPointLatLng = null;
297
nextbillionMap.getUiSettings().setFocalPoint(null);
301
private void recalculateFocalPoint() {
302
if (focalPointLatLng != null) {
303
nextbillionMap.getUiSettings().setFocalPoint(
304
nextbillionMap.getProjection().toScreenLocation(focalPointLatLng)
309
private static class GestureAlertsAdapter extends RecyclerView.Adapter<GestureAlertsAdapter.ViewHolder> {
311
private boolean isUpdating;
312
private final Handler updateHandler = new Handler();
313
private final List<GestureAlert> alerts = new ArrayList<>();
315
public static class ViewHolder extends RecyclerView.ViewHolder {
317
TextView alertMessageTv;
320
public int textColor;
322
ViewHolder(View view) {
324
Typeface typeface = FontCache.get("Roboto-Regular.ttf", view.getContext());
325
alertMessageTv = view.findViewById(R.id.alert_message);
326
alertMessageTv.setTypeface(typeface);
333
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
334
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_gesture_alert, parent, false);
335
return new ViewHolder(view);
339
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
340
GestureAlert alert = alerts.get(position);
341
holder.alertMessageTv.setText(alert.getMessage());
342
holder.alertMessageTv.setTextColor(
343
ContextCompat.getColor(holder.alertMessageTv.getContext(), alert.getColor()));
347
public int getItemCount() {
348
return alerts.size();
351
void addAlert(GestureAlert alert) {
352
for (GestureAlert gestureAlert : alerts) {
353
if (gestureAlert.getAlertType() != GestureAlert.TYPE_PROGRESS) {
357
if (alert.getAlertType() == GestureAlert.TYPE_PROGRESS && gestureAlert.equals(alert)) {
362
if (getItemCount() >= MAX_NUMBER_OF_ALERTS) {
363
alerts.remove(getItemCount() - 1);
366
alerts.add(0, alert);
369
updateHandler.postDelayed(updateRunnable, 250);
373
private Runnable updateRunnable = new Runnable() {
376
notifyDataSetChanged();
381
void cancelUpdates() {
382
updateHandler.removeCallbacksAndMessages(null);
386
private static class GestureAlert {
388
@IntDef( {TYPE_NONE, TYPE_START, TYPE_PROGRESS, TYPE_END, TYPE_OTHER})
392
static final int TYPE_NONE = 0;
393
static final int TYPE_START = 1;
394
static final int TYPE_END = 2;
395
static final int TYPE_PROGRESS = 3;
396
static final int TYPE_OTHER = 4;
399
private int alertType;
401
private String message;
406
GestureAlert(@Type int alertType, String message) {
407
this.alertType = alertType;
408
this.message = message;
412
color = android.R.color.black;
415
color = android.R.color.holo_red_dark;
418
color = android.R.color.holo_purple;
421
color = android.R.color.holo_orange_dark;
424
color = android.R.color.holo_green_dark;
433
String getMessage() {
442
public boolean equals(Object o) {
446
if (o == null || getClass() != o.getClass()) {
450
GestureAlert that = (GestureAlert) o;
452
if (alertType != that.alertType) {
455
return message != null ? message.equals(that.message) : that.message == null;
459
public int hashCode() {
460
int result = alertType;
461
result = 31 * result + (message != null ? message.hashCode() : 0);