com.wikitude.phonegap.WikitudePlugin.java Source code

Java tutorial

Introduction

Here is the source code for com.wikitude.phonegap.WikitudePlugin.java

Source

package com.wikitude.phonegap;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Date;
import java.util.Scanner;

import org.apache.cordova.CallbackContext;
import org.apache.cordova.CordovaPlugin;
import org.apache.cordova.CordovaWebView;
import org.apache.cordova.PluginResult;
import org.json.JSONArray;
import org.json.JSONException;

import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Rect;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.text.format.DateUtils;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.view.ViewManager;
import android.view.inputmethod.InputMethodManager;
import android.widget.Toast;

import com.wikitude.architect.ArchitectView;
import com.wikitude.architect.ArchitectView.ArchitectConfig;
import com.wikitude.architect.ArchitectView.ArchitectUrlListener;
import com.wikitude.architect.ArchitectView.CaptureScreenCallback;
import com.wikitude.phonegap.WikitudePlugin.ArchitectViewPhoneGap.OnKeyDownListener;

/**
 * Basic PhoneGap Wikitude ARchitect Plugin
 * 
 * You must add "<plugin name="WikitudePlugin" value="com.wikitude.phonegap.WikitudePlugin"/>"
 * in config.xml to enable this plug-in in your project
 * 
 * Also ensure to have wikitudesdk.jar in your libs folder
 * 
 * Note:
 * This plug-in is written under Apache License, Version 2.0
 * http://www.apache.org/licenses/LICENSE-2.0.html
 */
public class WikitudePlugin extends CordovaPlugin implements ArchitectUrlListener {

    /** PhoneGap-root to Android-app-assets folder ; e.g. use "assets/foo.html" as source if you want to load foo.html from your android-project's assets-folder */
    private static final String LOCAL_ASSETS_PATH_ROOT = "assets/";

    /* static action strings */
    /**
     * opens architect-view (add to view stack)
     */
    private static final String ACTION_OPEN = "open";

    /**
     * closes architect-view (remove view stack)
     */
    private static final String ACTION_CLOSE = "close";

    /**
     * set visibility of architectView to visible (of present)
     */
    private static final String ACTION_SHOW = "show";

    /**
     * set visibility of architectView to invisible (of present)
     */
    private static final String ACTION_HIDE = "hide";

    /**
     * inject location information
     */
    private static final String ACTION_SET_LOCATION = "setLocation";

    /**
     * inject location information
     */
    private static final String ACTION_CAPTURE_SCREEN = "captureScreen";

    /**
     * callback for uri-invocations
     */
    private static final String ACTION_ON_URLINVOKE = "onUrlInvoke";

    /**
     * life-cycle notification for resume
     */
    private static final String ACTION_ON_RESUME = "onResume";

    /**
     * life-cycle notification for pause
     */
    private static final String ACTION_ON_PAUSE = "onPause";

    /**
     * check if view is on view-stack (no matter if visible or not)
     */
    private static final String ACTION_STATE_ISOPEN = "isOpen";

    /**
     * opens architect-view (add to view stack)
     */
    private static final String ACTION_IS_DEVICE_SUPPORTED = "isDeviceSupported";

    /**
     * check if view is on view-stack (no matter if visible or not)
     */
    private static final String ACTION_CALL_JAVASCRIPT = "callJavascript";

    /**
     * the Wikitude ARchitectview
     */
    private ArchitectViewPhoneGap architectView;

    /**
     * callback-Id of url-invocation method
     */
    private CallbackContext urlInvokeCallback = null;

    /**
     * callback-id of "open"-action method
     */
    private CallbackContext openCallback = null;

    /**
     * last known location of the user, used internally for content-loading after user location was fetched
     */
    protected Location lastKnownLocaton;

    /**
     * sample location strategy
     */
    protected ILocationProvider locationProvider;

    /**
     * location listener receives location updates and must forward them to the architectView
     */
    protected LocationListener locationListener;

