├── .gitignore ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── pubnub │ │ └── tutorials │ │ └── map │ │ └── android │ │ └── pubnubmaptutorialandroid │ │ ├── Constants.java │ │ ├── LoginActivity.java │ │ ├── MainActivity.java │ │ ├── MainActivityTabManager.java │ │ ├── flightpaths │ │ ├── FlightPathsMapAdapter.java │ │ ├── FlightPathsPnCallback.java │ │ └── FlightPathsTabContentFragment.java │ │ ├── locationpublish │ │ ├── LocationHelper.java │ │ ├── LocationPublishMapAdapter.java │ │ ├── LocationPublishPnCallback.java │ │ └── LocationPublishTabContentFragment.java │ │ ├── locationsubscribe │ │ ├── LocationSubscribeMapAdapter.java │ │ ├── LocationSubscribePnCallback.java │ │ └── LocationSubscribeTabContentFragment.java │ │ └── util │ │ └── JsonUtil.java │ └── res │ ├── layout │ ├── activity_login.xml │ ├── activity_main.xml │ ├── fragment_flightpaths.xml │ ├── fragment_locationpublish.xml │ └── fragment_locationsubscribe.xml │ ├── mipmap-hdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-mdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xxhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xxxhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ └── values │ ├── colors.xml │ ├── strings.xml │ └── styles.xml ├── build.gradle ├── gradle.properties └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | .idea 4 | /local.properties 5 | /.idea/workspace.xml 6 | /.idea/libraries 7 | .DS_Store 8 | /build 9 | /captures 10 | .externalNativeBuild 11 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 25 5 | buildToolsVersion "26.0.2" 6 | defaultConfig { 7 | applicationId "com.pubnub.tutorials.map.android.pubnubmaptutorialandroid" 8 | minSdkVersion 23 9 | targetSdkVersion 25 10 | versionCode 1 11 | versionName "1.0" 12 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | packagingOptions { 21 | exclude 'META-INF/DEPENDENCIES.txt' 22 | exclude 'META-INF/LICENSE.txt' 23 | exclude 'META-INF/NOTICE.txt' 24 | exclude 'META-INF/NOTICE' 25 | exclude 'META-INF/LICENSE' 26 | exclude 'META-INF/DEPENDENCIES' 27 | exclude 'META-INF/notice.txt' 28 | exclude 'META-INF/license.txt' 29 | exclude 'META-INF/dependencies.txt' 30 | exclude 'META-INF/LGPL2.1' 31 | } 32 | } 33 | 34 | dependencies { 35 | compile fileTree(dir: 'libs', include: ['*.jar']) 36 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { 37 | exclude group: 'com.android.support', module: 'support-annotations' 38 | exclude group: 'com.google.code.findbugs', module: 'jsr305' 39 | }) 40 | compile group: 'com.pubnub', name: 'pubnub-gson', version: '4.12.0' 41 | compile group: 'com.fasterxml.jackson.core', name: 'jackson-core', version: '2.9.2' 42 | compile group: 'com.fasterxml.jackson.core', name: 'jackson-annotations', version: '2.9.2' 43 | compile group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.9.2' 44 | compile group: 'com.google.guava', name: 'guava', version: '23.2-android' 45 | compile 'com.google.android.gms:play-services:11.0.4' 46 | compile 'com.android.support:appcompat-v7:25.3.1' 47 | compile 'com.android.support:design:25.3.1' 48 | compile 'com.android.support:support-v4:25.3.1' 49 | compile 'com.android.support.constraint:constraint-layout:1.0.2' 50 | testCompile 'junit:junit:4.12' 51 | } 52 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /Users/sunny/android-sdks/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | 19 | # Uncomment this to preserve the line number information for 20 | # debugging stack traces. 21 | #-keepattributes SourceFile,LineNumberTable 22 | 23 | # If you keep the line number information, uncomment this to 24 | # hide the original source file name. 25 | #-renamesourcefileattribute SourceFile 26 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /app/src/main/java/com/pubnub/tutorials/map/android/pubnubmaptutorialandroid/Constants.java: -------------------------------------------------------------------------------- 1 | package com.pubnub.tutorials.map.android.pubnubmaptutorialandroid; 2 | 3 | public class Constants { 4 | public static final String PUBNUB_PUBLISH_KEY = "YOUR_PUB_KEY"; 5 | public static final String PUBNUB_SUBSCRIBE_KEY = "YOUR_SUB_KEY"; 6 | 7 | public static final String SUBSCRIBE_CHANNEL_NAME = "basic_location_subscribe"; 8 | public static final String PUBLISH_CHANNEL_NAME = "basic_location_publish"; 9 | public static final String FLIGHTPATHS_CHANNEL_NAME = "basic_flightpaths_subscribe"; 10 | 11 | public static final String DATASTREAM_PREFS = "com.pubnub.tutorials.map.android.pubnubmaptutorialandroid.DATASTREAM_PREFS"; 12 | public static final String DATASTREAM_UUID = "com.pubnub.tutorials.map.android.pubnubmaptutorialandroid.DATASTREAM_UUID"; 13 | } 14 | -------------------------------------------------------------------------------- /app/src/main/java/com/pubnub/tutorials/map/android/pubnubmaptutorialandroid/LoginActivity.java: -------------------------------------------------------------------------------- 1 | package com.pubnub.tutorials.map.android.pubnubmaptutorialandroid; 2 | 3 | import android.content.Intent; 4 | import android.content.SharedPreferences; 5 | import android.os.Bundle; 6 | import android.support.v7.app.AppCompatActivity; 7 | import android.view.View; 8 | import android.widget.EditText; 9 | 10 | public class LoginActivity extends AppCompatActivity { 11 | private EditText mUsername; 12 | 13 | private static boolean isValid(String username) { 14 | return username.matches("^[a-zA-Z0-9_]+$"); 15 | } 16 | 17 | @Override 18 | protected void onCreate(Bundle savedInstanceState) { 19 | super.onCreate(savedInstanceState); 20 | setContentView(R.layout.activity_login); 21 | 22 | mUsername = (EditText) findViewById(R.id.usernameEdit); 23 | } 24 | 25 | public void joinChat(View view) { 26 | String username = mUsername.getText().toString(); 27 | 28 | if (!isValid(username)) { 29 | return; 30 | } 31 | 32 | SharedPreferences sp = getSharedPreferences(Constants.DATASTREAM_PREFS, MODE_PRIVATE); 33 | SharedPreferences.Editor edit = sp.edit(); 34 | edit.putString(Constants.DATASTREAM_UUID, username); 35 | edit.apply(); 36 | 37 | Intent intent = new Intent(this, MainActivity.class); 38 | startActivity(intent); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /app/src/main/java/com/pubnub/tutorials/map/android/pubnubmaptutorialandroid/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.pubnub.tutorials.map.android.pubnubmaptutorialandroid; 2 | 3 | import android.content.Intent; 4 | import android.content.SharedPreferences; 5 | import android.os.Bundle; 6 | import android.support.annotation.NonNull; 7 | import android.support.design.widget.TabLayout; 8 | import android.support.v4.view.ViewPager; 9 | import android.support.v7.app.AppCompatActivity; 10 | 11 | import com.pubnub.api.PNConfiguration; 12 | import com.pubnub.api.PubNub; 13 | 14 | import java.util.Random; 15 | 16 | public class MainActivity extends AppCompatActivity { 17 | private SharedPreferences mSharedPrefs; 18 | private PubNub pubNub; 19 | private String userName; 20 | private Random random; 21 | 22 | @Override 23 | protected void onCreate(Bundle savedInstanceState) { 24 | super.onCreate(savedInstanceState); 25 | 26 | mSharedPrefs = getSharedPreferences(Constants.DATASTREAM_PREFS, MODE_PRIVATE); 27 | if (!mSharedPrefs.contains(Constants.DATASTREAM_UUID)) { 28 | Intent toLogin = new Intent(this, LoginActivity.class); 29 | startActivity(toLogin); 30 | return; 31 | } 32 | 33 | setContentView(R.layout.activity_main); 34 | 35 | this.random = new Random(); 36 | this.userName = mSharedPrefs.getString(Constants.DATASTREAM_UUID, "anonymous_" + random.nextInt(10000)); 37 | this.pubNub = initPubNub(this.userName); 38 | 39 | TabLayout tabLayout = (TabLayout) findViewById(R.id.tab_layout); 40 | tabLayout.addTab(tabLayout.newTab().setText("1_Marker")); 41 | tabLayout.addTab(tabLayout.newTab().setText("2_Live_Location")); 42 | tabLayout.addTab(tabLayout.newTab().setText("3_Flightpath")); 43 | tabLayout.setTabGravity(TabLayout.GRAVITY_FILL); 44 | 45 | final ViewPager viewPager = (ViewPager) findViewById(R.id.pager); 46 | final MainActivityTabManager adapter = new MainActivityTabManager 47 | (getSupportFragmentManager(), tabLayout.getTabCount(), pubNub); 48 | 49 | viewPager.setAdapter(adapter); 50 | viewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabLayout)); 51 | tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() { 52 | @Override 53 | public void onTabSelected(TabLayout.Tab tab) { 54 | viewPager.setCurrentItem(tab.getPosition()); 55 | } 56 | 57 | @Override 58 | public void onTabUnselected(TabLayout.Tab tab) { 59 | } 60 | 61 | @Override 62 | public void onTabReselected(TabLayout.Tab tab) { 63 | } 64 | }); 65 | } 66 | 67 | @NonNull 68 | private PubNub initPubNub(String userName) { 69 | PNConfiguration pnConfiguration = new PNConfiguration(); 70 | pnConfiguration.setPublishKey(Constants.PUBNUB_PUBLISH_KEY); 71 | pnConfiguration.setSubscribeKey(Constants.PUBNUB_SUBSCRIBE_KEY); 72 | pnConfiguration.setSecure(true); 73 | pnConfiguration.setUuid(userName); 74 | 75 | return new PubNub(pnConfiguration); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /app/src/main/java/com/pubnub/tutorials/map/android/pubnubmaptutorialandroid/MainActivityTabManager.java: -------------------------------------------------------------------------------- 1 | package com.pubnub.tutorials.map.android.pubnubmaptutorialandroid; 2 | 3 | import android.support.v4.app.Fragment; 4 | import android.support.v4.app.FragmentManager; 5 | import android.support.v4.app.FragmentStatePagerAdapter; 6 | 7 | import com.google.common.collect.ImmutableList; 8 | import com.pubnub.api.PubNub; 9 | import com.pubnub.tutorials.map.android.pubnubmaptutorialandroid.flightpaths.FlightPathsTabContentFragment; 10 | import com.pubnub.tutorials.map.android.pubnubmaptutorialandroid.locationpublish.LocationPublishTabContentFragment; 11 | import com.pubnub.tutorials.map.android.pubnubmaptutorialandroid.locationsubscribe.LocationSubscribeTabContentFragment; 12 | 13 | public class MainActivityTabManager extends FragmentStatePagerAdapter { 14 | private final LocationSubscribeTabContentFragment locationSubscribe; 15 | private final LocationPublishTabContentFragment locationPublish; 16 | private final FlightPathsTabContentFragment flightPathsTabContentFragment; 17 | 18 | private ImmutableList items; 19 | 20 | public MainActivityTabManager(FragmentManager fm, int NumOfTabs, PubNub pubNub) { 21 | super(fm); 22 | 23 | this.locationSubscribe = new LocationSubscribeTabContentFragment(); 24 | this.locationSubscribe.setPubNub(pubNub); 25 | 26 | this.locationPublish = new LocationPublishTabContentFragment(); 27 | this.locationPublish.setPubNub(pubNub); 28 | 29 | this.flightPathsTabContentFragment = new FlightPathsTabContentFragment(); 30 | this.flightPathsTabContentFragment.setPubNub(pubNub); 31 | 32 | this.items = ImmutableList.of((Fragment) locationSubscribe, (Fragment) locationPublish, (Fragment) flightPathsTabContentFragment); 33 | } 34 | 35 | @Override 36 | public Fragment getItem(int position) { 37 | return this.items.get(position); 38 | } 39 | 40 | @Override 41 | public int getCount() { 42 | return this.items.size(); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /app/src/main/java/com/pubnub/tutorials/map/android/pubnubmaptutorialandroid/flightpaths/FlightPathsMapAdapter.java: -------------------------------------------------------------------------------- 1 | package com.pubnub.tutorials.map.android.pubnubmaptutorialandroid.flightpaths; 2 | 3 | import android.app.Activity; 4 | import android.util.Log; 5 | 6 | import com.google.android.gms.maps.CameraUpdateFactory; 7 | import com.google.android.gms.maps.GoogleMap; 8 | import com.google.android.gms.maps.model.LatLng; 9 | import com.google.android.gms.maps.model.Polyline; 10 | import com.google.android.gms.maps.model.PolylineOptions; 11 | 12 | import java.util.ArrayList; 13 | import java.util.List; 14 | import java.util.Map; 15 | 16 | public class FlightPathsMapAdapter { 17 | private static final String TAG = FlightPathsMapAdapter.class.getName(); 18 | 19 | private Polyline polyline; 20 | private Activity activity; 21 | private GoogleMap map; 22 | 23 | private List polylinePoints; 24 | 25 | public FlightPathsMapAdapter(Activity activity, GoogleMap map) { 26 | this.activity = activity; 27 | this.map = map; 28 | this.polylinePoints = new ArrayList<>(); 29 | } 30 | 31 | public void locationUpdated(final Map newLocation) { 32 | if (newLocation.containsKey("lat") && newLocation.containsKey("lng")) { 33 | String lat = newLocation.get("lat"); 34 | String lng = newLocation.get("lng"); 35 | 36 | doUiUpdate(new LatLng(Double.parseDouble(lat), Double.parseDouble(lng))); 37 | } else { 38 | Log.w(TAG, "message ignored: " + newLocation.toString()); 39 | } 40 | } 41 | 42 | private void doUiUpdate(final LatLng location) { 43 | activity.runOnUiThread(new Runnable() { 44 | @Override 45 | public void run() { 46 | polylinePoints.add(location); 47 | 48 | if (polyline != null) { 49 | polyline.setPoints(polylinePoints); 50 | } else { 51 | polyline = map.addPolyline(new PolylineOptions().addAll(polylinePoints)); 52 | } 53 | 54 | map.moveCamera(CameraUpdateFactory.newLatLng(location)); 55 | } 56 | }); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /app/src/main/java/com/pubnub/tutorials/map/android/pubnubmaptutorialandroid/flightpaths/FlightPathsPnCallback.java: -------------------------------------------------------------------------------- 1 | package com.pubnub.tutorials.map.android.pubnubmaptutorialandroid.flightpaths; 2 | 3 | import android.util.Log; 4 | 5 | import com.pubnub.api.PubNub; 6 | import com.pubnub.api.callbacks.SubscribeCallback; 7 | import com.pubnub.api.models.consumer.PNStatus; 8 | import com.pubnub.api.models.consumer.pubsub.PNMessageResult; 9 | import com.pubnub.api.models.consumer.pubsub.PNPresenceEventResult; 10 | import com.pubnub.tutorials.map.android.pubnubmaptutorialandroid.util.JsonUtil; 11 | 12 | import java.util.LinkedHashMap; 13 | import java.util.Map; 14 | 15 | public class FlightPathsPnCallback extends SubscribeCallback { 16 | private static final String TAG = FlightPathsPnCallback.class.getName(); 17 | private FlightPathsMapAdapter flightPathsMapAdapter; 18 | private String watchChannel; 19 | 20 | public FlightPathsPnCallback(FlightPathsMapAdapter flightPathsMapAdapter, String watchChannel) { 21 | this.flightPathsMapAdapter = flightPathsMapAdapter; 22 | this.watchChannel = watchChannel; 23 | } 24 | 25 | @Override 26 | public void status(PubNub pubnub, PNStatus status) { 27 | Log.d(TAG, "status: " + status.toString()); 28 | } 29 | 30 | @Override 31 | public void message(PubNub pubnub, PNMessageResult message) { 32 | if (!message.getChannel().equals(watchChannel)) { 33 | return; 34 | } 35 | 36 | try { 37 | Log.d(TAG, "message: " + message.toString()); 38 | 39 | Map newLocation = JsonUtil.fromJson(message.getMessage().toString(), LinkedHashMap.class); 40 | flightPathsMapAdapter.locationUpdated(newLocation); 41 | } catch (Exception e) { 42 | throw new RuntimeException(e); 43 | } 44 | } 45 | 46 | @Override 47 | public void presence(PubNub pubnub, PNPresenceEventResult presence) { 48 | if (!presence.getChannel().equals(watchChannel)) { 49 | return; 50 | } 51 | 52 | Log.d(TAG, "presence: " + presence.toString()); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /app/src/main/java/com/pubnub/tutorials/map/android/pubnubmaptutorialandroid/flightpaths/FlightPathsTabContentFragment.java: -------------------------------------------------------------------------------- 1 | package com.pubnub.tutorials.map.android.pubnubmaptutorialandroid.flightpaths; 2 | 3 | import android.app.Activity; 4 | import android.os.Bundle; 5 | import android.support.v4.app.Fragment; 6 | import android.util.Log; 7 | import android.view.LayoutInflater; 8 | import android.view.View; 9 | import android.view.ViewGroup; 10 | 11 | import com.google.android.gms.maps.GoogleMap; 12 | import com.google.android.gms.maps.OnMapReadyCallback; 13 | import com.google.android.gms.maps.SupportMapFragment; 14 | import com.google.common.collect.ImmutableMap; 15 | import com.pubnub.api.PubNub; 16 | import com.pubnub.api.callbacks.PNCallback; 17 | import com.pubnub.api.models.consumer.PNPublishResult; 18 | import com.pubnub.api.models.consumer.PNStatus; 19 | import com.pubnub.tutorials.map.android.pubnubmaptutorialandroid.Constants; 20 | import com.pubnub.tutorials.map.android.pubnubmaptutorialandroid.R; 21 | import com.pubnub.tutorials.map.android.pubnubmaptutorialandroid.util.JsonUtil; 22 | 23 | import java.util.Arrays; 24 | import java.util.Map; 25 | import java.util.Random; 26 | import java.util.concurrent.Executors; 27 | import java.util.concurrent.ScheduledExecutorService; 28 | import java.util.concurrent.TimeUnit; 29 | 30 | public class FlightPathsTabContentFragment extends Fragment implements OnMapReadyCallback { 31 | private static final String TAG = FlightPathsTabContentFragment.class.getName(); 32 | private static final Double generatorOriginLat = 37.8199; 33 | private static final Double generatorOriginLng = -122.4783; 34 | private PubNub pubNub; 35 | private GoogleMap map; 36 | private String userName; 37 | private ScheduledExecutorService executorService; 38 | private Random random = new Random(); 39 | private Long startTime; 40 | 41 | private static ImmutableMap getNewLocationMessage(String userName, int randomLat, int randomLng, long elapsedTime) { 42 | String newLat = Double.toString(generatorOriginLat + ((randomLat + elapsedTime) * 0.000003)); 43 | String newLng = Double.toString(generatorOriginLng + ((randomLng + elapsedTime) * 0.00001)); 44 | 45 | return ImmutableMap.of("who", userName, "lat", newLat, "lng", newLng); 46 | } 47 | 48 | @Override 49 | public View onCreateView(LayoutInflater inflater, ViewGroup container, 50 | Bundle savedInstanceState) { 51 | View view = inflater.inflate(R.layout.fragment_flightpaths, container, false); 52 | 53 | SupportMapFragment mapFragment = (SupportMapFragment) getChildFragmentManager() 54 | .findFragmentById(R.id.map_flightpaths); 55 | mapFragment.getMapAsync(this); 56 | 57 | return view; 58 | } 59 | 60 | public void setPubNub(PubNub pubNub) { 61 | this.pubNub = pubNub; 62 | this.userName = this.pubNub.getConfiguration().getUuid(); 63 | } 64 | 65 | @Override 66 | public void onMapReady(GoogleMap map) { 67 | this.map = map; 68 | 69 | pubNub.addListener(new FlightPathsPnCallback(new FlightPathsMapAdapter((Activity) this.getContext(), map), Constants.FLIGHTPATHS_CHANNEL_NAME)); 70 | pubNub.subscribe().channels(Arrays.asList(Constants.FLIGHTPATHS_CHANNEL_NAME)).execute(); 71 | 72 | scheduleRandomUpdates(); 73 | } 74 | 75 | private void scheduleRandomUpdates() { 76 | this.executorService = Executors.newSingleThreadScheduledExecutor(); 77 | this.startTime = System.currentTimeMillis(); 78 | 79 | this.executorService.scheduleAtFixedRate(new Runnable() { 80 | @Override 81 | public void run() { 82 | ((Activity) FlightPathsTabContentFragment.this.getContext()).runOnUiThread(new Runnable() { 83 | @Override 84 | public void run() { 85 | int randomLat = random.nextInt(10); 86 | int randomLng = random.nextInt(10); 87 | long elapsedTime = System.currentTimeMillis() - startTime; 88 | 89 | final Map message = getNewLocationMessage(userName, randomLat, randomLng, elapsedTime); 90 | 91 | pubNub.publish().channel(Constants.FLIGHTPATHS_CHANNEL_NAME).message(message).async( 92 | new PNCallback() { 93 | @Override 94 | public void onResponse(PNPublishResult result, PNStatus status) { 95 | try { 96 | if (!status.isError()) { 97 | Log.v(TAG, "publish(" + JsonUtil.asJson(result) + ")"); 98 | } else { 99 | Log.v(TAG, "publishErr(" + status.toString() + ")"); 100 | } 101 | } catch (Exception e) { 102 | e.printStackTrace(); 103 | } 104 | } 105 | } 106 | ); 107 | } 108 | }); 109 | } 110 | }, 0, 5, TimeUnit.SECONDS); 111 | } 112 | } -------------------------------------------------------------------------------- /app/src/main/java/com/pubnub/tutorials/map/android/pubnubmaptutorialandroid/locationpublish/LocationHelper.java: -------------------------------------------------------------------------------- 1 | package com.pubnub.tutorials.map.android.pubnubmaptutorialandroid.locationpublish; 2 | 3 | 4 | import android.content.Context; 5 | import android.location.Location; 6 | import android.os.Bundle; 7 | import android.support.annotation.NonNull; 8 | import android.support.annotation.Nullable; 9 | import android.util.Log; 10 | 11 | import com.google.android.gms.common.ConnectionResult; 12 | import com.google.android.gms.common.api.GoogleApiClient; 13 | import com.google.android.gms.location.LocationListener; 14 | import com.google.android.gms.location.LocationRequest; 15 | import com.google.android.gms.location.LocationServices; 16 | import com.pubnub.tutorials.map.android.pubnubmaptutorialandroid.util.JsonUtil; 17 | 18 | public class LocationHelper implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, LocationListener { 19 | private GoogleApiClient mGoogleApiClient; 20 | private LocationListener mLocationListener; 21 | 22 | public LocationHelper(Context context, LocationListener mLocationListener) { 23 | this.mGoogleApiClient = new GoogleApiClient.Builder(context) 24 | .addConnectionCallbacks(this) 25 | .addOnConnectionFailedListener(this) 26 | .addApi(LocationServices.API) 27 | .build(); 28 | 29 | this.mGoogleApiClient.connect(); 30 | 31 | this.mLocationListener = mLocationListener; 32 | } 33 | 34 | public void connect() { 35 | this.mGoogleApiClient.connect(); 36 | } 37 | 38 | public void disconnect() { 39 | this.mGoogleApiClient.disconnect(); 40 | } 41 | 42 | @Override 43 | public void onConnected(@Nullable Bundle bundle) { 44 | try { 45 | Location lastLocation = LocationServices.FusedLocationApi.getLastLocation( 46 | mGoogleApiClient); 47 | 48 | if (lastLocation != null) { 49 | onLocationChanged(lastLocation); 50 | } 51 | } catch (SecurityException e) { 52 | Log.v("locationDenied", e.getMessage()); 53 | } 54 | 55 | try { 56 | LocationRequest locationRequest = LocationRequest.create().setInterval(5000); 57 | 58 | LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, locationRequest, this); 59 | } catch (SecurityException e) { 60 | Log.v("locationDenied", e.getMessage()); 61 | } 62 | } 63 | 64 | @Override 65 | public void onConnectionFailed(@NonNull ConnectionResult connectionResult) { 66 | Log.v("googlePlayDenied", connectionResult.toString()); 67 | } 68 | 69 | @Override 70 | public void onLocationChanged(Location location) { 71 | try { 72 | Log.v("locationChanged", JsonUtil.asJson(location)); 73 | } catch (Exception e) { 74 | throw new RuntimeException(e); 75 | } 76 | 77 | mLocationListener.onLocationChanged(location); 78 | } 79 | 80 | @Override 81 | public void onConnectionSuspended(int i) { 82 | mLocationListener.onLocationChanged(null); 83 | } 84 | } -------------------------------------------------------------------------------- /app/src/main/java/com/pubnub/tutorials/map/android/pubnubmaptutorialandroid/locationpublish/LocationPublishMapAdapter.java: -------------------------------------------------------------------------------- 1 | package com.pubnub.tutorials.map.android.pubnubmaptutorialandroid.locationpublish; 2 | 3 | import android.app.Activity; 4 | import android.util.Log; 5 | 6 | import com.google.android.gms.maps.CameraUpdateFactory; 7 | import com.google.android.gms.maps.GoogleMap; 8 | import com.google.android.gms.maps.model.LatLng; 9 | import com.google.android.gms.maps.model.Marker; 10 | import com.google.android.gms.maps.model.MarkerOptions; 11 | 12 | import java.util.Map; 13 | 14 | public class LocationPublishMapAdapter { 15 | private static final String TAG = LocationPublishMapAdapter.class.getName(); 16 | 17 | private Marker marker; 18 | private Activity activity; 19 | private GoogleMap map; 20 | 21 | public LocationPublishMapAdapter(Activity activity, GoogleMap map) { 22 | this.activity = activity; 23 | this.map = map; 24 | } 25 | 26 | public void locationUpdated(final Map newLocation) { 27 | if (newLocation.containsKey("lat") && newLocation.containsKey("lng")) { 28 | String lat = newLocation.get("lat"); 29 | String lng = newLocation.get("lng"); 30 | 31 | doUiUpdate(new LatLng(Double.parseDouble(lat), Double.parseDouble(lng))); 32 | } else { 33 | Log.w(TAG, "message ignored: " + newLocation.toString()); 34 | } 35 | } 36 | 37 | private void doUiUpdate(final LatLng location) { 38 | activity.runOnUiThread(new Runnable() { 39 | @Override 40 | public void run() { 41 | if (marker != null) { 42 | marker.setPosition(location); 43 | } else { 44 | marker = map.addMarker(new MarkerOptions().position(location)); 45 | } 46 | 47 | map.moveCamera(CameraUpdateFactory.newLatLng(location)); 48 | } 49 | }); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /app/src/main/java/com/pubnub/tutorials/map/android/pubnubmaptutorialandroid/locationpublish/LocationPublishPnCallback.java: -------------------------------------------------------------------------------- 1 | package com.pubnub.tutorials.map.android.pubnubmaptutorialandroid.locationpublish; 2 | 3 | import android.util.Log; 4 | 5 | import com.pubnub.api.PubNub; 6 | import com.pubnub.api.callbacks.SubscribeCallback; 7 | import com.pubnub.api.models.consumer.PNStatus; 8 | import com.pubnub.api.models.consumer.pubsub.PNMessageResult; 9 | import com.pubnub.api.models.consumer.pubsub.PNPresenceEventResult; 10 | import com.pubnub.tutorials.map.android.pubnubmaptutorialandroid.locationsubscribe.LocationSubscribeMapAdapter; 11 | import com.pubnub.tutorials.map.android.pubnubmaptutorialandroid.util.JsonUtil; 12 | 13 | import java.util.LinkedHashMap; 14 | import java.util.Map; 15 | 16 | public class LocationPublishPnCallback extends SubscribeCallback { 17 | private static final String TAG = LocationPublishPnCallback.class.getName(); 18 | private LocationPublishMapAdapter locationMapAdapter; 19 | private String watchChannel; 20 | 21 | public LocationPublishPnCallback(LocationPublishMapAdapter locationMapAdapter, String watchChannel) { 22 | this.locationMapAdapter = locationMapAdapter; 23 | this.watchChannel = watchChannel; 24 | } 25 | 26 | @Override 27 | public void status(PubNub pubnub, PNStatus status) { 28 | Log.d(TAG, "status: " + status.toString()); 29 | } 30 | 31 | @Override 32 | public void message(PubNub pubnub, PNMessageResult message) { 33 | if (!message.getChannel().equals(watchChannel)) { 34 | return; 35 | } 36 | 37 | try { 38 | Log.d(TAG, "message: " + message.toString()); 39 | 40 | Map newLocation = JsonUtil.fromJson(message.getMessage().toString(), LinkedHashMap.class); 41 | locationMapAdapter.locationUpdated(newLocation); 42 | } catch (Exception e) { 43 | throw new RuntimeException(e); 44 | } 45 | } 46 | 47 | @Override 48 | public void presence(PubNub pubnub, PNPresenceEventResult presence) { 49 | if (!presence.getChannel().equals(watchChannel)) { 50 | return; 51 | } 52 | 53 | Log.d(TAG, "presence: " + presence.toString()); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /app/src/main/java/com/pubnub/tutorials/map/android/pubnubmaptutorialandroid/locationpublish/LocationPublishTabContentFragment.java: -------------------------------------------------------------------------------- 1 | package com.pubnub.tutorials.map.android.pubnubmaptutorialandroid.locationpublish; 2 | 3 | import android.app.Activity; 4 | import android.location.Location; 5 | import android.os.Bundle; 6 | import android.support.v4.app.Fragment; 7 | import android.util.Log; 8 | import android.view.LayoutInflater; 9 | import android.view.View; 10 | import android.view.ViewGroup; 11 | 12 | import com.google.android.gms.location.LocationListener; 13 | import com.google.android.gms.maps.GoogleMap; 14 | import com.google.android.gms.maps.OnMapReadyCallback; 15 | import com.google.android.gms.maps.SupportMapFragment; 16 | import com.google.common.collect.ImmutableMap; 17 | import com.pubnub.api.PubNub; 18 | import com.pubnub.api.callbacks.PNCallback; 19 | import com.pubnub.api.models.consumer.PNPublishResult; 20 | import com.pubnub.api.models.consumer.PNStatus; 21 | import com.pubnub.tutorials.map.android.pubnubmaptutorialandroid.Constants; 22 | import com.pubnub.tutorials.map.android.pubnubmaptutorialandroid.R; 23 | import com.pubnub.tutorials.map.android.pubnubmaptutorialandroid.locationsubscribe.LocationSubscribeMapAdapter; 24 | import com.pubnub.tutorials.map.android.pubnubmaptutorialandroid.locationsubscribe.LocationSubscribePnCallback; 25 | import com.pubnub.tutorials.map.android.pubnubmaptutorialandroid.util.JsonUtil; 26 | 27 | import java.util.Arrays; 28 | import java.util.Map; 29 | 30 | public class LocationPublishTabContentFragment extends Fragment implements OnMapReadyCallback, LocationListener { 31 | private static final String TAG = LocationPublishTabContentFragment.class.getName(); 32 | 33 | private PubNub pubNub; 34 | private GoogleMap map; 35 | private LocationHelper locationHelper; 36 | private String userName; 37 | 38 | private static ImmutableMap getNewLocationMessage(String userName, Location location) { 39 | return ImmutableMap.of("who", userName, "lat", Double.toString(location.getLatitude()), "lng", Double.toString(location.getLongitude())); 40 | } 41 | 42 | @Override 43 | public View onCreateView(LayoutInflater inflater, ViewGroup container, 44 | Bundle savedInstanceState) { 45 | View view = inflater.inflate(R.layout.fragment_locationpublish, container, false); 46 | 47 | SupportMapFragment mapFragment = (SupportMapFragment) getChildFragmentManager() 48 | .findFragmentById(R.id.map_locationpublish); 49 | mapFragment.getMapAsync(this); 50 | 51 | return view; 52 | } 53 | 54 | public void setPubNub(PubNub pubNub) { 55 | this.pubNub = pubNub; 56 | this.userName = this.pubNub.getConfiguration().getUuid(); 57 | } 58 | 59 | @Override 60 | public void onMapReady(GoogleMap map) { 61 | this.map = map; 62 | 63 | this.pubNub.addListener(new LocationPublishPnCallback(new LocationPublishMapAdapter((Activity) this.getContext(), map), Constants.PUBLISH_CHANNEL_NAME)); 64 | this.pubNub.subscribe().channels(Arrays.asList(Constants.PUBLISH_CHANNEL_NAME)).execute(); 65 | 66 | this.locationHelper = new LocationHelper((Activity) this.getContext(), this); 67 | } 68 | 69 | @Override 70 | public void onLocationChanged(Location location) { 71 | final Map message = getNewLocationMessage(this.userName, location); 72 | 73 | this.pubNub.publish().channel(Constants.PUBLISH_CHANNEL_NAME).message(message).async( 74 | new PNCallback() { 75 | @Override 76 | public void onResponse(PNPublishResult result, PNStatus status) { 77 | try { 78 | if (!status.isError()) { 79 | Log.v(TAG, "publish(" + JsonUtil.asJson(result) + ")"); 80 | } else { 81 | Log.v(TAG, "publishErr(" + status.toString() + ")"); 82 | } 83 | } catch (Exception e) { 84 | e.printStackTrace(); 85 | } 86 | } 87 | } 88 | ); 89 | } 90 | } -------------------------------------------------------------------------------- /app/src/main/java/com/pubnub/tutorials/map/android/pubnubmaptutorialandroid/locationsubscribe/LocationSubscribeMapAdapter.java: -------------------------------------------------------------------------------- 1 | package com.pubnub.tutorials.map.android.pubnubmaptutorialandroid.locationsubscribe; 2 | 3 | import android.app.Activity; 4 | import android.util.Log; 5 | 6 | import com.google.android.gms.maps.CameraUpdateFactory; 7 | import com.google.android.gms.maps.GoogleMap; 8 | import com.google.android.gms.maps.model.LatLng; 9 | import com.google.android.gms.maps.model.Marker; 10 | import com.google.android.gms.maps.model.MarkerOptions; 11 | 12 | import java.util.Map; 13 | 14 | public class LocationSubscribeMapAdapter { 15 | private static final String TAG = LocationSubscribeMapAdapter.class.getName(); 16 | 17 | private Marker marker; 18 | private Activity activity; 19 | private GoogleMap map; 20 | 21 | public LocationSubscribeMapAdapter(Activity activity, GoogleMap map) { 22 | this.activity = activity; 23 | this.map = map; 24 | } 25 | 26 | public void locationUpdated(final Map newLocation) { 27 | if (newLocation.containsKey("lat") && newLocation.containsKey("lng")) { 28 | String lat = newLocation.get("lat"); 29 | String lng = newLocation.get("lng"); 30 | 31 | doUiUpdate(new LatLng(Double.parseDouble(lat), Double.parseDouble(lng))); 32 | } else { 33 | Log.w(TAG, "message ignored: " + newLocation.toString()); 34 | } 35 | } 36 | 37 | private void doUiUpdate(final LatLng location) { 38 | activity.runOnUiThread(new Runnable() { 39 | @Override 40 | public void run() { 41 | if (marker != null) { 42 | marker.setPosition(location); 43 | } else { 44 | marker = map.addMarker(new MarkerOptions().position(location)); 45 | } 46 | 47 | map.moveCamera(CameraUpdateFactory.newLatLng(location)); 48 | } 49 | }); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /app/src/main/java/com/pubnub/tutorials/map/android/pubnubmaptutorialandroid/locationsubscribe/LocationSubscribePnCallback.java: -------------------------------------------------------------------------------- 1 | package com.pubnub.tutorials.map.android.pubnubmaptutorialandroid.locationsubscribe; 2 | 3 | import android.util.Log; 4 | 5 | import com.pubnub.api.PubNub; 6 | import com.pubnub.api.callbacks.SubscribeCallback; 7 | import com.pubnub.api.models.consumer.PNStatus; 8 | import com.pubnub.api.models.consumer.pubsub.PNMessageResult; 9 | import com.pubnub.api.models.consumer.pubsub.PNPresenceEventResult; 10 | import com.pubnub.tutorials.map.android.pubnubmaptutorialandroid.util.JsonUtil; 11 | 12 | import java.util.LinkedHashMap; 13 | import java.util.Map; 14 | 15 | public class LocationSubscribePnCallback extends SubscribeCallback { 16 | private static final String TAG = LocationSubscribePnCallback.class.getName(); 17 | private LocationSubscribeMapAdapter locationMapAdapter; 18 | private String watchChannel; 19 | 20 | public LocationSubscribePnCallback(LocationSubscribeMapAdapter locationMapAdapter, String watchChannel) { 21 | this.locationMapAdapter = locationMapAdapter; 22 | this.watchChannel = watchChannel; 23 | } 24 | 25 | @Override 26 | public void status(PubNub pubnub, PNStatus status) { 27 | Log.d(TAG, "status: " + status.toString()); 28 | } 29 | 30 | @Override 31 | public void message(PubNub pubnub, PNMessageResult message) { 32 | if (!message.getChannel().equals(watchChannel)) { 33 | return; 34 | } 35 | 36 | try { 37 | Log.d(TAG, "message: " + message.toString()); 38 | 39 | Map newLocation = JsonUtil.fromJson(message.getMessage().toString(), LinkedHashMap.class); 40 | locationMapAdapter.locationUpdated(newLocation); 41 | } catch (Exception e) { 42 | throw new RuntimeException(e); 43 | } 44 | } 45 | 46 | @Override 47 | public void presence(PubNub pubnub, PNPresenceEventResult presence) { 48 | if (!presence.getChannel().equals(watchChannel)) { 49 | return; 50 | } 51 | 52 | Log.d(TAG, "presence: " + presence.toString()); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /app/src/main/java/com/pubnub/tutorials/map/android/pubnubmaptutorialandroid/locationsubscribe/LocationSubscribeTabContentFragment.java: -------------------------------------------------------------------------------- 1 | package com.pubnub.tutorials.map.android.pubnubmaptutorialandroid.locationsubscribe; 2 | 3 | import android.app.Activity; 4 | import android.os.Bundle; 5 | import android.support.v4.app.Fragment; 6 | import android.util.Log; 7 | import android.view.LayoutInflater; 8 | import android.view.View; 9 | import android.view.ViewGroup; 10 | 11 | import com.google.android.gms.maps.GoogleMap; 12 | import com.google.android.gms.maps.OnMapReadyCallback; 13 | import com.google.android.gms.maps.SupportMapFragment; 14 | import com.google.common.collect.ImmutableMap; 15 | import com.pubnub.api.PubNub; 16 | import com.pubnub.api.callbacks.PNCallback; 17 | import com.pubnub.api.models.consumer.PNPublishResult; 18 | import com.pubnub.api.models.consumer.PNStatus; 19 | import com.pubnub.tutorials.map.android.pubnubmaptutorialandroid.Constants; 20 | import com.pubnub.tutorials.map.android.pubnubmaptutorialandroid.R; 21 | import com.pubnub.tutorials.map.android.pubnubmaptutorialandroid.util.JsonUtil; 22 | 23 | import java.util.Arrays; 24 | import java.util.Map; 25 | import java.util.Random; 26 | import java.util.concurrent.Executors; 27 | import java.util.concurrent.ScheduledExecutorService; 28 | import java.util.concurrent.TimeUnit; 29 | 30 | public class LocationSubscribeTabContentFragment extends Fragment implements OnMapReadyCallback { 31 | private static final String TAG = LocationSubscribeTabContentFragment.class.getName(); 32 | private static final Double generatorOriginLat = 37.8199; 33 | private static final Double generatorOriginLng = -122.4783; 34 | private PubNub pubNub; 35 | private GoogleMap map; 36 | private String userName; 37 | private ScheduledExecutorService executorService; 38 | private Random random = new Random(); 39 | private Long startTime; 40 | 41 | private static ImmutableMap getNewLocationMessage(String userName, int randomLat, int randomLng, long elapsedTime) { 42 | String newLat = Double.toString(generatorOriginLat + ((randomLat + elapsedTime) * 0.000003)); 43 | String newLng = Double.toString(generatorOriginLng + ((randomLng + elapsedTime) * 0.00001)); 44 | 45 | return ImmutableMap.of("who", userName, "lat", newLat, "lng", newLng); 46 | } 47 | 48 | @Override 49 | public View onCreateView(LayoutInflater inflater, ViewGroup container, 50 | Bundle savedInstanceState) { 51 | View view = inflater.inflate(R.layout.fragment_locationsubscribe, container, false); 52 | 53 | SupportMapFragment mapFragment = (SupportMapFragment) getChildFragmentManager() 54 | .findFragmentById(R.id.map_locationsubscribe); 55 | mapFragment.getMapAsync(this); 56 | 57 | return view; 58 | } 59 | 60 | public void setPubNub(PubNub pubNub) { 61 | this.pubNub = pubNub; 62 | this.userName = this.pubNub.getConfiguration().getUuid(); 63 | } 64 | 65 | @Override 66 | public void onMapReady(GoogleMap map) { 67 | this.map = map; 68 | 69 | pubNub.addListener(new LocationSubscribePnCallback(new LocationSubscribeMapAdapter((Activity) this.getContext(), map), Constants.SUBSCRIBE_CHANNEL_NAME)); 70 | pubNub.subscribe().channels(Arrays.asList(Constants.SUBSCRIBE_CHANNEL_NAME)).execute(); 71 | 72 | scheduleRandomUpdates(); 73 | } 74 | 75 | private void scheduleRandomUpdates() { 76 | this.executorService = Executors.newSingleThreadScheduledExecutor(); 77 | this.startTime = System.currentTimeMillis(); 78 | 79 | this.executorService.scheduleAtFixedRate(new Runnable() { 80 | @Override 81 | public void run() { 82 | ((Activity) LocationSubscribeTabContentFragment.this.getContext()).runOnUiThread(new Runnable() { 83 | @Override 84 | public void run() { 85 | int randomLat = random.nextInt(10); 86 | int randomLng = random.nextInt(10); 87 | long elapsedTime = System.currentTimeMillis() - startTime; 88 | 89 | final Map message = getNewLocationMessage(userName, randomLat, randomLng, elapsedTime); 90 | 91 | pubNub.publish().channel(Constants.SUBSCRIBE_CHANNEL_NAME).message(message).async( 92 | new PNCallback() { 93 | @Override 94 | public void onResponse(PNPublishResult result, PNStatus status) { 95 | try { 96 | if (!status.isError()) { 97 | Log.v(TAG, "publish(" + JsonUtil.asJson(result) + ")"); 98 | } else { 99 | Log.v(TAG, "publishErr(" + status.toString() + ")"); 100 | } 101 | } catch (Exception e) { 102 | e.printStackTrace(); 103 | } 104 | } 105 | } 106 | ); 107 | } 108 | }); 109 | } 110 | }, 0, 5, TimeUnit.SECONDS); 111 | } 112 | } -------------------------------------------------------------------------------- /app/src/main/java/com/pubnub/tutorials/map/android/pubnubmaptutorialandroid/util/JsonUtil.java: -------------------------------------------------------------------------------- 1 | package com.pubnub.tutorials.map.android.pubnubmaptutorialandroid.util; 2 | 3 | import com.fasterxml.jackson.databind.ObjectMapper; 4 | 5 | import java.util.Map; 6 | 7 | /** 8 | * Utility class for converting JSON objects/strings/etc. 9 | */ 10 | public class JsonUtil { 11 | private static final ObjectMapper mapper = new ObjectMapper(); 12 | 13 | public static T fromJson(byte[] value, Class clazz) throws Exception { 14 | return mapper.readValue(value, clazz); 15 | } 16 | 17 | public static T fromJson(String value, Class clazz) throws Exception { 18 | return mapper.readValue(value, clazz); 19 | } 20 | 21 | public static String asJson(Object value) throws Exception { 22 | return mapper.writeValueAsString(value); 23 | } 24 | 25 | public static T convert(Map value, Class clazz) throws Exception { 26 | return mapper.convertValue(value, clazz); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_login.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 16 | 17 | 18 | 24 | 25 | 26 | 27 |