diff --git a/plugin.xml b/plugin.xml
index 68a46ff3..a0df6414 100755
--- a/plugin.xml
+++ b/plugin.xml
@@ -41,6 +41,7 @@
 			
 			
 			
+			
 			
 			
 			
@@ -56,6 +57,13 @@
 				
 			
 			
+			
+
+			
+			
 		
 
 		
@@ -63,7 +71,13 @@
 		
 		
 		
+		
+		
+		
+		
+
 		
+		
 
 	
 
diff --git a/src/android/com/plugin/android-support-v13.jar b/src/android/com/plugin/android-support-v13.jar
index cd47212b..3c1de8a2 100644
Binary files a/src/android/com/plugin/android-support-v13.jar and b/src/android/com/plugin/android-support-v13.jar differ
diff --git a/src/android/com/plugin/gcm/AlertDialogActivity.java b/src/android/com/plugin/gcm/AlertDialogActivity.java
new file mode 100644
index 00000000..3648c871
--- /dev/null
+++ b/src/android/com/plugin/gcm/AlertDialogActivity.java
@@ -0,0 +1,55 @@
+package com.plugin.gcm;
+
+import android.os.Bundle;
+import android.support.v4.app.FragmentActivity;
+import android.util.Log;
+import android.view.Window;
+import android.view.WindowManager;
+import android.os.Vibrator;
+import android.content.Context;
+import android.app.KeyguardManager;
+import android.content.Context;
+
+public class AlertDialogActivity extends FragmentActivity {
+    private static final String TAG = "AlertDialogActivity";
+
+	private	KeyguardManager	_KeyguardManager;
+	private	boolean			_bScreenLocked = false;
+ 
+	public AlertDialogActivity() {
+        Log.d(TAG, "AlertDialogActivity#AlertDialogActivity(): check-1");
+	}
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        Bundle extras = getIntent().getExtras();
+        AlertDialogFragment fragment = new AlertDialogFragment(extras);
+        fragment.show(getSupportFragmentManager(), "alert_dialog");
+        Log.d(TAG, "AlertDialogActivity#onCreate(): check-1");
+
+		_KeyguardManager = (KeyguardManager)getSystemService(Context.KEYGUARD_SERVICE);
+		_bScreenLocked = _KeyguardManager.inKeyguardRestrictedInputMode();
+    }
+
+	@Override
+	public void onAttachedToWindow() {
+        Log.d(TAG, "AlertDialogActivity#onAttachedToWindow(): check-1");
+	    Window window = getWindow();
+	    window.addFlags(WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON	// スクリーンをONにする
+	            | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED		// ロック画面の場合でも表示する
+	            | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
+	}
+	@Override
+	public void onStop() {
+		super.onStop();
+		_bScreenLocked = _KeyguardManager.inKeyguardRestrictedInputMode();
+		if(!_bScreenLocked)
+		{
+			final Vibrator vibrator = 
+					(Vibrator)getSystemService(Context.VIBRATOR_SERVICE);
+			vibrator.cancel();
+		}
+	}
+}
diff --git a/src/android/com/plugin/gcm/AlertDialogFragment.java b/src/android/com/plugin/gcm/AlertDialogFragment.java
new file mode 100644
index 00000000..48b33172
--- /dev/null
+++ b/src/android/com/plugin/gcm/AlertDialogFragment.java
@@ -0,0 +1,112 @@
+package com.plugin.gcm;
+
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.NotificationManager;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.Context;
+import android.os.Bundle;
+import android.os.Vibrator;
+import android.support.v4.app.DialogFragment;
+import android.util.Log;
+import android.graphics.Bitmap;
+import android.net.Uri;
+import android.graphics.drawable.BitmapDrawable;
+
+import com.google.gson.Gson;
+ 
+public class AlertDialogFragment extends DialogFragment {
+    private static final String TAG = "AlertDialogFragment";
+	private Bundle extras;
+    private AssetUtil assets;
+
+	public AlertDialogFragment(Bundle extras) {
+		this.extras = extras;
+	}
+ 
+    @Override
+    public Dialog onCreateDialog(Bundle savedInstanceState) {
+        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+        final Bundle originalExtras = extras.getBundle("pushBundle");
+		final Context context = getActivity().getApplicationContext();
+        final NotificationManager notificationManager = 
+				(NotificationManager)getActivity().getSystemService(Context.NOTIFICATION_SERVICE);
+		final Vibrator vibrator = 
+				(Vibrator)getActivity().getSystemService(Context.VIBRATOR_SERVICE);
+        String vibrateStrValue = originalExtras.getString("vibrate");
+        final long[] pattern = strValueToLongArray(vibrateStrValue);
+		Log.v(TAG, "onCreateDialog(): icon = "+ originalExtras.getString("icon"));
+		assets = AssetUtil.getInstance(context);
+		final Bitmap largeIcon = getLargeIcon(originalExtras.getString("icon"));
+
+		final int notId = Integer.parseInt(originalExtras.getString("notId"));
+        final String appName = GCMIntentService.getAppName(context);
+		Log.v(TAG, "onCreateDialog(): notId = "+ notId);
+        Dialog dialog = builder
+				.setTitle(originalExtras.getString("title"))
+				.setMessage(originalExtras.getString("text"))
+                .setIcon(new BitmapDrawable(largeIcon))
+				.setPositiveButton("OK", new DialogInterface.OnClickListener() {
+					@Override
+					public void onClick(DialogInterface dialog, int which) {
+						Intent intent = new Intent(context, PushHandlerActivity.class);
+						intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);
+						intent.putExtra("pushBundle", originalExtras);
+						startActivity(intent);
+						notificationManager.cancel(appName, notId);
+						vibrator.cancel();
+					}
+				})
+				.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
+					@Override
+					public void onClick(DialogInterface dialog, int which) {
+						vibrator.cancel();
+					}
+				})
+				.create();
+        dialog.setCanceledOnTouchOutside(false);
+		vibrator.vibrate(pattern, -1);
+ 
+        return dialog;
+    }
+
+    private long[] strValueToLongArray(String vibrateStrValue) {
+        Gson gson = new Gson();
+
+        return gson.fromJson(vibrateStrValue, long[].class);
+    }
+
+    @Override
+    public void onStop() {
+        super.onStop();
+        getActivity().finish();
+    }
+
+    public int getSmallIcon(String smallIcon) {
+        int resId = assets.getResIdForDrawable(smallIcon);
+
+        if (resId == 0) {
+            resId = android.R.drawable.ic_menu_mylocation;
+        }
+
+        return resId;
+    }
+
+    public Bitmap getLargeIcon(String icon) {
+        Bitmap bmp;
+
+		Log.d(TAG, "getLargeIcon(): icon = "+ icon);
+
+        try{
+            Uri uri = assets.parse(icon);
+			Log.d(TAG, "getLargeIcon(): uri = "+ uri);
+            bmp = assets.getIconFromUri(uri);
+        } catch (Exception e){
+            bmp = assets.getIconFromDrawable(icon);
+        }
+		Log.d(TAG, "getLargeIcon(): bmp = "+ bmp);
+
+        return bmp;
+    }
+}
diff --git a/src/android/com/plugin/gcm/AssetUtil.java b/src/android/com/plugin/gcm/AssetUtil.java
new file mode 100644
index 00000000..97689152
--- /dev/null
+++ b/src/android/com/plugin/gcm/AssetUtil.java
@@ -0,0 +1,442 @@
+/*
+Taken from https://github.com/katzer/cordova-plugin-local-notifications plugin
+ */
+
+/*
+ * Copyright (c) 2013-2015 by appPlant UG. All rights reserved.
+ *
+ * @APPPLANT_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apache License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://opensource.org/licenses/Apache-2.0/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPPLANT_LICENSE_HEADER_END@
+ */
+
+package com.plugin.gcm;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
+import java.net.URL;
+
+import android.content.Context;
+import android.content.res.AssetManager;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.media.RingtoneManager;
+import android.net.Uri;
+import android.os.StrictMode;
+import android.util.Log;
+
+/**
+ * Util class to map unified asset URIs to native URIs. URIs like file:///
+ * map to absolute paths while file:// point relatively to the www folder
+ * within the asset resources. And res:// means a resource from the native
+ * res folder. Remote assets are accessible via http:// for example.
+ */
+class AssetUtil {
+
+    // Name of the storage folder
+    private static final String STORAGE_FOLDER = "/geofence_notifications";
+
+    // Placeholder URI for default sound
+    private static final String DEFAULT_SOUND = "res://platform_default";
+
+    // Ref to the context passed through the constructor to access the
+    // resources and app directory.
+    private final Context context;
+
+    /**
+     * Constructor
+     *
+     * @param context
+     *      Application context
+     */
+    private AssetUtil(Context context) {
+        this.context = context;
+    }
+
+    /**
+     * Static method to retrieve class instance.
+     *
+     * @param context
+     *      Application context
+     */
+    static AssetUtil getInstance(Context context) {
+        return new AssetUtil(context);
+    }
+
+    /**
+     * Parse path path to native URI.
+     *
+     * @param path
+     *      Path to path file
+     */
+    Uri parseSound (String path) {
+
+        if (path == null || path.isEmpty())
+            return Uri.EMPTY;
+
+        if (path.equalsIgnoreCase(DEFAULT_SOUND)) {
+            return RingtoneManager.getDefaultUri(RingtoneManager
+                    .TYPE_NOTIFICATION);
+        }
+
+        return parse(path);
+    }
+
+    /**
+     * The URI for a path.
+     *
+     * @param path
+     *      The given path
+     */
+    Uri parse (String path) {
+
+        if (path.startsWith("res:")) {
+            return getUriForResourcePath(path);
+        } else if (path.startsWith("file:///")) {
+            return getUriFromPath(path);
+        } else if (path.startsWith("file://")) {
+            return getUriFromAsset(path);
+        } else if (path.startsWith("http")){
+            return getUriFromRemote(path);
+        }
+
+        return Uri.EMPTY;
+    }
+
+
+
+    /**
+     * URI for a file.
+     *
+     * @param path
+     *      Absolute path like file:///...
+     *
+     * @return
+     *      URI pointing to the given path
+     */
+    private Uri getUriFromPath(String path) {
+        String absPath = path.replaceFirst("file://", "");
+        File file = new File(absPath);
+
+        if (!file.exists()) {
+            Log.e("Asset", "File not found: " + file.getAbsolutePath());
+            return Uri.EMPTY;
+        }
+
+        return Uri.fromFile(file);
+    }
+
+    /**
+     * URI for an asset.
+     *
+     * @param path
+     *      Asset path like file://...
+     *
+     * @return
+     *      URI pointing to the given path
+     */
+    private Uri getUriFromAsset(String path) {
+        File dir = context.getExternalCacheDir();
+
+        if (dir == null) {
+            Log.e("Asset", "Missing external cache dir");
+            return Uri.EMPTY;
+        }
+
+        String resPath  = path.replaceFirst("file:/", "www");
+        String fileName = resPath.substring(resPath.lastIndexOf('/') + 1);
+        String storage  = dir.toString() + STORAGE_FOLDER;
+        File file       = new File(storage, fileName);
+
+        //noinspection ResultOfMethodCallIgnored
+        new File(storage).mkdir();
+
+        try {
+            AssetManager assets = context.getAssets();
+            FileOutputStream outStream = new FileOutputStream(file);
+            InputStream inputStream = assets.open(resPath);
+
+            copyFile(inputStream, outStream);
+
+            outStream.flush();
+            outStream.close();
+
+            return Uri.fromFile(file);
+
+        } catch (Exception e) {
+            Log.e("Asset", "File not found: assets/" + resPath);
+            e.printStackTrace();
+        }
+
+        return Uri.EMPTY;
+    }
+
+    /**
+     * The URI for a resource.
+     *
+     * @param path
+     *            The given relative path
+     *
+     * @return
+     *      URI pointing to the given path
+     */
+    private Uri getUriForResourcePath(String path) {
+        File dir = context.getExternalCacheDir();
+
+        if (dir == null) {
+            Log.e("Asset", "Missing external cache dir");
+            return Uri.EMPTY;
+        }
+
+        String resPath = path.replaceFirst("res://", "");
+
+        int resId = getResIdForDrawable(resPath);
+
+        if (resId == 0) {
+            Log.e("Asset", "File not found: " + resPath);
+            return Uri.EMPTY;
+        }
+
+        String resName = extractResourceName(resPath);
+        String extName = extractResourceExtension(resPath);
+        String storage = dir.toString() + STORAGE_FOLDER;
+        File file      = new File(storage, resName + extName);
+
+        //noinspection ResultOfMethodCallIgnored
+        new File(storage).mkdir();
+
+        try {
+            Resources res = context.getResources();
+            FileOutputStream outStream = new FileOutputStream(file);
+            InputStream inputStream = res.openRawResource(resId);
+            copyFile(inputStream, outStream);
+
+            outStream.flush();
+            outStream.close();
+
+            return Uri.fromFile(file);
+
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+
+        return Uri.EMPTY;
+    }
+
+    /**
+     * Uri from remote located content.
+     *
+     * @param path
+     *      Remote address
+     *
+     * @return
+     *      Uri of the downloaded file
+     */
+    private Uri getUriFromRemote(String path) {
+        File dir = context.getExternalCacheDir();
+
+        if (dir == null) {
+            Log.e("Asset", "Missing external cache dir");
+            return Uri.EMPTY;
+        }
+
+        String resName  = extractResourceName(path);
+        String extName  = extractResourceExtension(path);
+        String storage  = dir.toString() + STORAGE_FOLDER;
+        File file       = new File(storage, resName + extName);
+
+        //noinspection ResultOfMethodCallIgnored
+        new File(storage).mkdir();
+
+        try {
+            URL url = new URL(path);
+            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
+
+            StrictMode.ThreadPolicy policy =
+                    new StrictMode.ThreadPolicy.Builder().permitAll().build();
+
+            StrictMode.setThreadPolicy(policy);
+
+            connection.setRequestProperty("Connection", "close");
+            connection.setConnectTimeout(5000);
+            connection.connect();
+
+            InputStream input = connection.getInputStream();
+            FileOutputStream outStream = new FileOutputStream(file);
+
+            copyFile(input, outStream);
+
+            outStream.flush();
+            outStream.close();
+
+            return Uri.fromFile(file);
+
+        } catch (MalformedURLException e) {
+            Log.e("Asset", "Incorrect URL");
+            e.printStackTrace();
+        } catch (FileNotFoundException e) {
+            Log.e("Asset", "Failed to create new File from HTTP Content");
+            e.printStackTrace();
+        } catch (IOException e) {
+            Log.e("Asset", "No Input can be created from http Stream");
+            e.printStackTrace();
+        }
+
+        return Uri.EMPTY;
+    }
+
+    /**
+     * Copy content from input stream into output stream.
+     *
+     * @param in
+     *      The input stream
+     * @param out
+     *      The output stream
+     */
+    private void copyFile(InputStream in, OutputStream out) throws IOException {
+        byte[] buffer = new byte[1024];
+        int read;
+
+        while ((read = in.read(buffer)) != -1) {
+            out.write(buffer, 0, read);
+        }
+    }
+
+    /**
+     * Resource ID for drawable.
+     *
+     * @param resPath
+     *      Resource path as string
+     */
+    int getResIdForDrawable(String resPath) {
+        int resId = getResIdForDrawable(getPkgName(), resPath);
+
+        if (resId == 0) {
+            resId = getResIdForDrawable("android", resPath);
+        }
+
+        return resId;
+    }
+
+    /**
+     * Resource ID for drawable.
+     *
+     * @param clsName
+     *      Relative package or global android name space
+     * @param resPath
+     *      Resource path as string
+     */
+    int getResIdForDrawable(String clsName, String resPath) {
+        String drawable = extractResourceName(resPath);
+        int resId = 0;
+
+        try {
+            Class> cls  = Class.forName(clsName + ".R$drawable");
+
+            resId = (Integer) cls.getDeclaredField(drawable).get(Integer.class);
+        } catch (Exception ignore) {}
+
+        return resId;
+    }
+
+    /**
+     * Convert drawable resource to bitmap.
+     *
+     * @param drawable
+     *      Drawable resource name
+     */
+    Bitmap getIconFromDrawable (String drawable) {
+        Resources res = context.getResources();
+        int iconId;
+
+        iconId = getResIdForDrawable(getPkgName(), drawable);
+
+        if (iconId == 0) {
+            iconId = getResIdForDrawable("android", drawable);
+        }
+
+        if (iconId == 0) {
+            iconId = android.R.drawable.ic_menu_info_details;
+        }
+
+        return BitmapFactory.decodeResource(res, iconId);
+    }
+
+    /**
+     * Convert URI to Bitmap.
+     *
+     * @param uri
+     *      Internal image URI
+     */
+    Bitmap getIconFromUri (Uri uri) throws IOException {
+        InputStream input = context.getContentResolver().openInputStream(uri);
+
+        return BitmapFactory.decodeStream(input);
+    }
+
+    /**
+     * Extract name of drawable resource from path.
+     *
+     * @param resPath
+     *      Resource path as string
+     */
+    private String extractResourceName (String resPath) {
+        String drawable = resPath;
+
+        if (drawable.contains("/")) {
+            drawable = drawable.substring(drawable.lastIndexOf('/') + 1);
+        }
+
+        if (resPath.contains(".")) {
+            drawable = drawable.substring(0, drawable.lastIndexOf('.'));
+        }
+
+        return drawable;
+    }
+
+    /**
+     * Extract extension of drawable resource from path.
+     *
+     * @param resPath
+     *      Resource path as string
+     */
+    private String extractResourceExtension (String resPath) {
+        String extName = "png";
+
+        if (resPath.contains(".")) {
+            extName = resPath.substring(resPath.lastIndexOf('.'));
+        }
+
+        return extName;
+    }
+
+    /**
+     * Package name specified by context.
+     */
+    private String getPkgName () {
+        return context.getPackageName();
+    }
+
+}
diff --git a/src/android/com/plugin/gcm/GCMIntentService.java b/src/android/com/plugin/gcm/GCMIntentService.java
index caee145e..e92d4bac 100644
--- a/src/android/com/plugin/gcm/GCMIntentService.java
+++ b/src/android/com/plugin/gcm/GCMIntentService.java
@@ -7,18 +7,34 @@
 import android.app.Notification;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
+import android.app.Activity;
 import android.content.Context;
 import android.content.Intent;
 import android.os.Bundle;
 import android.support.v4.app.NotificationCompat;
 import android.util.Log;
+import android.app.AlertDialog;
+import android.content.DialogInterface;
+
+
+import android.location.Location;
+import android.location.LocationListener;
+import android.location.LocationManager;
+import android.location.LocationProvider;
+import android.location.Criteria;
+
+import android.graphics.Bitmap;
+import android.net.Uri;
 
 import com.google.android.gcm.GCMBaseIntentService;
 
+import com.google.gson.Gson;
+
 @SuppressLint("NewApi")
 public class GCMIntentService extends GCMBaseIntentService {
 
 	private static final String TAG = "GCMIntentService";
+    private AssetUtil assets;
 	
 	public GCMIntentService() {
 		super("GCMIntentService");
@@ -55,12 +71,24 @@ public void onUnregistered(Context context, String regId) {
 		Log.d(TAG, "onUnregistered - regId: " + regId);
 	}
 
+
 	@Override
 	protected void onMessage(Context context, Intent intent) {
 		Log.d(TAG, "onMessage - context: " + context);
+		Bundle extras = intent.getExtras();
+		String listenerType = extras.getString("listener");
+
+		Log.d(TAG, "onMessage: listenerType == " + listenerType);
+		if (listenerType.equals("SendGeolocationRequest")) {
+			Log.d(TAG, "onMessage: check-1");
+			String url   = extras.getString("url");
+			String token = extras.getString("token");
+			Log.d(TAG, "onMessage: url = " + url);
+			sendGeolocation(url, token);
+			return;
+		}
 
 		// Extract the payload from the message
-		Bundle extras = intent.getExtras();
 		if (extras != null)
 		{
 			// if we are in the foreground, just surface the payload, else post it to the statusbar
@@ -70,15 +98,25 @@ protected void onMessage(Context context, Intent intent) {
 			}
 			else {
 				extras.putBoolean("foreground", false);
-
-                // Send a notification if there is a message
-                if (extras.getString("message") != null && extras.getString("message").length() != 0) {
-                    createNotification(context, extras);
-                }
+				createNotification(context, extras);
+				showDialog(context, extras);
             }
         }
 	}
 
+	private void showDialog(Context context, Bundle extras) {
+        Intent intent = new Intent(this, AlertDialogActivity.class);
+		intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);//新規起動の記述
+		intent.putExtra("pushBundle", extras);
+		startActivity(intent);
+	}
+
+	private long[] strValueToLongArray(String vibrateStrValue) {
+		Gson gson = new Gson();
+
+		return gson.fromJson(vibrateStrValue, long[].class);
+	}
+
 	public void createNotification(Context context, Bundle extras)
 	{
 		NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
@@ -97,24 +135,29 @@ public void createNotification(Context context, Bundle extras)
 				defaults = Integer.parseInt(extras.getString("defaults"));
 			} catch (NumberFormatException e) {}
 		}
+
+		assets = AssetUtil.getInstance(context);
+		// int    smallIcon = getSmallIcon(extras.getString("smallIcon"));
+		Log.d(TAG, "createNotification(): icon = " + extras.getString("icon"));
+		Bitmap largeIcon = getLargeIcon(extras.getString("icon"));
 		
+ 		String vibrateStrValue = extras.getString("vibrate");
+		long[] vibrate = strValueToLongArray(vibrateStrValue);
+
 		NotificationCompat.Builder mBuilder =
 			new NotificationCompat.Builder(context)
-				.setDefaults(defaults)
+				//.setDefaults(defaults)
 				.setSmallIcon(context.getApplicationInfo().icon)
+                .setLargeIcon(largeIcon)
+				//.setSmallIcon(smallIcon)
+                .setVibrate(vibrate)
 				.setWhen(System.currentTimeMillis())
 				.setContentTitle(extras.getString("title"))
+				.setContentText(extras.getString("text"))
 				.setTicker(extras.getString("title"))
 				.setContentIntent(contentIntent)
 				.setAutoCancel(true);
 
-		String message = extras.getString("message");
-		if (message != null) {
-			mBuilder.setContentText(message);
-		} else {
-			mBuilder.setContentText("");
-		}
-
 		String msgcnt = extras.getString("msgcnt");
 		if (msgcnt != null) {
 			mBuilder.setNumber(Integer.parseInt(msgcnt));
@@ -131,11 +174,12 @@ public void createNotification(Context context, Bundle extras)
 		catch(Exception e) {
 			Log.e(TAG, "Number format exception - Error parsing Notification ID" + e.getMessage());
 		}
+		Log.d(TAG, "createNotification(): notId = " + notId);
 		
 		mNotificationManager.notify((String) appName, notId, mBuilder.build());
 	}
 	
-	private static String getAppName(Context context)
+	public static String getAppName(Context context)
 	{
 		CharSequence appName = 
 				context
@@ -144,10 +188,44 @@ private static String getAppName(Context context)
 		
 		return (String)appName;
 	}
-	
+
 	@Override
 	public void onError(Context context, String errorId) {
 		Log.e(TAG, "onError - errorId: " + errorId);
 	}
+	
+	private void sendGeolocation(String url, String token) {
+		Log.d(TAG, "sendGeolocation: check-1");
+		Log.d(TAG, "sendGeolocation: url   = " + url);
+		Log.d(TAG, "sendGeolocation: token = " + token);
+
+		Intent broadcastIntent = new Intent();
+		broadcastIntent.putExtra( "url", url);
+		broadcastIntent.putExtra( "token", token);
+		broadcastIntent.setAction("com.plugin.gcm.LocationUpdateService");
+		getBaseContext().sendBroadcast(broadcastIntent); 
+	}
+
+    public int getSmallIcon(String smallIcon) {
+        int resId = assets.getResIdForDrawable(smallIcon);
+
+        if (resId == 0) {
+            resId = android.R.drawable.ic_menu_mylocation;
+        }
+
+        return resId;
+    }
+
+    public Bitmap getLargeIcon(String icon) {
+        Bitmap bmp;
+
+        try{
+            Uri uri = assets.parse(icon);
+            bmp = assets.getIconFromUri(uri);
+        } catch (Exception e){
+            bmp = assets.getIconFromDrawable(icon);
+        }
 
+        return bmp;
+    }
 }