    @Override
    public boolean execute(final String action, final JSONArray args, final CallbackContext callContext) {

        /* hide architect-view -> destroy and remove from activity */
        if (WikitudePlugin.ACTION_CLOSE.equals(action)) {
            if (this.architectView != null) {
                this.cordova.getActivity().runOnUiThread(new Runnable() {

                    @Override
                    public void run() {
                        removeArchitectView();
                    }
                });
                callContext.success(action + ": architectView is present");
            } else {
                callContext.error(action + ": architectView is not present");
            }
            return true;
        }

        /* return success only if view is opened (no matter if visible or not) */
        if (WikitudePlugin.ACTION_STATE_ISOPEN.equals(action)) {
            if (this.architectView != null) {
                callContext.success(action + ": architectView is present");
            } else {
                callContext.error(action + ": architectView is not present");
            }
            return true;
        }

        /* return success only if view is opened (no matter if visible or not) */
        if (WikitudePlugin.ACTION_IS_DEVICE_SUPPORTED.equals(action)) {
            if (ArchitectView.isDeviceSupported(this.cordova.getActivity()) && hasNeonSupport()) {
                callContext.success(action + ": this device is ARchitect-ready");
            } else {
                callContext.error(action + action + ":Sorry, this device is NOT ARchitect-ready");
            }
            return true;
        }

        if (WikitudePlugin.ACTION_CAPTURE_SCREEN.equals(action)) {
            if (architectView != null) {

                int captureMode = ArchitectView.CaptureScreenCallback.CAPTURE_MODE_CAM_AND_WEBVIEW;

                try {
                    captureMode = (args.getBoolean(0))
                            ? ArchitectView.CaptureScreenCallback.CAPTURE_MODE_CAM_AND_WEBVIEW
                            : ArchitectView.CaptureScreenCallback.CAPTURE_MODE_CAM;
                } catch (Exception e) {
                    // unexpected error;
                }

                architectView.captureScreen(captureMode, new CaptureScreenCallback() {

                    @Override
                    public void onScreenCaptured(Bitmap screenCapture) {
                        try {
                            // final File imageDirectory = cordova.getActivity().getExternalFilesDir(Environment.DIRECTORY_PICTURES);
                            final File imageDirectory = Environment.getExternalStorageDirectory();
                            if (imageDirectory == null) {
                                callContext.error("External storage not available");
                            }

                            final File screenCaptureFile = new File(imageDirectory,
                                    System.currentTimeMillis() + ".jpg");

                            if (screenCaptureFile.exists()) {
                                screenCaptureFile.delete();
                            }
                            final FileOutputStream out = new FileOutputStream(screenCaptureFile);
                            screenCapture.compress(Bitmap.CompressFormat.JPEG, 90, out);
                            out.flush();
                            out.close();

                            cordova.getActivity().runOnUiThread(new Runnable() {

                                @Override
                                public void run() {
                                    final String absoluteCaptureImagePath = screenCaptureFile.getAbsolutePath();
                                    callContext.success(absoluteCaptureImagePath);

                                    //                         in case you want to sent the pic to other applications, uncomment these lines (for future use)
                                    //                        final Intent share = new Intent(Intent.ACTION_SEND);
                                    //                        share.setType("image/jpg");
                                    //                        share.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(screenCaptureFile));
                                    //                        final String chooserTitle = "Share Snaphot";
                                    //                        cordova.getActivity().startActivity(Intent.createChooser(share, chooserTitle));
                                }
                            });
                        } catch (Exception e) {
                            callContext.error(e.getMessage());
                        }

                    }
                });
                return true;
            }
        }

        /* life-cycle's RESUME */
        if (WikitudePlugin.ACTION_ON_RESUME.equals(action)) {

            if (this.architectView != null) {
                this.cordova.getActivity().runOnUiThread(new Runnable() {

                    @Override
                    public void run() {
                        WikitudePlugin.this.architectView.onResume();
                        callContext.success(action + ": architectView is present");
                        locationProvider.onResume();
                    }
                });

                // callContext.success( action + ": architectView is present" );
            } else {
                callContext.error(action + ": architectView is not present");
            }
            return true;
        }

        /* life-cycle's PAUSE */
        if (WikitudePlugin.ACTION_ON_PAUSE.equals(action)) {
            if (architectView != null) {
                this.cordova.getActivity().runOnUiThread(new Runnable() {

                    @Override
                    public void run() {
                        WikitudePlugin.this.architectView.onPause();
                        locationProvider.onPause();
                    }
                });

                callContext.success(action + ": architectView is present");
            } else {
                callContext.error(action + ": architectView is not present");
            }
            return true;
        }

        /* set visibility to "visible", return error if view is null */
        if (WikitudePlugin.ACTION_SHOW.equals(action)) {

            this.cordova.getActivity().runOnUiThread(new Runnable() {

                @Override
                public void run() {
                    if (architectView != null) {
                        architectView.setVisibility(View.VISIBLE);
                        callContext.success(action + ": architectView is present");
                    } else {
                        callContext.error(action + ": architectView is not present");
                    }
                }
            });

            return true;
        }

        /* set visibility to "invisible", return error if view is null */
        if (WikitudePlugin.ACTION_HIDE.equals(action)) {

            this.cordova.getActivity().runOnUiThread(new Runnable() {

                @Override
                public void run() {
                    if (architectView != null) {
                        architectView.setVisibility(View.INVISIBLE);
                        callContext.success(action + ": architectView is present");
                    } else {
                        callContext.error(action + ": architectView is not present");
                    }
                }
            });

            return true;
        }

        /* define call-back for url-invocations */
        if (WikitudePlugin.ACTION_ON_URLINVOKE.equals(action)) {
            this.urlInvokeCallback = callContext;
            final PluginResult result = new PluginResult(PluginResult.Status.NO_RESULT,
                    action + ": registered callback");
            result.setKeepCallback(true);
            callContext.sendPluginResult(result);
            return true;
        }

        /* location update */
        if (WikitudePlugin.ACTION_SET_LOCATION.equals(action)) {
            if (this.architectView != null) {
                try {
                    final double lat = args.getDouble(0);
                    final double lon = args.getDouble(1);
                    float alt = Float.MIN_VALUE;
                    try {
                        alt = (float) args.getDouble(2);
                    } catch (Exception e) {
                        // invalid altitude -> ignore it
                    }
                    final float altitude = alt;
                    Double acc = null;
                    try {
                        acc = args.getDouble(3);
                    } catch (Exception e) {
                        // invalid accuracy -> ignore it
                    }
                    final Double accuracy = acc;
                    if (this.cordova != null && this.cordova.getActivity() != null) {
                        cordova.getActivity().runOnUiThread(
                                //                  this.cordova.getThreadPool().execute( 
                                new Runnable() {

                                    @Override
                                    public void run() {
                                        if (accuracy != null) {
                                            WikitudePlugin.this.architectView.setLocation(lat, lon, altitude,
                                                    accuracy.floatValue());
                                        } else {
                                            WikitudePlugin.this.architectView.setLocation(lat, lon, altitude);
                                        }
                                    }
                                });
                    }

                } catch (Exception e) {
                    callContext.error(
                            action + ": exception thrown, " + e != null ? e.getMessage() : "(exception is NULL)");
                    return true;
                }
                callContext.success(action + ": updated location");
                return true;
            } else {
                /* return error if there is no architect-view active*/
                callContext.error(action + ": architectView is not present");
            }
            return true;
        }

        if (WikitudePlugin.ACTION_CALL_JAVASCRIPT.equals(action)) {

            String logMsg = null;
            try {
                final String callJS = args.getString(0);
                logMsg = callJS;

                this.cordova.getActivity().runOnUiThread(new Runnable() {

                    @Override
                    public void run() {
                        if (architectView != null) {
                            WikitudePlugin.this.architectView.callJavascript(callJS);
                        } else {
                            callContext.error(action + ": architectView is not present");
                        }
                    }
                });

            } catch (JSONException je) {
                callContext.error(
                        action + ": exception thrown, " + je != null ? je.getMessage() : "(exception is NULL)");
                return true;
            }
            callContext.success(action + ": called js, '" + logMsg + "'");

            return true;
        }

        /* initial set-up, show ArchitectView full-screen in current screen/activity */
        if (WikitudePlugin.ACTION_OPEN.equals(action)) {
            this.openCallback = callContext;
            PluginResult result = null;
            try {
                final String apiKey = args.getString(0);
                final String filePath = args.getString(1);

                this.cordova.getActivity().runOnUiThread(new Runnable() {

                    @Override
                    public void run() {
                        try {
                            WikitudePlugin.this.addArchitectView(apiKey, filePath);

                            /* call success method once architectView was added successfully */
                            if (openCallback != null) {
                                PluginResult result = new PluginResult(PluginResult.Status.OK);
                                result.setKeepCallback(false);
                                openCallback.sendPluginResult(result);
                            }
                        } catch (Exception e) {
                            /* in case "addArchitectView" threw an exception -> notify callback method asynchronously */
                            openCallback.error(e != null ? e.getMessage() : "Exception is 'null'");
                        }
                    }
                });

            } catch (Exception e) {
                result = new PluginResult(PluginResult.Status.ERROR,
                        action + ": exception thown, " + e != null ? e.getMessage() : "(exception is NULL)");
                result.setKeepCallback(false);
                callContext.sendPluginResult(result);
                return true;
            }

            /* adding architect-view is done in separate thread, ensure to setKeepCallback so one can call success-method properly later on */
            result = new PluginResult(PluginResult.Status.NO_RESULT,
                    action + ": no result required, just registered callback-method");
            result.setKeepCallback(true);
            callContext.sendPluginResult(result);
            return true;
        }

        /* fall-back return value */
        callContext.sendPluginResult(new PluginResult(PluginResult.Status.ERROR, "no such action: " + action));
        return false;
    }

