Java tutorial
package com.wipro.sa349342.wmar; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.nio.MappedByteBuffer; import java.nio.channels.FileChannel; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import org.json.JSONArray; import org.json.JSONObject; import android.annotation.SuppressLint; import android.app.Activity; import android.content.pm.ApplicationInfo; import android.graphics.Color; import android.location.Location; import android.location.LocationListener; import android.media.AudioManager; import android.opengl.GLES20; import android.os.Build; import android.os.Bundle; import android.os.Environment; import android.support.v4.app.FragmentActivity; import android.util.Log; import android.view.View; import android.webkit.WebView; import android.widget.Toast; import com.google.android.gms.location.LocationServices; import com.google.android.gms.maps.CameraUpdateFactory; import com.google.android.gms.maps.GoogleMap; import com.google.android.gms.maps.LocationSource; import com.google.android.gms.maps.OnMapReadyCallback; import com.google.android.gms.maps.SupportMapFragment; import com.google.android.gms.maps.model.BitmapDescriptor; import com.google.android.gms.maps.model.BitmapDescriptorFactory; import com.google.android.gms.maps.model.CircleOptions; import com.google.android.gms.maps.model.LatLng; import com.google.android.gms.maps.model.Marker; import com.google.android.gms.maps.model.MarkerOptions; import com.google.android.gms.maps.model.Polyline; import com.google.android.gms.maps.model.PolylineOptions; import com.wikitude.architect.ArchitectView; import com.wikitude.architect.ArchitectView.ArchitectUrlListener; import com.wikitude.architect.ArchitectView.SensorAccuracyChangeListener; import com.wikitude.architect.StartupConfiguration; import com.wikitude.architect.StartupConfiguration.CameraPosition; import static android.R.attr.strokeColor; import static com.wipro.sa349342.wmar.R.id.map; //import com.wikitude.sdksamples.R; /** * Abstract activity which handles live-cycle events. * Feel free to extend from this activity when setting up your own AR-Activity * */ public abstract class AbstractArchitectCamActivity extends FragmentActivity implements OnMapReadyCallback, ArchitectViewHolderInterface { /** * holds the Wikitude SDK AR-View, this is where camera, markers, compass, 3D models etc. are rendered */ protected ArchitectView architectView; /** * sensor accuracy listener in case you want to display calibration hints */ protected SensorAccuracyChangeListener sensorAccuracyListener; /** * last known location of the user, used internally for content-loading after user location was fetched */ protected Location lastKnownLocaton; /** * sample location strategy, you may implement a more sophisticated approach too */ protected ILocationProvider locationProvider; /** * location listener receives location updates and must forward them to the architectView */ protected LocationListener locationListener; /** * urlListener handling "document.location= 'architectsdk://...' " calls in JavaScript" */ protected ArchitectUrlListener urlListener; protected JSONArray poiData; protected boolean isLoading = false; private GoogleMap mMap; public static List<featuresItem> UtlityLinesFeatureList = new ArrayList<featuresItem>(); public static List<featuresItem> EquipmentsFeatureList = new ArrayList<featuresItem>(); Location mLastLocation; Marker mCurrLocationMarker; double radiusInMeters = 100.0; int strokeColor = 0xffff0000; //Color Code you want int shadeColor = 0x44ff0000; boolean mapLoaded = false; /** Called when the activity is first created. */ @SuppressLint("NewApi") @Override public void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState); /* pressing volume up/down should cause music volume changes */ this.setVolumeControlStream(AudioManager.STREAM_MUSIC); /* set samples content view */ this.setContentView(this.getContentViewId()); this.setTitle(this.getActivityTitle()); View mapFrag = findViewById(R.id.map); if (this.isMapPanelRequired()) { mapFrag.setVisibility(View.VISIBLE); // Obtain the SupportMapFragment and get notified when the map is ready to be used. SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager().findFragmentById(map); mapFragment.getMapAsync(AbstractArchitectCamActivity.this); } else { mapFrag.setVisibility(View.GONE); } /* * this enables remote debugging of a WebView on Android 4.4+ when debugging = true in AndroidManifest.xml * If you get a compile time error here, ensure to have SDK 19+ used in your ADT/Eclipse. * You may even delete this block in case you don't need remote debugging or don't have an Android 4.4+ device in place. * Details: https://developers.google.com/chrome-developer-tools/docs/remote-debugging */ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { if (0 != (getApplicationInfo().flags &= ApplicationInfo.FLAG_DEBUGGABLE)) { WebView.setWebContentsDebuggingEnabled(true); } } /* set AR-view for life-cycle notifications etc. */ this.architectView = (ArchitectView) this.findViewById(this.getArchitectViewId()); /* pass SDK key if you have one, this one is only valid for this package identifier and must not be used somewhere else */ final StartupConfiguration config = new StartupConfiguration(this.getWikitudeSDKLicenseKey(), this.getFeatures(), this.getCameraPosition()); try { /* first mandatory life-cycle notification */ this.architectView.onCreate(config); } catch (RuntimeException rex) { this.architectView = null; Toast.makeText(getApplicationContext(), "can't create Architect View", Toast.LENGTH_SHORT).show(); Log.e(this.getClass().getName(), "Exception in ArchitectView.onCreate()", rex); } // set accuracy listener if implemented, you may e.g. show calibration prompt for compass using this listener this.sensorAccuracyListener = this.getSensorAccuracyListener(); // set urlListener, any calls made in JS like "document.location = 'architectsdk://foo?bar=123'" is forwarded to this listener, use this to interact between JS and native Android activity/fragment this.urlListener = this.getUrlListener(); // register valid urlListener in architectView, ensure this is set before content is loaded to not miss any event if (this.urlListener != null && this.architectView != null) { this.architectView.registerUrlListener(this.getUrlListener()); } if (hasGeo()) { // listener passed over to locationProvider, any location update is handled here this.locationListener = new LocationListener() { @Override public void onStatusChanged(String provider, int status, Bundle extras) { } @Override public void onProviderEnabled(String provider) { } @Override public void onProviderDisabled(String provider) { } @Override public void onLocationChanged(final Location location) { // forward location updates fired by LocationProvider to architectView, you can set lat/lon from any location-strategy if (location != null) { // sore last location as member, in case it is needed somewhere (in e.g. your adjusted project) AbstractArchitectCamActivity.this.lastKnownLocaton = location; if (AbstractArchitectCamActivity.this.architectView != null) { // check if location has altitude at certain accuracy level & call right architect method (the one with altitude information) if (location.hasAltitude() && location.hasAccuracy() && location.getAccuracy() < 7) { AbstractArchitectCamActivity.this.architectView.setLocation(location.getLatitude(), location.getLongitude(), location.getAltitude(), location.getAccuracy()); } else { AbstractArchitectCamActivity.this.architectView.setLocation(location.getLatitude(), location.getLongitude(), location.hasAccuracy() ? location.getAccuracy() : 1000); } } // currentLocationMarker(location); } } }; // locationProvider used to fetch user position this.locationProvider = getLocationProvider(this.locationListener); } else { this.locationProvider = null; this.locationListener = null; } } @Override public void onMapReady(GoogleMap googleMap) { try { mMap = googleMap; mMap.animateCamera(CameraUpdateFactory.zoomTo(13)); mMap.setMyLocationEnabled(true); //mMap.setLocationSource(LocationSource.OnLocationChangedListener); mMap.getUiSettings().setCompassEnabled(true); mMap.getUiSettings().setZoomControlsEnabled(true); mMap.getUiSettings().setIndoorLevelPickerEnabled(true); mMap.getUiSettings().setMapToolbarEnabled(true); createFCListFromJsonFile(); injectData(); mapLoaded = true; } catch (SecurityException ex) { ex.printStackTrace(); } catch (Exception ex) { ex.printStackTrace(); } } /* private void currentLocationMarker(Location location) { if(mapLoaded) { mLastLocation = location; if (mCurrLocationMarker != null) { mCurrLocationMarker.remove(); } //Place current location marker LatLng latLng = new LatLng(location.getLatitude(), location.getLongitude()); MarkerOptions markerOptions = new MarkerOptions(); markerOptions.position(latLng); markerOptions.title("Current Position"); markerOptions.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_MAGENTA)); mCurrLocationMarker = mMap.addMarker(markerOptions); CircleOptions addCircle = new CircleOptions().center(latLng).radius(radiusInMeters).fillColor(shadeColor).strokeColor(strokeColor).strokeWidth(8); mMap.addCircle(addCircle); //move map camera mMap.moveCamera(CameraUpdateFactory.newLatLng(latLng)); mMap.animateCamera(CameraUpdateFactory.zoomTo(11)); } //stop location updates *//* if (mGoogleApiClient != null) { LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this); }*//* }*/ protected abstract CameraPosition getCameraPosition(); private int getFeatures() { int features = (hasGeo() ? StartupConfiguration.Features.Geo : 0) | (hasIR() ? StartupConfiguration.Features.Tracking2D : 0); return features; } protected abstract boolean hasGeo(); protected abstract boolean hasIR(); @Override protected void onPostCreate(final Bundle savedInstanceState) { super.onPostCreate(savedInstanceState); if (this.architectView != null) { // call mandatory live-cycle method of architectView this.architectView.onPostCreate(); try { // load content via url in architectView, ensure '<script src="architect://architect.js"></script>' is part of this HTML file, have a look at wikitude.com's developer section for API references this.architectView.load(this.getARchitectWorldPath()); if (this.getInitialCullingDistanceMeters() != ArchitectViewHolderInterface.CULLING_DISTANCE_DEFAULT_METERS) { // set the culling distance - meaning: the maximum distance to render geo-content this.architectView.setCullingDistance(this.getInitialCullingDistanceMeters()); } } catch (IOException e1) { e1.printStackTrace(); } } } @Override protected void onResume() { super.onResume(); // call mandatory live-cycle method of architectView if (this.architectView != null) { this.architectView.onResume(); // register accuracy listener in architectView, if set if (this.sensorAccuracyListener != null) { this.architectView.registerSensorAccuracyChangeListener(this.sensorAccuracyListener); } } // tell locationProvider to resume, usually location is then (again) fetched, so the GPS indicator appears in status bar if (this.locationProvider != null) { this.locationProvider.onResume(); } } @Override protected void onPause() { super.onPause(); // call mandatory live-cycle method of architectView if (this.architectView != null) { this.architectView.onPause(); // unregister accuracy listener in architectView, if set if (this.sensorAccuracyListener != null) { this.architectView.unregisterSensorAccuracyChangeListener(this.sensorAccuracyListener); } } // tell locationProvider to pause, usually location is then no longer fetched, so the GPS indicator disappears in status bar if (this.locationProvider != null) { this.locationProvider.onPause(); } } @Override protected void onStop() { super.onStop(); } @Override protected void onDestroy() { super.onDestroy(); // call mandatory live-cycle method of architectView if (this.architectView != null) { this.architectView.onDestroy(); } } @Override public void onLowMemory() { super.onLowMemory(); if (this.architectView != null) { this.architectView.onLowMemory(); } } /** * title shown in activity * @return */ public abstract String getActivityTitle(); /** * path to the architect-file (AR-Experience HTML) to launch * @return */ @Override public abstract String getARchitectWorldPath(); /** * url listener fired once e.g. 'document.location = "architectsdk://foo?bar=123"' is called in JS * @return */ @Override public abstract ArchitectUrlListener getUrlListener(); /** * @return layout id of your layout.xml that holds an ARchitect View, e.g. R.layout.camview */ @Override public abstract int getContentViewId(); /** * @return true, if map panel is required */ @Override public abstract boolean isMapPanelRequired(); /** * @return Wikitude SDK license key, checkout www.wikitude.com for details */ @Override public abstract String getWikitudeSDKLicenseKey(); /** * @return layout-id of architectView, e.g. R.id.architectView */ @Override public abstract int getArchitectViewId(); /** * * @return Implementation of a Location */ @Override public abstract ILocationProvider getLocationProvider(final LocationListener locationListener); /** * @return Implementation of Sensor-Accuracy-Listener. That way you can e.g. show prompt to calibrate compass */ @Override public abstract ArchitectView.SensorAccuracyChangeListener getSensorAccuracyListener(); /** * helper to check if video-drawables are supported by this device. recommended to check before launching ARchitect Worlds with videodrawables * @return true if AR.VideoDrawables are supported, false if fallback rendering would apply (= show video fullscreen) */ public static final boolean isVideoDrawablesSupported() { String extensions = GLES20.glGetString(GLES20.GL_EXTENSIONS); return extensions != null && extensions.contains("GL_OES_EGL_image_external"); } protected void injectData() { if (!isLoading) { final Thread t = new Thread(new Runnable() { @Override public void run() { isLoading = true; final int WAIT_FOR_LOCATION_STEP_MS = 2000; while (lastKnownLocaton == null && !isFinishing()) { runOnUiThread(new Runnable() { @Override public void run() { Toast.makeText(AbstractArchitectCamActivity.this, R.string.location_fetching, Toast.LENGTH_SHORT).show(); } }); try { Thread.sleep(WAIT_FOR_LOCATION_STEP_MS); } catch (InterruptedException e) { break; } } if (lastKnownLocaton != null && !isFinishing()) { // TODO: you may replace this dummy implementation and instead load POI information e.g. from your database poiData = getPoiFromJsonFile(lastKnownLocaton); //poiData = getPoiInformation(lastKnownLocaton, 10); callJavaScript("World.loadPoisFromJsonData", new String[] { poiData.toString(), "'ALL'" }); } isLoading = false; } }); t.start(); } } /** * call JacaScript in architectView * @param methodName * @param arguments */ private void callJavaScript(final String methodName, final String[] arguments) { final StringBuilder argumentsString = new StringBuilder(""); for (int i = 0; i < arguments.length; i++) { argumentsString.append(arguments[i]); if (i < arguments.length - 1) { argumentsString.append(", "); } } if (this.architectView != null) { final String js = (methodName + "( " + argumentsString.toString() + " );"); this.architectView.callJavascript(js); } } /** * loads poiInformation and returns them as JSONArray. Ensure attributeNames of JSON POIs are well known in JavaScript, so you can parse them easily * @param userLocation the location of the user * @param numberOfPlaces number of places to load (at max) * @return POI information in JSONArray */ public static JSONArray getPoiInformation(final Location userLocation, final int numberOfPlaces) { if (userLocation == null) { return null; } final JSONArray pois = new JSONArray(); // ensure these attributes are also used in JavaScript when extracting POI data final String ATTR_ID = "id"; final String ATTR_NAME = "name"; final String ATTR_DESCRIPTION = "description"; final String ATTR_LATITUDE = "latitude"; final String ATTR_LONGITUDE = "longitude"; final String ATTR_ALTITUDE = "altitude"; for (int i = 1; i <= numberOfPlaces; i++) { final HashMap<String, String> poiInformation = new HashMap<String, String>(); poiInformation.put(ATTR_ID, String.valueOf(i)); poiInformation.put(ATTR_NAME, "POI#" + i); poiInformation.put(ATTR_DESCRIPTION, "This is the description of POI#" + i); double[] poiLocationLatLon = getRandomLatLonNearby(userLocation.getLatitude(), userLocation.getLongitude()); poiInformation.put(ATTR_LATITUDE, String.valueOf(poiLocationLatLon[0])); poiInformation.put(ATTR_LONGITUDE, String.valueOf(poiLocationLatLon[1])); final float UNKNOWN_ALTITUDE = -32768f; // equals "AR.CONST.UNKNOWN_ALTITUDE" in JavaScript (compare AR.GeoLocation specification) // Use "AR.CONST.UNKNOWN_ALTITUDE" to tell ARchitect that altitude of places should be on user level. Be aware to handle altitude properly in locationManager in case you use valid POI altitude value (e.g. pass altitude only if GPS accuracy is <7m). poiInformation.put(ATTR_ALTITUDE, String.valueOf(UNKNOWN_ALTITUDE)); pois.put(new JSONObject(poiInformation)); } return pois; } /** * helper for creation of dummy places. * @param lat center latitude * @param lon center longitude * @return lat/lon values in given position's vicinity */ private static double[] getRandomLatLonNearby(final double lat, final double lon) { return new double[] { lat + Math.random() / 5 - 0.1, lon + Math.random() / 5 - 0.1 }; } /** * loads poiInformation and returns them as JSONArray. Ensure attributeNames of JSON POIs are well known in JavaScript, so you can parse them easily * @param userLocation the location of the user * @return POI information in JSONArray */ public JSONArray getPoiFromJsonFile(final Location userLocation) { if (userLocation == null) { return null; } //createFCListFromJsonFile(); final JSONArray pois = new JSONArray(); // ensure these attributes are also used in JavaScript when extracting POI data final String ATTR_ID = "id"; final String ATTR_CATEGORY = "category"; final String ATTR_NAME = "name"; final String ATTR_DESCRIPTION = "description"; final String ATTR_LATITUDE = "latitude"; final String ATTR_LONGITUDE = "longitude"; final String ATTR_ALTITUDE = "altitude"; for (int index = 0; index < EquipmentsFeatureList.size(); index++) { final HashMap<String, String> poiInformation = new HashMap<String, String>(); poiInformation.put(ATTR_ID, EquipmentsFeatureList.get(index).id); poiInformation.put(ATTR_CATEGORY, EquipmentsFeatureList.get(index).category); poiInformation.put(ATTR_NAME, EquipmentsFeatureList.get(index).name); poiInformation.put(ATTR_DESCRIPTION, EquipmentsFeatureList.get(index).description); //double[] poiLocationLatLon = getRandomLatLonNearby(userLocation.getLatitude(), userLocation.getLongitude()); poiInformation.put(ATTR_LATITUDE, EquipmentsFeatureList.get(index).getLatitude(0)); poiInformation.put(ATTR_LONGITUDE, EquipmentsFeatureList.get(index).getLongitude(0)); final float UNKNOWN_ALTITUDE = -32768f; // equals "AR.CONST.UNKNOWN_ALTITUDE" in JavaScript (compare AR.GeoLocation specification) // Use "AR.CONST.UNKNOWN_ALTITUDE" to tell ARchitect that altitude of places should be on user level. Be aware to handle altitude properly in locationManager in case you use valid POI altitude value (e.g. pass altitude only if GPS accuracy is <7m). poiInformation.put(ATTR_ALTITUDE, String.valueOf(UNKNOWN_ALTITUDE)); pois.put(new JSONObject(poiInformation)); } return pois; } public void createFCListFromJsonFile() { try { //downloadAndStoreJson("http://jsonblob.com/api/jsonBlob/57b57cc1e4b0dc55a4edf932"); File jsonFile = new File(Environment.getExternalStorageDirectory().getPath(), MainActivityLanding.DefaultJSONFileFromMemeory); /*if (!jsonFile.isFile()) { System.out.println("MyGlobalVariables--readJSONFromMemory::-downloaded json file not found.Switching to default file"); jsonFile = new File(Environment.getExternalStorageDirectory().getPath(), MyGlobalVariables.defaultJSONFileFromMemeory); }*/ FileInputStream stream = new FileInputStream(jsonFile); String jsonStr = null; try { FileChannel fc = stream.getChannel(); MappedByteBuffer bb = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size()); jsonStr = Charset.defaultCharset().decode(bb).toString(); } finally { stream.close(); } JSONObject jsonObj = new JSONObject(jsonStr); // Getting data JSON Array nodes // JSONArray data = jsonObj.getJSONArray("utility_lines"); addFeaturesInList(jsonObj.getJSONArray("utility_lines"), UtlityLinesFeatureList, "utility_lines"); addFeaturesInList(jsonObj.getJSONArray("equipments"), EquipmentsFeatureList, "equipments"); com.google.android.gms.maps.model.CameraPosition cameraPosition = new com.google.android.gms.maps.model.CameraPosition.Builder() .target(new LatLng(12.8363773, 77.6585139)) //.target(london_eye)//Sets the center of the map to .zoom(19) // Sets the zoom .bearing(0) // Sets the orientation of the camera to east .tilt(0) // Sets the tilt of the camera to 1 degrees .build(); mMap.animateCamera(CameraUpdateFactory.newCameraPosition(cameraPosition)); } catch (Exception e) { e.printStackTrace(); } } private void addFeaturesInList(JSONArray data, List<featuresItem> FeatureList, String className) { try { if (data != null) { FeatureList.clear(); // looping through All nodes for (int featCount = 0; featCount < data.length(); featCount++) { JSONObject c = data.getJSONObject(featCount); String id = c.getString("id"); String category = c.getString("category"); JSONObject fieldsJSON = c.getJSONObject("fields"); String name = fieldsJSON.getString("name"); String description = fieldsJSON.getString("description"); JSONObject geometryJSON = c.getJSONObject("geometry"); String geometryType = geometryJSON.getString("type"); String[] cordArray = new String[1]; if (!geometryType.equalsIgnoreCase("Point"))//for polylines and polygons { int noOfVertices = geometryJSON.getJSONArray("coordinates").length(); cordArray = new String[noOfVertices]; int vertexCounter = 0; List<LatLng> verticesCollectionList = new ArrayList<LatLng>(); for (int vertex = 0; vertex < noOfVertices; vertex++) { String lat = geometryJSON.getJSONArray("coordinates").getJSONArray(vertex).getString(1); String longt = geometryJSON.getJSONArray("coordinates").getJSONArray(vertex) .getString(0); String alt = geometryJSON.getJSONArray("coordinates").getJSONArray(vertex).getString(2); String cord = lat + "," + longt + "," + alt; cordArray[vertexCounter] = cord; vertexCounter++; verticesCollectionList.add(new LatLng(Double.valueOf(lat), Double.valueOf(longt))); } Polyline line = mMap.addPolyline(new PolylineOptions().width(5).color(Color.RED)); line.setPoints(verticesCollectionList); } else { String lat = geometryJSON.getJSONArray("coordinates").getString(1); String longt = geometryJSON.getJSONArray("coordinates").getString(0); String alt = geometryJSON.getJSONArray("coordinates").getString(2); String cord = lat + "," + longt + "," + alt; cordArray[0] = cord; BitmapDescriptor iconCategory = getIconFile(category); Marker marker = mMap.addMarker( new MarkerOptions().position(new LatLng(Double.valueOf(lat), Double.valueOf(longt))) .title(name).snippet(description).icon(iconCategory)); } //Create the feature object featuresItem feature = new featuresItem(className, id, category, name, description, geometryType, cordArray); //Add to the feature list. FeatureList.add(feature); } } else { Log.e("readJSONFromMemory()", "Couldn't find the details in JSON files so skipping data sync."); } } catch (Exception ex) { ex.printStackTrace(); } } private BitmapDescriptor getIconFile(String category) { BitmapDescriptor icon = null; if (category.equalsIgnoreCase("TR")) { icon = BitmapDescriptorFactory.fromResource(R.drawable.icon_tr); } else if (category.equalsIgnoreCase("GN")) { icon = BitmapDescriptorFactory.fromResource(R.drawable.icon_gn); } else if (category.equalsIgnoreCase("JB")) { icon = BitmapDescriptorFactory.fromResource(R.drawable.icon_jb); } else if (category.equalsIgnoreCase("MT")) { icon = BitmapDescriptorFactory.fromResource(R.drawable.icon_mt); } else if (category.equalsIgnoreCase("SB")) { icon = BitmapDescriptorFactory.fromResource(R.drawable.icon_sb); } else { icon = BitmapDescriptorFactory.fromResource(R.drawable.icon_oh); } return icon; } }