diff --git a/src/android/com/plugin/gcm/LocationUpdateService.java b/src/android/com/plugin/gcm/LocationUpdateService.java
new file mode 100644
index 00000000..a16e8838
--- /dev/null
+++ b/src/android/com/plugin/gcm/LocationUpdateService.java
@@ -0,0 +1,188 @@
+package com.plugin.gcm;
+
+import java.util.List;
+import java.util.Iterator;
+
+import org.apache.http.HttpResponse;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.client.DefaultHttpClient;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import android.media.AudioManager;
+import android.media.ToneGenerator;
+
+import android.app.PendingIntent;
+import android.app.Service;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.BroadcastReceiver;
+
+import android.location.Location;
+import android.location.Criteria;
+import android.location.LocationListener;
+import android.location.LocationManager;
+
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
+
+import android.os.AsyncTask;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.IBinder;
+
+import android.util.Log;
+
+import static java.lang.Math.*;
+
+public class LocationUpdateService extends Service {
+    private static final String TAG = "LocationUpdateService";
+    private static final String SINGLE_LOCATION_UPDATE_ACTION   = "SINGLE_LOCATION_UPDATE_ACTION";
+
+    private PendingIntent singleUpdatePI;
+    private Criteria criteria;
+    private LocationManager locationManager;
+	private String url;
+	private String token;
+	private JSONObject params = new JSONObject();
+
+    private BroadcastReceiver receiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+			Log.d(TAG, "onReceive(): enter");
+            url   = (String)intent.getExtras().get("url");
+            token = (String)intent.getExtras().get("token");
+			Log.d(TAG, "onReceive(): url = " + url);
+			Log.d(TAG, "onReceive(): token = " + token);
+            criteria.setAccuracy(Criteria.ACCURACY_FINE);
+            criteria.setHorizontalAccuracy(Criteria.ACCURACY_HIGH);
+            criteria.setPowerRequirement(Criteria.POWER_HIGH);
+            locationManager.requestSingleUpdate(criteria, singleUpdatePI);
+			Log.d(TAG, "onReceive(): leave");
+        }
+    };
+
+    @Override
+    public void onCreate() {
+        super.onCreate();
+        Log.i(TAG, "OnCreate");
+
+        locationManager         = (LocationManager)this.getSystemService(Context.LOCATION_SERVICE);
+
+        // One-shot PI (TODO currently unused)
+        singleUpdatePI = PendingIntent.getBroadcast(this, 0, new Intent(SINGLE_LOCATION_UPDATE_ACTION), PendingIntent.FLAG_CANCEL_CURRENT);
+        registerReceiver(singleUpdateReceiver, new IntentFilter(SINGLE_LOCATION_UPDATE_ACTION));
+        registerReceiver(receiver, new IntentFilter("com.plugin.gcm.LocationUpdateService"));
+
+        // Location criteria
+        criteria = new Criteria();
+        criteria.setAltitudeRequired(false);
+        criteria.setBearingRequired(false);
+        criteria.setSpeedRequired(true);
+        criteria.setCostAllowed(true);
+    }
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        // TODO Auto-generated method stub
+        Log.i(TAG, "OnBind" + intent);
+        return null;
+    }
+
+    @Override
+    public int onStartCommand(Intent intent, int flags, int startId) {
+        Log.i(TAG, "Received start id " + startId + ": " + intent);
+        return START_REDELIVER_INTENT;
+    }
+
+    @Override
+    public boolean stopService(Intent intent) {
+        Log.i(TAG, "- Received stop: " + intent);
+        return super.stopService(intent);
+    }
+
+    private BroadcastReceiver singleUpdateReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+			Log.d(TAG, "- singleUpdateReciever()");
+            String key = LocationManager.KEY_LOCATION_CHANGED;
+            Location location = (Location)intent.getExtras().get(key);
+            if (location == null) {
+				return ;
+			}
+			Log.d(TAG, "- singleUpdateReciever" + location.toString());
+
+			PostLocationTask task = 
+					new LocationUpdateService.PostLocationTask(location);
+			task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+        }
+    };
+
+    private boolean postLocation(Location l) {
+        try {
+            Log.i(TAG, "Posting  native location update: " + l);
+            DefaultHttpClient httpClient = new DefaultHttpClient();
+            HttpPost request = new HttpPost(this.url);
+
+            JSONObject location = new JSONObject();
+            location.put("latitude", l.getLatitude());
+            location.put("longitude", l.getLongitude());
+            params.put("location", location);
+            params.put("token", this.token);
+            params.put("trigger_name", "GCM");
+
+            Log.i(TAG, "location: " + location.toString());
+
+            StringEntity se = new StringEntity(params.toString());
+            request.setEntity(se);
+            request.setHeader("Accept", "application/json");
+            request.setHeader("Content-type", "application/json");
+
+            Log.d(TAG, "Posting to " + request.getURI().toString());
+            HttpResponse response = httpClient.execute(request);
+            Log.i(TAG, "Response received: " + response.getStatusLine());
+            if ((response.getStatusLine().getStatusCode() >= 200) &&
+                (response.getStatusLine().getStatusCode() <= 299)) {
+                return true;
+            } else {
+                return false;
+            }
+        } catch (Throwable e) {
+            Log.w(TAG, "Exception posting location: " + e);
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    private class PostLocationTask extends AsyncTask