    /**
     * called when url was invoked in architectView (by e.g. calling document.location = "myprotocoll://foo";
     * @param url the invoked url (e.g. "architectsdk://foo")
     * @return true if call was handled properly
     */
    @Override
    public boolean urlWasInvoked(final String url) {

        /* call callback-method if set*/
        if (this.urlInvokeCallback != null) {
            try {
                /* pass called url as String to callback-method */
                final PluginResult res = new PluginResult(PluginResult.Status.OK, url);
                res.setKeepCallback(true);
                this.urlInvokeCallback.sendPluginResult(res);
            } catch (Exception e) {
                this.urlInvokeCallback.error("invalid url invoked: " + url);
            }
            return true;
        }
        return false;
    }

    /**
     * hides/removes ARchitect-View completely
     * @return true if successful, false otherwise
     */
    private boolean removeArchitectView() {
        if (this.architectView != null) {

            /* fake life-cycle calls, because activity is already up and running */
            this.architectView.onPause();
            this.architectView.onDestroy();

            // clean-up used temp-directory
            try {
                WikitudePlugin.clearCacheFolder(
                        new File(ArchitectView.getCacheDirectoryAbsoluteFilePath(this.cordova.getActivity())), 0);
            } catch (Exception e) {
                // had troubles in clearing files from cache
                e.printStackTrace();
            }

            this.architectView.setVisibility(View.GONE);
            ((ViewManager) this.architectView.getParent()).removeView(this.architectView);
            this.architectView = null;

            WikitudePlugin.handleResumeInCordovaWebView(
                    cordova.getActivity().getWindow().getDecorView().findViewById(android.R.id.content));
            return true;
        }
        return false;
    }

