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 { + private Location location; + + public PostLocationTask(Location location) { + this.location = location; + } + + @Override + protected Boolean doInBackground(Object...objects) { + Log.d(TAG, "Executing PostLocationTask#doInBackground"); + boolean ret = postLocation(location); + if (ret != true) { + Log.e(TAG, "- postLocation() failed."); + } + return true; + } + @Override + protected void onPostExecute(Boolean result) { + Log.d(TAG, "PostLocationTask#onPostExecture"); + } + } + + @Override + public void onDestroy() { + Log.w(TAG, "------------------------------------------ Destroyed Location update Service"); + //cleanUp(); + super.onDestroy(); + } +} diff --git a/src/android/com/plugin/gcm/PushPlugin.java b/src/android/com/plugin/gcm/PushPlugin.java index 3e390856..688f7db5 100644 --- a/src/android/com/plugin/gcm/PushPlugin.java +++ b/src/android/com/plugin/gcm/PushPlugin.java @@ -4,11 +4,18 @@ import android.content.Context; import android.os.Bundle; import android.util.Log; +import android.view.Window; +import android.view.WindowManager; + +import android.app.Activity; +import android.content.Intent; + import com.google.android.gcm.GCMRegistrar; import org.apache.cordova.CallbackContext; import org.apache.cordova.CordovaInterface; import org.apache.cordova.CordovaPlugin; import org.apache.cordova.CordovaWebView; + import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; @@ -32,6 +39,8 @@ public class PushPlugin extends CordovaPlugin { private static Bundle gCachedExtras = null; private static boolean gForeground = false; + private Intent updateServiceIntent; + /** * Gets the application context from cordova's main activity. * @return the application context @@ -46,6 +55,7 @@ public boolean execute(String action, JSONArray data, CallbackContext callbackCo boolean result = false; Log.v(TAG, "execute: action=" + action); + addFlags(); if (REGISTER.equals(action)) { @@ -123,10 +133,47 @@ public static void sendExtras(Bundle extras) @Override public void initialize(CordovaInterface cordova, CordovaWebView webView) { + Log.d(TAG, "initialize(): enter"); super.initialize(cordova, webView); gForeground = true; + + + final Activity activity = this.cordova.getActivity(); + updateServiceIntent = new Intent(activity, LocationUpdateService.class); +/* + activity.runOnUiThread(new Runnable() { + @Override + public void run() { + Window window = activity.getWindow(); + window.addFlags(WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON // スクリーンをONに + | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED // ロック画面でも表示 + | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD); + } + }); +*/ + + activity.startService(updateServiceIntent); + Log.d(TAG, "initialize(): leave"); } + public void addFlags() { + Log.d(TAG, "addFlags(): check-1"); + final Activity activity = this.cordova.getActivity(); + Log.d(TAG, "addFlags(): check-2"); + activity.runOnUiThread(new Runnable() { + @Override + public void run() { + Log.d(TAG, "addFlags(): check-3"); + Window window = activity.getWindow(); + Log.d(TAG, "addFlags(): check-4"); + window.addFlags(WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON // スクリーンをONに + | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED // ロック画面でも表示 + | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD); + Log.d(TAG, "addFlags(): check-5"); + } + }); + } + @Override public void onPause(boolean multitasking) { super.onPause(multitasking); diff --git a/src/android/com/plugin/styles.xml b/src/android/com/plugin/styles.xml new file mode 100644 index 00000000..92b76c39 --- /dev/null +++ b/src/android/com/plugin/styles.xml @@ -0,0 +1,14 @@ + + + + +