    private static int clearCacheFolder(final File dir, final int numDays) {

        int deletedFiles = 0;
        if (dir != null && dir.isDirectory()) {
            try {
                for (File child : dir.listFiles()) {

                    //first delete subdirectories recursively
                    if (child.isDirectory()) {
                        deletedFiles += clearCacheFolder(child, numDays);
                    }

                    //then delete the files and subdirectories in this dir
                    //only empty directories can be deleted, so subdirs have been done first
                    if (child.lastModified() < new Date().getTime() - numDays * DateUtils.DAY_IN_MILLIS) {
                        if (child.delete()) {
                            deletedFiles++;
                        }
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return deletedFiles;
    }

    /**
     * Architect-Configuration required for proper set-up
     * @param apiKey
     * @return
     */
    protected ArchitectConfig getArchitectConfig(final String apiKey) {
        /* no special set-up required in default Wikitude-Plugin, further things required in advanced usage (e.g. Vuforia Image Recognition) */
        ArchitectConfig config = new ArchitectConfig(apiKey);
        config.setOrigin(ArchitectConfig.ORIGIN_PHONEGAP);
        return config;
    }

    /**
     * add architectView to current screen
     * @param apiKey developers's api key to use (hides watermarking/intro-animation if it matches your package-name)
     * @param filePath the url (starting with http:// for online use; starting with LOCAL_ASSETS_PATH_ROOT if oyu want to load assets within your app-assets folder)
     * @throws IOException might be thrown from ARchitect-SDK
     */
    private void addArchitectView(final String apiKey, String filePath) throws IOException {
        if (this.architectView == null) {

            this.architectView = new ArchitectViewPhoneGap(this.cordova.getActivity(), new OnKeyDownListener() {

                @Override
                public boolean onKeyDown(int keyCode, KeyEvent event) {
                    if (WikitudePlugin.this.architectView != null && keyCode == KeyEvent.KEYCODE_BACK) {
                        WikitudePlugin.this.locationProvider.onPause();
                        removeArchitectView();
                        return true;
                    }
                    return false;
                }
            });

            this.architectView.setFocusableInTouchMode(true);
            this.architectView.requestFocus();

            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) {
                    if (location != null) {
                        WikitudePlugin.this.lastKnownLocaton = location;
                        if (WikitudePlugin.this.architectView != null) {
                            if (location.hasAltitude()) {
                                WikitudePlugin.this.architectView.setLocation(location.getLatitude(),
                                        location.getLongitude(), location.getAltitude(), location.getAccuracy());
                            } else {
                                WikitudePlugin.this.architectView.setLocation(location.getLatitude(),
                                        location.getLongitude(), location.getAccuracy());
                            }
                        }
                    }
                }
            };

            /* add content view and fake initial life-cycle */
            (this.cordova.getActivity()).addContentView(this.architectView,
                    new ViewGroup.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));

            /* fake life-cycle calls, because activity is already up and running */
            this.architectView.onCreate(getArchitectConfig(apiKey));
            this.architectView.onPostCreate();

            /* register self as url listener to fwd these native calls to PhoneGap */
            this.architectView.registerUrlListener(WikitudePlugin.this);

            /* load asset from local directory if prefix is used */
            if (filePath.startsWith(WikitudePlugin.LOCAL_ASSETS_PATH_ROOT)) {
                filePath = filePath.substring(WikitudePlugin.LOCAL_ASSETS_PATH_ROOT.length());
            }
            this.architectView.load(filePath);

            /* also a fake-life-cycle call (the last one before it is really shown in UI */
            this.architectView.onResume();

            this.locationProvider = new LocationProvider(this.cordova.getActivity(), this.locationListener);

            this.locationProvider.onResume();

        }

        // hide keyboard when adding AR view on top of views
        InputMethodManager inputManager = (InputMethodManager) (this.cordova.getActivity())
                .getSystemService(Context.INPUT_METHOD_SERVICE);
        inputManager.hideSoftInputFromWindow((this.cordova.getActivity()).getCurrentFocus().getWindowToken(),
                InputMethodManager.HIDE_NOT_ALWAYS);
    }

    /**
     * 
     * @return true if device chip has neon-command support
     */
    private boolean hasNeonSupport() {
        /* Read cpu info */

        FileInputStream fis;
        try {
            fis = new FileInputStream("/proc/cpuinfo");

        } catch (FileNotFoundException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
            return false;
        }

        Scanner scanner = new Scanner(fis);

        boolean neonSupport = false;

        try {

            while (scanner.hasNextLine()) {

                if (!neonSupport && (scanner.findInLine("neon") != null)) {

                    neonSupport = true;

                }

                scanner.nextLine();

            }

        } catch (Exception e) {

            Log.i("Wikitudeplugin", "error while getting info about neon support" + e.getMessage());
            e.printStackTrace();

        } finally {

            scanner.close();

        }

        return neonSupport;
    }

    /**
     * To avoid JavaScript in Cordova staying paused after CordovaWebView lost focus call "handleResume" of the CordovaView in current Activity
     * @param rootView the root view to search recursively for a CordovaWebView
     */
    private static void handleResumeInCordovaWebView(final View rootView) {
        if (rootView instanceof CordovaWebView) {
            ((CordovaWebView) rootView).handleResume(true, true);
            ((CordovaWebView) rootView).requestFocus();
        } else if (rootView instanceof ViewGroup) {
            final int childCount = ((ViewGroup) rootView).getChildCount();
            for (int i = 0; i < childCount; i++) {
                WikitudePlugin.handleResumeInCordovaWebView(((ViewGroup) rootView).getChildAt(i));
            }
        }
    }

    protected static class ArchitectViewPhoneGap extends ArchitectView {
        public static interface OnKeyDownListener {
            public boolean onKeyDown(int keyCode, KeyEvent event);
        }

        private final OnKeyDownListener onKeyDownListener;

        @Deprecated
        public ArchitectViewPhoneGap(Context context) {
            super(context);
            this.onKeyDownListener = null;
        }

        public ArchitectViewPhoneGap(Context context, OnKeyDownListener onKeyDownListener) {
            super(context);
            this.onKeyDownListener = onKeyDownListener;
        }

        @Override
        public boolean onKeyDown(int keyCode, KeyEvent event) {
            // forward onKeyDown events to listener
            return this.onKeyDownListener != null && this.onKeyDownListener.onKeyDown(keyCode, event);
        }

        @Override
        protected void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) {
            super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);

            // ensure architectView does not loose focus on screen orientation changes etc.
            if (!gainFocus) {
                this.requestFocus();
            }
        }
    }

    /**
     * Sample implementation of a locationProvider, feel free to polish this very basic approach (compare http://goo.gl/pvkXV )
     * @author Wikitude GmbH
     *
     */
    private static class LocationProvider implements ILocationProvider {

        /** location listener called on each location update */
        private final LocationListener locationListener;

        /** system's locationManager allowing access to GPS / Network position */
        private final LocationManager locationManager;

        /** location updates should fire approximately every second */
        private static final int LOCATION_UPDATE_MIN_TIME_GPS = 1000;

        /** location updates should fire, even if last signal is same than current one (0m distance to last location is OK) */
        private static final int LOCATION_UPDATE_DISTANCE_GPS = 0;

        /** location updates should fire approximately every second */
        private static final int LOCATION_UPDATE_MIN_TIME_NW = 1000;

        /** location updates should fire, even if last signal is same than current one (0m distance to last location is OK) */
        private static final int LOCATION_UPDATE_DISTANCE_NW = 0;

        /** to faster access location, even use 10 minute old locations on start-up */
        private static final int LOCATION_OUTDATED_WHEN_OLDER_MS = 1000 * 60 * 10;

        /** is gpsProvider and networkProvider enabled in system settings */
        private boolean gpsProviderEnabled, networkProviderEnabled;

        /** the context in which we're running */
        private final Context context;

        public LocationProvider(final Context context, LocationListener locationListener) {
            super();
            this.locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
            this.locationListener = locationListener;
            this.context = context;
            this.gpsProviderEnabled = this.locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
            this.networkProviderEnabled = this.locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
        }

        @Override
        public void onPause() {
            if (this.locationListener != null && this.locationManager != null
                    && (this.gpsProviderEnabled || this.networkProviderEnabled)) {
                this.locationManager.removeUpdates(this.locationListener);
            }
        }

        @Override
        public void onResume() {
            if (this.locationManager != null && this.locationListener != null) {

                // check which providers are available are available
                this.gpsProviderEnabled = this.locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
                this.networkProviderEnabled = this.locationManager
                        .isProviderEnabled(LocationManager.NETWORK_PROVIDER);

                /** is GPS provider enabled? */
                if (this.gpsProviderEnabled) {
                    final Location lastKnownGPSLocation = this.locationManager
                            .getLastKnownLocation(LocationManager.GPS_PROVIDER);
                    if (lastKnownGPSLocation != null && lastKnownGPSLocation.getTime() > System.currentTimeMillis()
                            - LOCATION_OUTDATED_WHEN_OLDER_MS) {
                        locationListener.onLocationChanged(lastKnownGPSLocation);
                    }
                    this.locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,
                            LOCATION_UPDATE_MIN_TIME_GPS, LOCATION_UPDATE_DISTANCE_GPS, this.locationListener);
                }

                /** is Network / WiFi positioning provider available? */
                if (this.networkProviderEnabled) {
                    final Location lastKnownNWLocation = this.locationManager
                            .getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
                    if (lastKnownNWLocation != null && lastKnownNWLocation.getTime() > System.currentTimeMillis()
                            - LOCATION_OUTDATED_WHEN_OLDER_MS) {
                        locationListener.onLocationChanged(lastKnownNWLocation);
                    }
                    this.locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER,
                            LOCATION_UPDATE_MIN_TIME_NW, LOCATION_UPDATE_DISTANCE_NW, this.locationListener);
                }

                /** user didn't check a single positioning in the location settings, recommended: handle this event properly in your app, e.g. forward user directly to location-settings, new Intent( Settings.ACTION_LOCATION_SOURCE_SETTINGS ) */
                if (!this.gpsProviderEnabled && !this.networkProviderEnabled) {
                    Toast.makeText(this.context, "Please enable GPS and Network positioning in your Settings ",
                            Toast.LENGTH_LONG).show();
                }
            }
        }
    }

    private interface ILocationProvider {

        /**
         * Call when host-activity is resumed (usually within systems life-cycle method)
         */
        public void onResume();

        /**
         * Call when host-activity is paused (usually within systems life-cycle method)
         */
        public void onPause();

    }

}